Untitled
unknown
plain_text
6 months ago
10 kB
5
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