]> Trent Huber's Code - thus.git/commitdiff
Finish README.md, finish cleaning
authorTrent Huber <trentmhuber@gmail.com>
Wed, 27 Aug 2025 08:40:05 +0000 (04:40 -0400)
committerTrent Huber <trentmhuber@gmail.com>
Wed, 27 Aug 2025 08:40:05 +0000 (04:40 -0400)
37 files changed:
README.md
external/cbsext.c [deleted file]
src/build.c
src/builtin/README.md [deleted file]
src/builtin/alias.h [deleted file]
src/builtin/build.c [deleted file]
src/builtin/pwd.c [deleted file]
src/builtins/.gitignore [moved from src/builtin/.gitignore with 100% similarity]
src/builtins/README.md [new file with mode: 0644]
src/builtins/alias.c [moved from src/builtin/alias.c with 88% similarity]
src/builtins/alias.h [new file with mode: 0644]
src/builtins/bg.c [moved from src/builtin/bg.c with 97% similarity]
src/builtins/bg.h [moved from src/builtin/bg.h with 100% similarity]
src/builtins/build.c [new file with mode: 0644]
src/builtins/builtin.c [moved from src/builtin/builtin.c with 63% similarity]
src/builtins/builtin.h [moved from src/builtin/builtin.h with 100% similarity]
src/builtins/cd.c [moved from src/builtin/cd.c with 97% similarity]
src/builtins/fg.c [moved from src/builtin/fg.c with 98% similarity]
src/builtins/fg.h [moved from src/builtin/fg.h with 100% similarity]
src/builtins/list.h [moved from src/builtin/list.h with 100% similarity]
src/builtins/pwd.c [new file with mode: 0644]
src/builtins/set.c [moved from src/builtin/set.c with 100% similarity]
src/builtins/source.c [moved from src/builtin/source.c with 95% similarity]
src/builtins/source.h [moved from src/builtin/source.h with 100% similarity]
src/builtins/unset.c [moved from src/builtin/unset.c with 100% similarity]
src/builtins/which.c [moved from src/builtin/which.c with 86% similarity]
src/builtins/which.h [moved from src/builtin/which.h with 100% similarity]
src/context.c
src/history.c
src/input.c
src/libbuiltins.a [new file with mode: 0644]
src/options.c
src/parse.c
src/run.c
src/utils.c
tools/install.c
tools/uninstall.c

index 09408b07d50183de75ae1309d65bfdf1224f7570..c353907bf36c3201437c2eed01cc925c4045a7a3 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,38 +1,64 @@
 # thus
 
-While Unix shells are a solved problem in computer science, recent iterations have admittedly been more and more complicated by feature sets that attempt to cater to all users. Ash seeks to be a completely stripped down, simplified approach to shells, only including the essential parts, i.e., just the things *I personally use*. In fact, the main goals for this project in order or priority have been:
+thus is a custom UNIX shell built entirely from scratch for POSIX platforms.
 
-1. To learn more about the interaction between shells, terminals, and the operating system.
-2. To create a utility I would personally want to use.
-3. To create a utility other people would want to use.
+## Features
 
-## Feature Set
-
-- Foreground and background process groups (`fg`, `bg`, `&`)
-- Unix pipes
+- Job control (`fg`, `bg`, `&`, `^Z`)
+- Pipelines
 - Conditional execution (`&&`, `||`)
-- Shell history (cached in `~/.thushistory`)
-- File redirection
-- Environment variables
-- File globbing
+- File redirection (`<file`, `2>&1`, etc.)
+- Globbing (`*`, `?`, `[...]`)
+- Quoting with escape sequences (`"\r...\n"`)
+- Environment variables (`set`, `unset`, `$VAR$`, etc.)
+- Aliasing (`alias`, `unalias`)
+- Configuration files (`~.thuslogin`, `~.thusrc`)
+- Cached history (`~.thushistory`)
+- [Automated integration of built-in commands](src/builtins/README.md)
 
 ## Building
 
-Similar to my other projects, thus uses [cbs](https://github.com/trenthuber/cbs) as its build system, included as a git submodule, so make sure to clone recursively.
+thus uses [cbs](https://github.com/trenthuber/cbs/) as its build system.
 
 ```console
-$ git clone --recursive https://github.com/trenthuber/thus
-$ cd thus
-$ cc -o build build.c
-$ ./build
-$ ./bin/thus
+> git clone --recursive https://github.com/trenthuber/thus/
+> cd thus/
+> cc -o build build.c
+> build
 ```
 
-Note, you only need to run the `cc` command the first time you build the project, as the `./build` executable will recompile itself everytime it is run.
+After building, you can use `install` to add the shell to your path. The default installation prefix is `/usr/local/`, but a custom one can be passed as an argument to the utility.
 
-## Resources
+```console
+> sudo ./install
+```
+
+After installing, you can use `uninstall` to remove the shell from the install location.
+
+```console
+> sudo ./uninstall
+```
+
+## Quirks
 
-These websites have been invaluable in the making of thus.
+While thus operates for the most part like Bourne shell, there are a few places where it takes a subtly different approach.
+
+### Quotes
+
+Quoting is done with double quotes (`"..."`) and undergoes no shell substitution, similar to single quotes in Bourne shell. In place of substitution, quotes can be concatenated with surrounding tokens not separated by whitespace.
+
+### Environment variables and aliases
+
+Environment variables are referred to by tokens that begin and end with a `$`. For example, evaluating the path would look like `$PATH$`. Setting environment variables is done with the `set` built-in command, not with the `name=value` syntax. This syntax is similarly avoided when declaring aliases with the `alias` built-in command.
+
+### Leading and trailing slashes
+
+Prepending `./` to executables located in the current directory is not mandatory unless there already exists an executable in `$PATH$` with the same name that you would like to override.
+
+The `$HOME$`, `$PWD$`, and `$PATH$` environment variables are always initialized with trailing slashes. Therefore, whenever one of these variables or `~` is substituted in the shell, it will retain the trailing slash.
+
+## Resources
 
 - [TTY Demystified](http://www.linusakesson.net/programming/tty/)
 - [Process Groups and Terminal Signaling](https://cs162.org/static/readings/ic221_s16_lec17.html)
+- [Terminal Input Sequences](https://en.wikipedia.org/wiki/ANSI_escape_code#Terminal_input_sequences)
diff --git a/external/cbsext.c b/external/cbsext.c
deleted file mode 100644 (file)
index e4657e8..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-struct cbsfile {
-   char *name, **flags, type;
-};
-
-void buildfiles(struct cbsfile *files) {
-   char **c, **l, **names;
-   struct cbsfile *target;
-   size_t i;
-
-   c = cflags;
-   l = lflags;
-
-   target = files++;
-
-   for (i = 0; files[i].name; ++i) if (files[i].flags) {
-       cflags = files[i].flags;
-       compile(files[i].name);
-   }
-
-   names = allocate((i + 1) * sizeof *names);
-   for (i = 0; files[i].name; ++i) names[i] = files[i].name;
-
-   lflags = target->flags;
-   load(target->type, target->name, names);
-
-   free(names);
-
-   cflags = c;
-   lflags = l;
-}
index 07a1eac5d64de9e09cc7d570a74ad8350fdb1b1b..177e59cc2b7c2a193846dc7d6414ddda923d1221 100644 (file)
@@ -1,27 +1,20 @@
 #include "../external/cbs/cbs.c"
-#include "../external/cbsext.c"
 
-#define BUILTINS LIST("-Ibuiltin/")
+#define SRC1 "context", "history", "input"
+#define SRC2 "main", "options", "parse", "run", "utils"
 
 int main(void) {
-   build("./");
-
-   build("builtin/");
+   char **src;
 
-   buildfiles((struct cbsfile []){{"../bin/thus", NONE, 'x'},
+   build("./");
 
-                                  {"context", NONE},
-                                  {"history", NONE},
-                                  {"input", NONE},
-                                  {"main", BUILTINS},
-                                  {"options", BUILTINS},
-                                  {"parse", BUILTINS},
-                                  {"run", BUILTINS},
-                                  {"utils", BUILTINS},
+   build("builtins/");
 
-                                  {"builtin.a"},
+   for (src = LIST(SRC1); *src; ++src) compile(*src);
+   cflags = LIST("-Ibuiltins/");
+   for (src = LIST(SRC2); *src; ++src) compile(*src);
 
-                                  {NULL}});
+   load('x', "../bin/thus", LIST(SRC1, SRC2, "builtins.a"));
 
    return EXIT_SUCCESS;
 }
diff --git a/src/builtin/README.md b/src/builtin/README.md
deleted file mode 100644 (file)
index 65108f7..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-# Builtins
-
-## TODO
- - Documentation on how to add builtins of your own
- - unalias builtin
diff --git a/src/builtin/alias.h b/src/builtin/alias.h
deleted file mode 100644 (file)
index 52a3725..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-char *getaliasrhs(char *token);
-char **getalias(char *token);
diff --git a/src/builtin/build.c b/src/builtin/build.c
deleted file mode 100644 (file)
index 36f41e2..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-#include <err.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <string.h>
-#include <sys/errno.h>
-
-#include "../../external/cbs/cbs.c"
-#include "../../external/cbsext.c"
-
-#define MAXBUILTINS 50
-
-int main(void) {
-   int listfd, l;
-   DIR *dir;
-   size_t i, offset;
-
-   /* The three extra files are:
-    * 1) ../libbuiltin.a (target file)
-    * 2) list.c (generated by this code)
-    * 3) builtin.c (not a builtin, just the API)
-    * 
-    * The remaining files all correspond to shell builtins. */
-   struct cbsfile files[3 + MAXBUILTINS + 1];
-
-   struct dirent *entry;
-   char *name, *identifier;
-
-   build("./");
-
-   if ((listfd = open("list.c", O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1)
-       err(EXIT_FAILURE, "Unable to open/create `list.c'");
-   if (!(dir = opendir("./")))
-       err(EXIT_FAILURE, "Unable to open current directory");
-
-   dprintf(listfd, "#include <stddef.h>\n\n#include \"builtin.h\"\n"
-           "#include \"list.h\"\n\n");
-
-   errno = i = 0;
-   files[i++] = (struct cbsfile){"../builtin", NONE, 's'};
-   files[i++] = (struct cbsfile){"list", NONE};
-   offset = i;
-   while ((entry = readdir(dir))) {
-       if (strcmp(entry->d_name, "build.c") == 0) continue;
-       if (!(name = strrchr(entry->d_name, '.')) || strcmp(name, ".c") != 0)
-           continue;
-       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)))
-           err(EXIT_FAILURE, "Unable to duplicate directory entry");
-       name[strlen(name) - strlen(".c")] = '\0';
-       if (strcmp(name, "list") == 0) continue;
-       if (strcmp(name, "builtin") != 0)
-           dprintf(listfd, "extern BUILTIN(%s);\n", name);
-       files[i++] = (struct cbsfile){name, LIST("-I../")};
-   }
-   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);
-   for (i = offset; (name = files[i].name); ++i)
-       if (strcmp(name, "builtin") != 0 && strcmp(name, "list") != 0)
-           dprintf(listfd, "{\"%s\", %s},\n%*s", name, name, l, "");
-   dprintf(listfd, "{NULL}};");
-
-   if (closedir(dir) == -1)
-       err(EXIT_FAILURE, "Unable to close current directory");
-   if (close(listfd) == -1) err(EXIT_FAILURE, "Unable to close `list.c'");
-
-   buildfiles(files);
-
-   while (files[offset].name) free(files[offset++].name);
-
-   return EXIT_SUCCESS;
-}
diff --git a/src/builtin/pwd.c b/src/builtin/pwd.c
deleted file mode 100644 (file)
index c9e6e2d..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "builtin.h"
-#include "utils.h"
-
-BUILTIN(pwd) {
-   char *cwd, buffer[PATH_MAX];
-
-   if (argc != 1) return usage(argv[0], NULL);
-
-   if (!(cwd = getenv("PWD")) && !(cwd = getcwd(buffer, PATH_MAX)))
-       fatal("Unable to get current working directory");
-
-   puts(cwd);
-
-   return EXIT_SUCCESS;
-}
diff --git a/src/builtins/README.md b/src/builtins/README.md
new file mode 100644 (file)
index 0000000..3c1954b
--- /dev/null
@@ -0,0 +1,22 @@
+# Adding a built-in shell command
+
+To add a built-in command to the shell, first make a source file in the `src/builtins/` directory with the same name as the built-in. The source file should contain at least the following code (where "foo" is the name of the built-in).
+
+```c
+// foo.c
+
+#include <stdlib.h>
+
+#include "builtin.h"
+#include "utils.h"
+
+BUILTIN(foo) {
+    return EXIT_SUCCESS;
+}
+```
+
+The `BUILTIN()` macro is defined in [`builtin.h`](builtin.h#L1) and provides an interface similar to that of `main()`, passing the arguments from the user as an array of C strings (`argv`) along with a count (`argc`). This allows you to write code for built-ins exactly as you would write them in a regular C program.
+
+Errors should be reported to the user using the `note()` function defined in [`utils.c`](../utils.c#L20).
+
+Once the source is done being written, simply rebuild the shell and it will automatically incorporate the new built-in.
similarity index 88%
rename from src/builtin/alias.c
rename to src/builtins/alias.c
index a208a86a933d998c90d4fba8368ffaf8fdcbbc42..e798f772f174ce45a6ba9545d2785fbce7df28cb 100644 (file)
@@ -4,7 +4,6 @@
 
 #include "builtin.h"
 #include "context.h"
-#include "input.h"
 #include "parse.h"
 #include "utils.h"
 
@@ -17,7 +16,7 @@ static struct {
    size_t size;
 } aliases;
 
-char *getaliasrhs(char *token) {
+char *getrawalias(char *token) {
    size_t i;
 
    for (i = 0; i < aliases.size; ++i)
@@ -31,8 +30,9 @@ char **getalias(char *token) {
    size_t l;
    static struct context context;
 
-   if (!(rhs = getaliasrhs(token))) return NULL;
+   if (!(rhs = getrawalias(token))) return NULL;
 
+   while (*rhs == ' ') ++rhs;
    strcpy(context.buffer, rhs);
    l = strlen(rhs);
    context.buffer[l + 1] = '\0';
@@ -41,6 +41,7 @@ char **getalias(char *token) {
    context.b = context.buffer;
 
    if (!parse(&context)) return NULL;
+   if (!context.t) *context.tokens = NULL;
 
    return context.tokens;
 }
@@ -59,10 +60,6 @@ BUILTIN(alias) {
            note("Unable to add alias `%s', maximum reached (%d)", argv[1], MAXALIAS);
            return EXIT_FAILURE;
        }
-       if (!*argv[2]) {
-           note("Cannot add empty alias");
-           return EXIT_FAILURE;
-       }
        for (i = 0; i < aliases.size; ++i)
            if (strcmp(aliases.entries[i].lhs, argv[1]) == 0) break;
 
diff --git a/src/builtins/alias.h b/src/builtins/alias.h
new file mode 100644 (file)
index 0000000..fc6edcb
--- /dev/null
@@ -0,0 +1,2 @@
+char *getrawalias(char *token);
+char **getalias(char *token);
similarity index 97%
rename from src/builtin/bg.c
rename to src/builtins/bg.c
index b8503a3a7df4861ab841471d05095c38d08c7141..6c50e1cbb26d1c7985e8aba67ef94083095600a0 100644 (file)
@@ -1,7 +1,6 @@
 #include <limits.h>
 #include <signal.h>
 #include <stdlib.h>
-#include <string.h>
 #include <sys/errno.h>
 #include <sys/wait.h>
 #include <termios.h>
@@ -19,7 +18,7 @@ struct bglink {
 };
 
 static struct {
-   struct bglink entries[MAXBG + 1], *active, *free;
+   struct bglink entries[MAXBG], *active, *free;
 } bgjobs;
 
 void initbg(void) {
@@ -49,6 +48,7 @@ int pushbg(struct bgjob job) {
 
 int peekbg(struct bgjob *job) {
    if (bgjobs.active && job) *job = bgjobs.active->job;
+
    return bgjobs.active != NULL;
 }
 
@@ -88,12 +88,11 @@ void waitbg(int sig) {
    e = errno;
    p = bgjobs.active;
    while (p) {
-       while ((id = waitpid(-p->job.id, &s, WNOHANG | WUNTRACED)) > 0) {
+       while ((id = waitpid(-p->job.id, &s, WNOHANG | WUNTRACED)) > 0)
            if (WIFSTOPPED(s)) {
                p->job.suspended = 1;
                break;
            }
-       }
        if (id == -1) {
            id = p->job.id;
            p = p->next;
similarity index 100%
rename from src/builtin/bg.h
rename to src/builtins/bg.h
diff --git a/src/builtins/build.c b/src/builtins/build.c
new file mode 100644 (file)
index 0000000..24eae10
--- /dev/null
@@ -0,0 +1,65 @@
+#include <err.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <string.h>
+#include <sys/errno.h>
+
+#include "../../external/cbs/cbs.c"
+
+#define MAXBUILTINS 50
+
+int main(void) {
+   int listfd, l;
+   DIR *dir;
+   char *src[MAXBUILTINS + 2 + 1], **p;
+   struct dirent *entry;
+
+   build("./");
+
+   if ((listfd = open("list.c", O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1)
+       err(EXIT_FAILURE, "Unable to open/create `list.c'");
+   if (!(dir = opendir("./")))
+       err(EXIT_FAILURE, "Unable to open current directory");
+
+   dprintf(listfd, "#include <stddef.h>\n\n#include \"builtin.h\"\n"
+           "#include \"list.h\"\n\n");
+
+   p = src;
+   errno = 0;
+   while ((entry = readdir(dir))) {
+       if (strcmp(entry->d_name, "build.c") == 0
+           || !(*p = strrchr(entry->d_name, '.')) || strcmp(*p, ".c") != 0)
+           continue;
+       if (!(*p = strdup(entry->d_name)))
+           err(EXIT_FAILURE, "Unable to duplicate directory entry");
+       (*p)[strlen(*p) - 2] = '\0';
+       if (p - src == 2 + MAXBUILTINS + 1)
+           errx(EXIT_FAILURE, "Unable to add %s built-in, maximum reached (%d)",
+                *p, MAXBUILTINS);
+       if (strcmp(*p, "builtin") != 0 && strcmp(*p, "list") != 0)
+           dprintf(listfd, "extern BUILTIN(%s);\n", *p);
+       ++p;
+   }
+   if (errno) err(EXIT_FAILURE, "Unable to read from current directory");
+
+   *p = "struct builtin builtins[] = {";
+   l = (int)strlen(*p);
+   dprintf(listfd, "\n%s", *p);
+   *p = NULL;
+   for (p = src; *p; ++p)
+       if (strcmp(*p, "builtin") != 0 && strcmp(*p, "list") != 0)
+           dprintf(listfd, "{\"%s\", %s},\n%*s", *p, *p, l, "");
+   dprintf(listfd, "{NULL}};\n");
+
+   if (closedir(dir) == -1)
+       err(EXIT_FAILURE, "Unable to close current directory");
+   if (close(listfd) == -1) err(EXIT_FAILURE, "Unable to close `list.c'");
+
+   cflags = LIST("-I../");
+   for (p = src; *p; ++p) compile(*p);
+   load('s', "../builtins", src);
+
+   for (p = src; *p; ++p) free(*p);
+
+   return EXIT_SUCCESS;
+}
similarity index 63%
rename from src/builtin/builtin.c
rename to src/builtins/builtin.c
index 52ea765319b6e28a75b63193a7c7cbd29b35a496..ccb7832eddbf7416a084d278c84400bd8e2e0311 100644 (file)
@@ -7,13 +7,13 @@
 #include "utils.h"
 
 int isbuiltin(char **args) {
-   struct builtin *builtinp;
+   struct builtin *builtin;
    size_t n;
 
-   for (builtinp = builtins; builtinp->func; ++builtinp)
-       if (strcmp(args[0], builtinp->name) == 0) {
+   for (builtin = builtins; builtin->func; ++builtin)
+       if (strcmp(args[0], builtin->name) == 0) {
            for (n = 1; args[n]; ++n);
-           status = builtinp->func(n, args);
+           status = builtin->func(n, args);
            return 1;
        }
 
@@ -21,7 +21,7 @@ int isbuiltin(char **args) {
 }
 
 int usage(char *program, char *options) {
-   fprintf(stderr, "Usage: %s", program);
+   fprintf(stderr, "usage: %s", program);
    if (options) fprintf(stderr, " %s", options);
    fputc('\n', stderr);
 
similarity index 100%
rename from src/builtin/builtin.h
rename to src/builtins/builtin.h
similarity index 97%
rename from src/builtin/cd.c
rename to src/builtins/cd.c
index 5c04eac25e8358ba0090b4a430269dba589ae4e5..023c9db101cf2f9ff42f16862fc4f37771b274cb 100644 (file)
@@ -1,5 +1,4 @@
 #include <limits.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
similarity index 98%
rename from src/builtin/fg.c
rename to src/builtins/fg.c
index 15fb381037a3ab8c8fa0f538b91a9cd31e5bb551..a868bf48beaa23792b7905b2e17eac2cdd32191a 100644 (file)
@@ -9,8 +9,6 @@
 
 #include "bg.h"
 #include "builtin.h"
-#include "context.h"
-#include "input.h"
 #include "utils.h"
 
 static struct {
similarity index 100%
rename from src/builtin/fg.h
rename to src/builtins/fg.h
similarity index 100%
rename from src/builtin/list.h
rename to src/builtins/list.h
diff --git a/src/builtins/pwd.c b/src/builtins/pwd.c
new file mode 100644 (file)
index 0000000..d16c3f7
--- /dev/null
@@ -0,0 +1,35 @@
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "builtin.h"
+#include "utils.h"
+
+BUILTIN(pwd) {
+   char *cwd, buffer[PATH_MAX];
+   size_t l;
+
+   if (argc != 1) return usage(argv[0], NULL);
+
+   if (!(cwd = getenv("PWD"))) {
+       if (!(cwd = getcwd(buffer, PATH_MAX))) {
+           note("Unable to get current working directory");
+           return EXIT_FAILURE;
+       }
+       l = strlen(cwd);
+       if (cwd[l - 1] != '/') {
+           cwd[l] = '/';
+           cwd[l + 1] = '\0';
+       }
+       if (setenv("PWD", cwd, 1) == -1) {
+           note("Unable to set $PWD$");
+           return EXIT_FAILURE;
+       }
+   }
+
+   puts(cwd);
+
+   return EXIT_SUCCESS;
+}
similarity index 100%
rename from src/builtin/set.c
rename to src/builtins/set.c
similarity index 95%
rename from src/builtin/source.c
rename to src/builtins/source.c
index 51001b01362ab46d9ee79cb4faf6fb98ddef6856..676c41424630819c9577c3750651a9613a9ccf51 100644 (file)
@@ -1,13 +1,11 @@
 #include <fcntl.h>
 #include <limits.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 
 #include "builtin.h"
 #include "context.h"
 #include "input.h"
-#include "parse.h"
 #include "run.h"
 #include "utils.h"
 
similarity index 100%
rename from src/builtin/source.h
rename to src/builtins/source.h
similarity index 100%
rename from src/builtin/unset.c
rename to src/builtins/unset.c
similarity index 86%
rename from src/builtin/which.c
rename to src/builtins/which.c
index 2cde2281a71f30c8e9c9a4e117fd343e2b7740fb..493c75f111c5995917b2efc6f2c15fb6c9af41f7 100644 (file)
 #include "utils.h"
 
 enum {
+   ALIAS,
    BUILTIN,
    PATH,
-   ALIAS,
 };
 
+static int type;
+
 static int exists(char *path) {
    struct stat pstat;
    mode_t mask;
@@ -24,26 +26,27 @@ static int exists(char *path) {
        mask = S_IFREG | S_IXUSR;
        if ((pstat.st_mode & mask) == mask) return 1;
    } else if (errno != ENOENT) note("Unable to check if `%s' exists", path);
+   else errno = 0;
 
    return 0;
 }
 
-static char *getpathtype(char *file, int *type) {
+char *getpath(char *file) {
    char *slash, *entry, *end, dir[PATH_MAX];
    struct builtin *builtin;
    size_t l;
    static char path[PATH_MAX];
 
-   *type = PATH;
+   type = PATH;
    if (!(slash = strchr(file, '/'))) {
-       if ((entry = getaliasrhs(file))) {
-           *type = ALIAS;
+       if ((entry = getrawalias(file))) {
+           type = ALIAS;
            return entry;
        }
 
        for (builtin = builtins; builtin->func; ++builtin)
            if (strcmp(file, builtin->name) == 0) {
-               *type = BUILTIN;
+               type = BUILTIN;
                return file;
            }
 
@@ -70,19 +73,12 @@ static char *getpathtype(char *file, int *type) {
    return NULL;
 }
 
-char *getpath(char *file) {
-   int type;
-
-   return getpathtype(file, &type);
-}
-
 BUILTIN(which) {
-   int type;
    char *result;
 
    if (argc != 2) return usage(argv[0], "name");
 
-   if (!(result = getpathtype(argv[1], &type))) {
+   if (!(result = getpath(argv[1]))) {
        printf("%s not found\n", argv[1]);
        return EXIT_SUCCESS;
    }
similarity index 100%
rename from src/builtin/which.h
rename to src/builtins/which.h
index 35f9b61ea68678343ad1b7b721dfdc73f0b00c7d..a3f76555de6493dde849553bc105a0b29de9460c 100644 (file)
@@ -1,4 +1,4 @@
-#include <stdlib.h>
+#include <stddef.h>
 
 #include "context.h"
 #include "input.h"
index b7a1b36d4bef2fba89cc413bf4a0979b6ebabe30..899eaf9a0959c01d04cf3dac9700750ea40bf495 100644 (file)
@@ -6,13 +6,13 @@
 #include <sys/errno.h>
 
 #include "context.h"
-#include "input.h"
+#include "options.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))
+#define INC(x) (history.x = (history.x + 1) % (MAXHIST + 1))
+#define DEC(x) (history.x = (history.x + MAXHIST) % (MAXHIST + 1))
 
 static struct {
    char path[PATH_MAX], entries[MAXHIST + 1][MAXCHARS + 1];
@@ -22,6 +22,8 @@ static struct {
 void inithistory(void) {
    FILE *file;
 
+   if (!interactive) return;
+
    if (!catpath(home, ".thushistory", history.path)) exit(EXIT_FAILURE);
    if (!(file = fopen(history.path, "r"))) {
        if (errno == ENOENT) return;
@@ -58,6 +60,8 @@ void deinithistory(void) {
    int fd;
    FILE *file;
 
+   if (!interactive) return;
+
    if ((fd = open(history.path, O_WRONLY | O_CREAT | O_TRUNC, 0600)) == -1) {
        note("Unable to open history file for writing");
        return;
index 9e6622f002a06c51ab2c2c815c247fade6124405..b49a390a94f14eb611a3b2f5c0fb033911b0295b 100644 (file)
@@ -1,5 +1,4 @@
 #include <fcntl.h>
-#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -9,7 +8,6 @@
 
 #include "context.h"
 #include "history.h"
-#include "input.h"
 #include "utils.h"
 
 enum {
@@ -130,8 +128,7 @@ int userinput(struct context *c) {
            /* This is a very minimal way to handle arrow keys. All modifiers except for
             * the ALT key are processed but ignored.
             *
-            * Reference:
-            * https://en.wikipedia.org/wiki/ANSI_escape_code#Terminal_input_sequences */
+            * See "Terminal Input Sequences" reference in `README.md'. */
        case ESCAPE:
            if ((current = getchar()) == '[') {
                while ((current = getchar()) >= '0' && current <= '9');
diff --git a/src/libbuiltins.a b/src/libbuiltins.a
new file mode 100644 (file)
index 0000000..7e53159
Binary files /dev/null and b/src/libbuiltins.a differ
index 58df464d4c87383e4fa07f1e2eda14f678610845..611d91685483dc873a5e1af00e8abad8c84e571e 100644 (file)
@@ -1,5 +1,5 @@
-#include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
 #include "builtin.h"
 int login, interactive;
 
 void options(struct context *context) {
-   int opt, l;
-   char *message = "[file | -c string] [arg ...] [-hl]\n"
-                   "    <file> [arg ...]      Run script with args\n"
-                   "    -c <string> [arg ...] Run string with args\n"
-                   "    -h                    Show this help message\n"
-                   "    -l                    Run as a login shell\n";
+   int opt;
+   char *p, *message = "[file | -c string] [arg ...] [-hl]\n"
+                       "    <file> [arg ...]      Run script\n"
+                       "    -c <string> [arg ...] Run string\n"
+                       "    -h                    Show this help message\n"
+                       "    -l                    Run as a login shell";
 
-
-   login = **arglist == '-';
+   opt = 0;
+   if (*arglist[0] == '-') {
+       ++arglist[0];
+       login = 1;
+   }
+   if ((p = strrchr(arglist[0], '/'))) arglist[0] = p + 1;
    interactive = 1;
    context->input = userinput;
 
-   while ((opt = getopt(argcount, arglist, ":c:hl")) != -1) {
+   while (opt != 'c' && (opt = getopt(argcount, arglist, ":c:hl")) != -1)
        switch (opt) {
        case 'c':
            interactive = 0;
@@ -44,8 +48,6 @@ void options(struct context *context) {
            note("Unknown command line option `-%c'\n", optopt);
            exit(usage(arglist[0], message));
        }
-       if (opt == 'c') break;
-   }
    if (!context->string && arglist[optind]) {
        interactive = 0;
        context->script = arglist[optind];
index 65e13086c58a400292dbc08c1b1e045cd0e57469..b81a33e9c3411c8a13206e70bd46c326d06a21c1 100644 (file)
@@ -7,7 +7,6 @@
 
 #include "alias.h"
 #include "context.h"
-#include "options.h"
 #include "utils.h"
 
 int parse(struct context *c) {
index a3675117bb832bcd0718ee7bf305c7c12478f89d..105c0f81f6cf0a98deb028c0ea4f441541b7996f 100644 (file)
--- a/src/run.c
+++ b/src/run.c
@@ -1,17 +1,14 @@
 #include <fcntl.h>
-#include <limits.h>
 #include <signal.h>
 #include <stdlib.h>
-#include <string.h>
 #include <sys/errno.h>
 #include <sys/wait.h>
 #include <termios.h>
 #include <unistd.h>
-#include <stdio.h> // XXX
 
+#include "bg.h"
 #include "builtin.h"
 #include "context.h"
-#include "bg.h"
 #include "fg.h"
 #include "parse.h"
 #include "utils.h"
@@ -61,8 +58,6 @@ static void redirectfiles(struct redirect *r) {
 }
 
 static void exec(char *path, struct context *c) {
-   char cwd[PATH_MAX];
-
    redirectfiles(c->redirects);
 
    if (isbuiltin(c->tokens)) exit(status);
@@ -82,8 +77,7 @@ int run(struct context *c) {
    islist = c->prev.term > BG || c->current.term > BG;
    if (c->t) {
        if (c->current.term == BG && fullbg()) {
-           note("Unable to place job in background, too many background jobs",
-                c->current.name);
+           note("Unable to place job in background, too many background jobs");
            return quit(c);
        }
        if (!(path = getpath(c->current.name))) {
index 0e0c25eb2f647dade9161246542199003f4a99d3..ddd46613393bc896b612456005392462541aa31d 100644 (file)
@@ -1,4 +1,3 @@
-#include <err.h>
 #include <limits.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -9,26 +8,43 @@
 #include <unistd.h>
 
 #include "bg.h"
-#include "context.h"
 #include "fg.h"
 #include "history.h"
-#include "options.h"
 
 int argcount, status;
 char **arglist, *home;
 
 void note(char *fmt, ...) {
    va_list args;
+
+   fprintf(stderr, "%s: ", arglist[0]);
+
    va_start(args, fmt);
-   (errno ? vwarn : vwarnx)(fmt, args);
+   vfprintf(stderr, fmt, args);
    va_end(args);
-   errno = 0;
+
+   if (errno) {
+       fprintf(stderr, ": %s", strerror(errno));
+       errno = 0;
+   }
+
+   putchar('\n');
 }
 
 void fatal(char *fmt, ...) {
    va_list args;
+
+   fprintf(stderr, "%s: ", arglist[0]);
+
    va_start(args, fmt);
-   (errno ? verr : verrx)(EXIT_FAILURE, fmt, args);
+   vfprintf(stderr, fmt, args);
+   va_end(args);
+
+   if (errno) fprintf(stderr, ": %s", strerror(errno));
+
+   putchar('\n');
+
+   exit(EXIT_FAILURE);
 }
 
 void init(void) {
@@ -51,6 +67,10 @@ void init(void) {
    if (setenv("PWD", buffer, 1) == -1)
        fatal("Unable to append trailing slash to $PWD$");
 
+   if (setenv("PATH", "/usr/local/bin/:/usr/local/sbin/"
+                      ":/usr/bin/:/usr/sbin/:/bin/:/sbin/", 1) == -1)
+       fatal("Unable to initialize $PATH$");
+
    if (!(shlvlstr = getenv("SHLVL"))) shlvlstr = "0";
    if ((shlvl = strtol(shlvlstr, NULL, 10)) < 0) shlvl = 0;
    sprintf(buffer, "%ld", shlvl + 1);
@@ -59,7 +79,7 @@ void init(void) {
 
    initfg();
    initbg();
-   if (interactive) inithistory();
+   inithistory();
 }
 
 char *catpath(char *dir, char *filename, char *buffer) {
@@ -81,7 +101,7 @@ char *catpath(char *dir, char *filename, char *buffer) {
 }
 
 void deinit(void) {
-   if (interactive) deinithistory();
+   deinithistory();
    deinitbg();
    deinitfg();
 }
index 85c7394de6411a908e40bb8dad97cdd0a6497bad..7e653b2211388a4e0d3a214278f7884f4dc96a99 100644 (file)
@@ -8,7 +8,7 @@ int main(int argc, char **argv) {
    int slash;
    pid_t cpid;
 
-   if (argc > 2) errx(EXIT_FAILURE, "%s [prefix]", argv[0]);
+   if (argc > 2) errx(EXIT_FAILURE, "usage: %s [prefix]", argv[0]);
 
    path = stpcpy(define, "-DPATH=\"");
    if (argc == 2) {
index da5876bf4f7745bd1cb04193b22ac8c579494af6..15ba8e4f0f73d6820057258a0b3ce9e1d557db77 100644 (file)
@@ -2,9 +2,11 @@
 
 #include "cbs.c"
 
-int main(void) {
+int main(int argc, char **argv) {
    pid_t cpid;
 
+   if (argc != 1) err(EXIT_FAILURE, "usage: %s\n", argv[0]);
+
    if ((cpid = fork()) == -1) err(EXIT_FAILURE, "Unable to fork");
    else if (cpid == 0)
        run("/bin/rm", LIST("rm", PATH, "uninstall"), "remove", PATH);