1 /* $begin shellmain */ 2 #include "csapp.h" 3 #define MAXARGS 128 4 5 /* function prototypes */ 6 void eval(char *cmdline); 7 int parseline(char *buf, char **argv); 8 int builtin_command(char **argv); 9 10 int main() 11 { 12 char cmdline[MAXLINE]; /* Command line */ 13 14 while (1) { 15 /* Read */ 16 printf("> "); 17 Fgets(cmdline, MAXLINE, stdin); 18 if (feof(stdin)) 19 exit(0); 20 21 /* Evaluate */ 22 eval(cmdline); 23 } 24 } 25 /* $end shellmain */ 26 27 /* $begin eval */ 28 /* eval - Evaluate a command line */ 29 void eval(char *cmdline) 30 { 31 char *argv[MAXARGS]; /* Argument list execve() */ 32 char buf[MAXLINE]; /* Holds modified command line */ 33 int bg; /* Should the job run in bg or fg? */ 34 pid_t pid; /* Process id */ 35 36 strcpy(buf, cmdline); 37 bg = parseline(buf, argv); 38 if (argv[0] == NULL) 39 return; /* Ignore empty lines */ 40 41 if (!builtin_command(argv)) { 42 if ((pid = Fork()) == 0) { /* Child runs user job */ 43 if (execve(argv[0], argv, environ) < 0) { 44 printf("%s: Command not found.\n", argv[0]); 45 exit(0); 46 } 47 } 48 49 /* Parent waits for foreground job to terminate */ 50 if (!bg) { 51 int status; 52 if (waitpid(pid, &status, 0) < 0) 53 unix_error("waitfg: waitpid error"); 54 } 55 else 56 printf("%d %s", pid, cmdline); 57 } 58 return; 59 } 60 61 /* If first arg is a builtin command, run it and return true */ 62 int builtin_command(char **argv) 63 { 64 if (!strcmp(argv[0], "quit")) /* quit command */ 65 exit(0); 66 if (!strcmp(argv[0], "&")) /* Ignore singleton & */ 67 return 1; 68 return 0; /* Not a builtin command */ 69 } 70 /* $end eval */ 71 72 /* $begin parseline */ 73 /* parseline - Parse the command line and build the argv array */ 74 int parseline(char *buf, char **argv) 75 { 76 char *delim; /* Points to first space delimiter */ 77 int argc; /* Number of args */ 78 int bg; /* Background job? */ 79 80 buf[strlen(buf)-1] = ' '; /* Replace trailing '\n' with space */ 81 while (*buf && (*buf == ' ')) /* Ignore leading spaces */ 82 buf++; 83 84 /* Build the argv list */ 85 argc = 0; 86 while ((delim = strchr(buf, ' '))) { 87 argv[argc++] = buf; 88 *delim = '\0'; 89 buf = delim + 1; 90 while (*buf && (*buf == ' ')) /* Ignore spaces */ 91 buf++; 92 } 93 argv[argc] = NULL; 94 95 if (argc == 0) /* Ignore blank line */ 96 return 1; 97 98 /* Should the job run in the background? */ 99 if ((bg = (*argv[argc-1] == '&')) != 0) 100 argv[--argc] = NULL; 101 102 return bg; 103 } 104 /* $end parseline */
Calling waitpid from more than one function, not a good idea.
This version doesn't adequately handle children when job control is added.