Pastie now auto-senses if line-wrap is a bad or good idea. Feedback?
## mark a section (Learn more)
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> /* The array below will hold the arguments: args[0] is the command. */ static char* args[512]; /* Modify this function to run commands. * 'first' and 'last' are useful when connecting pipes. * * input: return value from previous command (useful for pipe file descriptor) * first: 1 if first command in pipe-sequence (no input from previous pipe) * last: 1 if last command in pipe-sequence (no input from previous pipe) * * EXAMPLE: If you type "ls | grep shell | wc" in your shell: * fd1 = command(0, 1, 0), with args[0] = "ls" * fd2 = command(fd1, 0, 0), with args[0] = "grep" and args[1] = "shell" * fd3 = command(fd2, 0, 1), with args[0] = "wc" * * So if 'command' returns a file descriptor, the next 'command' has this * descriptor as its 'input'. */ static int command(int input, int first, int last) { /* Be careful when using 'fork': make sure the child terminates (call 'exit' if 'execvp' fails). */ int i, commands = 0; pid_t pid; char *env[] = { "HOME=/usr/home/", "LOGNAME=home", (char *)0 }; char loc[35] = ""; int pd[2]; /* Initialize the pipe */ if(last == 0) { fprintf(stderr,"Pipe created.\n"); if(pipe(pd) < 0) { perror("Creating pipe"); exit(EXIT_FAILURE); } } pid = fork(); if(pid == 0) { /* Child */ /* Redirection and closing of pipes */ if(first == 1 && last == 0) { dup2(pd[1],1); close(pd[1]); } else if(first == 0 && last == 1) { dup2(input,0); close(input); close(pd[0]); close(pd[1]); } else if(first == 0 && last == 0) { dup2(pd[1],1); close(pd[1]); dup2(input,0); close(input); } /* Construct the command */ strcat(loc,"/bin/"); strcat(loc,args[0]); fprintf(stderr,"command: %s\n", args[0]); for (i = 1; args[i] != NULL; i++) { commands++; fprintf(stderr,"argument %d: %s\n", i, args[i]); } char *cmd[commands+1]; for(i = 0; args[i] != NULL; i++) { cmd[i] = args[i]; } cmd[commands+1] = (char *)0; /* Call the constructed command */ execve(loc, cmd, env); exit(EXIT_SUCCESS); } else { /* Parent */ wait(NULL); /* IF one single command, return 0 */ if(first == 1 && last == 1) { return 0; } close(pd[1]); if(last == 1) { close(input); close(pd[0]); return 0; } } return pd[0]; } /* Here you can do some final cleanup, such as 'wait' for * processes to terminate. * * n : Number of times 'command' was invoked. */ static void cleanup(int n) { /* something like this, perhaps: */ int i; for(i = 0; i < n; i++) wait(NULL); } /* * NOTHING need to be changed below here... */ static int run(char* cmd, int input, int first, int last); static char line[1024]; static int n = 0; /* number of calls to 'command' */ int main() { printf("SIMPLE SHELL: Type 'exit' or send EOF to exit.\n"); while (1) { /* Print the command prompt */ printf("$> "); fflush(NULL); /* Read a command line */ if (!fgets(line, 1024, stdin)) return 0; int input = 0; int first = 1; char* cmd = line; char* next = strchr(cmd, '|'); /* Find first '|' */ while (next != NULL) { /* 'next' points to '|' */ *next = '\0'; input = run(cmd, input, first, 0); cmd = next + 1; next = strchr(cmd, '|'); /* Find next '|' */ first = 0; } input = run(cmd, input, first, 1); cleanup(n); n = 0; } return 0; } static void split(char* cmd); static int run(char* cmd, int input, int first, int last) { split(cmd); if (args[0] != NULL) { if (strcmp(args[0], "exit") == 0) exit(0); n += 1; return command(input, first, last); } return 0; } static char* skipwhite(char* s) { while (isspace(*s)) ++s; return s; } static void split(char* cmd) { cmd = skipwhite(cmd); char* next = strchr(cmd, ' '); int i = 0; while(next != NULL) { next[0] = '\0'; args[i] = cmd; ++i; cmd = skipwhite(next + 1); next = strchr(cmd, ' '); } if (cmd[0] != '\0') { args[i] = cmd; next = strchr(cmd, '\n'); next[0] = '\0'; ++i; } args[i] = NULL; }
This paste will be private.
From the Design Piracy series on my blog: