/* * Input a line with some basic editing. */ char *read_line() { // Set terminal in raw mode tty_raw_mode(); // Initialize the parameters line_length = 0; cursor_position = 0; if (history == NULL) { // whiout the check, up-arrow will give seg fault history = (char **)malloc(HIST_MAX * sizeof(char *)); } // Read one line until enter is typed while (1) { // Read one character in raw mode. char ch; read(0, &ch, 1); // for all printable character. if (ch >= 32 && ch <= 126) { // Do echo write(1, &ch, 1); // If max number of character reached return. if (line_length == MAX_BUFFER_LINE - 2) break; // if in the middle of what typed if (cursor_position != line_length) { char temp; int i; line_length++; //shift the content to the right of cursor for (i = line_length; i > cursor_position; i--) { line_buffer[i] = line_buffer[i - 1]; } //let the content to be written in the buffer be stored line_buffer[cursor_position] = ch; //print the chars to the right of cursor for (i = cursor_position + 1; i < line_length; i++) { ch = line_buffer[i]; write(1, &ch, 1); } //put the cursor back to the right position. ch = 8; for (i = cursor_position + 1; i < line_length; i++) { write(1, &ch, 1); } } else { // at the end, just add char to buffer. line_buffer[line_length] = ch; line_length++; } cursor_position++; } else if (ch == 10) { // <Enter> was typed. Return line // Print newline write(1, &ch, 1); if (history_length == HIST_MAX) { HIST_MAX *= 2; history = (char **)realloc(history, HIST_MAX * sizeof(char *)); } line_buffer[line_length] = 0; if (line_buffer[0] != 0) { history[history_length] = strdup(line_buffer); history_length++; } break; } else if (ch == 1) { // CTRL-A : Move to beginning of line int i; for (i = cursor_position; i > 0; i--) { ch = 8; write(1, &ch, 1); cursor_position--; } } else if (ch == 31) { // ctrl-? read_line_print_usage(); line_buffer[0] = 0; break; } else if ((ch == 8 || ch == 127) && line_length != 0) { // <backspace> was typed. Remove previous character read. // Go back one character ch = 8; write(1, &ch, 1); // Write a space to erase the last character read ch = ' '; write(1, &ch, 1); // Go back one character ch = 8; write(1, &ch, 1); // Remove one character from buffer line_length--; cursor_position--; } else if (ch == 27) { // Escape sequence. Read two chars more // // HINT: Use the program "keyboard-example" to // see the ascii code for the different chars typed. // char ch1; char ch2; read(0, &ch1, 1); read(0, &ch2, 1); // left arrow if (ch1 == 91 && ch2 == 68) { if (cursor_position > 0) { ch = 8; write(1, &ch, 1); cursor_position--; } } // right arrow if (ch1 == 91 && ch2 == 67) { if (cursor_position < line_length) { // char ch = line_buffer[cursor_position]; // write(1, &ch, 1); write(1, &ch, 1); write(1, &ch1, 1); write(1, &ch2, 1); cursor_position++; } } // Up arrow. Print next line in history. if (ch1 == 91 && ch2 == 65 && history_length > 0) { // Erase old line // Print backspaces int i = 0; for (i = 0; i < line_length; i++) { ch = 8; write(1, &ch, 1); } // Print spaces on top for (i = 0; i < line_length; i++) { ch = ' '; write(1, &ch, 1); } // Print backspaces for (i = 0; i < line_length; i++) { ch = 8; write(1, &ch, 1); } // Copy line from history strcpy(line_buffer, history[history_index]); line_length = strlen(line_buffer); history_index = (history_index + 1) % history_length; // echo line write(1, line_buffer, line_length); cursor_position = line_length; } // down arrow, similar to UP if (ch1 == 91 && ch2 == 66) { // down arrow. Print next line in history. // Erase old line // Print backspaces int i = 0; for (i = line_length - cursor_position; i < line_length; i++) { ch = 8; write(1, &ch, 1); } // Print spaces on top for (i = 0; i < line_length; i++) { ch = ' '; write(1, &ch, 1); } // Print backspaces for (i = 0; i < line_length; i++) { ch = 8; write(1, &ch, 1); } if (history_index > 0) { // Copy line from history strcpy(line_buffer, history[history_index]); line_length = strlen(line_buffer); history_index = (history_index - 1) % history_length; // echo line write(1, line_buffer, line_length); cursor_position = line_length; } else { // Copy line from history strcpy(line_buffer, ""); line_length = strlen(line_buffer); // echo line write(1, line_buffer, line_length); cursor_position = line_length; } } } } // Add eol and null char at the end of string line_buffer[line_length] = 10; line_length++; line_buffer[line_length] = 0; return line_buffer; }
/* * Input a line with some basic editing. */ char * read_line() { // save terminal settings struct termios orig_attr; tcgetattr(0, &orig_attr); // Set terminal in raw mode tty_raw_mode(); line_length = 0; line_pos = 0; // reset the line buffer int t = 0; for (t = 0; t < MAX_BUFFER_LINE; t++) { line_buffer[t] = '\0'; } // Read one line until enter is typed while (1) { // init history if necessary if (history == NULL) { init_hist(); } // Read one character in raw mode. char ch; read(0, &ch, 1); if (ch>=32 && ch < 127) { // It is a printable character. if (line_pos == line_length) { // we're at the end of the line // Do echo write(1,&ch,1); // If max number of character reached return. if (line_length==MAX_BUFFER_LINE-2) break; // add char to buffer. line_buffer[line_pos]=ch; line_length++; line_pos++; } else { // in the middle of the line somewhere char * temp = (char*)malloc(MAX_BUFFER_LINE * sizeof(char)); int i; // copy all the characters after where we're at for ( i = 0; i < MAX_BUFFER_LINE; i++) { if (line_buffer[line_pos + i] == '\0' ) { // if we see the null char, we've gotten it all break; } temp[i] = line_buffer[line_pos + i]; } // write the character we want to add write (1, &ch, 1); // If max number of character reached return. if (line_length==MAX_BUFFER_LINE-2) break; // add char to buffer. line_buffer[line_pos]=ch; line_length++; line_pos++; // print all the rest of the characters afterwards int chars_added = 0; for (i = 0; i < MAX_BUFFER_LINE; i++) { chars_added+=1; write(1, &temp[i], 1); if (line_buffer[line_pos + i] == '\0' ) { // if we see the null char, we've gotten it all break; } } // go back to where we were backspace(chars_added); } } else if (ch==10) { // <Enter> was typed. Return line // add line to history linked list if it's not empty if ( strlen(line_buffer) != 0 ) { add_hist_line(line_buffer); } // Print newline write(1,&ch,1); break; } else if (ch == 31) { // ctrl-? read_line_print_usage(); line_buffer[0]=0; break; } else if (ch == 127) { // <backspace> was typed. Remove previous character read. // don't do anything if we're already at the beginning if (line_pos <= 0) { continue; } // Go back one character backspace(1); // Write a space to erase the last character read ch = ' '; write(1,&ch,1); // Go back one character backspace(1); // Remove one character from buffer line_buffer[ line_pos ] = '\0'; line_length--; line_pos--; } else if (ch==27) { // Escape sequence. Read two chars more // // HINT: Use the program "keyboard-example" to // see the ascii code for the different chars typed. // char ch1; char ch2; read(0, &ch1, 1); read(0, &ch2, 1); if (ch1==91 && ch2==65) { // Up arrow. Print next line in history. // Erase old line // Print backspaces int i = 0; for (i =0; i < line_length; i++) { ch = 8; write(1,&ch,1); } // Print spaces on top for (i =0; i < line_length; i++) { ch = ' '; write(1,&ch,1); } // Print backspaces for (i =0; i < line_length; i++) { ch = 8; write(1,&ch,1); } // if history is uninitialized, do nothing // Copy line from history history_index -= 1; if (history_index <= 0) { // loop back to the most recent command history_index = history_length - 1; } if (history[history_index] == NULL) { const char * empty = ""; strcpy(line_buffer, empty); } else { strcpy(line_buffer, history[history_index]); } line_length = strlen(line_buffer); // echo line write(1, line_buffer, line_length); } else if (ch1 == 91 && ch2 == 66) { // down arrow. print previous line in history // Erase old line // Print backspaces backspace( line_length ); // Print spaces on top int i = 0; for (i =0; i < line_length; i++) { ch = ' '; write(1,&ch,1); } // Print backspaces backspace( line_length ); // increment index accordingly if (history_index <= 0) { // stay at 0 history_index = 0; } else { history_index += 1; if (history_index >= history_length ) { history_index = 0; } } // Copy line from history if (history[history_index] == NULL) { const char * empty = ""; strcpy(line_buffer, empty); } else { strcpy(line_buffer, history[history_index]); } line_length = strlen(line_buffer); // echo line write(1, line_buffer, line_length); } else if (ch1 == 91 && ch2 == 68) { // left arrow if (line_pos > 0) { line_pos--; backspace(1); } } else if (ch1 == 91 && ch2 == 67) { // right arrow if (line_pos < line_length) { // grab current char char c = line_buffer[line_pos]; // print grabbed char write( 1, &c, 1); line_pos++; } } } } // Add eol and null char at the end of string line_buffer[line_length]=10; line_length++; line_buffer[line_length]=0; // set the terminal back to orig settings tcsetattr(0, TCSANOW, &orig_attr); return line_buffer; }
char * read_line() { int itr; if(debug_mode) for(itr = history_index; itr > 0; itr--) fprintf(stderr, "\nhistory[%d]=%s", itr, history[itr]); // Set terminal in raw mode tty_raw_mode(); line_length = 0; while (1) { // Read one character in raw mode. char ch; read(0, &ch, 1); if (ch>=32 && ch != ESC && ch < 127 ) { // It is a printable character. display it back write(1,&ch,1); // If max number of character reached return. if (line_length==MAX_BUFFER_LINE-2) break; // add char to buffer. line_buffer[line_length]=ch; line_length++; position++; } else if (ch==10) { // <Enter> was typed. Return line. add current line to history if(line_length > 0) { history[history_index] = strdup(line_buffer); if(history_index == 29) history_index = 0; else history_index++; if(debug_mode) for(itr = 0; itr < history_index; itr++) fprintf(stderr, "\nhistory[%d]=%s\n", itr, history[itr]); } write(1,&ch,1); break; } else if (ch == 31) { // ctrl-? read_line_print_usage(); line_buffer[0]=0; break; } else if (ch == BACKSPACE || ch==127) { if(line_length>0 && position> 0) { // <backspace> or ctrl-H was typed. Remove previous character read. // Go back one character if(position == line_length) { ch = BACKSPACE; write(1,&ch,1); // Write a space to erase the last character read ch = ' '; write(1,&ch,1); // Go back one character ch = BACKSPACE; write(1,&ch,1); // Remove one character from buffer line_length--; position--; } else delete_and_shift(1); } } else if(ch == 4) { /* ctrl-D: Removes the character at the cursor. The characters in the right side are shifted to the left. */ delete_and_shift(0); } else if(ch == 1) { /*Home key (or ctrl-A): The cursor moves to the beginning of the line */ if(position != 0 && position < line_length+1 && position > 0) { while(position != 0 ) { ch = BACKSPACE; write(1, &ch, 1); position--; } } } else if(ch == 12) { /* Clear line (or ctrl-l): clear current line */ clear_line(); } else if(ch==5) { /*End key (or ctrl-E): The cursor moves to the end of the line */ if( position < line_length && position >= 0) { while(position != line_length ) { ch = line_buffer[position]; write(1, &ch, 1); position++; } } } else if (ch==ESC) // Esc. Read two chars more { char ch1; char ch2; read(0, &ch1, 1); read(0, &ch2, 1); if (ch1==91 && ch2==65) // up { // Print previous line in history. // Erase old line clear_line(); // Copy line from history if(history_access > history_index) history_access = history_index-1; else if(history_access < 0) history_access = 0; if( history_access >= 0 && history[history_access] ) { memset(line_buffer,0,sizeof(line_buffer)); strcpy(line_buffer, history[history_access]); line_length = strlen(line_buffer); position= line_length-1; history_access--; if(debug_mode) fprintf(stderr, "history_index after <up>=%d\n", history_index); // echo line write(1, line_buffer, line_length); } } else if(ch1==91 && ch2==66) //down { // Shows the next command in the history list // Print next line in history. // Erase old line clear_line(); // Copy line from history if(history_access > history_index) history_access = history_index-1; else if(history_access < 0) history_access = 0; if(history_access >= 0 && history[history_access]) { memset(line_buffer,0,sizeof(line_buffer)); strcpy(line_buffer, history[history_access]); line_length = strlen(line_buffer); position= line_length-1; history_access++; if(debug_mode) fprintf(stderr, "history_index=%d\n", history_index); write(1, line_buffer, line_length); } } else if(ch1==91 && ch2==67) //right { /* Move the cursor to the right and allow insertion at that position. If the cursor is at the end of the line it does nothing. */ if(position >= 0 && position < line_length && line_length > 0 ) { ch= line_buffer[position]; write(1, &ch, 1); position++; } } else if(ch1==91 && ch2==68) //left { /* Move the cursor to the left and allow insertion at that position. If the cursor is at the beginning of the line it does nothing. */ if(position > 0 && position <= line_length && line_length > 0) { ch=BACKSPACE; write(1, &ch, 1); position--; } } else if(ch1==91 && ch2==52) // <end> { //read char because end is ESC+91+52+126 read(0, &ch1, 1); /* end key */ if( position < line_length && position >= 0) { while(position != line_length ) { ch = line_buffer[position]; write(1, &ch, 1); position++; } } } else if(ch1==91 && ch2==51) // <del> { //read char because del is ESC+91+51+126 read(0, &ch1, 1); /* del key */ delete_and_shift(0); } else if(ch1==91 && ch2==49) // <HOME> { //read char because home is ESC+91+49+126 read(0, &ch1, 1); /* home key */ if(position > 0 && position <= line_length ) { while(position != 0 ) { ch = BACKSPACE; write(1, &ch, 1); position--; } } } } } // Add eol and null char at the end of string if(line_length < 0) return ""; line_buffer[line_length]=10; line_length++; line_buffer[line_length]=0; position = 0; return line_buffer; }
/* * Input a line with some basic editing. */ char * read_line() { // Set terminal in raw mode tty_raw_mode(); line_length = 0; pos = 0; // Read one line until enter is typed while (1) { // Read one character in raw mode. char ch; read(0, &ch, 1); if (ch>=32) { // It is a printable character. // Do echo write(1,&ch,1); // If max number of character reached return. if (line_length==MAX_BUFFER_LINE-2) break; // add char to buffer. line_buffer[line_length]=ch; line_length++; } else if (ch==10) { // <Enter> was typed. Return line // Print newline write(1,&ch,1); break; } else if (ch == 31) { // ctrl-? read_line_print_usage(); line_buffer[0]=0; break; } else if (ch == 8) { // <backspace> was typed. Remove previous character read. // Go back one character ch = 8; write(1,&ch,1); // Write a space to erase the last character read ch = ' '; write(1,&ch,1); // Go back one character ch = 8; write(1,&ch,1); // Remove one character from buffer line_length--; } else if (ch==27) { // Escape sequence. Read two chars more // // HINT: Use the program "keyboard-example" to // see the ascii code for the different chars typed. // char ch1; char ch2; read(0, &ch1, 1); read(0, &ch2, 1); if (ch1==91 && ch2==65) { // Up arrow. Print next line in history. // Erase old line // Print backspaces int i = 0; for (i =0; i < line_length; i++) { ch = 8; write(1,&ch,1); } // Print spaces on top for (i =0; i < line_length; i++) { ch = ' '; write(1,&ch,1); } // Print backspaces for (i =0; i < line_length; i++) { ch = 8; write(1,&ch,1); } // Copy line from history strcpy(line_buffer, history[history_index]); line_length = strlen(line_buffer); history_index=(history_index+1)%history_length; // echo line write(1, line_buffer, line_length); } } } // Add eol and null char at the end of string line_buffer[line_length]=10; line_length++; line_buffer[line_length]=0; return line_buffer; }
/* * Input a line with some basic editing. */ char * read_line() { struct termios orig_attr; tcgetattr(0, &orig_attr); // Set terminal in raw mode tty_raw_mode(); line_length = 0; line_pos = 0; // Read one line until enter is typed while (1) { // Read one character in raw mode. char ch; read(0, &ch, 1); if (ch >= 32 && ch != 127) { // It is a printable character. int i; for (i = line_length; i > line_pos; i--) { line_buffer[i] = line_buffer[i - 1]; } line_buffer[i] = ch; line_length++; if (line_length == MAX_BUFFER_LINE - 2) break; for (i = line_pos; i < line_length; i++) { ch = line_buffer[i]; write(1, &ch, 1); } ch = 8; for (i = line_length; i > line_pos + 1; i--) { write(1, &ch, 1); } line_pos++; } else if (ch == 10) { // <Enter> was typed. Return line // Print newline write(1,&ch,1); break; } else if (ch == 31) { // ctrl-? read_line_print_usage(); line_buffer[0]=0; break; } else if (ch == 8 || ch == 127) { // <backspace> was typed. Remove previous character read. if (line_length == 0 || line_pos == 0) { continue; } else { int i; for (i = line_pos - 1; i < line_length - 1; i++) { line_buffer[i] = line_buffer[i + 1]; } ch = 8; write(1, &ch, 1); for (i = line_pos; i < line_length; i++) { ch = line_buffer[i - 1]; write(1, &ch, 1); } ch = ' '; write(1, &ch, 1); ch = 8; write(1, &ch, 1); for (i = line_pos; i < line_length; i++) { write(1, &ch, 1); } line_pos--; line_length--; } } else if (ch == 27) { // Escape sequence. Read two chars more // // HINT: Use the program "keyboard-example" to // see the ascii code for the different chars typed. // char ch1; char ch2; read(0, &ch1, 1); read(0, &ch2, 1); if (ch1 == 91 && ch2 == 65) { // Up arrow. Print next line in history. if (history_count == 0 || history_index == 0) { continue; } // Erase old line // Print backspaces int i = 0; for (i =0; i < line_length; i++) { ch = 8; write(1, &ch, 1); } // Print spaces on top for (i =0; i < line_length; i++) { ch = ' '; write(1, &ch, 1); } // Print backspaces for (i =0; i < line_length; i++) { ch = 8; write(1, &ch, 1); } // Copy line from history if (history_index > 0) { history_index--; } strcpy(line_buffer, history[history_index]); line_length = strlen(line_buffer); // echo line write(1, line_buffer, line_length); line_pos = line_length; } else if (ch1 == 91 && ch2 == 66) { // Down arrow. Print previous line in history if (history_count == 0 || history_index == history_count) { line_pos = 0; line_length = 0; continue; } int i = 0; for (i = 0; i < line_length; i++) { ch = 8; write(1, &ch, 1); } for (i = 0; i < line_length; i++) { ch = ' '; write(1, &ch, 1); } for (i = 0; i < line_length; i++) { ch = 8; write(1, &ch, 1); } history_index++; if (history_index == history_count) { line_pos = 0; line_length = 0; continue; } strcpy(line_buffer,history[history_index]); line_length = strlen(line_buffer); write(1, line_buffer, line_length); line_pos = line_length; } else if (ch1 == 91 && ch2 == 67) { // Right arrow. Move line position to the right if (line_pos < line_length) { ch = line_buffer[line_pos++]; write(1, &ch, 1); } } else if (ch1 == 91 && ch2 == 68) { // Left arrow. Move line position to the left if (line_pos > 0) { ch = 8; write(1, &ch, 1); line_pos--; } } else if (ch1 == 79 && ch2 == 72) { ch = 8; while (line_pos > 0) { write(1, &ch, 1); line_pos--; } } else if (ch1 == 79 && ch2 == 70) { while (line_pos < line_length + 1) { ch = line_buffer[line_pos - 1]; write(1, &ch, 1); line_pos++; } line_pos--; } } else if (ch == 1) { // Home button. Move line position to start ch = 8; while (line_pos > 0) { write(1, &ch, 1); line_pos--; } } else if (ch == 5) { // End button. Move line position to end while (line_pos < line_length + 1) { ch = line_buffer[line_pos - 1]; write(1, &ch, 1); line_pos++; } line_pos--; } else if (ch == 4) { // Delete. Move characters following current position to the left one if (line_length == 0 || line_pos == line_length) { continue; } else { int i; for (i = line_pos; i < line_length - 1; i++) { line_buffer[i] = line_buffer[i + 1]; } line_length--; for (i = line_pos; i < line_length; i++) { ch = line_buffer[i]; write(1, &ch, 1); } ch = ' '; write(1, &ch, 1); ch = 8; write(1, &ch, 1); for (i = line_pos; i < line_length; i++) { write(1, &ch, 1); } } } else if (ch == 9) { // Tab. Path completion // TODO: extra credit if (tablistset == 0) { char * regex = (char *)malloc(sizeof(char) * (line_length + 5)); regex[0] = '^'; int i; for (i = line_length - 1; i >= 0; i--) { if (line_buffer[i] == ' ') { spaceindex = i; break; } } if (spaceindex != 0) { int copysize = (line_buffer + line_length) - (line_buffer + spaceindex) - 1; strncpy(regex + 1, line_buffer + spaceindex + 1, copysize); regex[copysize + 1] = '.'; regex[copysize + 2] = '*'; regex[copysize + 3] = '$'; regex[copysize + 4] = '\0'; } else { strncpy(regex + 1, line_buffer, line_length); regex[line_length] = '.'; regex[line_length + 1] = '*'; regex[line_length + 2] = '$'; regex[line_length + 3] = '\0'; } regex_t re; int regexbuf = regcomp(&re, regex, REG_EXTENDED | REG_NOSUB); if (regexbuf != 0) { perror("regcomp"); return; } char * d = (char *)malloc(sizeof(char) * 2); d[0] = '.'; d[1] = '\0'; DIR * dir = opendir(d); if (dir == NULL) { perror("opendir"); return; } free(d); struct dirent * ent; regmatch_t match; int maxEntries = 10; tablistsize = 0; tablist = (char **)malloc(maxEntries * sizeof(char *)); while ((ent = readdir(dir)) != NULL) { if (regexec(&re, ent->d_name, 1, &match, 0) == 0) { if (tablistsize == maxEntries) { maxEntries *= 2; tablist = (char **)realloc(tablist, maxEntries * sizeof(char *)); } tablist[tablistsize++] = strdup(ent->d_name); } } tablistset = 1; } int i; ch = 8; for (i = 0; i < line_length; i++) { write(1, &ch, 1); } ch = ' '; for (i = 0; i < line_length; i++) { write(1, &ch, 1); } ch = 8; for (i = 0; i < line_length; i++) { write(1, &ch, 1); } if (spaceindex == 0) { strcpy(line_buffer, tablist[tablistindex]); line_length = strlen(line_buffer); } else { char * tmptab = tablist[tablistindex]; for (i = 0; i < strlen(tmptab); i++) { line_buffer[spaceindex + i + 1] = tmptab[i]; } line_length = spaceindex + strlen(tablist[tablistindex]) + 1; } write(1, line_buffer, line_length); line_pos = line_length; if (tablistindex < tablistsize - 1) { tablistindex++; } } } if (strlen(line_buffer) > 1) { char * tmpbuf = (char *)malloc(sizeof(char) * (line_length + 2)); strncpy(tmpbuf, line_buffer, line_length); tmpbuf[line_length] = 0; history[history_count++] = strdup(tmpbuf); free(tmpbuf); } history_index = history_count; // Add eol and null char at the end of string line_buffer[line_length] = 10; line_length++; line_buffer[line_length] = 0; if (tablistset) { spaceindex = 0; tablistset = 0; tablistindex = 0; free(tablist); } tcsetattr(0, TCSANOW, &orig_attr); return line_buffer; }