]> Trent Huber's Code - thus.git/commitdiff
More refactoring, minor behavior fixes
authorTrent Huber <trentmhuber@gmail.com>
Sat, 15 Nov 2025 22:52:36 +0000 (17:52 -0500)
committerTrent Huber <trentmhuber@gmail.com>
Sat, 15 Nov 2025 22:52:36 +0000 (17:52 -0500)
16 files changed:
external/cbs
src/builtins/alias.c
src/builtins/alias.h
src/builtins/bg.c
src/builtins/build.c
src/builtins/exec.c
src/builtins/fg.c
src/builtins/set.c
src/builtins/unset.c
src/builtins/which.c
src/main.c
src/options.c
src/parse.c
src/run.c
src/signals.c
src/utils.c

index e998819b1d1e191d035600967abd84e9f2eb9cf8..011c66e9c2332506752b701fdfa37739dde67f6a 160000 (submodule)
@@ -1 +1 @@
-Subproject commit e998819b1d1e191d035600967abd84e9f2eb9cf8
+Subproject commit 011c66e9c2332506752b701fdfa37739dde67f6a
index 62f3786a03c7c8dce945846d73f3ac9a0ee9c6de..1f4a21b9e0c6ef0b7d29a6c890f2cd1091fb1bb1 100644 (file)
@@ -25,19 +25,18 @@ static size_t getindex(char *name) {
    return i;
 }
 
-char *getaliasvalue(char *name) {
+char *getalias(char *name) {
    size_t i;
 
    if ((i = getindex(name)) == aliases.size) return NULL;
    return aliases.entries[i].value;
 }
 
-char **getalias(char *name) {
-   char *value;
+char **parsealias(char *value) {
    size_t l;
    static struct context c;
 
-   if (!(value = getaliasvalue(name))) return NULL;
+   if (!value) return NULL;
 
    strcpy(c.buffer, value);
    l = strlen(value);
@@ -72,14 +71,16 @@ int alias(char **args, size_t numargs) {
    switch (numargs) {
    case 1:
        for (i = 0; i < aliases.size; ++i)
-           printf("%s -> %s\n", quoted(aliases.entries[i].name),
+           printf("%s = %s\n", quoted(aliases.entries[i].name),
                   aliases.entries[i].value);
        break;
    case 3:
        if (aliases.size == MAXALIAS) {
-           note("Unable to add alias, maximum reached (%d)", MAXALIAS);
+           note("Unable to add `%s' alias, maximum reached (%d)", args[1], MAXALIAS);
            return EXIT_FAILURE;
        }
+       if (!parsealias(args[2])) return EXIT_FAILURE;
+
        for (i = 1; i <= 2; ++i) {
            end = args[i] + strlen(args[i]);
            while (*args[i] == ' ') ++args[i];
index ba5206541bcb41ad7fcd6a1061ca29e3f8a5bc01..6bf7ccb5a247d24f51cba4706b231870ee73d848 100644 (file)
@@ -1,3 +1,3 @@
-char *getaliasvalue(char *name);
-char **getalias(char *name);
+char *getalias(char *name);
+char **parsealias(char *value);
 int removealias(char *name);
index c9207edd8c0fa822ea6cc9844ae3b39124ac176a..028a51f8382147082d8a5e8c336f80353b310508 100644 (file)
 
 #define MAXBG 100
 
-struct bglink {
-   struct bgjob job;
-   struct bglink *next;
-};
-
 static struct {
-   struct bglink entries[MAXBG], *active, *free;
+   struct bglink {
+       struct bgjob job;
+       struct bglink *next;
+   } entries[MAXBG], *active, *free;
 } bgjobs;
 struct sigaction bgaction;
 
index 40596af8d593b621a478d3e3138f65a34e861ec7..a115a3971cb3ec51a9363a7ff0292f5689a99a55 100644 (file)
@@ -34,7 +34,7 @@ int main(void) {
            err(EXIT_FAILURE, "Unable to duplicate directory entry");
        (*src)[strlen(*src) - 2] = '\0';
        if (src - srcs == 2 + MAXBUILTINS + 1)
-           errx(EXIT_FAILURE, "Unable to add %s built-in, maximum reached (%d)",
+           errx(EXIT_FAILURE, "Unable to add `%s' built-in, maximum reached (%d)",
                 *src, MAXBUILTINS);
        if (strcmp(*src, "builtin") != 0 && strcmp(*src, "list") != 0)
            dprintf(listfd, "int %s(char **args, size_t numargs);\n", *src);
index e786c96fda1788c862a3f0b17087e3e969b6bb86..4976c7071b02a1dcb2c14f175e917c3d6d72bf44 100644 (file)
@@ -40,5 +40,5 @@ int exec(char **args, size_t numargs) {
 
    /* execute() is guaranteed not to return, this statement just appeases the
     * compiler */
-   return EXIT_SUCCESS;
+   exit(EXIT_SUCCESS);
 }
index 9af112553da1ace0fbefe5abb7d769516ef72cc3..0812bee9b1c03d0a7b2e9082ec8d0e7f921b000b 100644 (file)
@@ -60,10 +60,9 @@ void initfg(void) {
    pgid = getpgrp();
    if (login && pid != pgid && setpgid(0, pgid = pid) == -1) exit(errno);
 
-   if (tcsetpgrp(STDIN_FILENO, pgid) == -1)
+   if (tcsetpgrp(STDIN_FILENO, pgid) == -1
+       || tcgetattr(STDIN_FILENO, &canonical) == -1)
        exit(errno);
-
-   if (tcgetattr(STDIN_FILENO, &canonical) == -1) exit(errno);
    raw = canonical;
    raw.c_lflag &= ~(ICANON | ECHO);
    if (!setconfig(&raw)) exit(EXIT_FAILURE);
index 56f780d6d2d6d3f5956972dfeb8e565a16b603e3..49bdd967d77853567f682f4b2023fdd73025eb1c 100644 (file)
@@ -7,7 +7,7 @@ int set(char **args, size_t numargs) {
    switch (numargs) {
    case 3:
        if (setenv(args[1], args[2], 1) == -1) {
-           note("Unable to set %s to %s", args[1], args[2]);
+           note("Unable to set `%s' to `%s'", args[1], args[2]);
            return EXIT_FAILURE;
        }
    case 2:
index af62aebceec6228079f607d41e523c534ac6b302..9d49f5d2805d03ebe1f8d16853ff822abf7d030d 100644 (file)
@@ -8,6 +8,6 @@ int unset(char **args, size_t numargs) {
 
    if (unsetenv(args[1]) != -1) return EXIT_SUCCESS;
 
-   note("Unable to unset $%s$", args[1]);
+   note("Unable to unset `%s'", args[1]);
    return EXIT_FAILURE;
 }
index 234a20c979c7527869ba4cf424592370fee61fc2..242659b6a3795d259a8020e8ce25273cea8c5de0 100644 (file)
@@ -56,8 +56,8 @@ int which(char **args, size_t numargs) {
 
    if (numargs != 2) return usage(args[0], "name");
 
-   if ((p = getaliasvalue(args[1]))) puts(p);
-   else if (getbuiltin(p = args[1])) printf("%s is built-in\n", p);
+   if ((p = getalias(args[1]))) puts(p);
+   else if (getbuiltin(p = args[1])) printf("%s is built-in\n", p);
    else if ((p = getpath(args[1]))) puts(quoted(p));
    else {
        printf("%s not found\n", quoted(args[1]));
index 09d058ca76a0536df2caf8f0ebf5f5fe7f21c087..c87dfc7efe98a108a3678eda45128f5828022bc9 100644 (file)
@@ -10,16 +10,12 @@ int main(int argc, char **argv) {
    struct context c;
 
    c = (struct context){0};
-
    options(argc, argv, &c);
 
    init();
-
    if (login) config(".thuslogin");
    if (interactive) config(".thusrc");
-
    while (run(&c));
-
    deinit();
 
    return EXIT_SUCCESS;
index ea305e2e641af8fa72481258a66e87462d60338a..48d3017de257e148d24d5cd8924302345838405e 100644 (file)
@@ -20,17 +20,16 @@ void options(int argc, char **argv, struct context *c) {
    int opt;
 
    argvector = argv;
-
    if (argvector[0][0] == '-') {
        ++argvector[0];
        login = 1;
    }
    if ((p = strrchr(argvector[0], '/'))) argvector[0] = p + 1;
-   interactive = 1;
-   c->input = userinput;
 
    opt = 0;
    argcount = argc;
+   interactive = 1;
+   c->input = userinput;
    while (opt != 'c' && (opt = getopt(argcount, argvector, ":c:hl")) != -1)
        switch (opt) {
        case 'c':
index 0ee28c428b54a56749cfe144f2abb3085f5f3455..b0904098dc09a9c52b72f49f464dbccbbf6b1e40 100644 (file)
@@ -16,16 +16,16 @@ static void sub(struct context *c, char **tokens, size_t numtokens) {
    c->t += numtokens - 1;
 }
 
-static int subalias(struct context *c) {
+static void subalias(struct context *c) {
    char **tokens;
    size_t numtokens;
 
-   if (c->alias || c->t != c->tokens || !(tokens = getalias(c->tokens[0]))) return 0;
+   if (c->alias || c->t != c->tokens
+       || !(tokens = parsealias(getalias(c->tokens[0]))))
+       return;
 
    for (numtokens = 0; tokens[numtokens]; ++numtokens);
    sub(c, tokens, numtokens);
-
-   return 1;
 }
 
 int parse(struct context *c) {
@@ -82,12 +82,8 @@ int parse(struct context *c) {
        errno = 0;
        if (stlend == c->b - 1)
            var = l >= 0 && l < argcount ? argvector[l] : c->b - 1;
-       else if (strcmp(p + 1, "^") == 0) {
-           if (!sprintf(var = (char [12]){0}, "%d", status)) {
-               note("Unable to get previous command status");
-               return quit(c);
-           }
-       } else if (!(var = getenv(p + 1))) var = "";
+       else if (strcmp(p + 1, "^") == 0) sprintf(var = (char [12]){0}, "%d", status);
+       else if (!(var = getenv(p + 1))) var = c->b - 1;
 
        v = strlen(var);
        offset = v - (c->b - p);
@@ -110,13 +106,11 @@ int parse(struct context *c) {
        *c->b = '\0';
        if (*c->t != c->b) ++c->t;
        *c->t = ++c->b;
-
        while (*c->b && *c->b != '\'') ++c->b;
        if (!*c->b) {
            note("Quote left open-ended");
            return quit(c);
        }
-
        *c->b = '\0';
        subalias(c);
        ++c->t;
@@ -124,13 +118,13 @@ int parse(struct context *c) {
 
        break;
    case '"':
+       quote = !quote;
+
        *c->b = '\0';
-       if (quote) subalias(c);
-       if (quote || *c->t != c->b) ++c->t;
+       if (!quote) subalias(c);
+       if (!quote || *c->t != c->b) ++c->t;
        *c->t = c->b + 1;
 
-       quote = !quote;
-
        break;
    case '\\':
        if (!quote) break;
@@ -166,6 +160,7 @@ int parse(struct context *c) {
    case ';':
    case ' ':
        if (quote) break;
+
        if (*c->b == '#') *(c->b + 1) = '\0';
 
        term = *c->b;
@@ -190,50 +185,53 @@ int parse(struct context *c) {
            c->r->mode = NONE;
        }
 
-       if (*c->t != c->b) {
-           if (!subalias(c) && globbing) {
-               globflags = GLOB_MARK;
-               if (prevnumglobs) globflags |= GLOB_APPEND;
-               switch (glob(*c->t, globflags, NULL, &globs)) {
-               case GLOB_NOMATCH:
-                   note("No matches found for `%s'", *c->t);
-                   return quit(c);
-               case GLOB_NOSPACE:
-                   fatal("Memory allocation");
-               }
-
-               globbing = 0;
-               sub(c, globs.gl_pathv + prevnumglobs, globs.gl_pathc - prevnumglobs);
-               prevnumglobs = globs.gl_pathc;
+       if (globbing) {
+           globflags = GLOB_MARK;
+           if (prevnumglobs) globflags |= GLOB_APPEND;
+           switch (glob(*c->t, globflags, NULL, &globs)) {
+           case GLOB_NOMATCH:
+               note("No matches found for `%s'", *c->t);
+               return quit(c);
+           case GLOB_NOSPACE:
+               fatal("Memory allocation");
            }
+
+           globbing = 0;
+           sub(c, globs.gl_pathv + prevnumglobs, globs.gl_pathc - prevnumglobs);
+           prevnumglobs = globs.gl_pathc;
+       }
+
+       if (*c->t != c->b) {
+           subalias(c);
            ++c->t;
        }
 
-       if (term != ' ') {
-           *c->t = NULL;
-           if (c->t != c->tokens) {
-               c->numtokens = c->t - c->tokens;
-               strcpy(c->current.name, c->tokens[0]);
-           } else c->t = NULL;
-           if (c->r == c->redirects) c->r = NULL;
-           switch (term) {
-           case '&':
-           case '|':
-               c->current.term = term;
-               if (*(c->b + 1) == term) {
-                   ++c->current.term;
-                   *++c->b = '\0';
-               }
-               break;
-           case ';':
-               c->current.term = SEMI;
-           }
-           ++c->b;
+       if (term == ' ') {
+           *c->t = c->b + 1;
+           break;
+       }
 
-           return 1;
+       *c->t = NULL;
+       if (c->t != c->tokens) {
+           c->numtokens = c->t - c->tokens;
+           strcpy(c->current.name, c->tokens[0]);
+       } else c->t = NULL;
+       if (c->r == c->redirects) c->r = NULL;
+       switch (term) {
+       case '&':
+       case '|':
+           c->current.term = term;
+           if (*(c->b + 1) == term) {
+               ++c->current.term;
+               *++c->b = '\0';
+           }
+           break;
+       case ';':
+           c->current.term = SEMI;
        }
+       ++c->b;
 
-       *c->t = c->b + 1;
+       return 1;
    }
 
    if (quote) {
index 0255cdadf452808a719370187f8e58f16801bfea..b426607558a8dce8361ad92dc0af6d37c504f012 100644 (file)
--- a/src/run.c
+++ b/src/run.c
@@ -79,8 +79,10 @@ int run(struct context *c) {
        }
        if (c->r) for (c->r = c->redirects; c->r->mode; ++c->r) {
            if (c->r != c->redirects) putchar(' ');
-           printf("%d%.*s", c->r->newfd, (c->r->mode & 1) + 1, &"<>>"[c->r->mode & 2]);
-           if (c->r->oldname) printf("%s", c->r->oldname);
+           if (c->r->newfd != c->r->mode >= WRITE) printf("%d", c->r->newfd);
+           putchar(c->r->mode < WRITE ? READ : WRITE);
+           if (c->r->mode == READWRITE || c->r->mode == APPEND) putchar(WRITE);
+           if (c->r->oldname) fputs(c->r->oldname, stdout);
            else printf("&%d", c->r->oldfd);
        }
        switch (c->current.term) {
@@ -96,83 +98,8 @@ int run(struct context *c) {
    }
 
    islist = c->previous.term > BG || c->current.term > BG;
-   if (c->t) {
-       if (c->current.term == BG && bgfull()) {
-           note("Unable to place job in background; too many background jobs");
-           return quit(c);
-       }
-       if (!(c->current.builtin = getbuiltin(c->current.name))
-           && !(c->current.path = getpath(c->current.name))) {
-           note("Couldn't find `%s' command", c->current.name);
-           if (c->previous.term == PIPE) killpg(pipeid, SIGKILL);
-           return quit(c);
-       }
-
-       ispipe = c->previous.term == PIPE || c->current.term == PIPE;
-       ispipestart = ispipe && c->previous.term != PIPE;
-       ispipeend = ispipe && c->current.term != PIPE;
-
-       if (ispipe) {
-           if (!ispipeend && pipe(c->current.pipe) == -1) {
-               note("Unable to create pipe");
-               if (!ispipestart) closepipe(c->previous);
-               return quit(c);
-           }
-           if ((cpid = fork()) == -1) {
-               note("Unable to fork child process");
-               return quit(c);
-           } else if (cpid == 0) {
-               if (!ispipestart) {
-                   if (dup2(c->previous.pipe[0], 0) == -1)
-                       fatal("Unable to duplicate read end of `%s' pipe", c->previous.name);
-                   if (!closepipe(c->previous)) exit(EXIT_FAILURE);
-               }
-               if (!ispipeend) {
-                   if (dup2(c->current.pipe[1], 1) == -1)
-                       fatal("Unable to duplicate write end of `%s' pipe", c->current.name);
-                   if (!closepipe(c->current)) exit(EXIT_FAILURE);
-               }
-               redirectfiles(c->redirects);
-               execute(c);
-           }
-           if (ispipestart) pipeid = cpid;
-           else if (!closepipe(c->previous)) {
-               killpg(pipeid, SIGKILL);
-               return quit(c);
-           }
-           jobid = pipeid;
-       } else if (!c->r && (c->current.builtin = getbuiltin(c->current.name))) {
-           status = c->current.builtin(c->tokens, c->numtokens);
-           cpid = 0;
-       } else if ((jobid = cpid = fork()) == -1) {
-           note("Unable to fork child process");
-           return quit(c);
-       } else if (cpid == 0) {
-           redirectfiles(c->redirects);
-           execute(c);
-       }
-
-       if (cpid) {
-           if (setpgid(cpid, jobid) == -1) {
-               if (errno != ESRCH) {
-                   note("Unable to set pgid of `%s' command to %d", c->current.name, jobid);
-                   if (kill(cpid, SIGKILL) == -1)
-                       note("Unable to kill process %d; may need to manually terminate", cpid);
-               }
-               return quit(c);
-           }
-           if (ispipestart || c->current.term == BG) {
-               pushbgid(jobid);
-               return 1;
-           }
-           if (c->current.term != PIPE && !runfg(jobid)) return quit(c);
-       }
 
-       if (status != EXIT_SUCCESS) {
-           if (!islist) return quit(c);
-           if (c->current.term == AND) return clear(c);
-       } else if (c->current.term == OR) return clear(c);
-   } else {
+   if (!c->t) {
        if (islist) {
            if (c->previous.term == PIPE) {
                killpg(pipeid, SIGKILL);
@@ -186,13 +113,93 @@ int run(struct context *c) {
        if ((cpid = fork()) == -1) {
            note("Unable to fork child process");
            return quit(c);
-       } else if (cpid == 0) {
+       }
+       if (!cpid) {
            redirectfiles(c->redirects);
            exit(EXIT_SUCCESS);
        }
        waitpid(cpid, NULL, 0);
        errno = 0;
+
+       return 1;
+   }
+
+   if (c->current.term == BG && bgfull()) {
+       note("Unable to place job in background; too many background jobs");
+       return quit(c);
+   }
+   if (!(c->current.builtin = getbuiltin(c->current.name))
+       && !(c->current.path = getpath(c->current.name))) {
+       note("Couldn't find `%s' command", c->current.name);
+       if (c->previous.term == PIPE) killpg(pipeid, SIGKILL);
+       return quit(c);
    }
 
+   ispipe = c->previous.term == PIPE || c->current.term == PIPE;
+   ispipestart = ispipe && c->previous.term != PIPE;
+   ispipeend = ispipe && c->current.term != PIPE;
+
+   if (ispipe) {
+       if (!ispipeend && pipe(c->current.pipe) == -1) {
+           note("Unable to create pipe");
+           if (!ispipestart) closepipe(c->previous);
+           return quit(c);
+       }
+       if ((cpid = fork()) == -1) {
+           note("Unable to fork child process");
+           return quit(c);
+       }
+       if (!cpid) {
+           if (!ispipestart) {
+               if (dup2(c->previous.pipe[0], 0) == -1)
+                   fatal("Unable to duplicate read end of `%s' pipe", c->previous.name);
+               if (!closepipe(c->previous)) exit(EXIT_FAILURE);
+           }
+           if (!ispipeend) {
+               if (dup2(c->current.pipe[1], 1) == -1)
+                   fatal("Unable to duplicate write end of `%s' pipe", c->current.name);
+               if (!closepipe(c->current)) exit(EXIT_FAILURE);
+           }
+           redirectfiles(c->redirects);
+           execute(c);
+       }
+       if (ispipestart) pipeid = cpid;
+       else if (!closepipe(c->previous)) {
+           killpg(pipeid, SIGKILL);
+           return quit(c);
+       }
+       jobid = pipeid;
+   } else if (!c->r && (c->current.builtin = getbuiltin(c->current.name))) {
+       status = c->current.builtin(c->tokens, c->numtokens);
+       cpid = 0;
+   } else if ((jobid = cpid = fork()) == -1) {
+       note("Unable to fork child process");
+       return quit(c);
+   } else if (!cpid) {
+       redirectfiles(c->redirects);
+       execute(c);
+   }
+
+   if (cpid) {
+       if (setpgid(cpid, jobid) == -1) {
+           if (errno != ESRCH) {
+               note("Unable to set pgid of `%s' command to %d", c->current.name, jobid);
+               if (kill(cpid, SIGKILL) == -1)
+                   note("Unable to kill process %d; may need to manually terminate", cpid);
+           }
+           return quit(c);
+       }
+       if (ispipestart || c->current.term == BG) {
+           pushbgid(jobid);
+           return 1;
+       }
+       if (c->current.term != PIPE && !runfg(jobid)) return quit(c);
+   }
+
+   if (status != EXIT_SUCCESS) {
+       if (!islist) return quit(c);
+       if (c->current.term == AND) return clear(c);
+   } else if (c->current.term == OR) return clear(c);
+
    return 1;
 }
index c1e2b76bbea6aedbaa05e555f969fca2f58b2035..4d658722d82abadea85964e3a488da7499d98437 100644 (file)
@@ -39,6 +39,12 @@ void initsignals(void) {
    sigaddset(&shellsigmask, SIGTSTP);
    sigaddset(&shellsigmask, SIGTTIN);
    sigaddset(&shellsigmask, SIGTTOU);
+   if (sigprocmask(SIG_BLOCK, &shellsigmask, &childsigmask) == -1) exit(errno);
+
+   defaultaction = (struct sigaction){.sa_handler = SIG_DFL};
+   setsig(SIGTSTP, &defaultaction);
+   setsig(SIGTTOU, &defaultaction);
+   setsig(SIGTTIN, &defaultaction);
 
    action = (struct sigaction){.sa_handler = sigwinchhandler};
    setsig(SIGWINCH, &action);
@@ -50,11 +56,4 @@ void initsignals(void) {
 
    action = (struct sigaction){.sa_handler = siginthandler};
    setsig(SIGINT, &action);
-
-   defaultaction = (struct sigaction){.sa_handler = SIG_DFL};
-   setsig(SIGTSTP, &defaultaction);
-   setsig(SIGTTOU, &defaultaction);
-   setsig(SIGTTIN, &defaultaction);
-
-   if (sigprocmask(SIG_BLOCK, &shellsigmask, &childsigmask) == -1) exit(errno);
 }
index cc3dc8e5a91966fc299fe84a793880c311d361d1..f7de7142fa60dbd2870baa52b253b2a08221af6a 100644 (file)
@@ -22,16 +22,13 @@ void note(char *fmt, ...) {
    va_list args;
 
    fprintf(stderr, "%s: ", argvector[0]);
-
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
-
    if (errno) {
        fprintf(stderr, ": %s", strerror(errno));
        errno = 0;
    }
-
    putchar('\n');
 }
 
@@ -39,13 +36,10 @@ void fatal(char *fmt, ...) {
    va_list args;
 
    fprintf(stderr, "%s: ", argvector[0]);
-
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
-
    if (errno) fprintf(stderr, ": %s", strerror(errno));
-
    putchar('\n');
 
    exit(errno);
@@ -144,7 +138,7 @@ char *quoted(char *token) {
        if (degree < SINGLE) degree = SINGLE;
        break;
    case '\'':
-       degree |= DOUBLE;
+       if (degree == NONE || degree == SINGLE) ++degree;
    }
    if (degree == NONE) return token;
 
@@ -153,7 +147,7 @@ char *quoted(char *token) {
    *p++ = quote;
    strcpy(p, token);
    for (q = p; *q; ++q);
-   if (degree & DOUBLE) for (; *p; ++p) switch (*p)
+   if (degree != SINGLE) for (; *p; ++p) switch (*p)
    case '$':
    case '~':
    case '"':
@@ -162,8 +156,8 @@ char *quoted(char *token) {
            memmove(p + 1, p, ++q - p);
            *p++ = '\\';
        }
-   *p++ = quote;
-   *p++ = '\0';
+   *q++ = quote;
+   *q++ = '\0';
 
    return buffer;
 }