| // Console input and output. | |
| // Input is from the keyboard or serial port. | |
| // Output is written to the screen and serial port. | |
| // Forward declaration of console output function. | |
| static void console_output_char(int c); | |
| static int panicked = 0; | |
| // Console lock state | |
| static struct { | |
| struct spinlock lock; | |
| int locking; | |
| } console_lock_state; | |
| // Copy buffer size | |
| // Structure to handle copy-paste functionality | |
| struct { | |
| char buffer[COPY_BUF_SIZE]; // Buffer to store copied characters | |
| int is_copying; // Flag to indicate if copying is active | |
| int index; // Index in the copy buffer | |
| } copy_buffer; | |
| // Function to print integer to console | |
| static void print_integer(int value, int base, int is_signed) { | |
| static char digits[] = "0123456789abcdef"; // This array holds characters representing digits 0-9 and a-f for hexadecimal values. | |
| char buffer[16]; // A temporary buffer to store the characters of the number to be printed. | |
| int i; // An index variable used to track the position in the buffer. | |
| uint x; // Unsigned integer to hold the absolute value of the number being printed. | |
| if (is_signed && (is_signed = value < 0)) | |
| x = -value; | |
| else | |
| x = value; | |
| i = 0; | |
| do { | |
| buffer[i++] = digits[x % base]; // Store the current digit (using the remainder) in the buffer. | |
| } while ((x /= base) != 0); // Continue dividing x by the base until x becomes 0. | |
| if (is_signed) | |
| buffer[i++] = '-'; | |
| while (--i >= 0) | |
| console_output_char(buffer[i]); // Output the digits to the console, one by one. | |
| } | |
| // Print to the console. Only understands %d, %x, %p, %s. | |
| void cprintf(char* fmt, ...) { | |
| int i, c, locking; | |
| uint* argp; | |
| char* s; | |
| locking = console_lock_state.locking; | |
| if (locking) | |
| acquire(&console_lock_state.lock); | |
| if (fmt == 0) | |
| panic("null fmt"); | |
| argp = (uint*)(void*)(&fmt + 1); | |
| for (i = 0; (c = fmt[i] & 0xff) != 0; i++) { | |
| if (c != '%') { | |
| console_output_char(c); | |
| continue; | |
| } | |
| c = fmt[++i] & 0xff; | |
| if (c == 0) | |
| break; | |
| switch (c) { | |
| case 'd': | |
| print_integer(*argp++, 10, 1); | |
| break; | |
| case 'x': | |
| case 'p': | |
| print_integer(*argp++, 16, 0); | |
| break; | |
| case 's': | |
| if ((s = (char*)*argp++) == 0) | |
| s = "(null)"; | |
| for (; *s; s++) | |
| console_output_char(*s); | |
| break; | |
| case '%': | |
| console_output_char('%'); | |
| break; | |
| default: | |
| // Print unknown % sequence to draw attention. | |
| console_output_char('%'); | |
| console_output_char(c); | |
| break; | |
| } | |
| } | |
| if (locking) | |
| release(&console_lock_state.lock); | |
| } | |
| void panic(char* s) { | |
| int i; | |
| uint pcs[10]; | |
| cli(); | |
| console_lock_state.locking = 0; | |
| // Use lapicid so that we can call panic from mycpu() | |
| cprintf("lapicid %d: panic: ", lapicid()); | |
| cprintf(s); | |
| cprintf("\n"); | |
| getcallerpcs(&s, pcs); | |
| for (i = 0; i < 10; i++) | |
| cprintf(" %p", pcs[i]); | |
| panicked = 1; // Freeze other CPUs | |
| for (;;) | |
| ; | |
| } | |
| static ushort* crt = (ushort*)P2V(0xb8000); // CGA memory | |
| static int get_cursor_position(void) { | |
| int pos; | |
| outb(CRTPORT, 14); | |
| pos = inb(CRTPORT + 1) << 8; | |
| outb(CRTPORT, 15); | |
| pos |= inb(CRTPORT + 1); | |
| return pos; | |
| } | |
| // Sets cursor position | |
| static void set_cursor_position(int pos) { | |
| outb(CRTPORT, 14); | |
| outb(CRTPORT + 1, pos >> 8); | |
| outb(CRTPORT, 15); | |
| outb(CRTPORT + 1, pos); | |
| } | |
| // Erases character at position | |
| static void console_erase_character(int pos) { | |
| crt[pos] = ' ' | 0x0700; | |
| } | |
| // Writes character at position | |
| static void console_write_character(int pos, int c) { | |
| crt[pos] = (c & 0xff) | 0x0700; | |
| } | |
| // Output character to CGA display | |
| static void cga_put_character(int c) { | |
| int pos = get_cursor_position(); | |
| if (c == '\n') | |
| pos += 80 - pos % 80; | |
| else if (c == BACKSPACE) { | |
| if (pos > 0) | |
| --pos; | |
| } else | |
| crt[pos++] = (c & 0xff) | 0x0700; // Black on white | |
| if (pos < 0 || pos > 25 * 80) | |
| panic("pos under/overflow"); | |
| if ((pos / 80) >= 24) { // Scroll up. | |
| memmove(crt, crt + 80, sizeof(crt[0]) * 23 * 80); | |
| pos -= 80; | |
| memset(crt + pos, 0, sizeof(crt[0]) * (24 * 80 - pos)); | |
| } | |
| set_cursor_position(pos); | |
| console_erase_character(pos); | |
| } | |
| // Output character to console | |
| void console_output_char(int c) { | |
| if (panicked) { | |
| cli(); | |
| for (;;) | |
| ; | |
| } | |
| if (c == BACKSPACE) { | |
| uartputc('\b'); | |
| uartputc(' '); | |
| uartputc('\b'); | |
| } else | |
| uartputc(c); | |
| cga_put_character(c); | |
| } | |
| // Input buffer structure | |
| struct { | |
| char buffer[INPUT_BUFFER_SIZE]; | |
| uint read_index; // Read index | |
| uint write_index; // Write index | |
| uint edit_index; // Edit index | |
| uint cursor_shift; // Number of positions the cursor has been shifted to the left (>= 0) | |
| } input_buffer; | |
| // Write string to console and input buffer | |
| void console_put_string(char* s) { | |
| for (int i = 0; i < INPUT_BUFFER_SIZE && s[i]; ++i) { | |
| input_buffer.buffer[input_buffer.edit_index++ % INPUT_BUFFER_SIZE] = s[i]; | |
| console_output_char(s[i]); | |
| } | |
| } | |
| // Functions to move cursor | |
| static void move_cursor_to_end(void) { | |
| set_cursor_position(get_cursor_position() + input_buffer.cursor_shift); | |
| } | |
| static void move_cursor_left(void) { | |
| set_cursor_position(get_cursor_position() - 1); | |
| } | |
| static void move_cursor_right(void) { | |
| set_cursor_position(get_cursor_position() + 1); | |
| } | |
| static void move_cursor_to_start(void) { | |
| input_buffer.cursor_shift = input_buffer.edit_index - input_buffer.write_index; | |
| set_cursor_position(get_cursor_position() - input_buffer.cursor_shift); | |
| } | |
| // Erase line and clear input buffer | |
| static void console_erase_line(void) { | |
| move_cursor_to_end(); | |
| input_buffer.cursor_shift = 0; | |
| while (input_buffer.edit_index != input_buffer.write_index && | |
| input_buffer.buffer[(input_buffer.edit_index - 1) % INPUT_BUFFER_SIZE] != '\n') { | |
| input_buffer.edit_index--; | |
| console_output_char(BACKSPACE); | |
| } | |
| } | |
| // Erase line without clearing input buffer | |
| static void console_erase_line_without_clearing_buffer(int num_chars) { | |
| move_cursor_to_end(); | |
| input_buffer.cursor_shift = 0; | |
| for (int i = 0; i < num_chars; i++) { | |
| input_buffer.edit_index--; | |
| console_output_char(BACKSPACE); | |
| } | |
| } | |
| // Erase terminal screen | |
| static void console_clear_screen(void) { | |
| int pos = get_cursor_position(); | |
| while (pos >= 0) | |
| console_erase_character(pos--); | |
| } | |
| // Print shell prompt | |
| static void console_new_command_prompt(void) { | |
| console_write_character(0, '$'); | |
| set_cursor_position(2); | |
| } | |
| // Shift input buffer left by one character | |
| static void input_shift_left(void) { | |
| for (int i = input_buffer.cursor_shift + 1; i > 1; i--) | |
| input_buffer.buffer[(input_buffer.edit_index - i) % INPUT_BUFFER_SIZE] = | |
| input_buffer.buffer[(input_buffer.edit_index - i + 1) % INPUT_BUFFER_SIZE]; | |
| input_buffer.edit_index--; | |
| } | |
| // Shift input buffer right by one character | |
| static void input_shift_right(void) { | |
| for (int i = 0; i < input_buffer.cursor_shift; i++) | |
| input_buffer.buffer[(input_buffer.edit_index - i) % INPUT_BUFFER_SIZE] = | |
| input_buffer.buffer[(input_buffer.edit_index - i - 1) % INPUT_BUFFER_SIZE]; | |
| } | |
| // Update console after input buffer has been modified (shift left) | |
| static void console_shift_left(void) { | |
| move_cursor_to_end(); | |
| for (int i = 0; i <= input_buffer.cursor_shift; i++) | |
| console_output_char(BACKSPACE); | |
| for (int i = input_buffer.cursor_shift; i > 0; i--) | |
| console_output_char(input_buffer.buffer[(input_buffer.edit_index - i) % INPUT_BUFFER_SIZE]); | |
| set_cursor_position(get_cursor_position() - input_buffer.cursor_shift); | |
| } | |
| // Update console after input buffer has been modified (shift right) | |
| static void console_shift_right(void) { | |
| move_cursor_to_end(); | |
| for (int i = 0; i < input_buffer.cursor_shift; i++) | |
| console_output_char(BACKSPACE); | |
| for (int i = input_buffer.cursor_shift; i >= 0; i--) | |
| console_output_char(input_buffer.buffer[(input_buffer.edit_index - i) % INPUT_BUFFER_SIZE]); | |
| set_cursor_position(get_cursor_position() - input_buffer.cursor_shift); | |
| } | |
| // Put character into input buffer | |
| static void input_put_character(char c) { | |
| if (input_buffer.cursor_shift == 0) { | |
| input_buffer.buffer[input_buffer.edit_index % INPUT_BUFFER_SIZE] = c; | |
| console_output_char(c); | |
| } else { | |
| input_shift_right(); | |
| input_buffer.buffer[(input_buffer.edit_index - input_buffer.cursor_shift) % INPUT_BUFFER_SIZE] = c; | |
| console_shift_right(); | |
| } | |
| input_buffer.edit_index++; | |
| } | |
| // Function to delete numbers from input | |
| static void delete_numbers_from_input(void) { | |
| char line[INPUT_BUFFER_SIZE]; | |
| int line_index = 0; | |
| for (int input_index = 0; input_index < input_buffer.edit_index - input_buffer.write_index; input_index++) { | |
| int idx = (input_buffer.write_index + input_index) % INPUT_BUFFER_SIZE; | |
| if (input_buffer.buffer[idx] >= '0' && input_buffer.buffer[idx] <= '9') | |
| continue; | |
| line[line_index++] = input_buffer.buffer[idx]; | |
| } | |
| line[line_index] = 0; | |
| console_erase_line(); | |
| console_put_string(line); | |
| } | |
| // Command history buffer | |
| struct { | |
| char buffer[COMMAND_HISTORY_SIZE][INPUT_BUFFER_SIZE]; // Buffer to store commands | |
| int read_index; // Read index (range [1, COMMAND_HISTORY_SIZE]) | |
| int write_index; // Write index | |
| int in_tab_mode; // Whether we are in tab completion mode | |
| char temp_command[INPUT_BUFFER_SIZE]; // Temporary command | |
| int last_used_index; // Index of last used command | |
| } command_history; | |
| // Store command into history buffer | |
| static void store_command(void) { | |
| // Shift existing commands to make room for the new command | |
| for (int i = COMMAND_HISTORY_SIZE - 1; i > 0; i--) | |
| memmove(command_history.buffer[i], command_history.buffer[i - 1], INPUT_BUFFER_SIZE); | |
| // Copy the new command into the buffer | |
| int j = 0; | |
| for (int i = input_buffer.write_index; i < input_buffer.edit_index; i++) { | |
| command_history.buffer[0][j] = input_buffer.buffer[i % INPUT_BUFFER_SIZE]; | |
| j++; | |
| } | |
| for (; j < INPUT_BUFFER_SIZE; j++) { | |
| command_history.buffer[0][j] = 0; | |
| } | |
| } | |
| // Load command from history buffer | |
| static void load_command(void) { | |
| console_erase_line(); | |
| int n = command_history.read_index - 1; | |
| input_buffer.edit_index = input_buffer.write_index; | |
| for (int i = 0; i < INPUT_BUFFER_SIZE; i++) { | |
| if (command_history.buffer[n][i] == '\0') | |
| break; | |
| input_buffer.buffer[input_buffer.edit_index++ % INPUT_BUFFER_SIZE] = command_history.buffer[n][i]; | |
| console_output_char(command_history.buffer[n][i]); | |
| } | |
| } | |
| // Copy current command | |
| static void copy_current_command(void) { | |
| int j = 0; | |
| for (int i = input_buffer.write_index; i < input_buffer.edit_index; i++) { | |
| command_history.temp_command[j] = input_buffer.buffer[i % INPUT_BUFFER_SIZE]; | |
| j++; | |
| } | |
| for (; j < INPUT_BUFFER_SIZE; j++) { | |
| command_history.temp_command[j] = 0; | |
| } | |
| } | |
| // Recover command from temporary storage | |
| static void recover_command(void) { | |
| console_erase_line(); | |
| input_buffer.edit_index = input_buffer.write_index; | |
| for (int i = 0; i < INPUT_BUFFER_SIZE; i++) { | |
| if (command_history.temp_command[i] == 0) | |
| break; | |
| input_buffer.buffer[input_buffer.edit_index++ % INPUT_BUFFER_SIZE] = command_history.temp_command[i]; | |
| console_output_char(command_history.temp_command[i]); | |
| } | |
| } | |
| // Check if cmd is a prefix of input | |
| static int is_prefix(const char* cmd, const char* input, int input_size) { | |
| for (int i = 0; i < input_size; i++) | |
| if (cmd[i] != input[i]) | |
| return 0; | |
| return 1; | |
| } | |
| // Get predicted command index based on input | |
| static int get_predicted_command_index(const char* cmd, uint cmd_size, int last_used_index) { | |
| for (int i = last_used_index; i < command_history.write_index; i++) { | |
| if (is_prefix(command_history.buffer[i], cmd, cmd_size)) | |
| return i; | |
| } | |
| return -1; | |
| } | |
| // Predict command based on current input | |
| static void predict_command(void) { | |
| int predicted_cmd_idx = -1; | |
| if (!command_history.in_tab_mode) { | |
| command_history.last_used_index = 0; | |
| predicted_cmd_idx = get_predicted_command_index( | |
| input_buffer.buffer + input_buffer.write_index, | |
| input_buffer.edit_index - input_buffer.write_index, | |
| command_history.last_used_index | |
| ); | |
| copy_current_command(); | |
| } else { | |
| predicted_cmd_idx = get_predicted_command_index( | |
| input_buffer.buffer + input_buffer.write_index, | |
| input_buffer.edit_index - input_buffer.write_index, | |
| command_history.last_used_index + 1 | |
| ); | |
| } | |
| if (predicted_cmd_idx >= 0) { | |
| command_history.in_tab_mode = 1; | |
| command_history.last_used_index = predicted_cmd_idx; | |
| console_erase_line(); | |
| console_put_string(command_history.buffer[predicted_cmd_idx]); | |
| } | |
| } | |
| // Reset command history | |
| static void reset_command_history(void) { | |
| command_history.in_tab_mode = 0; | |
| command_history.temp_command[0] = '\0'; | |
| command_history.last_used_index = 0; | |
| command_history.write_index = ((command_history.write_index + 1) > COMMAND_HISTORY_SIZE ? COMMAND_HISTORY_SIZE : (command_history.write_index + 1)); | |
| store_command(); | |
| command_history.read_index = 0; | |
| move_cursor_to_end(); | |
| } | |
| // Control key definitions | |
| // Simple strcmp implementation | |
| static int string_compare(const char *s1, const char *s2) { | |
| while(*s1 && *s1 == *s2){ | |
| s1++; | |
| s2++; | |
| } | |
| return (unsigned char)*s1 - (unsigned char)*s2; | |
| } | |
| // Evaluate expression from end of input buffer | |
| static int evaluate_expression_from_end(int end_idx, int* result) { | |
| int num1 = 0, num2 = 0; | |
| char op = 0; | |
| int idx = end_idx; | |
| int multiplier = 1; | |
| while (idx >= input_buffer.write_index && input_buffer.buffer[idx % INPUT_BUFFER_SIZE] >= '0' && input_buffer.buffer[idx % INPUT_BUFFER_SIZE] <= '9') { | |
| num2 += (input_buffer.buffer[idx % INPUT_BUFFER_SIZE] - '0') * multiplier; | |
| multiplier *= 10; | |
| idx--; | |
| } | |
| if (idx >= input_buffer.write_index && (input_buffer.buffer[idx % INPUT_BUFFER_SIZE] == '+' || input_buffer.buffer[idx % INPUT_BUFFER_SIZE] == '-' || | |
| input_buffer.buffer[idx % INPUT_BUFFER_SIZE] == '*' || input_buffer.buffer[idx % INPUT_BUFFER_SIZE] == '/')) { | |
| op = input_buffer.buffer[idx % INPUT_BUFFER_SIZE]; | |
| idx--; | |
| } else { | |
| return 0; // Not a valid operator | |
| } | |
| multiplier = 1; | |
| while (idx >= input_buffer.write_index && input_buffer.buffer[idx % INPUT_BUFFER_SIZE] >= '0' && input_buffer.buffer[idx % INPUT_BUFFER_SIZE] <= '9') { | |
| num1 += (input_buffer.buffer[idx % INPUT_BUFFER_SIZE] - '0') * multiplier; | |
| multiplier *= 10; | |
| idx--; | |
| } | |
| if (multiplier == 1) { | |
| return 0; | |
| } | |
| switch (op) { | |
| case '+': | |
| *result = num1 + num2; | |
| break; | |
| case '-': | |
| *result = num1 - num2; | |
| break; | |
| case '*': | |
| *result = num1 * num2; | |
| break; | |
| case '/': | |
| if (num2 == 0) | |
| return 0; | |
| *result = num1 / num2; | |
| break; | |
| default: | |
| return 0; | |
| } | |
| return end_idx - idx; | |
| } | |
| // Process input buffer and replace 'N O N=?' patterns with result | |
| static void process_input_buffer(void) { | |
| int i = input_buffer.edit_index - 1; // Start from the end of the input buffer | |
| int write_idx = input_buffer.write_index; | |
| while (i >= write_idx) { | |
| // Check for the pattern '=?' at the end | |
| if (input_buffer.buffer[i % INPUT_BUFFER_SIZE] == '?' && input_buffer.buffer[(i - 1) % INPUT_BUFFER_SIZE] == '=') { | |
| int expr_end = i - 2; // The position before '=' | |
| int result = 0; | |
| int expr_len = evaluate_expression_from_end(expr_end, &result); | |
| if (expr_len > 0) { | |
| // Remove the 'N O N=?' from input buffer | |
| int total_len = expr_len + 2; // +2 for '=?' | |
| int start_pos = expr_end - expr_len + 1; // Start position of the expression | |
| // Shift the remaining buffer left to remove the expression | |
| for (int j = start_pos; j < input_buffer.edit_index - total_len; j++) { | |
| input_buffer.buffer[j % INPUT_BUFFER_SIZE] = input_buffer.buffer[(j + total_len) % INPUT_BUFFER_SIZE]; | |
| } | |
| input_buffer.edit_index -= total_len; | |
| // Convert result to string | |
| char res_str[16]; | |
| int res_len = 0; | |
| int temp_result = result; | |
| if (result == 0) { | |
| res_str[res_len++] = '0'; | |
| } else { | |
| if (result < 0) { | |
| res_str[res_len++] = '-'; | |
| temp_result = -temp_result; | |
| } | |
| int digits[10]; | |
| int num_digits = 0; | |
| while (temp_result > 0) { | |
| digits[num_digits++] = temp_result % 10; | |
| temp_result /= 10; | |
| } | |
| for (int k = num_digits - 1; k >= 0; k--) { | |
| res_str[res_len++] = '0' + digits[k]; | |
| } | |
| } | |
| // Shift input buffer to make space for result | |
| int shift_amount = res_len; | |
| for (int j = input_buffer.edit_index - 1; j >= start_pos; j--) { | |
| input_buffer.buffer[(j + shift_amount) % INPUT_BUFFER_SIZE] = input_buffer.buffer[j % INPUT_BUFFER_SIZE]; | |
| } | |
| input_buffer.edit_index += shift_amount; | |
| // Insert result into input buffer | |
| for (int j = 0; j < res_len; j++) { | |
| input_buffer.buffer[(start_pos + j) % INPUT_BUFFER_SIZE] = res_str[j]; | |
| } | |
| //clean the console | |
| console_erase_line_without_clearing_buffer(total_len); | |
| // console_output_char(res_len + '0'); | |
| //inset result in consule output | |
| for (int j = 0; j < res_len; j++) { | |
| console_output_char(res_str[j]); | |
| // add to buffer | |
| input_buffer.buffer[input_buffer.edit_index++ % INPUT_BUFFER_SIZE] = res_str[j]; | |
| } | |
| input_buffer.cursor_shift = 0; | |
| // Adjust 'i' to continue processing correctly | |
| i = start_pos + res_len - 1; | |
| } | |
| } | |
| i--; | |
| } | |
| } | |
| // Console interrupt handler | |
| void consoleintr(int (*getc)(void)) { | |
| int c, doprocdump = 0; | |
| acquire(&console_lock_state.lock); | |
| while ((c = getc()) >= 0) { | |
| switch (c) { | |
| case CTRL('P'): // Process listing. | |
| doprocdump = 1; | |
| break; | |
| case CTRL('U'): // Kill line. | |
| console_erase_line(); | |
| break; | |
| case CTRL('H'): | |
| case '\x7f': // Backspace | |
| if ((input_buffer.edit_index - input_buffer.cursor_shift) > input_buffer.write_index) { | |
| input_shift_left(); | |
| console_shift_left(); | |
| } | |
| break; | |
| case CTRL('L'): // Clear screen. | |
| console_erase_line(); | |
| console_clear_screen(); | |
| console_new_command_prompt(); | |
| break; | |
| case ARROW_LEFT: | |
| if (input_buffer.cursor_shift < input_buffer.edit_index - input_buffer.write_index) { | |
| input_buffer.cursor_shift++; | |
| move_cursor_left(); | |
| } | |
| break; | |
| case ARROW_RIGHT: | |
| if (input_buffer.cursor_shift > 0) { | |
| input_buffer.cursor_shift--; | |
| move_cursor_right(); | |
| } | |
| break; | |
| case CTRL('N'): | |
| delete_numbers_from_input(); | |
| break; | |
| case CTRL('A'): // Move cursor to start | |
| if (input_buffer.cursor_shift < input_buffer.edit_index - input_buffer.write_index) { | |
| move_cursor_to_start(); | |
| input_buffer.cursor_shift = input_buffer.edit_index - input_buffer.write_index; | |
| } | |
| break; | |
| case CTRL('E'): // Move cursor to end | |
| move_cursor_to_end(); | |
| input_buffer.cursor_shift = 0; | |
| break; | |
| case ARROW_UP: | |
| if (command_history.read_index == 0) | |
| copy_current_command(); | |
| command_history.read_index++; | |
| if (command_history.read_index > command_history.write_index) | |
| command_history.read_index = command_history.write_index; | |
| else | |
| load_command(); | |
| break; | |
| case ARROW_DOWN: | |
| command_history.read_index--; | |
| if (command_history.read_index > 0) | |
| load_command(); | |
| else { | |
| command_history.read_index = 0; | |
| recover_command(); | |
| } | |
| break; | |
| case TAB: | |
| predict_command(); | |
| break; | |
| case CTRL('S'): | |
| copy_buffer.is_copying = 1; | |
| console_output_char('C'); | |
| copy_buffer.index = 0; | |
| break; | |
| case CTRL('F'): | |
| copy_buffer.is_copying = 0; | |
| for (int i = 0; i < copy_buffer.index; i++) { | |
| if (input_buffer.edit_index - input_buffer.read_index < INPUT_BUFFER_SIZE) { | |
| input_put_character(copy_buffer.buffer[i]); | |
| } | |
| } | |
| break; | |
| default: | |
| if (c != 0 && input_buffer.edit_index - input_buffer.read_index < INPUT_BUFFER_SIZE) { | |
| c = (c == '\r') ? '\n' : c; | |
| if (copy_buffer.is_copying && ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) { | |
| if (copy_buffer.index < COPY_BUF_SIZE - 1) { | |
| copy_buffer.buffer[copy_buffer.index++] = c; | |
| } | |
| } | |
| process_input_buffer(); | |
| if (c == '\n' && input_buffer.edit_index - input_buffer.write_index > 0) { | |
| reset_command_history(); | |
| input_buffer.cursor_shift = 0; | |
| } | |
| input_put_character(c); | |
| if (c == '\n' || c == CTRL('D') || input_buffer.edit_index == input_buffer.read_index + INPUT_BUFFER_SIZE) { | |
| int cmd_len = input_buffer.edit_index - input_buffer.write_index; | |
| char cmd[INPUT_BUFFER_SIZE]; | |
| for (int i = 0; i < cmd_len; i++) { | |
| cmd[i] = input_buffer.buffer[(input_buffer.write_index + i) % INPUT_BUFFER_SIZE]; | |
| } | |
| cmd[cmd_len - 1] = '\0'; | |
| if (string_compare(cmd, "history") == 0) { | |
| for (int i = command_history.write_index - 1; i >= 0; i--) { | |
| console_put_string(command_history.buffer[i]); | |
| console_output_char('\n'); | |
| } | |
| input_buffer.write_index = input_buffer.edit_index; | |
| console_output_char('$'); | |
| break; | |
| } | |
| input_buffer.write_index = input_buffer.edit_index; | |
| wakeup(&input_buffer.read_index); | |
| } | |
| } | |
| break; | |
| } | |
| } | |
| release(&console_lock_state.lock); | |
| if (doprocdump) { | |
| procdump(); // Now call procdump() without console_lock_state.lock held | |
| } | |
| } | |
| // Read from console | |
| int consoleread(struct inode* ip, char* dst, int n) { | |
| uint target; | |
| int c; | |
| iunlock(ip); | |
| target = n; | |
| acquire(&console_lock_state.lock); | |
| while (n > 0) { | |
| while (input_buffer.read_index == input_buffer.write_index) { | |
| if (myproc()->killed) { | |
| release(&console_lock_state.lock); | |
| ilock(ip); | |
| return -1; | |
| } | |
| sleep(&input_buffer.read_index, &console_lock_state.lock); | |
| } | |
| c = input_buffer.buffer[input_buffer.read_index++ % INPUT_BUFFER_SIZE]; | |
| if (c == CTRL('D')) { | |
| if (n < target) { | |
| input_buffer.read_index--; | |
| } | |
| break; | |
| } | |
| *dst++ = c; | |
| --n; | |
| if (c == '\n') | |
| break; | |
| } | |
| release(&console_lock_state.lock); | |
| ilock(ip); | |
| return target - n; | |
| } | |
| // Write to console | |
| int consolewrite(struct inode* ip, char* buf, int n) { | |
| int i; | |
| iunlock(ip); | |
| acquire(&console_lock_state.lock); | |
| for (i = 0; i < n; i++) | |
| console_output_char(buf[i] & 0xff); | |
| release(&console_lock_state.lock); | |
| ilock(ip); | |
| return n; | |
| } | |
| // Initialize console | |
| void consoleinit(void) { | |
| initlock(&console_lock_state.lock, "console"); | |
| devsw[CONSOLE].write = consolewrite; | |
| devsw[CONSOLE].read = consoleread; | |
| console_lock_state.locking = 1; | |
| ioapicenable(IRQ_KBD, 0); | |
| } | |
Xet Storage Details
- Size:
- 26.8 kB
- Xet hash:
- 15f0e691ff903ba11f1ca1037a1c89121f294179acf43ab32c0e83969f6e535f
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.