From 3b3daf772ff478bf0887331f51d107b61f8db29d Mon Sep 17 00:00:00 2001 From: Trent Huber Date: Wed, 27 Aug 2025 04:40:05 -0400 Subject: [PATCH] Finish README.md, finish cleaning --- README.md | 68 +++++++++++++++-------- external/cbsext.c | 30 ----------- src/build.c | 25 ++++----- src/builtin/README.md | 5 -- src/builtin/alias.h | 2 - src/builtin/build.c | 77 --------------------------- src/builtin/pwd.c | 20 ------- src/{builtin => builtins}/.gitignore | 0 src/builtins/README.md | 22 ++++++++ src/{builtin => builtins}/alias.c | 11 ++-- src/builtins/alias.h | 2 + src/{builtin => builtins}/bg.c | 7 ++- src/{builtin => builtins}/bg.h | 0 src/builtins/build.c | 65 ++++++++++++++++++++++ src/{builtin => builtins}/builtin.c | 10 ++-- src/{builtin => builtins}/builtin.h | 0 src/{builtin => builtins}/cd.c | 1 - src/{builtin => builtins}/fg.c | 2 - src/{builtin => builtins}/fg.h | 0 src/{builtin => builtins}/list.h | 0 src/builtins/pwd.c | 35 ++++++++++++ src/{builtin => builtins}/set.c | 0 src/{builtin => builtins}/source.c | 2 - src/{builtin => builtins}/source.h | 0 src/{builtin => builtins}/unset.c | 0 src/{builtin => builtins}/which.c | 24 ++++----- src/{builtin => builtins}/which.h | 0 src/context.c | 2 +- src/history.c | 10 ++-- src/input.c | 5 +- src/libbuiltins.a | Bin 0 -> 78456 bytes src/options.c | 26 ++++----- src/parse.c | 1 - src/run.c | 10 +--- src/utils.c | 36 ++++++++++--- tools/install.c | 2 +- tools/uninstall.c | 4 +- 37 files changed, 259 insertions(+), 245 deletions(-) delete mode 100644 external/cbsext.c delete mode 100644 src/builtin/README.md delete mode 100644 src/builtin/alias.h delete mode 100644 src/builtin/build.c delete mode 100644 src/builtin/pwd.c rename src/{builtin => builtins}/.gitignore (100%) create mode 100644 src/builtins/README.md rename src/{builtin => builtins}/alias.c (88%) create mode 100644 src/builtins/alias.h rename src/{builtin => builtins}/bg.c (97%) rename src/{builtin => builtins}/bg.h (100%) create mode 100644 src/builtins/build.c rename src/{builtin => builtins}/builtin.c (63%) rename src/{builtin => builtins}/builtin.h (100%) rename src/{builtin => builtins}/cd.c (97%) rename src/{builtin => builtins}/fg.c (98%) rename src/{builtin => builtins}/fg.h (100%) rename src/{builtin => builtins}/list.h (100%) create mode 100644 src/builtins/pwd.c rename src/{builtin => builtins}/set.c (100%) rename src/{builtin => builtins}/source.c (95%) rename src/{builtin => builtins}/source.h (100%) rename src/{builtin => builtins}/unset.c (100%) rename src/{builtin => builtins}/which.c (86%) rename src/{builtin => builtins}/which.h (100%) create mode 100644 src/libbuiltins.a diff --git a/README.md b/README.md index 09408b0..c353907 100644 --- 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 (`&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 index e4657e8..0000000 --- a/external/cbsext.c +++ /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; -} diff --git a/src/build.c b/src/build.c index 07a1eac..177e59c 100644 --- a/src/build.c +++ b/src/build.c @@ -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 index 65108f7..0000000 --- a/src/builtin/README.md +++ /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 index 52a3725..0000000 --- a/src/builtin/alias.h +++ /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 index 36f41e2..0000000 --- a/src/builtin/build.c +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include -#include -#include -#include - -#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 \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 index c9e6e2d..0000000 --- a/src/builtin/pwd.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include -#include -#include - -#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/builtin/.gitignore b/src/builtins/.gitignore similarity index 100% rename from src/builtin/.gitignore rename to src/builtins/.gitignore diff --git a/src/builtins/README.md b/src/builtins/README.md new file mode 100644 index 0000000..3c1954b --- /dev/null +++ b/src/builtins/README.md @@ -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 + +#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. diff --git a/src/builtin/alias.c b/src/builtins/alias.c similarity index 88% rename from src/builtin/alias.c rename to src/builtins/alias.c index a208a86..e798f77 100644 --- a/src/builtin/alias.c +++ b/src/builtins/alias.c @@ -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 index 0000000..fc6edcb --- /dev/null +++ b/src/builtins/alias.h @@ -0,0 +1,2 @@ +char *getrawalias(char *token); +char **getalias(char *token); diff --git a/src/builtin/bg.c b/src/builtins/bg.c similarity index 97% rename from src/builtin/bg.c rename to src/builtins/bg.c index b8503a3..6c50e1c 100644 --- a/src/builtin/bg.c +++ b/src/builtins/bg.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include @@ -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; diff --git a/src/builtin/bg.h b/src/builtins/bg.h 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 index 0000000..24eae10 --- /dev/null +++ b/src/builtins/build.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include + +#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 \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; +} diff --git a/src/builtin/builtin.c b/src/builtins/builtin.c similarity index 63% rename from src/builtin/builtin.c rename to src/builtins/builtin.c index 52ea765..ccb7832 100644 --- a/src/builtin/builtin.c +++ b/src/builtins/builtin.c @@ -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); diff --git a/src/builtin/builtin.h b/src/builtins/builtin.h similarity index 100% rename from src/builtin/builtin.h rename to src/builtins/builtin.h diff --git a/src/builtin/cd.c b/src/builtins/cd.c similarity index 97% rename from src/builtin/cd.c rename to src/builtins/cd.c index 5c04eac..023c9db 100644 --- a/src/builtin/cd.c +++ b/src/builtins/cd.c @@ -1,5 +1,4 @@ #include -#include #include #include #include diff --git a/src/builtin/fg.c b/src/builtins/fg.c similarity index 98% rename from src/builtin/fg.c rename to src/builtins/fg.c index 15fb381..a868bf4 100644 --- a/src/builtin/fg.c +++ b/src/builtins/fg.c @@ -9,8 +9,6 @@ #include "bg.h" #include "builtin.h" -#include "context.h" -#include "input.h" #include "utils.h" static struct { diff --git a/src/builtin/fg.h b/src/builtins/fg.h similarity index 100% rename from src/builtin/fg.h rename to src/builtins/fg.h diff --git a/src/builtin/list.h b/src/builtins/list.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 index 0000000..d16c3f7 --- /dev/null +++ b/src/builtins/pwd.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include + +#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; +} diff --git a/src/builtin/set.c b/src/builtins/set.c similarity index 100% rename from src/builtin/set.c rename to src/builtins/set.c diff --git a/src/builtin/source.c b/src/builtins/source.c similarity index 95% rename from src/builtin/source.c rename to src/builtins/source.c index 51001b0..676c414 100644 --- a/src/builtin/source.c +++ b/src/builtins/source.c @@ -1,13 +1,11 @@ #include #include -#include #include #include #include "builtin.h" #include "context.h" #include "input.h" -#include "parse.h" #include "run.h" #include "utils.h" diff --git a/src/builtin/source.h b/src/builtins/source.h similarity index 100% rename from src/builtin/source.h rename to src/builtins/source.h diff --git a/src/builtin/unset.c b/src/builtins/unset.c similarity index 100% rename from src/builtin/unset.c rename to src/builtins/unset.c diff --git a/src/builtin/which.c b/src/builtins/which.c similarity index 86% rename from src/builtin/which.c rename to src/builtins/which.c index 2cde228..493c75f 100644 --- a/src/builtin/which.c +++ b/src/builtins/which.c @@ -11,11 +11,13 @@ #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; } diff --git a/src/builtin/which.h b/src/builtins/which.h similarity index 100% rename from src/builtin/which.h rename to src/builtins/which.h diff --git a/src/context.c b/src/context.c index 35f9b61..a3f7655 100644 --- a/src/context.c +++ b/src/context.c @@ -1,4 +1,4 @@ -#include +#include #include "context.h" #include "input.h" diff --git a/src/history.c b/src/history.c index b7a1b36..899eaf9 100644 --- a/src/history.c +++ b/src/history.c @@ -6,13 +6,13 @@ #include #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; diff --git a/src/input.c b/src/input.c index 9e6622f..b49a390 100644 --- a/src/input.c +++ b/src/input.c @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -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 index 0000000000000000000000000000000000000000..7e5315913edd0485766bc0e97f1cda3280d2ae82 GIT binary patch literal 78456 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 QySk-$)5hzr*6SAj6M}D0`Tzg` literal 0 HcmV?d00001 diff --git a/src/options.c b/src/options.c index 58df464..611d916 100644 --- a/src/options.c +++ b/src/options.c @@ -1,5 +1,5 @@ -#include #include +#include #include #include "builtin.h" @@ -10,19 +10,23 @@ int login, interactive; void options(struct context *context) { - int opt, l; - char *message = "[file | -c string] [arg ...] [-hl]\n" - " [arg ...] Run script with args\n" - " -c [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" + " [arg ...] Run script\n" + " -c [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]; diff --git a/src/parse.c b/src/parse.c index 65e1308..b81a33e 100644 --- a/src/parse.c +++ b/src/parse.c @@ -7,7 +7,6 @@ #include "alias.h" #include "context.h" -#include "options.h" #include "utils.h" int parse(struct context *c) { diff --git a/src/run.c b/src/run.c index a367511..105c0f8 100644 --- a/src/run.c +++ b/src/run.c @@ -1,17 +1,14 @@ #include -#include #include #include -#include #include #include #include #include -#include // 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))) { diff --git a/src/utils.c b/src/utils.c index 0e0c25e..ddd4661 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -9,26 +8,43 @@ #include #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(); } diff --git a/tools/install.c b/tools/install.c index 85c7394..7e653b2 100644 --- a/tools/install.c +++ b/tools/install.c @@ -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) { diff --git a/tools/uninstall.c b/tools/uninstall.c index da5876b..15ba8e4 100644 --- a/tools/uninstall.c +++ b/tools/uninstall.c @@ -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); -- 2.51.0