Untitled

 avatar
unknown
plain_text
11 days ago
10 kB
3
Indexable
/*
 * CS252: Systems Programming
 * Purdue University
 * Example that shows how to read one line with simple editing
 * using raw terminal.
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define MAX_BUFFER_LINE 2048

extern void tty_raw_mode(void);

// Buffer where line is stored
int line_length;
char line_buffer[MAX_BUFFER_LINE];

// Simple history array
// This history does not change.
// Yours have to be updated.
int history_index = 0;
char *history[1024];
int history_length = 0;

void read_line_print_usage()
{
  char *usage = "\n"
                " ctrl-?       Print usage\n"
                " Backspace    Deletes last character\n"
                " up arrow     See last command in the history\n";

  write(1, usage, strlen(usage));
}

/*
 * Input a line with some basic editing.
 */
char *read_line()
{

  // Set terminal in raw mode
  tty_raw_mode();

  line_length = 0;
  int cursor_position = line_length;

  // Read one line until enter is typed
  while (1)
  {

    // Read one character in raw mode.
    char ch;
    read(0, &ch, 1);
    // printf("\nRead : %c == %d\n", ch, ch);

    if (ch >= 32)
    {
      // It is a printable character.

      // Backspace For keyboard
      if (ch == 127)
      {
        // <backspace> was typed. Remove previous character read.

        // Go back one character
        if (line_length == 0 || cursor_position == 0) continue;
        if(cursor_position == line_length){
          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{
          // Move cursor left (backspace effect)
          char ch = 8; // backspace ASCII
          write(1, &ch, 1);

          // Shift characters left from the current position
          for (int i = cursor_position - 1; i < line_length - 1; i++)
          {
            line_buffer[i] = line_buffer[i + 1];
          }

          line_length--;
          cursor_position--;
          line_buffer[line_length] = '\0'; // Null terminate

          // Redraw the rest of the line from cursor
          for (int i = cursor_position; i < line_length; i++)
          {
            write(1, &line_buffer[i], 1);
          }

          // Write a space to clear the last character
          ch = ' ';
          write(1, &ch, 1);

          // Move cursor back to correct position
          int move_back = line_length - cursor_position + 1;
          ch = 8; // backspace
          for (int i = 0; i < move_back; i++)
          {
            write(1, &ch, 1);
          }
        }
        continue;
      }

      // 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;
      if (cursor_position == line_length) line_length++;
      cursor_position++;
    }
    else if (ch == 4)
    {
      if (line_length > 0 && line_length != cursor_position)
      {
        // Shift all characters after cursor left by one
        for (int i = cursor_position; i < line_length - 1; i++)
        {
          line_buffer[i] = line_buffer[i + 1];
        }
        line_length--;
        line_buffer[line_length] = '\0'; // Null terminate

        // Redraw from current cursor to end
        for (int i = cursor_position; i < line_length; i++)
        {
          write(1, &line_buffer[i], 1);
        }

        // Erase the last character (now duplicate)
        char ch = ' ';
        write(1, &ch, 1);

        // Move cursor back to original position
        int move_back = line_length - cursor_position + 1;
        ch = 8; // backspace
        for (int i = 0; i < move_back; i++)
        {
          write(1, &ch, 1);
        }
      }
    }
    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
      if (line_length == 0 || cursor_position == 0) continue;
      if(cursor_position == line_length){
        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{
        // Move cursor left (backspace effect)
        char ch = 8; // backspace ASCII
        write(1, &ch, 1);

        // Shift characters left from the current position
        for (int i = cursor_position - 1; i < line_length - 1; i++)
        {
          line_buffer[i] = line_buffer[i + 1];
        }

        line_length--;
        cursor_position--;
        line_buffer[line_length] = '\0'; // Null terminate

        // Redraw the rest of the line from cursor
        for (int i = cursor_position; i < line_length; i++)
        {
          write(1, &line_buffer[i], 1);
        }

        // Write a space to clear the last character
        ch = ' ';
        write(1, &ch, 1);

        // Move cursor back to correct position
        int move_back = line_length - cursor_position + 1;
        ch = 8; // backspace
        for (int i = 0; i < move_back; i++)
        {
          write(1, &ch, 1);
        }
      }
    }
    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
        if (history_length > 0 && history_index >= 0)
        {
          strcpy(line_buffer, history[history_index--]);
          if (history_index == -1)
          {
            history_index = history_length - 1;
          }

          line_length = strlen(line_buffer);
        }
        // echo line
        cursor_position = line_length;
        write(1, line_buffer, line_length);
      } // end of up
      else if (ch1 == 91 && ch2 == 66)
      {
        // Down arrow. Print prev 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
        if (history_length > 0 && history_index <= history_length - 1)
          strcpy(line_buffer, history[history_index++]);
        else if (history_index == history_length)
        {
          history_index = history_length - 1;
          strcpy(line_buffer, "");
        }

        line_length = strlen(line_buffer);
        cursor_position = line_length;
        // echo line
        write(1, line_buffer, line_length);
      } // End down arrow
      else if (ch1 == 91 && ch2 == 68)
      {
        // Left Arrow
        if (cursor_position > 0)
        {
          ch = 27;
          write(1, &ch, 1);
          ch = 91;
          write(1, &ch, 1);
          ch = 68;
          write(1, &ch, 1);
          cursor_position--;
        }
      } // End Left
      else if (ch1 == 91 && ch2 == 67)
      {
        // Right Arrow
        if (cursor_position < line_length)
        {
          ch = 27;
          write(1, &ch, 1);
          ch = 91;
          write(1, &ch, 1);
          ch = 67;
          write(1, &ch, 1);
          cursor_position++;
        }
      } // End Right
      else if (ch1 == 79 && ch2 == 72)
      { // Home
        while (cursor_position > 0)
        {
          ch = 27;
          write(1, &ch, 1);
          ch = 91;
          write(1, &ch, 1);
          ch = 68;
          write(1, &ch, 1);
          cursor_position--;
        }
      } // End Home

      else if (ch1 == 79 && ch2 == 70)
      { // End
        while (cursor_position != line_length)
        {
          ch = 27;
          write(1, &ch, 1);
          ch = 91;
          write(1, &ch, 1);
          ch = 67;
          write(1, &ch, 1);
          cursor_position++;
        }
      } // End End
    }
  }

  // Add eol and null char at the end of string
  line_buffer[line_length] = 10;
  line_length++;
  line_buffer[line_length] = 0;

  // update history
  history[history_length] = (char *)malloc(strlen(line_buffer) * sizeof(char) + 1);
  // printf("%s", line_buffer);

  strcpy(history[history_length++], line_buffer);
  history[history_length - 1][strlen(line_buffer) - 1] = '\0';
  history_index = history_length - 1;

  tty_term_mode();

  return line_buffer;
}
Editor is loading...
Leave a Comment