final_1
This commit is contained in:
parent
626e12097d
commit
ccb7d7e118
175
main.c
175
main.c
@ -5,23 +5,142 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <termios.h>
|
||||
|
||||
#define MAX_SIZE 1024
|
||||
#define HISTORY_SIZE 5
|
||||
|
||||
// int LogCommandHistory(char* buf, char** command_log, int n) {
|
||||
// command_log[n] = buf;
|
||||
// }
|
||||
// RAW TERMINAL INPUT / LOGGING HISTORY IMPLEMENTATION -----------
|
||||
|
||||
void PrintCurrentDir() { // pwd
|
||||
// Global variable for termios
|
||||
struct termios orig_termios;
|
||||
|
||||
// Termios functions
|
||||
void EnableRawMode(struct termios* orig_termios) {
|
||||
struct termios raw = *orig_termios;
|
||||
raw.c_lflag &= ~(ECHO | ICANON);
|
||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
|
||||
}
|
||||
|
||||
void DisableRawMode(struct termios* orig_termios) {
|
||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, orig_termios);
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
void ClearBufferContent(int length) { // Function to clear buffer
|
||||
for (int i = 0; i < length; i++) {
|
||||
printf("\b \b");
|
||||
}
|
||||
}
|
||||
|
||||
// Get raw input from terminal + arrow key history navigation
|
||||
void GetRawInput(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(); // Skip '[' character
|
||||
char arrow = getchar();
|
||||
|
||||
if (arrow == 'A') { // Up arrow
|
||||
int prev_index = (index == 0) ? HISTORY_SIZE - 1 : (index - 1) % HISTORY_SIZE;
|
||||
if (command_log[prev_index] != NULL) {
|
||||
ClearBufferContent(pos); // Clear current buffer
|
||||
index = (index == 0) ? HISTORY_SIZE - 1 : index - 1;
|
||||
history_counter++;
|
||||
|
||||
strcpy(buf, command_log[index]);
|
||||
printf("%s", buf);
|
||||
pos = strlen(buf);
|
||||
}
|
||||
}
|
||||
else if (arrow == 'B') { // Down arrow
|
||||
if (history_counter > 0) {
|
||||
index = (index + 1) % HISTORY_SIZE;
|
||||
history_counter--;
|
||||
ClearBufferContent(pos);
|
||||
if (history_counter == 0) {
|
||||
buf[0] = '\0'; // Clear buffer
|
||||
pos = 0;
|
||||
} else {
|
||||
strcpy(buf, command_log[index]);
|
||||
printf("%s", buf);
|
||||
pos = strlen(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // Regular character
|
||||
if (pos < MAX_SIZE - 1) {
|
||||
buf[pos++] = c;
|
||||
buf[pos] = '\0';
|
||||
printf("%c", c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MAIN MICROSHELL FUNCTIONS -----------
|
||||
|
||||
char* GetCurrentUserAndDir() { // return current user + working directory
|
||||
char cwd[MAX_SIZE];
|
||||
if (getcwd(cwd, sizeof(cwd)) == NULL) {
|
||||
perror("getcwd() error");
|
||||
return NULL;
|
||||
}
|
||||
char* user = getenv("USER");
|
||||
if (user == NULL) {
|
||||
perror("getenv() error");
|
||||
return NULL;
|
||||
}
|
||||
printf("[%s@%s] $ ", user, cwd);
|
||||
|
||||
size_t result_size = strlen(user) + strlen(cwd) + 7; // Allocate memory (include extra space for format characters)
|
||||
char* result = (char*)malloc(result_size);
|
||||
|
||||
snprintf(result, result_size, "[%s@%s] $ ", user, cwd); // Format the prompt string
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int ChangeDirectory(char** args) { // cd
|
||||
@ -38,14 +157,12 @@ int ChangeDirectory(char** args) { // cd
|
||||
}
|
||||
|
||||
void PrintHelp() { // help
|
||||
printf("-------------------------------------------------");
|
||||
printf("-------------------------------------------------\n");
|
||||
printf("C Microshell implementation by Maciej Życzyński\n");
|
||||
printf("\"exit\" - exit the program");
|
||||
printf("\"help\" - display this menu");
|
||||
printf("Other bash commands work accordingly in child processes");
|
||||
printf("Currently logged user / working directory:");
|
||||
PrintCurrentDir();
|
||||
printf("-------------------------------------------------");
|
||||
printf("\"exit\" - exit the program\n");
|
||||
printf("\"help\" - display this menu\n");
|
||||
printf("Other bash commands work accordingly in child processes\n");
|
||||
printf("-------------------------------------------------\n");
|
||||
}
|
||||
|
||||
int HandleBuiltInCommands(char* command, char** args) { // Manual implementation of commands unsupported by execvp()
|
||||
@ -71,10 +188,9 @@ int HandleCommand(char* command, char** args) { // Execute commands supported by
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ParseCommand(char* buf, char** command, char** args) {
|
||||
int ParseCommand(char* buf, char** command, char** args) { // Parse input string into command and array of arguments
|
||||
char buf_cp[MAX_SIZE];
|
||||
strcpy(buf_cp, buf); // Leave the original buffer (important for command history implementation)
|
||||
buf_cp[strlen(buf_cp) - 1] = '\0'; // Remove newline from input string
|
||||
|
||||
char* token = strtok(buf_cp, " ");
|
||||
int tok_count = 0;
|
||||
@ -94,25 +210,39 @@ int ParseCommand(char* buf, char** command, char** args) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
char buf[MAX_SIZE];
|
||||
char* command_log[MAX_SIZE];
|
||||
char* command;
|
||||
char* args[MAX_SIZE];
|
||||
int n = 0;
|
||||
char* command_log[HISTORY_SIZE] = {NULL};
|
||||
|
||||
// Save original terminal settings and restore them on exit
|
||||
if (tcgetattr(STDIN_FILENO, &orig_termios) == -1) {
|
||||
perror("tcgetattr() error");
|
||||
return 1;
|
||||
}
|
||||
atexit(DisableRawModeWrapper); // call DisableRawModeWrapper when program exits
|
||||
|
||||
while (1) {
|
||||
PrintCurrentDir();
|
||||
char* prompt = GetCurrentUserAndDir(); // Display prompt
|
||||
if (prompt != NULL) {
|
||||
printf("%s", prompt);
|
||||
free(prompt);
|
||||
}
|
||||
|
||||
char* command;
|
||||
char* args[MAX_SIZE];
|
||||
fgets(buf, sizeof(buf), stdin);
|
||||
EnableRawMode(&orig_termios);
|
||||
GetRawInput(buf, command_log, n);
|
||||
DisableRawMode(&orig_termios);
|
||||
|
||||
if (ParseCommand(buf, &command, args) < 0) {
|
||||
|
||||
if (ParseCommand(buf, &command, args) < 0) { // Parse buffer input
|
||||
printf("Invalid command\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// LogCommandHistory(buf, &command_log, n);
|
||||
// n++;
|
||||
LogCommandHistory(buf, command_log, &n); // Add buffer to logging history
|
||||
|
||||
int handler_value = HandleBuiltInCommands(command, args);
|
||||
if (handler_value == 2) { // Exit command
|
||||
@ -140,5 +270,6 @@ int main() {
|
||||
}
|
||||
}
|
||||
|
||||
FreeCommandHistory(command_log, n);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user