/* * Stuff to mention next time: * includes and silly stuff * if(' ') is always true * space = 0 for else if case * permissions need to be set (show without doing this) * newline in command line is a problem for execvp, not system * * Next time: * Actually call chdir() * */ #include #include #include #include #include #include #include #include #include #define MAX_CMDLEN 10000 #define HISTORYLEN 100 char *prompt = " $: "; char command[MAX_CMDLEN]; char cwd[1024] = ""; char *history; int hspot = 0; void eat_spaces(char **spot_pointer){ while(*(*spot_pointer) == ' ') (*spot_pointer)++; } int main(){ history = malloc(MAX_CMDLEN * HISTORYLEN); while(1){ // Write the prompt and read a command write(2, cwd, strlen(cwd)); write(2, prompt, strlen(prompt)); size_t cmdlen = read(0, command, MAX_CMDLEN); if(!cmdlen){ write(2, "\n", 1); goto done; } if(cmdlen == 1){ strcpy(command, history + (hspot-1) * MAX_CMDLEN); } else { command[cmdlen] = 0; strcpy(history + hspot * MAX_CMDLEN, command); hspot++; hspot = hspot % HISTORYLEN; } // Check to see if the command requires action by us if(!strncmp("cd ", command, 3)){ char* directory = command+3; while(directory[0] == ' ') directory++; directory[strlen(directory)-1] = 0; if(chdir(directory)) perror(directory); else if(!getcwd(cwd, 1024)) perror("getcwd"); continue; } char quote = 0; char stdout_file[128]; stdout_file[0] = 0; // *spot means the same thing as spot[0] for(char *spot = command; *spot && *spot != '\n'; spot++){ if(*spot == '"') // TODO: What if we're in single quotes instead of double? quote = !quote; if(*spot == '>' && !quote){ char* redirfile; redirfile = spot+1; eat_spaces(&redirfile); char* filename_end = redirfile; while(*filename_end && *filename_end != ' ' && *filename_end != '\n') filename_end++; *filename_end = 0; filename_end[1] = 0; strcpy(stdout_file, redirfile); while(*redirfile){ *redirfile = ' '; redirfile++; } *filename_end = ' '; *spot = ' '; } } pid_t pid = fork(); if(pid){ // We're the parent wait(0); } else { // We're the child // setup redirection char *argv[128]; argv[0] = command; int argv_total = 1; char space = 0; quote = 0; for(char *spot = command; *spot; spot++){ if(*spot == '"') { // TODO: What if we're in single quotes instead of double? if(*(spot-1) == '\\'){ // Then it's an escaped quote! for(char *c = spot; *c; c++) *(c-1) = *c; spot--; } else { quote = !quote; *spot = 0; spot++; } } if((*spot == ' ' || *spot == '\n') && !quote){ space = 1; *spot = 0; } else if(space) { space = 0; argv[argv_total] = spot; argv_total++; } } argv[argv_total] = 0; int stdout_fd = 0; if(stdout_file[0]){ stdout_fd = open(stdout_file, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); dup2(stdout_fd, 1); } // otherwise we don't have to do any redirection execvp(command, argv); perror("execvp"); if(stdout_fd) close(stdout_fd); return 0; } } done: free(history); return 0; }