]> Trent Huber's Code - thus.git/commitdiff
Clean up term.c
authorTrent Huber <trentmhuber@gmail.com>
Mon, 14 Jul 2025 08:39:38 +0000 (04:39 -0400)
committerTrent Huber <trentmhuber@gmail.com>
Mon, 14 Jul 2025 08:39:38 +0000 (04:39 -0400)
src/builtins.c
src/input.c
src/run.c
src/term.c

index fdd7e384456744d011bdb5acd6759e45b3056fd0..f42c54265dba6a62f1700703432a08edf2723bf4 100644 (file)
@@ -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;
index 5c56f9a25466c6e027f178490dcc18b633028c8f..abef388852ef64ae58effc79334e1e5e2f755c24 100644 (file)
@@ -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);
index 8ba727e27172c3d8019eaa55280ac5a21a0b7399..4e1d1b4a43f4b2982e4c32d0d3f5846f02b59aa2 100644 (file)
--- 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
index c703d344c5d877b37b3996e67757e70c98740412..f7bd4a759bba5a6ff751119532ec55a86a7796ec 100644 (file)
 #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;
 }