summaryrefslogtreecommitdiffstats
path: root/history.c
diff options
context:
space:
mode:
authorVincent Lefevre <vincent@vinc17.net>2007-02-26 17:17:13 +0000
committerVincent Lefevre <vincent@vinc17.net>2007-02-26 17:17:13 +0000
commit36677253ad25081ad3c4bf070d195d99170a90e8 (patch)
tree4106d10e6872b3ff15c09bf11582a8437872afd7 /history.c
parent7f8539489eef75c796ef6eab8024bb3fe6aad103 (diff)
Add $history_file and $save_history, for saving command history across
sessions.
Diffstat (limited to 'history.c')
-rw-r--r--history.c143
1 files changed, 142 insertions, 1 deletions
diff --git a/history.c b/history.c
index 4bee9ab9..78c8f46d 100644
--- a/history.c
+++ b/history.c
@@ -56,6 +56,145 @@ static void init_history (struct history *h)
h->last = 0;
}
+void mutt_read_histfile (void)
+{
+ FILE *f;
+ int line = 0, hclass, read;
+ char *linebuf = NULL, *p;
+ size_t buflen;
+
+ if ((f = fopen (HistFile, "r")) == NULL)
+ return;
+
+ while ((linebuf = mutt_read_line (linebuf, &buflen, f, &line)) != NULL)
+ {
+ read = 0;
+ if (sscanf (linebuf, "%d:%n", &hclass, &read) < 1 || read == 0 ||
+ *(p = linebuf + strlen (linebuf) - 1) != '|')
+ {
+ mutt_error (_("Bad history file format (line %d)"), line);
+ break;
+ }
+ *p = '\0';
+ p = safe_strdup (linebuf + read);
+ if (p)
+ {
+ mutt_convert_string (&p, "utf-8", Charset, 0);
+ mutt_history_add (hclass, p, 0);
+ FREE (&p);
+ }
+ }
+
+ fclose (f);
+ FREE (&linebuf);
+}
+
+static void shrink_histfile (void)
+{
+ char tmpfname[_POSIX_PATH_MAX];
+ FILE *f, *tmp = NULL;
+ int n[HC_LAST] = { 0 };
+ int line, hclass;
+ char *linebuf = NULL;
+ size_t buflen;
+
+ if ((f = fopen (HistFile, "r")) == NULL)
+ return;
+
+ line = 0;
+ while ((linebuf = mutt_read_line (linebuf, &buflen, f, &line)) != NULL)
+ {
+ if (sscanf (linebuf, "%d", &hclass) < 1)
+ {
+ mutt_error (_("Bad history file format (line %d)"), line);
+ goto cleanup;
+ }
+ n[hclass]++;
+ }
+
+ for(hclass = HC_FIRST; hclass < HC_LAST; hclass++)
+ if (n[hclass] > SaveHist)
+ {
+ mutt_mktemp (tmpfname);
+ if ((tmp = safe_fopen (tmpfname, "w+")) == NULL)
+ mutt_perror (tmpfname);
+ break;
+ }
+
+ if (tmp != NULL)
+ {
+ rewind (f);
+ line = 0;
+ while ((linebuf = mutt_read_line (linebuf, &buflen, f, &line)) != NULL)
+ {
+ if (sscanf (linebuf, "%d", &hclass) < 1)
+ {
+ mutt_error (_("Bad history file format (line %d)"), line);
+ goto cleanup;
+ }
+ if (n[hclass]-- <= SaveHist)
+ fprintf (tmp, "%s\n", linebuf);
+ }
+ }
+
+cleanup:
+ fclose (f);
+ FREE (&linebuf);
+ if (tmp != NULL)
+ {
+ if (fflush (tmp) == 0 &&
+ (f = fopen (HistFile, "w")) != NULL) /* __FOPEN_CHECKED__ */
+ {
+ rewind (tmp);
+ mutt_copy_stream (tmp, f);
+ fclose (f);
+ }
+ fclose (tmp);
+ unlink (tmpfname);
+ }
+}
+
+static void save_history (history_class_t hclass, const char *s)
+{
+ static int n = 0;
+ FILE *f;
+ char *tmp, *p;
+
+ if (!s || !*s) /* This shouldn't happen, but it's safer. */
+ return;
+
+ if ((f = fopen (HistFile, "a")) == NULL)
+ {
+ mutt_perror ("fopen");
+ return;
+ }
+
+ tmp = safe_strdup (s);
+ mutt_convert_string (&tmp, Charset, "utf-8", 0);
+
+ /* Format of a history item (1 line): "<histclass>:<string>|".
+ We add a '|' in order to avoid lines ending with '\'. */
+ fprintf (f, "%d:", (int) hclass);
+ for (p = tmp; *p; p++)
+ {
+ /* Don't copy \n as a history item must fit on one line. The string
+ shouldn't contain such a character anyway, but as this can happen
+ in practice, we must deal with that. */
+ if (*p != '\n')
+ putc ((unsigned char) *p, f);
+ }
+ fputs ("|\n", f);
+
+ fclose (f);
+ FREE (&tmp);
+
+ if (--n < 0)
+ {
+ n = SaveHist;
+ shrink_histfile();
+ }
+}
+
void mutt_init_history(void)
{
history_class_t hclass;
@@ -69,7 +208,7 @@ void mutt_init_history(void)
OldSize = HistSize;
}
-void mutt_history_add (history_class_t hclass, const char *s)
+void mutt_history_add (history_class_t hclass, const char *s, int save)
{
int prev;
struct history *h = &History[hclass];
@@ -88,6 +227,8 @@ void mutt_history_add (history_class_t hclass, const char *s)
*/
if (*s != ' ' && (!h->hist[prev] || mutt_strcmp (h->hist[prev], s) != 0))
{
+ if (save && SaveHist)
+ save_history (hclass, s);
mutt_str_replace (&h->hist[h->last++], s);
if (h->last > HistSize - 1)
h->last = 0;