From 38a3a4a1abfac2017af41ec256f7dc6b582133b3 Mon Sep 17 00:00:00 2001 From: Trent Huber Date: Mon, 14 Jul 2025 04:39:38 -0400 Subject: [PATCH] Clean up term.c --- src/builtins.c | 2 +- src/input.c | 150 +++++++++++++++++++++++++------------------------ src/run.c | 2 + src/term.c | 122 ++++++++++++++-------------------------- 4 files changed, 121 insertions(+), 155 deletions(-) diff --git a/src/builtins.c b/src/builtins.c index fdd7e38..f42c542 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -46,7 +46,7 @@ BUILTINSIG(fg) { warnx("No processes to bring into the foreground"); return 1; } - setfg(*job); + if (!setfg(*job)) return 1; waitfg(*job); return 0; diff --git a/src/input.c b/src/input.c index 5c56f9a..abef388 100644 --- a/src/input.c +++ b/src/input.c @@ -16,6 +16,7 @@ enum character { CTRLC = '\003', CTRLD, + BACKSPACE = '\010', CLEAR = '\014', ESCAPE = '\033', FORWARD = 'f', @@ -25,14 +26,15 @@ enum character { DOWN, RIGHT, LEFT, - BACKSPACE = '\177', + DEL = '\177', }; char buffer[BUFLEN + 2]; // Terminating ";" char *input(void) { char *cursor, *end; - int c, i; + unsigned int c; + int i; signal(SIGCHLD, waitbg); // TODO: Use sigaction for portability @@ -41,87 +43,87 @@ char *input(void) { history.c = history.t; while (buffer == end) { fputs(PROMPT, stdout); - while ((c = getchar()) != '\n') { - switch (c) { - default: - if (c >= ' ' && c <= '~') { - if (end - buffer == BUFLEN) continue; - memmove(cursor + 1, cursor, end - cursor); - *cursor++ = c; - *++end = '\0'; - - putchar(c); - fputs(cursor, stdout); - for (i = end - cursor; i > 0; --i) putchar('\b'); - } + while ((c = getchar()) != '\r') switch (c) { + default: + if (c >= ' ' && c <= '~') { + if (end - buffer == BUFLEN) continue; + memmove(cursor + 1, cursor, end - cursor); + *cursor++ = c; + *++end = '\0'; + + putchar(c); + fputs(cursor, stdout); + for (i = end - cursor; i > 0; --i) putchar('\b'); + } + break; + case CTRLC: + puts("^C\r"); + *buffer = '\0'; + return buffer; + case CTRLD: + puts("^D\r"); + signal(SIGCHLD, SIG_DFL); + return NULL; + case CLEAR: + fputs("\033[H\033[J", stdout); + fputs(PROMPT, stdout); + fputs(buffer, stdout); + continue; + case ESCAPE: + switch ((c = getchar())) { + case FORWARD: + while (cursor != end && *cursor != ' ') putchar(*cursor++); + while (cursor != end && *cursor == ' ') putchar(*cursor++); break; - case CTRLC: - puts("^C"); - *buffer = '\0'; - return buffer; - case CTRLD: - puts("^D"); - signal(SIGCHLD, SIG_DFL); - return NULL; - case CLEAR: - fputs("\033[H\033[J", stdout); - fputs(PROMPT, stdout); - fputs(buffer, stdout); - continue; - case ESCAPE: + case BACKWARD: + while (cursor != buffer && *(cursor - 1) == ' ') putchar((--cursor, '\b')); + while (cursor != buffer && *(cursor - 1) != ' ') putchar((--cursor, '\b')); + break; + case ARROW: switch ((c = getchar())) { - case FORWARD: - while (cursor != end && *cursor != ' ') putchar(*cursor++); - while (cursor != end && *cursor == ' ') putchar(*cursor++); + case UP: + case DOWN: + if (history.c == (c == UP ? history.b : history.t)) continue; + + putchar('\r'); + for (i = end - buffer + strlen(PROMPT); i > 0; --i) putchar(' '); + putchar('\r'); + + if (strcmp(history.c, buffer) != 0) strcpy(history.t, buffer); + if (c == UP) DEC(history, c); else INC(history, c); + strcpy(buffer, history.c); + end = cursor = buffer + strlen(buffer); + + fputs(PROMPT, stdout); + fputs(buffer, stdout); break; - case BACKWARD: - while (cursor != buffer && *(cursor - 1) == ' ') putchar((--cursor, '\b')); - while (cursor != buffer && *(cursor - 1) != ' ') putchar((--cursor, '\b')); + case LEFT: + if (cursor > buffer) putchar((--cursor, '\b')); break; - case ARROW: - switch ((c = getchar())) { - case UP: - case DOWN: - if (history.c == (c == UP ? history.b : history.t)) continue; - - putchar('\r'); - for (i = end - buffer + strlen(PROMPT); i > 0; --i) putchar(' '); - putchar('\r'); - - if (strcmp(history.c, buffer) != 0) strcpy(history.t, buffer); - if (c == UP) DEC(history, c); else INC(history, c); - strcpy(buffer, history.c); - end = cursor = buffer + strlen(buffer); - - fputs(PROMPT, stdout); - fputs(buffer, stdout); - break; - case LEFT: - if (cursor > buffer) putchar((--cursor, '\b')); - break; - case RIGHT: - if (cursor < end) putchar(*cursor++); - break; - } + case RIGHT: + if (cursor < end) putchar(*cursor++); break; - default: - ungetc(c, stdin); } break; - case BACKSPACE: - if (cursor == buffer) continue; - memmove(cursor - 1, cursor, end - cursor); - --cursor; - *--end = '\0'; - - putchar('\b'); - fputs(cursor, stdout); - putchar(' '); - for (i = end - cursor + 1; i > 0; --i) putchar('\b'); - - break; + default: + ungetc(c, stdin); } + break; + case BACKSPACE: + case DEL: + if (cursor == buffer) continue; + memmove(cursor - 1, cursor, end - cursor); + --cursor; + *--end = '\0'; + + putchar('\b'); + fputs(cursor, stdout); + putchar(' '); + for (i = end - cursor + 1; i > 0; --i) putchar('\b'); + + break; } + puts("\r"); } fpurge(stdout); push(&history, buffer); diff --git a/src/run.c b/src/run.c index 8ba727e..4e1d1b4 100644 --- a/src/run.c +++ b/src/run.c @@ -199,7 +199,9 @@ void runscript(char *filename) { void runinteractive(void) { struct cmd *cmd; + readhist(); while ((cmd = lex(input()))) runcmd(cmd); + writehist(); } #define MAXPATH 1000 diff --git a/src/term.c b/src/term.c index c703d34..f7bd4a7 100644 --- a/src/term.c +++ b/src/term.c @@ -11,114 +11,76 @@ #include "stack.h" struct termios raw, canonical; -static pid_t self; -static int tcsetraw(void) { - if (tcsetattr(STDIN_FILENO, TCSANOW, &raw) == -1) { - warn("Unable to set termios state to raw mode"); +static int setconfig(struct termios *mode) { + if (tcsetattr(STDIN_FILENO, TCSANOW, mode) == -1) { + warn("Unable to set termios config"); return 0; } - return 1; } void initterm(void) { + cfmakeraw(&raw); if (tcgetattr(STDIN_FILENO, &canonical) == -1) - err(EXIT_FAILURE, "Unable to get termios structure"); - raw = canonical; - raw.c_lflag &= ~ICANON & ~ECHO & ~ISIG; - raw.c_lflag |= ECHONL; - if (!tcsetraw()) exit(EXIT_FAILURE); - - if ((self = getpgid(0)) == -1) err(EXIT_FAILURE, "Unable to get pgid of self"); + err(EXIT_FAILURE, "Unable to get default termios config"); + if (!setconfig(&raw)) exit(EXIT_FAILURE); } void deinitterm(void) { - if (tcsetattr(STDIN_FILENO, TCSANOW, &canonical) == -1) - warn("Unable to return to initial terminal settings"); -} - -static void tcsetself(void) { - if (signal(SIGTTOU, SIG_IGN) == SIG_ERR) { - warn("Unable to ignore SIGTTOU signal"); - goto quit; - } - if (tcsetpgrp(STDIN_FILENO, self) == -1) { - warn("Unable to set self as foreground process; exiting"); - goto quit; - } - if (signal(SIGTTOU, SIG_DFL) == SIG_ERR) warn("Ignoring signal SIGTTOU"); - - return; - -quit: - writehist(); - deinitterm(); - exit(EXIT_FAILURE); -} - -static void sigkill(pid_t jobid) { - if (killpg(jobid, SIGKILL) == -1) - warn("Unable to kill process group %d; manual termination may be required", - jobid); + setconfig(&canonical); } int setfg(struct job job) { - if (tcsetattr(STDIN_FILENO, TCSANOW, &job.config) == -1) - warn("Unable to set termios structure"); + if (!setconfig(&job.config)) return 0; if (tcsetpgrp(STDIN_FILENO, job.id) == -1) { - warn("Unable to bring process group %d to foreground", job.id); - goto setraw; + warn("Unable to bring job %d to foreground\r", job.id); + setconfig(&raw); + return 0; } if (killpg(job.id, SIGCONT) == -1) { - warn("Unable to wake up suspended process group %d", job.id); - goto setself; + warn("Unable to wake up job %d\r", job.id); + return 0; } - return 1; - -setself: - tcsetself(); - -setraw: - tcsetraw(); - - sigkill(job.id); - - return 0; } int waitfg(struct job job) { - int status, result; - -wait: - if (waitpid(job.id, &status, WUNTRACED) != -1 && !WIFSTOPPED(status)) { - while (waitpid(-job.id, NULL, 0) != -1); - if (errno != ECHILD && killpg(job.id, SIGKILL) == -1) - err(EXIT_FAILURE, "Unable to kill child process group %d", job.id); + int status, pgid, result; + + errno = 0; + do waitpid(job.id, &status, WUNTRACED); while (errno == EINTR); + if (!errno && !WIFSTOPPED(status)) + do while (waitpid(-job.id, NULL, 0) != -1); while (errno == EINTR); + result = errno; + + // TODO: Use sigaction >:( + if ((pgid = getpgid(0)) == -1 || signal(SIGTTOU, SIG_IGN) == SIG_ERR + || tcsetpgrp(STDIN_FILENO, pgid) == -1 + || signal(SIGTTOU, SIG_DFL) == SIG_ERR) { + warn("Unable to reclaim foreground; terminating\r"); + writehist(); + deinitterm(); + exit(EXIT_FAILURE); } - - tcsetself(); + if (tcgetattr(STDIN_FILENO, &job.config) == -1) + warn("Unable to save termios config of job %d\r", job.id); + setconfig(&raw); + if (result) return 1; if (WIFSIGNALED(status)) { - putchar('\n'); result = WTERMSIG(status); + puts("\r"); } else if (WIFSTOPPED(status)) { - if (tcgetattr(STDIN_FILENO, &job.config) == -1) - warn("Unable to save termios state for stopped process group %d", job.id); - job.type = SUSPENDED; - if (!push(&jobs, &job)) { - warnx("Unable to add process to job list; too many jobs\n" - "Press any key to continue"); - getchar(); - if (setfg(job)) goto wait; - warn("Unable to continue foreground process; terminating"); - sigkill(job.id); - } result = WSTOPSIG(status); - } else result = WEXITSTATUS(status); - - tcsetraw(); + job.type = SUSPENDED; + if (push(&jobs, &job)) return result; + warnx("Unable to add job %d to list; too many jobs\r\n" + "Press any key to continue\r", job.id); + getchar(); + if (setfg(job)) return waitfg(job); + warnx("Manual intervention required for job %d\r", job.id); + } else if (WIFEXITED(status)) result = WEXITSTATUS(status); return result; } -- 2.51.0