]> git.ipfire.org Git - thirdparty/bash.git/blob - bashhist.c
Imported from ../bash-2.05.tar.gz.
[thirdparty/bash.git] / bashhist.c
1 /* bashhist.c -- bash interface to the GNU history library. */
2
3 /* Copyright (C) 1993 Free Software Foundation, Inc.
4
5 This file is part of GNU Bash, the Bourne Again SHell.
6
7 Bash is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with Bash; see the file COPYING. If not, write to the Free Software
19 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
20
21 #include "config.h"
22
23 #if defined (HISTORY)
24
25 #if defined (HAVE_UNISTD_H)
26 # ifdef _MINIX
27 # include <sys/types.h>
28 # endif
29 # include <unistd.h>
30 #endif
31
32 #include "bashtypes.h"
33 #include <stdio.h>
34 #include <errno.h>
35 #include "bashansi.h"
36 #include "posixstat.h"
37 #include "filecntl.h"
38
39 #include "shell.h"
40 #include "flags.h"
41 #include "input.h"
42 #include "parser.h" /* for the struct dstack stuff. */
43 #include "pathexp.h" /* for the struct ignorevar stuff */
44 #include "builtins/common.h"
45
46 #include <readline/history.h>
47 #include <glob/fnmatch.h>
48
49 #if defined (READLINE)
50 # include "bashline.h"
51 #endif
52
53 #if !defined (errno)
54 extern int errno;
55 #endif
56
57 extern int glob_pattern_p ();
58
59 static int histignore_item_func ();
60
61 static struct ignorevar histignore =
62 {
63 "HISTIGNORE",
64 (struct ign *)0,
65 0,
66 (char *)0,
67 (Function *)histignore_item_func,
68 };
69
70 #define HIGN_EXPAND 0x01
71
72 /* Declarations of bash history variables. */
73 /* Non-zero means to remember lines typed to the shell on the history
74 list. This is different than the user-controlled behaviour; this
75 becomes zero when we read lines from a file, for example. */
76 int remember_on_history = 1;
77
78 /* The number of lines that Bash has added to this history session. */
79 int history_lines_this_session;
80
81 /* The number of lines that Bash has read from the history file. */
82 int history_lines_in_file;
83
84 #if defined (BANG_HISTORY)
85 /* Non-zero means do no history expansion on this line, regardless
86 of what history_expansion says. */
87 int history_expansion_inhibited;
88 #endif
89
90 /* By default, every line is saved in the history individually. I.e.,
91 if the user enters:
92 bash$ for i in a b c
93 > do
94 > echo $i
95 > done
96 Each line will be individually saved in the history.
97 bash$ history
98 10 for i in a b c
99 11 do
100 12 echo $i
101 13 done
102 14 history
103 If the variable command_oriented_history is set, multiple lines
104 which form one command will be saved as one history entry.
105 bash$ for i in a b c
106 > do
107 > echo $i
108 > done
109 bash$ history
110 10 for i in a b c
111 do
112 echo $i
113 done
114 11 history
115 The user can then recall the whole command all at once instead
116 of just being able to recall one line at a time.
117 */
118 int command_oriented_history = 1;
119
120 /* Non-zero means to store newlines in the history list when using
121 command_oriented_history rather than trying to use semicolons. */
122 int literal_history;
123
124 /* Non-zero means to append the history to the history file at shell
125 exit, even if the history has been stifled. */
126 int force_append_history;
127
128 /* A nit for picking at history saving.
129 Value of 0 means save all lines parsed by the shell on the history.
130 Value of 1 means save all lines that do not start with a space.
131 Value of 2 means save all lines that do not match the last line saved. */
132 int history_control;
133
134 /* Set to 1 if the last command was added to the history list successfully
135 as a separate history entry; set to 0 if the line was ignored or added
136 to a previous entry as part of command-oriented-history processing. */
137 int hist_last_line_added;
138
139 #if defined (READLINE)
140 /* If non-zero, and readline is being used, the user is offered the
141 chance to re-edit a failed history expansion. */
142 int history_reediting;
143
144 /* If non-zero, and readline is being used, don't directly execute a
145 line with history substitution. Reload it into the editing buffer
146 instead and let the user further edit and confirm with a newline. */
147 int hist_verify;
148
149 #endif /* READLINE */
150
151 /* Variables declared in other files used here. */
152 extern int interactive;
153 extern int current_command_line_count;
154
155 extern struct dstack dstack;
156
157 extern char *extract_colon_unit ();
158 extern char *history_delimiting_chars ();
159 extern void maybe_add_history (); /* forward declaration */
160 extern void bash_add_history (); /* forward declaration */
161
162 static int history_should_ignore ();
163
164 /* Is the history expansion starting at string[i] one that should not
165 be expanded? */
166 static int
167 bash_history_inhibit_expansion (string, i)
168 char *string;
169 int i;
170 {
171 /* The shell uses ! as a pattern negation character in globbing [...]
172 expressions, so let those pass without expansion. */
173 if (i > 0 && (string[i - 1] == '[') && member (']', string + i + 1))
174 return (1);
175 /* The shell uses ! as the indirect expansion character, so let those
176 expansions pass as well. */
177 else if (i > 1 && string[i - 1] == '{' && string[i - 2] == '$' &&
178 member ('}', string + i + 1))
179 return (1);
180 #if defined (EXTENDED_GLOB)
181 else if (extended_glob && i > 1 && string[i+1] == '(' && member (')', string + i + 2))
182 return (1);
183 #endif
184 else
185 return (0);
186 }
187
188 void
189 bash_initialize_history ()
190 {
191 history_quotes_inhibit_expansion = 1;
192 history_search_delimiter_chars = ";&()|<>";
193 history_inhibit_expansion_function = bash_history_inhibit_expansion;
194 }
195
196 void
197 bash_history_reinit (interact)
198 int interact;
199 {
200 #if defined (BANG_HISTORY)
201 history_expansion = interact != 0;
202 history_expansion_inhibited = 1;
203 #endif
204 remember_on_history = interact != 0;
205 history_inhibit_expansion_function = bash_history_inhibit_expansion;
206 }
207
208 void
209 bash_history_disable ()
210 {
211 remember_on_history = 0;
212 #if defined (BANG_HISTORY)
213 history_expansion_inhibited = 1;
214 #endif
215 }
216
217 void
218 bash_history_enable ()
219 {
220 remember_on_history = 1;
221 #if defined (BANG_HISTORY)
222 history_expansion_inhibited = 0;
223 #endif
224 history_inhibit_expansion_function = bash_history_inhibit_expansion;
225 sv_history_control ("HISTCONTROL");
226 sv_histignore ("HISTIGNORE");
227 }
228
229 /* Load the history list from the history file. */
230 void
231 load_history ()
232 {
233 char *hf;
234 struct stat buf;
235
236 /* Truncate history file for interactive shells which desire it.
237 Note that the history file is automatically truncated to the
238 size of HISTSIZE if the user does not explicitly set the size
239 differently. */
240 set_if_not ("HISTFILESIZE", get_string_value ("HISTSIZE"));
241 sv_histsize ("HISTFILESIZE");
242
243 /* Read the history in HISTFILE into the history list. */
244 hf = get_string_value ("HISTFILE");
245
246 if (hf && *hf && stat (hf, &buf) == 0)
247 {
248 read_history (hf);
249 using_history ();
250 history_lines_in_file = where_history ();
251 }
252 }
253
254 #ifdef INCLUDE_UNUSED
255 /* Write the existing history out to the history file. */
256 void
257 save_history ()
258 {
259 char *hf;
260 struct stat buf;
261
262 hf = get_string_value ("HISTFILE");
263 if (hf && *hf && stat (hf, &buf) == 0)
264 {
265 /* Append only the lines that occurred this session to
266 the history file. */
267 using_history ();
268
269 if (history_lines_this_session < where_history () || force_append_history)
270 append_history (history_lines_this_session, hf);
271 else
272 write_history (hf);
273
274 sv_histsize ("HISTFILESIZE");
275 }
276 }
277 #endif
278
279 int
280 maybe_append_history (filename)
281 char *filename;
282 {
283 int fd, result;
284 struct stat buf;
285
286 result = EXECUTION_SUCCESS;
287 if (history_lines_this_session && (history_lines_this_session < where_history ()))
288 {
289 /* If the filename was supplied, then create it if necessary. */
290 if (stat (filename, &buf) == -1 && errno == ENOENT)
291 {
292 fd = open (filename, O_WRONLY|O_CREAT, 0600);
293 if (fd < 0)
294 {
295 builtin_error ("%s: cannot create: %s", filename, strerror (errno));
296 return (EXECUTION_FAILURE);
297 }
298 close (fd);
299 }
300 result = append_history (history_lines_this_session, filename);
301 history_lines_in_file += history_lines_this_session;
302 history_lines_this_session = 0;
303 }
304 return (result);
305 }
306
307 /* If this is an interactive shell, then append the lines executed
308 this session to the history file. */
309 int
310 maybe_save_shell_history ()
311 {
312 int result;
313 char *hf;
314 struct stat buf;
315
316 result = 0;
317 if (history_lines_this_session)
318 {
319 hf = get_string_value ("HISTFILE");
320
321 if (hf && *hf)
322 {
323 /* If the file doesn't exist, then create it. */
324 if (stat (hf, &buf) == -1)
325 {
326 int file;
327 file = open (hf, O_CREAT | O_TRUNC | O_WRONLY, 0600);
328 if (file != -1)
329 close (file);
330 }
331
332 /* Now actually append the lines if the history hasn't been
333 stifled. If the history has been stifled, rewrite the
334 history file. */
335 using_history ();
336 if (history_lines_this_session <= where_history () || force_append_history)
337 {
338 result = append_history (history_lines_this_session, hf);
339 history_lines_in_file += history_lines_this_session;
340 }
341 else
342 {
343 result = write_history (hf);
344 history_lines_in_file = history_lines_this_session;
345 }
346 history_lines_this_session = 0;
347
348 sv_histsize ("HISTFILESIZE");
349 }
350 }
351 return (result);
352 }
353
354 #if defined (READLINE)
355 /* Tell readline () that we have some text for it to edit. */
356 static void
357 re_edit (text)
358 char *text;
359 {
360 if (bash_input.type == st_stdin)
361 bash_re_edit (text);
362 }
363 #endif /* READLINE */
364
365 /* Return 1 if this line needs history expansion. */
366 static int
367 history_expansion_p (line)
368 char *line;
369 {
370 register char *s;
371
372 for (s = line; *s; s++)
373 if (*s == history_expansion_char || *s == history_subst_char)
374 return 1;
375 return 0;
376 }
377
378 /* Do pre-processing on LINE. If PRINT_CHANGES is non-zero, then
379 print the results of expanding the line if there were any changes.
380 If there is an error, return NULL, otherwise the expanded line is
381 returned. If ADDIT is non-zero the line is added to the history
382 list after history expansion. ADDIT is just a suggestion;
383 REMEMBER_ON_HISTORY can veto, and does.
384 Right now this does history expansion. */
385 char *
386 pre_process_line (line, print_changes, addit)
387 char *line;
388 int print_changes, addit;
389 {
390 char *history_value;
391 char *return_value;
392 int expanded;
393
394 return_value = line;
395 expanded = 0;
396
397 # if defined (BANG_HISTORY)
398 /* History expand the line. If this results in no errors, then
399 add that line to the history if ADDIT is non-zero. */
400 if (!history_expansion_inhibited && history_expansion && history_expansion_p (line))
401 {
402 expanded = history_expand (line, &history_value);
403
404 if (expanded)
405 {
406 if (print_changes)
407 {
408 if (expanded < 0)
409 internal_error ("%s", history_value);
410 #if defined (READLINE)
411 else if (hist_verify == 0 || expanded == 2)
412 #else
413 else
414 #endif
415 fprintf (stderr, "%s\n", history_value);
416 }
417
418 /* If there was an error, return NULL. */
419 if (expanded < 0 || expanded == 2) /* 2 == print only */
420 {
421 free (history_value);
422
423 # if defined (READLINE)
424 /* New hack. We can allow the user to edit the
425 failed history expansion. */
426 if (history_reediting && expanded < 0)
427 re_edit (line);
428 # endif /* READLINE */
429 return ((char *)NULL);
430 }
431
432 # if defined (READLINE)
433 if (hist_verify && expanded == 1)
434 {
435 re_edit (history_value);
436 return ((char *)NULL);
437 }
438 # endif
439 }
440
441 /* Let other expansions know that return_value can be free'ed,
442 and that a line has been added to the history list. Note
443 that we only add lines that have something in them. */
444 expanded = 1;
445 return_value = history_value;
446 }
447 # endif /* BANG_HISTORY */
448
449 if (addit && remember_on_history && *return_value)
450 maybe_add_history (return_value);
451
452 #if 0
453 if (expanded == 0)
454 return_value = savestring (line);
455 #endif
456
457 return (return_value);
458 }
459
460 /* Return 1 if the first non-whitespace character in LINE is a `#', indicating
461 * that the line is a shell comment. */
462 static int
463 shell_comment (line)
464 char *line;
465 {
466 char *p;
467
468 for (p = line; p && *p && whitespace (*p); p++)
469 ;
470 return (p && *p == '#');
471 }
472
473 /* Remove shell comments from LINE. A `#' and anything after it is a comment.
474 This isn't really useful yet, since it doesn't handle quoting. */
475 static char *
476 filter_comments (line)
477 char *line;
478 {
479 char *p;
480
481 for (p = line; p && *p && *p != '#'; p++)
482 ;
483 if (p && *p == '#')
484 *p = '\0';
485 return (line);
486 }
487
488 /* Add LINE to the history list depending on the value of HISTORY_CONTROL. */
489 void
490 maybe_add_history (line)
491 char *line;
492 {
493 static int first_line_saved = 0;
494 HIST_ENTRY *temp;
495
496 hist_last_line_added = 0;
497
498 /* Don't use the value of history_control to affect the second
499 and subsequent lines of a multi-line command (old code did
500 this only when command_oriented_history is enabled). */
501 #if 0
502 if (command_oriented_history && current_command_line_count > 1)
503 #else
504 if (current_command_line_count > 1)
505 #endif
506 {
507 if (first_line_saved &&
508 (literal_history || dstack.delimiter_depth != 0 || shell_comment (line) == 0))
509 bash_add_history (line);
510 return;
511 }
512
513 /* This is the first line of a (possible multi-line) command. Note whether
514 or not we should save the first line and remember it. */
515 first_line_saved = 0;
516
517 switch (history_control)
518 {
519 case 0:
520 first_line_saved = 1;
521 break;
522 case 1:
523 if (*line != ' ')
524 first_line_saved = 1;
525 break;
526 case 3:
527 if (*line == ' ')
528 break;
529 /* FALLTHROUGH if case == 3 (`ignoreboth') */
530 case 2:
531 using_history ();
532 temp = previous_history ();
533
534 if (temp == 0 || STREQ (temp->line, line) == 0)
535 first_line_saved = 1;
536
537 using_history ();
538 break;
539 }
540
541 if (first_line_saved && history_should_ignore (line) == 0)
542 bash_add_history (line);
543 else
544 first_line_saved = 0;
545 }
546
547 /* Add a line to the history list.
548 The variable COMMAND_ORIENTED_HISTORY controls the style of history
549 remembering; when non-zero, and LINE is not the first line of a
550 complete parser construct, append LINE to the last history line instead
551 of adding it as a new line. */
552 void
553 bash_add_history (line)
554 char *line;
555 {
556 int add_it, offset, curlen;
557 HIST_ENTRY *current, *old;
558 char *chars_to_add, *new_line;
559
560 add_it = 1;
561 if (command_oriented_history && current_command_line_count > 1)
562 {
563 chars_to_add = literal_history ? "\n" : history_delimiting_chars ();
564
565 using_history ();
566 current = previous_history ();
567
568 if (current)
569 {
570 /* If the previous line ended with an escaped newline (escaped
571 with backslash, but otherwise unquoted), then remove the quoted
572 newline, since that is what happens when the line is parsed. */
573 curlen = strlen (current->line);
574
575 if (dstack.delimiter_depth == 0 && current->line[curlen - 1] == '\\' &&
576 current->line[curlen - 2] != '\\')
577 {
578 current->line[curlen - 1] = '\0';
579 curlen--;
580 chars_to_add = "";
581 }
582
583 new_line = (char *) xmalloc (1
584 + curlen
585 + strlen (line)
586 + strlen (chars_to_add));
587 sprintf (new_line, "%s%s%s", current->line, chars_to_add, line);
588 offset = where_history ();
589 old = replace_history_entry (offset, new_line, current->data);
590 free (new_line);
591
592 if (old)
593 {
594 FREE (old->line);
595 free (old);
596 }
597 add_it = 0;
598 }
599 }
600
601 if (add_it)
602 {
603 hist_last_line_added = 1;
604 add_history (line);
605 history_lines_this_session++;
606 }
607 using_history ();
608 }
609
610 int
611 history_number ()
612 {
613 using_history ();
614 return (get_string_value ("HISTSIZE") ? history_base + where_history () : 1);
615 }
616
617 static int
618 should_expand (s)
619 char *s;
620 {
621 char *p;
622
623 for (p = s; p && *p; p++)
624 {
625 if (*p == '\\')
626 p++;
627 else if (*p == '&')
628 return 1;
629 }
630 return 0;
631 }
632
633 static int
634 histignore_item_func (ign)
635 struct ign *ign;
636 {
637 if (should_expand (ign->val))
638 ign->flags |= HIGN_EXPAND;
639 return (0);
640 }
641
642 void
643 setup_history_ignore (varname)
644 char *varname;
645 {
646 setup_ignore_patterns (&histignore);
647 }
648
649 static HIST_ENTRY *
650 last_history_entry ()
651 {
652 HIST_ENTRY *he;
653
654 using_history ();
655 he = previous_history ();
656 using_history ();
657 return he;
658 }
659
660 char *
661 last_history_line ()
662 {
663 HIST_ENTRY *he;
664
665 he = last_history_entry ();
666 if (he == 0)
667 return ((char *)NULL);
668 return he->line;
669 }
670
671 static char *
672 expand_histignore_pattern (pat)
673 char *pat;
674 {
675 HIST_ENTRY *phe;
676 char *ret;
677
678 phe = last_history_entry ();
679
680 if (phe == (HIST_ENTRY *)0)
681 return (savestring (pat));
682
683 ret = strcreplace (pat, '&', phe->line, 1);
684
685 return ret;
686 }
687
688 /* Return 1 if we should not put LINE into the history according to the
689 patterns in HISTIGNORE. */
690 static int
691 history_should_ignore (line)
692 char *line;
693 {
694 register int i, match;
695 char *npat;
696
697 if (histignore.num_ignores == 0)
698 return 0;
699
700 for (i = match = 0; i < histignore.num_ignores; i++)
701 {
702 if (histignore.ignores[i].flags & HIGN_EXPAND)
703 npat = expand_histignore_pattern (histignore.ignores[i].val);
704 else
705 npat = histignore.ignores[i].val;
706
707 match = fnmatch (npat, line, FNMATCH_EXTFLAG) != FNM_NOMATCH;
708
709 if (histignore.ignores[i].flags & HIGN_EXPAND)
710 free (npat);
711
712 if (match)
713 break;
714 }
715
716 return match;
717 }
718 #endif /* HISTORY */