]> Trent Huber's Code - thus.git/commitdiff
File redirection implementation complete
authorTrent Huber <trentmhuber@gmail.com>
Thu, 3 Jul 2025 06:32:22 +0000 (02:32 -0400)
committerTrent Huber <trentmhuber@gmail.com>
Thu, 3 Jul 2025 06:32:22 +0000 (02:32 -0400)
src/lex.c
src/lex.h
src/main.c

index 642e2c8213ce1b4390a3665cfca432bbe97d84c8..0def809b38d7fdfb2a8a52d707e3ac4e3bc08075 100644 (file)
--- a/src/lex.c
+++ b/src/lex.c
@@ -2,18 +2,21 @@
 #include <stddef.h>
 #include <stdlib.h>
 #include <err.h>
+#include <limits.h>
 #include <stdio.h> // DEBUG
 
 #include "history.h"
 #include "lex.h"
 
 static char *tokens[1 + BUFLEN + 1];
-static struct cmd cmds[1 + (BUFLEN + 1) / 2 + 1] = {{.args = tokens, .f = cmds->freds}};
+static struct cmd cmds[1 + (BUFLEN + 1) / 2 + 1] = {{.args = tokens}};
 
 void printfreds(struct cmd *c) {
-   for (; c->f->mode != END; ++c->f) {
-       printf("%d", c->f->newfd);
-       switch (c->f->mode) {
+   struct fred *f;
+
+   for (f = c->freds; f->mode != END; ++f) {
+       printf("%d ", f->newfd);
+       switch (f->mode) {
        case READ:
            fputs("<", stdout);
            break;
@@ -28,13 +31,23 @@ void printfreds(struct cmd *c) {
            break;
        default:;
        }
-       puts(c->f->old.name);
+       switch (f->type) {
+       case FD:
+           printf(" #%d\n", f->old.fd);
+           break;
+       case NAME:
+           printf(" %s\n", f->old.name);
+           break;
+       default:;
+       }
    }
 }
 
 struct cmd *lex(char *b) {
    char **t, *end;
    struct cmd *c;
+   struct fred *f;
+   long test;
    
    if (!b) return NULL;
    t = tokens;
@@ -47,22 +60,29 @@ struct cmd *lex(char *b) {
        }
        ++b;
        break;
+   case ' ':
+       *b++ = '\0';
+       break;
    case '<':
    case '>':
        if (*(b - 1)) {
-           if ((c->f->newfd = strtol(*--t, &end, 10)) < 0 || end != b) {
+           if ((test = strtol(*--t, &end, 10)) < 0 || test > INT_MAX || end != b) {
                warnx("Invalid file redirection operator");
                c->args = NULL;
                return c - 1;
            }
+           f->newfd = (int)test;
            if (c->args == t) c->args = NULL;
-       } else c->f->newfd = *b == '>';
-       c->f->mode = *b++;
+       } else f->newfd = *b == '>';
+       f->mode = *b++;
        if (*b == '>') {
            ++b;
-           ++c->f->mode;
+           ++f->mode;
        }
-       c->f++->old.name = b;
+       f->old.name = b;
+
+       (++f)->mode = END;
+
        if (*b == '&') ++b;
        break;
    case '&':
@@ -71,29 +91,38 @@ struct cmd *lex(char *b) {
    case ';':
        if (c->args) {
            *t++ = NULL;
-           if (!*b) {
-               ++b;
-               ++c->type;
+           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;
            }
-           c->type += *b;
-           *(c->f) = (struct fred){0};
-           c->f = c->freds;
 
            (++c)->args = NULL;
+       } else {
+           if (!*b) ++b;
+           *b++ = '\0';
        }
-       c->f = c->freds;
-   case ' ':
-       *b++ = '\0';
+       f = c->freds;
+       f->mode = END;
    }
-   switch (c->type) {
+
+   switch ((c - 1)->type) {
    case AND:
    case PIPE:
    case OR:
        warnx("Command left open-ended");
-       c->args = NULL;
        return c - 1;
    default:
-       *++c = (struct cmd){0};
+       *c = (struct cmd){0};
    }
 
    return cmds;
index f3b26fb26649da05071d32e2aa4b1d2fc4f606ed..e80a1d42ea1e05ceed15ae64dd9efeb65ec9dcea 100644 (file)
--- a/src/lex.h
+++ b/src/lex.h
@@ -46,7 +46,7 @@ struct fred {
 struct cmd {
    char **args;
    enum terminator type;
-   struct fred *f, freds[(BUFLEN - 1) / 3 + 1];
+   struct fred freds[(BUFLEN - 1) / 3 + 1];
    int pipe[2];
 };
 
index d0904580e8a74ee56db37b6d6748b868d4f4b073..7080219772d271437e8fc20e8f48c57d780b2182 100644 (file)
@@ -1,11 +1,12 @@
 #include <err.h>
+#include <fcntl.h>
 #include <signal.h>
+#include <stdio.h> // DEBUG
 #include <stdlib.h>
 #include <string.h>
 #include <sys/errno.h>
 #include <termios.h>
 #include <unistd.h>
-#include <stdio.h> // DEBUG
 
 #include "builtins.h"
 #include "stack.h"
@@ -33,6 +34,46 @@ static int closepipe(struct cmd *cmd) {
    return result;
 }
 
+static int redirectfiles(struct fred *f) {
+   int oflag, fd;
+
+   for (; f->mode; ++f) {
+       if (f->type == NAME) {
+           switch (f->mode) {
+           case READ:
+               oflag = O_RDONLY;
+               break;
+           case WRITE:
+               oflag = O_WRONLY | O_CREAT | O_TRUNC;
+               break;
+           case READWRITE:
+               oflag = O_RDWR | O_CREAT | O_APPEND;
+               break;
+           case APPEND:
+               oflag = O_WRONLY | O_CREAT | O_APPEND;
+               break;
+           default:;
+           }
+           if ((fd = open(f->old.name, oflag, 0644)) == -1) {
+               warn("Unable to open `%s'", f->old.name);
+               return 0;
+           }
+           f->old.fd = fd;
+       }
+       if (dup2(f->old.fd, f->newfd) == -1) {
+           warn("Unable to redirect %d to %d", f->newfd, f->old.fd);
+           return 0;
+       }
+       if (f->type == NAME) {
+           if (close(f->old.fd) == -1) {
+               warn("Unable to close file descriptor %d", f->old.fd);
+               return 0;
+           }
+       }
+   }
+   return 1;
+}
+
 int main(void) {
    struct cmd *cmd, *prev;
    int ispipe, ispipestart, ispipeend, status;
@@ -44,7 +85,6 @@ int main(void) {
 
    while ((cmd = lex(input()))) {
        while (prev = cmd++, cmd->args) {
-           printfreds(cmd);
            ispipe = cmd->type == PIPE || prev->type == PIPE;
            ispipestart = ispipe && prev->type != PIPE;
            ispipeend = ispipe && cmd->type != PIPE;
@@ -72,6 +112,7 @@ int main(void) {
                        if (!closepipe(cmd)) exit(EXIT_FAILURE);
                    }
 
+                   if (!redirectfiles(cmd->freds)) 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);
@@ -81,12 +122,16 @@ int main(void) {
                    jobid = ((struct job *)(ispipeend ? pull : peek)(&jobs))->id;
                }
            } else {
-               if (isbuiltin(cmd->args, &status)) break;
+               if (cmd->freds->mode == END && isbuiltin(cmd->args, &status)) break;
                if ((jobid = cpid = fork()) == -1) {
                    warn("Unable to create child process");
                    break;
-               } else if (cpid == 0 && execvp(*cmd->args, cmd->args) == -1)
-                   err(EXIT_FAILURE, "Couldn't find `%s' command", *cmd->args);
+               } else if (cpid == 0) {
+                   if (!redirectfiles(cmd->freds)) 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);
+               }
            }
            if (setpgid(cpid, jobid) == -1) {
                if (errno != ESRCH) {