From: Trent Huber Date: Sat, 5 Jul 2025 07:03:22 +0000 (-0400) Subject: Bug fixes, cmd/tokens/buffer reorganization X-Git-Url: https://trenthuber.com/code?a=commitdiff_plain;h=84521bfa916f4c3aa6e3b01e81fcba1daee13019;p=thus.git Bug fixes, cmd/tokens/buffer reorganization --- diff --git a/src/builtins.c b/src/builtins.c index 8199fbf..fdd7e38 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -71,12 +71,14 @@ BUILTINSIG(bg) { warnx("Job %d already in background", (pid_t)jobid); return 1; } - } else - for (jobs.c = MINUSONE(jobs, t); CURRENT->type == BACKGROUND; DEC(jobs, c)) - if (jobs.c == jobs.b) { - warnx("No suspended jobs to run in background"); - 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)) { + warnx("No suspended jobs to run in background"); + return 1; + } + } job = deletejob(); if (!(push(&jobs, job))) { diff --git a/src/history.c b/src/history.c index fc2a351..ca39b45 100644 --- a/src/history.c +++ b/src/history.c @@ -4,11 +4,11 @@ #include #include -#include "history.h" #include "input.h" #include "stack.h" #include "utils.h" +#define HISTLEN 100 #define HISTNAME ".ashhistory" static char *histpath, histarr[HISTLEN + 1][BUFLEN + 1]; diff --git a/src/history.h b/src/history.h index c395a45..bb7130f 100644 --- a/src/history.h +++ b/src/history.h @@ -1,6 +1,3 @@ -#define HISTLEN 100 -#define BUFLEN 1000 - extern struct stack history; void readhist(void); diff --git a/src/input.c b/src/input.c index 29dc7b1..d04bad9 100644 --- a/src/input.c +++ b/src/input.c @@ -5,6 +5,7 @@ #include #include "history.h" +#include "input.h" #include "job.h" #include "stack.h" @@ -25,23 +26,23 @@ enum character { BACKSPACE = '\177', }; -static char buffer[1 + BUFLEN + 2]; +static char buffer[BUFLEN + 2]; // Terminating ';' char *input(void) { - char *start, *cursor, *end; + char *cursor, *end; int c, i; signal(SIGCHLD, waitbg); // TODO: Use sigaction for portability reset: - end = cursor = start = buffer + 1; - *history.t = *start = '\0'; + end = cursor = buffer; + *history.t = *buffer = '\0'; history.c = history.t; - while (start == end) { + while (buffer == end) { fputs(PROMPT, stdout); while ((c = getchar()) != '\n') { if (c >= ' ' && c <= '~') { - if (end - start == BUFLEN) continue; + if (end - buffer == BUFLEN) continue; memmove(cursor + 1, cursor, end - cursor); *cursor++ = c; *++end = '\0'; @@ -60,7 +61,7 @@ reset: case CLEAR: fputs("\033[H\033[J", stdout); fputs(PROMPT, stdout); - fputs(start, stdout); + fputs(buffer, stdout); continue; case ESCAPE: switch ((c = getchar())) { @@ -69,8 +70,8 @@ reset: while (cursor != end && *cursor == ' ') putchar(*cursor++); break; case BACKWARD: - while (cursor != start && *(cursor - 1) == ' ') putchar((--cursor, '\b')); - while (cursor != start && *(cursor - 1) != ' ') putchar((--cursor, '\b')); + while (cursor != buffer && *(cursor - 1) == ' ') putchar((--cursor, '\b')); + while (cursor != buffer && *(cursor - 1) != ' ') putchar((--cursor, '\b')); break; case ARROW: switch ((c = getchar())) { @@ -79,19 +80,19 @@ reset: if (history.c == (c == UP ? history.b : history.t)) continue; putchar('\r'); - for (i = end - start + strlen(PROMPT); i > 0; --i) putchar(' '); + for (i = end - buffer + strlen(PROMPT); i > 0; --i) putchar(' '); putchar('\r'); - if (strcmp(history.c, start) != 0) strcpy(history.t, start); + if (strcmp(history.c, buffer) != 0) strcpy(history.t, buffer); if (c == UP) DEC(history, c); else INC(history, c); - strcpy(start, history.c); - end = cursor = start + strlen(start); + strcpy(buffer, history.c); + end = cursor = buffer + strlen(buffer); fputs(PROMPT, stdout); - fputs(start, stdout); + fputs(buffer, stdout); break; case LEFT: - if (cursor > start) putchar((--cursor, '\b')); + if (cursor > buffer) putchar((--cursor, '\b')); break; case RIGHT: if (cursor < end) putchar(*cursor++); @@ -103,7 +104,7 @@ reset: } break; case BACKSPACE: - if (cursor == start) continue; + if (cursor == buffer) continue; memmove(cursor - 1, cursor, end - cursor); --cursor; *--end = '\0'; @@ -118,9 +119,8 @@ reset: } } fpurge(stdout); - push(&history, start); + push(&history, buffer); - *buffer = ';'; *end = ';'; *++end = '\0'; diff --git a/src/input.h b/src/input.h index dee8d7a..652daa8 100644 --- a/src/input.h +++ b/src/input.h @@ -1 +1,3 @@ +#define BUFLEN 1000 + char *input(void); diff --git a/src/job.c b/src/job.c index a5f366e..6573c4b 100644 --- a/src/job.c +++ b/src/job.c @@ -23,7 +23,7 @@ void *findjob(pid_t jobid) { void *deletejob(void) { memcpy(jobs.t, jobs.c, jobs.size); memmove(jobs.c, PLUSONE(jobs, c), jobs.t - jobs.c); - return MINUSONE(jobs, t); + return DEC(jobs, t); } void waitbg(int sig) { diff --git a/src/lex.c b/src/lex.c index 0def809..108084f 100644 --- a/src/lex.c +++ b/src/lex.c @@ -1,128 +1,86 @@ +#include #include +#include #include #include -#include -#include -#include // DEBUG +#include // XXX -#include "history.h" +#include "input.h" #include "lex.h" -static char *tokens[1 + BUFLEN + 1]; -static struct cmd cmds[1 + (BUFLEN + 1) / 2 + 1] = {{.args = tokens}}; - -void printfreds(struct cmd *c) { - struct fred *f; +#define MAXCMDS 100 - for (f = c->freds; f->mode != END; ++f) { - printf("%d ", f->newfd); - switch (f->mode) { - case READ: - fputs("<", stdout); - break; - case WRITE: - fputs(">", stdout); - break; - case READWRITE: - fputs("<>", stdout); - break; - case APPEND: - fputs(">>", stdout); - break; - default:; - } - switch (f->type) { - case FD: - printf(" #%d\n", f->old.fd); - break; - case NAME: - printf(" %s\n", f->old.name); - break; - default:; - } - } -} +static char *tokens[BUFLEN + 1]; +static struct cmd cmds[MAXCMDS + 1]; +struct cmd empty = {0}; struct cmd *lex(char *b) { char **t, *end; struct cmd *c; - struct fred *f; - long test; + long l; if (!b) return NULL; t = tokens; c = cmds; - while (*b) switch (*b) { + for (c->args = NULL, c->r = c->rds; *b; ++b) switch (*b) { default: - if (!*(b - 1)) { // Start of a token - if (!c->args) c->args = t; // Start of a command - *t++ = b; - } - ++b; - break; - case ' ': - *b++ = '\0'; + if (!c->args) c->args = t; + if (!*(b - 1)) *t++ = b; break; case '<': case '>': + c->r->newfd = *b == '>'; if (*(b - 1)) { - if ((test = strtol(*--t, &end, 10)) < 0 || test > INT_MAX || end != b) { + if (c->args == --t) c->args = NULL; + if ((l = strtol(*t, &end, 10)) < 0 || l > INT_MAX || end != b) { warnx("Invalid file redirection operator"); - c->args = NULL; - return c - 1; + return ∅ } - f->newfd = (int)test; - if (c->args == t) c->args = NULL; - } else f->newfd = *b == '>'; - f->mode = *b++; - if (*b == '>') { + c->r->newfd = l; + } + c->r->mode = *b; + if (*(b + 1) == '>') { + ++c->r->mode; ++b; - ++f->mode; } - f->old.name = b; - - (++f)->mode = END; - - if (*b == '&') ++b; + c->r++->oldname = b + 1; + if (*(b + 1) == '&') ++b; break; case '&': case '|': - if (*b == *(b + 1)) *b = '\0'; case ';': if (c->args) { - *t++ = NULL; - c->type = !*b ? *b++ + 1 : *b; - *b++ = '\0'; - for (f = c->freds; f->mode; ++f) { - if (*f->old.name == '&') { - if ((test = strtol(++f->old.name, &end, 10)) < 0 - || test > INT_MAX || (*end && !*f->old.name)) { - warnx("Invalid file redirection operator"); - c->args = NULL; - return c - 1; - } - f->type = FD; - f->old.fd = (int)test; - } else f->type = NAME; + if ((c->term = *b) != ';' && *b == *(b + 1)) { + ++c->term; + *b++ = '\0'; + } + *b = '\0'; + c->r->mode = END; + for (c->r = c->rds; c->r->mode; ++c->r) if (*c->r->oldname == '&') { + if ((l = strtol(++c->r->oldname, &end, 10)) < 0 || l > INT_MAX || *end) { + warnx("Invalid file redirection"); + return ∅ + } + c->r->oldfd = l; + c->r->oldname = NULL; } (++c)->args = NULL; - } else { - if (!*b) ++b; - *b++ = '\0'; + *t++ = NULL; } - f = c->freds; - f->mode = END; + c->r = c->rds; + case ' ': + *b = '\0'; } - switch ((c - 1)->type) { + switch ((c - 1)->term) { case AND: case PIPE: case OR: warnx("Command left open-ended"); - return c - 1; + return ∅ default: - *c = (struct cmd){0}; + break; } return cmds; diff --git a/src/lex.h b/src/lex.h index e80a1d4..21aace6 100644 --- a/src/lex.h +++ b/src/lex.h @@ -1,12 +1,4 @@ -enum terminator { - SEMI = ';', - BG = '&', - AND, - PIPE = '|', - OR, -}; - -enum mode { +enum accessmode { END, READ = '<', READWRITE, @@ -14,41 +6,28 @@ enum mode { APPEND, }; -enum type { - FD, - NAME, +struct redirect { + enum accessmode mode; + int oldfd, newfd; + char *oldname; }; -// if (cmd->f->type == NAME) cmd->f->old.fd = open(cmd->f->old.name, mode); -// dup2(cmd->f->newfd, cmd->f->old.fd); -// if (cmd->f->type == NAME) close(cmd->f->old.fd); -// -// // vs. -// -// if (*cmd->f->oldfd == '&') fd = open(++cmd->f->oldfd, mode); -// dup2(cmd->f->newfd, cmd-> - -struct fred { - int newfd; - enum mode mode; - enum type type; - union { - int fd; - char *name; - } old; +enum terminator { + SEMI = ';', + BG = '&', + AND, + PIPE = '|', + OR, }; -/* a>&b -> dup2(b, a); reopen(a, "w"); | (1)>&3 -> dup2(3, 1); - * a<&b -> dup2(b, a); reopen(a, "r"); | (0)<&3 -> dup2(3, 0); - * x >a >b >c ... - */ - +#define MAXRDS 25 struct cmd { char **args; - enum terminator type; - struct fred freds[(BUFLEN - 1) / 3 + 1]; + struct redirect *r, rds[MAXRDS + 1]; + enum terminator term; int pipe[2]; }; -void printfreds(struct cmd *c); +extern struct cmd empty; + struct cmd *lex(char *b); diff --git a/src/main.c b/src/main.c index 7080219..c30e40f 100644 --- a/src/main.c +++ b/src/main.c @@ -34,12 +34,12 @@ static int closepipe(struct cmd *cmd) { return result; } -static int redirectfiles(struct fred *f) { +static int redirectfiles(struct redirect *r) { int oflag, fd; - for (; f->mode; ++f) { - if (f->type == NAME) { - switch (f->mode) { + for (; r->mode; ++r) { + if (r->oldname) { + switch (r->mode) { case READ: oflag = O_RDONLY; break; @@ -54,19 +54,19 @@ static int redirectfiles(struct fred *f) { break; default:; } - if ((fd = open(f->old.name, oflag, 0644)) == -1) { - warn("Unable to open `%s'", f->old.name); + if ((fd = open(r->oldname, oflag, 0644)) == -1) { + warn("Unable to open `%s'", r->oldname); return 0; } - f->old.fd = fd; + r->oldfd = fd; } - if (dup2(f->old.fd, f->newfd) == -1) { - warn("Unable to redirect %d to %d", f->newfd, f->old.fd); + if (dup2(r->oldfd, r->newfd) == -1) { + warn("Unable to redirect %d to %d", r->newfd, r->oldfd); return 0; } - if (f->type == NAME) { - if (close(f->old.fd) == -1) { - warn("Unable to close file descriptor %d", f->old.fd); + if (r->oldname) { + if (close(r->oldfd) == -1) { + warn("Unable to close file descriptor %d", r->oldfd); return 0; } } @@ -83,11 +83,11 @@ int main(void) { initterm(); readhist(); - while ((cmd = lex(input()))) { - while (prev = cmd++, cmd->args) { - ispipe = cmd->type == PIPE || prev->type == PIPE; - ispipestart = ispipe && prev->type != PIPE; - ispipeend = ispipe && cmd->type != PIPE; + for (prev = ∅ (cmd = lex(input())); prev = &empty) { + for (; cmd->args; prev = cmd++) { + ispipe = cmd->term == PIPE || prev->term == PIPE; + ispipestart = ispipe && prev->term != PIPE; + ispipeend = ispipe && cmd->term != PIPE; if (ispipe) { if (!ispipeend && pipe(cmd->pipe) == -1) { @@ -112,7 +112,7 @@ int main(void) { if (!closepipe(cmd)) exit(EXIT_FAILURE); } - if (!redirectfiles(cmd->freds)) exit(EXIT_FAILURE); + if (!redirectfiles(cmd->rds)) exit(EXIT_FAILURE); if (isbuiltin(cmd->args, &status)) exit(EXIT_SUCCESS); if (execvp(*cmd->args, cmd->args) == -1) err(EXIT_FAILURE, "Couldn't find `%s' command", *cmd->args); @@ -122,12 +122,12 @@ int main(void) { jobid = ((struct job *)(ispipeend ? pull : peek)(&jobs))->id; } } else { - if (cmd->freds->mode == END && isbuiltin(cmd->args, &status)) break; + if (cmd->rds->mode == END && isbuiltin(cmd->args, &status)) break; if ((jobid = cpid = fork()) == -1) { warn("Unable to create child process"); break; } else if (cpid == 0) { - if (!redirectfiles(cmd->freds)) exit(EXIT_FAILURE); + if (!redirectfiles(cmd->rds)) exit(EXIT_FAILURE); if (isbuiltin(cmd->args, &status)) exit(EXIT_SUCCESS); if (execvp(*cmd->args, cmd->args) == -1) err(EXIT_FAILURE, "Couldn't find `%s' command", *cmd->args); @@ -144,18 +144,18 @@ int main(void) { } job = (struct job){.id = jobid, .config = canonical, .type = BACKGROUND}; - if (ispipestart || cmd->type == BG) { + if (ispipestart || cmd->term == BG) { if (!push(&jobs, &job)) { warn("Unable to add command to background; " "too many processes in the background"); if (ispipestart) closepipe(cmd); break; } - } else if (cmd->type != PIPE) { + } else if (cmd->term != PIPE) { if (!setfg(job)) break; status = waitfg(job); - if (cmd->type == AND && status != 0) break; - if (cmd->type == OR && status == 0) break; + if (cmd->term == AND && status != 0) break; + if (cmd->term == OR && status == 0) break; } } waitbg(0);