#include #include #include // for exit() #include #include #include #include #define MAX_LINE 80 #define PROMPT "-> " void setup_sig_suspend(void); #define HISTORY_SIZE 10 int lock; /* I would have used a circular array but there were time concerns */ char history[MAX_LINE][HISTORY_SIZE]; int itm_cnt; void push_back_history(void) { int i; for (i =1; i < itm_cnt; ++i) strcpy(history[i-1], history[i]); } void add_to_history(char *buf) { if (itm_cnt < HISTORY_SIZE) strcpy(history[itm_cnt++], buf); else { push_back_history(); strcpy(history[itm_cnt], buf); } } int shlock; void show_history(void) { if (shlock) return; shlock++; int i; for (i = 0; i < itm_cnt; ++i) printf("(%d) %s%s", i, history[i], /* Print \n only for lines not with it already. */ (last_char(history[i]) == '\n'? "" : "\n")); shlock = 0; } /** setup() reads in the next command line, separating it into distinct tokens using whitespace as delimiters. setup() modifies the args parameter so that it holds pointers to the null-terminated strings that are the tokens in the most recent user command line as well as a NULL pointer, indicating the end of the argument list, which comes after the string pointers that have been assigned to args. */ void setup(char inputBuffer[], char *args[], int *background) { int length = 0, /* # of characters in the command line */ i, /* loop index for accessing inputBuffer array */ start, /* index where beginning of next command parameter is */ ct; /* index of where to place the next parameter into args[] */ ct = 0; int alreadyInList = 0; int itor; /* read what the user enters on the command line */ /*while (length <= 0) { */ length = read(STDIN_FILENO, inputBuffer, MAX_LINE); start = -1; if (length == 0) { exit(0); /* ^d was entered, end of user command stream */ } else if (length < 0) { perror("error reading the command"); exit(-1); /* terminate with error code of -1 */ } /*} */ /* examine every character in the inputBuffer */ for (i = 0; i < length; i++) { switch (inputBuffer[i]) { case ' ': case '\t': /* argument separators */ if (start != -1) { args[ct] = &inputBuffer[start]; /* set up pointer */ ct++; } inputBuffer[i] = '\0'; /* add a null char; make a C string */ start = -1; break; case '\n': /* should be the final char examined */ if (start != -1) { args[ct] = &inputBuffer[start]; ct++; } inputBuffer[i] = '\0'; args[ct] = NULL; /* no more arguments to this command */ break; default: /* some other character */ if (inputBuffer[i] == '&') { /*printf("Running in bg\n"); fflush(stdin); */ *background = 1; inputBuffer[i] = '\0'; } else if (start == -1) start = i; } } args[ct] = NULL; /* just in case the input line was > 80 */ add_to_history(inputBuffer); } /* Signal handler for ^Z */ void sig_suspend(int sig) { int j; int rNum = HISTORY_SIZE + 2; if (lock) return; lock = 1; printf("\nCommand History:\n"); show_history(); fflush(stdout); printf("Select by number. > "); while (rNum < 0 || rNum > HISTORY_SIZE) { scanf("%d", &rNum); } printf("You pressed %d.\n", rNum); printf(PROMPT); fflush(stdout); lock = 0; setup_sig_suspend(); } void setup_sig_suspend(void) { signal(SIGTSTP, sig_suspend); /*struct sigaction new_action; new_action.sa_handler = sig_suspend; sigemptyset(&new_action.sa_mask); new_action.sa_flags = SA_RESTART; sigaction(SIGTSTP, &new_action, NULL);*/ } void unsetup_sig_suspend(void) { signal(SIGTSTP, SIG_DFL); } int main(void) { int i; lock = 0; shlock = 0; char inputBuffer[MAX_LINE]; /* buffer to hold command entered */ int background; /* equals 1 if a command is followed by '&' */ char *args[MAX_LINE / 2 + 1]; /* command line arguments */ pid_t pid; itm_cnt = 0; setup_sig_suspend(); //bsd_signal(SIGTSTP, sig_suspend); while (1) { background = 0; printf(PROMPT); fflush(stdout); /* setup() calls exit() when Control-D is entered */ setup(inputBuffer, args, &background); /** the steps are: (1) fork a child process using fork() (2) the child process will invoke execvp() (3) if background == 1, the parent will wait, otherwise it will invoke the setup() function again. */ /* fork a child process */ pid = fork(); unsetup_sig_suspend(); if (pid < 0) { /* error occurred */ fprintf(stderr, "Fork Failed"); exit(-1); } else if (pid == 0) { /* child process */ execvp(args[0], args); /* parent */ } else { setup_sig_suspend(); /*printf("%d^", background); */ /*for (i=0;args[i]!=NULL;++i) printf("'%s'\n",args[i]); */ if (!background) { wait(NULL); } else { printf("[%d]\n", pid); fflush(stdout); sleep(0.7); } } } }