예제 #1
0
/*
 * 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;
}
예제 #2
0
/* 
 * 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;
}
예제 #3
0
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;
}
예제 #4
0
/* 
 * 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;
}
예제 #5
0
/* 
 * 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;
}