]> Trent Huber's Code - thus.git/commitdiff
shell struct, source builtin
authorTrent Huber <trentmhuber@gmail.com>
Thu, 7 Aug 2025 01:01:25 +0000 (21:01 -0400)
committerTrent Huber <trentmhuber@gmail.com>
Thu, 7 Aug 2025 01:01:25 +0000 (21:01 -0400)
28 files changed:
external/cbs
src/build.c
src/builtin/alias.c [new file with mode: 0644]
src/builtin/alias.h [new file with mode: 0644]
src/builtin/bg.c
src/builtin/build.c
src/builtin/cd.c
src/builtin/fg.c
src/builtin/fg.h [new file with mode: 0644]
src/builtin/source.c [new file with mode: 0644]
src/builtin/source.h [new file with mode: 0644]
src/builtin/which.c
src/config.h [deleted file]
src/history.c
src/input.c
src/input.h
src/job.c
src/job.h
src/main.c
src/options.c
src/options.h
src/parse.c
src/parse.h
src/run.c
src/run.h
src/shell.h [new file with mode: 0644]
src/utils.c
src/utils.h

index 4711a83fafa0282fadeaba701a25539b3e73d073..5ab49da8d4ab0b8e6cb23c3cb1f927e4402db4fc 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 4711a83fafa0282fadeaba701a25539b3e73d073
+Subproject commit 5ab49da8d4ab0b8e6cb23c3cb1f927e4402db4fc
index 1f74e835166a2a962759df549f35f4e1254b0658..8f2965fa72ea500d0bd8cb3256b79f94d4334849 100644 (file)
@@ -1,6 +1,8 @@
 #include "../external/cbs/cbs.c"
 #include "../external/cbsfile.c"
 
+#define BUILTINS LIST("-Ibuiltin/")
+
 int main(void) {
    build("./");
 
@@ -8,13 +10,13 @@ int main(void) {
 
    buildfiles((struct cbsfile []){{"../bin/ash", NONE, 'x'},
 
-                                  {"input", NONE},
                                   {"history", NONE},
+                                  {"input", NONE},
                                   {"job", NONE},
-                                  {"parse", NONE},
-                                  {"main", NONE},
+                                  {"main", BUILTINS},
                                   {"options", NONE},
-                                  {"run", LIST("-Ibuiltin/")},
+                                  {"parse", NONE},
+                                  {"run", BUILTINS},
                                   {"stack", NONE},
                                   {"utils", NONE},
 
diff --git a/src/builtin/alias.c b/src/builtin/alias.c
new file mode 100644 (file)
index 0000000..716be35
--- /dev/null
@@ -0,0 +1,81 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "builtin.h"
+#include "utils.h"
+#include "stack.h"
+#include "input.h"
+#include "shell.h"
+#include "parse.h"
+
+#define MAXALIAS 25
+#define ALIAS ((struct alias *)aliases.c)
+
+struct alias {
+   char lhs[MAXCHARS - 5], *rhs;
+   struct shell shell;
+};
+
+static struct alias aliasarr[MAXALIAS + 1];
+static INITSTACK(aliases, aliasarr, 0);
+
+void applyaliases(struct shell *shell) {
+   struct cmd *cmd, *p;
+   char **end;
+   size_t l, a;
+
+   p = cmd = shell->cmds;
+
+   end = p->args;
+   while ((p = p->next)) if (p->args) end = p->args;
+   if (end) while (*end) ++end;
+
+   while ((p = cmd = cmd->next)) {
+       if (!cmd->args) continue;
+       for (aliases.c = aliases.b; aliases.c != aliases.t; INC(aliases, c))
+           if (strcmp(ALIAS->lhs, *cmd->args) == 0) break;
+       if (aliases.c == aliases.t) continue;
+
+       strcpy(ALIAS->shell.buffer, ALIAS->rhs);
+       l = strlen(ALIAS->shell.buffer);
+       ALIAS->shell.buffer[l + 1] = '\0';
+       ALIAS->shell.buffer[l] = ';';
+
+       parse(&ALIAS->shell);
+
+       for (a = 0; ALIAS->shell.tokens[a]; ++a);
+       memmove(cmd->args + a, cmd->args + 1, (end - cmd->args + 1) * sizeof*cmd->args);
+       memcpy(cmd->args, ALIAS->shell.tokens, a * sizeof*cmd->args);
+       while ((p = p->next)) p->args += a - 1;
+   }
+}
+
+BUILTINSIG(alias) {
+   switch (argc) {
+   case 1:
+       for (aliases.c = aliases.b; aliases.c != aliases.t; INC(aliases, c))
+           printf("%s = \"%s\"\r\n", ALIAS->lhs, ALIAS->rhs);
+       break;
+   case 3:
+       if (!*argv[2]) {
+           note("Cannot add empty alias");
+           return EXIT_FAILURE;
+       }
+       for (aliases.c = aliases.b; aliases.c != aliases.t; INC(aliases, c))
+           if (strcmp(ALIAS->lhs, argv[1]) == 0) break;
+       if (PLUSONE(aliases, c) == aliases.b) {
+           note("Unable to add alias `%s', maximum reached (%d)", argv[1], MAXALIAS);
+           return EXIT_FAILURE;
+       }
+       strcpy(ALIAS->lhs, argv[1]);
+       strcpy(ALIAS->rhs = ALIAS->lhs + strlen(ALIAS->lhs) + 1, argv[2]);
+       if (aliases.c == aliases.t) INC(aliases, t);
+       break;
+   default:
+       puts("Usage: alias [lhs rhs]\r");
+       return EXIT_FAILURE;
+   }
+
+   return EXIT_SUCCESS;
+}
diff --git a/src/builtin/alias.h b/src/builtin/alias.h
new file mode 100644 (file)
index 0000000..540e935
--- /dev/null
@@ -0,0 +1 @@
+void applyaliases(struct shell *shell);
index 1e090f02b0614f66b889d325c8e2b7951beef870..8e90c581f933f6766fa7e0c33884d5d90620b517 100644 (file)
@@ -35,7 +35,7 @@ BUILTINSIG(bg) {
        }
    } else {
        for (jobs.c = MINUSONE(jobs, t); jobs.c != MINUSONE(jobs, b); DEC(jobs, c))
-           if (CURRENT->type == SUSPENDED) break;
+           if (JOB->type == SUSPENDED) break;
        if (jobs.c == MINUSONE(jobs, b)) {
            note("No suspended jobs to run in background");
            return EXIT_FAILURE;
index 30de555ca6ab310055395b8dd6a23f44640452c7..9f526507b759abcf8c49dcfa0d34e03a24885d9b 100644 (file)
@@ -6,7 +6,8 @@
 
 #include "../../external/cbs/cbs.c"
 #include "../../external/cbsfile.c"
-#include "../config.h"
+
+#define MAXBUILTINS 50
 
 int main(void) {
    int listfd, l;
@@ -23,7 +24,7 @@ int main(void) {
    if (!(dir = opendir("./")))
        err(EXIT_FAILURE, "Unable to open current directory");
 
-   dprintf(listfd, "#include <stdlib.h>\n\n#include \"builtin.h\"\n"
+   dprintf(listfd, "#include <stddef.h>\n\n#include \"builtin.h\"\n"
            "#include \"list.h\"\n\n");
 
    errno = i = 0;
@@ -35,7 +36,8 @@ int main(void) {
        if (!(name = strrchr(entry->d_name, '.')) || strcmp(name, ".c") != 0)
            continue;
        if (i == 1 + MAXBUILTINS + 1)
-           errx(EXIT_FAILURE, "Maximum allowed builtins (%d) exceeded", MAXBUILTINS);
+           errx(EXIT_FAILURE, "Unable to add built-in `%s', maximum reached (%d)",
+                name, MAXBUILTINS);
        if (!(name = strdup(entry->d_name)))
            err(EXIT_FAILURE, "Unable to duplicate directory entry");
        name[strlen(name) - strlen(".c")] = '\0';
index 518df502189d95973f1a3b69cd25138f781d16e5..4eb01feff5a77f86741107adcd6b37ef0fbe6a99 100644 (file)
@@ -1,27 +1,25 @@
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
+#include <limits.h>
 
 #include "builtin.h"
 #include "utils.h"
 
 BUILTINSIG(cd) {
-   char *fullpath;
+   char *path;
 
-   if (!argv[1]) fullpath = home;
-   else if (!(fullpath = realpath(argv[1], NULL))) {
-       note("Could not resolve path name");
+   path = argc == 1 ? home : argv[1];
+
+   if (chdir(path) == -1) {
+       note("Unable to change directory to `%s'", path);
        return EXIT_FAILURE;
    }
 
-   if (chdir(fullpath) == -1) {
-       note("Unable to change directory to `%s'", argv[1]);
+   if (setenv("PWD", path, 1) == -1) {
+       note("Unable to change $PWD$ to `%s'", path);
        return EXIT_FAILURE;
    }
 
-   if (setenv("PWD", fullpath, 1) == -1)
-       note("Unable to change $PWD$ to `%s'", fullpath);
-
-   if (fullpath != home) free(fullpath);
-
    return EXIT_SUCCESS;
 }
index c2f035c92d7ea9a38fcbf805ef966059e8952b3a..6a4958c3a6a9fe365e5c9916128b14270434ed07 100644 (file)
@@ -1,14 +1,58 @@
 #include <limits.h>
 #include <signal.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <sys/errno.h>
 #include <termios.h>
+#include <unistd.h>
 
 #include "builtin.h"
 #include "job.h"
 #include "stack.h"
 #include "utils.h"
 
+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) {
+   while (waitpid(job.id, NULL, 0) != -1);
+   errno = 0;
+
+   if (sigaction(SIGTTOU, &sigign, NULL) == -1
+       || tcsetpgrp(STDIN_FILENO, getpgrp()) == -1
+       || sigaction(SIGTTOU, &sigdfl, NULL) == -1) {
+       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 (WIFEXITED(fgstatus)) return WEXITSTATUS(fgstatus);
+   else if (WIFSIGNALED(fgstatus)) return WTERMSIG(fgstatus);
+   job.type = SUSPENDED;
+   if (!push(&jobs, &job)) {
+       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);
+   }
+   return WSTOPSIG(fgstatus);
+}
+
 BUILTINSIG(fg) {
    long jobid;
    struct job *job;
@@ -36,7 +80,7 @@ BUILTINSIG(fg) {
    }
 
    if (sigaction(SIGCHLD, &sigchld, NULL) == -1) {
-       note("Unable to install SIGCHLD handler");
+       note("Unable to reinstall SIGCHLD handler");
        return EXIT_FAILURE;
    }
 
diff --git a/src/builtin/fg.h b/src/builtin/fg.h
new file mode 100644 (file)
index 0000000..00b6eaa
--- /dev/null
@@ -0,0 +1,2 @@
+int setfg(struct job job);
+int waitfg(struct job job);
diff --git a/src/builtin/source.c b/src/builtin/source.c
new file mode 100644 (file)
index 0000000..de2f166
--- /dev/null
@@ -0,0 +1,27 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include "input.h"
+#include "shell.h"
+#include "parse.h"
+#include "run.h"
+#include "utils.h"
+#include "builtin.h"
+
+BUILTINSIG(source) {
+   struct shell shell;
+
+   shell.script = argv[1];
+   shell.input = scriptinput;
+
+   while (run(parse(shell.input(&shell))));
+
+   return EXIT_SUCCESS; // TODO: Handle exit status
+}
+
+void config(char *name) {
+   char path[PATH_MAX];
+
+   source(2, (char *[]){name, catpath(home, name, path), NULL});
+}
diff --git a/src/builtin/source.h b/src/builtin/source.h
new file mode 100644 (file)
index 0000000..55e2527
--- /dev/null
@@ -0,0 +1 @@
+void config(char *name);
index 9c4c48af6742f053ba4a60fd2fa14b4a08600b57..85d442725ee1d6e0aff32ae3059cd0fadc8e9cb0 100644 (file)
@@ -1,54 +1,56 @@
-#include <stdlib.h>
 #include <stdio.h>
-#include <sys/stat.h>
-#include <sys/errno.h>
+#include <stdlib.h>
 #include <string.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <limits.h>
 
 #include "builtin.h"
 #include "list.h"
 #include "utils.h"
 
-static int inpath(char *dir, char *filename) {
-   char *filepath;
-   struct stat estat;
-
-   if (stat(filepath = catpath(dir, filename), &estat) != -1) {
-       if (estat.st_mode & S_IXUSR) {
-           puts(filepath);
-           putchar('\r');
-           return 1;
-       }
-   } else if (errno != ENOENT) note("Unable to check if `%s' exists", filepath);
-
-   return 0;
-}
-
 BUILTINSIG(which) {
+   int result;
+   size_t i, l;
    struct builtin *builtin;
-   char *path, *dir, *p;
+   char *entry, *end, dir[PATH_MAX], path[PATH_MAX];
+   struct stat pstat;
    
-   if (!argv[1]) return EXIT_FAILURE;
-   for (builtin = builtins; builtin->func; ++builtin)
-       if (strcmp(argv[1], builtin->name) == 0) {
-           printf("%s is built-in\r\n", argv[1]);
-           return EXIT_SUCCESS;
+   if (argc == 1) return EXIT_FAILURE;
+
+   result = EXIT_SUCCESS;
+   for (i = 1; argv[i]; ++i) {
+       for (builtin = builtins; builtin->func; ++builtin)
+           if (strcmp(argv[i], builtin->name) == 0) {
+               printf("%s is built-in\r\n", argv[i]);
+               break;
+           }
+       if (builtin->func) continue;
+
+       if (!(entry = getenv("PATH"))) {
+           note("Unable to examine $PATH$");
+           return EXIT_FAILURE;
+       }
+       for (end = entry; end; entry = end + 1) {
+           l = (end = strchr(entry, ':')) ? end - entry : strlen(entry);
+           strncpy(dir, entry, l);
+           dir[l] = '\0';
+           if (!catpath(dir, argv[i], path)) return EXIT_FAILURE;
+           if (stat(path, &pstat) != -1) {
+               if (pstat.st_mode & S_IXUSR) {
+                   printf("%s\r\n", path);
+                   break;
+               }
+           } else if (errno != ENOENT) {
+               note("Unable to check if `%s' exists", path);
+               return EXIT_FAILURE;
+           }
        }
+       if (entry != end + 1) continue;
 
-   if (!(path = getenv("PATH"))) {
-       note("Unable to examine $PATH$");
-       return EXIT_FAILURE;
-   }
-   if (!(path = p = strdup(path))) {
-       note("Unable to duplicate $PATH$");
-       return EXIT_FAILURE;
+       printf("%s not found\r\n", argv[i]);
+       result = EXIT_FAILURE;
    }
-   do {
-       if (!(dir = p)) break;
-       if ((p = strchr(dir, ':'))) *p++ = '\0';
-   } while (!inpath(dir, argv[1]));
-   free(path);
-   if (dir) return EXIT_SUCCESS;
 
-   printf("%s not found\r\n", argv[1]);
-   return EXIT_FAILURE;
+   return result;
 }
diff --git a/src/config.h b/src/config.h
deleted file mode 100644 (file)
index b16bd76..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#define DEFAULTPROMPT ">"
-
-#define HISTORYFILE ".ashhistory"
-#define INTFILE ".ashint"
-#define LOGINFILE ".ashlogin"
-
-#define MAXBUILTINS 100 // Maximum number of builtin commands
-#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 cc48df9b41050910e965c1ca2a4df18e1deec167..ecba616085794fb48d82494dfbecb626e70aca34 100644 (file)
@@ -1,26 +1,40 @@
-#include <stdio.h>
 #include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
 #include <string.h>
+#include <limits.h>
 #include <sys/errno.h>
 
-#include "config.h"
 #include "input.h"
+#include "shell.h"
 #include "stack.h"
 #include "utils.h"
 
-static char historyarr[MAXHIST + 1][MAXCHARS + 1];
+#define HISTORYFILE ".ashhistory"
+#define MAXHIST 100
+#define BUFFER ((char *)history.t)
+
+static char historyarr[MAXHIST + 1][MAXCHARS + 1], filepath[PATH_MAX];
 INITSTACK(history, historyarr, 1);
 
+/* TODO
+   void addhistory(char *buffer);
+   int prevhistory(char *buffer);
+   int nexthistory(char *buffer);
+*/
+
 void readhistory(void) {
+   char *p;
    FILE *file;
-
-   if (!(file = fopen(catpath(home, HISTORYFILE), "r"))) {
+   
+   if (!catpath(home, HISTORYFILE, filepath)) exit(EXIT_FAILURE);
+   if (!(file = fopen(filepath, "r"))) {
        if (errno == ENOENT) return;
        fatal("Unable to open history file for reading");
    }
-   while (fgets(buffer, history.size, file)) {
-       *(buffer + strlen(buffer) - 1) = '\0';
-       push(&history, buffer);
+   while (fgets(BUFFER, history.size, file)) {
+       *(BUFFER + strlen(BUFFER) - 1) = '\0';
+       push(&history, BUFFER);
    }
    if (ferror(file) || !feof(file))
        fatal("Unable to read from history file");
@@ -28,9 +42,10 @@ void readhistory(void) {
 }
 
 void writehistory(void) {
+   char *filename;
    FILE *file;
 
-   if (!(file = fopen(catpath(home, HISTORYFILE), "w"))) {
+   if (!(file = fopen(filepath, "w"))) {
        note("Unable to open history file for writing");
        return;
    }
index dea4330379ece545266efe34911df4a94cfb1214..78082205355ace2ce0eb189507a42d7e2032d6e4 100644 (file)
@@ -1,20 +1,20 @@
 #include <fcntl.h>
-#include <signal.h>
+#include <limits.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 "shell.h"
+#include "history.h"
 #include "stack.h"
 #include "utils.h"
 
+#define DEFAULTPROMPT ">"
+
 enum {
    CTRLC = '\003',
    CTRLD,
@@ -31,73 +31,65 @@ enum {
    DEL = '\177',
 };
 
-char *string, buffer[MAXCHARS + 2], *script;
-
 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 (!*shell->string) {
+       if (shell->script && munmap(shell->map.m, shell->map.l) == -1)
+           note("Unable to unmap memory associated with `%s'", shell->script);
+       return NULL;
+   }
+   start = shell->string;
+   while (*shell->string && *shell->string != '\n') ++shell->string;
+   l = shell->string - start;
+   if (*shell->string == '\n') ++shell->string;
+// puts("test\r\n");
    if (l > MAXCHARS) fatal("Line too long, exceeds %d character limit", MAXCHARS);
-   strncpy(buffer, start, l);
-   buffer[l] = ';';
-   buffer[l + 1] = '\0';
+   strncpy(shell->buffer, start, l);
+   shell->buffer[l] = ';';
+   shell->buffer[l + 1] = '\0';
 
-   return buffer;
+   return shell;
 }
 
 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;
+   if ((fd = open(shell->script, O_RDONLY)) == -1)
+       fatal("Unable to open `%s'", shell->script);
+   if (stat(shell->script, &sstat) == -1)
+       fatal("Unable to stat `%s'", shell->script);
+   if ((shell->map.l = sstat.st_size) == 0) return NULL;
+   if ((shell->string = shell->map.m = mmap(NULL, shell->map.l, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED)
+       fatal("Unable to memory map `%s'", shell->script);
+   if (close(fd) == -1) fatal("Unable to close `%s'", shell->script);
+   shell->input = stringinput;
+
+   return shell->input(shell);
 }
 
-char *config(char *name) {
+static struct shell *config(char *name) {
    int fd;
-   char *result;
-   static char *origscript, *origstr;
-
-   if (!origscript) {
-       origscript = script;
-       origstr = string;
-       script = catpath(home, name);
-   }
-
-   if ((fd = open(script, O_RDONLY | O_CREAT, 0644)) == -1)
-       fatal("Unable to open `%s'\n", script);
-   if (close(fd) == -1)
-       fatal("Unable to close `%s'", script);
-
-   if (!(result = scriptinput())) {
-       script = origscript;
-       string = origstr;
-       origscript = NULL;
+   struct shell *result;
+   static struct shell shell;
+   static char path[PATH_MAX];
+
+   if (!shell.script) {
+       shell.script = catpath(home, name, path);
+       shell.input = scriptinput;
+
+       if ((fd = open(shell.script, O_RDONLY | O_CREAT, 0644)) == -1)
+           fatal("Unable to open `%s'", shell.script);
+       if (close(fd) == -1)
+           fatal("Unable to close `%s'", shell.script);
    }
 
-   return result;
+   result = shell.input(&shell);
+   if (result) return result;
+   shell.script = NULL;
+   return NULL;
 }
 
 static size_t prompt(void) {
@@ -110,20 +102,20 @@ static size_t prompt(void) {
 }
 
 INPUT(userinput) {
-   char *cursor, *end;
+   char *start, *cursor, *end;
    size_t promptlen;
    unsigned int c;
    int i;
 
-   end = cursor = buffer;
-   *history.t = *buffer = '\0';
+   end = cursor = start = shell->buffer;
+   *history.t = *start = '\0';
    history.c = history.t;
-   while (buffer == end) {
+   while (start == end) {
        promptlen = prompt();
        while ((c = getchar()) != '\r') switch (c) {
        default:
            if (c >= ' ' && c <= '~') {
-               if (end - buffer == MAXCHARS) continue;
+               if (end - start == MAXCHARS) continue;
                memmove(cursor + 1, cursor, end - cursor);
                *cursor++ = c;
                *++end = '\0';
@@ -135,15 +127,15 @@ INPUT(userinput) {
            break;
        case CTRLC:
            puts("^C\r");
-           *buffer = '\0';
-           return buffer;
+           *start = '\0';
+           return shell;
        case CTRLD:
            puts("^D\r");
            return NULL;
        case CLEAR:
            fputs("\033[H\033[J", stdout);
            prompt();
-           fputs(buffer, stdout);
+           fputs(start, stdout);
            continue;
        case ESCAPE:
            switch ((c = getchar())) {
@@ -152,8 +144,8 @@ INPUT(userinput) {
                while (cursor != end && *cursor == ' ') putchar(*cursor++);
                break;
            case BACKWARD:
-               while (cursor != buffer && *(cursor - 1) == ' ') putchar((--cursor, '\b'));
-               while (cursor != buffer && *(cursor - 1) != ' ') putchar((--cursor, '\b'));
+               while (cursor != start && *(cursor - 1) == ' ') putchar((--cursor, '\b'));
+               while (cursor != start && *(cursor - 1) != ' ') putchar((--cursor, '\b'));
                break;
            case ARROW:
                switch ((c = getchar())) {
@@ -162,20 +154,20 @@ INPUT(userinput) {
                    if (history.c == (c == UP ? history.b : history.t)) continue;
 
                    putchar('\r');
-                   for (i = end - buffer + promptlen; i > 0; --i) putchar(' ');
+                   for (i = end - start + promptlen; i > 0; --i) putchar(' ');
                    putchar('\r');
 
-                   if (strcmp((char *)history.c, buffer) != 0)
-                       strcpy((char *)history.t, buffer);
+                   if (strcmp((char *)history.c, start) != 0)
+                       strcpy((char *)history.t, start);
                    if (c == UP) DEC(history, c); else INC(history, c);
-                   strcpy(buffer, (char *)history.c);
-                   end = cursor = buffer + strlen(buffer);
+                   strcpy(start, (char *)history.c);
+                   end = cursor = start + strlen(start);
 
                    prompt();
-                   fputs(buffer, stdout);
+                   fputs(start, stdout);
                    break;
                case LEFT:
-                   if (cursor > buffer) putchar((--cursor, '\b'));
+                   if (cursor > start) putchar((--cursor, '\b'));
                    break;
                case RIGHT:
                    if (cursor < end) putchar(*cursor++);
@@ -188,7 +180,7 @@ INPUT(userinput) {
            break;
        case BACKSPACE:
        case DEL:
-           if (cursor == buffer) continue;
+           if (cursor == start) continue;
            memmove(cursor - 1, cursor, end - cursor);
            --cursor;
            *--end = '\0';
@@ -202,10 +194,10 @@ INPUT(userinput) {
        }
        puts("\r");
    }
-   push(&history, buffer);
+   push(&history, start);
 
    *end++ = ';';
    *end = '\0';
 
-   return buffer;
+   return shell;
 }
index eae90c51acfcb82e19c85ac2c4f1954e9aa93205..50dc132be6a75fb9fbae4bc41ce6fdf7873a78ad 100644 (file)
@@ -1,8 +1,8 @@
-#define INPUT(name) char *name(void)
+#define INPUT(name) struct shell *name(struct shell *shell)
 
-extern char *string, buffer[MAXCHARS + 2], *script;
+typedef INPUT((*Input));
 
 INPUT(stringinput);
 INPUT(scriptinput);
-char *config(char *name);
+// struct shell *config(char *name);
 INPUT(userinput);
index a412e890126a493803b7d0dd212ad99900d9b604..857dfe4d6f4f27d3a3b64668bd33f113a8599c53 100644 (file)
--- a/src/job.c
+++ b/src/job.c
@@ -1,26 +1,25 @@
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
+#include <stdint.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 jobarr[MAXJOBS + 1];
 INITSTACK(jobs, jobarr, 0);
-struct termios raw, canonical;
-struct sigaction sigchld, sigdfl, sigign;
-static int fgstatus;
+int fgstatus;
+
+/* TODO
+   addjob
+   popjob
+   findjob
+*/
 
 void *findjob(pid_t jobid) {
    if (jobs.b == jobs.t) return NULL;
-   for (jobs.c = jobs.b; CURRENT->id != jobid; INC(jobs, c))
+   for (jobs.c = jobs.b; JOB->id != jobid; INC(jobs, c))
        if (jobs.c == jobs.t) return NULL;
    return jobs.c;
 }
@@ -30,71 +29,3 @@ void *deletejob(void) {
    memmove(jobs.c, PLUSONE(jobs, c), jobs.t - jobs.c);
    return DEC(jobs, t);
 }
-
-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) {
-   while (waitpid(job.id, NULL, 0) != -1);
-   errno = 0;
-
-   if (sigaction(SIGTTOU, &sigign, NULL) == -1
-       || tcsetpgrp(STDIN_FILENO, getpgrp()) == -1
-       || sigaction(SIGTTOU, &sigdfl, NULL) == -1) {
-       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 (WIFEXITED(fgstatus)) return WEXITSTATUS(fgstatus);
-   else if (WIFSIGNALED(fgstatus)) return WTERMSIG(fgstatus);
-   job.type = SUSPENDED;
-   if (!push(&jobs, &job)) {
-       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);
-   }
-   return WSTOPSIG(fgstatus);
-}
-
-void sigchldhandler(int sig) {
-   int status;
-   pid_t id;
-
-   (void)sig;
-   while ((id = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
-       for (jobs.c = jobs.b; jobs.c != jobs.t; INC(jobs, c)) if (CURRENT->id == id) {
-           if (WIFSTOPPED(status)) CURRENT->type = SUSPENDED;
-           else deletejob();
-           break;
-       }
-       if (jobs.c == jobs.t) {
-           fgstatus = status;
-           if (!WIFSTOPPED(fgstatus)) while (waitpid(-id, NULL, 0) != -1);
-       }
-   }
-}
index 7b33124870a8e77062ec110066d5077a04181131..1a6f2887dc644241de1adc0950add3a258f82ca4 100644 (file)
--- a/src/job.h
+++ b/src/job.h
@@ -1,4 +1,4 @@
-#define CURRENT ((struct job *)jobs.c)
+#define JOB ((struct job *)jobs.c)
 
 enum jobtype {
    BACKGROUND,
@@ -12,12 +12,7 @@ struct job {
 };
 
 extern struct stack jobs;
-extern struct termios raw, canonical;
-extern struct sigaction sigchld, sigdfl, sigign;
+extern int fgstatus;
 
 void *findjob(pid_t jobid);
 void *deletejob(void);
-int setconfig(struct termios *mode);
-int setfg(struct job job);
-int waitfg(struct job job);
-void sigchldhandler(int sig);
index a547092874e09c3098dea2edade4058621920eaa..12b278ebb7f37523ce78a3352e0728d3c81e10c5 100644 (file)
@@ -1,24 +1,25 @@
 #include <stdlib.h>
 
-#include "config.h"
 #include "input.h"
+#include "shell.h"
 #include "options.h"
 #include "parse.h"
 #include "run.h"
 #include "utils.h"
+#include "source.h"
 
-int main(int localargc, char **localargv) {
-   argc = localargc;
-   argv = localargv;
+int main(int c, char **v) {
+   argc = c;
+   argv = v;
 
    options();
 
    initialize();
 
-   if (login) while (run(parse(config(LOGINFILE))));
-   if (interactive) while (run(parse(config(INTFILE))));
+   if (login) config(".ashlogin");
+   if (interactive) config(".ashint");
 
-   while (run(parse(input())));
+   while (run(parse(shell.input(&shell))));
 
    deinitialize();
 
index 0476c18cfba909eeaa99d6f407268668ea1ebc6e..d54ca9bf7fdd89787a7fe7f09bd25510d995f2f6 100644 (file)
@@ -3,14 +3,14 @@
 #include <stdlib.h>
 #include <unistd.h>
 
-#include "config.h"
 #include "input.h"
-#include "options.h"
+#include "shell.h"
 
 int login, interactive, argc;
-Input input;
 char **argv;
 
+struct shell shell;
+
 static void usage(char *program, int code) {
    printf("Usage: %s [file] [-c string] [-hl]\n"
           "    <file> ...      Run script\n"
@@ -25,14 +25,14 @@ void options(void) {
 
    login = **argv == '-';
    interactive = 1;
-   input = userinput;
+   shell.input = userinput;
 
    while ((opt = getopt(argc, argv, ":c:hl")) != -1) {
        switch (opt) {
        case 'c':
            interactive = 0;
-           input = stringinput;
-           string = optarg;
+           shell.string = optarg;
+           shell.input = stringinput;
            break;
        case 'h':
            usage(*argv, EXIT_SUCCESS);
@@ -49,10 +49,10 @@ void options(void) {
        }
        if (opt == 'c') break;
    }
-   if (!string && argv[optind]) {
+   if (!shell.string && argv[optind]) {
        interactive = 0;
-       input = scriptinput;
-       script = argv[optind];
+       shell.script = argv[optind];
+       shell.input = scriptinput;
    }
    if (!interactive) {
        argc -= optind;
index 991820771a4769c9ad2abddfc4e5540be2221081..3186fadfb0bb3b2461e4c2bb3a682a7ba96e54b8 100644 (file)
@@ -1,7 +1,5 @@
-typedef INPUT((*Input));
-
 extern int login, interactive, argc;
-extern Input input;
 extern char **argv;
+extern struct shell shell;
 
 void options(void);
index e377aa58593f63d1d4220790bd2ca7d4ba8d541b..37ad6ebaa4a21f30e417cf561642feb351386d37 100644 (file)
@@ -3,16 +3,12 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "config.h"
 #include "input.h"
+#include "shell.h"
 #include "options.h"
-#include "parse.h"
 #include "run.h"
 #include "utils.h"
 
-static char *tokens[MAXCHARS + 1];
-static struct cmd cmds[MAXCMDS + 1];
-
 static void initcmd(struct cmd *cmd) {
    cmd->args = NULL;
    cmd->r = cmd->rds;
@@ -21,18 +17,19 @@ static void initcmd(struct cmd *cmd) {
    cmd->next = NULL;
 }
 
-struct cmd *parse(char *b) {
-   char **t, *name, *value, *stlend, *p, *end, *env;
+struct shell *parse(struct shell *shell) {
+   char *b, **t, *name, *value, *stlend, *p, *end, *env;
    struct cmd *c;
    long l;
    int e, offset;
    
-   if (!b) return NULL;
-   t = tokens;
-   c = cmds;
-   c->next = c + 1;
-   value = name = NULL;
-   for (initcmd(++c); *b; ++b) switch (*b) {
+   if (!shell) return NULL;
+   b = shell->buffer;
+   t = shell->tokens;
+   c = shell->cmds + 1;
+   shell->cmds->next = NULL;
+   *t = value = name = NULL;
+   for (initcmd(c); *b; ++b) switch (*b) {
    default:
        if (c->r->mode) break;
        if (!c->args) c->args = t;
@@ -44,14 +41,14 @@ struct cmd *parse(char *b) {
    case '>':
        if (c->r->mode) {
            note("File redirections should be separated by spaces");
-           return c;
+           return shell;
        }
        c->r->newfd = *b == '>';
        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 c;
+               return shell;
            }
            c->r->newfd = l;
        }
@@ -73,7 +70,7 @@ struct cmd *parse(char *b) {
        }
        if (!b) {
            note("Quote left open-ended");
-           return c;
+           return shell;
        }
        memmove(p, p + 1, end-- - p);
        --b;
@@ -112,7 +109,7 @@ struct cmd *parse(char *b) {
        while (*b && *b != '$') ++b;
        if (!*b) {
            note("Environment variable lacks a terminating `$'");
-           return c;
+           return shell;
        }
        *b++ = '\0';
        for (end = b; *end; ++end);
@@ -122,11 +119,11 @@ struct cmd *parse(char *b) {
        else if (strcmp(p + 1, "?") == 0) {
            if (!sprintf(env = (char [12]){0}, "%d", status)) {
                note("Unable to get previous command status");
-               return c;
+               return shell;
            }
        } else if ((env = getenv(p + 1)) == NULL) {
            note("Environment variable does not exist");
-           return c;
+           return shell;
        }
 
        e = strlen(env);
@@ -162,7 +159,7 @@ struct cmd *parse(char *b) {
                if ((l = strtol(++c->r->oldname, &stlend, 10)) < 0
                    || l > INT_MAX || *stlend) {
                    note("Incorrect syntax for file redirection");
-                   return c;
+                   return shell;
                }
                c->r->oldfd = l;
                c->r->oldname = NULL;
@@ -178,7 +175,7 @@ struct cmd *parse(char *b) {
        if (value) {
            if (setenv(name, value, 1) == -1) {
                note("Unable to set environment variable");
-               return c;
+               return shell;
            }
            value = name = NULL;
        }
@@ -191,10 +188,11 @@ struct cmd *parse(char *b) {
    case PIPE:
    case OR:
        note("Expected another command");
-       return c;
+       return shell;
    default:
        break;
    }
 
-   return cmds;
+   shell->cmds->next = shell->cmds + 1;
+   return shell;
 }
index 29623943265c8dc93851b90619eba63f1cafa9e1..4053bf5ec90e82b3c9d53ad94fbed4b93c9ffb99 100644 (file)
@@ -1,31 +1 @@
-enum accessmode {
-   END,
-   READ = '<',
-   READWRITE,
-   WRITE = '>',
-   APPEND,
-};
-
-struct redirect {
-   enum accessmode mode;
-   int oldfd, newfd;
-   char *oldname;
-};
-
-enum terminator {
-   SEMI = ';',
-   BG = '&',
-   AND,
-   PIPE = '|',
-   OR,
-};
-
-struct cmd {
-   char **args;
-   struct redirect *r, rds[MAXRDS + 1];
-   enum terminator term;
-   int pipe[2];
-   struct cmd *prev, *next;
-};
-
-struct cmd *parse(char *b);
+struct shell *parse(struct shell *shell);
index e78656bc627a36c7ba0bbea3a56428fbc068ea4e..f66e3edb7ed0b3db5f93e185f789829b1975a7ac 100644 (file)
--- a/src/run.c
+++ b/src/run.c
@@ -4,11 +4,15 @@
 #include <sys/errno.h>
 #include <termios.h>
 #include <unistd.h>
+#include <limits.h>
+#include <stdio.h> // XXX
 
+#include "input.h"
+#include "shell.h"
+#include "alias.h"
 #include "builtin.h"
-#include "config.h"
 #include "job.h"
-#include "parse.h"
+#include "fg.h"
 #include "stack.h"
 #include "utils.h"
 
@@ -55,23 +59,25 @@ static void redirectfiles(struct redirect *r) {
 }
 
 static void exec(struct cmd *cmd) {
-   char *cwd;
+   char cwd[PATH_MAX];
 
    execvp(*cmd->args, cmd->args);
-   if (!(cwd = getcwd(NULL, 0)))
-       fatal("Unable to check current working directory");
+   if (!getcwd(cwd, PATH_MAX)) fatal("Unable to check current working directory");
    execvP(*cmd->args, cwd, cmd->args);
-   free(cwd);
    fatal("Couldn't find `%s' command", *cmd->args);
 }
 
-int run(struct cmd *cmd) {
+int run(struct shell *shell) {
+   struct cmd *cmd;
    int ispipe, ispipestart, ispipeend;
    pid_t cpid, jobid;
    struct job job;
 
-   if (!cmd) return 0;
+   if (!shell) return 0;
 
+   applyaliases(shell);
+
+   cmd = shell->cmds;
    while ((cmd = cmd->next)) {
        if (!cmd->args) {
            if (!cmd->r->mode) break;
index 7760e69ed1adf6886cbb80ea94865e7854a94f7e..cebcc90b7f63a66c19aefef3428a824cda5448d9 100644 (file)
--- a/src/run.h
+++ b/src/run.h
@@ -1,3 +1,3 @@
 extern int status;
 
-int run(struct cmd *cmd);
+int run(struct shell *shell);
diff --git a/src/shell.h b/src/shell.h
new file mode 100644 (file)
index 0000000..a153acd
--- /dev/null
@@ -0,0 +1,43 @@
+#define MAXCHARS 500
+#define MAXCMDS (MAXCHARS + 1) / 2
+#define MAXRDS (MAXCHARS / 3)
+
+enum accessmode {
+   END,
+   READ = '<',
+   READWRITE,
+   WRITE = '>',
+   APPEND,
+};
+
+struct redirect {
+   enum accessmode mode;
+   int oldfd, newfd;
+   char *oldname;
+};
+
+enum terminator {
+   SEMI = ';',
+   BG = '&',
+   AND,
+   PIPE = '|',
+   OR,
+};
+
+struct cmd {
+   char **args;
+   struct redirect *r, rds[MAXRDS + 1];
+   enum terminator term;
+   int pipe[2];
+   struct cmd *prev, *next;
+};
+
+struct shell {
+   char buffer[MAXCHARS + 1 + 1], *tokens[MAXCMDS + 1], *script, *string;
+   struct {
+       char *m;
+       size_t l;
+   } map;
+   struct cmd cmds[MAXCMDS + 1];
+   Input input;
+};
index b8cf6b91b71716fc186c7e6aec9301f97cda7f3e..30e379935e268f1a3fc0cf2334b01d4660270dc1 100644 (file)
@@ -1,4 +1,5 @@
 #include <err.h>
+#include <limits.h>
 #include <signal.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -8,13 +9,14 @@
 #include <termios.h>
 #include <unistd.h>
 
-#include "config.h"
 #include "history.h"
 #include "input.h"
 #include "job.h"
 #include "options.h"
-#include "utils.h"
+#include "stack.h"
 
+struct termios raw, canonical;
+struct sigaction sigchld, sigdfl, sigign;
 char *home;
 
 void note(char *fmt, ...) {
@@ -35,54 +37,78 @@ void fatal(char *fmt, ...) {
    exit(EXIT_FAILURE);
 }
 
-char *catpath(char *dir, char *filename) {
-   static char path[MAXPATH + 1];
-   
-   strcpy(path, dir);
-   strcat(path, "/");
-   strcat(path, filename);
+int setconfig(struct termios *mode) {
+   if (tcsetattr(STDIN_FILENO, TCSANOW, mode) == -1) {
+       note("Unable to set termios config");
+       return 0;
+   }
+   return 1;
+}
+
+static void sigchldhandler(int sig) {
+   int status;
+   pid_t id;
 
-   return path;
+   (void)sig;
+   while ((id = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
+       for (jobs.c = jobs.b; jobs.c != jobs.t; INC(jobs, c))
+           if (JOB->id == id) {
+               if (WIFSTOPPED(status)) JOB->type = SUSPENDED;
+               else deletejob();
+               break;
+           }
+       if (jobs.c == jobs.t) {
+           fgstatus = status;
+           if (!WIFSTOPPED(fgstatus)) while (waitpid(-id, NULL, 0) != -1);
+       }
+   }
 }
 
 void initialize(void) {
-   char *shlvlstr;
+   char *shlvlstr, buffer[19 + 1];
    long shlvl;
 
-   // Raw mode
    if (tcgetattr(STDIN_FILENO, &canonical) == -1)
        err(EXIT_FAILURE, "Unable to get default termios config");
    cfmakeraw(&raw);
    if (!setconfig(&raw)) exit(EXIT_FAILURE);
 
-   // Set signal actions
    sigchld.sa_handler = sigchldhandler;
    sigdfl.sa_handler = SIG_DFL;
    sigign.sa_handler = SIG_IGN;
    if (sigaction(SIGCHLD, &sigchld, NULL) == -1)
        fatal("Unable to install SIGCHLD handler");
 
-   // Initialize `home'
    if (!(home = getenv("HOME")))
        fatal("Unable to locate user's home directory, $HOME$ not set");
 
-   // Update $SHLVL$
    if (!(shlvlstr = getenv("SHLVL"))) shlvlstr = "0";
    if ((shlvl = strtol(shlvlstr, NULL, 10)) < 0) shlvl = 0;
-   asprintf(&shlvlstr, "%ld", shlvl + 1);
+   sprintf(shlvlstr = buffer, "%ld", shlvl + 1);
    if (setenv("SHLVL", shlvlstr, 1) == -1)
        note("Unable to update $SHLVL$ environment variable");
-   free(shlvlstr);
 
-   // History read
    if (interactive) readhistory();
 }
 
-void deinitialize(void) {
+char *catpath(char *dir, char *filename, char *buffer) {
+   int slash;
 
-   // History write
+   slash = dir[strlen(dir) - 1] == '/';
+   if (strlen(dir) + slash + strlen(filename) + 1 > PATH_MAX) {
+       note("Path name `%s%s%s' too long", dir, slash ? "/" : "", filename);
+       return NULL;
+   }
+   
+   strcpy(buffer, dir);
+   if (!slash) strcat(buffer, "/");
+   strcat(buffer, filename);
+
+   return buffer;
+}
+
+void deinitialize(void) {
    if (interactive) writehistory();
 
-   // Canonical mode
    setconfig(&canonical);
 }
index 24bd6e8eb7a8e0956c4d4a70bec772063fde6883..1cbc15e3accefd58f14383a1f2eead90ebc93e7b 100644 (file)
@@ -1,7 +1,10 @@
+extern struct termios raw, canonical;
+extern struct sigaction sigchld, sigdfl, sigign;
 extern char *home;
 
 void note(char *fmt, ...);
 void fatal(char *fmt, ...);
-char *catpath(char *dir, char *filename);
+int setconfig(struct termios *mode);
 void initialize(void);
+char *catpath(char *dir, char *filename, char *buffer);
 void deinitialize(void);