]> Trent Huber's Code - thus.git/commitdiff
Bug fixes, cmd/tokens/buffer reorganization
authorTrent Huber <trentmhuber@gmail.com>
Sat, 5 Jul 2025 07:03:22 +0000 (03:03 -0400)
committerTrent Huber <trentmhuber@gmail.com>
Sat, 5 Jul 2025 07:03:22 +0000 (03:03 -0400)
src/builtins.c
src/history.c
src/history.h
src/input.c
src/input.h
src/job.c
src/lex.c
src/lex.h
src/main.c

index 8199fbfbde866b02db2f215898c76df40ea1e951..fdd7e384456744d011bdb5acd6759e45b3056fd0 100644 (file)
@@ -71,12 +71,14 @@ BUILTINSIG(bg) {
            warnx("Job %d already in background", (pid_t)jobid);
            return 1;
        }
-   } else
-       for (jobs.c = MINUSONE(jobs, t); CURRENT->type == BACKGROUND; DEC(jobs, c))
-           if (jobs.c == jobs.b) {
-               warnx("No suspended jobs to run in background");
-               return 1;
-           }
+   } else {
+       for (jobs.c = MINUSONE(jobs, t); jobs.c != MINUSONE(jobs, b); DEC(jobs, c))
+           if (CURRENT->type == SUSPENDED) break;
+       if (jobs.c == MINUSONE(jobs, b)) {
+           warnx("No suspended jobs to run in background");
+           return 1;
+       }
+   }
    job = deletejob();
 
    if (!(push(&jobs, job))) {
index fc2a351c3698e506372fe67de57087e93aea10d0..ca39b45b04cdea5e6bc0785776500f0c27bcf0c4 100644 (file)
@@ -4,11 +4,11 @@
 #include <string.h>
 #include <sys/errno.h>
 
-#include "history.h"
 #include "input.h"
 #include "stack.h"
 #include "utils.h"
 
+#define HISTLEN 100
 #define HISTNAME ".ashhistory"
 
 static char *histpath, histarr[HISTLEN + 1][BUFLEN + 1];
index c395a45fd8e59863910f79c1197cb563ccc43fd5..bb7130f3cdcdfcc5b86ade385872fb21e0bda4c5 100644 (file)
@@ -1,6 +1,3 @@
-#define HISTLEN 100
-#define BUFLEN 1000
-
 extern struct stack history;
 
 void readhist(void);
index 29dc7b139c855292d82915fa25db0970eacf4f7d..d04bad902e46f3ceef0b39a87609ea12b0c96efe 100644 (file)
@@ -5,6 +5,7 @@
 #include <unistd.h>
 
 #include "history.h"
+#include "input.h"
 #include "job.h"
 #include "stack.h"
 
@@ -25,23 +26,23 @@ enum character {
    BACKSPACE = '\177',
 };
 
-static char buffer[1 + BUFLEN + 2];
+static char buffer[BUFLEN + 2]; // Terminating ';'
 
 char *input(void) {
-   char *start, *cursor, *end;
+   char *cursor, *end;
    int c, i;
 
    signal(SIGCHLD, waitbg); // TODO: Use sigaction for portability
 
 reset:
-   end = cursor = start = buffer + 1;
-   *history.t = *start = '\0';
+   end = cursor = buffer;
+   *history.t = *buffer = '\0';
    history.c = history.t;
-   while (start == end) {
+   while (buffer == end) {
        fputs(PROMPT, stdout);
        while ((c = getchar()) != '\n') {
            if (c >= ' ' && c <= '~') {
-               if (end - start == BUFLEN) continue;
+               if (end - buffer == BUFLEN) continue;
                memmove(cursor + 1, cursor, end - cursor);
                *cursor++ = c;
                *++end = '\0';
@@ -60,7 +61,7 @@ reset:
            case CLEAR:
                fputs("\033[H\033[J", stdout);
                fputs(PROMPT, stdout);
-               fputs(start, stdout);
+               fputs(buffer, stdout);
                continue;
            case ESCAPE:
                switch ((c = getchar())) {
@@ -69,8 +70,8 @@ reset:
                    while (cursor != end && *cursor == ' ') putchar(*cursor++);
                    break;
                case BACKWARD:
-                   while (cursor != start && *(cursor - 1) == ' ') putchar((--cursor, '\b'));
-                   while (cursor != start && *(cursor - 1) != ' ') putchar((--cursor, '\b'));
+                   while (cursor != buffer && *(cursor - 1) == ' ') putchar((--cursor, '\b'));
+                   while (cursor != buffer && *(cursor - 1) != ' ') putchar((--cursor, '\b'));
                    break;
                case ARROW:
                    switch ((c = getchar())) {
@@ -79,19 +80,19 @@ reset:
                        if (history.c == (c == UP ? history.b : history.t)) continue;
 
                        putchar('\r');
-                       for (i = end - start + strlen(PROMPT); i > 0; --i) putchar(' ');
+                       for (i = end - buffer + strlen(PROMPT); i > 0; --i) putchar(' ');
                        putchar('\r');
 
-                       if (strcmp(history.c, start) != 0) strcpy(history.t, start);
+                       if (strcmp(history.c, buffer) != 0) strcpy(history.t, buffer);
                        if (c == UP) DEC(history, c); else INC(history, c);
-                       strcpy(start, history.c);
-                       end = cursor = start + strlen(start);
+                       strcpy(buffer, history.c);
+                       end = cursor = buffer + strlen(buffer);
 
                        fputs(PROMPT, stdout);
-                       fputs(start, stdout);
+                       fputs(buffer, stdout);
                        break;
                    case LEFT:
-                       if (cursor > start) putchar((--cursor, '\b'));
+                       if (cursor > buffer) putchar((--cursor, '\b'));
                        break;
                    case RIGHT:
                        if (cursor < end) putchar(*cursor++);
@@ -103,7 +104,7 @@ reset:
                }
                break;
            case BACKSPACE:
-               if (cursor == start) continue;
+               if (cursor == buffer) continue;
                memmove(cursor - 1, cursor, end - cursor);
                --cursor;
                *--end = '\0';
@@ -118,9 +119,8 @@ reset:
        }
    }
    fpurge(stdout);
-   push(&history, start);
+   push(&history, buffer);
 
-   *buffer = ';';
    *end = ';';
    *++end = '\0';
 
index dee8d7a21fc13541b5cdf2232665310a857b0c15..652daa8a340bb4e10ed0814e36c46c06c6fad970 100644 (file)
@@ -1 +1,3 @@
+#define BUFLEN 1000
+
 char *input(void);
index a5f366e6f3535bee2497ad88dfe5fd9266f7a846..6573c4bf4ee4ac673b69c5027084860b3f313b9f 100644 (file)
--- a/src/job.c
+++ b/src/job.c
@@ -23,7 +23,7 @@ void *findjob(pid_t jobid) {
 void *deletejob(void) {
    memcpy(jobs.t, jobs.c, jobs.size);
    memmove(jobs.c, PLUSONE(jobs, c), jobs.t - jobs.c);
-   return MINUSONE(jobs, t);
+   return DEC(jobs, t);
 }
 
 void waitbg(int sig) {
index 0def809b38d7fdfb2a8a52d707e3ac4e3bc08075..108084f9b0fe113095cfa91f48f65f77eac6289e 100644 (file)
--- a/src/lex.c
+++ b/src/lex.c
+#include <err.h>
 #include <fcntl.h>
+#include <limits.h>
 #include <stddef.h>
 #include <stdlib.h>
-#include <err.h>
-#include <limits.h>
-#include <stdio.h> // DEBUG
+#include <stdio.h> // XXX
 
-#include "history.h"
+#include "input.h"
 #include "lex.h"
 
-static char *tokens[1 + BUFLEN + 1];
-static struct cmd cmds[1 + (BUFLEN + 1) / 2 + 1] = {{.args = tokens}};
-
-void printfreds(struct cmd *c) {
-   struct fred *f;
+#define MAXCMDS 100
 
-   for (f = c->freds; f->mode != END; ++f) {
-       printf("%d ", f->newfd);
-       switch (f->mode) {
-       case READ:
-           fputs("<", stdout);
-           break;
-       case WRITE:
-           fputs(">", stdout);
-           break;
-       case READWRITE:
-           fputs("<>", stdout);
-           break;
-       case APPEND:
-           fputs(">>", stdout);
-           break;
-       default:;
-       }
-       switch (f->type) {
-       case FD:
-           printf(" #%d\n", f->old.fd);
-           break;
-       case NAME:
-           printf(" %s\n", f->old.name);
-           break;
-       default:;
-       }
-   }
-}
+static char *tokens[BUFLEN + 1];
+static struct cmd cmds[MAXCMDS + 1];
+struct cmd empty = {0};
 
 struct cmd *lex(char *b) {
    char **t, *end;
    struct cmd *c;
-   struct fred *f;
-   long test;
+   long l;
    
    if (!b) return NULL;
    t = tokens;
    c = cmds;
-   while (*b) switch (*b) {
+   for (c->args = NULL, c->r = c->rds; *b; ++b) switch (*b) {
    default:
-       if (!*(b - 1)) { // Start of a token
-           if (!c->args) c->args = t; // Start of a command
-           *t++ = b;
-       }
-       ++b;
-       break;
-   case ' ':
-       *b++ = '\0';
+       if (!c->args) c->args = t;
+       if (!*(b - 1)) *t++ = b;
        break;
    case '<':
    case '>':
+       c->r->newfd = *b == '>';
        if (*(b - 1)) {
-           if ((test = strtol(*--t, &end, 10)) < 0 || test > INT_MAX || end != b) {
+           if (c->args == --t) c->args = NULL;
+           if ((l = strtol(*t, &end, 10)) < 0 || l > INT_MAX || end != b) {
                warnx("Invalid file redirection operator");
-               c->args = NULL;
-               return c - 1;
+               return &empty;
            }
-           f->newfd = (int)test;
-           if (c->args == t) c->args = NULL;
-       } else f->newfd = *b == '>';
-       f->mode = *b++;
-       if (*b == '>') {
+           c->r->newfd = l;
+       }
+       c->r->mode = *b;
+       if (*(b + 1) == '>') {
+           ++c->r->mode;
            ++b;
-           ++f->mode;
        }
-       f->old.name = b;
-
-       (++f)->mode = END;
-
-       if (*b == '&') ++b;
+       c->r++->oldname = b + 1;
+       if (*(b + 1) == '&') ++b;
        break;
    case '&':
    case '|':
-       if (*b == *(b + 1)) *b = '\0';
    case ';':
        if (c->args) {
-           *t++ = NULL;
-           c->type = !*b ? *b++ + 1 : *b;
-           *b++ = '\0';
-           for (f = c->freds; f->mode; ++f) {
-               if (*f->old.name == '&') {
-                   if ((test = strtol(++f->old.name, &end, 10)) < 0
-                       || test > INT_MAX || (*end && !*f->old.name)) {
-                       warnx("Invalid file redirection operator");
-                       c->args = NULL;
-                       return c - 1;
-                   }
-                   f->type = FD;
-                   f->old.fd = (int)test;
-               } else f->type = NAME;
+           if ((c->term = *b) != ';' && *b == *(b + 1)) {
+               ++c->term;
+               *b++ = '\0';
+           }
+           *b = '\0';
+           c->r->mode = END;
+           for (c->r = c->rds; c->r->mode; ++c->r) if (*c->r->oldname == '&') {
+               if ((l = strtol(++c->r->oldname, &end, 10)) < 0 || l > INT_MAX || *end) {
+                   warnx("Invalid file redirection");
+                   return &empty;
+               }
+               c->r->oldfd = l;
+               c->r->oldname = NULL;
            }
 
            (++c)->args = NULL;
-       } else {
-           if (!*b) ++b;
-           *b++ = '\0';
+           *t++ = NULL;
        }
-       f = c->freds;
-       f->mode = END;
+       c->r = c->rds;
+   case ' ':
+       *b = '\0';
    }
 
-   switch ((c - 1)->type) {
+   switch ((c - 1)->term) {
    case AND:
    case PIPE:
    case OR:
        warnx("Command left open-ended");
-       return c - 1;
+       return &empty;
    default:
-       *c = (struct cmd){0};
+       break;
    }
 
    return cmds;
index e80a1d42ea1e05ceed15ae64dd9efeb65ec9dcea..21aace68ab83a7a0a2f4ef9543fd48a84c6e694b 100644 (file)
--- a/src/lex.h
+++ b/src/lex.h
@@ -1,12 +1,4 @@
-enum terminator {
-   SEMI = ';',
-   BG = '&',
-   AND,
-   PIPE = '|',
-   OR,
-};
-
-enum mode {
+enum accessmode {
    END,
    READ = '<',
    READWRITE,
@@ -14,41 +6,28 @@ enum mode {
    APPEND,
 };
 
-enum type {
-   FD,
-   NAME,
+struct redirect {
+   enum accessmode mode;
+   int oldfd, newfd;
+   char *oldname;
 };
 
-// if (cmd->f->type == NAME) cmd->f->old.fd = open(cmd->f->old.name, mode);
-// dup2(cmd->f->newfd, cmd->f->old.fd);
-// if (cmd->f->type == NAME) close(cmd->f->old.fd);
-// 
-// // vs.
-// 
-// if (*cmd->f->oldfd == '&') fd = open(++cmd->f->oldfd, mode);
-// dup2(cmd->f->newfd, cmd->
-
-struct fred {
-   int newfd;
-   enum mode mode;
-   enum type type;
-   union {
-       int fd;
-       char *name;
-   } old;
+enum terminator {
+   SEMI = ';',
+   BG = '&',
+   AND,
+   PIPE = '|',
+   OR,
 };
 
-/* a>&b -> dup2(b, a); reopen(a, "w"); | (1)>&3 -> dup2(3, 1);
- * a<&b -> dup2(b, a); reopen(a, "r"); | (0)<&3 -> dup2(3, 0);
- * x >a >b >c ...
- */
-
+#define MAXRDS 25
 struct cmd {
    char **args;
-   enum terminator type;
-   struct fred freds[(BUFLEN - 1) / 3 + 1];
+   struct redirect *r, rds[MAXRDS + 1];
+   enum terminator term;
    int pipe[2];
 };
 
-void printfreds(struct cmd *c);
+extern struct cmd empty;
+
 struct cmd *lex(char *b);
index 7080219772d271437e8fc20e8f48c57d780b2182..c30e40ffc4e00c21b59ea6646a96f19ea584aa28 100644 (file)
@@ -34,12 +34,12 @@ static int closepipe(struct cmd *cmd) {
    return result;
 }
 
-static int redirectfiles(struct fred *f) {
+static int redirectfiles(struct redirect *r) {
    int oflag, fd;
 
-   for (; f->mode; ++f) {
-       if (f->type == NAME) {
-           switch (f->mode) {
+   for (; r->mode; ++r) {
+       if (r->oldname) {
+           switch (r->mode) {
            case READ:
                oflag = O_RDONLY;
                break;
@@ -54,19 +54,19 @@ static int redirectfiles(struct fred *f) {
                break;
            default:;
            }
-           if ((fd = open(f->old.name, oflag, 0644)) == -1) {
-               warn("Unable to open `%s'", f->old.name);
+           if ((fd = open(r->oldname, oflag, 0644)) == -1) {
+               warn("Unable to open `%s'", r->oldname);
                return 0;
            }
-           f->old.fd = fd;
+           r->oldfd = fd;
        }
-       if (dup2(f->old.fd, f->newfd) == -1) {
-           warn("Unable to redirect %d to %d", f->newfd, f->old.fd);
+       if (dup2(r->oldfd, r->newfd) == -1) {
+           warn("Unable to redirect %d to %d", r->newfd, r->oldfd);
            return 0;
        }
-       if (f->type == NAME) {
-           if (close(f->old.fd) == -1) {
-               warn("Unable to close file descriptor %d", f->old.fd);
+       if (r->oldname) {
+           if (close(r->oldfd) == -1) {
+               warn("Unable to close file descriptor %d", r->oldfd);
                return 0;
            }
        }
@@ -83,11 +83,11 @@ int main(void) {
    initterm();
    readhist();
 
-   while ((cmd = lex(input()))) {
-       while (prev = cmd++, cmd->args) {
-           ispipe = cmd->type == PIPE || prev->type == PIPE;
-           ispipestart = ispipe && prev->type != PIPE;
-           ispipeend = ispipe && cmd->type != PIPE;
+   for (prev = &empty; (cmd = lex(input())); prev = &empty) {
+       for (; cmd->args; prev = cmd++) {
+           ispipe = cmd->term == PIPE || prev->term == PIPE;
+           ispipestart = ispipe && prev->term != PIPE;
+           ispipeend = ispipe && cmd->term != PIPE;
 
            if (ispipe) {
                if (!ispipeend && pipe(cmd->pipe) == -1) {
@@ -112,7 +112,7 @@ int main(void) {
                        if (!closepipe(cmd)) exit(EXIT_FAILURE);
                    }
 
-                   if (!redirectfiles(cmd->freds)) exit(EXIT_FAILURE);
+                   if (!redirectfiles(cmd->rds)) exit(EXIT_FAILURE);
                    if (isbuiltin(cmd->args, &status)) exit(EXIT_SUCCESS);
                    if (execvp(*cmd->args, cmd->args) == -1)
                        err(EXIT_FAILURE, "Couldn't find `%s' command", *cmd->args);
@@ -122,12 +122,12 @@ int main(void) {
                    jobid = ((struct job *)(ispipeend ? pull : peek)(&jobs))->id;
                }
            } else {
-               if (cmd->freds->mode == END && isbuiltin(cmd->args, &status)) break;
+               if (cmd->rds->mode == END && isbuiltin(cmd->args, &status)) break;
                if ((jobid = cpid = fork()) == -1) {
                    warn("Unable to create child process");
                    break;
                } else if (cpid == 0) {
-                   if (!redirectfiles(cmd->freds)) exit(EXIT_FAILURE);
+                   if (!redirectfiles(cmd->rds)) exit(EXIT_FAILURE);
                    if (isbuiltin(cmd->args, &status)) exit(EXIT_SUCCESS);
                    if (execvp(*cmd->args, cmd->args) == -1)
                        err(EXIT_FAILURE, "Couldn't find `%s' command", *cmd->args);
@@ -144,18 +144,18 @@ int main(void) {
            }
 
            job = (struct job){.id = jobid, .config = canonical, .type = BACKGROUND};
-           if (ispipestart || cmd->type == BG) {
+           if (ispipestart || cmd->term == BG) {
                if (!push(&jobs, &job)) {
                    warn("Unable to add command to background; "
                         "too many processes in the background");
                    if (ispipestart) closepipe(cmd);
                    break;
                }
-           } else if (cmd->type != PIPE) {
+           } else if (cmd->term != PIPE) {
                if (!setfg(job)) break;
                status = waitfg(job);
-               if (cmd->type == AND && status != 0) break;
-               if (cmd->type == OR && status == 0) break;
+               if (cmd->term == AND && status != 0) break;
+               if (cmd->term == OR && status == 0) break;
            }
        }
        waitbg(0);