]> Trent Huber's Code - thus.git/commitdiff
Memory optimization for file redirect structs, clean up code
authorTrent Huber <trentmhuber@gmail.com>
Tue, 12 Aug 2025 02:45:32 +0000 (22:45 -0400)
committerTrent Huber <trentmhuber@gmail.com>
Tue, 12 Aug 2025 02:45:32 +0000 (22:45 -0400)
21 files changed:
src/builtin/alias.c
src/builtin/alias.h
src/builtin/build.c
src/builtin/fg.c
src/builtin/fg.h
src/builtin/source.c
src/context.h
src/history.c
src/history.h
src/input.c
src/input.h
src/job.c
src/job.h
src/main.c
src/options.c
src/parse.c
src/parse.h
src/run.c
src/run.h
src/utils.c
src/utils.h

index 22d57234f043ba6242fd068cb2a088848546d3e9..49c9100a18d2cc5da18d79d33c05ca45a4ee526e 100644 (file)
@@ -3,8 +3,8 @@
 #include <string.h>
 
 #include "builtin.h"
-#include "input.h"
 #include "context.h"
+#include "input.h"
 #include "parse.h"
 #include "utils.h"
 
@@ -18,22 +18,22 @@ static struct {
    size_t size;
 } aliases;
 
-void applyaliases(struct cmd *cmd) {
-   struct cmd *p;
+void applyaliases(struct command *command) {
+   struct command *c;
    char **end;
    size_t i, l, a;
    struct context *context;
 
-   p = cmd;
+   c = command;
 
-   end = p->args;
-   while ((p = p->next)) if (p->args) end = p->args;
+   end = c->args;
+   while ((c = c->next)) if (c->args) end = c->args;
    if (end) while (*end) ++end;
 
-   while ((p = cmd = cmd->next)) {
-       if (!cmd->args) continue;
+   while ((c = command = command->next)) {
+       if (!command->args) continue;
        for (i = 0; i < aliases.size; ++i)
-           if (strcmp(aliases.entries[i].lhs, *cmd->args) == 0) break;
+           if (strcmp(aliases.entries[i].lhs, *command->args) == 0) break;
        if (i == aliases.size) continue;
        context = &aliases.entries[i].context;
 
@@ -45,9 +45,10 @@ void applyaliases(struct cmd *cmd) {
        parse(context);
 
        for (a = 0; context->tokens[a]; ++a);
-       memmove(cmd->args + a, cmd->args + 1, (end - cmd->args + 1) * sizeof*cmd->args);
-       memcpy(cmd->args, context->tokens, a * sizeof*cmd->args);
-       while ((p = p->next)) p->args += a - 1;
+       memmove(command->args + a, command->args + 1,
+               (end - command->args + 1) * sizeof*command->args);
+       memcpy(command->args, context->tokens, a * sizeof*command->args);
+       while ((c = c->next)) c->args += a - 1;
    }
 }
 
index 02b4643ae553e990b60996828f205be7d4d4b1ad..b84318f364713e22ba103452c541633ee8191531 100644 (file)
@@ -1 +1 @@
-void applyaliases(struct cmd *cmd);
+void applyaliases(struct command *command);
index 9f526507b759abcf8c49dcfa0d34e03a24885d9b..9a5c843eb08fba3457f7a8d0c0d28cc065cf61f2 100644 (file)
@@ -13,7 +13,13 @@ int main(void) {
    int listfd, l;
    DIR *dir;
    size_t i, offset;
-   struct cbsfile files[1 + MAXBUILTINS + 1];
+
+   /* The three extra files correspond to:
+    * 1) output file (../libbuiltin.a)
+    * 2) list.c
+    * 3) builtin.c */
+   struct cbsfile files[3 + MAXBUILTINS + 1];
+
    struct dirent *entry;
    char *name, *identifier;
 
@@ -35,7 +41,7 @@ int main(void) {
        if (strcmp(entry->d_name, "build.c") == 0) continue;
        if (!(name = strrchr(entry->d_name, '.')) || strcmp(name, ".c") != 0)
            continue;
-       if (i == 1 + MAXBUILTINS + 1)
+       if (i == 3 + MAXBUILTINS + 1)
            errx(EXIT_FAILURE, "Unable to add built-in `%s', maximum reached (%d)",
                 name, MAXBUILTINS);
        if (!(name = strdup(entry->d_name)))
@@ -48,7 +54,7 @@ int main(void) {
    }
    if (errno) err(EXIT_FAILURE, "Unable to read from current directory");
    files[i] = (struct cbsfile){NULL};
-   
+
    identifier = "struct builtin builtins[] = {";
    l = (int)strlen(identifier);
    dprintf(listfd, "\n%s", identifier);
index c471f46691c88f23b44545f796320ccf8f783179..cdff59b607dbb8d8790bee680eabae67e4caec7d 100644 (file)
@@ -1,4 +1,3 @@
-#include <err.h>
 #include <limits.h>
 #include <signal.h>
 #include <stdio.h>
@@ -12,8 +11,9 @@
 #include "utils.h"
 
 static int fgstatus;
+struct termios canonical;
+static struct termios raw;
 struct sigaction sigchld, sigdfl;
-struct termios raw, canonical;
 
 static int setconfig(struct termios *mode) {
    if (tcsetattr(STDIN_FILENO, TCSANOW, mode) == -1) {
@@ -39,9 +39,9 @@ void setsigchld(struct sigaction *act) {
        fatal("Unable to install SIGCHLD handler");
 }
 
-void initterm(void) {
+void initfg(void) {
    if (tcgetattr(STDIN_FILENO, &canonical) == -1)
-       err(EXIT_FAILURE, "Unable to get default termios config");
+       fatal("Unable to get default termios config");
    cfmakeraw(&raw);
    if (!setconfig(&raw)) exit(EXIT_FAILURE);
 
@@ -71,15 +71,15 @@ void waitfg(struct job job) {
     * the waitpid() below is just to block the current thread of execution until
     * the foreground process has been reaped */
    setsigchld(&sigchld);
-   while (waitpid(job.id, NULL, 0) != -1);
-   errno = 0;
+   waitpid(job.id, NULL, 0);
+   errno = 0; // waitpid() will set errno
    setsigchld(&sigdfl);
 
    if (sigaction(SIGTTOU, &(struct sigaction){{SIG_IGN}}, NULL) == -1
        || tcsetpgrp(STDIN_FILENO, getpgrp()) == -1
        || sigaction(SIGTTOU, &sigdfl, NULL) == -1) {
        note("Unable to reclaim foreground; terminating");
-       deinitialize();
+       deinit();
        exit(EXIT_FAILURE);
    }
    if (tcgetattr(STDIN_FILENO, &job.config) == -1)
@@ -101,7 +101,7 @@ void waitfg(struct job job) {
    }
 }
 
-void deinitterm(void) {
+void deinitfg(void) {
    setconfig(&canonical);
 }
 
@@ -126,5 +126,8 @@ BUILTINSIG(fg) {
        return EXIT_FAILURE;
    }
 
-   return setfg(*job) ? (waitfg(*job), EXIT_SUCCESS) : EXIT_FAILURE;
+   if (!setfg(*job)) return EXIT_FAILURE;
+   waitfg(*job);
+
+   return EXIT_SUCCESS;
 }
index da4eff73217739bdf58d278f5ad9cd4a8054fcdd..dd98ff57dd44422d9764e4c91abe2a21ce6e0cf6 100644 (file)
@@ -1,8 +1,8 @@
+extern struct termios canonical;
 extern struct sigaction sigchld, sigdfl;
-extern struct termios raw, canonical;
 
 void setsigchld(struct sigaction *act);
-void initterm(void);
+void initfg(void);
 int setfg(struct job job);
 void waitfg(struct job job);
-void deinitterm(void);
+void deinitfg(void);
index 90f15cc03407d2f02ea8239958298f81f03f9fe4..7190f84bc684558538f1a6f487c1c266a27b4b6f 100644 (file)
@@ -3,8 +3,8 @@
 #include <stdlib.h>
 
 #include "builtin.h"
-#include "input.h"
 #include "context.h"
+#include "input.h"
 #include "parse.h"
 #include "run.h"
 #include "utils.h"
index 87e9d64c424dbefe63ce608acb904d9062dd2215..4fa355e184a930666bd56a459fd667c6cef3a045 100644 (file)
@@ -1,9 +1,11 @@
-#define MAXCHARS 500
-#define MAXCMDS (MAXCHARS + 1) / 2
-#define MAXRDS (MAXCHARS / 3)
+#define MAXCHARS 1000
+#define MAXCOMMANDS (MAXCHARS + 1) / 2
+#define MAXREDIRECTS (MAXCHARS / 3)
 
-enum accessmode {
-   END,
+#define PIPELINE(name) struct context *name(struct context *context)
+
+enum access {
+   NONE,
    READ = '<',
    READWRITE,
    WRITE = '>',
@@ -11,9 +13,10 @@ enum accessmode {
 };
 
 struct redirect {
-   enum accessmode mode;
+   enum access mode;
    int oldfd, newfd;
    char *oldname;
+   struct redirect *next;
 };
 
 enum terminator {
@@ -24,20 +27,24 @@ enum terminator {
    OR,
 };
 
-struct cmd {
+struct command {
    char **args;
-   struct redirect *r, rds[MAXRDS + 1];
+   struct redirect *r;
    enum terminator term;
    int pipe[2];
-   struct cmd *prev, *next;
+   struct command *prev, *next;
 };
 
 struct context {
-   char buffer[MAXCHARS + 1 + 1], *tokens[MAXCMDS + 1], *script, *string;
    struct {
-       char *m;
-       size_t l;
-   } map;
-   struct cmd cmds[MAXCMDS + 1];
-   Input input;
+       char *string, *script;
+       struct {
+           char *map;
+           size_t len;
+       };
+       PIPELINE((*input));
+   };
+   char buffer[MAXCHARS + 1 + 1], *tokens[MAXCOMMANDS + 1];
+   struct redirect redirects[MAXREDIRECTS + 1];
+   struct command commands[1 + MAXCOMMANDS];
 };
index 093c95c38a6017455c56923898a5c934f94d5848..945064d8f846842ecf110bf6be300b6c84a918f8 100644 (file)
@@ -4,11 +4,12 @@
 #include <string.h>
 #include <sys/errno.h>
 
-#include "input.h"
 #include "context.h"
+#include "input.h"
 #include "utils.h"
 
 #define MAXHIST 100
+
 #define INC(v) (history.v = (history.v + 1) % (MAXHIST + 1))
 #define DEC(v) (history.v = (history.v + MAXHIST) % (MAXHIST + 1))
 
@@ -17,9 +18,9 @@ static struct {
    size_t b, c, t;
 } history;
 
-void readhistory(void) {
+void inithistory(void) {
    FILE *file;
-   
+
    if (!catpath(home, ".ashhistory", history.path)) exit(EXIT_FAILURE);
    if (!(file = fopen(history.path, "r"))) {
        if (errno == ENOENT) return;
@@ -52,7 +53,7 @@ void sethistory(char *buffer) {
    *history.entries[history.t] = '\0';
 }
 
-void writehistory(void) {
+void deinithistory(void) {
    FILE *file;
 
    if (!(file = fopen(history.path, "w"))) {
index 60b4bac9eff0d1ad4a04921c5c461d089d154fad..4c2428d4742ca98e1cc16228b3f768e57f6ccbd5 100644 (file)
@@ -1,4 +1,4 @@
-void readhistory(void);
+void inithistory(void);
 int gethistory(char direction, char *buffer);
 void sethistory(char *buffer);
-void writehistory(void);
+void deinithistory(void);
index 559053f3a0481d75d7354fec75d9c0e9160b2c81..0e5dc41a9c003f63774e82c8173ae2f75fb5b36f 100644 (file)
@@ -7,22 +7,21 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include "context.h"
 #include "history.h"
 #include "input.h"
-#include "context.h"
 #include "utils.h"
 
-#define DEFAULTPROMPT ">"
-
-INPUT(stringinput) {
+PIPELINE(stringinput) {
    char *start;
    size_t l;
 
    if (!*context->string) {
-       if (context->script && munmap(context->map.m, context->map.l) == -1)
+       if (context->script && munmap(context->map, context->len) == -1)
            note("Unable to unmap memory associated with `%s'", context->script);
        return NULL;
    }
+
    start = context->string;
    while (*context->string && *context->string != '\n') ++context->string;
    l = context->string - start;
@@ -31,6 +30,7 @@ INPUT(stringinput) {
        note("Line too long, exceeds %d character limit", MAXCHARS);
        return NULL;
    }
+
    strncpy(context->buffer, start, l);
    context->buffer[l] = ';';
    context->buffer[l + 1] = '\0';
@@ -38,7 +38,7 @@ INPUT(stringinput) {
    return context;
 }
 
-INPUT(scriptinput) {
+PIPELINE(scriptinput) {
    int fd;
    struct stat sstat;
 
@@ -50,8 +50,9 @@ INPUT(scriptinput) {
        note("Unable to stat `%s'", context->script);
        return NULL;
    }
-   if ((context->map.l = sstat.st_size) == 0) return NULL;
-   if ((context->string = context->map.m = mmap(NULL, context->map.l, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
+   if ((context->len = sstat.st_size) == 0) return NULL;
+   if ((context->map = mmap(NULL, context->len, PROT_READ, MAP_PRIVATE, fd, 0))
+       == MAP_FAILED) {
        note("Unable to memory map `%s'", context->script);
        return NULL;
    }
@@ -59,28 +60,29 @@ INPUT(scriptinput) {
        note("Unable to close `%s'", context->script);
        return NULL;
    }
+
+   context->string = context->map;
    context->input = stringinput;
 
    return context->input(context);
 }
 
-static size_t prompt(void) {
+static void prompt(void) {
    char *p;
 
-   if (!(p = getenv("PROMPT")) && setenv("PROMPT", p = DEFAULTPROMPT, 1) == -1)
+   if (!(p = getenv("PROMPT")) && setenv("PROMPT", p = ">", 1) == -1)
        note("Unable to update $PROMPT$ environment variable");
-   printf("%s ", p);
-   return strlen(p) + 1;
+   printf("\r%s ", p);
 }
 
-INPUT(userinput) {
+PIPELINE(userinput) {
    char *start, *cursor, *end;
    unsigned int c;
    int i;
    size_t oldlen, newlen;
 
    end = cursor = start = context->buffer;
-   *start = '\0';
+   *context->buffer = '\0';
    while (start == end) {
        prompt();
        while ((c = getchar()) != '\r') switch (c) {
@@ -98,7 +100,7 @@ INPUT(userinput) {
            break;
        case CTRLC:
            puts("^C\r");
-           *start = '\0';
+           *context->buffer = '\0';
            return context;
        case CTRLD:
            puts("^D\r");
@@ -106,7 +108,7 @@ INPUT(userinput) {
        case CLEAR:
            fputs("\033[H\033[J", stdout);
            prompt();
-           fputs(start, stdout);
+           fputs(context->buffer, stdout);
            continue;
        case ESCAPE:
            switch ((c = getchar())) {
@@ -122,16 +124,17 @@ INPUT(userinput) {
                switch ((c = getchar())) {
                case UP:
                case DOWN:
-                   oldlen = strlen(start);
-                   if (!gethistory(c, start)) continue;
-                   newlen = strlen(start);
+                   oldlen = strlen(context->buffer);
+                   if (!gethistory(c, context->buffer)) continue;
+                   newlen = strlen(context->buffer);
                    end = cursor = start + newlen;
 
                    putchar('\r');
                    prompt();
-                   fputs(start, stdout);
+                   fputs(context->buffer, stdout);
                    for (i = oldlen - newlen; i > 0; --i) putchar(' ');
                    for (i = oldlen - newlen; i > 0; --i) putchar('\b');
+
                    break;
                case LEFT:
                    if (cursor > start) putchar((--cursor, '\b'));
@@ -161,7 +164,14 @@ INPUT(userinput) {
        }
        puts("\r");
    }
-   sethistory(start);
+
+   while (*start == ' ') ++start;
+   if (start == end) {
+       *context->buffer = '\0';
+       return context;
+   }
+
+   sethistory(context->buffer);
 
    *end++ = ';';
    *end = '\0';
index 0b6dc8ecf03623261db80dc1455fec5c9128b6d7..7ba2dcfe746e40f46566e59c5365b1e5d09ac0d1 100644 (file)
@@ -1,7 +1,3 @@
-#define INPUT(name) struct context *name(struct context *context)
-
-typedef INPUT((*Input));
-
 enum {
    CTRLC = '\003',
    CTRLD,
@@ -18,6 +14,6 @@ enum {
    DEL = '\177',
 };
 
-INPUT(stringinput);
-INPUT(scriptinput);
-INPUT(userinput);
+PIPELINE(stringinput);
+PIPELINE(scriptinput);
+PIPELINE(userinput);
index 3829255a36556e784c126454cb88d639628a5074..9c02e8b2ca0ab50da8b4ea750316e2f5a710a4bd 100644 (file)
--- a/src/job.c
+++ b/src/job.c
@@ -1,6 +1,5 @@
 #include <string.h>
 #include <termios.h>
-// #include <stdio.h> // XXX
 
 #include "job.h"
 #include "utils.h"
@@ -16,6 +15,13 @@ static struct {
    struct joblink entries[MAXJOBS + 1], *active, *free;
 } jobs;
 
+void initjobs(void) {
+   size_t i;
+
+   for (i = 0; i < MAXJOBS - 1; ++i) jobs.entries[i].next = &jobs.entries[i + 1];
+   jobs.free = jobs.entries;
+}
+
 struct job *pushjob(struct job *job) {
    struct joblink *p;
 
@@ -29,10 +35,6 @@ struct job *pushjob(struct job *job) {
    return &p->job;
 }
 
-struct job *peekjob(void) {
-   return jobs.active ? &jobs.active->job : NULL;
-}
-
 struct job *pulljob(void) {
    struct joblink *p;
 
@@ -46,6 +48,10 @@ struct job *pulljob(void) {
    return &p->job;
 }
 
+struct job *peekjob(void) {
+   return jobs.active ? &jobs.active->job : NULL;
+}
+
 struct job *searchjobid(pid_t id) {
    struct joblink *p;
 
@@ -74,10 +80,3 @@ struct job *deletejobid(pid_t id) {
 
    return &p->job;
 }
-
-void initjobs(void) {
-   size_t i;
-
-   for (i = 0; i < MAXJOBS - 1; ++i) jobs.entries[i].next = &jobs.entries[i + 1];
-   jobs.free = jobs.entries;
-}
index f0432866da0097caada62d9f750e44613e988f56..f4777505d75b8e215626d015d021e7ad5765a7f4 100644 (file)
--- a/src/job.h
+++ b/src/job.h
@@ -9,10 +9,10 @@ struct job {
    enum jobtype type;
 };
 
+void initjobs(void);
 struct job *pushjob(struct job *job);
-struct job *peekjob(void);
 struct job *pulljob(void);
+struct job *peekjob(void);
 struct job *searchjobid(pid_t id);
 struct job *searchjobtype(enum jobtype);
 struct job *deletejobid(pid_t id);
-void initjobs(void);
index 982704f3da8acddb5fd02e964084f2035f5a596e..c6dc2021f0e53b40e06db08020fa4ac8cdc579b5 100644 (file)
@@ -1,7 +1,7 @@
 #include <stdlib.h>
 
-#include "input.h"
 #include "context.h"
+#include "input.h"
 #include "options.h"
 #include "parse.h"
 #include "run.h"
@@ -14,14 +14,14 @@ int main(int c, char **v) {
 
    options();
 
-   initialize();
+   init();
 
    if (login) config(".ashlogin");
-   if (interactive) config(".ashint");
+   if (interactive) config(".ashrc");
 
    while (run(parse(context.input(&context))));
 
-   deinitialize();
+   deinit();
 
    return EXIT_SUCCESS;
 }
index eb0e6db10353270d8839f09df9cc6fdb3954c53c..35f39a3125471cefb0eb56641e85b2f75ef759c3 100644 (file)
@@ -1,14 +1,13 @@
-#include <err.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 
-#include "input.h"
 #include "context.h"
+#include "input.h"
+#include "utils.h"
 
 int login, interactive, argc;
 char **argv;
-
 struct context context;
 
 static void usage(char *program, int code) {
@@ -40,11 +39,11 @@ void options(void) {
            login = 1;
            break;
        case ':':
-           warnx("Expected argument following `-%c'\n", optopt);
+           note("Expected argument following `-%c'\n", optopt);
            usage(*argv, EXIT_FAILURE);
        case '?':
        default:
-           warnx("Unknown command line option `-%c'\n", optopt);
+           note("Unknown command line option `-%c'\n", optopt);
            usage(*argv, EXIT_FAILURE);
        }
        if (opt == 'c') break;
index 10ac748b5bfe7cbbf66acb14cdb816ca5a011b37..e36637e1ea3dc6b01e7eb786adfa39a46b790103 100644 (file)
@@ -3,34 +3,37 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "input.h"
 #include "context.h"
+#include "input.h"
 #include "options.h"
 #include "utils.h"
 
-static void initcmd(struct cmd *cmd) {
-   cmd->args = NULL;
-   cmd->r = cmd->rds;
-   cmd->r->mode = END;
-   cmd->prev = cmd - 1;
-   cmd->next = NULL;
+static void initcommand(struct command *c) {
+   c->args = NULL;
+   c->r = NULL;
+   c->prev = c - 1;
+   c->next = NULL;
 }
 
-struct context *parse(struct context *context) {
+PIPELINE(parse) {
    char *b, **t, *name, *value, *stlend, *p, *end, *env;
-   struct cmd *c;
+   struct redirect *r, *q;
+   struct command *c;
    long l;
    int e, offset;
    
    if (!context) return NULL;
+
    b = context->buffer;
    t = context->tokens;
-   c = context->cmds + 1;
-   context->cmds->next = NULL;
+   r = context->redirects;
+   c = context->commands + 1;
+   context->commands->next = NULL;
    *t = value = name = NULL;
-   for (initcmd(c); *b; ++b) switch (*b) {
+   r->mode = NONE;
+   for (initcommand(c); *b; ++b) switch (*b) {
    default:
-       if (c->r->mode) break;
+       if (r->mode) break;
        if (!c->args) c->args = t;
        if (!*(b - 1)) {
            if (!name) *t++ = b; else if (!value) value = b;
@@ -38,25 +41,29 @@ struct context *parse(struct context *context) {
        break;
    case '<':
    case '>':
-       if (c->r->mode) {
+       if (r->mode) {
            note("File redirections should be separated by spaces");
            return context;
        }
-       c->r->newfd = *b == '>';
+       if (r - context->redirects == MAXREDIRECTS) {
+           note("Too many file redirects, exceeds %d redirect limit", MAXREDIRECTS);
+           return context;
+       }
+       if (!c->r) c->r = r;
        if (*(b - 1)) {
            if (c->args == --t) c->args = NULL;
            if ((l = strtol(*t, &stlend, 10)) < 0 || l > INT_MAX || stlend != b) {
                note("Invalid value for a file redirection");
                return context;
            }
-           c->r->newfd = l;
-       }
-       c->r->mode = *b;
+           r->newfd = l;
+       } else r->newfd = *b == '>';
+       r->mode = *b;
        if (*(b + 1) == '>') {
-           ++c->r->mode;
+           ++r->mode;
            ++b;
        }
-       c->r->oldname = b + 1;
+       r->oldname = b + 1;
        if (*(b + 1) == '&') ++b;
        break;
    case '"':
@@ -95,6 +102,7 @@ struct context *parse(struct context *context) {
        *end = '\0';
        memmove(p, p + 1, end - p);
        --b;
+
        break;
    case '=':
        name = *--t;
@@ -130,6 +138,7 @@ struct context *parse(struct context *context) {
        memmove(b + offset, b, end - b + 1);
        strncpy(p, env, e);
        b += offset - 1;
+
        break;
    case '~':
        if (!*(b - 1)) {
@@ -147,26 +156,27 @@ struct context *parse(struct context *context) {
    case '|':
    case ';':
        if (name && *c->args == name) c->args = NULL;
-       if (c->args || c->rds->mode) {
+       if (c->args || c->r) {
            if ((c->term = *b) == *(b + 1) && (*b == '&' || *b == '|')) {
                ++c->term;
                *b++ = '\0';
            }
            *b = '\0';
-           if (c->r->mode) (++c->r)->mode = END;
-           for (c->r = c->rds; c->r->mode; ++c->r) if (*c->r->oldname == '&') {
-               if ((l = strtol(++c->r->oldname, &stlend, 10)) < 0
-                   || l > INT_MAX || *stlend) {
+
+           if (r->mode) {
+               r++->next = NULL;
+               r->mode = NONE;
+           } else if (c->r) (r - 1)->next = NULL;
+           for (q = c->r; q; q = q->next) if (*q->oldname == '&') {
+               if ((l = strtol(++q->oldname, &stlend, 10)) < 0 || l > INT_MAX || *stlend) {
                    note("Incorrect syntax for file redirection");
                    return context;
                }
-               c->r->oldfd = l;
-               c->r->oldname = NULL;
+               q->oldfd = l;
+               q->oldname = NULL;
            }
-           c->r = c->rds;
-           c->next = c + 1;
 
-           initcmd(++c);
+           initcommand(c = c->next = c + 1);
            *t++ = NULL;
        }
    case ' ':
@@ -178,7 +188,10 @@ struct context *parse(struct context *context) {
            }
            value = name = NULL;
        }
-       if (c->r->mode) (++c->r)->mode = END;
+       if (r->mode) {
+           r = r->next = r + 1;
+           r->mode = NONE;
+       }
    }
 
    (--c)->next = NULL;
@@ -192,6 +205,7 @@ struct context *parse(struct context *context) {
        break;
    }
 
-   context->cmds->next = context->cmds + 1;
+   context->commands->next = context->commands + 1;
+
    return context;
 }
index c76ce9fde323f254eb3f2f5e3dbd6a9df2abffd3..377fc376dd3378f0569bbc5f3183bd25d9166da8 100644 (file)
@@ -1 +1 @@
-struct context *parse(struct context *context);
+PIPELINE(parse);
index add19cc758f9a1345220d8cd2dea0abb5ff26c64..69c8dbae3e3a568739970d4ffe3c863a42ac23d7 100644 (file)
--- a/src/run.c
+++ b/src/run.c
@@ -3,31 +3,32 @@
 #include <signal.h>
 #include <stdlib.h>
 #include <sys/errno.h>
+#include <sys/wait.h>
 #include <termios.h>
 #include <unistd.h>
-// #include <stdio.h> // XXX
 
 #include "builtin.h"
-#include "input.h"
 #include "context.h"
 #include "alias.h"
+#include "input.h"
 #include "job.h"
 #include "fg.h"
 #include "utils.h"
 
-static int closepipe(struct cmd *cmd) {
+static int closepipe(struct command *command) {
    int result;
 
-   result = close(cmd->pipe[0]) == 0;
-   result &= close(cmd->pipe[1]) == 0;
-   if (!result) note("Unable to close `%s' pipe", *cmd->args);
+   result = close(command->pipe[0]) == 0;
+   result &= close(command->pipe[1]) == 0;
+   if (!result) note("Unable to close `%s' pipe", *command->args);
+
    return result;
 }
 
 static void redirectfiles(struct redirect *r) {
    int mode, fd;
 
-   for (; r->mode; ++r) {
+   for (; r; r = r->next) {
        if (r->oldname) {
            switch (r->mode) {
            case READ:
@@ -55,105 +56,111 @@ static void redirectfiles(struct redirect *r) {
    }
 }
 
-static void exec(struct cmd *cmd) {
+static void exec(struct command *c) {
    char cwd[PATH_MAX];
 
-   redirectfiles(cmd->rds);
-   if (isbuiltin(cmd->args)) exit(status);
-   execvp(*cmd->args, cmd->args);
+   redirectfiles(c->r);
+
+   if (isbuiltin(c->args)) exit(status);
+   execvp(*c->args, c->args);
    if (!getcwd(cwd, PATH_MAX)) fatal("Unable to check current working directory");
-   execvP(*cmd->args, cwd, cmd->args);
-   fatal("Couldn't find `%s' command", *cmd->args);
+   execvP(*c->args, cwd, c->args);
+
+   fatal("Couldn't find `%s' command", *c->args);
 }
 
-int run(struct context *context) {
-   struct cmd *cmd;
+PIPELINE(run) {
+   struct command *c;
    int ispipe, ispipestart, ispipeend;
    pid_t cpid, jobid;
    struct job job;
 
-   if (!context) return 0;
+   if (!context) return NULL;
 
-   applyaliases(cmd = context->cmds);
+   applyaliases(c = context->commands);
 
    setsigchld(&sigdfl);
 
-   while ((cmd = cmd->next)) {
-       if (!cmd->args) {
-           if (!cmd->r->mode) break;
-           if ((cpid = fork()) == -1) {
-               note("Unable to create child process");
-               break;
-           } else if (cpid == 0) {
-               redirectfiles(cmd->r);
-               exit(EXIT_SUCCESS);
-           }
-           continue;
-       }
-
-       ispipe = cmd->term == PIPE || cmd->prev->term == PIPE;
-       ispipestart = ispipe && cmd->prev->term != PIPE;
-       ispipeend = ispipe && cmd->term != PIPE;
+   while ((c = c->next)) if (c->args) {
+       ispipe = c->term == PIPE || c->prev->term == PIPE;
+       ispipestart = ispipe && c->prev->term != PIPE;
+       ispipeend = ispipe && c->term != PIPE;
 
        if (ispipe) {
-           if (!ispipeend && pipe(cmd->pipe) == -1) {
+           if (!ispipeend && pipe(c->pipe) == -1) {
                note("Unable to create pipe");
-               if (!ispipestart) closepipe(cmd->prev);
+               if (!ispipestart) closepipe(c->prev);
                break;
            }
            if ((jobid = cpid = fork()) == -1) {
-               note("Unable to create child process");
+               note("Unable to fork child process");
                break;
            } else if (cpid == 0) {
                if (!ispipestart) {
-                   if (dup2(cmd->prev->pipe[0], 0) == -1)
-                       fatal("Unable to duplicate read end of `%s' pipe", *cmd->prev->args);
-                   if (!closepipe(cmd->prev)) exit(EXIT_FAILURE);
+                   if (dup2(c->prev->pipe[0], 0) == -1)
+                       fatal("Unable to duplicate read end of `%s' pipe", *c->prev->args);
+                   if (!closepipe(c->prev)) exit(EXIT_FAILURE);
                }
                if (!ispipeend) {
-                   if (dup2(cmd->pipe[1], 1) == -1)
-                       fatal("Unable to duplicate write end of `%s' pipe", *cmd->args);
-                   if (!closepipe(cmd)) exit(EXIT_FAILURE);
+                   if (dup2(c->pipe[1], 1) == -1)
+                       fatal("Unable to duplicate write end of `%s' pipe", *c->args);
+                   if (!closepipe(c)) exit(EXIT_FAILURE);
                }
-               exec(cmd);
+               exec(c);
            }
            if (!ispipestart) {
-               closepipe(cmd->prev);
+               closepipe(c->prev);
                jobid = (ispipeend ? pulljob : peekjob)()->id;
            }
-       } else if (!cmd->rds->mode && isbuiltin(cmd->args)) cpid = 0;
+       } else if (!c->r && isbuiltin(c->args)) cpid = 0;
        else if ((jobid = cpid = fork()) == -1) {
-           note("Unable to create child process");
+           note("Unable to fork child process");
            break;
-       } else if (cpid == 0) exec(cmd);
+       } else if (cpid == 0) exec(c);
 
        if (cpid) {
            if (setpgid(cpid, jobid) == -1) {
                if (errno != ESRCH) {
-                   note("Unable to set pgid of `%s' command to %d", *cmd->args, jobid);
+                   note("Unable to set pgid of `%s' command to %d", *c->args, jobid);
                    if (kill(cpid, SIGKILL) == -1)
                        note("Unable to kill process %d; may need to manually terminate", cpid);
                }
                break;
            }
            job = (struct job){.id = jobid, .config = canonical, .type = BACKGROUND};
-           if (ispipestart || cmd->term == BG) {
+           if (ispipestart || c->term == BG) {
                if (!pushjob(&job)) {
                    note("Unable to add job to background; too many background jobs");
-                   if (ispipestart) closepipe(cmd);
+                   if (ispipestart) closepipe(c);
                    break;
                }
-           } else if (cmd->term != PIPE) {
+           } else if (c->term != PIPE) {
                if (!setfg(job)) break;
                waitfg(job);
            }
        }
 
-       if (cmd->term == AND && status != EXIT_SUCCESS) break;
-       if (cmd->term == OR && status == EXIT_SUCCESS) break;
+       if (c->term == AND && status != EXIT_SUCCESS) break;
+       if (c->term == OR && status == EXIT_SUCCESS) break;
+   } else {
+       if (c->term == AND || c->term == PIPE || c->term == OR) {
+           note("Expected command");
+           break;
+       }
+       if (!c->r) break;
+
+       if ((cpid = fork()) == -1) {
+           note("Unable to fork child process");
+           break;
+       } else if (cpid == 0) {
+           redirectfiles(c->r);
+           exit(EXIT_SUCCESS);
+       }
+       waitpid(cpid, NULL, 0);
+       errno = 0; // waitpid() might set errno
    }
 
    setsigchld(&sigchld);
 
-   return 1;
+   return context;
 }
index 4f79635c29b61edeb7ebfeeed7edff94c3fa25c0..e7eaa0802d87f36fc5df4bcfc495f904ee33b5db 100644 (file)
--- a/src/run.h
+++ b/src/run.h
@@ -1,3 +1,3 @@
 extern int status;
 
-int run(struct context *context);
+PIPELINE(run);
index dfcb36f19b476df8039c83608fd05c64ce4cd585..b95bcf9886c84ba160b7b13b3ffa1e423e9fad87 100644 (file)
@@ -21,7 +21,7 @@ void note(char *fmt, ...) {
    va_start(args, fmt);
    (errno ? vwarn : vwarnx)(fmt, args);
    va_end(args);
-   putchar('\r');
+   putc('\r', stderr);
    errno = 0;
 }
 
@@ -30,27 +30,26 @@ void fatal(char *fmt, ...) {
    va_start(args, fmt);
    (errno ? vwarn : vwarnx)(fmt, args);
    va_end(args);
-   putchar('\r');
+   putc('\r', stderr);
    exit(EXIT_FAILURE);
 }
 
-void initialize(void) {
+void init(void) {
    char *shlvlstr, buffer[19 + 1];
    long shlvl;
 
-   initterm();
-
    if (!(home = getenv("HOME")))
        fatal("Unable to locate user's home directory, $HOME$ not set");
 
    if (!(shlvlstr = getenv("SHLVL"))) shlvlstr = "0";
    if ((shlvl = strtol(shlvlstr, NULL, 10)) < 0) shlvl = 0;
-   sprintf(shlvlstr = buffer, "%ld", shlvl + 1);
-   if (setenv("SHLVL", shlvlstr, 1) == -1)
+   sprintf(buffer, "%ld", shlvl + 1);
+   if (setenv("SHLVL", buffer, 1) == -1)
        note("Unable to update $SHLVL$ environment variable");
 
-   if (interactive) readhistory();
+   initfg();
    initjobs();
+   if (interactive) inithistory();
 }
 
 char *catpath(char *dir, char *filename, char *buffer) {
@@ -69,8 +68,7 @@ char *catpath(char *dir, char *filename, char *buffer) {
    return buffer;
 }
 
-void deinitialize(void) {
-   deinitterm();
-
-   if (interactive) writehistory();
+void deinit(void) {
+   if (interactive) deinithistory();
+   deinitfg();
 }
index 38848322665a57d7b0ac62d2bab87a3094bafc08..c2884c06963d1b458950078a984007da9e0cfc85 100644 (file)
@@ -3,6 +3,6 @@ extern int status;
 
 void note(char *fmt, ...);
 void fatal(char *fmt, ...);
-void initialize(void);
+void init(void);
 char *catpath(char *dir, char *filename, char *buffer);
-void deinitialize(void);
+void deinit(void);