history.c (4049B)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <stdbool.h> 4 #include <string.h> 5 #include <unistd.h> 6 #include <linux/limits.h> 7 8 #include "history.h" 9 #include "90s.h" 10 #include "constants.h" 11 12 FILE *history_file; 13 char *histfile_path; 14 int cmd_count = 0; 15 16 FILE *open_history_file(char *mode) { 17 history_file = fopen(histfile_path, mode); 18 if (history_file == NULL) { 19 fprintf(stderr, "90s: Error opening history file\n"); 20 exit(EXIT_FAILURE); 21 } 22 return history_file; 23 } 24 void check_history_file() { 25 char *env_home; 26 env_home = getenv("XDG_CONFIG_HOME"); 27 if (env_home == NULL) { 28 // fallback to $HOME if $XDG_CONFIG_HOME is null 29 env_home = getenv("HOME"); 30 } 31 if (env_home == NULL) { 32 fprintf(stderr, "90s: HOME AND XDG_CONFIG_HOME environment variable is missing\n"); 33 exit(EXIT_FAILURE); 34 } 35 int env_home_len = strlen(env_home); 36 int histfilename_len = strlen(HISTFILE); 37 int path_len = env_home_len + histfilename_len + 2; // 2 for slash and null byte 38 histfile_path = memalloc(sizeof(char) * path_len); 39 histfile_path[0] = '\0'; // initialise string 40 // concatenate home and history file name to a path 41 strcat(histfile_path, env_home); 42 strcat(histfile_path, "/"); 43 strcat(histfile_path, HISTFILE); 44 histfile_path[path_len - 1] = '\0'; 45 if (access(histfile_path, F_OK) != 0) { // check for file existence 46 history_file = open_history_file("w"); // read and write, if doesn't exist, create 47 fclose(history_file); 48 } 49 } 50 51 void save_command_history(char *args) { 52 history_file = open_history_file("a+"); 53 char cmd[RL_BUFSIZE]; 54 cmd[0] = '\0'; 55 strcat(cmd, args); 56 int cmd_len = strlen(cmd); 57 cmd[cmd_len] = '\n'; // put new line feed to split commands 58 // ptr to first obj, size of each obj, number of obj, file ptr 59 fwrite(cmd, sizeof(char), cmd_len + 1, history_file); 60 fclose(history_file); 61 } 62 63 char *read_command(int direction) { 64 if (direction == 1) { // up 65 cmd_count++; 66 } else { // down 67 if (cmd_count == 0) { 68 return NULL; 69 } else { 70 cmd_count--; 71 } 72 } 73 char **history = get_all_history(false); 74 int num_history = 0; 75 while (*history != NULL) { 76 num_history++; 77 history++; 78 } 79 if (cmd_count > num_history) { 80 cmd_count = num_history; 81 return NULL; 82 } 83 history -= num_history; 84 return history[num_history - cmd_count]; 85 } 86 87 int is_duplicate(char **history, int line_count, char *line) { 88 for (int i = 0; i < line_count; ++i) { 89 if (strcmp(history[i], line) == 0) { 90 return 1; 91 } 92 } 93 return 0; 94 } 95 96 char **get_all_history(bool check) { 97 history_file = open_history_file("r"); 98 char **history = memalloc(MAX_HISTORY * sizeof(char*)); 99 char buffer[RL_BUFSIZE]; 100 int line_count = 0; 101 102 while (fgets(buffer, sizeof(buffer), history_file) != NULL) { 103 buffer[strcspn(buffer, "\n")] = '\0'; 104 if (check) { 105 if (!is_duplicate(history, line_count, buffer)) { 106 history[line_count] = strdup(buffer); 107 if (history[line_count] == NULL) { 108 fprintf(stderr, "Error allocating memory\n"); 109 exit(EXIT_FAILURE); 110 } 111 line_count++; 112 if (line_count >= MAX_HISTORY) { 113 fprintf(stderr, "Maximum number of lines reached.\n"); 114 exit(EXIT_FAILURE); 115 } 116 } 117 } else { 118 history[line_count] = strdup(buffer); 119 if (history[line_count] == NULL) { 120 fprintf(stderr, "Error allocating memory\n"); 121 exit(EXIT_FAILURE); 122 } 123 line_count++; 124 if (line_count >= MAX_HISTORY) { 125 fprintf(stderr, "Maximum number of lines reached.\n"); 126 exit(EXIT_FAILURE); 127 } 128 } 129 } 130 131 fclose(history_file); 132 history[line_count] = NULL; 133 return history; 134 }