-Subproject commit e998819b1d1e191d035600967abd84e9f2eb9cf8
+Subproject commit 011c66e9c2332506752b701fdfa37739dde67f6a
return i;
}
-char *getaliasvalue(char *name) {
+char *getalias(char *name) {
size_t i;
if ((i = getindex(name)) == aliases.size) return NULL;
return aliases.entries[i].value;
}
-char **getalias(char *name) {
- char *value;
+char **parsealias(char *value) {
size_t l;
static struct context c;
- if (!(value = getaliasvalue(name))) return NULL;
+ if (!value) return NULL;
strcpy(c.buffer, value);
l = strlen(value);
switch (numargs) {
case 1:
for (i = 0; i < aliases.size; ++i)
- printf("%s -> %s\n", quoted(aliases.entries[i].name),
+ printf("%s = %s\n", quoted(aliases.entries[i].name),
aliases.entries[i].value);
break;
case 3:
if (aliases.size == MAXALIAS) {
- note("Unable to add alias, maximum reached (%d)", MAXALIAS);
+ note("Unable to add `%s' alias, maximum reached (%d)", args[1], MAXALIAS);
return EXIT_FAILURE;
}
+ if (!parsealias(args[2])) return EXIT_FAILURE;
+
for (i = 1; i <= 2; ++i) {
end = args[i] + strlen(args[i]);
while (*args[i] == ' ') ++args[i];
-char *getaliasvalue(char *name);
-char **getalias(char *name);
+char *getalias(char *name);
+char **parsealias(char *value);
int removealias(char *name);
#define MAXBG 100
-struct bglink {
- struct bgjob job;
- struct bglink *next;
-};
-
static struct {
- struct bglink entries[MAXBG], *active, *free;
+ struct bglink {
+ struct bgjob job;
+ struct bglink *next;
+ } entries[MAXBG], *active, *free;
} bgjobs;
struct sigaction bgaction;
err(EXIT_FAILURE, "Unable to duplicate directory entry");
(*src)[strlen(*src) - 2] = '\0';
if (src - srcs == 2 + MAXBUILTINS + 1)
- errx(EXIT_FAILURE, "Unable to add %s built-in, maximum reached (%d)",
+ errx(EXIT_FAILURE, "Unable to add `%s' built-in, maximum reached (%d)",
*src, MAXBUILTINS);
if (strcmp(*src, "builtin") != 0 && strcmp(*src, "list") != 0)
dprintf(listfd, "int %s(char **args, size_t numargs);\n", *src);
/* execute() is guaranteed not to return, this statement just appeases the
* compiler */
- return EXIT_SUCCESS;
+ exit(EXIT_SUCCESS);
}
pgid = getpgrp();
if (login && pid != pgid && setpgid(0, pgid = pid) == -1) exit(errno);
- if (tcsetpgrp(STDIN_FILENO, pgid) == -1)
+ if (tcsetpgrp(STDIN_FILENO, pgid) == -1
+ || tcgetattr(STDIN_FILENO, &canonical) == -1)
exit(errno);
-
- if (tcgetattr(STDIN_FILENO, &canonical) == -1) exit(errno);
raw = canonical;
raw.c_lflag &= ~(ICANON | ECHO);
if (!setconfig(&raw)) exit(EXIT_FAILURE);
switch (numargs) {
case 3:
if (setenv(args[1], args[2], 1) == -1) {
- note("Unable to set %s to %s", args[1], args[2]);
+ note("Unable to set `%s' to `%s'", args[1], args[2]);
return EXIT_FAILURE;
}
case 2:
if (unsetenv(args[1]) != -1) return EXIT_SUCCESS;
- note("Unable to unset $%s$", args[1]);
+ note("Unable to unset `%s'", args[1]);
return EXIT_FAILURE;
}
if (numargs != 2) return usage(args[0], "name");
- if ((p = getaliasvalue(args[1]))) puts(p);
- else if (getbuiltin(p = args[1])) printf("%s is a built-in\n", p);
+ if ((p = getalias(args[1]))) puts(p);
+ else if (getbuiltin(p = args[1])) printf("%s is built-in\n", p);
else if ((p = getpath(args[1]))) puts(quoted(p));
else {
printf("%s not found\n", quoted(args[1]));
struct context c;
c = (struct context){0};
-
options(argc, argv, &c);
init();
-
if (login) config(".thuslogin");
if (interactive) config(".thusrc");
-
while (run(&c));
-
deinit();
return EXIT_SUCCESS;
int opt;
argvector = argv;
-
if (argvector[0][0] == '-') {
++argvector[0];
login = 1;
}
if ((p = strrchr(argvector[0], '/'))) argvector[0] = p + 1;
- interactive = 1;
- c->input = userinput;
opt = 0;
argcount = argc;
+ interactive = 1;
+ c->input = userinput;
while (opt != 'c' && (opt = getopt(argcount, argvector, ":c:hl")) != -1)
switch (opt) {
case 'c':
c->t += numtokens - 1;
}
-static int subalias(struct context *c) {
+static void subalias(struct context *c) {
char **tokens;
size_t numtokens;
- if (c->alias || c->t != c->tokens || !(tokens = getalias(c->tokens[0]))) return 0;
+ if (c->alias || c->t != c->tokens
+ || !(tokens = parsealias(getalias(c->tokens[0]))))
+ return;
for (numtokens = 0; tokens[numtokens]; ++numtokens);
sub(c, tokens, numtokens);
-
- return 1;
}
int parse(struct context *c) {
errno = 0;
if (stlend == c->b - 1)
var = l >= 0 && l < argcount ? argvector[l] : c->b - 1;
- else if (strcmp(p + 1, "^") == 0) {
- if (!sprintf(var = (char [12]){0}, "%d", status)) {
- note("Unable to get previous command status");
- return quit(c);
- }
- } else if (!(var = getenv(p + 1))) var = "";
+ else if (strcmp(p + 1, "^") == 0) sprintf(var = (char [12]){0}, "%d", status);
+ else if (!(var = getenv(p + 1))) var = c->b - 1;
v = strlen(var);
offset = v - (c->b - p);
*c->b = '\0';
if (*c->t != c->b) ++c->t;
*c->t = ++c->b;
-
while (*c->b && *c->b != '\'') ++c->b;
if (!*c->b) {
note("Quote left open-ended");
return quit(c);
}
-
*c->b = '\0';
subalias(c);
++c->t;
break;
case '"':
+ quote = !quote;
+
*c->b = '\0';
- if (quote) subalias(c);
- if (quote || *c->t != c->b) ++c->t;
+ if (!quote) subalias(c);
+ if (!quote || *c->t != c->b) ++c->t;
*c->t = c->b + 1;
- quote = !quote;
-
break;
case '\\':
if (!quote) break;
case ';':
case ' ':
if (quote) break;
+
if (*c->b == '#') *(c->b + 1) = '\0';
term = *c->b;
c->r->mode = NONE;
}
- if (*c->t != c->b) {
- if (!subalias(c) && globbing) {
- globflags = GLOB_MARK;
- if (prevnumglobs) globflags |= GLOB_APPEND;
- switch (glob(*c->t, globflags, NULL, &globs)) {
- case GLOB_NOMATCH:
- note("No matches found for `%s'", *c->t);
- return quit(c);
- case GLOB_NOSPACE:
- fatal("Memory allocation");
- }
-
- globbing = 0;
- sub(c, globs.gl_pathv + prevnumglobs, globs.gl_pathc - prevnumglobs);
- prevnumglobs = globs.gl_pathc;
+ if (globbing) {
+ globflags = GLOB_MARK;
+ if (prevnumglobs) globflags |= GLOB_APPEND;
+ switch (glob(*c->t, globflags, NULL, &globs)) {
+ case GLOB_NOMATCH:
+ note("No matches found for `%s'", *c->t);
+ return quit(c);
+ case GLOB_NOSPACE:
+ fatal("Memory allocation");
}
+
+ globbing = 0;
+ sub(c, globs.gl_pathv + prevnumglobs, globs.gl_pathc - prevnumglobs);
+ prevnumglobs = globs.gl_pathc;
+ }
+
+ if (*c->t != c->b) {
+ subalias(c);
++c->t;
}
- if (term != ' ') {
- *c->t = NULL;
- if (c->t != c->tokens) {
- c->numtokens = c->t - c->tokens;
- strcpy(c->current.name, c->tokens[0]);
- } else c->t = NULL;
- if (c->r == c->redirects) c->r = NULL;
- switch (term) {
- case '&':
- case '|':
- c->current.term = term;
- if (*(c->b + 1) == term) {
- ++c->current.term;
- *++c->b = '\0';
- }
- break;
- case ';':
- c->current.term = SEMI;
- }
- ++c->b;
+ if (term == ' ') {
+ *c->t = c->b + 1;
+ break;
+ }
- return 1;
+ *c->t = NULL;
+ if (c->t != c->tokens) {
+ c->numtokens = c->t - c->tokens;
+ strcpy(c->current.name, c->tokens[0]);
+ } else c->t = NULL;
+ if (c->r == c->redirects) c->r = NULL;
+ switch (term) {
+ case '&':
+ case '|':
+ c->current.term = term;
+ if (*(c->b + 1) == term) {
+ ++c->current.term;
+ *++c->b = '\0';
+ }
+ break;
+ case ';':
+ c->current.term = SEMI;
}
+ ++c->b;
- *c->t = c->b + 1;
+ return 1;
}
if (quote) {
}
if (c->r) for (c->r = c->redirects; c->r->mode; ++c->r) {
if (c->r != c->redirects) putchar(' ');
- printf("%d%.*s", c->r->newfd, (c->r->mode & 1) + 1, &"<>>"[c->r->mode & 2]);
- if (c->r->oldname) printf("%s", c->r->oldname);
+ if (c->r->newfd != c->r->mode >= WRITE) printf("%d", c->r->newfd);
+ putchar(c->r->mode < WRITE ? READ : WRITE);
+ if (c->r->mode == READWRITE || c->r->mode == APPEND) putchar(WRITE);
+ if (c->r->oldname) fputs(c->r->oldname, stdout);
else printf("&%d", c->r->oldfd);
}
switch (c->current.term) {
}
islist = c->previous.term > BG || c->current.term > BG;
- if (c->t) {
- if (c->current.term == BG && bgfull()) {
- note("Unable to place job in background; too many background jobs");
- return quit(c);
- }
- if (!(c->current.builtin = getbuiltin(c->current.name))
- && !(c->current.path = getpath(c->current.name))) {
- note("Couldn't find `%s' command", c->current.name);
- if (c->previous.term == PIPE) killpg(pipeid, SIGKILL);
- return quit(c);
- }
-
- ispipe = c->previous.term == PIPE || c->current.term == PIPE;
- ispipestart = ispipe && c->previous.term != PIPE;
- ispipeend = ispipe && c->current.term != PIPE;
-
- if (ispipe) {
- if (!ispipeend && pipe(c->current.pipe) == -1) {
- note("Unable to create pipe");
- if (!ispipestart) closepipe(c->previous);
- return quit(c);
- }
- if ((cpid = fork()) == -1) {
- note("Unable to fork child process");
- return quit(c);
- } else if (cpid == 0) {
- if (!ispipestart) {
- if (dup2(c->previous.pipe[0], 0) == -1)
- fatal("Unable to duplicate read end of `%s' pipe", c->previous.name);
- if (!closepipe(c->previous)) exit(EXIT_FAILURE);
- }
- if (!ispipeend) {
- if (dup2(c->current.pipe[1], 1) == -1)
- fatal("Unable to duplicate write end of `%s' pipe", c->current.name);
- if (!closepipe(c->current)) exit(EXIT_FAILURE);
- }
- redirectfiles(c->redirects);
- execute(c);
- }
- if (ispipestart) pipeid = cpid;
- else if (!closepipe(c->previous)) {
- killpg(pipeid, SIGKILL);
- return quit(c);
- }
- jobid = pipeid;
- } else if (!c->r && (c->current.builtin = getbuiltin(c->current.name))) {
- status = c->current.builtin(c->tokens, c->numtokens);
- cpid = 0;
- } else if ((jobid = cpid = fork()) == -1) {
- note("Unable to fork child process");
- return quit(c);
- } else if (cpid == 0) {
- redirectfiles(c->redirects);
- execute(c);
- }
-
- if (cpid) {
- if (setpgid(cpid, jobid) == -1) {
- if (errno != ESRCH) {
- note("Unable to set pgid of `%s' command to %d", c->current.name, jobid);
- if (kill(cpid, SIGKILL) == -1)
- note("Unable to kill process %d; may need to manually terminate", cpid);
- }
- return quit(c);
- }
- if (ispipestart || c->current.term == BG) {
- pushbgid(jobid);
- return 1;
- }
- if (c->current.term != PIPE && !runfg(jobid)) return quit(c);
- }
- if (status != EXIT_SUCCESS) {
- if (!islist) return quit(c);
- if (c->current.term == AND) return clear(c);
- } else if (c->current.term == OR) return clear(c);
- } else {
+ if (!c->t) {
if (islist) {
if (c->previous.term == PIPE) {
killpg(pipeid, SIGKILL);
if ((cpid = fork()) == -1) {
note("Unable to fork child process");
return quit(c);
- } else if (cpid == 0) {
+ }
+ if (!cpid) {
redirectfiles(c->redirects);
exit(EXIT_SUCCESS);
}
waitpid(cpid, NULL, 0);
errno = 0;
+
+ return 1;
+ }
+
+ if (c->current.term == BG && bgfull()) {
+ note("Unable to place job in background; too many background jobs");
+ return quit(c);
+ }
+ if (!(c->current.builtin = getbuiltin(c->current.name))
+ && !(c->current.path = getpath(c->current.name))) {
+ note("Couldn't find `%s' command", c->current.name);
+ if (c->previous.term == PIPE) killpg(pipeid, SIGKILL);
+ return quit(c);
}
+ ispipe = c->previous.term == PIPE || c->current.term == PIPE;
+ ispipestart = ispipe && c->previous.term != PIPE;
+ ispipeend = ispipe && c->current.term != PIPE;
+
+ if (ispipe) {
+ if (!ispipeend && pipe(c->current.pipe) == -1) {
+ note("Unable to create pipe");
+ if (!ispipestart) closepipe(c->previous);
+ return quit(c);
+ }
+ if ((cpid = fork()) == -1) {
+ note("Unable to fork child process");
+ return quit(c);
+ }
+ if (!cpid) {
+ if (!ispipestart) {
+ if (dup2(c->previous.pipe[0], 0) == -1)
+ fatal("Unable to duplicate read end of `%s' pipe", c->previous.name);
+ if (!closepipe(c->previous)) exit(EXIT_FAILURE);
+ }
+ if (!ispipeend) {
+ if (dup2(c->current.pipe[1], 1) == -1)
+ fatal("Unable to duplicate write end of `%s' pipe", c->current.name);
+ if (!closepipe(c->current)) exit(EXIT_FAILURE);
+ }
+ redirectfiles(c->redirects);
+ execute(c);
+ }
+ if (ispipestart) pipeid = cpid;
+ else if (!closepipe(c->previous)) {
+ killpg(pipeid, SIGKILL);
+ return quit(c);
+ }
+ jobid = pipeid;
+ } else if (!c->r && (c->current.builtin = getbuiltin(c->current.name))) {
+ status = c->current.builtin(c->tokens, c->numtokens);
+ cpid = 0;
+ } else if ((jobid = cpid = fork()) == -1) {
+ note("Unable to fork child process");
+ return quit(c);
+ } else if (!cpid) {
+ redirectfiles(c->redirects);
+ execute(c);
+ }
+
+ if (cpid) {
+ if (setpgid(cpid, jobid) == -1) {
+ if (errno != ESRCH) {
+ note("Unable to set pgid of `%s' command to %d", c->current.name, jobid);
+ if (kill(cpid, SIGKILL) == -1)
+ note("Unable to kill process %d; may need to manually terminate", cpid);
+ }
+ return quit(c);
+ }
+ if (ispipestart || c->current.term == BG) {
+ pushbgid(jobid);
+ return 1;
+ }
+ if (c->current.term != PIPE && !runfg(jobid)) return quit(c);
+ }
+
+ if (status != EXIT_SUCCESS) {
+ if (!islist) return quit(c);
+ if (c->current.term == AND) return clear(c);
+ } else if (c->current.term == OR) return clear(c);
+
return 1;
}
sigaddset(&shellsigmask, SIGTSTP);
sigaddset(&shellsigmask, SIGTTIN);
sigaddset(&shellsigmask, SIGTTOU);
+ if (sigprocmask(SIG_BLOCK, &shellsigmask, &childsigmask) == -1) exit(errno);
+
+ defaultaction = (struct sigaction){.sa_handler = SIG_DFL};
+ setsig(SIGTSTP, &defaultaction);
+ setsig(SIGTTOU, &defaultaction);
+ setsig(SIGTTIN, &defaultaction);
action = (struct sigaction){.sa_handler = sigwinchhandler};
setsig(SIGWINCH, &action);
action = (struct sigaction){.sa_handler = siginthandler};
setsig(SIGINT, &action);
-
- defaultaction = (struct sigaction){.sa_handler = SIG_DFL};
- setsig(SIGTSTP, &defaultaction);
- setsig(SIGTTOU, &defaultaction);
- setsig(SIGTTIN, &defaultaction);
-
- if (sigprocmask(SIG_BLOCK, &shellsigmask, &childsigmask) == -1) exit(errno);
}
va_list args;
fprintf(stderr, "%s: ", argvector[0]);
-
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
-
if (errno) {
fprintf(stderr, ": %s", strerror(errno));
errno = 0;
}
-
putchar('\n');
}
va_list args;
fprintf(stderr, "%s: ", argvector[0]);
-
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
-
if (errno) fprintf(stderr, ": %s", strerror(errno));
-
putchar('\n');
exit(errno);
if (degree < SINGLE) degree = SINGLE;
break;
case '\'':
- degree |= DOUBLE;
+ if (degree == NONE || degree == SINGLE) ++degree;
}
if (degree == NONE) return token;
*p++ = quote;
strcpy(p, token);
for (q = p; *q; ++q);
- if (degree & DOUBLE) for (; *p; ++p) switch (*p)
+ if (degree != SINGLE) for (; *p; ++p) switch (*p)
case '$':
case '~':
case '"':
memmove(p + 1, p, ++q - p);
*p++ = '\\';
}
- *p++ = quote;
- *p++ = '\0';
+ *q++ = quote;
+ *q++ = '\0';
return buffer;
}