]> Trent Huber's Code - thus.git/commitdiff
Builtins reorganized and automatically detected
authorTrent Huber <trentmhuber@gmail.com>
Sat, 26 Jul 2025 07:22:46 +0000 (03:22 -0400)
committerTrent Huber <trentmhuber@gmail.com>
Sat, 26 Jul 2025 07:22:46 +0000 (03:22 -0400)
19 files changed:
.gitignore
build.c
external/cbs
external/cbsfile.c [new file with mode: 0644]
src/.gitignore [new file with mode: 0644]
src/build.c [new file with mode: 0644]
src/builtin/.gitignore [new file with mode: 0644]
src/builtin/bg.c [new file with mode: 0644]
src/builtin/build.c [new file with mode: 0644]
src/builtin/builtin.c [new file with mode: 0644]
src/builtin/builtin.h [new file with mode: 0644]
src/builtin/cd.c [new file with mode: 0644]
src/builtin/fg.c [new file with mode: 0644]
src/builtin/list.h [new file with mode: 0644]
src/builtin/which.c [new file with mode: 0644]
src/builtins.c [deleted file]
src/builtins.h [deleted file]
src/config.h
src/run.c

index 7353e7e145139bbcfb99384df098facea1844fb9..c685519a375be24df8ed1031599d1673bdc530ee 100644 (file)
@@ -1,2 +1,2 @@
-build
+*build
 *.o
diff --git a/build.c b/build.c
index d84fbf4c7f6da803a5f3b9910515343dfd1de39c..41025fd540f8651b3ae6df599e57550a8b91c03d 100644 (file)
--- a/build.c
+++ b/build.c
@@ -1,30 +1,9 @@
 #include "external/cbs/cbs.c"
 
-#define SRCDIR "src/"
-#define SRC \
-   SRCDIR "builtins", \
-   SRCDIR "input", \
-   SRCDIR "history", \
-   SRCDIR "job", \
-   SRCDIR "parse", \
-   SRCDIR "main", \
-   SRCDIR "options", \
-   SRCDIR "run", \
-   SRCDIR "stack", \
-   SRCDIR "utils"
-#define BINDIR "bin/"
-#define ASH BINDIR "ash"
-
 int main(void) {
-   char **src;
-
-   build(NULL);
-
-   src = (char *[]){SRC, NULL};
-   // cflags = (char *[]){"-ferror-limit=1", NULL};
-   while (*src) compile(*src++, NULL);
+   build("./");
 
-   load('x', ASH, SRC, NULL);
+   build("src/");
 
    return EXIT_SUCCESS;
 }
index a2cb47c262bee92a2f7cab689e42ae8452c9e952..47569fbe806a5138763e7ef3447dca254357dff8 160000 (submodule)
@@ -1 +1 @@
-Subproject commit a2cb47c262bee92a2f7cab689e42ae8452c9e952
+Subproject commit 47569fbe806a5138763e7ef3447dca254357dff8
diff --git a/external/cbsfile.c b/external/cbsfile.c
new file mode 100644 (file)
index 0000000..e4657e8
--- /dev/null
@@ -0,0 +1,30 @@
+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/.gitignore b/src/.gitignore
new file mode 100644 (file)
index 0000000..d08de4e
--- /dev/null
@@ -0,0 +1 @@
+libbuiltin.a
diff --git a/src/build.c b/src/build.c
new file mode 100644 (file)
index 0000000..1f74e83
--- /dev/null
@@ -0,0 +1,26 @@
+#include "../external/cbs/cbs.c"
+#include "../external/cbsfile.c"
+
+int main(void) {
+   build("./");
+
+   build("builtin/");
+
+   buildfiles((struct cbsfile []){{"../bin/ash", NONE, 'x'},
+
+                                  {"input", NONE},
+                                  {"history", NONE},
+                                  {"job", NONE},
+                                  {"parse", NONE},
+                                  {"main", NONE},
+                                  {"options", NONE},
+                                  {"run", LIST("-Ibuiltin/")},
+                                  {"stack", NONE},
+                                  {"utils", NONE},
+
+                                  {"builtin.a"},
+
+                                  {NULL}});
+
+   return EXIT_SUCCESS;
+}
diff --git a/src/builtin/.gitignore b/src/builtin/.gitignore
new file mode 100644 (file)
index 0000000..3309b20
--- /dev/null
@@ -0,0 +1 @@
+list.c
diff --git a/src/builtin/bg.c b/src/builtin/bg.c
new file mode 100644 (file)
index 0000000..76c58a8
--- /dev/null
@@ -0,0 +1,62 @@
+#include <limits.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/errno.h>
+#include <termios.h>
+
+#include "builtin.h"
+#include "job.h"
+#include "stack.h"
+#include "utils.h"
+
+BUILTINSIG(bg) {
+   long jobid;
+   struct job *job;
+
+   if (sigaction(SIGCHLD, &sigdfl, NULL) == -1) {
+       note("Unable to acquire lock on the job stack");
+       return 1;
+   }
+
+   if (argv[1]) {
+       errno = 0;
+       if ((jobid = strtol(argv[1], NULL, 10)) == LONG_MAX && errno
+           || jobid <= 0) {
+           note("Invalid job id");
+           return 1;
+       }
+       if (!(job = findjob((pid_t)jobid))) {
+           note("Unable to find job %d", (pid_t)jobid);
+           return 1;
+       }
+       if (job->type == BACKGROUND) {
+           note("Job %d already in background", (pid_t)jobid);
+           return 1;
+       }
+   } else {
+       for (jobs.c = MINUSONE(jobs, t); jobs.c != MINUSONE(jobs, b); DEC(jobs, c))
+           if (CURRENT->type == SUSPENDED) break;
+       if (jobs.c == MINUSONE(jobs, b)) {
+           note("No suspended jobs to run in background");
+           return 1;
+       }
+   }
+   job = deletejob();
+
+   if (!(push(&jobs, job))) {
+       note("Unable to add job to background; too many jobs");
+       return 1;
+   }
+   if (killpg(job->id, SIGCONT) == -1) {
+       note("Unable to wake up suspended process group %d", job->id);
+       return 1;
+   }
+   job->type = BACKGROUND;
+
+   if (sigaction(SIGCHLD, &sigchld, NULL) == -1) {
+       note("Unable to install SIGCHLD handler");
+       return 1;
+   }
+
+   return 0;
+}
diff --git a/src/builtin/build.c b/src/builtin/build.c
new file mode 100644 (file)
index 0000000..30de555
--- /dev/null
@@ -0,0 +1,67 @@
+#include <err.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <string.h>
+#include <sys/errno.h>
+
+#include "../../external/cbs/cbs.c"
+#include "../../external/cbsfile.c"
+#include "../config.h"
+
+int main(void) {
+   int listfd, l;
+   DIR *dir;
+   size_t i, offset;
+   struct cbsfile files[1 + 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 <stdlib.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 == 1 + MAXBUILTINS + 1)
+           errx(EXIT_FAILURE, "Maximum allowed builtins (%d) exceeded", 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 BUILTINSIG(%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/builtin.c b/src/builtin/builtin.c
new file mode 100644 (file)
index 0000000..03731af
--- /dev/null
@@ -0,0 +1,17 @@
+#include <string.h>
+
+#include "builtin.h"
+#include "list.h"
+
+int isbuiltin(char **args, int *statusp) {
+   struct builtin *builtinp;
+   size_t n;
+
+   for (builtinp = builtins; builtinp->func; ++builtinp)
+       if (strcmp(*args, builtinp->name) == 0) {
+           for (n = 0; args[n]; ++n);
+           *statusp = builtinp->func(n, args);
+           return 1;
+       }
+   return 0;
+}
diff --git a/src/builtin/builtin.h b/src/builtin/builtin.h
new file mode 100644 (file)
index 0000000..cc96b3a
--- /dev/null
@@ -0,0 +1,3 @@
+#define BUILTINSIG(name) int name(int argc, char **argv)
+
+int isbuiltin(char **args, int *statusp);
diff --git a/src/builtin/cd.c b/src/builtin/cd.c
new file mode 100644 (file)
index 0000000..d3ef299
--- /dev/null
@@ -0,0 +1,24 @@
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "builtin.h"
+#include "utils.h"
+
+BUILTINSIG(cd) {
+   char *fullpath;
+
+   if (argv[1]) {
+       if (!(fullpath = realpath(argv[1], NULL))) {
+           note("Could not resolve path name");
+           return 1;
+       }
+   } else fullpath = home;
+   if (chdir(fullpath) == -1) {
+       note("Unable to change directory to `%s'", argv[1]);
+       return 1;
+   }
+   if (setenv("PWD", fullpath, 1) == -1)
+       note("Unable to change $PWD$ to `%s'", fullpath);
+   if (fullpath != home) free(fullpath);
+   return 0;
+}
diff --git a/src/builtin/fg.c b/src/builtin/fg.c
new file mode 100644 (file)
index 0000000..f53a261
--- /dev/null
@@ -0,0 +1,47 @@
+#include <limits.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/errno.h>
+#include <termios.h>
+
+#include "builtin.h"
+#include "job.h"
+#include "stack.h"
+#include "utils.h"
+
+BUILTINSIG(fg) {
+   long jobid;
+   struct job *job;
+
+   if (sigaction(SIGCHLD, &sigdfl, NULL) == -1) {
+       note("Unable to acquire lock on the job stack");
+       return 1;
+   }
+
+   if (argv[1]) {
+       errno = 0;
+       if ((jobid = strtol(argv[1], NULL, 10)) == LONG_MAX && errno
+           || jobid <= 0) {
+           note("Invalid process group id");
+           return 1;
+       }
+       if (!(job = findjob((pid_t)jobid))) {
+           note("Unable to find process group %d", (pid_t)jobid);
+           return 1;
+       }
+       job = deletejob();
+   } else if (!(job = pull(&jobs))) {
+       note("No processes to bring into the foreground");
+       return 1;
+   }
+
+   if (sigaction(SIGCHLD, &sigchld, NULL) == -1) {
+       note("Unable to install SIGCHLD handler");
+       return 1;
+   }
+
+   if (!setfg(*job)) return 1;
+   waitfg(*job);
+
+   return 0;
+}
diff --git a/src/builtin/list.h b/src/builtin/list.h
new file mode 100644 (file)
index 0000000..7c33a2f
--- /dev/null
@@ -0,0 +1,6 @@
+struct builtin {
+   char *name;
+   BUILTINSIG((*func));
+};
+
+extern struct builtin builtins[];
diff --git a/src/builtin/which.c b/src/builtin/which.c
new file mode 100644 (file)
index 0000000..c956da8
--- /dev/null
@@ -0,0 +1,53 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+#include <string.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) {
+   struct builtin *builtin;
+   char *path, *dir, *p;
+   
+   if (!argv[1]) return 1;
+   for (builtin = builtins; builtin->func; ++builtin)
+       if (strcmp(argv[1], builtin->name) == 0) {
+           puts("Built-in command\r");
+           return 0;
+       }
+
+   if (!(path = getenv("PATH"))) {
+       note("Unable to examine $PATH$");
+       return 1;
+   }
+   if (!(path = p = strdup(path))) {
+       note("Unable to duplicate $PATH$");
+       return 1;
+   }
+   do {
+       if (!(dir = p)) break;
+       if ((p = strchr(dir, ':'))) *p++ = '\0';
+   } while (!inpath(dir, argv[1]));
+   free(path);
+   if (dir) return 0;
+
+   printf("%s not found\r\n", argv[1]);
+   return 1;
+}
diff --git a/src/builtins.c b/src/builtins.c
deleted file mode 100644 (file)
index 9112d67..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-#include <limits.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/errno.h>
-#include <termios.h>
-#include <unistd.h>
-#include <sys/stat.h>
-
-#include "job.h"
-#include "stack.h"
-#include "term.h"
-#include "utils.h"
-
-#define BUILTINSIG(name) int name(int argc, char **argv)
-
-struct builtin {
-   char *name;
-   BUILTINSIG((*func));
-};
-
-BUILTINSIG(cd) {
-   char *fullpath;
-
-   if (argv[1]) {
-       if (!(fullpath = realpath(argv[1], NULL))) {
-           note("Could not resolve path name");
-           return 1;
-       }
-   } else fullpath = home;
-   if (chdir(fullpath) == -1) {
-       note("Unable to change directory to `%s'", argv[1]);
-       return 1;
-   }
-   if (setenv("PWD", fullpath, 1) == -1)
-       note("Unable to change $PWD$ to `%s'", fullpath);
-   if (fullpath != home) free(fullpath);
-   return 0;
-}
-
-BUILTINSIG(fg) {
-   long jobid;
-   struct job *job;
-
-   if (sigaction(SIGCHLD, &sigdfl, NULL) == -1) {
-       note("Unable to acquire lock on the job stack");
-       return 1;
-   }
-
-   if (argv[1]) {
-       errno = 0;
-       if ((jobid = strtol(argv[1], NULL, 10)) == LONG_MAX && errno
-           || jobid <= 0) {
-           note("Invalid process group id");
-           return 1;
-       }
-       if (!(job = findjob((pid_t)jobid))) {
-           note("Unable to find process group %d", (pid_t)jobid);
-           return 1;
-       }
-       job = deletejob();
-   } else if (!(job = pull(&jobs))) {
-       note("No processes to bring into the foreground");
-       return 1;
-   }
-
-   if (sigaction(SIGCHLD, &sigchld, NULL) == -1) {
-       note("Unable to install SIGCHLD handler");
-       return 1;
-   }
-
-   if (!setfg(*job)) return 1;
-   waitfg(*job);
-
-   return 0;
-}
-
-BUILTINSIG(bg) {
-   long jobid;
-   struct job *job;
-
-   if (sigaction(SIGCHLD, &sigdfl, NULL) == -1) {
-       note("Unable to acquire lock on the job stack");
-       return 1;
-   }
-
-   if (argv[1]) {
-       errno = 0;
-       if ((jobid = strtol(argv[1], NULL, 10)) == LONG_MAX && errno
-           || jobid <= 0) {
-           note("Invalid job id");
-           return 1;
-       }
-       if (!(job = findjob((pid_t)jobid))) {
-           note("Unable to find job %d", (pid_t)jobid);
-           return 1;
-       }
-       if (job->type == BACKGROUND) {
-           note("Job %d already in background", (pid_t)jobid);
-           return 1;
-       }
-   } else {
-       for (jobs.c = MINUSONE(jobs, t); jobs.c != MINUSONE(jobs, b); DEC(jobs, c))
-           if (CURRENT->type == SUSPENDED) break;
-       if (jobs.c == MINUSONE(jobs, b)) {
-           note("No suspended jobs to run in background");
-           return 1;
-       }
-   }
-   job = deletejob();
-
-   if (!(push(&jobs, job))) {
-       note("Unable to add job to background; too many jobs");
-       return 1;
-   }
-   if (killpg(job->id, SIGCONT) == -1) {
-       note("Unable to wake up suspended process group %d", job->id);
-       return 1;
-   }
-   job->type = BACKGROUND;
-
-   if (sigaction(SIGCHLD, &sigchld, NULL) == -1) {
-       note("Unable to install SIGCHLD handler");
-       return 1;
-   }
-
-   return 0;
-}
-
-#define BUILTIN(name) {#name, name}
-BUILTINSIG(which);
-struct builtin builtins[] = {
-   BUILTIN(cd),
-   BUILTIN(fg),
-   BUILTIN(bg),
-   BUILTIN(which),
-   BUILTIN(NULL),
-};
-
-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) {
-   struct builtin *builtin;
-   char *path, *dir, *p;
-   
-   if (!argv[1]) return 1;
-   for (builtin = builtins; builtin->func; ++builtin)
-       if (strcmp(argv[1], builtin->name) == 0) {
-           puts("Built-in command\r");
-           return 0;
-       }
-
-   if (!(path = getenv("PATH"))) {
-       note("Unable to examine $PATH$");
-       return 1;
-   }
-   if (!(path = p = strdup(path))) {
-       note("Unable to duplicate $PATH$");
-       return 1;
-   }
-   do {
-       if (!(dir = p)) break;
-       if ((p = strchr(dir, ':'))) *p++ = '\0';
-   } while (!inpath(dir, argv[1]));
-   free(path);
-   if (dir) return 0;
-
-   printf("%s not found\r\n", argv[1]);
-   return 1;
-}
-
-int isbuiltin(char **args, int *statusp) {
-   struct builtin *builtinp;
-   size_t n;
-
-   for (builtinp = builtins; builtinp->func; ++builtinp)
-       if (strcmp(*args, builtinp->name) == 0) {
-           for (n = 0; args[n]; ++n);
-           *statusp = builtinp->func(n, args);
-           return 1;
-       }
-   return 0;
-}
diff --git a/src/builtins.h b/src/builtins.h
deleted file mode 100644 (file)
index 0798e58..0000000
+++ /dev/null
@@ -1 +0,0 @@
-int isbuiltin(char **args, int *statusp);
index 97e9448a1c4ad6e23df96d4666c4a76f4a50518c..9e6818aed0bddaed46f1ae0a2ae44e6e176c77fa 100644 (file)
@@ -4,6 +4,7 @@
 #define INTERACTIVEFILE ".ashinteractive"
 #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
index 9adbe86a3faa9f52cb0cc1dce35c9aa9d4109979..160cf9b178f7d89c352c9fcee7d856f25678aff1 100644 (file)
--- a/src/run.c
+++ b/src/run.c
@@ -5,7 +5,7 @@
 #include <termios.h>
 #include <unistd.h>
 
-#include "builtins.h"
+#include "builtin.h"
 #include "config.h"
 #include "job.h"
 #include "parse.h"