static int read_debug_line(const char **outbuffer, void *cookie) { int pos = 0; int escape_level = 0; #if CONSOLE_ENABLE_HISTORY uint history_cursor = start_history_cursor(); #endif char *buffer = debug_buffer; for (;;) { /* loop until we get a char */ int c; if ((c = getchar()) < 0) continue; // TRACEF("c = 0x%hhx\n", c); if (escape_level == 0) { switch (c) { case '\r': case '\n': if (echo) putchar('\n'); goto done; case 0x7f: // backspace or delete case 0x8: if (pos > 0) { pos--; fputc('\b', stdout); putchar(' '); fputc('\b', stdout); // move to the left one } break; case 0x1b: // escape escape_level++; break; default: buffer[pos++] = c; if (echo) putchar(c); } } else if (escape_level == 1) { // inside an escape, look for '[' if (c == '[') { escape_level++; } else { // we didn't get it, abort escape_level = 0; } } else { // escape_level > 1 switch (c) { case 67: // right arrow buffer[pos++] = ' '; if (echo) putchar(' '); break; case 68: // left arrow if (pos > 0) { pos--; if (echo) { fputc('\b', stdout); // move to the left one putchar(' '); fputc('\b', stdout); // move to the left one } } break; #if CONSOLE_ENABLE_HISTORY case 65: // up arrow -- previous history case 66: // down arrow -- next history // wipe out the current line while (pos > 0) { pos--; if (echo) { fputc('\b', stdout); // move to the left one putchar(' '); fputc('\b', stdout); // move to the left one } } if (c == 65) strlcpy(buffer, prev_history(&history_cursor), LINE_LEN); else strlcpy(buffer, next_history(&history_cursor), LINE_LEN); pos = strlen(buffer); if (echo) fputs(buffer, stdout); break; #endif default: break; } escape_level = 0; } /* end of line. */ if (pos == (LINE_LEN - 1)) { fputs("\nerror: line too long\n", stdout); pos = 0; goto done; } } done: // dprintf("returning pos %d\n", pos); // null terminate buffer[pos] = 0; #if CONSOLE_ENABLE_HISTORY // add to history add_history(buffer); #endif // return a pointer to our buffer *outbuffer = buffer; return pos; }
int main(int argc, char *argv[], char *envp[]) { read_config(); //read the config file char c; //reading one letter at time here //building a command line which will eventually get parsed line = (char *)malloc(sizeof(char) * 100); memset(line,0,100); char *cmd = (char *)malloc(sizeof(char) * 100); //the program (command w/o args) char *printBuff = (char *)malloc(sizeof(char)*100); //a printing buffer (for use with raw tty) //holder for history if stuff is typed, then history is used to go back to typed stuff char *historyHold = (char *)malloc(sizeof(char)*100); path = (char*)malloc(sizeof(char)*100); fullPath = (char*)malloc(sizeof(char)*100); memset(printBuff,0,100); memset(historyHold,0,100); memset(cmd,0,100); signal(SIGINT, handle_sig); //register interrupt signal (for CTRL+C) int promptLen; //making sure we dont backspace the prompt int fromHistory = 0; //a type of check to see if our line is from history (not user typed) if(fork() == 0) { execve("/usr/bin/clear", argv, envp); //simply clear the screen exit(1); } else { wait(NULL); //wait to clear screen } get_path(); //gets the 2dir path for prompt tty_raw_mode();//set terminal into raw mode sprintf(printBuff,"%s:%s",path,PROMPT); //build print buff promptLen = strlen(printBuff); curPos = promptLen; //leave a space write(1,printBuff,promptLen); //print initial prompt memset(printBuff,0,100); //clear printBuff clear_args(); //just get any initial crap out /* MAIN LOOP */ while(1) { read(0,&c,1); //read 1 character from stdin if(((c >= 32) && c!=127) || c == 10) { //here, we only want to process characters that are //"readable" (or enter). special characters will be //handled differently tabPressNo = 0; //they didnt press tab write(1,&c,1); //write char (echo is off for raw mode) ++curPos; switch(c) { case '\n': //end of the line (enter was pressed after input) if(line[0] == '\0') { //they didnt type anything sprintf(printBuff,"%s:%s",path,PROMPT); write(1,printBuff,promptLen); } else if(strcmp(line,"exit")==0) { printf("\n"); //for niceness quit_raw_mode(); //play nice and restore term state return 0; //quit if they type "exit" } else { //prepare to actually process strncat(line,"\0",1); if(line[0] != '!') { add_history(line); //add command to history } int pipe = 0; int separ = check_separ(line); if(!separ){ pipe = check_pipe(line); } if(!separ && !pipe){ //try to execute the command if there werent pipes or semicolons parse_args(line); //build array of arguments strcpy(cmd, args[0]); //cmd = program to run execute(cmd); clear_args(); //resets all arg array strings } c = '\0'; memset(cmd, 0, 100); //clear the cmd array //reprint prompt sprintf(printBuff,"%s:%s",path,PROMPT); promptLen = strlen(printBuff); curPos = promptLen; write(1,printBuff,promptLen); } memset(line,0,100); //clear line array memset(historyHold,0,100);//clear history hold break; default: strncat(line, &c, 1);//build the line break; } } else if(c == 8) { //backspace pressed if(curPos > promptLen) { backspace(); //backspace until we reach prompt line[strlen(line)-1] = 0; //thank god this finally works --curPos; } } else if(c == 27) { //the user pressed some sort of //escape sequence char c1; char c2; read(0,&c1,1); read(0,&c2,1); //ok, we have the two parts of the //escape sequence in c1 and c2 if(c1 == 91 && c2 == 65) { //this is the escape for the up arrow //which we want to use for history //browsing char *tmpLine; tmpLine = prev_history(); if(tmpLine != 0) { if(line[0] != '\0' && fromHistory==0) { //store what user currently has typed (if anything) memset(historyHold,0,100); strncpy(historyHold,line,strlen(line)); } clear_line(strlen(line)); //clears whatever is at the prompt memset(line,0,100); strncpy(line,tmpLine,strlen(tmpLine)); //copy this command free(tmpLine); //play nice write(1,line,strlen(line)); //write old command fromHistory = 1; //current line has been replaced by history curPos = strlen(line) + promptLen; //so we know where are } } else if(c1 == 91 && c2 == 66) { //this is the escape for the down arrow //which should make us go "forward" //in history (if we are back in it) char *tmpLine; tmpLine = next_history(); //get the next history if(tmpLine != 0) { //next_history gave us a line clear_line(strlen(line)); //clear old line from screen memset(line,0,100); //clear old line in mem strncpy(line,tmpLine,strlen(tmpLine)); //copy new line to old line write(1,line,strlen(line)); //write new line to screen curPos = strlen(line) + promptLen; //update pos free(tmpLine); } else if(historyHold[0] != '\0') { //if we dont have a next_line, lets see if //we had some buffer before browsing history clear_line(strlen(line)); memset(line,0,100); strncpy(line,historyHold,strlen(historyHold)); write(1,line,strlen(line)); curPos = strlen(line) +promptLen; fromHistory = 0; //back to user typed } else { //it was blank before history was browsed clear_line(strlen(line)); memset(line,0,100); curPos = promptLen; } } } else if(c == '\t') { //tab press. should i dare try to do tab //completion? i guess... //if this is the 2nd time in a row pressing tab //they want a listing of everything that can be //completed if(tabPressNo) { //print everything in tabHold tabPressNo = 0; if(tabCompHold[0] != NULL) { int i = 1; char *x = tabCompHold[0]; char *tmp = (char*)malloc(sizeof(char)*100); memset(tmp,0,100); write(1,"\n",1); while(x != NULL) { sprintf(tmp,"%s\t",x); write(1,tmp,strlen(tmp)); memset(tmp,0,100); x = tabCompHold[i]; ++i; } write(1,"\n",1); //reprint prompt sprintf(printBuff,"%s:%s",path,PROMPT); promptLen = strlen(printBuff); curPos = promptLen + strlen(line); write(1,printBuff,promptLen); //write the line again write(1,line,strlen(line)); clear_tab_hold(); } } else { //otherwise just let tab_complete //print a single completion char *tabcomp; tabcomp = tab_complete(line); if(tabcomp != NULL) { //tab comp found a single thing, so //lets just complete it int i = 1; char c = tabcomp[0]; while(c!='\0') { write(1,&c,1); strncat(line,&c,1); c = tabcomp[i]; ++i; } curPos += strlen(tabcomp); //set our new position free(tabcomp); } ++tabPressNo; } } else if(c == '\177') { //other form of backspace if(curPos > promptLen) { backspace(); //backspace until we reach prompt line[strlen(line)-1] = 0; //thank god this finally works --curPos; } } memset(printBuff,0,100); //clear printing buffer } printf("\n"); //for niceness quit_raw_mode(); //so we dont get stuck in it return 0; //goodbye }