#include #include #include #include #include #include #include #define PROMPT "msh> " #define EXIT_CMD "exit" #define MAX_BUF 121 // Statuses from builtin responses #define RESP_HELP 1 #define RESP_DATE 2 #define RESP_ECHO 3 #define RESP_SHELL 4 #define RESP_CD_FAIL -1 #define RESP_CD_SUCCESS 6 // Sub statuses that are generally nice to have #define CD_NOP 0x1 void echo(const char*); void remove_newline(char*); void exit_branch(const char*); int builtin_response(char*); int cd_handler(char**, const int); int main(int argc, char** argv) { FILE* file = NULL; if(argc == 2) { file = fopen(argv[1], "r"); if(!file) { return 1; } } char buffer[MAX_BUF]; while(1) { // determine if we're reading from stdin or a stream of some sort if(file == NULL && isatty(STDIN_FILENO)) { printf("%s", PROMPT); fgets(buffer, MAX_BUF, stdin); } else { fgets(buffer, MAX_BUF, file); printf("buffer: %s\n", buffer); } // Deal with EOF input if(!strlen(buffer)) { exit(0); } exit_branch(buffer); remove_newline(buffer); int status = builtin_response(buffer); // the switch in case we need to add more response flags later switch(status) { case RESP_ECHO: echo(buffer); case RESP_SHELL: // shell command handler was used continue; case RESP_CD_FAIL: printf("msh: cd: No such file or directory\n"); } memset(buffer, 0x00, MAX_BUF); // reset buffer after each usage } return 0; } void echo(const char* buf) { printf("%s\n", buf); } void remove_newline(char* buf) { char* c = buf; while(*c != '\n') { c++; } *c='\0'; } void exit_branch(const char* buf) { if(!strcmp(buf, EXIT_CMD)) { exit(0); } } int builtin_response(char* buffer) { #define STRING_DELIMITER " " #define TIME_FMT "%D" exit_branch(buffer); // exit is builtin so here we are if(!strcmp(buffer, "help")) { echo("enter Linux commands, or ‘exit’ to exit"); return RESP_HELP; } // Printout the date today if(!strcmp(buffer, "date")) { static char date[64]; time_t now = time(0); strftime(date, sizeof(date), TIME_FMT, localtime(&now)); echo(date); return RESP_DATE; } // Populate tokens char *tokens[64]; int idx = 0; for(char* cur = strtok(buffer, STRING_DELIMITER); cur != NULL; cur=strtok(NULL, STRING_DELIMITER)) { #ifdef DBG_LINE printf("%s ", cur); #endif tokens[idx] = cur; idx++; } // Handling director changes int cd_result = cd_handler(tokens, idx); if(cd_result != CD_NOP) { return cd_result; } // Execute child process pid_t child = fork(); if(child != 0) { int status_child = wait(NULL); if(status_child == 127) { printf("msh: %s: %d", tokens[0], status_child); } } else { execvp(tokens[0], tokens); } // Cleanup pointers for(int i = 0; i< 64; i++) { tokens[i] = NULL; } } int cd_handler(char** tokens, const int t_count) { if(!strcmp(tokens[0], "cd")) { if(t_count < 2) { int ret = chdir(getenv("HOME")); return ret; } return chdir(tokens[1]); } return CD_NOP; }