-Subproject commit 4711a83fafa0282fadeaba701a25539b3e73d073
+Subproject commit 5ab49da8d4ab0b8e6cb23c3cb1f927e4402db4fc
#include "../external/cbs/cbs.c"
#include "../external/cbsfile.c"
+#define BUILTINS LIST("-Ibuiltin/")
+
int main(void) {
build("./");
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},
--- /dev/null
+#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;
+}
--- /dev/null
+void applyaliases(struct shell *shell);
}
} 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;
#include "../../external/cbs/cbs.c"
#include "../../external/cbsfile.c"
-#include "../config.h"
+
+#define MAXBUILTINS 50
int main(void) {
int listfd, l;
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;
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';
#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;
}
#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;
}
if (sigaction(SIGCHLD, &sigchld, NULL) == -1) {
- note("Unable to install SIGCHLD handler");
+ note("Unable to reinstall SIGCHLD handler");
return EXIT_FAILURE;
}
--- /dev/null
+int setfg(struct job job);
+int waitfg(struct job job);
--- /dev/null
+#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});
+}
--- /dev/null
+void config(char *name);
-#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;
}
+++ /dev/null
-#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
-#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");
}
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;
}
#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,
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) {
}
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';
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())) {
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())) {
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++);
break;
case BACKSPACE:
case DEL:
- if (cursor == buffer) continue;
+ if (cursor == start) continue;
memmove(cursor - 1, cursor, end - cursor);
--cursor;
*--end = '\0';
}
puts("\r");
}
- push(&history, buffer);
+ push(&history, start);
*end++ = ';';
*end = '\0';
- return buffer;
+ return shell;
}
-#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);
-#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;
}
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);
- }
- }
-}
-#define CURRENT ((struct job *)jobs.c)
+#define JOB ((struct job *)jobs.c)
enum jobtype {
BACKGROUND,
};
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);
#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();
#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"
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);
}
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;
-typedef INPUT((*Input));
-
extern int login, interactive, argc;
-extern Input input;
extern char **argv;
+extern struct shell shell;
void options(void);
#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;
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;
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;
}
}
if (!b) {
note("Quote left open-ended");
- return c;
+ return shell;
}
memmove(p, p + 1, end-- - p);
--b;
while (*b && *b != '$') ++b;
if (!*b) {
note("Environment variable lacks a terminating `$'");
- return c;
+ return shell;
}
*b++ = '\0';
for (end = b; *end; ++end);
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);
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;
if (value) {
if (setenv(name, value, 1) == -1) {
note("Unable to set environment variable");
- return c;
+ return shell;
}
value = name = NULL;
}
case PIPE:
case OR:
note("Expected another command");
- return c;
+ return shell;
default:
break;
}
- return cmds;
+ shell->cmds->next = shell->cmds + 1;
+ return shell;
}
-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);
#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"
}
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;
extern int status;
-int run(struct cmd *cmd);
+int run(struct shell *shell);
--- /dev/null
+#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;
+};
#include <err.h>
+#include <limits.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#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, ...) {
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);
}
+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);