]> Trent Huber's Code - thus.git/commitdiff
Linux compatibility checkin, more bug fixes
authorTrent Huber <trentmhuber@gmail.com>
Fri, 22 Aug 2025 18:11:37 +0000 (14:11 -0400)
committerTrent Huber <trentmhuber@gmail.com>
Fri, 22 Aug 2025 18:11:37 +0000 (14:11 -0400)
19 files changed:
src/build.c
src/builtin/alias.c
src/builtin/bg.c
src/builtin/bg.h [new file with mode: 0644]
src/builtin/builtin.c
src/builtin/fg.c
src/builtin/fg.h
src/builtin/source.c
src/builtin/which.c
src/context.c
src/history.c
src/history.h
src/input.c
src/input.h
src/job.c [deleted file]
src/job.h [deleted file]
src/parse.c
src/run.c
src/utils.c

index 8e7627442d65127ff37729f5b4c9efb3b46b8521..07a1eac5d64de9e09cc7d570a74ad8350fdb1b1b 100644 (file)
@@ -13,7 +13,6 @@ int main(void) {
                                   {"context", NONE},
                                   {"history", NONE},
                                   {"input", NONE},
-                                  {"job", NONE},
                                   {"main", BUILTINS},
                                   {"options", BUILTINS},
                                   {"parse", BUILTINS},
index a4c5d6d4e35bde6c86123e6aefaee95fc6b3b00d..a208a86a933d998c90d4fba8368ffaf8fdcbbc42 100644 (file)
@@ -52,7 +52,7 @@ BUILTIN(alias) {
    switch (argc) {
    case 1:
        for (i = 0; i < aliases.size; ++i)
-           printf("%s = \"%s\"\r\n", aliases.entries[i].lhs, aliases.entries[i].rhs);
+           printf("%s = \"%s\"\n", aliases.entries[i].lhs, aliases.entries[i].rhs);
        break;
    case 3:
        if (aliases.size == MAXALIAS) {
index 55232ec6fd7ff339e1efcad973fbbff077217e42..15457b031f7d1aacf2b76939157223c3695465e0 100644 (file)
 #include <limits.h>
 #include <signal.h>
 #include <stdlib.h>
+#include <string.h>
 #include <sys/errno.h>
 #include <termios.h>
 
+#include "bg.h"
 #include "builtin.h"
-#include "job.h"
+#include "fg.h"
 #include "utils.h"
 
+#define MAXBG 100
+
+struct bglink {
+   struct bgjob job;
+   struct bglink *next;
+};
+
+static struct {
+   struct bglink entries[MAXBG + 1], *active, *free;
+} bgjobs;
+
+void initbg(void) {
+   size_t i;
+
+   for (i = 0; i < MAXBG - 1; ++i)
+       bgjobs.entries[i].next = &bgjobs.entries[i + 1];
+   bgjobs.free = bgjobs.entries;
+}
+
+int fullbg(void) {
+   return !bgjobs.free;
+}
+
+int pushbg(struct bgjob job) {
+   struct bglink *p;
+
+   if (fullbg()) return 0;
+
+   (p = bgjobs.free)->job = job;
+   bgjobs.free = p->next;
+   p->next = bgjobs.active;
+   bgjobs.active = p;
+
+   return 1;
+}
+
+int peekbg(struct bgjob *job) {
+   if (bgjobs.active && job) *job = bgjobs.active->job;
+   return bgjobs.active != NULL;
+}
+
+int searchbg(pid_t id, struct bgjob *job) {
+   struct bglink *p;
+
+   for (p = bgjobs.active; p; p = p->next) if (p->job.id == id) {
+       if (job) *job = p->job;
+       return 1;
+   }
+
+   return 0;
+}
+
+int pushid(pid_t id) {
+   return pushbg((struct bgjob){.id = id, .config = canonical});
+}
+
+void removeid(pid_t id) {
+   struct bglink *p, *prev;
+   
+   for (prev = NULL, p = bgjobs.active; p; prev = p, p = p->next)
+       if (p->job.id == id) break;
+   if (!p) return;
+
+   if (prev) prev->next = p->next; else bgjobs.active = p->next;
+   p->next = bgjobs.free;
+   bgjobs.free = p;
+}
+
+void waitbg(int sig) {
+   int e, s;
+   struct bglink *p;
+   pid_t id;
+
+   (void)sig;
+   e = errno;
+   p = bgjobs.active;
+   while (p) {
+       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;
+           removeid(id);
+       } else p = p->next;
+   }
+   errno = e;
+}
+
+void deinitbg(void) {
+   struct bglink *p;
+
+   for (p = bgjobs.active; p; p = p->next) killpg(p->job.id, SIGKILL);
+}
+
 BUILTIN(bg) {
+   struct bglink *p;
+   struct bgjob job;
    long l;
-   pid_t id;
-   struct job *job;
 
    switch (argc) {
    case 1:
-       if (!(job = peeksuspendedjob())) return EXIT_FAILURE;
+       for (p = bgjobs.active; p; p = p->next) if (p->job.suspended) {
+           job = p->job;
+           break;
+       }
+       if (!p) {
+           note("No suspended jobs to run in the background");
+           return EXIT_FAILURE;
+       }
        break;
    case 2:
        errno = 0;
@@ -23,26 +130,26 @@ BUILTIN(bg) {
            note("Invalid job id %ld", l);
            return EXIT_FAILURE;
        }
-       if (!(job = searchjobid(id = (pid_t)l))) {
-           note("Unable to find job %d", id);
+       if (!searchbg(l, &job)) {
+           note("Unable to find job %d", (pid_t)l);
            return EXIT_FAILURE;
        }
-       if (!job->suspended) {
-           note("Job %d already in background", id);
+       if (!job.suspended) {
+           note("Job %d already in background", job.id);
            return EXIT_FAILURE;
        }
        break;
    default:
        return usage(argv[0], "[pgid]");
    }
-   deletejobid(job->id);
 
-   if (!pushjob(job)) return EXIT_FAILURE;
-   if (killpg(job->id, SIGCONT) == -1) {
-       note("Unable to wake up suspended job %d", job->id);
+   if (killpg(job.id, SIGCONT) == -1) {
+       note("Unable to wake up suspended job %d", job.id);
        return EXIT_FAILURE;
    }
-   job->suspended = 0;
+   removeid(job.id);
+   job.suspended = 0;
+   pushbg(job);
 
    return EXIT_SUCCESS;
 }
diff --git a/src/builtin/bg.h b/src/builtin/bg.h
new file mode 100644 (file)
index 0000000..6b6c135
--- /dev/null
@@ -0,0 +1,19 @@
+struct bgjob {
+   pid_t id;
+   struct termios config;
+   int suspended;
+};
+
+void initbg(void);
+
+int fullbg(void);
+int pushbg(struct bgjob job);
+int peekbg(struct bgjob *job);
+int searchbg(pid_t id, struct bgjob *job);
+
+int pushid(pid_t id);
+void removeid(pid_t id);
+
+void waitbg(int sig);
+
+void deinitbg(void);
index 7a2831c3199a0ce6cf624427fa8425068944bb60..d9ef4d130e75e32e04a95273c8db6f24fff47190 100644 (file)
@@ -20,6 +20,6 @@ int isbuiltin(char **args) {
 }
 
 int usage(char *program, char *options) {
-   fprintf(stderr, "Usage: %s %s\r\n", program, options);
+   fprintf(stderr, "Usage: %s %s\n", program, options);
    return EXIT_FAILURE;
 }
index 1335957a1e53442cc769477decdd872596d6dd23..15fb381037a3ab8c8fa0f538b91a9cd31e5bb551 100644 (file)
@@ -3,20 +3,24 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/errno.h>
+#include <sys/wait.h>
 #include <termios.h>
 #include <unistd.h>
 
+#include "bg.h"
 #include "builtin.h"
-#include "job.h"
+#include "context.h"
+#include "input.h"
 #include "utils.h"
 
 static struct {
    pid_t id;
    int status, done;
-} fgpg;
+} fgjob;
 struct termios canonical;
 static struct termios raw;
-struct sigaction sigchld, sigdfl;
+struct sigaction actbg, actdefault;
+static struct sigaction actall, actignore;
 
 static int setconfig(struct termios *mode) {
    if (tcsetattr(STDIN_FILENO, TCSANOW, mode) == -1) {
@@ -26,22 +30,21 @@ static int setconfig(struct termios *mode) {
    return 1;
 }
 
-static void sigchldhandler(int sig) {
-   int e;
+static void waitall(int sig) {
+   int e, s;
    pid_t id;
-   struct job *job;
 
-   (void)sig;
    e = errno;
-   while ((id = waitpid(-1, &fgpg.status, WNOHANG | WUNTRACED)) > 0)
-       if ((job = searchjobid(id))) {
-           if (WIFSTOPPED(fgpg.status)) job->suspended = 1; else deletejobid(id);
-       } else {
-           fgpg.done = 1;
-           if (WIFSTOPPED(fgpg.status)) continue;
-           if (id != fgpg.id) waitpid(fgpg.id, &fgpg.status, 0);
-           while (waitpid(-fgpg.id, NULL, 0) != -1);
+   while ((id = waitpid(-fgjob.id, &s, WNOHANG | WUNTRACED)) > 0) {
+       if (id == fgjob.id) fgjob.status = s;
+       if (WIFSTOPPED(s)) {
+           fgjob.status = s;
+           fgjob.done = 1;
+           break;
        }
+   }
+   if (id == -1) fgjob.done = 1;
+   waitbg(sig);
    errno = e;
 }
 
@@ -53,62 +56,65 @@ void setsigchld(struct sigaction *act) {
 void initfg(void) {
    if (tcgetattr(STDIN_FILENO, &canonical) == -1)
        fatal("Unable to get default termios config");
-   cfmakeraw(&raw);
+   raw = canonical;
+   raw.c_lflag &= ~(ICANON | ECHO | ISIG);
    if (!setconfig(&raw)) exit(EXIT_FAILURE);
 
-   sigchld.sa_handler = sigchldhandler;
-   sigdfl.sa_handler = SIG_DFL;
-   setsigchld(&sigchld);
+   actbg.sa_handler = waitbg;
+   actall.sa_handler = waitall;
+   actdefault.sa_handler = SIG_DFL;
+   actignore.sa_handler = SIG_IGN;
 }
 
-int setfg(struct job job) {
+int runfg(pid_t id) {
+   struct bgjob job;
+
+   if (!searchbg(id, &job)) job = (struct bgjob){.id = id, .config = canonical};
    if (!setconfig(&job.config)) return 0;
-   if (tcsetpgrp(STDIN_FILENO, job.id) == -1) {
-       note("Unable to bring job %d to foreground", job.id);
+   if (tcsetpgrp(STDIN_FILENO, id) == -1) {
+       note("Unable to bring job %d to foreground", id);
        setconfig(&raw);
        return 0;
    }
-   if (killpg(job.id, SIGCONT) == -1) {
-       note("Unable to wake up job %d", job.id);
+   if (killpg(id, SIGCONT) == -1) {
+       note("Unable to wake up job %d", id);
        return 0;
    }
-   return 1;
-}
-
-void waitfg(struct job job) {
-   struct sigaction sigign;
+   removeid(id);
 
    /* SIGCHLD handler is really the function that reaps the foreground process,
     * the waitpid() below is just to block the current thread of execution until
     * the foreground process has been reaped. */
-   fgpg.id = job.id;
-   setsigchld(&sigchld);
-   while (waitpid(fgpg.id, NULL, 0) && !fgpg.done);
-   fgpg.done = errno = 0;
-   setsigchld(&sigdfl);
+   fgjob.id = id;
+   setsigchld(&actall);
+   while (!fgjob.done) sigsuspend(&actall.sa_mask);
+   setsigchld(&actdefault);
+   fgjob.done = errno = 0;
 
-   if (sigaction(SIGTTOU, &(struct sigaction){{SIG_IGN}}, NULL) == -1
+   if (sigaction(SIGTTOU, &actignore, NULL) == -1
        || tcsetpgrp(STDIN_FILENO, getpgrp()) == -1
-       || sigaction(SIGTTOU, &sigdfl, NULL) == -1) {
+       || sigaction(SIGTTOU, &actdefault, NULL) == -1) {
        note("Unable to reclaim foreground; terminating");
        deinit();
        exit(EXIT_FAILURE);
    }
    if (tcgetattr(STDIN_FILENO, &job.config) == -1)
-       note("Unable to save termios config of job %d", job.id);
+       note("Unable to save termios config of job %d", id);
    setconfig(&raw);
 
-   if (WIFEXITED(fgpg.status)) status = WEXITSTATUS(fgpg.status);
-   else if (WIFSTOPPED(fgpg.status)) {
-       status = WSTOPSIG(fgpg.status);
+   if (WIFEXITED(fgjob.status)) status = WEXITSTATUS(fgjob.status);
+   else if (WIFSTOPPED(fgjob.status)) {
+       status = WSTOPSIG(fgjob.status);
        job.suspended = 1;
-       if (!pushjob(&job)) {
-           note("Press any key to continue");
+       if (!pushbg(job)) {
+           note("Unable to suspend current process, too many background jobs\n"
+                "(Press any key to continue)");
            getchar();
-           if (setfg(job)) return waitfg(job);
-           note("Manual intervention required for job %d", job.id);
+           return runfg(id);
        }
-   } else status = WTERMSIG(fgpg.status);
+   } else status = WTERMSIG(fgjob.status);
+   
+   return 1;
 }
 
 void deinitfg(void) {
@@ -116,16 +122,17 @@ void deinitfg(void) {
 }
 
 BUILTIN(fg) {
+   struct bgjob job;
    long l;
    pid_t id;
-   struct job *job;
 
    switch (argc) {
    case 1:
-       if (!(job = pulljob())) {
+       if (!peekbg(&job)) {
            note("No job to bring into the foreground");
            return EXIT_FAILURE;
        }
+       id = job.id;
        break;
    case 2:
        errno = 0;
@@ -133,18 +140,17 @@ BUILTIN(fg) {
            note("Invalid process group id %ld", l);
            return EXIT_FAILURE;
        }
-       if (!(job = searchjobid(id))) {
+       id = (pid_t)l;
+       if (!searchbg(id, NULL)) {
            note("Unable to find job %d", id);
            return EXIT_FAILURE;
        }
-       deletejobid(id);
        break;
    default:
        return usage(argv[0], "[pgid]");
    }
 
-   if (!setfg(*job)) return EXIT_FAILURE;
-   waitfg(*job);
+   if (!runfg(id)) return EXIT_FAILURE;
 
    return EXIT_SUCCESS;
 }
index dd98ff57dd44422d9764e4c91abe2a21ce6e0cf6..6436bc40ab8c4553f3c33b5f3be8a35ce0b796e6 100644 (file)
@@ -1,8 +1,7 @@
 extern struct termios canonical;
-extern struct sigaction sigchld, sigdfl;
+extern struct sigaction actbg, actdefault;
 
 void setsigchld(struct sigaction *act);
 void initfg(void);
-int setfg(struct job job);
-void waitfg(struct job job);
+int runfg(pid_t id);
 void deinitfg(void);
index c53c09c55aadc082cc5530912e7d9edfa1c3ffe3..91f0570a75b7e10e48d030cdf7bd716cbb9a9dd4 100644 (file)
@@ -14,10 +14,7 @@ BUILTIN(source) {
    int c;
    char **v;
    
-   if (argc == 1) {
-       fputs("Usage: source file [args ...]\r\n", stderr);
-       return EXIT_FAILURE;
-   }
+   if (argc == 1) return usage(argv[0], "file [args ...]");
 
    context = (struct context){0};
    context.script = argv[1];
index 6b3d6a58f7e3d3a3d632c04061202cc7ae6c361f..2cde2281a71f30c8e9c9a4e117fd343e2b7740fb 100644 (file)
@@ -83,13 +83,13 @@ BUILTIN(which) {
    if (argc != 2) return usage(argv[0], "name");
 
    if (!(result = getpathtype(argv[1], &type))) {
-       printf("%s not found\r\n", argv[1]);
+       printf("%s not found\n", argv[1]);
        return EXIT_SUCCESS;
    }
    
    fputs(result, stdout);
    if (type == BUILTIN) fputs(" is built-in", stdout);
-   puts("\r");
+   putchar('\n');
 
    return EXIT_SUCCESS;
 }
index e11ec3c97ad8385eb8c98bdc29a56e836c73ed36..35f9b61ea68678343ad1b7b721dfdc73f0b00c7d 100644 (file)
@@ -7,7 +7,7 @@ int clear(struct context *c) {
    c->b = NULL;
    c->t = NULL;
    c->r = NULL;
-   *c->current.name = '\0';
+   *c->current.name = *c->buffer = '\0';
    c->current.term = SEMI;
 
    return 1;
index 945064d8f846842ecf110bf6be300b6c84a918f8..511ce7aaf0d95356ef56e233e80367af6e388c51 100644 (file)
@@ -35,14 +35,14 @@ void inithistory(void) {
    if (fclose(file) == EOF) fatal("Unable to close history file");
 }
 
-int gethistory(char direction, char *buffer) {
-   if (history.c == (direction == UP ? history.b : history.t)) return 0;
+int gethistory(int back, char *buffer) {
+   if (history.c == (back ? history.b : history.t)) return 0;
 
    // Save the most recently modified history entry at the top of the list
    if (strcmp(history.entries[history.c], buffer) != 0)
        strcpy(history.entries[history.t], buffer);
 
-   strcpy(buffer, history.entries[direction == UP ? DEC(c) : INC(c)]);
+   strcpy(buffer, history.entries[back ? DEC(c) : INC(c)]);
 
    return 1;
 }
index 4c2428d4742ca98e1cc16228b3f768e57f6ccbd5..49dce14aaf8fb9b102f19367c26f51f800b3c589 100644 (file)
@@ -1,4 +1,4 @@
 void inithistory(void);
-int gethistory(char direction, char *buffer);
+int gethistory(int back, char *buffer);
 void sethistory(char *buffer);
 void deinithistory(void);
index b73b69bfae95198b930c6d65a6efeaa73ccb8ce2..9e6622f002a06c51ab2c2c815c247fade6124405 100644 (file)
 #include "input.h"
 #include "utils.h"
 
+enum {
+   CTRLC = '\003',
+   CTRLD,
+   CLEAR = '\014',
+   ESCAPE = '\033',
+
+   // See ESCAPE case in userinput()
+   ALT = '2' + 1,
+
+   UP = 'A',
+   DOWN,
+   RIGHT,
+   LEFT,
+   FORWARD = 'f',
+   BACKWARD = 'b',
+   DEL = '\177',
+};
+
 int stringinput(struct context *c) {
    char *start;
    size_t l;
@@ -72,23 +90,22 @@ static void prompt(void) {
 
    if (!(p = getenv("PROMPT")) && setenv("PROMPT", p = ">", 1) == -1)
        note("Unable to update $PROMPT$ environment variable");
-   printf("\r%s ", p);
+   printf("%s ", p);
 }
 
 int userinput(struct context *c) {
    char *start, *cursor, *end;
-   unsigned int current;
-   int i;
+   int current, i;
    size_t oldlen, newlen;
 
+   clear(c);
    end = cursor = start = c->buffer;
-   *c->buffer = '\0';
    while (start == end) {
        prompt();
-       while ((current = getchar()) != '\r') switch (current) {
+       while ((current = getchar()) != '\n') switch (current) {
        default:
            if (current >= ' ' && current <= '~') {
-               if (end - start == MAXCHARS) continue;
+               if (end - start == MAXCHARS) break;
                memmove(cursor + 1, cursor, end - cursor);
                *cursor++ = current;
                *++end = '\0';
@@ -99,32 +116,41 @@ int userinput(struct context *c) {
            }
            break;
        case CTRLC:
-           puts("^C\r");
+           puts("^C");
            return quit(c);
        case CTRLD:
-           puts("^D\r");
+           puts("^D");
            return 0;
        case CLEAR:
            fputs("\033[H\033[J", stdout);
            prompt();
            fputs(c->buffer, stdout);
-           continue;
+           break;
+
+           /* 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 */
        case ESCAPE:
-           switch ((current = getchar())) {
-           case FORWARD:
-               while (cursor != end && *cursor != ' ') putchar(*cursor++);
-               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'));
-               break;
-           case ARROW:
-               switch ((current = getchar())) {
+           if ((current = getchar()) == '[') {
+               while ((current = getchar()) >= '0' && current <= '9');
+               if (current == ';') {
+                   if ((current = getchar()) == ALT) switch ((current = getchar())) {
+                   case LEFT:
+                       current = BACKWARD;
+                       break;
+                   case RIGHT:
+                       current = FORWARD;
+                       break;
+                   } else if ((current = getchar()) >= '0' && current <= '6')
+                       current = getchar();
+               }
+               switch (current) {
                case UP:
                case DOWN:
                    oldlen = strlen(c->buffer);
-                   if (!gethistory(current, c->buffer)) continue;
+                   if (!gethistory(current == UP, c->buffer)) break;
                    newlen = strlen(c->buffer);
                    end = cursor = start + newlen;
 
@@ -142,14 +168,21 @@ int userinput(struct context *c) {
                    if (cursor < end) putchar(*cursor++);
                    break;
                }
+           }
+           switch (current) {
+           case FORWARD:
+               while (cursor != end && *cursor != ' ') putchar(*cursor++);
+               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'));
                break;
-           default:
-               ungetc(current, stdin);
            }
            break;
-       case BACKSPACE:
+
        case DEL:
-           if (cursor == start) continue;
+           if (cursor == start) break;
            memmove(cursor - 1, cursor, end - cursor);
            --cursor;
            *--end = '\0';
@@ -161,7 +194,7 @@ int userinput(struct context *c) {
 
            break;
        }
-       puts("\r");
+       putchar('\n');
    }
 
    while (*start == ' ') ++start;
index 3762b05afd050df6b6fcce3a4d67c7063414be5c..ba5568807f28eb24bce34c46ad2ee5a9d9344868 100644 (file)
@@ -1,19 +1,3 @@
-enum {
-   CTRLC = '\003',
-   CTRLD,
-   BACKSPACE = '\010',
-   CLEAR = '\014',
-   ESCAPE = '\033',
-   FORWARD = 'f',
-   BACKWARD = 'b',
-   ARROW = '[',
-   UP = 'A',
-   DOWN,
-   RIGHT,
-   LEFT,
-   DEL = '\177',
-};
-
 int stringinput(struct context *c);
 int scriptinput(struct context *c);
 int userinput(struct context *c);
diff --git a/src/job.c b/src/job.c
deleted file mode 100644 (file)
index c412040..0000000
--- a/src/job.c
+++ /dev/null
@@ -1,88 +0,0 @@
-#include <string.h>
-#include <termios.h>
-
-#include "job.h"
-#include "utils.h"
-
-#define MAXJOBS 100
-
-struct joblink {
-   struct job job;
-   struct joblink *next;
-};
-
-static struct {
-   struct joblink entries[MAXJOBS + 1], *active, *free;
-} jobs;
-
-void initjobs(void) {
-   size_t i;
-
-   for (i = 0; i < MAXJOBS - 1; ++i) jobs.entries[i].next = &jobs.entries[i + 1];
-   jobs.free = jobs.entries;
-}
-
-struct job *pushjob(struct job *job) {
-   struct joblink *p;
-
-   if (!jobs.free) {
-       note("Unable to %s, exceeds %d job limit",
-            job->suspended ? "suspend job" : "place job in background", MAXJOBS);
-       return NULL;
-   }
-
-   (p = jobs.free)->job = *job;
-   jobs.free = p->next;
-   p->next = jobs.active;
-   jobs.active = p;
-
-   return &p->job;
-}
-
-struct job *pulljob(void) {
-   struct joblink *p;
-
-   if (!jobs.active) return NULL;
-
-   p = jobs.active;
-   jobs.active = p->next;
-   p->next = jobs.free;
-   jobs.free = p;
-
-   return &p->job;
-}
-
-struct job *peekjob(void) {
-   return jobs.active ? &jobs.active->job : NULL;
-}
-
-struct job *peeksuspendedjob(void) {
-   struct joblink *p;
-
-   for (p = jobs.active; p; p = p->next) if (p->job.suspended) return &p->job;
-
-   note("No suspended job to run in background");
-
-   return NULL;
-}
-
-struct job *searchjobid(pid_t id) {
-   struct joblink *p;
-
-   for (p = jobs.active; p; p = p->next) if (p->job.id == id) return &p->job;
-
-   return NULL;
-}
-
-struct job *deletejobid(pid_t id) {
-   struct joblink *p, *prev;
-   
-   for (prev = NULL, p = jobs.active; p; prev = p, p = p->next) if (p->job.id == id) break;
-   if (!p) return NULL;
-
-   if (prev) prev->next = p->next; else jobs.active = p->next;
-   p->next = jobs.free;
-   jobs.free = p;
-
-   return &p->job;
-}
diff --git a/src/job.h b/src/job.h
deleted file mode 100644 (file)
index 28a4673..0000000
--- a/src/job.h
+++ /dev/null
@@ -1,13 +0,0 @@
-struct job {
-   pid_t id;
-   struct termios config;
-   int suspended;
-};
-
-void initjobs(void);
-struct job *pushjob(struct job *job);
-struct job *pulljob(void);
-struct job *peekjob(void);
-struct job *peeksuspendedjob(void);
-struct job *searchjobid(pid_t id);
-struct job *deletejobid(pid_t id);
index 2ef49b4503cb782d81a83e153f64b39b2ea81ceb..65e13086c58a400292dbc08c1b1e045cd0e57469 100644 (file)
 #include "utils.h"
 
 int parse(struct context *c) {
-   int globbing, e, offset;
+   int globbing, e, offset, globflags;
+   size_t prevsublen, sublen;
    char *stlend, *p, *end, *env, term, **sub;
    long l;
-   size_t sublen;
    static glob_t globs;
 
    if (!c->b) {
@@ -29,7 +29,7 @@ int parse(struct context *c) {
    c->r = c->redirects;
    c->r->mode = NONE;
    c->prev = c->current;
-   globbing = 0;
+   prevsublen = globbing = 0;
 
    for (*c->t = c->b; *c->b; ++c->b) switch (*c->b) {
    case '<':
@@ -164,15 +164,18 @@ int parse(struct context *c) {
            *c->t = c->b;
        } else if (!c->alias && c->t == c->tokens && (sub = getalias(*c->tokens)) || globbing) {
            if (globbing) {
-               switch (glob(*c->t, GLOB_APPEND | GLOB_MARK, NULL, &globs)) {
+               globflags = GLOB_MARK;
+               if (prevsublen) 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");
                }
-               sublen = globs.gl_matchc;
-               sub = globs.gl_pathv + globs.gl_pathc - sublen;
+               sublen = globs.gl_pathc - prevsublen;
+               sub = globs.gl_pathv + prevsublen;
+               prevsublen = globs.gl_pathc;
                globbing = 0;
            } else for (sublen = 0; sub[sublen]; ++sublen);
 
index 6fa314c60b163fbd1522bb0a68766b89e436474b..a3675117bb832bcd0718ee7bf305c7c12478f89d 100644 (file)
--- a/src/run.c
+++ b/src/run.c
@@ -7,10 +7,11 @@
 #include <sys/wait.h>
 #include <termios.h>
 #include <unistd.h>
+#include <stdio.h> // XXX
 
 #include "builtin.h"
 #include "context.h"
-#include "job.h"
+#include "bg.h"
 #include "fg.h"
 #include "parse.h"
 #include "utils.h"
@@ -73,17 +74,23 @@ int run(struct context *c) {
    int islist, ispipe, ispipestart, ispipeend;
    char *path;
    pid_t cpid, jobid;
-   struct job *p, job;
+   static pid_t pipeid;
 
-   setsigchld(&sigchld);
+   setsigchld(&actbg);
    if (!parse(c)) return 0;
-   setsigchld(&sigdfl);
-
+   setsigchld(&actdefault);
    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);
+           return quit(c);
+       }
        if (!(path = getpath(c->current.name))) {
            note("Couldn't find `%s' command", c->current.name);
-           if (c->prev.term == PIPE) closepipe(c->prev);
+           if (c->prev.term == PIPE) {
+               killpg(pipeid, SIGKILL);
+           }
            return quit(c);
        }
 
@@ -97,7 +104,7 @@ int run(struct context *c) {
                if (!ispipestart) closepipe(c->prev);
                return quit(c);
            }
-           if ((jobid = cpid = fork()) == -1) {
+           if ((cpid = fork()) == -1) {
                note("Unable to fork child process");
                return quit(c);
            } else if (cpid == 0) {
@@ -113,15 +120,8 @@ int run(struct context *c) {
                }
                exec(path, c);
            }
-           if (!ispipestart) {
-               closepipe(c->prev);
-               if (!(p = (ispipeend ? pulljob : peekjob)())) {
-                   note("Unable to %s pipeline job from background",
-                        ispipeend ? "remove" : "get");
-                   return quit(c);
-               }
-               jobid = p->id;
-           }
+           if (ispipestart) pipeid = cpid;
+           jobid = pipeid;
        } else if (!c->r && isbuiltin(c->tokens)) cpid = 0;
        else if ((jobid = cpid = fork()) == -1) {
            note("Unable to fork child process");
@@ -137,16 +137,11 @@ int run(struct context *c) {
                }
                return quit(c);
            }
-           job = (struct job){.id = jobid, .config = canonical};
            if (ispipestart || c->current.term == BG) {
-               if (!pushjob(&job)) {
-                   if (ispipestart) closepipe(c->current);
-                   return quit(c);
-               }
-           } else if (c->current.term != PIPE) {
-               if (!setfg(job)) return quit(c);
-               waitfg(job);
+               pushid(jobid);
+               return 1;
            }
+           if (c->current.term != PIPE && !runfg(jobid)) return quit(c);
        }
 
        if (status != EXIT_SUCCESS) {
@@ -155,11 +150,11 @@ int run(struct context *c) {
        } else if (c->current.term == OR) return clear(c);
    } else {
        if (islist) {
-           if (c->prev.term == PIPE) closepipe(c->prev);
+           if (c->prev.term == PIPE) killpg(pipeid, SIGKILL);
            note("Expected command");
            return quit(c);
        }
-       if (c->r) return 1;
+       if (!c->r) return 1;
 
        if ((cpid = fork()) == -1) {
            note("Unable to fork child process");
index e0ff12acd198257612f00e0f08d3ce5da5ceb864..d02330e5aa34dd94d9f36e7b2ad5af4789a77aed 100644 (file)
@@ -8,10 +8,10 @@
 #include <termios.h>
 #include <unistd.h>
 
+#include "bg.h"
 #include "context.h"
-#include "history.h"
-#include "job.h"
 #include "fg.h"
+#include "history.h"
 #include "options.h"
 
 int argcount, status;
@@ -22,7 +22,6 @@ void note(char *fmt, ...) {
    va_start(args, fmt);
    (errno ? vwarn : vwarnx)(fmt, args);
    va_end(args);
-   putc('\r', stderr);
    errno = 0;
 }
 
@@ -31,7 +30,6 @@ void fatal(char *fmt, ...) {
    va_start(args, fmt);
    (errno ? vwarn : vwarnx)(fmt, args);
    va_end(args);
-   putc('\r', stderr);
    exit(EXIT_FAILURE);
 }
 
@@ -62,7 +60,7 @@ void init(void) {
        note("Unable to update $SHLVL$ environment variable");
 
    initfg();
-   initjobs();
+   initbg();
    if (interactive) inithistory();
 }
 
@@ -84,5 +82,6 @@ char *catpath(char *dir, char *filename, char *buffer) {
 
 void deinit(void) {
    if (interactive) deinithistory();
+   deinitbg();
    deinitfg();
 }