navhistory.c (3718B)
1 static char *histfile; 2 static char **history; 3 static size_t histsz, histpos; 4 static size_t cap = 0; 5 static struct item *backup_items = NULL; 6 7 void 8 cleanhistory(void) 9 { 10 int i; 11 12 for (i = 0; i < histsz; i++) { 13 free(history[i]); 14 } 15 free(history); 16 } 17 18 void 19 loadhistory(void) 20 { 21 FILE *fp = NULL; 22 size_t llen; 23 char *line; 24 25 if (!histfile) { 26 return; 27 } 28 29 fp = fopen(histfile, "r"); 30 if (!fp) { 31 return; 32 } 33 34 for (;;) { 35 line = NULL; 36 llen = 0; 37 if (-1 == getline(&line, &llen, fp)) { 38 if (ferror(fp)) { 39 die("failed to read history"); 40 } 41 free(line); 42 break; 43 } 44 45 addhistory(line); 46 free(line); 47 } 48 histpos = histsz; 49 50 if (fclose(fp)) { 51 die("failed to close file %s", histfile); 52 } 53 } 54 55 void 56 navhistory(int dir) 57 { 58 static char def[BUFSIZ]; 59 char *p = NULL; 60 size_t len = 0; 61 62 if (!history || histpos + 1 == 0) 63 return; 64 65 if (histsz == histpos) { 66 strncpy(def, text, sizeof(def)); 67 } 68 69 switch(dir) { 70 case 1: 71 if (histpos < histsz - 1) { 72 p = history[++histpos]; 73 } else if (histpos == histsz - 1) { 74 p = def; 75 histpos++; 76 } 77 break; 78 case -1: 79 if (histpos > 0) { 80 p = history[--histpos]; 81 } 82 break; 83 } 84 if (p == NULL) { 85 return; 86 } 87 88 len = MIN(strlen(p), BUFSIZ - 1); 89 strncpy(text, p, len); 90 text[len] = '\0'; 91 cursor = len; 92 match(); 93 } 94 95 void 96 addhistory(char *input) 97 { 98 unsigned int i; 99 100 if (!histfile || 101 0 == maxhist || 102 0 == strlen(input)) { 103 return; 104 } 105 106 strtok(input, "\n"); 107 108 if (histnodup) { 109 for (i = 0; i < histsz; i++) { 110 if (!strcmp(input, history[i])) { 111 return; 112 } 113 } 114 } 115 116 if (cap == histsz) { 117 reallochistory(); 118 } 119 120 history[histsz] = strdup(input); 121 histsz++; 122 } 123 124 void 125 addhistoryitem(struct item *item) 126 { 127 #if SEPARATOR_PATCH 128 if (separator && item->text_output && item->text != item->text_output) { 129 int histlen = strlen(item->text) + strlen(item->text_output) + 2; 130 char *histitem = ecalloc(histlen + 1, sizeof(char *)); 131 snprintf(histitem, histlen, "%s%c%s", item->text, separator, item->text_output); 132 addhistory(histitem); 133 free(histitem); 134 return; 135 } 136 #endif // SEPARATOR_PATCH 137 138 addhistory(item->text); 139 } 140 141 void 142 reallochistory(void) 143 { 144 size_t oldcap = cap; 145 cap += 64; 146 char **newhistory = realloc(history, cap * sizeof *history); 147 if (!newhistory) { 148 die("failed to realloc memory"); 149 } 150 151 history = newhistory; 152 memset(history + oldcap, 0, (cap - oldcap) * sizeof *history); 153 } 154 155 void 156 togglehistoryitems(void) 157 { 158 int i; 159 #if SEPARATOR_PATCH || TSV_PATCH 160 char *p; 161 #endif // SEPARATOR_PATCH 162 163 if (!histfile) 164 return; 165 166 if (backup_items) { 167 restorebackupitems(); 168 return; 169 } 170 171 backup_items = items; 172 items = calloc(histsz + 1, sizeof(struct item)); 173 if (!items) { 174 die("cannot allocate memory"); 175 } 176 177 for (i = 0; i < histsz; i++) { 178 items[i].text = strdup(history[i]); 179 #if SEPARATOR_PATCH 180 if (separator && (p = sepchr(items[i].text, separator)) != NULL) { 181 *p = '\0'; 182 items[i].text_output = ++p; 183 } else { 184 items[i].text_output = items[i].text; 185 } 186 #elif TSV_PATCH 187 items[i].stext = strdup(items[i].text); 188 if ((p = strchr(items[i].stext, '\t'))) 189 *p = '\0'; 190 #endif // SEPARATOR_PATCH 191 } 192 } 193 194 void 195 restorebackupitems(void) 196 { 197 size_t i; 198 199 if (!backup_items) 200 return; 201 202 for (i = 0; items && items[i].text; ++i) { 203 free(items[i].text); 204 } 205 free(items); 206 207 items = backup_items; 208 backup_items = NULL; 209 } 210 211 void 212 savehistory(void) 213 { 214 unsigned int i; 215 FILE *fp; 216 217 if (!histfile || 0 == maxhist) 218 return; 219 220 fp = fopen(histfile, "w"); 221 if (!fp) { 222 die("failed to open %s", histfile); 223 } 224 225 for (i = histsz < maxhist ? 0 : histsz - maxhist; i < histsz; i++) { 226 if (0 >= fprintf(fp, "%s\n", history[i])) { 227 die("failed to write to %s", histfile); 228 } 229 } 230 231 if (fclose(fp)) { 232 die("failed to close file %s", histfile); 233 } 234 }