#include #include #include #include #include #define MAX_SIZE 1024 #define HISTORY_SIZE 10 // Global variable for termios struct termios orig_termios; // Terminal input helpers void EnableRawMode(struct termios* orig_termios) { struct termios raw = *orig_termios; raw.c_lflag &= ~(ECHO | ICANON); // Disable echo and canonical mode tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw); } void DisableRawMode(struct termios* orig_termios) { tcsetattr(STDIN_FILENO, TCSAFLUSH, orig_termios); } // Wrapper function to pass DisableRawMode with argument void DisableRawModeWrapper() { DisableRawMode(&orig_termios); } int LogCommandHistory(char* buf, char** command_log, int* n) { int index = *n % HISTORY_SIZE; int prev_index = (*n == 0) ? HISTORY_SIZE - 1 : (*n - 1) % HISTORY_SIZE; if (command_log[prev_index] != NULL && strcmp(buf, command_log[prev_index]) == 0) { return 0; } if (command_log[index] != NULL) { free(command_log[index]); } command_log[index] = strdup(buf); (*n)++; return 0; } void FreeCommandHistory(char** command_log, int n) { for (int i = 0; i < n; i++) { free(command_log[i]); } } // Get input with arrow key navigation void GetInputWithHistory(char* buf, char** command_log, int n) { int index = n % HISTORY_SIZE; int history_counter = 0; int pos = 0; char c; while (1) { c = getchar(); if (c == '\n') { // Enter key buf[pos] = '\0'; printf("\n"); return; } else if (c == 127 || c == '\b') { // Backspace if (pos > 0) { pos--; buf[pos] = '\0'; printf("\b \b"); } } else if (c == '\033') { // Inputting arrow keys getchar(); // Skipping the first '[' character char arrow = getchar(); if (arrow == 'A' && history_counter < HISTORY_SIZE) { // Up arrow int prev_index = (index == 0) ? HISTORY_SIZE - 1 : (index - 1) % HISTORY_SIZE; if (command_log[prev_index] != NULL) { index = (index == 0) ? HISTORY_SIZE - 1 : index - 1; // Decrease the index history_counter++; strcpy(buf, command_log[index]); printf("\33[2K\r"); // Clear line printf("[%s] $ %s", getcwd(NULL, 0), buf); pos = strlen(buf); } } else if (arrow == 'B') { // Down arrow if (history_counter > 1) { index = (index + 1) % HISTORY_SIZE; history_counter--; strcpy(buf, command_log[index]); printf("\33[2K\r"); // Clear line printf("[%s] $ %s", getcwd(NULL, 0), buf); pos = strlen(buf); } else if (history_counter == 1) { history_counter--; index++; buf[0] = '\0'; // Clear buffer printf("\33[2K\r"); // Clear line printf("[%s] $ ", getcwd(NULL, 0)); pos = 0; } } } else { // Regular character if (pos < MAX_SIZE - 1) { buf[pos++] = c; buf[pos] = '\0'; printf("%c", c); } } } } int main() { char buf[MAX_SIZE]; char* command_log[HISTORY_SIZE] = {NULL}; int n = 0; tcgetattr(STDIN_FILENO, &orig_termios); // Register atexit to call DisableRawModeWrapper when the program exits atexit(DisableRawModeWrapper); while (1) { printf("[%s] $ ", getcwd(NULL, 0)); // Enable raw mode for manual input handling EnableRawMode(&orig_termios); GetInputWithHistory(buf, command_log, n); DisableRawMode(&orig_termios); if (strcmp(buf, "exit") == 0) { break; } LogCommandHistory(buf, command_log, &n); printf("Executed: %s\n", buf); // For testing, replace with actual command handling } FreeCommandHistory(command_log, n); return 0; }