]> Trent Huber's Code - thus.git/commitdiff
Major refactoring, cleaning
authorTrent Huber <trentmhuber@gmail.com>
Fri, 18 Jul 2025 07:32:32 +0000 (03:32 -0400)
committerTrent Huber <trentmhuber@gmail.com>
Fri, 18 Jul 2025 07:32:32 +0000 (03:32 -0400)
22 files changed:
build.c
src/builtins.c
src/config.h [new file with mode: 0644]
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/options.h
src/parse.c [moved from src/lex.c with 78% similarity]
src/parse.h [moved from src/lex.h with 89% similarity]
src/run.c
src/run.h
src/stack.c
src/stack.h
src/term.c [deleted file]
src/term.h [deleted file]
src/utils.c
src/utils.h

diff --git a/build.c b/build.c
index aaecd9d8d9257ce0ce8310a42adeeb687466e5b1..d84fbf4c7f6da803a5f3b9910515343dfd1de39c 100644 (file)
--- a/build.c
+++ b/build.c
@@ -3,15 +3,14 @@
 #define SRCDIR "src/"
 #define SRC \
    SRCDIR "builtins", \
-   SRCDIR "history", \
    SRCDIR "input", \
+   SRCDIR "history", \
    SRCDIR "job", \
-   SRCDIR "lex", \
-   SRCDIR "options", \
+   SRCDIR "parse", \
    SRCDIR "main", \
+   SRCDIR "options", \
    SRCDIR "run", \
    SRCDIR "stack", \
-   SRCDIR "term", \
    SRCDIR "utils"
 #define BINDIR "bin/"
 #define ASH BINDIR "ash"
index f42c54265dba6a62f1700703432a08edf2723bf4..5ec4be3a68939d60cc59af5240d6864aa8b49e13 100644 (file)
@@ -1,4 +1,3 @@
-#include <err.h>
 #include <limits.h>
 #include <signal.h>
 #include <stdio.h>
@@ -11,6 +10,7 @@
 #include "job.h"
 #include "stack.h"
 #include "term.h"
+#include "utils.h"
 
 #define BUILTINSIG(name) int name(char **tokens)
 
@@ -19,10 +19,10 @@ struct builtin {
    BUILTINSIG((*func));
 };
 
-BUILTINSIG(cd) {
+BUILTINSIG(cd) { // TODO: Affect $PWD$ env var
    if (!tokens[1]) return 1;
    if (chdir(tokens[1]) != -1) return 0;
-   warn("Unable to change directory to `%s'", tokens[1]);
+   note("Unable to change directory to `%s'", tokens[1]);
    return 1;
 }
 
@@ -34,16 +34,16 @@ BUILTINSIG(fg) {
        errno = 0;
        if ((jobid = strtol(tokens[1], NULL, 10)) == LONG_MAX && errno
            || jobid <= 0) {
-           warn("Invalid process group id");
+           note("Invalid process group id");
            return 1;
        }
        if (!(job = findjob((pid_t)jobid))) {
-           warnx("Unable to find process group %d", (pid_t)jobid);
+           note("Unable to find process group %d", (pid_t)jobid);
            return 1;
        }
        job = deletejob();
    } else if (!(job = pull(&jobs))) {
-       warnx("No processes to bring into the foreground");
+       note("No processes to bring into the foreground");
        return 1;
    }
    if (!setfg(*job)) return 1;
@@ -60,33 +60,33 @@ BUILTINSIG(bg) {
        errno = 0;
        if ((jobid = strtol(tokens[1], NULL, 10)) == LONG_MAX && errno
            || jobid <= 0) {
-           warn("Invalid job id");
+           note("Invalid job id");
            return 1;
        }
        if (!(job = findjob((pid_t)jobid))) {
-           warnx("Unable to find job %d", (pid_t)jobid);
+           note("Unable to find job %d", (pid_t)jobid);
            return 1;
        }
        if (job->type == BACKGROUND) {
-           warnx("Job %d already in background", (pid_t)jobid);
+           note("Job %d already in background", (pid_t)jobid);
            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");
+           note("No suspended jobs to run in background");
            return 1;
        }
    }
    job = deletejob();
 
    if (!(push(&jobs, job))) {
-       warnx("Unable to add job to background; too many jobs");
+       note("Unable to add job to background; too many jobs");
        return 1;
    }
    if (killpg(job->id, SIGCONT) == -1) {
-       warn("Unable to wake up suspended process group %d", job->id);
+       note("Unable to wake up suspended process group %d", job->id);
        return 1;
    }
    job->type = BACKGROUND;
diff --git a/src/config.h b/src/config.h
new file mode 100644 (file)
index 0000000..add21bf
--- /dev/null
@@ -0,0 +1,10 @@
+#define HISTORYFILE ".ashhistory"
+#define INTERACTIVEFILE ".ashinteractive"
+#define LOGINFILE ".ashlogin"
+
+#define MAXCHARS 1000 // Maximum number of character per line
+#define MAXCMDS 100 // Maximum number of commands per line
+#define MAXHIST 100 // Maximum number of entries to store in history file
+#define MAXJOBS 100 // Maximum number of suspended/background jobs at any time
+#define MAXPATH 100 // Maximum number of character for a file path
+#define MAXRDS 10 // Maximum number of file redirects per command
index ca39b45b04cdea5e6bc0785776500f0c27bcf0c4..121b9a61e89a67ee1d07da0d6aff3431e200c9db 100644 (file)
@@ -1,63 +1,48 @@
-#include <err.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/errno.h>
 
+#include "config.h"
 #include "input.h"
 #include "stack.h"
 #include "utils.h"
 
-#define HISTLEN 100
-#define HISTNAME ".ashhistory"
+static char historyarr[MAXHIST + 1][MAXCHARS + 1];
+INITSTACK(history, historyarr, 1);
 
-static char *histpath, histarr[HISTLEN + 1][BUFLEN + 1];
-struct stack INITSTACK(history, histarr, 1);
+void readhistory(void) {
+   FILE *file;
 
-void readhist(void) {
-   char *homepath, buffer[BUFLEN + 1];
-   FILE *histfile;
-   int e;
-
-   if (!(homepath = getenv("HOME")))
-       errx(EXIT_FAILURE, "HOME environment variable does not exist");
-   histpath = allocate(strlen(homepath) + 1 + strlen(HISTNAME) + 1);
-   strcpy(histpath, homepath);
-   strcat(histpath, "/");
-   strcat(histpath, HISTNAME);
-
-   if (!(histfile = fopen(histpath, "r"))) {
+   if (!(file = fopen(prependhome(HISTORYFILE), "r"))) {
        if (errno == ENOENT) return;
-       err(EXIT_FAILURE, "Unable to open history file for reading");
+       fatal("Unable to open history file for reading");
    }
-   while (fgets(buffer, history.size, histfile)) {
+   while (fgets(buffer, history.size, file)) {
        *(buffer + strlen(buffer) - 1) = '\0';
        push(&history, buffer);
    }
-
-   if (ferror(histfile) || !feof(histfile))
-       err(EXIT_FAILURE, "Unable to read from history file");
-   if (fclose(histfile) == EOF) err(EXIT_FAILURE, "Unable to close history file");
+   if (ferror(file) || !feof(file))
+       fatal("Unable to read from history file");
+   if (fclose(file) == EOF) fatal("Unable to close history file");
 }
 
-void writehist(void) {
-   FILE *histfile;
+void writehistory(void) {
+   FILE *file;
 
-   if (!(histfile = fopen(histpath, "w"))) {
-       warn("Unable to open history file for writing");
+   if (!(file = fopen(prependhome(HISTORYFILE), "w"))) {
+       note("Unable to open history file for writing");
        return;
    }
-
    for (history.c = history.b; history.c != history.t; INC(history, c)) {
-       if (fputs(history.c, histfile) == EOF) {
-           warn("Unable to write to history file");
+       if (fputs((char *)history.c, file) == EOF) {
+           note("Unable to write to history file");
            break;
        }
-       if (fputc('\n', histfile) == EOF) {
-           warn("Unable to write newline to history file");
+       if (fputc('\n', file) == EOF) {
+           note("Unable to terminate line of history file");
            break;
        }
    }
-
-   if (fclose(histfile) == EOF) warn("Unable to close history stream");
+   if (fclose(file) == EOF) note("Unable to close history stream");
 }
index bb7130f3cdcdfcc5b86ade385872fb21e0bda4c5..22d30e6670579edc67ca2ada903330d1c27ca788 100644 (file)
@@ -1,4 +1,5 @@
 extern struct stack history;
 
-void readhist(void);
-void writehist(void);
+void readhistory(void);
+void writehistory(void);
+
index abef388852ef64ae58effc79334e1e5e2f755c24..a7d01e3f93285f440b24e0d692dc7b59b68da943 100644 (file)
@@ -1,17 +1,21 @@
-#include <err.h>
+#include <fcntl.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
 #include <termios.h>
 #include <unistd.h>
 
+#include "config.h"
 #include "history.h"
 #include "input.h"
 #include "job.h"
 #include "stack.h"
-#include "options.h"
+#include "utils.h"
 
-#define PROMPT "% "
+#define PROMPT "> " // TODO: Have prompt be an environment variable
 
 enum character {
    CTRLC = '\003',
@@ -29,14 +33,80 @@ enum character {
    DEL = '\177',
 };
 
-char buffer[BUFLEN + 2]; // Terminating ";"
+char *string, buffer[MAXCHARS + 2], *script;
 
-char *input(void) {
+INPUT(stringinput) {
+   char *start;
+   size_t l;
+
+   if (!*string) return NULL;
+   start = string;
+   while (*string && *string != '\n') ++string;
+   l = string - start;
+   if (*string == '\n') ++string;
+   if (l > MAXCHARS) fatal("Line too long, exceeds %d character limit", MAXCHARS);
+   strncpy(buffer, start, l);
+   buffer[l] = ';';
+   buffer[l + 1] = '\0';
+
+   return buffer;
+}
+
+INPUT(scriptinput) {
+   int fd;
+   struct stat sstat;
+   char *result;
+   static char *map;
+   static size_t l;
+
+   if (!map) {
+       if ((fd = open(script, O_RDONLY)) == -1) fatal("Unable to open `%s'", script);
+       if (stat(script, &sstat) == -1) fatal("Unable to stat `%s'", script);
+       if ((l = sstat.st_size) == 0) return NULL;
+       if ((map = string = mmap(NULL, l, PROT_READ, MAP_PRIVATE, fd, 0))
+           == MAP_FAILED)
+           fatal("Unable to memory map `%s'", script);
+       if (close(fd) == -1) fatal("Unable to close `%s'", script);
+   }
+
+   if (!(result = stringinput())) {
+       if (munmap(map, l) == -1) fatal("Unable to unmap %s from memory", script);
+       map = NULL;
+   }
+
+   return result;
+}
+
+char *config(char *name) {
+   char *result;
+   static char *origscript, *origstr;
+
+   if (!origscript) {
+       origscript = script;
+       origstr = string;
+       script = prependhome(name);
+   }
+
+   if (!(result = scriptinput())) {
+       script = origscript;
+       string = origstr;
+       origscript = NULL;
+   }
+
+   return result;
+}
+
+static void waitbgsig(int sig) {
+   (void)sig;
+   waitbg();
+}
+
+INPUT(userinput) {
    char *cursor, *end;
    unsigned int c;
    int i;
 
-   signal(SIGCHLD, waitbg); // TODO: Use sigaction for portability
+   signal(SIGCHLD, waitbgsig); // TODO: Use sigaction for portability
 
    end = cursor = buffer;
    *history.t = *buffer = '\0';
@@ -46,7 +116,7 @@ char *input(void) {
        while ((c = getchar()) != '\r') switch (c) {
        default:
            if (c >= ' ' && c <= '~') {
-               if (end - buffer == BUFLEN) continue;
+               if (end - buffer == MAXCHARS) continue;
                memmove(cursor + 1, cursor, end - cursor);
                *cursor++ = c;
                *++end = '\0';
@@ -62,7 +132,7 @@ char *input(void) {
            return buffer;
        case CTRLD:
            puts("^D\r");
-           signal(SIGCHLD, SIG_DFL);
+           signal(SIGCHLD, SIG_DFL); // XXX
            return NULL;
        case CLEAR:
            fputs("\033[H\033[J", stdout);
@@ -89,9 +159,10 @@ char *input(void) {
                    for (i = end - buffer + strlen(PROMPT); i > 0; --i) putchar(' ');
                    putchar('\r');
 
-                   if (strcmp(history.c, buffer) != 0) strcpy(history.t, buffer);
+                   if (strcmp((char *)history.c, buffer) != 0)
+                       strcpy((char *)history.t, buffer);
                    if (c == UP) DEC(history, c); else INC(history, c);
-                   strcpy(buffer, history.c);
+                   strcpy(buffer, (char *)history.c);
                    end = cursor = buffer + strlen(buffer);
 
                    fputs(PROMPT, stdout);
@@ -131,7 +202,7 @@ char *input(void) {
    *end++ = ';';
    *end = '\0';
 
-   signal(SIGCHLD, SIG_DFL);
+   signal(SIGCHLD, SIG_DFL); // XXX
 
    return buffer;
 }
index 1ca304b80bd104df4ac814b5ed27fd087ce6f068..eae90c51acfcb82e19c85ac2c4f1954e9aa93205 100644 (file)
@@ -1,5 +1,8 @@
-#define BUFLEN 1000
+#define INPUT(name) char *name(void)
 
-extern char buffer[BUFLEN + 2];
+extern char *string, buffer[MAXCHARS + 2], *script;
 
-char *input(void);
+INPUT(stringinput);
+INPUT(scriptinput);
+char *config(char *name);
+INPUT(userinput);
index 6573c4bf4ee4ac673b69c5027084860b3f313b9f..7c9bb090faf96ab4ffd19a3a11a7f7bafb861439 100644 (file)
--- a/src/job.c
+++ b/src/job.c
@@ -1,17 +1,20 @@
-#include <err.h>
 #include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <sys/errno.h>
 #include <sys/wait.h>
 #include <termios.h>
+#include <unistd.h>
 
+#include "config.h"
 #include "job.h"
 #include "stack.h"
+#include "utils.h"
 
-#define MAXJOBS 100
-
-static struct job jobarray[MAXJOBS + 1];
-struct stack INITSTACK(jobs, jobarray, 0);
+static struct job jobarr[MAXJOBS + 1];
+INITSTACK(jobs, jobarr, 0);
+struct termios raw, canonical;
 
 void *findjob(pid_t jobid) {
    if (jobs.b == jobs.t) return NULL;
@@ -26,17 +29,84 @@ void *deletejob(void) {
    return DEC(jobs, t);
 }
 
-void waitbg(int sig) {
+int setconfig(struct termios *mode) {
+   if (tcsetattr(STDIN_FILENO, TCSANOW, mode) == -1) {
+       note("Unable to set termios config");
+       return 0;
+   }
+   return 1;
+}
+
+int setfg(struct job job) {
+   if (!setconfig(&job.config)) return 0;
+   if (tcsetpgrp(STDIN_FILENO, job.id) == -1) {
+       note("Unable to bring job %d to foreground", job.id);
+       setconfig(&raw);
+       return 0;
+   }
+   if (killpg(job.id, SIGCONT) == -1) {
+       note("Unable to wake up job %d", job.id);
+       return 0;
+   }
+   return 1;
+}
+
+int waitfg(struct job job) {
+   int status, pgid, result;
+
+   do {
+       errno = 0;
+       waitpid(job.id, &status, WUNTRACED);
+   } while (errno == EINTR);
+   if (!errno && !WIFSTOPPED(status)) do {
+       errno = 0;
+       while (waitpid(-job.id, NULL, 0) != -1);
+   } while (errno == EINTR);
+   result = errno != ECHILD ? errno : 0;
+
+   // 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) {
+       note("Unable to reclaim foreground; terminating");
+       deinitialize();
+       exit(EXIT_FAILURE);
+   }
+   if (tcgetattr(STDIN_FILENO, &job.config) == -1)
+       note("Unable to save termios config of job %d", job.id);
+   setconfig(&raw);
+   if (result) return result;
+
+   if (WIFSIGNALED(status)) {
+       result = WTERMSIG(status);
+       puts("\r");
+   } else if (WIFSTOPPED(status)) {
+       result = WSTOPSIG(status);
+       job.type = SUSPENDED;
+       if (push(&jobs, &job)) return result;
+       note("Unable to add job %d to list; too many jobs\r\n"
+             "Press any key to continue", job.id);
+       getchar();
+       if (setfg(job)) return waitfg(job);
+       note("Manual intervention required for job %d", job.id);
+   } else if (WIFEXITED(status)) result = WEXITSTATUS(status);
+
+   return result;
+}
+
+void waitbg(void) {
    int status;
    pid_t id;
 
-   (void)sig;
    for (jobs.c = jobs.b; jobs.c != jobs.t; INC(jobs, c)) {
        if (CURRENT->type != BACKGROUND) continue;
        id = CURRENT->id;
+
+       // TODO: weird EINTR thing here too??
        while ((id = waitpid(-id, &status, WNOHANG | WUNTRACED)) > 0)
            if (WIFSTOPPED(status)) CURRENT->type = SUSPENDED;
+
        if (id == -1 && errno != ECHILD)
-           warn("Unable to wait on some child processes");
+           note("Unable to wait on some child processes");
    }
 }
index 73b2ed107eb7e6193dbb42d6f862f84cb75c55d2..12fa031d5efe2dce5e1b87ffdc0263adfe196467 100644 (file)
--- a/src/job.h
+++ b/src/job.h
@@ -1,3 +1,5 @@
+#define CURRENT ((struct job *)jobs.c)
+
 enum jobtype {
    BACKGROUND,
    SUSPENDED,
@@ -9,9 +11,12 @@ struct job {
    enum jobtype type;
 };
 
-#define CURRENT ((struct job *)jobs.c)
 extern struct stack jobs;
+extern struct termios raw, canonical;
 
 void *findjob(pid_t jobid);
 void *deletejob(void);
-void waitbg(int sig);
+int setconfig(struct termios *mode);
+int setfg(struct job job);
+int waitfg(struct job job);
+void waitbg(void);
index 9c05d5c6d4b975c0d01b92921cbe10a75f6cd6fa..30a92febc9dea942c66a952f02b17927397f7690 100644 (file)
@@ -1,30 +1,23 @@
 #include <stdlib.h>
-#include <termios.h>
-#include <stdio.h> // XXX
 
-#include "job.h"
+#include "config.h"
+#include "input.h"
 #include "options.h"
+#include "parse.h"
 #include "run.h"
-#include "term.h"
+#include "utils.h"
 
 int main(int argc, char **argv) {
-   struct cmd *cmd;
+   options(&argc, &argv);
 
-   // TODO: Have `cd' builtin affect $PWD$ env var
+   initialize();
 
-   options(&argc, &argv);
+   if (login) while (run(parse(config(LOGINFILE))));
+   if (interactive) while (run(parse(config(INTERACTIVEFILE))));
+
+   while (run(parse(input())));
 
-   initterm(); // <-- TODO: Set $SHLVL$ in this function
-   if (login) runhome(".ashlogin");
-   if (string) {
-       runstr(string);
-       free(string);
-   } else if (*argv) runscript(*argv);
-   else {
-       runhome(".ashinteractive");
-       runinteractive();
-   }
-   deinitterm();
+   deinitialize();
 
    return EXIT_SUCCESS;
 }
index 3e07cc619534b203fddcae5f5688c49eef4b928a..453613924a210521088ab998db2bf4f1309ebe8b 100644 (file)
@@ -1,29 +1,27 @@
+#include <err.h>
 #include <stdlib.h>
-#include <stdio.h>
 #include <unistd.h>
-#include <err.h>
-#include <string.h>
 
-int login;
-char *string;
+#include "config.h"
+#include "input.h"
+#include "options.h"
+
+int login, interactive;
+Input input;
 
 void options(int *argcp, char ***argvp) {
    int opt, l;
    char *usage = "TODO: WRITE USAGE";
 
    login = ***argvp == '-';
+   interactive = 1;
+   input = userinput;
 
-   // -h -> help message
-   // -l -> login shell
-   // -c "***" -> run string
-   // file.ash -> run file
    while ((opt = getopt(*argcp, *argvp, ":c:hl")) != -1) switch (opt) {
    case 'c':
-       l = strlen(optarg) + 2;
-       if (!(string = malloc(l))) err(EXIT_FAILURE, "Memory allocation");
-       strcpy(string, optarg);
-       *(string + l - 1) = ';';
-       *(string + l) = '\0';
+       interactive = 0;
+       input = stringinput;
+       string = optarg;
        break;
    case 'h':
        errx(EXIT_SUCCESS, "%s", usage);
@@ -37,5 +35,11 @@ void options(int *argcp, char ***argvp) {
        errx(EXIT_FAILURE, "Unknown command line option `-%c'\n%s", optopt, usage);
    }
    *argcp -= optind;
-   *argvp+= optind;
+   *argvp += optind;
+
+   if (!string && **argvp) {
+       interactive = 0;
+       input = scriptinput;
+       script = **argvp;
+   }
 }
index 6bb8fa681d063c17badda541686c69dafa5a35c0..724c3aa7a7f6bebbcc46b996183a8c01903095a2 100644 (file)
@@ -1,4 +1,6 @@
-extern int login;
-extern char *string;
+typedef INPUT((*Input));
+
+extern int login, interactive;
+extern Input input;
 
 void options(int *argcp, char ***argvp);
similarity index 78%
rename from src/lex.c
rename to src/parse.c
index 29410dfcb8e98dd6b33d22f77e08ec7070c0333e..7a93f748a4dc639fcc2d09a3fdfca23e5ecc0735 100644 (file)
--- a/src/lex.c
@@ -1,25 +1,21 @@
-#include <err.h>
-#include <fcntl.h>
 #include <limits.h>
-#include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
-#include <stdio.h> // XXX
 
+#include "config.h"
 #include "input.h"
-#include "lex.h"
+#include "parse.h"
+#include "utils.h"
 
-#define MAXCMDS 100
-
-static char *tokens[BUFLEN + 1];
+static char *tokens[MAXCHARS + 1];
 static struct cmd cmds[MAXCMDS + 1];
 struct cmd empty = {0};
 
-struct cmd *lex(char *b) {
-   char **t, *end, *p, *env, *name, *value;
-   int e, offset;
+struct cmd *parse(char *b) {
+   char **t, *name, *value, *end, *p, *env;
    struct cmd *c;
    long l;
+   int e, offset;
    
    if (!b) return NULL;
    t = tokens;
@@ -38,7 +34,7 @@ struct cmd *lex(char *b) {
        if (*(b - 1)) {
            if (c->args == --t) c->args = NULL;
            if ((l = strtol(*t, &end, 10)) < 0 || l > INT_MAX || end != b) {
-               warnx("Invalid file redirection");
+               note("Incorrect syntax for file redirection\r");
                return &empty;
            }
            c->r->newfd = l;
@@ -60,31 +56,25 @@ struct cmd *lex(char *b) {
            if (*end == '\\') ++end;
        }
        if (!b) {
-           warnx("Open-ended quote");
+           note("Quote left open-ended\r");
            return &empty;
        }
-
-       // "..."...\0
-       // ^   ^   ^
-       // p   b   end
        memmove(p, p + 1, end-- - p);
        --b;
-       // ..."...\0
-       // ^  ^   ^
-       // p  b   end
+
        while (p != b) if (*p++ == '\\') {
            switch (*p) {
-           case 'n':
-               *p = '\n';
-               break;
            case 't':
                *p = '\t';
                break;
+           case 'v':
+               *p = '\v';
+               break;
            case 'r':
                *p = '\r';
                break;
-           case 'v':
-               *p = '\v';
+           case 'n':
+               *p = '\n';
                break;
            }
            memmove(p - 1, p, end-- - p);
@@ -105,17 +95,14 @@ struct cmd *lex(char *b) {
        p = b++;
        while (*b && *b != '$') ++b;
        if (!*b) {
-           warnx("Open-ended environment variable");
+           note("Environment variable lacks a terminating `$'\r");
            return &empty;
        }
        *b++ = '\0';
        for (end = b; *end; ++end);
-       // $...\0...\0
-       // ^     ^  ^
-       // p     b end
 
        if ((env = getenv(p + 1)) == NULL) {
-           warnx("Unknown environment variable");
+           note("Environment variable does not exist\r");
            return &empty;
        }
        e = strlen(env);
@@ -132,7 +119,7 @@ struct cmd *lex(char *b) {
    case ';':
        if (name && *c->args == name) c->args = NULL;
        if (c->args) {
-           if ((c->term = *b) == *(b + 1) && *b == '&' || *b == '|') {
+           if ((c->term = *b) == *(b + 1) && (*b == '&' || *b == '|')) {
                ++c->term;
                *b++ = '\0';
            }
@@ -140,7 +127,7 @@ struct cmd *lex(char *b) {
            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");
+                   note("Incorrect syntax for file redirection\r");
                    return &empty;
                }
                c->r->oldfd = l;
@@ -155,7 +142,7 @@ struct cmd *lex(char *b) {
        *b = '\0';
        if (value) {
            if (setenv(name, value, 1) == -1) {
-               warn("Unable to set environment variable");
+               note("Unable to set environment variable\r");
                return &empty;
            }
            value = name = NULL;
@@ -166,7 +153,7 @@ struct cmd *lex(char *b) {
    case AND:
    case PIPE:
    case OR:
-       warnx("Command left open-ended");
+       note("Expected another command\r");
        return &empty;
    default:
        break;
similarity index 89%
rename from src/lex.h
rename to src/parse.h
index 21aace68ab83a7a0a2f4ef9543fd48a84c6e694b..4d1a430fb7155b85b284bccb00c2925247653a48 100644 (file)
--- a/src/lex.h
@@ -20,7 +20,6 @@ enum terminator {
    OR,
 };
 
-#define MAXRDS 25
 struct cmd {
    char **args;
    struct redirect *r, rds[MAXRDS + 1];
@@ -30,4 +29,4 @@ struct cmd {
 
 extern struct cmd empty;
 
-struct cmd *lex(char *b);
+struct cmd *parse(char *b);
index 4e1d1b4a43f4b2982e4c32d0d3f5846f02b59aa2..a93f65ff52819509af254bc817e09ff7d3bbd824 100644 (file)
--- a/src/run.c
+++ b/src/run.c
@@ -1,89 +1,66 @@
-#include <err.h>
 #include <fcntl.h>
 #include <signal.h>
-#include <stdio.h> // DEBUG
 #include <stdlib.h>
-#include <string.h>
 #include <sys/errno.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
 #include <termios.h>
 #include <unistd.h>
 
 #include "builtins.h"
-#include "history.h"
-#include "input.h"
+#include "config.h"
 #include "job.h"
-#include "lex.h"
+#include "parse.h"
 #include "stack.h"
-#include "term.h"
 #include "utils.h"
 
 static int closepipe(struct cmd *cmd) {
    int result;
 
-   if (!cmd->args) return 1;
-
-   result = 1;
-   if (close(cmd->pipe[0]) == -1) {
-       warn("Unable to close read end of `%s' pipe", *cmd->args);
-       result = 0;
-   }
-   if (close(cmd->pipe[1]) == -1) {
-       warn("Unable to close write end of `%s' pipe", *cmd->args);
-       result = 0;
-   }
+   result = close(cmd->pipe[0]) == 0;
+   result &= close(cmd->pipe[1]) == 0;
+   if (!result) note("Unable to close `%s' pipe", *cmd->args);
    return result;
 }
 
-static int redirectfiles(struct redirect *r) {
-   int oflag, fd;
+static void redirectfiles(struct redirect *r) {
+   int mode, fd;
 
    for (; r->mode; ++r) {
        if (r->oldname) {
            switch (r->mode) {
            case READ:
-               oflag = O_RDONLY;
+               mode = O_RDONLY;
                break;
            case WRITE:
-               oflag = O_WRONLY | O_CREAT | O_TRUNC;
+               mode = O_WRONLY | O_CREAT | O_TRUNC;
                break;
            case READWRITE:
-               oflag = O_RDWR | O_CREAT | O_APPEND;
+               mode = O_RDWR | O_CREAT | O_APPEND;
                break;
            case APPEND:
-               oflag = O_WRONLY | O_CREAT | O_APPEND;
+               mode = O_WRONLY | O_CREAT | O_APPEND;
+           default:
                break;
-           default:;
-           }
-           if ((fd = open(r->oldname, oflag, 0644)) == -1) {
-               warn("Unable to open `%s'", r->oldname);
-               return 0;
            }
+           if ((fd = open(r->oldname, mode, 0644)) == -1)
+               fatal("Unable to open `%s'", r->oldname);
            r->oldfd = fd;
        }
-       if (dup2(r->oldfd, r->newfd) == -1) {
-           warn("Unable to redirect %d to %d", r->newfd, r->oldfd);
-           return 0;
-       }
-       if (r->oldname) {
-           if (close(r->oldfd) == -1) {
-               warn("Unable to close file descriptor %d", r->oldfd);
-               return 0;
-           }
-       }
+       if (dup2(r->oldfd, r->newfd) == -1)
+           fatal("Unable to redirect %d to %d", r->newfd, r->oldfd);
+       if (r->oldname && close(r->oldfd) == -1)
+           fatal("Unable to close `%s'", r->oldname);
    }
-   return 1;
 }
 
-static void runcmd(struct cmd *cmd) {
+int run(struct cmd *cmd) {
    struct cmd *prev;
    int ispipe, ispipestart, ispipeend;
    static int status;
    pid_t cpid, jobid;
    struct job job;
 
+   if (!cmd) return 0;
+
    for (prev = &empty; cmd->args; prev = cmd++) {
        ispipe = cmd->term == PIPE || prev->term == PIPE;
        ispipestart = ispipe && prev->term != PIPE;
@@ -91,31 +68,29 @@ static void runcmd(struct cmd *cmd) {
 
        if (ispipe) {
            if (!ispipeend && pipe(cmd->pipe) == -1) {
-               warn("Unable to create pipe");
+               note("Unable to create pipe");
                if (!ispipestart) closepipe(prev);
                break;
            }
            if ((jobid = cpid = fork()) == -1) {
-               warn("Unable to create child process");
+               note("Unable to create child process");
                break;
            } else if (cpid == 0) {
                if (!ispipestart) {
                    if (dup2(prev->pipe[0], 0) == -1)
-                       err(EXIT_FAILURE, "Unable to duplicate read end of `%s' pipe",
-                           *prev->args);
+                       fatal("Unable to duplicate read end of `%s' pipe", *prev->args);
                    if (!closepipe(prev)) exit(EXIT_FAILURE);
                }
                if (!ispipeend) {
                    if (dup2(cmd->pipe[1], 1) == -1)
-                       err(EXIT_FAILURE, "Unable to duplicate write end of `%s' pipe",
-                           *cmd->args);
+                       fatal("Unable to duplicate write end of `%s' pipe", *cmd->args);
                    if (!closepipe(cmd)) exit(EXIT_FAILURE);
                }
 
-               if (!redirectfiles(cmd->rds)) exit(EXIT_FAILURE);
+               redirectfiles(cmd->rds);
                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);
+                   fatal("Couldn't find `%s' command", *cmd->args);
            }
            if (!ispipestart) {
                closepipe(prev);
@@ -124,108 +99,40 @@ static void runcmd(struct cmd *cmd) {
        } else {
            if (cmd->rds->mode == END && isbuiltin(cmd->args, &status)) break;
            if ((jobid = cpid = fork()) == -1) {
-               warn("Unable to create child process");
+               note("Unable to create child process");
                break;
            } else if (cpid == 0) {
-               if (!redirectfiles(cmd->rds)) exit(EXIT_FAILURE);
+               redirectfiles(cmd->rds);
                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);
+                   fatal("Couldn't find `%s' command", *cmd->args);
            }
        }
+
        if (setpgid(cpid, jobid) == -1) {
            if (errno != ESRCH) {
-               warn("Unable to set pgid of `%s' command to %d", *cmd->args, jobid);
+               note("Unable to set pgid of `%s' command to %d", *cmd->args, jobid);
                if (kill(cpid, SIGKILL) == -1)
-                   warn("Unable to kill process %d; manual termination may be required",
-                        cpid);
+                   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 (!push(&jobs, &job)) {
-               warn("Unable to add command to background; "
-                    "too many processes in the background");
+               note("Unable to add job to background; too many background jobs");
                if (ispipestart) closepipe(cmd);
                break;
            }
        } else if (cmd->term != PIPE) {
            if (!setfg(job)) break;
            status = waitfg(job);
+
            if (cmd->term == AND && status != 0) break;
            if (cmd->term == OR && status == 0) break;
        }
    }
-   waitbg(0);
-}
-
-void runstr(char *start) {
-   char *p;
-   size_t l;
+   waitbg();
 
-   for (p = start; *p; start = ++p) {
-       while (*p && *p != '\n') ++p;
-       l = p - start;
-       if (l > BUFLEN)
-           errx(EXIT_FAILURE, "Line is too long; exceeds %d characters", BUFLEN);
-       strncpy(buffer, start, l);
-       *(buffer + l) = ';';
-       *(buffer + l + 1) = '\0';
-       runcmd(lex(buffer));
-   }
-}
-
-void runscript(char *filename) {
-   int fd;
-   struct stat sstat;
-   char *str;
-
-   if ((fd = open(filename, O_RDONLY)) == -1)
-       err(EXIT_FAILURE, "Unable to open `%s'", filename);
-   if (stat(filename, &sstat) == -1)
-       err(EXIT_FAILURE, "Unable to stat `%s'", filename);
-   if (sstat.st_size == 0) return;
-   if ((str = mmap(NULL, sstat.st_size, PROT_READ, MAP_PRIVATE, fd, 0))
-       == MAP_FAILED)
-       err(EXIT_FAILURE, "Unable to memory map `%s'", filename);
-   if (close(fd) == -1) err(EXIT_FAILURE, "Unable to close `%s'", filename);
-   runstr(str);
-   if (munmap(str, sstat.st_size) == -1)
-       err(EXIT_FAILURE, "Unable to unmap `%s'", filename);
-}
-
-void runinteractive(void) {
-   struct cmd *cmd;
-
-   readhist();
-   while ((cmd = lex(input()))) runcmd(cmd);
-   writehist();
-}
-
-#define MAXPATH 1000
-char *prependhome(char *filename) {
-   static char filepath[MAXPATH + 1];
-
-   strcpy(filepath, getenv("HOME"));
-   strcat(filepath, "/");
-   strcat(filepath, filename);
-
-   return filepath;
-}
-
-void runhome(char *filename) {
-   char *filepath;
-   int fd;
-   
-   filepath = prependhome(filename);
-   if (access(filepath, R_OK) == -1) {
-       if (errno != ENOENT)
-           err(EXIT_FAILURE, "Unable to access `%s'", filepath);
-       if ((fd = open(filepath, O_RDONLY | O_CREAT, 0644)) == -1)
-           err(EXIT_FAILURE, "Unable to open `%s'", filepath);
-       if (close(fd) == -1)
-           err(EXIT_FAILURE, "Unable to close `%s'", filepath);
-   } else runscript(filepath);
+   return 1;
 }
index 87eb89039cc90d35365a05fd53dca6e3c928a23b..bf296d07020c58828b2bb45486d16d3d4e94f3a5 100644 (file)
--- a/src/run.h
+++ b/src/run.h
@@ -1,6 +1 @@
-char *prependhome(char *filename);
-
-void runstr(char *str);
-void runscript(char *filename);
-void runinteractive(void);
-void runhome(char *filename);
+int run(struct cmd *cmd);
index 4d21bd7e61ceecb339ccbfd84db8ad34206d2d09..a5df54ed1c10b106fb42c56c6483c18aed1894e5 100644 (file)
@@ -1,18 +1,16 @@
 #include <string.h>
+#include <stdint.h>
 
 #include "stack.h"
 
 int push(struct stack *s, void *d) {
-   int result;
-
-   result = 0;
    if (PLUSONE(*s, t) == s->b) {
-       if (!s->overwrite) return result;
+       if (!s->overwrite) return 0;
        INC(*s, b);
-   } else result = 1;
+   }
    memmove(s->t, d, s->size);
    INC(*s, t);
-   return result;
+   return 1;
 }
 
 void *peek(struct stack *s) {
index d33cbe5b19e3dcb35db4ab73234777d419820ec8..e0dbe60ac087c665b850dd08fa6060939b171d43 100644 (file)
@@ -5,10 +5,12 @@
 #define DEC(s, m) ((s).m = MINUSONE(s, m))
 
 #define INITSTACK(s, d, o) \
-   s = {sizeof*d, sizeof d, (char *)d, (char *)d, (char *)d, (char *)d, o}
+   struct stack s = {sizeof*d, sizeof d, (uint8_t *)d, (uint8_t *)d, \
+                     (uint8_t *)d, (uint8_t *)d, o}
+
 struct stack {
-   size_t size, cap; // In bytes
-   char *b, *c, *t, *data;
+   size_t size, cap;
+   uint8_t *b, *c, *t, *data;
    int overwrite;
 };
 
diff --git a/src/term.c b/src/term.c
deleted file mode 100644 (file)
index f7bd4a7..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-#include <termios.h>
-#include <unistd.h>
-#include <err.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <sys/errno.h>
-#include <stdio.h>
-
-#include "job.h"
-#include "history.h"
-#include "stack.h"
-
-struct termios raw, canonical;
-
-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 default termios config");
-   if (!setconfig(&raw)) exit(EXIT_FAILURE);
-}
-
-void deinitterm(void) {
-   setconfig(&canonical);
-}
-
-int setfg(struct job job) {
-   if (!setconfig(&job.config)) return 0;
-   if (tcsetpgrp(STDIN_FILENO, job.id) == -1) {
-       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 job %d\r", job.id);
-       return 0;
-   }
-   return 1;
-}
-
-int waitfg(struct job job) {
-   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);
-   }
-   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)) {
-       result = WTERMSIG(status);
-       puts("\r");
-   } else if (WIFSTOPPED(status)) {
-       result = WSTOPSIG(status);
-       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;
-}
diff --git a/src/term.h b/src/term.h
deleted file mode 100644 (file)
index 3bc6806..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-extern struct termios raw, canonical;
-
-void initterm(void);
-void deinitterm(void);
-int setfg(struct job job);
-int waitfg(struct job job);
index 07327e4b6a69605093ff654de56628cb7bacb693..f943c205d452fdae3a9f586e2840a157d5e48bf1 100644 (file)
@@ -1,12 +1,61 @@
 #include <err.h>
+#include <stdarg.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/errno.h>
+#include <termios.h>
+#include <unistd.h>
 
-void *allocate(size_t s) {
-   void *r;
+#include "config.h"
+#include "history.h"
+#include "input.h"
+#include "job.h"
+#include "options.h"
+#include "utils.h"
 
-   if (!(r = malloc(s))) err(EXIT_FAILURE, "Memory allocation");
+void note(char *fmt, ...) {
+   va_list args;
+   va_start(args, fmt);
+   (errno ? vwarn : vwarnx)(fmt, args);
+   va_end(args);
+   putchar('\r');
+}
+
+void fatal(char *fmt, ...) {
+   va_list args;
+   va_start(args, fmt);
+   (errno ? vwarn : vwarnx)(fmt, args);
+   va_end(args);
+   putchar('\r');
+   exit(EXIT_FAILURE);
+}
+
+char *prependhome(char *name) {
+   static char *p, path[MAXPATH + 1];
+   
+   if (!p) {
+       if (!(p = getenv("HOME")))
+           fatal("Unable to access $HOME$ environment variable");
+       strcpy(path, p);
+       strcat(path, "/");
+       p = path + strlen(path);
+   }
+   *p = '\0';
+   strcat(path, name);
 
-   return memset(r, 0, s);
+   return path;
 }
 
+void initialize(void) { // <-- TODO: Set $SHLVL$ in this function
+   cfmakeraw(&raw);
+   if (tcgetattr(STDIN_FILENO, &canonical) == -1)
+       fatal("Unable to get default termios config");
+   if (!setconfig(&raw)) exit(EXIT_FAILURE);
+   if (interactive) readhistory();
+}
+
+void deinitialize(void) {
+   if (interactive) writehistory();
+   setconfig(&canonical);
+}
index 8954d59649c0df962b90bfc7acbb8ef6d0eab0c6..a78c43ba8f0a26e2bd4a89a6920ed6d8c64c29f9 100644 (file)
@@ -1 +1,5 @@
-void *allocate(size_t s);
+void note(char *fmt, ...);
+void fatal(char *fmt, ...);
+char *prependhome(char *name);
+void initialize(void);
+void deinitialize(void);