90s

Minimalist, customizable shell written in C99 with syntax highlighting
git clone https://codeberg.org/night0721/90s
Log | Files | Refs | README | LICENSE

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 }