2 * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
33 /* global vars used for the string-history routines */
35 static struct history History[HC_LAST];
36 static int OldSize = 0;
38 #define GET_HISTORY(CLASS) ((CLASS >= HC_LAST) ? NULL : &History[CLASS])
40 static void init_history (struct history *h)
48 for (i = 0 ; i < OldSize ; i ++)
55 h->hist = safe_calloc (HistSize, sizeof (char *));
61 void mutt_read_histfile (void)
64 int line = 0, hclass, read;
65 char *linebuf = NULL, *p;
68 if ((f = fopen (HistFile, "r")) == NULL)
71 while ((linebuf = mutt_read_line (linebuf, &buflen, f, &line, 0)) != NULL)
74 if (sscanf (linebuf, "%d:%n", &hclass, &read) < 1 || read == 0 ||
75 *(p = linebuf + strlen (linebuf) - 1) != '|' || hclass < 0)
77 mutt_error (_("Bad history file format (line %d)"), line);
80 /* silently ignore too high class (probably newer mutt) */
81 if (hclass >= HC_LAST)
84 p = safe_strdup (linebuf + read);
87 mutt_convert_string (&p, "utf-8", Charset, 0);
88 mutt_history_add (hclass, p, 0);
97 static void shrink_histfile (void)
99 char tmpfname[_POSIX_PATH_MAX];
100 FILE *f, *tmp = NULL;
101 int n[HC_LAST] = { 0 };
103 char *linebuf = NULL;
106 if ((f = fopen (HistFile, "r")) == NULL)
110 while ((linebuf = mutt_read_line (linebuf, &buflen, f, &line, 0)) != NULL)
112 if (sscanf (linebuf, "%d", &hclass) < 1 || hclass < 0)
114 mutt_error (_("Bad history file format (line %d)"), line);
117 /* silently ignore too high class (probably newer mutt) */
118 if (hclass >= HC_LAST)
123 for(hclass = HC_FIRST; hclass < HC_LAST; hclass++)
124 if (n[hclass] > SaveHist)
126 mutt_mktemp (tmpfname, sizeof (tmpfname));
127 if ((tmp = safe_fopen (tmpfname, "w+")) == NULL)
128 mutt_perror (tmpfname);
136 while ((linebuf = mutt_read_line (linebuf, &buflen, f, &line, 0)) != NULL)
138 if (sscanf (linebuf, "%d", &hclass) < 1 || hclass < 0)
140 mutt_error (_("Bad history file format (line %d)"), line);
143 /* silently ignore too high class (probably newer mutt) */
144 if (hclass >= HC_LAST)
146 if (n[hclass]-- <= SaveHist)
147 fprintf (tmp, "%s\n", linebuf);
156 if (fflush (tmp) == 0 &&
157 (f = fopen (HistFile, "w")) != NULL) /* __FOPEN_CHECKED__ */
160 mutt_copy_stream (tmp, f);
168 static void save_history (history_class_t hclass, const char *s)
174 if (!s || !*s) /* This shouldn't happen, but it's safer. */
177 if ((f = fopen (HistFile, "a")) == NULL)
179 mutt_perror ("fopen");
183 tmp = safe_strdup (s);
184 mutt_convert_string (&tmp, Charset, "utf-8", 0);
186 /* Format of a history item (1 line): "<histclass>:<string>|".
187 We add a '|' in order to avoid lines ending with '\'. */
188 fprintf (f, "%d:", (int) hclass);
189 for (p = tmp; *p; p++)
191 /* Don't copy \n as a history item must fit on one line. The string
192 shouldn't contain such a character anyway, but as this can happen
193 in practice, we must deal with that. */
195 putc ((unsigned char) *p, f);
209 void mutt_init_history(void)
211 history_class_t hclass;
213 if (HistSize == OldSize)
216 for(hclass = HC_FIRST; hclass < HC_LAST; hclass++)
217 init_history(&History[hclass]);
222 void mutt_history_add (history_class_t hclass, const char *s, int save)
225 struct history *h = GET_HISTORY(hclass);
228 return; /* disabled */
233 if (prev < 0) prev = HistSize - 1;
235 /* don't add to prompt history:
236 * - lines beginning by a space
239 if (*s != ' ' && (!h->hist[prev] || mutt_strcmp (h->hist[prev], s) != 0))
241 if (save && SaveHist)
242 save_history (hclass, s);
243 mutt_str_replace (&h->hist[h->last++], s);
244 if (h->last > HistSize - 1)
248 h->cur = h->last; /* reset to the last entry */
251 char *mutt_history_next (history_class_t hclass)
254 struct history *h = GET_HISTORY(hclass);
257 return (""); /* disabled */
260 if (next > HistSize - 1)
262 h->cur = h->hist[next] ? next : 0;
263 return (h->hist[h->cur] ? h->hist[h->cur] : "");
266 char *mutt_history_prev (history_class_t hclass)
269 struct history *h = GET_HISTORY(hclass);
272 return (""); /* disabled */
278 while (prev > 0 && h->hist[prev] == NULL)
283 return (h->hist[h->cur] ? h->hist[h->cur] : "");