diff --git a/.gitignore b/.gitignore index aeb82b2..97bad5e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ build/ a.out val/ tmp* -test/ \ No newline at end of file +test/ +vgcore* \ No newline at end of file diff --git a/README.md b/README.md index 4b7bd26..688e212 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ Work is still in porgress, buf when you will see a "finished" topic assigned to * Running commands in separate process and termination them with `ctrl+c` * `cd`, `exit` and `exec` builtin commands * Files and commands from `/usr/bin` autocompletion on `Tab` keypress -* History of commands and navigation through it with `up/down` keys +* History of commands and navigation or search through it with `up/down` keys +* Username, ip address and current path in prompt before each command input # Builtin commands * `cd`: changes current working directory to the one specified by user. If no arguments provided, shows error. diff --git a/include/history.h b/include/history.h index ac10b36..78ee50f 100644 --- a/include/history.h +++ b/include/history.h @@ -2,7 +2,8 @@ #define _HISTORY_H void append_to_history(char *line); -void clear_search_tree(); -char *previous_hist_entry(); +void clear_sub_history(); +char *previous_hist_entry(char *line); +char *next_hist_entry(char *line); #endif \ No newline at end of file diff --git a/include/input.h b/include/input.h index 0a9e196..045c2ab 100644 --- a/include/input.h +++ b/include/input.h @@ -23,5 +23,6 @@ enum keys { void change_mode(int on); char *read_line(); int process_keypress(char c); +void free_input(int *pos, int *n, char **line); #endif \ No newline at end of file diff --git a/include/shell.h b/include/shell.h index 01b4a11..f140947 100644 --- a/include/shell.h +++ b/include/shell.h @@ -9,10 +9,13 @@ #include #include #include +#include #include #include +#include + #include "../include/tree.h" // Defines @@ -20,9 +23,9 @@ #define ARG_SIZE 32 // Types definitions -struct hist_tree +struct hist_sub { - struct tree_node *r; + char **content; int length; int pos; }; @@ -32,8 +35,9 @@ struct history char **content; int length; int pos; + char *curr_command; - struct hist_tree tree; + struct hist_sub sub; }; typedef struct diff --git a/src/history.c b/src/history.c index 5524646..42f9e54 100644 --- a/src/history.c +++ b/src/history.c @@ -1,5 +1,6 @@ #include "../include/history.h" #include "../include/shell.h" +#include "../include/utils.h" /** * @brief Append entry to commands history @@ -12,6 +13,9 @@ void append_to_history(char *line) if (strcmp(line, term.hist.content[term.hist.length - 1]) == 0) return; + if (line[0] == '\0') + return; + term.hist.length++; term.hist.content = (char **)realloc(term.hist.content, term.hist.length * sizeof(char *)); term.hist.content[term.hist.length - 1] = strdup(line); @@ -19,15 +23,13 @@ void append_to_history(char *line) term.hist.pos = -1; } -/** - * @brief Clear history entries search tree - * - */ -void clear_search_tree() +void clear_sub_history() { - term.hist.tree.length = -1; - term.hist.tree.pos = -1; - free_tree(term.hist.tree.r); + free(term.hist.sub.content); + + term.hist.sub.content = malloc(0); + term.hist.sub.length = -1; + term.hist.sub.pos = -1; } /** @@ -38,9 +40,78 @@ void clear_search_tree() */ char *previous_hist_entry(char *line) { + static int h_size; if (line == NULL) { + if (term.hist.pos + 1 == term.hist.length) + return NULL; + term.hist.pos++; - return term.hist.content[term.hist.length - term.hist.pos - 1]; + return strdup(term.hist.content[term.hist.length - term.hist.pos - 1]); } + + if (term.hist.sub.length < 0) + { + term.hist.sub.length++; + for (int i = 0; i < term.hist.length; i++) + if (strncmp(term.hist.content[i], line, strlen(line)) == 0) + { + term.hist.sub.length++; + term.hist.sub.content = realloc(term.hist.sub.content, term.hist.sub.length * sizeof(char *)); + term.hist.sub.content[term.hist.sub.length - 1] = term.hist.content[i]; + } + h_size = term.hist.sub.length; + } + else + { + int tmp_len = term.hist.sub.length; + term.hist.sub.length = 0; + for (int i = 0; i < tmp_len; i++) + if (strncmp(term.hist.sub.content[i], line, strlen(line)) == 0) + { + term.hist.sub.length++; + term.hist.sub.content[term.hist.sub.length - 1] = term.hist.sub.content[i]; + } + term.hist.sub.content = realloc(term.hist.sub.content, term.hist.sub.length * sizeof(char *)); + + if (term.hist.sub.length != h_size) + { + h_size = term.hist.sub.length; + term.hist.sub.pos = -1; + } + } + + term.hist.sub.pos++; + + if (term.hist.sub.pos >= term.hist.sub.length) + { + term.hist.sub.pos = term.hist.sub.length - 1; + return NULL; + } + + return strdup(term.hist.sub.content[term.hist.sub.length - term.hist.sub.pos - 1]); +} + +/** + * @brief Get next history entry + * + * @param line + * @return char* + */ +char *next_hist_entry(char *line) +{ + if (line == NULL) + { + if (term.hist.pos == 0) + return NULL; + + term.hist.pos--; + return strdup(term.hist.content[term.hist.length - term.hist.pos - 1]); + } + + if (term.hist.sub.pos <= 0) + return NULL; + + term.hist.sub.pos--; + return strdup(term.hist.sub.content[term.hist.sub.length - term.hist.sub.pos - 1]); } \ No newline at end of file diff --git a/src/input.c b/src/input.c index 55fef00..93d2700 100644 --- a/src/input.c +++ b/src/input.c @@ -1,6 +1,7 @@ #include "../include/input.h" #include "../include/keys.h" #include "../include/shell.h" +#include "../include/output.h" /** * @brief Switches console raw mode @@ -43,10 +44,6 @@ char *read_line() { switch (c) { - case DELETE_KEY: - delete_key(pos, &n, &line); - break; - case UP_KEY: up_key(&pos, &n, &line); break; @@ -55,46 +52,57 @@ char *read_line() down_key(&pos, &n, &line); break; - case LEFT_KEY: - move_left(&pos); - break; - - case RIGHT_KEY: - move_right(&pos, n); - break; - - case HOME_KEY: - home_key(&pos); - break; - - case END_KEY: - end_key(&pos, n); - break; - - case BACKSPACE_KEY: - backspace_key(&pos, &n, &line); - break; - - case ENTER_KEY: - new_line(line); - - return line; - break; - - case TAB_KEY: - { - tab_key(&pos, &n, &line); - } - break; - - case ESCAPE_KEY: - break; - default: - if ((c > 31 && c < 127) || (c > 127 && c < 255)) - printable_key(&pos, &n, (char)c, &line); + term.hist.pos = -1; + switch (c) + { + + case DELETE_KEY: + delete_key(pos, &n, &line); + break; + + case LEFT_KEY: + move_left(&pos); + break; + + case RIGHT_KEY: + move_right(&pos, n); + break; + + case HOME_KEY: + home_key(&pos); + break; + + case END_KEY: + end_key(&pos, n); + break; + + case BACKSPACE_KEY: + backspace_key(&pos, &n, &line); + break; + + case ENTER_KEY: + new_line(line); + + return line; + break; + + case TAB_KEY: + { + tab_key(&pos, &n, &line); + } break; + + case ESCAPE_KEY: + break; + + default: + if ((c > 31 && c < 127) || (c > 127 && c < 255)) + printable_key(&pos, &n, (char)c, &line); + + break; + } } } } @@ -137,7 +145,7 @@ int process_keypress(char c) case 'B': return DOWN_KEY; - break; + break; case 'C': return RIGHT_KEY; @@ -174,4 +182,24 @@ int process_keypress(char c) { return c; } +} + +void free_input(int *pos, int *n, char **line) +{ + char *buff = strdup(""); + size_t buff_size = 1; + + free(*line); + *line = strdup(""); + *n = 0; + + for (int i = 0; i < *pos; i++) + append_to_buff(&buff, &buff_size, "\033[D", 3); + + append_to_buff(&buff, &buff_size, "\033[K", 3); + + *pos = *n; + + print_str(buff, buff_size); + free(buff); } \ No newline at end of file diff --git a/src/keys.c b/src/keys.c index 5fde5ee..ae83bea 100644 --- a/src/keys.c +++ b/src/keys.c @@ -4,6 +4,7 @@ #include "../include/complete.h" #include "../include/shell.h" #include "../include/history.h" +#include "../include/input.h" /** * @brief Delete key action @@ -41,68 +42,36 @@ void delete_key(int pos, int *n, char **line) */ void up_key(int *pos, int *n, char **line) { - if (term.hist.pos + 1 == term.hist.length) - return; - print_str("\033[K", 3); - (*line)[*pos] = '\0'; + char *buff = strdup("\033[K"); + size_t buff_size = 4; - char *buff = strdup(""); - size_t buff_size = 1; + char *entry = NULL; if (*pos == 0) - { - *line = strdup(previous_hist_entry(NULL)); - *n = strlen(*line); - - append_to_buff(&buff, &buff_size, "\0337", 2); - append_to_buff(&buff, &buff_size, *line, *n); - append_to_buff(&buff, &buff_size, "\0338", 2); - - print_str(buff, buff_size); - free(buff); - } + entry = previous_hist_entry(NULL); else { - if (term.hist.tree.length < 0) - { - term.hist.tree.r = get_new_node(); - for (int i = 0; i < term.hist.length; i++) - insert_tree(term.hist.tree.r, term.hist.content[i]); - - term.hist.tree.length = term.hist.length; - term.hist.tree.pos = 0; - } - - char **tmp_strings = malloc(0); - ssize_t sz = list_strings_containing(term.hist.tree.r, *line, &tmp_strings); - - if (sz < 1) - { - free(buff); - return; - } - - free(*line); - *line = strdup(tmp_strings[term.hist.tree.pos]); - *n = strlen(*line); - - append_to_buff(&buff, &buff_size, "\033[2K", 4); - append_to_buff(&buff, &buff_size, "\033[2A", 4); - - char *prompt = compose_prompt(); - append_to_buff(&buff, &buff_size, prompt, strlen(prompt)); - - append_to_buff(&buff, &buff_size, *line, *n); - for (int i = 0; i < *n - *pos; i++) - append_to_buff(&buff, &buff_size, "\033[D", 3); - - print_str(buff, buff_size); - free(buff); - - for (int i = 0; i < sz; i++) - insert_tree(term.hist.tree.r, tmp_strings[i]); + (*line)[*pos] = '\0'; + entry = previous_hist_entry(*line); } + + if (entry == NULL) + { + free(buff); + return; + } + + free(*line); + *line = entry; + *n = strlen(*line); + + append_to_buff(&buff, &buff_size, "\0337", 2); + append_to_buff(&buff, &buff_size, *line + *pos, *n - *pos); + append_to_buff(&buff, &buff_size, "\0338", 2); + + print_str(buff, buff_size); + free(buff); } /** @@ -114,49 +83,58 @@ void up_key(int *pos, int *n, char **line) */ void down_key(int *pos, int *n, char **line) { - if (term.hist.pos < 0) - return; - print_str("\033[K", 3); - (*line)[*pos] = '\0'; + char *buff = strdup("\033[K"); + size_t buff_size = 4; - char *buff = strdup(""); - size_t buff_size = 1; - - if (term.hist.pos == 0) - { - term.hist.pos--; - - free(*line); - *line = strdup(buff); - *n = 0; - *pos = *n; - - for (int i = 0; i < *pos; i++) - append_to_buff(&buff, &buff_size, "\033[D", 3); - - append_to_buff(&buff, &buff_size, "\033[K", 3); - - print_str(buff, buff_size); - free(buff); - - return; - } + char *entry = NULL; if (*pos == 0) { - term.hist.pos--; - *line = strdup(term.hist.content[term.hist.length - term.hist.pos - 1]); - *n = strlen(*line); + if (term.hist.pos <= 0) + { + if (term.hist.pos == 0) + term.hist.pos--; - append_to_buff(&buff, &buff_size, "\0337", 2); - append_to_buff(&buff, &buff_size, *line, *n); - append_to_buff(&buff, &buff_size, "\0338", 2); + free(buff); + free_input(pos, n, line); + return; + } - print_str(buff, buff_size); - free(buff); + entry = next_hist_entry(NULL); + } + else + { + (*line)[*pos] = '\0'; + + if (term.hist.sub.pos <= 0) + { + if (term.hist.sub.pos == 0) + term.hist.sub.pos--; + + free(buff); + free_input(pos, n, line); + return; + } + + entry = next_hist_entry(*line); } + if (entry == NULL) + { + free(buff); + return; + } + + *line = entry; + *n = strlen(*line); + + append_to_buff(&buff, &buff_size, "\0337", 2); + append_to_buff(&buff, &buff_size, *line + *pos, *n - *pos); + append_to_buff(&buff, &buff_size, "\0338", 2); + + print_str(buff, buff_size); + free(buff); } /** @@ -166,7 +144,7 @@ void down_key(int *pos, int *n, char **line) */ void move_left(int *pos) { - clear_search_tree(); + clear_sub_history(); if (*pos > 0) { print_str("\033[D", 3); @@ -186,6 +164,8 @@ void move_right(int *pos, int n) { print_str("\033[C", 3); (*pos)++; + + clear_sub_history(); } } @@ -196,7 +176,8 @@ void move_right(int *pos, int n) */ void home_key(int *pos) { - clear_search_tree(); + clear_sub_history(); + char *buff = strdup(""); size_t buff_size = 1; @@ -241,7 +222,7 @@ void backspace_key(int *pos, int *n, char **line) { if (*pos > 0) { - clear_search_tree(); + clear_sub_history(); remove_on_pos(line, *pos); (*n)--; @@ -269,7 +250,7 @@ void backspace_key(int *pos, int *n, char **line) void new_line(char *line) { append_to_history(line); - clear_search_tree(); + clear_sub_history(); print_str("\n", 1); } @@ -282,7 +263,7 @@ void new_line(char *line) */ void tab_key(int *pos, int *n, char **line) { - clear_search_tree(); + clear_sub_history(); (*line)[*pos] = '\0'; *line = realloc(*line, strlen(*line) + 1); diff --git a/src/main.c b/src/main.c index 3b98a9c..052eeb8 100644 --- a/src/main.c +++ b/src/main.c @@ -44,9 +44,9 @@ t_ init_term() term.hist.pos = -1; term.hist.content = (char **)malloc(sizeof(char *) * term.hist.length); - term.hist.tree.length = -1; - term.hist.tree.pos = -1; - term.hist.tree.r = NULL; + term.hist.sub.length = -1; + term.hist.sub.pos = -1; + term.hist.sub.content = (char **)malloc(sizeof(char *) * 0); signal(SIGINT, SIG_IGN); diff --git a/src/shell.c b/src/shell.c index 8d3db7c..f37c6bc 100644 --- a/src/shell.c +++ b/src/shell.c @@ -166,6 +166,31 @@ int sh_exec(char **args) exit(EXIT_FAILURE); } +char *get_ip_addr() +{ + struct ifaddrs *host, *tmp; + getifaddrs(&host); + tmp = host; + char *ip = NULL; + + while (tmp) + { + if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET) + { + struct sockaddr_in *pAddr = (struct sockaddr_in *)tmp->ifa_addr; + ip = inet_ntoa(pAddr->sin_addr); + if (strncmp(ip, "127", 3) != 0) + break; + } + + tmp = tmp->ifa_next; + } + + freeifaddrs(host); + + return ip; +} + /** * @brief Creates prompt string * @@ -173,14 +198,38 @@ int sh_exec(char **args) */ char *compose_prompt() { + // New line char *prompt = strdup("\n"); + // Username + char *username = getenv("USER"); + if (username == NULL) + username = "none"; + prompt = realloc(prompt, strlen(prompt) + strlen("\033[97;44m") + strlen(username) + 2); + prompt = strcat(prompt, "\033[97;44m"); + prompt = strcat(prompt, username); + + // Current host ip + char *ip = get_ip_addr(); + if (ip == NULL) + ip = "none"; + prompt = realloc(prompt, strlen(prompt) + 1 + strlen(ip) + strlen("\033[39m") + strlen("\033[48;2;28;32;35m") + 2); + prompt = strcat(prompt, "@"); + prompt = strcat(prompt, ip); + prompt = strcat(prompt, "\033[39m"); + prompt = strcat(prompt, "\033[48;2;28;32;35m"); + prompt = strcat(prompt, ":"); + + // Current path char *full_path = get_current_dir_name(); - prompt = realloc(prompt, strlen(prompt) + strlen(full_path) + 2); + prompt = realloc(prompt, strlen(prompt) + strlen("\033[92;1m") + strlen("\033[39;0m") + strlen(full_path) + 2); + prompt = strcat(prompt, "\033[92;1m"); prompt = strcat(prompt, full_path); + prompt = strcat(prompt, "\033[39;0m"); free(full_path); + // Permissions specific character before user input prompt = realloc(prompt, strlen(prompt) + 4); if (getuid() == 0) { diff --git a/src/utils.c b/src/utils.c index 085dad7..360513e 100644 --- a/src/utils.c +++ b/src/utils.c @@ -21,8 +21,6 @@ void append_to_pos(char **str, int pos, char ch) (*str)[pos] = ch; (*str)[len + 1] = '\0'; } - else - fprintf(stderr, "Can't add \"%c\" symbol outside of the string\n", ch); } /** @@ -42,8 +40,6 @@ void remove_on_pos(char **str, int pos) (*str)[len] = '\0'; *str = realloc(*str, len); } - else - fprintf(stderr, "Can't remove symbol outside the string\n"); } /** @@ -146,7 +142,7 @@ char **slice_array(char **arr, int beg, int end, bool asc) int get_null_term_arr_size(char **arr) { int k = 0; - for (int i = 0; arr[i]!= NULL; i++) + for (int i = 0; arr[i] != NULL; i++) k++; return k;