summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Kaivo <jkk@ung.org>2023-04-01 20:41:59 -0400
committerJakob Kaivo <jkk@ung.org>2023-04-01 20:41:59 -0400
commita46ccd3ebd191c1b685b3c4e0f4c8802631303e1 (patch)
tree0d77e5eb05690db7605ad33df7b1f4d6a3e6d231
parentd905faaa0a3180e20532eff6b1effbec06431d87 (diff)
integrate interactive command editing
-rw-r--r--Makefile10
-rw-r--r--interactive.c36
-rw-r--r--set.c5
-rw-r--r--sh.l9
-rw-r--r--sh.y8
-rw-r--r--shed.c65
-rw-r--r--shed.h92
-rw-r--r--shed_commands.c163
-rw-r--r--shed_edit.c97
-rw-r--r--shed_insert.c62
-rw-r--r--shed_io.c91
-rw-r--r--shed_move.c45
-rw-r--r--shed_non_vi.c99
-rw-r--r--umask.c27
14 files changed, 758 insertions, 51 deletions
diff --git a/Makefile b/Makefile
index 15c92ea..e16dc06 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
default: all
-CFLAGS=-g -Wall -Wextra -Wpedantic
+CFLAGS=-g -Wall -Wextra -Wpedantic -D_XOPEN_SOURCE=700
UTILITY=sh
SOURCES=alias.c bg.c builtins.c cd.c command.c fc.c fg.c getopts.c \
@@ -12,14 +12,16 @@ SOURCES=alias.c bg.c builtins.c cd.c command.c fc.c fg.c getopts.c \
ulimit.c umask.c wait.c \
dot.c eval.c exec.c exit.c export.c readonly.c shift.c times.c trap.c \
unset.c \
- interactive.c parse.c init.c getopt.c
-HEADERS=sh.h
+ interactive.c parse.c init.c getopt.c \
+ shed.c shed_commands.c shed_edit.c shed_insert.c shed_io.c shed_move.c shed_non_vi.c
+HEADERS=sh.h shed.h
OBJECTS=alias.o bg.o builtins.o cd.o command.o fc.o fg.o getopts.o \
hash.o jobs.o kill.o newgrp.o pwd.o read.o set.o main.o type.o \
ulimit.o umask.o wait.o \
dot.o eval.o exec.o exit.o export.o readonly.o shift.o times.o trap.o \
unset.o \
interactive.o parse.o init.o getopt.o \
+ shed.o shed_commands.o shed_edit.o shed_insert.o shed_io.o shed_move.o shed_non_vi.o \
sh.tab.o sh.yy.o
BUILTINS=alias bg cd command fc fg getopts jobs newgrp read \
ulimit umask unalias wait
@@ -27,7 +29,7 @@ BUILTINS=alias bg cd command fc fg getopts jobs newgrp read \
all: $(UTILITY) $(L10N) $(BUILTINS)
sh: $(OBJECTS) $(HEADERS)
- $(CC) -o $@ $(CFLAGS) $(OBJECTS) -ly -ll
+ $(CC) -o $@ $(CFLAGS) $(OBJECTS)
$(BUILTINS): $(UTILITY)
#ln -s $(UTILITY) $@
diff --git a/interactive.c b/interactive.c
index 6db84b0..3f753a3 100644
--- a/interactive.c
+++ b/interactive.c
@@ -19,46 +19,26 @@
#define _XOPEN_SOURCE 700
-#include "sh.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-static char *sh_getline(char **cmdline)
-{
- char *prompt = getenv(*cmdline ? "PS2" : "PS1");
- /* wordexpand prompt */
- fprintf(stderr, "%s", prompt);
-
- size_t n = 0;
- getline(cmdline, &n, stdin);
- return *cmdline;
-}
+#include "sh.h"
+#include "shed.h"
int sh_interactive(void)
{
- while (!feof(stdin)) {
- char *cmdline = NULL;
- sh_getline(&cmdline);
-
- if (cmdline == NULL) {
- break;
- }
-
- struct command *command = sh_parse(cmdline);
- #if 0
- while (command == NULL) {
- /* append more text */
- /* attempt parsing again */
- }
- #endif
+ struct shed ed = {
+ .prompt = getenv("PS1"),
+ .handle = shed_handle_non_vi,
+ };
+ while (shed(&ed) != NULL) {
+ struct command *command = sh_parse(ed.cur->buf);
if (command) {
sh_execute(command);
sh_freecmd(command);
}
-
- free(cmdline);
}
return 0;
diff --git a/set.c b/set.c
index de7f288..0bd718c 100644
--- a/set.c
+++ b/set.c
@@ -110,11 +110,10 @@ int set_main(int argc, char *argv[])
break;
case ':':
- if (optopt == 'o') {
- show = 1;
- } else {
+ if (optopt != 'o') {
return 1;
}
+ show = 1;
break;
default:
diff --git a/sh.l b/sh.l
index c38ea7c..289c97a 100644
--- a/sh.l
+++ b/sh.l
@@ -1,9 +1,7 @@
%{
+#include <stdio.h>
#include "sh.h"
#include "sh.tab.h"
-/* thanks, flex, for implicitly declaring identifiers */
-/* bonus points for something that isn't part of ISO C */
-extern int fileno(FILE *);
%}
NAME [_a-zA-Z0-9]
@@ -65,6 +63,11 @@ OPERATOR [()|;&<>]
{WHITESPACE} ;
%%
+int yywrap(void)
+{
+ return 1;
+}
+
void sh_silence_warning(void)
{
input();
diff --git a/sh.y b/sh.y
index 14ad022..7a981d7 100644
--- a/sh.y
+++ b/sh.y
@@ -310,3 +310,11 @@ sequential_sep : ';' linebreak {
puts("sequential_sep:newline_list");
}
;
+
+%%
+
+int yyerror(const char *s)
+{
+ return fprintf(stderr, "%s\n", s);
+}
+
diff --git a/shed.c b/shed.c
new file mode 100644
index 0000000..a0cc554
--- /dev/null
+++ b/shed.c
@@ -0,0 +1,65 @@
+#define _POSIX_C_SOURCE 200809L
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include "shed.h"
+
+/*
+ * BIG FAT TODO: DEAL WITH MULTIBYTE CHARACTERS CORRECTLY
+ */
+
+struct shed *shed(struct shed *e)
+{
+ if (e == NULL) {
+ e = calloc(1, sizeof(*e));
+ if (e == NULL) {
+ return NULL;
+ }
+ }
+
+ /* TODO: head/tail/history */
+ if (e->cur == NULL) {
+ e->cur = calloc(1, sizeof(*e->cur));
+ if (e->cur == NULL) {
+ return e;
+ }
+ e->handle = shed_handle_non_vi;
+ }
+
+ memset(e->cur, '\0', sizeof(*e->cur));
+
+ struct termios original_tio;
+ if (tcgetattr(STDIN_FILENO, &original_tio) != 0) {
+ e->cur = NULL;
+ return e;
+ }
+
+ struct termios tio = original_tio;
+ tio.c_iflag &= ~BRKINT;
+ tio.c_lflag &= ~ECHO;
+ tio.c_lflag &= ~IEXTEN;
+ tio.c_lflag &= ~ICANON;
+ tio.c_lflag &= ~ISIG;
+ tcsetattr(STDIN_FILENO, TCSADRAIN, &tio);
+
+ if (e->prompt == NULL) {
+ e->prompt = getenv("PS1");
+ if (e->prompt == NULL) {
+ e->prompt = "$ ";
+ }
+ }
+ write(STDOUT_FILENO, e->prompt, strlen(e->prompt));
+
+ char c;
+ do {
+ if (read(STDIN_FILENO, &c, 1) == -1) {
+ //b.nread = -1;
+ /* TODO: signal failure */
+ break;
+ }
+ } while (e->handle(e, &tio, c));
+
+ tcsetattr(STDIN_FILENO, TCSADRAIN, &original_tio);
+ return e;
+}
diff --git a/shed.h b/shed.h
new file mode 100644
index 0000000..fac00c4
--- /dev/null
+++ b/shed.h
@@ -0,0 +1,92 @@
+#ifndef SHED_H
+#define SHED_H
+
+#include <sys/types.h>
+
+enum {
+ CTRL_A = 0x01,
+ CTRL_B = 0x02,
+ CTRL_C = 0x03,
+ CTRL_D = 0x04,
+ CTRL_E = 0x05,
+ CTRL_F = 0x06,
+ CTRL_G = 0x07,
+ CTRL_H = 0x08,
+ CTRL_I = 0x09,
+ CTRL_J = 0x0a,
+ CTRL_K = 0x0b,
+ CTRL_L = 0x0c,
+ CTRL_M = 0x0d,
+ CTRL_N = 0x0e,
+ CTRL_O = 0x0f,
+ CTRL_P = 0x10,
+ CTRL_Q = 0x11,
+ CTRL_R = 0x12,
+ CTRL_S = 0x13,
+ CTRL_T = 0x14,
+ CTRL_U = 0x15,
+ CTRL_V = 0x16,
+ CTRL_W = 0x17,
+ CTRL_X = 0x18,
+ CTRL_Y = 0x19,
+ CTRL_Z = 0x1a,
+ ESCAPE = 0x1b,
+};
+
+struct termios;
+
+struct buffer {
+ size_t len;
+ size_t pos;
+ ssize_t nread;
+ char buf[512]; /* TODO: dynamic */
+};
+
+struct shed {
+ char *prompt;
+ int (*handle)(struct shed *e, struct termios *, char);
+ struct buffer *head;
+ struct buffer *tail;
+ struct buffer *cur;
+ int count;
+};
+
+void shed_replace_char(struct buffer *b, char c);
+void shed_insert_char(struct buffer *b, char c);
+void shed_remove_char(struct buffer *b, int forward);
+void shed_move_cursor(struct buffer *b, int move);
+
+int shed_append(struct shed *e);
+int shed_append_end(struct shed *e);
+int shed_backspace(struct shed *e);
+int shed_cancel(struct shed *e);
+int shed_change(struct shed *e);
+int shed_comment(struct shed *e);
+int shed_convert_case(struct shed *e);
+int shed_eof(struct shed *e);
+int shed_delete(struct shed *e);
+int shed_delete_toend(struct shed *e);
+int shed_erase(struct shed *e);
+int shed_execute(struct shed *e);
+int shed_insert(struct shed *e);
+int shed_insert_beginning(struct shed *e);
+int shed_redraw(struct shed *e);
+int shed_replace(struct shed *e);
+int shed_start_over(struct shed *e);
+int shed_worderase(struct shed *e);
+
+int shed_move_forward(struct shed *e);
+int shed_move_backward(struct shed *e);
+int shed_move_beginning(struct shed *e);
+int shed_move_end(struct shed *e);
+int shed_move_0(struct shed *e);
+int shed_move_column(struct shed *e);
+
+int shed_handle_insert(struct shed *e, struct termios *t, char c);
+int shed_handle_replace(struct shed *e, struct termios *t, char c);
+int shed_handle_edit(struct shed *e, struct termios *t, char c);
+int shed_handle_non_vi(struct shed *e, struct termios *t, char c);
+
+struct shed *shed(struct shed *e);
+
+#endif
diff --git a/shed_commands.c b/shed_commands.c
new file mode 100644
index 0000000..0c2bdfc
--- /dev/null
+++ b/shed_commands.c
@@ -0,0 +1,163 @@
+#define _POSIX_C_SOURCE 200809L
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "shed.h"
+
+int shed_append(struct shed *e)
+{
+ e->count = 1;
+ shed_move_forward(e);
+ return shed_insert(e);
+}
+
+int shed_append_end(struct shed *e)
+{
+ shed_move_end(e);
+ return shed_insert(e);
+}
+
+int shed_backspace(struct shed *e)
+{
+ int count = e->count ? e->count : 1;
+ for (int i = 0; i < count; i++) {
+ shed_remove_char(e->cur, 0);
+ }
+ return 1;
+}
+
+int shed_cancel(struct shed *e)
+{
+ struct buffer *b = e->cur;
+ write(STDOUT_FILENO, "^C", 2);
+ b->nread = 0;
+ return 0;
+}
+
+int shed_change(struct shed *e)
+{
+ shed_delete_toend(e);
+ return shed_append_end(e);
+}
+
+int shed_comment(struct shed *e)
+{
+ shed_move_cursor(e->cur, -e->cur->pos);
+ shed_insert_char(e->cur, '#');
+ return 0;
+}
+
+int shed_convert_case(struct shed *e)
+{
+ char *b = e->cur->buf;
+ size_t pos = e->cur->pos;
+ int count = e->count ? e->count : 1;
+
+ /* TODO: don't overflow */
+ for (int i = 0; i < count && pos + i < (size_t)e->cur->nread; i++) {
+ if (isupper(b[pos + i])) {
+ shed_replace_char(e->cur, tolower(b[pos + i]));
+ } else if (islower(b[pos + i])) {
+ shed_replace_char(e->cur, toupper(b[pos + i]));
+ } else {
+ shed_replace_char(e->cur, b[pos + i]);
+ }
+ }
+ return 1;
+}
+
+int shed_delete(struct shed *e)
+{
+ int count = e->count ? e->count : 1;
+ for (int i = 0; i < count; i++) {
+ shed_remove_char(e->cur, 1);
+ }
+ return 1;
+}
+
+int shed_delete_toend(struct shed *e)
+{
+ while (e->cur->pos < (size_t)e->cur->nread) {
+ shed_remove_char(e->cur, 1);
+ }
+ return 1;
+}
+
+int shed_eof(struct shed *e)
+{
+ struct buffer *b = e->cur;
+ if (b->nread == 0) {
+ b->buf[0] = CTRL_D;
+ b->nread = 1;
+ return 0;
+ }
+ return 1;
+}
+
+int shed_erase(struct shed *e)
+{
+ struct buffer *b = e->cur;
+ while (b->pos != 0) {
+ shed_remove_char(b, 0);
+ }
+ return 1;
+}
+
+int shed_execute(struct shed *e)
+{
+ struct buffer *b = e->cur;
+ b->pos = b->nread;
+ shed_insert_char(b, '\n');
+ if (e->handle == shed_handle_edit) {
+ e->handle = shed_handle_insert;
+ }
+ return 0;
+}
+
+int shed_insert(struct shed *e)
+{
+ e->handle = shed_handle_insert;
+ return 1;
+}
+
+int shed_insert_beginning(struct shed *e)
+{
+ shed_move_0(e);
+ return shed_insert(e);
+}
+
+int shed_redraw(struct shed *e)
+{
+ system("tput clear"); // TODO: pfork() and cache the output
+ write(STDOUT_FILENO, e->prompt, strlen(e->prompt));
+ write(STDOUT_FILENO, e->cur->buf, e->cur->nread);
+ int move = e->cur->nread - e->cur->pos;
+ e->cur->pos = e->cur->nread;
+ shed_move_cursor(e->cur, -move);
+ return 1;
+}
+
+int shed_replace(struct shed *e)
+{
+ e->handle = shed_handle_replace;
+ return 1;
+}
+
+int shed_start_over(struct shed *e)
+{
+ shed_move_0(e);
+ return shed_change(e);
+}
+
+int shed_worderase(struct shed *e)
+{
+ struct buffer *b = e->cur;
+ while (b->pos != 0 && (isblank(b->buf[b->pos - 1]) || ispunct(b->buf[b->pos - 1]))) {
+ shed_remove_char(b, 0);
+ }
+ while (b->pos != 0 && !(isspace(b->buf[b->pos - 1]) || ispunct(b->buf[b->pos - 1]))) {
+ shed_remove_char(b, 0);
+ }
+ return 1;
+}
diff --git a/shed_edit.c b/shed_edit.c
new file mode 100644
index 0000000..44af225
--- /dev/null
+++ b/shed_edit.c
@@ -0,0 +1,97 @@
+#define _POSIX_C_SOURCE 200809L
+#include <ctype.h>
+#include <stdlib.h>
+#include "shed.h"
+
+int shed_handle_edit(struct shed *e, struct termios *t, char c)
+{
+ (void)t;
+ int r = -1;
+
+ switch (c) {
+ case '\n': r = shed_execute(e); break;
+ case CTRL_L: r = shed_redraw(e); break;
+ case '#': r = shed_comment(e); break;
+
+ case '=': // r = shed_complete_wordexp(e); break;
+ case '\\': // r = shed_complete_pathname(e); break;
+ case '*': // r = shed_complete_wildcard(e); break;
+
+ case '@': // r = shed_insert_alias(e); // read one letter
+
+ case '~': r = shed_convert_case(e); break;
+ case '.': // r = shed_repeat(e); break;
+ case 'v': // r = shed_invoke_vi(e); break;
+
+ case 'l': /* FALLTHROUGH */
+ case ' ': r = shed_move_forward(e); break;
+ case 'h': r = shed_move_backward(e); break;
+ case 'w': // r = shed_move_forword(e); break;
+ case 'W': // r = shed_move_forbigword(e); break;
+ case 'e': // r = shed_move_endword(e); break;
+ case 'E': // r = shed_move_endbigword(e); break;
+ case 'b': // r = shed_move_backword(e); break;
+ case 'B': // r = shed_move_backbigword(e); break;
+ case '^': r = shed_move_beginning(e); break;
+ case '$': r = shed_move_end(e); break;
+ case '0': r = shed_move_0(e); break;
+ case '|': r = shed_move_column(e); break;
+
+ case 'f': // r = shed_move_first(e); break;
+ case 'F': // r = shed_move_prev(e); break;
+ case 't': // r = shed_move_before(e); break;
+ case 'T': // r = shed_move_after(e); break;
+ case ';': // r = shed_repeat_fftt(e); break;
+ case ',': // r = shed_reverse_fftt(e); break;
+
+ case 'a': r = shed_append(e); break;
+ case 'A': r = shed_append_end(e); break;
+ case 'i': r = shed_insert(e); break;
+ case 'I': r = shed_insert_beginning(e); break;
+ case 'R': r = shed_replace(e); break;
+
+ case 'c': // r = shed_delete_to(e); break;
+ case 'C': r = shed_change(e); break;
+ case 'S': r = shed_start_over(e); break;
+
+ case 'r': // r = shed_replace(e); break;
+ case '_': // ???
+ case 'x': r = shed_delete(e); break;
+ case 'X': r = shed_backspace(e); break;
+ case 'd': // r = shed_delete_motion(e); break;
+ case 'D': r = shed_delete_toend(e); break;
+ case 'y': // r = shed_yank(e); break;
+ case 'Y': // r = shed_bigyank(e); break;
+ case 'p': // r = shed_paste(e); break;
+ case 'P': // r = shed_bigpaste(e); break;
+
+ case 'u': // r = shed_undo(e); break;
+ case 'U': // r = shed_bigundo(e); break;
+
+ case 'k': /* FALLTHROUGH */
+ case '-': // r = shed_history_back(e); break;
+
+ case 'j': /* FALLTHOUGH */
+ case '+': // r = shed_history_forward(e); break;
+
+ case 'G': // r = shed_history_first(e); break;
+ case '/': // r = shed_history_backsearch(e); break;
+ case '?': // r = shed_history_forwardsearch(e); break;
+ case 'n': // r = shed_history_repeat(e); break;
+ case 'N': // r = shed_history_reverse(e); break;
+
+ default:
+ break;
+ }
+
+ if (isdigit(c)) {
+ char digit[2] = { c, '\0' };
+ e->count = (e->count * 10) + atoi(digit);
+ }
+
+ if (r != -1) {
+ e->count = 0;
+ }
+
+ return r;
+}
diff --git a/shed_insert.c b/shed_insert.c
new file mode 100644
index 0000000..384cbea
--- /dev/null
+++ b/shed_insert.c
@@ -0,0 +1,62 @@
+#define _POSIX_C_SOURCE 200809L
+#include <termios.h>
+#include "shed.h"
+
+static int shed_insert_special(struct shed *e, struct termios *t, char c)
+{
+ if (c == '\n') {
+ return shed_execute(e);
+ }
+
+ if (c == t->c_cc[VERASE]) {
+ return shed_backspace(e);
+ }
+
+ if (c == t->c_cc[VINTR]) {
+ return shed_cancel(e);
+ }
+
+ if (c == t->c_cc[VKILL]) {
+ return shed_erase(e);
+ }
+
+ if (c == CTRL_V) {
+ /* quote the next character */
+ return 1;
+ }
+
+ if (c == CTRL_W) {
+ return shed_worderase(e);
+ }
+
+ if (c == t->c_cc[VEOF]) {
+ return shed_eof(e);
+ }
+
+ if (c == ESCAPE) {
+ e->handle = shed_handle_edit;
+ return 1;
+ }
+
+ return -1;
+}
+
+int shed_handle_insert(struct shed *e, struct termios *t, char c)
+{
+ int r = shed_insert_special(e, t, c);
+ if (r == -1) {
+ shed_insert_char(e->cur, c);
+ r = 1;
+ }
+ return r;
+}
+
+int shed_handle_replace(struct shed *e, struct termios *t, char c)
+{
+ int r = shed_insert_special(e, t, c);
+ if (r == -1) {
+ shed_replace_char(e->cur, c);
+ r = 1;
+ }
+ return r;
+}
diff --git a/shed_io.c b/shed_io.c
new file mode 100644
index 0000000..17aee8e
--- /dev/null
+++ b/shed_io.c
@@ -0,0 +1,91 @@
+#define _POSIX_C_SOURCE 200809L
+#include <string.h>
+#include <unistd.h>
+#include "shed.h"
+
+void shed_replace_char(struct buffer *b, char c)
+{
+ if (b->pos >= (size_t)b->nread) {
+ shed_insert_char(b, c);
+ return;
+ }
+ b->buf[b->pos] = c;
+ write(STDOUT_FILENO, &c, 1);
+ b->pos++;
+}
+
+void shed_insert_char(struct buffer *b, char c)
+{
+ if (b->pos >= (size_t)b->nread) {
+ b->buf[b->pos] = c;
+ write(STDOUT_FILENO, &c, 1);
+ } else {
+ size_t shift = b->nread - b->pos;
+ char *start = b->buf + b->pos;
+ memmove(start + 1, start, shift);
+ *start = c;
+
+ char back[shift];
+ memset(back, '\b', shift);
+ write(STDOUT_FILENO, start, shift + 1);
+ write(STDOUT_FILENO, back, shift);
+ }
+
+ b->pos++;
+ b->nread++;
+}
+
+void shed_remove_char(struct buffer *b, int forward)
+{
+ /* TODO: don't forward delete past the end */
+ if (forward) {
+ write(STDOUT_FILENO, b->buf + b->pos, 1);
+ b->pos++;
+ }
+
+ if (b->pos == 0) {
+ return;
+ }
+
+ b->pos--;
+
+ char *start = b->buf + b->pos;
+ size_t shift = (size_t)b->nread - b->pos;
+
+ b->nread--;
+
+ for (size_t i = 0; i < shift; i++) {
+ start[i] = start[i + 1];
+ }
+ start[shift] = '\0';
+
+ char back[shift];
+ memset(back, '\b', shift);
+ write(STDOUT_FILENO, back, 1);
+ write(STDOUT_FILENO, start, shift);
+ write(STDOUT_FILENO, " \b", 2);
+ write(STDOUT_FILENO, back, shift - 1);
+}
+
+void shed_move_cursor(struct buffer *b, int move)
+{
+ if (move > 0) {
+ int maxfwd = (int)(b->nread - b->pos);
+ if (move > maxfwd) {
+ move = maxfwd;
+ }
+ write(STDOUT_FILENO, b->buf + b->pos, move);
+ b->pos += move;
+ }
+
+ if (move < 0) {
+ size_t len = (size_t)(-move);
+ if (len > b->pos) {
+ len = b->pos;
+ }
+ char back[len];
+ memset(back, '\b', len);
+ write(STDOUT_FILENO, back, len);
+ b->pos -= len;
+ }
+}
diff --git a/shed_move.c b/shed_move.c
new file mode 100644
index 0000000..0970085
--- /dev/null
+++ b/shed_move.c
@@ -0,0 +1,45 @@
+#define _POSIX_C_SOURCE 200809L
+#include <ctype.h>
+#include "shed.h"
+
+int shed_move_forward(struct shed *e)
+{
+ shed_move_cursor(e->cur, e->count ? e->count : 1);
+ return 1;
+}
+
+int shed_move_backward(struct shed *e)
+{
+ shed_move_cursor(e->cur, e->count ? -e->count : -1);
+ return 1;
+}
+
+int shed_move_beginning(struct shed *e)
+{
+ shed_move_cursor(e->cur, -e->cur->pos);
+ while (isspace(e->cur->buf[e->cur->pos])) {
+ shed_move_cursor(e->cur, 1);
+ }
+ return 1;
+}
+
+int shed_move_end(struct shed *e)
+{
+ shed_move_cursor(e->cur, e->cur->nread);
+ return 1;
+}
+
+int shed_move_0(struct shed *e)
+{
+ shed_move_cursor(e->cur, -e->cur->pos);
+ return 1;
+}
+
+int shed_move_column(struct shed *e)
+{
+ if (e->count == 0) {
+ e->count = 1;
+ }
+ shed_move_cursor(e->cur, e->count - e->cur->pos - 1);
+ return 1;
+}
diff --git a/shed_non_vi.c b/shed_non_vi.c
new file mode 100644
index 0000000..eda2cc6
--- /dev/null
+++ b/shed_non_vi.c
@@ -0,0 +1,99 @@
+#define _POSIX_C_SOURCE 200809L
+#include <ctype.h>
+#include <termios.h>
+#include <unistd.h>
+#include "shed.h"
+
+int shed_handle_non_vi(struct shed *e, struct termios *t, char c)
+{
+ if (c == t->c_cc[VEOF]) {
+ if (shed_eof(e) == 0) {
+ return 0;
+ }
+ }
+
+ if (c == t->c_cc[VINTR]) {
+ return shed_cancel(e);
+ }
+
+ if (c == t->c_cc[VEOL]) {
+ return shed_move_end(e);
+ }
+
+ if (c == t->c_cc[VERASE]) {
+ return shed_backspace(e);
+ }
+
+ if (c == t->c_cc[VQUIT]) {
+ /* ^\ */
+ return 1;
+ }
+
+ if (c == t->c_cc[VSTART]) {
+ /* ^Q */
+ return 1;
+ }
+
+ if (c == t->c_cc[VSTOP]) {
+ /* ^S */
+ return 1;
+ }
+
+ if (c == t->c_cc[VSUSP]) {
+ /* ^Z */
+ return 1;
+ }
+
+ if (c == '\033') {
+ char esc[2];
+ read(STDIN_FILENO, esc, 2);
+ if (esc[1] == 'C') {
+ return shed_move_forward(e);
+ }
+ if (esc[1] == 'D' && e->cur->pos > 0) {
+ return shed_move_backward(e);
+ }
+ return 1;
+ }
+
+ if (c == '\n') {
+ return shed_execute(e);
+ }
+
+ if (CTRL_A <= c && c <= CTRL_Z) {
+ switch (c) {
+ case CTRL_A: return shed_move_0(e);
+ case CTRL_B: return shed_move_backward(e);
+ case CTRL_C: return shed_cancel(e);
+ case CTRL_D: return shed_delete(e);
+ case CTRL_E: return shed_move_end(e);
+ case CTRL_F: return shed_move_forward(e);
+ case CTRL_G: break; // return abort(e)?
+ case CTRL_H: return shed_backspace(e);
+ case CTRL_I: break; // return complete_wordexp(e);
+ case CTRL_J: return shed_execute(e);
+ case CTRL_K: return shed_delete_toend(e);
+ case CTRL_L: return shed_redraw(e);
+ case CTRL_M: return shed_execute(e);
+ case CTRL_N: // return history_forward(e);
+ case CTRL_O: // return ??? /* ??? */
+ case CTRL_P: // return history_backward(e);
+ case CTRL_Q: // /* TTY START */
+ case CTRL_R: // return history_backsearch(e);
+ case CTRL_S: // /* TTY STOP */
+ case CTRL_T: break; // /* ??? */
+ case CTRL_U: return shed_erase(e);
+ case CTRL_V: break; // return quote(e);
+ case CTRL_W: return shed_worderase(e);
+ case CTRL_X: // /* ??? */
+ case CTRL_Y: // /* ??? */
+ case CTRL_Z: // /* ??? */
+ break;
+ }
+ return 1;
+ }
+
+ /* regular character */
+ shed_insert_char(e->cur, c);
+ return 1;
+}
diff --git a/umask.c b/umask.c
index f6fca22..124c226 100644
--- a/umask.c
+++ b/umask.c
@@ -47,19 +47,20 @@ int umask_main(int argc, char *argv[])
umask(mask);
if (symbolic) {
- fputs("u=", stdout);
- fputs(mask & S_IRUSR ? "" : "r", stdout);
- fputs(mask & S_IWUSR ? "" : "w", stdout);
- fputs(mask & S_IXUSR ? "" : "x", stdout);
- fputs(",g=", stdout);
- fputs(mask & S_IRGRP ? "" : "r", stdout);
- fputs(mask & S_IWGRP ? "" : "w", stdout);
- fputs(mask & S_IXGRP ? "" : "x", stdout);
- fputs(",o=", stdout);
- fputs(mask & S_IRGRP ? "" : "r", stdout);
- fputs(mask & S_IWGRP ? "" : "w", stdout);
- fputs(mask & S_IXGRP ? "" : "x", stdout);
- putchar('\n');
+ printf("u=");
+ printf("%s", mask & S_IRUSR ? "" : "r");
+ printf("%s", mask & S_IWUSR ? "" : "w");
+ printf("%s", mask & S_IXUSR ? "" : "x");
+
+ printf(",g=");
+ printf("%s", mask & S_IRGRP ? "" : "r");
+ printf("%s", mask & S_IWGRP ? "" : "w");
+ printf("%s", mask & S_IXGRP ? "" : "x");
+
+ printf("%s", ",o=");
+ printf("%s", mask & S_IRGRP ? "" : "r");
+ printf("%s", mask & S_IWGRP ? "" : "w");
+ printf("%s\n", mask & S_IXGRP ? "" : "x");
} else {
printf("%04o\n", mask);
}