NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
history.c File Reference

Read/write command history from/to a file. More...

#include "config.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "core/lib.h"
#include "lib.h"
+ Include dependency graph for history.c:

Go to the source code of this file.

Data Structures

struct  History
 Saved list of user-entered commands/searches. More...
 

Macros

#define HC_FIRST   HC_CMD
 

Functions

static struct Historyget_history (enum HistoryClass hclass)
 Get a particular history. More...
 
static void init_history (struct History *h)
 Set up a new History ring buffer. More...
 
static int dup_hash_dec (struct HashTable *dup_hash, char *str)
 Decrease the refcount of a history string. More...
 
static int dup_hash_inc (struct HashTable *dup_hash, char *str)
 Increase the refcount of a history string. More...
 
static void shrink_histfile (void)
 Read, de-dupe and write the history file. More...
 
static void save_history (enum HistoryClass hclass, const char *str)
 Save one history string to a file. More...
 
static void remove_history_dups (enum HistoryClass hclass, const char *str)
 De-dupe the history. More...
 
int mutt_hist_search (const char *search_buf, enum HistoryClass hclass, char **matches)
 Find matches in a history list. More...
 
void mutt_hist_free (void)
 Free all the history lists. More...
 
void mutt_hist_init (void)
 Create a set of empty History ring buffers. More...
 
void mutt_hist_add (enum HistoryClass hclass, const char *str, bool save)
 Add a string to a history. More...
 
char * mutt_hist_next (enum HistoryClass hclass)
 Get the next string in a History. More...
 
char * mutt_hist_prev (enum HistoryClass hclass)
 Get the previous string in a History. More...
 
void mutt_hist_reset_state (enum HistoryClass hclass)
 Move the 'current' position to the end of the History. More...
 
void mutt_hist_read_file (void)
 Read the History from a file. More...
 
bool mutt_hist_at_scratch (enum HistoryClass hclass)
 Is the current History position at the 'scratch' place? More...
 
void mutt_hist_save_scratch (enum HistoryClass hclass, const char *str)
 Save a temporary string to the History. More...
 

Variables

static struct History Histories [HC_MAX]
 
static int OldSize = 0
 

Detailed Description

Read/write command history from/to a file.

Authors
  • Michael R. Elkins

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file history.c.

Macro Definition Documentation

◆ HC_FIRST

#define HC_FIRST   HC_CMD

Definition at line 81 of file history.c.

Function Documentation

◆ get_history()

static struct History* get_history ( enum HistoryClass  hclass)
static

Get a particular history.

Parameters
hclassType of history to find
Return values
ptrHistory ring buffer

Definition at line 105 of file history.c.

106 {
107  const short c_history = cs_subset_number(NeoMutt->sub, "history");
108  if ((hclass >= HC_MAX) || (c_history == 0))
109  return NULL;
110 
111  struct History *hist = &Histories[hclass];
112  return hist->hist ? hist : NULL;
113 }
static struct History Histories[HC_MAX]
Definition: history.c:97
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
Container for Accounts, Notifications.
Definition: neomutt.h:36
Saved list of user-entered commands/searches.
Definition: history.c:88
char ** hist
Definition: history.c:90
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
Definition: lib.h:55
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ init_history()

static void init_history ( struct History h)
static

Set up a new History ring buffer.

Parameters
hHistory to populate

If the History already has entries, they will be freed.

Definition at line 121 of file history.c.

122 {
123  if (OldSize != 0)
124  {
125  if (h->hist)
126  {
127  for (int i = 0; i <= OldSize; i++)
128  FREE(&h->hist[i]);
129  FREE(&h->hist);
130  }
131  }
132 
133  const short c_history = cs_subset_number(NeoMutt->sub, "history");
134  if (c_history != 0)
135  h->hist = mutt_mem_calloc(c_history + 1, sizeof(char *));
136 
137  h->cur = 0;
138  h->last = 0;
139 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
static int OldSize
Definition: history.c:98
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
Container for Accounts, Notifications.
Definition: neomutt.h:36
short cur
Definition: history.c:91
short last
Definition: history.c:92
#define FREE(x)
Definition: memory.h:40
char ** hist
Definition: history.c:90
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ dup_hash_dec()

static int dup_hash_dec ( struct HashTable dup_hash,
char *  str 
)
static

Decrease the refcount of a history string.

Parameters
dup_hashHash Table containing unique history strings
strString to find
Return values
0String was deleted from the Hash Table
>0Refcount of string
-1Error, string not found

If the string's refcount is 1, then the string will be deleted.

Definition at line 151 of file history.c.

152 {
153  struct HashElem *elem = mutt_hash_find_elem(dup_hash, str);
154  if (!elem)
155  return -1;
156 
157  uintptr_t count = (uintptr_t) elem->data;
158  if (count <= 1)
159  {
160  mutt_hash_delete(dup_hash, str, NULL);
161  return 0;
162  }
163 
164  count--;
165  elem->data = (void *) count;
166  return count;
167 }
struct HashElem * mutt_hash_find_elem(const struct HashTable *table, const char *strkey)
Find the HashElem in a Hash Table element using a key.
Definition: hash.c:369
void * data
User-supplied data.
Definition: hash.h:47
void mutt_hash_delete(struct HashTable *table, const char *strkey, const void *data)
Remove an element from a Hash Table.
Definition: hash.c:419
The item stored in a Hash Table.
Definition: hash.h:43
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ dup_hash_inc()

static int dup_hash_inc ( struct HashTable dup_hash,
char *  str 
)
static

Increase the refcount of a history string.

Parameters
dup_hashHash Table containing unique history strings
strString to find
Return values
numRefcount of string

If the string isn't found it will be added to the Hash Table.

Definition at line 177 of file history.c.

178 {
179  uintptr_t count;
180 
181  struct HashElem *elem = mutt_hash_find_elem(dup_hash, str);
182  if (!elem)
183  {
184  count = 1;
185  mutt_hash_insert(dup_hash, str, (void *) count);
186  return count;
187  }
188 
189  count = (uintptr_t) elem->data;
190  count++;
191  elem->data = (void *) count;
192  return count;
193 }
struct HashElem * mutt_hash_insert(struct HashTable *table, const char *strkey, void *data)
Add a new element to the Hash Table (with string keys)
Definition: hash.c:327
struct HashElem * mutt_hash_find_elem(const struct HashTable *table, const char *strkey)
Find the HashElem in a Hash Table element using a key.
Definition: hash.c:369
void * data
User-supplied data.
Definition: hash.h:47
The item stored in a Hash Table.
Definition: hash.h:43
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ shrink_histfile()

static void shrink_histfile ( void  )
static

Read, de-dupe and write the history file.

Definition at line 198 of file history.c.

199 {
200  FILE *fp_tmp = NULL;
201  int n[HC_MAX] = { 0 };
202  int line, hclass, read;
203  char *linebuf = NULL, *p = NULL;
204  size_t buflen;
205  bool regen_file = false;
206  struct HashTable *dup_hashes[HC_MAX] = { 0 };
207 
208  const char *const c_history_file =
209  cs_subset_path(NeoMutt->sub, "history_file");
210  FILE *fp = mutt_file_fopen(c_history_file, "r");
211  if (!fp)
212  return;
213 
214  const bool c_history_remove_dups =
215  cs_subset_bool(NeoMutt->sub, "history_remove_dups");
216  const short c_save_history = cs_subset_number(NeoMutt->sub, "save_history");
217  if (c_history_remove_dups)
218  {
219  for (hclass = 0; hclass < HC_MAX; hclass++)
220  dup_hashes[hclass] = mutt_hash_new(MAX(10, c_save_history * 2), MUTT_HASH_STRDUP_KEYS);
221  }
222 
223  line = 0;
224  while ((linebuf = mutt_file_read_line(linebuf, &buflen, fp, &line, MUTT_RL_NO_FLAGS)))
225  {
226  if ((sscanf(linebuf, "%d:%n", &hclass, &read) < 1) || (read == 0) ||
227  (*(p = linebuf + strlen(linebuf) - 1) != '|') || (hclass < 0))
228  {
229  mutt_error(_("Bad history file format (line %d)"), line);
230  goto cleanup;
231  }
232  /* silently ignore too high class (probably newer neomutt) */
233  if (hclass >= HC_MAX)
234  continue;
235  *p = '\0';
236  if (c_history_remove_dups && (dup_hash_inc(dup_hashes[hclass], linebuf + read) > 1))
237  {
238  regen_file = true;
239  continue;
240  }
241  n[hclass]++;
242  }
243 
244  if (!regen_file)
245  {
246  for (hclass = HC_FIRST; hclass < HC_MAX; hclass++)
247  {
248  if (n[hclass] > c_save_history)
249  {
250  regen_file = true;
251  break;
252  }
253  }
254  }
255 
256  if (regen_file)
257  {
258  fp_tmp = mutt_file_mkstemp();
259  if (!fp_tmp)
260  {
261  mutt_perror(_("Can't create temporary file"));
262  goto cleanup;
263  }
264  rewind(fp);
265  line = 0;
266  while ((linebuf = mutt_file_read_line(linebuf, &buflen, fp, &line, MUTT_RL_NO_FLAGS)))
267  {
268  if ((sscanf(linebuf, "%d:%n", &hclass, &read) < 1) || (read == 0) ||
269  (*(p = linebuf + strlen(linebuf) - 1) != '|') || (hclass < 0))
270  {
271  mutt_error(_("Bad history file format (line %d)"), line);
272  goto cleanup;
273  }
274  if (hclass >= HC_MAX)
275  continue;
276  *p = '\0';
277  if (c_history_remove_dups && (dup_hash_dec(dup_hashes[hclass], linebuf + read) > 0))
278  {
279  continue;
280  }
281  *p = '|';
282  if (n[hclass]-- <= c_save_history)
283  fprintf(fp_tmp, "%s\n", linebuf);
284  }
285  }
286 
287 cleanup:
288  mutt_file_fclose(&fp);
289  FREE(&linebuf);
290  if (fp_tmp)
291  {
292  if ((fflush(fp_tmp) == 0) && (fp = fopen(NONULL(c_history_file), "w")))
293  {
294  rewind(fp_tmp);
295  mutt_file_copy_stream(fp_tmp, fp);
296  mutt_file_fclose(&fp);
297  }
298  mutt_file_fclose(&fp_tmp);
299  }
300  if (c_history_remove_dups)
301  for (hclass = 0; hclass < HC_MAX; hclass++)
302  mutt_hash_free(&dup_hashes[hclass]);
303 }
#define NONULL(x)
Definition: string2.h:37
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
A Hash Table.
Definition: hash.h:87
#define mutt_error(...)
Definition: logging.h:88
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:449
#define HC_FIRST
Definition: history.c:81
#define _(a)
Definition: message.h:28
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition: file.c:667
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
#define mutt_perror(...)
Definition: logging.h:89
Container for Accounts, Notifications.
Definition: neomutt.h:36
#define MAX(a, b)
Definition: memory.h:30
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
#define mutt_file_mkstemp()
Definition: file.h:108
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:271
static int dup_hash_dec(struct HashTable *dup_hash, char *str)
Decrease the refcount of a history string.
Definition: history.c:151
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:38
#define FREE(x)
Definition: memory.h:40
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
#define MUTT_HASH_STRDUP_KEYS
make a copy of the keys
Definition: hash.h:102
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:589
Definition: lib.h:55
struct HashTable * mutt_hash_new(size_t num_elems, HashFlags flags)
Create a new Hash Table (with string keys)
Definition: hash.c:251
static int dup_hash_inc(struct HashTable *dup_hash, char *str)
Increase the refcount of a history string.
Definition: history.c:177
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ save_history()

static void save_history ( enum HistoryClass  hclass,
const char *  str 
)
static

Save one history string to a file.

Parameters
hclassHistory type
strString to save

Definition at line 310 of file history.c.

311 {
312  static int n = 0;
313  char *tmp = NULL;
314 
315  if (!str || (*str == '\0')) /* This shouldn't happen, but it's safer. */
316  return;
317 
318  const char *const c_history_file =
319  cs_subset_path(NeoMutt->sub, "history_file");
320  FILE *fp = mutt_file_fopen(c_history_file, "a");
321  if (!fp)
322  return;
323 
324  tmp = mutt_str_dup(str);
325  const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
326  mutt_ch_convert_string(&tmp, c_charset, "utf-8", MUTT_ICONV_NO_FLAGS);
327 
328  /* Format of a history item (1 line): "<histclass>:<string>|".
329  * We add a '|' in order to avoid lines ending with '\'. */
330  fprintf(fp, "%d:", (int) hclass);
331  for (char *p = tmp; *p; p++)
332  {
333  /* Don't copy \n as a history item must fit on one line. The string
334  * shouldn't contain such a character anyway, but as this can happen
335  * in practice, we must deal with that. */
336  if (*p != '\n')
337  putc((unsigned char) *p, fp);
338  }
339  fputs("|\n", fp);
340 
341  mutt_file_fclose(&fp);
342  FREE(&tmp);
343 
344  if (--n < 0)
345  {
346  const short c_save_history = cs_subset_number(NeoMutt->sub, "save_history");
347  n = c_save_history;
348  shrink_histfile();
349  }
350 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition: charset.c:758
#define MUTT_ICONV_NO_FLAGS
No flags are set.
Definition: charset.h:71
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
Container for Accounts, Notifications.
Definition: neomutt.h:36
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
#define FREE(x)
Definition: memory.h:40
static void shrink_histfile(void)
Read, de-dupe and write the history file.
Definition: history.c:198
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:589
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ remove_history_dups()

static void remove_history_dups ( enum HistoryClass  hclass,
const char *  str 
)
static

De-dupe the history.

Parameters
hclassHistory to de-dupe
strString to find

If the string is found, it is removed from the history.

When removing dups, we want the created "blanks" to be right below the resulting h->last position. See the comment section above 'struct History'.

Definition at line 362 of file history.c.

363 {
364  struct History *h = get_history(hclass);
365  if (!h)
366  return; /* disabled */
367 
368  /* Remove dups from 0..last-1 compacting up. */
369  int source = 0;
370  int dest = 0;
371  while (source < h->last)
372  {
373  if (mutt_str_equal(h->hist[source], str))
374  FREE(&h->hist[source++]);
375  else
376  h->hist[dest++] = h->hist[source++];
377  }
378 
379  /* Move 'last' entry up. */
380  h->hist[dest] = h->hist[source];
381  int old_last = h->last;
382  h->last = dest;
383 
384  /* Fill in moved entries with NULL */
385  while (source > h->last)
386  h->hist[source--] = NULL;
387 
388  /* Remove dups from last+1 .. `$history` compacting down. */
389  const short c_history = cs_subset_number(NeoMutt->sub, "history");
390  source = c_history;
391  dest = c_history;
392  while (source > old_last)
393  {
394  if (mutt_str_equal(h->hist[source], str))
395  FREE(&h->hist[source--]);
396  else
397  h->hist[dest--] = h->hist[source--];
398  }
399 
400  /* Fill in moved entries with NULL */
401  while (dest > old_last)
402  h->hist[dest--] = NULL;
403 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
Container for Accounts, Notifications.
Definition: neomutt.h:36
Saved list of user-entered commands/searches.
Definition: history.c:88
static struct History * get_history(enum HistoryClass hclass)
Get a particular history.
Definition: history.c:105
short last
Definition: history.c:92
#define FREE(x)
Definition: memory.h:40
char ** hist
Definition: history.c:90
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_hist_search()

int mutt_hist_search ( const char *  search_buf,
enum HistoryClass  hclass,
char **  matches 
)

Find matches in a history list.

Parameters
[in]search_bufString to find
[in]hclassHistory list
[out]matchesAll the matching lines
Return values
numMatches found

Definition at line 412 of file history.c.

413 {
414  if (!search_buf || !matches)
415  return 0;
416 
417  struct History *h = get_history(hclass);
418  if (!h)
419  return 0;
420 
421  int match_count = 0;
422  int cur = h->last;
423  const short c_history = cs_subset_number(NeoMutt->sub, "history");
424  do
425  {
426  cur--;
427  if (cur < 0)
428  cur = c_history;
429  if (cur == h->last)
430  break;
431  if (mutt_istr_find(h->hist[cur], search_buf))
432  matches[match_count++] = h->hist[cur];
433  } while (match_count < c_history);
434 
435  return match_count;
436 }
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
Container for Accounts, Notifications.
Definition: neomutt.h:36
Saved list of user-entered commands/searches.
Definition: history.c:88
static struct History * get_history(enum HistoryClass hclass)
Get a particular history.
Definition: history.c:105
short cur
Definition: history.c:91
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition: string.c:689
short last
Definition: history.c:92
char ** hist
Definition: history.c:90
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_hist_free()

void mutt_hist_free ( void  )

Free all the history lists.

Definition at line 441 of file history.c.

442 {
443  if (!NeoMutt)
444  return;
445 
446  const short c_history = cs_subset_number(NeoMutt->sub, "history");
447  for (enum HistoryClass hclass = HC_FIRST; hclass < HC_MAX; hclass++)
448  {
449  struct History *h = &Histories[hclass];
450  if (!h->hist)
451  continue;
452 
453  /* The array has (`$history`+1) elements */
454  for (int i = 0; i <= c_history; i++)
455  {
456  FREE(&h->hist[i]);
457  }
458  FREE(&h->hist);
459  }
460 }
static struct History Histories[HC_MAX]
Definition: history.c:97
#define HC_FIRST
Definition: history.c:81
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
Container for Accounts, Notifications.
Definition: neomutt.h:36
Saved list of user-entered commands/searches.
Definition: history.c:88
HistoryClass
Type to differentiate different histories.
Definition: lib.h:46
#define FREE(x)
Definition: memory.h:40
char ** hist
Definition: history.c:90
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
Definition: lib.h:55
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_hist_init()

void mutt_hist_init ( void  )

Create a set of empty History ring buffers.

This just creates empty histories. To fill them, call mutt_hist_read_file().

Definition at line 468 of file history.c.

469 {
470  const short c_history = cs_subset_number(NeoMutt->sub, "history");
471  if (c_history == OldSize)
472  return;
473 
474  for (enum HistoryClass hclass = HC_FIRST; hclass < HC_MAX; hclass++)
475  init_history(&Histories[hclass]);
476 
477  OldSize = c_history;
478 }
static struct History Histories[HC_MAX]
Definition: history.c:97
#define HC_FIRST
Definition: history.c:81
static int OldSize
Definition: history.c:98
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
Container for Accounts, Notifications.
Definition: neomutt.h:36
static void init_history(struct History *h)
Set up a new History ring buffer.
Definition: history.c:121
HistoryClass
Type to differentiate different histories.
Definition: lib.h:46
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
Definition: lib.h:55
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_hist_add()

void mutt_hist_add ( enum HistoryClass  hclass,
const char *  str,
bool  save 
)

Add a string to a history.

Parameters
hclassHistory to add to
strString to add
saveShould the changes be saved to file immediately?

Definition at line 486 of file history.c.

487 {
488  struct History *h = get_history(hclass);
489  if (!h)
490  return; /* disabled */
491 
492  if (*str)
493  {
494  int prev = h->last - 1;
495  const short c_history = cs_subset_number(NeoMutt->sub, "history");
496  if (prev < 0)
497  prev = c_history;
498 
499  /* don't add to prompt history:
500  * - lines beginning by a space
501  * - repeated lines */
502  if ((*str != ' ') && (!h->hist[prev] || !mutt_str_equal(h->hist[prev], str)))
503  {
504  const bool c_history_remove_dups =
505  cs_subset_bool(NeoMutt->sub, "history_remove_dups");
506  if (c_history_remove_dups)
507  remove_history_dups(hclass, str);
508  const short c_save_history =
509  cs_subset_number(NeoMutt->sub, "save_history");
510  const char *const c_history_file =
511  cs_subset_path(NeoMutt->sub, "history_file");
512  if (save && (c_save_history != 0) && c_history_file)
513  save_history(hclass, str);
514  mutt_str_replace(&h->hist[h->last++], str);
515  if (h->last > c_history)
516  h->last = 0;
517  }
518  }
519  h->cur = h->last; /* reset to the last entry */
520 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
Container for Accounts, Notifications.
Definition: neomutt.h:36
static void save_history(enum HistoryClass hclass, const char *str)
Save one history string to a file.
Definition: history.c:310
Saved list of user-entered commands/searches.
Definition: history.c:88
static struct History * get_history(enum HistoryClass hclass)
Get a particular history.
Definition: history.c:105
static void remove_history_dups(enum HistoryClass hclass, const char *str)
De-dupe the history.
Definition: history.c:362
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
short cur
Definition: history.c:91
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
short last
Definition: history.c:92
char ** hist
Definition: history.c:90
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_hist_next()

char* mutt_hist_next ( enum HistoryClass  hclass)

Get the next string in a History.

Parameters
hclassHistory to choose
Return values
ptrNext string

If there is no next string, and empty string will be returned.

Definition at line 529 of file history.c.

530 {
531  struct History *h = get_history(hclass);
532  if (!h)
533  return ""; /* disabled */
534 
535  int next = h->cur;
536  do
537  {
538  next++;
539  const short c_history = cs_subset_number(NeoMutt->sub, "history");
540  if (next > c_history)
541  next = 0;
542  if (next == h->last)
543  break;
544  } while (!h->hist[next]);
545 
546  h->cur = next;
547  return NONULL(h->hist[h->cur]);
548 }
#define NONULL(x)
Definition: string2.h:37
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
Container for Accounts, Notifications.
Definition: neomutt.h:36
Saved list of user-entered commands/searches.
Definition: history.c:88
static struct History * get_history(enum HistoryClass hclass)
Get a particular history.
Definition: history.c:105
short cur
Definition: history.c:91
short last
Definition: history.c:92
char ** hist
Definition: history.c:90
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_hist_prev()

char* mutt_hist_prev ( enum HistoryClass  hclass)

Get the previous string in a History.

Parameters
hclassHistory to choose
Return values
ptrPrevious string

If there is no previous string, and empty string will be returned.

Definition at line 557 of file history.c.

558 {
559  struct History *h = get_history(hclass);
560  if (!h)
561  return ""; /* disabled */
562 
563  int prev = h->cur;
564  do
565  {
566  prev--;
567  const short c_history = cs_subset_number(NeoMutt->sub, "history");
568  if (prev < 0)
569  prev = c_history;
570  if (prev == h->last)
571  break;
572  } while (!h->hist[prev]);
573 
574  h->cur = prev;
575  return NONULL(h->hist[h->cur]);
576 }
#define NONULL(x)
Definition: string2.h:37
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
Container for Accounts, Notifications.
Definition: neomutt.h:36
Saved list of user-entered commands/searches.
Definition: history.c:88
static struct History * get_history(enum HistoryClass hclass)
Get a particular history.
Definition: history.c:105
short cur
Definition: history.c:91
short last
Definition: history.c:92
char ** hist
Definition: history.c:90
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_hist_reset_state()

void mutt_hist_reset_state ( enum HistoryClass  hclass)

Move the 'current' position to the end of the History.

Parameters
hclassHistory to reset

After calling mutt_hist_next() and mutt_hist_prev(), this function resets the current position ('cur' pointer).

Definition at line 585 of file history.c.

586 {
587  struct History *h = get_history(hclass);
588  if (!h)
589  return; /* disabled */
590 
591  h->cur = h->last;
592 }
Saved list of user-entered commands/searches.
Definition: history.c:88
static struct History * get_history(enum HistoryClass hclass)
Get a particular history.
Definition: history.c:105
short cur
Definition: history.c:91
short last
Definition: history.c:92
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_hist_read_file()

void mutt_hist_read_file ( void  )

Read the History from a file.

The file $history_file is read and parsed into separate History ring buffers.

Definition at line 599 of file history.c.

600 {
601  int line = 0, hclass, read;
602  char *linebuf = NULL, *p = NULL;
603  size_t buflen;
604 
605  const char *const c_history_file =
606  cs_subset_path(NeoMutt->sub, "history_file");
607  if (!c_history_file)
608  return;
609 
610  FILE *fp = mutt_file_fopen(c_history_file, "r");
611  if (!fp)
612  return;
613 
614  while ((linebuf = mutt_file_read_line(linebuf, &buflen, fp, &line, MUTT_RL_NO_FLAGS)))
615  {
616  read = 0;
617  if ((sscanf(linebuf, "%d:%n", &hclass, &read) < 1) || (read == 0) ||
618  (*(p = linebuf + strlen(linebuf) - 1) != '|') || (hclass < 0))
619  {
620  mutt_error(_("Bad history file format (line %d)"), line);
621  break;
622  }
623  /* silently ignore too high class (probably newer neomutt) */
624  if (hclass >= HC_MAX)
625  continue;
626  *p = '\0';
627  p = mutt_str_dup(linebuf + read);
628  if (p)
629  {
630  const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
631  mutt_ch_convert_string(&p, "utf-8", c_charset, MUTT_ICONV_NO_FLAGS);
632  mutt_hist_add(hclass, p, false);
633  FREE(&p);
634  }
635  }
636 
637  mutt_file_fclose(&fp);
638  FREE(&linebuf);
639 }
#define mutt_error(...)
Definition: logging.h:88
void mutt_hist_add(enum HistoryClass hclass, const char *str, bool save)
Add a string to a history.
Definition: history.c:486
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
#define _(a)
Definition: message.h:28
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition: charset.c:758
#define MUTT_ICONV_NO_FLAGS
No flags are set.
Definition: charset.h:71
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition: file.c:667
Container for Accounts, Notifications.
Definition: neomutt.h:36
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:38
#define FREE(x)
Definition: memory.h:40
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:589
Definition: lib.h:55
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_hist_at_scratch()

bool mutt_hist_at_scratch ( enum HistoryClass  hclass)

Is the current History position at the 'scratch' place?

Parameters
hclassHistory to use
Return values
trueHistory is at 'scratch' place

The last entry in the history is used as a 'scratch' area. It can be overwritten as the user types and edits.

To get (back) to the scratch area, call mutt_hist_next(), mutt_hist_prev() or mutt_hist_reset_state().

Definition at line 652 of file history.c.

653 {
654  struct History *h = get_history(hclass);
655  if (!h)
656  return false; /* disabled */
657 
658  return h->cur == h->last;
659 }
Saved list of user-entered commands/searches.
Definition: history.c:88
static struct History * get_history(enum HistoryClass hclass)
Get a particular history.
Definition: history.c:105
short cur
Definition: history.c:91
short last
Definition: history.c:92
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_hist_save_scratch()

void mutt_hist_save_scratch ( enum HistoryClass  hclass,
const char *  str 
)

Save a temporary string to the History.

Parameters
hclassHistory to alter
strString to set

Write a 'scratch' string into the History's current position. This is useful to preserver a user's edits.

Definition at line 669 of file history.c.

670 {
671  struct History *h = get_history(hclass);
672  if (!h)
673  return; /* disabled */
674 
675  /* Don't check if str has a value because the scratch buffer may contain
676  * an old garbage value that should be overwritten */
677  mutt_str_replace(&h->hist[h->last], str);
678 }
Saved list of user-entered commands/searches.
Definition: history.c:88
static struct History * get_history(enum HistoryClass hclass)
Get a particular history.
Definition: history.c:105
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
short last
Definition: history.c:92
char ** hist
Definition: history.c:90
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ Histories

struct History Histories[HC_MAX]
static

Definition at line 97 of file history.c.

◆ OldSize

int OldSize = 0
static

Definition at line 98 of file history.c.