2 static char *RCSid() { return RCSid("$Id: history.c,v 1.21.2.4 2009/03/26 22:02:02 mikulik Exp $"); }
5 /* GNUPLOT - history.c */
8 * Copyright 1986 - 1993, 1999, 2004 Thomas Williams, Colin Kelley
10 * Permission to use, copy, and distribute this software and its
11 * documentation for any purpose with or without fee is hereby granted,
12 * provided that the above copyright notice appear in all copies and
13 * that both that copyright notice and this permission notice appear
14 * in supporting documentation.
16 * Permission to modify the software is granted, but not the right to
17 * distribute the complete modified source code. Modifications are to
18 * be distributed as patches to the released version. Permission to
19 * distribute binaries produced by compiling modified sources is granted,
21 * 1. distribute the corresponding source modifications from the
22 * released version in the form of a patch file along with the binaries,
23 * 2. add special version identification to distinguish your version
24 * in addition to the base release version number,
25 * 3. provide your name and address as the primary contact for the
26 * support of your modified version, and
27 * 4. retain our contact information in regard to use of the base
29 * Permission to distribute the released version of the source code along
30 * with corresponding source modifications in the form of a patch file is
31 * granted with same provisions 2 through 4 for binary distributions.
33 * This software is provided "as is" without express or implied warranty
34 * to the extent permitted by applicable law.
45 /* moved here from plot.c */
46 #ifdef GNUPLOT_HISTORY
48 /* Can be overriden with the environment variable 'GNUPLOT_HISTORY_SIZE' */
49 # define HISTORY_SIZE 666
51 long int gnuplot_history_size = HISTORY_SIZE;
55 #if defined(READLINE) && !defined(HAVE_LIBREADLINE) && !defined(HAVE_LIBEDITLINE)
57 struct hist *history = NULL; /* no history yet */
58 struct hist *cur_entry = NULL;
60 /* add line to the history */
62 add_history(char *line)
64 static struct hist *first_entry = NULL;
65 /* this points to first entry in history list,
66 whereas "history" points to last entry */
67 static long int hist_count = 0;
68 /* number of entries in history list */
72 while (entry != NULL) {
73 /* Don't store duplicate entries */
74 if (!strcmp(entry->line, line)) {
75 /* cmd lines are equal, relink entry that was found last */
76 if (entry->next == NULL) {
77 /* previous command repeated, no change */
80 if (entry->prev == NULL) {
81 /* current cmd line equals the first in the history */
82 (entry->next)->prev = NULL;
83 first_entry = entry->next;
84 history->next = entry;
85 entry->prev = history;
90 /* bridge over entry's vacancy, then move it to the end */
91 (entry->prev)->next = entry->next;
92 (entry->next)->prev = entry->prev;
93 entry->prev = history;
94 history->next = entry;
100 } /* end of not-storing duplicated entries */
102 #ifdef GNUPLOT_HISTORY
103 /* limit size of history list to "gnuplot_history_size" */
104 if (gnuplot_history_size != -1) {
105 while ((hist_count >= gnuplot_history_size) && (first_entry != NULL)) {
109 /* remove first entry from chain */
110 first_entry = first_entry->next;
112 first_entry->prev = NULL;
116 /* remove references */
117 if (cur_entry == entry)
118 cur_entry = first_entry;
119 if (history == entry) {
120 cur_entry = history = NULL;
130 entry = (struct hist *) gp_alloc(sizeof(struct hist), "history");
131 entry->line = gp_strdup(line);
133 entry->prev = history;
135 if (history != NULL) {
136 history->next = entry;
146 * New functions for browsing the history. They are called from command.c
147 * when the user runs the 'history' command
150 /* write <n> last entries of the history to the file <filename>
152 * n > 0 ... write only <n> last entries; otherwise all entries
153 * filename == NULL ... write to stdout; otherwise to the filename
154 * filename == "" ... write to stdout, but without entry numbers
155 * mode ... should be "w" or "a" to select write or append for file,
156 * ignored if history is written to a pipe
159 write_history_n(const int n, const char *filename, const char *mode)
161 struct hist *entry = history, *start = NULL;
164 int is_pipe = 0; /* not filename but pipe to an external program */
166 int hist_entries = 0;
170 return; /* no history yet */
172 /* find the beginning of the history and count nb of entries */
173 while (entry->prev != NULL) {
176 if (n <= 0 || hist_entries <= n)
177 start = entry; /* listing will start from this entry */
180 hist_index = (n > 0) ? GPMAX(hist_entries - n, 0) + 1 : 1;
182 /* now write the history */
183 if (filename != NULL && filename[0]) {
185 if (filename[0]=='|') {
186 out = popen(filename+1, "w");
190 out = fopen(filename, mode);
193 /* cannot use int_error() because we are just exiting gnuplot:
194 int_error(NO_CARET, "cannot open file for saving the history");
196 fprintf(stderr, "Warning: cannot open file %s for saving the history.", filename);
198 while (entry != NULL) {
199 /* don't add line numbers when writing to file
200 * to make file loadable */
202 if (filename[0]==0) fputs(" ", out);
203 fprintf(out, "%s\n", entry->line);
205 fprintf(out, "%5i %s\n", hist_index++, entry->line);
208 if (filename != NULL && filename[0]) {
220 /* obviously the same routine as in GNU readline, according to code from
221 * plot.c:#if defined(HAVE_LIBREADLINE) && defined(GNUPLOT_HISTORY)
224 write_history(char *filename)
226 write_history_n(0, filename, "w");
230 /* routine to read history entries from a file,
231 * this complements write_history and is necessary for
232 * saving of history when we are not using libreadline
235 read_history(char *filename)
239 if ((hist_file = fopen( filename, "r" ))) {
240 while (!feof(hist_file)) {
241 char *pline, line[MAX_LINE_LEN+1];
242 pline = fgets(line, MAX_LINE_LEN, hist_file);
244 /* remove trailing linefeed */
245 if ((pline = strrchr(line, '\n')))
247 if ((pline = strrchr(line, '\r')))
258 /* finds and returns a command from the history which starts with <cmd>
259 * (ignores leading spaces in <cmd>)
260 * Returns NULL if nothing found
263 history_find(char *cmd)
265 struct hist *entry = history;
270 return NULL; /* no history yet */
272 cmd++; /* remove surrounding quotes */
278 if (cmd[len - 1] == '"')
283 /* search through the history */
284 while (entry != NULL) {
286 while (isspace((unsigned char) *line))
287 line++; /* skip leading spaces */
288 if (!strncmp(cmd, line, len)) /* entry found */
296 /* finds and print all occurencies of commands from the history which
298 * (ignores leading spaces in <cmd>)
299 * Returns 1 on success, 0 if no such entry exists
302 history_find_all(char *cmd)
304 struct hist *entry = history;
311 return 0; /* no history yet */
313 cmd++; /* remove surrounding quotes */
317 if (cmd[len - 1] == '"')
321 /* find the beginning of the history */
322 while (entry->prev != NULL)
324 /* search through the history */
325 while (entry != NULL) {
327 while (isspace((unsigned char) *line))
328 line++; /* skip leading spaces */
329 if (!strncmp(cmd, line, len)) { /* entry found */
330 printf("%5i %s\n", hist_index, line);
339 #elif defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDITLINE)
341 /* Save history to file, or write to stdout or pipe.
342 * For pipes, only "|" works, pipes starting with ">" get a strange
343 * filename like in the non-readline version.
345 * Peter Weilbacher, 28Jun2004
349 write_history_list(num, filename, mode)
351 const char *const filename;
354 #ifdef HAVE_LIBREADLINE
355 HIST_ENTRY **the_list = history_list();
357 const HIST_ENTRY *list_entry;
364 if (filename && filename[0] ) {
365 /* good filename given and not quiet */
367 if (filename[0]=='|') {
368 out = popen(filename+1, "w");
372 if (! (out = fopen(filename, mode) ) ) {
373 /* Fall back to 'stdout' */
374 int_warn(NO_CARET, "Cannot open file to save history, using standard output.\n");
380 } else if (filename && !filename[0])
383 /* Determine starting point and output in loop.
384 * For some reason the readline functions append_history()
385 * and write_history() do not work they way I thought they did...
388 istart = history_length - num;
389 if (istart <= 0 || istart > history_length)
392 #ifdef HAVE_LIBREADLINE
395 for (i = istart; list_entry = history_get(i); i++) {
396 /* don't add line numbers when writing to file to make file loadable */
398 fprintf(out, "%s\n", list_entry->line);
400 if (!is_quiet) fprintf(out, "%5i", i + history_base - 1);
401 fprintf(out, " %s\n", list_entry->line);
404 /* close if something was opened */
406 if (is_pipe) pclose(out);
408 if (is_file) fclose(out);
411 /* This is the function getting called in command.c */
413 write_history_n(n, filename, mode)
415 const char *filename;
418 write_history_list(n, filename, mode);
421 /* finds and returns a command from the history which starts with <cmd>
422 * Returns NULL if nothing found
424 * Peter Weilbacher, 28Jun2004
432 /* quote removal, copied from non-readline version */
433 if (*cmd == '"') cmd++;
436 if (cmd[len - 1] == '"') cmd[--len] = 0;
438 /* printf ("searching for '%s'\n", cmd); */
440 /* Anchored backward search for prefix */
441 if (history_search_prefix(cmd, -1) == 0)
442 return current_history()->line;
446 /* finds and print all occurencies of commands from the history which
448 * Returns the number of found entries on success,
449 * and 0 if no such entry exists
451 * Peter Weilbacher 28Jun2004
454 history_find_all(cmd)
459 int number = 0; /* each found entry increases this */
461 /* quote removal, copied from non-readline version */
462 if (*cmd == '"') cmd++;
465 if (cmd[len - 1] == '"') cmd[--len] = 0;
467 /* printf ("searching for all occurrences of '%s'\n", cmd); */
469 /* Output matching history entries in chronological order (not backwards
470 * so we have to start at the beginning of the history list.
474 found = history_search_prefix(cmd, 1); /* Anchored backward search for prefix */
477 printf("%5i %s\n", where_history() + history_base, current_history()->line);
478 /* go one step back or you find always the same entry. */
479 if (!history_set_pos(where_history() + 1))
480 break; /* finished if stepping didn't work */
482 } while (found > -1);
487 #endif /* READLINE && !HAVE_LIBREADLINE && !HAVE_LIBEDITLINE */