]>
Commit | Line | Data |
---|---|---|
726f6388 JA |
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, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | ||
ccc6cda3 JA |
21 | #include "config.h" |
22 | ||
23 | #if defined (HISTORY) | |
24 | ||
25 | #if defined (HAVE_UNISTD_H) | |
cce855bc JA |
26 | # ifdef _MINIX |
27 | # include <sys/types.h> | |
28 | # endif | |
ccc6cda3 JA |
29 | # include <unistd.h> |
30 | #endif | |
31 | ||
32 | #include "bashtypes.h" | |
726f6388 JA |
33 | #include <stdio.h> |
34 | #include <errno.h> | |
35 | #include "bashansi.h" | |
36 | #include "posixstat.h" | |
37 | #include "filecntl.h" | |
d166f048 | 38 | |
726f6388 JA |
39 | #include "shell.h" |
40 | #include "flags.h" | |
ccc6cda3 JA |
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" | |
d166f048 | 45 | |
726f6388 | 46 | #include <readline/history.h> |
ccc6cda3 JA |
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 | ||
d166f048 JA |
57 | extern int glob_pattern_p (); |
58 | ||
ccc6cda3 JA |
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 | |
726f6388 JA |
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. */ | |
ccc6cda3 | 79 | int history_lines_this_session; |
726f6388 JA |
80 | |
81 | /* The number of lines that Bash has read from the history file. */ | |
ccc6cda3 | 82 | int history_lines_in_file; |
726f6388 | 83 | |
ccc6cda3 | 84 | #if defined (BANG_HISTORY) |
726f6388 JA |
85 | /* Non-zero means do no history expansion on this line, regardless |
86 | of what history_expansion says. */ | |
ccc6cda3 JA |
87 | int history_expansion_inhibited; |
88 | #endif | |
726f6388 JA |
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 | |
ccc6cda3 JA |
93 | > do |
94 | > echo $i | |
95 | > done | |
726f6388 JA |
96 | Each line will be individually saved in the history. |
97 | bash$ history | |
98 | 10 for i in a b c | |
ccc6cda3 JA |
99 | 11 do |
100 | 12 echo $i | |
101 | 13 done | |
102 | 14 history | |
726f6388 JA |
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 | |
ccc6cda3 JA |
106 | > do |
107 | > echo $i | |
108 | > done | |
109 | bash$ history | |
726f6388 JA |
110 | 10 for i in a b c |
111 | do | |
112 | echo $i | |
113 | done | |
ccc6cda3 | 114 | 11 history |
726f6388 JA |
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 | */ | |
ccc6cda3 JA |
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; | |
726f6388 JA |
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. */ | |
ccc6cda3 JA |
132 | int history_control; |
133 | ||
d166f048 JA |
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 | ||
ccc6cda3 JA |
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; | |
d166f048 JA |
148 | |
149 | #endif /* READLINE */ | |
726f6388 JA |
150 | |
151 | /* Variables declared in other files used here. */ | |
152 | extern int interactive; | |
153 | extern int current_command_line_count; | |
726f6388 | 154 | |
ccc6cda3 JA |
155 | extern struct dstack dstack; |
156 | ||
157 | extern char *extract_colon_unit (); | |
726f6388 JA |
158 | extern char *history_delimiting_chars (); |
159 | extern void maybe_add_history (); /* forward declaration */ | |
d166f048 | 160 | extern void bash_add_history (); /* forward declaration */ |
726f6388 | 161 | |
ccc6cda3 JA |
162 | static int history_should_ignore (); |
163 | ||
d166f048 JA |
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); | |
cce855bc JA |
180 | #if defined (EXTENDED_GLOB) |
181 | else if (extended_glob && i > 1 && string[i+1] == '(' && member (')', string + i + 2)) | |
182 | return (1); | |
183 | #endif | |
d166f048 JA |
184 | else |
185 | return (0); | |
186 | } | |
187 | ||
ccc6cda3 JA |
188 | void |
189 | bash_initialize_history () | |
190 | { | |
191 | history_quotes_inhibit_expansion = 1; | |
192 | history_search_delimiter_chars = ";&()|<>"; | |
d166f048 | 193 | history_inhibit_expansion_function = bash_history_inhibit_expansion; |
ccc6cda3 JA |
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; | |
d166f048 | 205 | history_inhibit_expansion_function = bash_history_inhibit_expansion; |
ccc6cda3 JA |
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 | |
d166f048 | 224 | history_inhibit_expansion_function = bash_history_inhibit_expansion; |
ccc6cda3 JA |
225 | sv_history_control ("HISTCONTROL"); |
226 | sv_histignore ("HISTIGNORE"); | |
227 | } | |
726f6388 JA |
228 | |
229 | /* Load the history list from the history file. */ | |
230 | void | |
231 | load_history () | |
232 | { | |
233 | char *hf; | |
ccc6cda3 | 234 | struct stat buf; |
726f6388 JA |
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")); | |
ccc6cda3 | 241 | sv_histsize ("HISTFILESIZE"); |
726f6388 JA |
242 | |
243 | /* Read the history in HISTFILE into the history list. */ | |
244 | hf = get_string_value ("HISTFILE"); | |
245 | ||
ccc6cda3 | 246 | if (hf && *hf && stat (hf, &buf) == 0) |
726f6388 | 247 | { |
ccc6cda3 JA |
248 | read_history (hf); |
249 | using_history (); | |
250 | history_lines_in_file = where_history (); | |
726f6388 JA |
251 | } |
252 | } | |
253 | ||
d166f048 | 254 | #ifdef INCLUDE_UNUSED |
726f6388 JA |
255 | /* Write the existing history out to the history file. */ |
256 | void | |
257 | save_history () | |
258 | { | |
ccc6cda3 JA |
259 | char *hf; |
260 | struct stat buf; | |
726f6388 | 261 | |
ccc6cda3 JA |
262 | hf = get_string_value ("HISTFILE"); |
263 | if (hf && *hf && stat (hf, &buf) == 0) | |
726f6388 | 264 | { |
ccc6cda3 JA |
265 | /* Append only the lines that occurred this session to |
266 | the history file. */ | |
267 | using_history (); | |
726f6388 | 268 | |
ccc6cda3 JA |
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); | |
726f6388 | 273 | |
ccc6cda3 JA |
274 | sv_histsize ("HISTFILESIZE"); |
275 | } | |
276 | } | |
d166f048 | 277 | #endif |
ccc6cda3 JA |
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 | { | |
b72432fd | 292 | fd = open (filename, O_WRONLY|O_CREAT, 0600); |
ccc6cda3 JA |
293 | if (fd < 0) |
294 | { | |
295 | builtin_error ("%s: cannot create: %s", filename, strerror (errno)); | |
296 | return (EXECUTION_FAILURE); | |
297 | } | |
298 | close (fd); | |
726f6388 | 299 | } |
ccc6cda3 JA |
300 | result = append_history (history_lines_this_session, filename); |
301 | history_lines_in_file += history_lines_this_session; | |
302 | history_lines_this_session = 0; | |
726f6388 | 303 | } |
ccc6cda3 | 304 | return (result); |
726f6388 JA |
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 | { | |
ccc6cda3 JA |
312 | int result; |
313 | char *hf; | |
314 | struct stat buf; | |
726f6388 | 315 | |
ccc6cda3 | 316 | result = 0; |
726f6388 JA |
317 | if (history_lines_this_session) |
318 | { | |
ccc6cda3 | 319 | hf = get_string_value ("HISTFILE"); |
726f6388 JA |
320 | |
321 | if (hf && *hf) | |
322 | { | |
726f6388 JA |
323 | /* If the file doesn't exist, then create it. */ |
324 | if (stat (hf, &buf) == -1) | |
325 | { | |
ccc6cda3 | 326 | int file; |
b72432fd | 327 | file = open (hf, O_CREAT | O_TRUNC | O_WRONLY, 0600); |
726f6388 JA |
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 (); | |
ccc6cda3 | 336 | if (history_lines_this_session <= where_history () || force_append_history) |
726f6388 JA |
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; | |
ccc6cda3 JA |
347 | |
348 | sv_histsize ("HISTFILESIZE"); | |
726f6388 JA |
349 | } |
350 | } | |
351 | return (result); | |
352 | } | |
353 | ||
ccc6cda3 | 354 | #if defined (READLINE) |
726f6388 JA |
355 | /* Tell readline () that we have some text for it to edit. */ |
356 | static void | |
357 | re_edit (text) | |
358 | char *text; | |
359 | { | |
ccc6cda3 | 360 | if (bash_input.type == st_stdin) |
726f6388 | 361 | bash_re_edit (text); |
ccc6cda3 | 362 | } |
726f6388 | 363 | #endif /* READLINE */ |
ccc6cda3 JA |
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; | |
726f6388 | 376 | } |
726f6388 JA |
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; | |
ccc6cda3 | 392 | int expanded; |
726f6388 JA |
393 | |
394 | return_value = line; | |
ccc6cda3 | 395 | expanded = 0; |
726f6388 JA |
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. */ | |
ccc6cda3 | 400 | if (!history_expansion_inhibited && history_expansion && history_expansion_p (line)) |
726f6388 JA |
401 | { |
402 | expanded = history_expand (line, &history_value); | |
403 | ||
404 | if (expanded) | |
405 | { | |
406 | if (print_changes) | |
407 | { | |
408 | if (expanded < 0) | |
cce855bc | 409 | internal_error ("%s", history_value); |
d166f048 | 410 | #if defined (READLINE) |
ccc6cda3 | 411 | else if (hist_verify == 0) |
d166f048 JA |
412 | #else |
413 | else | |
414 | #endif | |
726f6388 JA |
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 | ||
ccc6cda3 | 423 | # if defined (READLINE) |
726f6388 JA |
424 | /* New hack. We can allow the user to edit the |
425 | failed history expansion. */ | |
ccc6cda3 JA |
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); | |
726f6388 JA |
436 | return ((char *)NULL); |
437 | } | |
ccc6cda3 | 438 | # endif |
726f6388 JA |
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 | ||
d166f048 | 452 | #if 0 |
ccc6cda3 | 453 | if (expanded == 0) |
726f6388 | 454 | return_value = savestring (line); |
d166f048 | 455 | #endif |
726f6388 JA |
456 | |
457 | return (return_value); | |
458 | } | |
459 | ||
460 | /* Add LINE to the history list depending on the value of HISTORY_CONTROL. */ | |
461 | void | |
462 | maybe_add_history (line) | |
463 | char *line; | |
464 | { | |
ccc6cda3 JA |
465 | int should_add; |
466 | HIST_ENTRY *temp; | |
467 | ||
d166f048 | 468 | should_add = hist_last_line_added = 0; |
726f6388 JA |
469 | |
470 | /* Don't use the value of history_control to affect the second | |
cce855bc JA |
471 | and subsequent lines of a multi-line command (old code did |
472 | this only when command_oriented_history is enabled). */ | |
473 | #if 0 | |
726f6388 | 474 | if (command_oriented_history && current_command_line_count > 1) |
cce855bc JA |
475 | #else |
476 | if (current_command_line_count > 1) | |
477 | #endif | |
ccc6cda3 JA |
478 | { |
479 | bash_add_history (line); | |
480 | return; | |
481 | } | |
726f6388 | 482 | |
ccc6cda3 | 483 | switch (history_control) |
726f6388 JA |
484 | { |
485 | case 0: | |
ccc6cda3 | 486 | should_add = 1; |
726f6388 JA |
487 | break; |
488 | case 1: | |
489 | if (*line != ' ') | |
ccc6cda3 | 490 | should_add = 1; |
726f6388 JA |
491 | break; |
492 | case 3: | |
493 | if (*line == ' ') | |
ccc6cda3 | 494 | break; |
726f6388 JA |
495 | /* FALLTHROUGH if case == 3 (`ignoreboth') */ |
496 | case 2: | |
ccc6cda3 JA |
497 | using_history (); |
498 | temp = previous_history (); | |
726f6388 | 499 | |
ccc6cda3 JA |
500 | if (temp == 0 || STREQ (temp->line, line) == 0) |
501 | should_add = 1; | |
726f6388 | 502 | |
ccc6cda3 | 503 | using_history (); |
726f6388 JA |
504 | break; |
505 | } | |
ccc6cda3 JA |
506 | |
507 | if (should_add && history_should_ignore (line) == 0) | |
508 | bash_add_history (line); | |
726f6388 JA |
509 | } |
510 | ||
511 | /* Add a line to the history list. | |
512 | The variable COMMAND_ORIENTED_HISTORY controls the style of history | |
513 | remembering; when non-zero, and LINE is not the first line of a | |
514 | complete parser construct, append LINE to the last history line instead | |
515 | of adding it as a new line. */ | |
d166f048 | 516 | void |
726f6388 JA |
517 | bash_add_history (line) |
518 | char *line; | |
519 | { | |
ccc6cda3 JA |
520 | int add_it, offset, curlen; |
521 | HIST_ENTRY *current, *old; | |
522 | char *chars_to_add, *new_line; | |
726f6388 | 523 | |
ccc6cda3 | 524 | add_it = 1; |
726f6388 JA |
525 | if (command_oriented_history && current_command_line_count > 1) |
526 | { | |
ccc6cda3 | 527 | chars_to_add = literal_history ? "\n" : history_delimiting_chars (); |
726f6388 JA |
528 | |
529 | using_history (); | |
726f6388 JA |
530 | current = previous_history (); |
531 | ||
532 | if (current) | |
533 | { | |
534 | /* If the previous line ended with an escaped newline (escaped | |
535 | with backslash, but otherwise unquoted), then remove the quoted | |
536 | newline, since that is what happens when the line is parsed. */ | |
726f6388 JA |
537 | curlen = strlen (current->line); |
538 | ||
ccc6cda3 | 539 | if (dstack.delimiter_depth == 0 && current->line[curlen - 1] == '\\' && |
726f6388 JA |
540 | current->line[curlen - 2] != '\\') |
541 | { | |
542 | current->line[curlen - 1] = '\0'; | |
543 | curlen--; | |
544 | chars_to_add = ""; | |
545 | } | |
546 | ||
726f6388 JA |
547 | new_line = (char *) xmalloc (1 |
548 | + curlen | |
549 | + strlen (line) | |
550 | + strlen (chars_to_add)); | |
551 | sprintf (new_line, "%s%s%s", current->line, chars_to_add, line); | |
ccc6cda3 | 552 | offset = where_history (); |
726f6388 JA |
553 | old = replace_history_entry (offset, new_line, current->data); |
554 | free (new_line); | |
555 | ||
556 | if (old) | |
557 | { | |
ccc6cda3 | 558 | FREE (old->line); |
726f6388 JA |
559 | free (old); |
560 | } | |
561 | add_it = 0; | |
562 | } | |
563 | } | |
564 | ||
565 | if (add_it) | |
566 | { | |
d166f048 | 567 | hist_last_line_added = 1; |
726f6388 JA |
568 | add_history (line); |
569 | history_lines_this_session++; | |
570 | } | |
571 | using_history (); | |
572 | } | |
573 | ||
574 | int | |
575 | history_number () | |
576 | { | |
577 | using_history (); | |
ccc6cda3 JA |
578 | return (get_string_value ("HISTSIZE") ? history_base + where_history () : 1); |
579 | } | |
580 | ||
581 | static int | |
582 | should_expand (s) | |
583 | char *s; | |
584 | { | |
585 | char *p; | |
586 | ||
587 | for (p = s; p && *p; p++) | |
588 | { | |
589 | if (*p == '\\') | |
590 | p++; | |
591 | else if (*p == '&') | |
592 | return 1; | |
593 | } | |
594 | return 0; | |
595 | } | |
596 | ||
597 | static int | |
598 | histignore_item_func (ign) | |
599 | struct ign *ign; | |
600 | { | |
601 | if (should_expand (ign->val)) | |
602 | ign->flags |= HIGN_EXPAND; | |
603 | return (0); | |
604 | } | |
605 | ||
606 | void | |
607 | setup_history_ignore (varname) | |
608 | char *varname; | |
609 | { | |
610 | setup_ignore_patterns (&histignore); | |
611 | } | |
612 | ||
613 | static HIST_ENTRY * | |
614 | last_history_entry () | |
615 | { | |
616 | HIST_ENTRY *he; | |
617 | ||
618 | using_history (); | |
619 | he = previous_history (); | |
620 | using_history (); | |
621 | return he; | |
622 | } | |
623 | ||
624 | char * | |
625 | last_history_line () | |
626 | { | |
627 | HIST_ENTRY *he; | |
628 | ||
629 | he = last_history_entry (); | |
630 | if (he == 0) | |
631 | return ((char *)NULL); | |
632 | return he->line; | |
633 | } | |
634 | ||
635 | static char * | |
636 | expand_histignore_pattern (pat) | |
637 | char *pat; | |
638 | { | |
639 | HIST_ENTRY *phe; | |
640 | char *ret, *p, *r, *t; | |
641 | int len, rlen, ind, tlen; | |
642 | ||
643 | phe = last_history_entry (); | |
644 | ||
645 | if (phe == (HIST_ENTRY *)0) | |
646 | return (savestring (pat)); | |
647 | ||
648 | len = strlen (phe->line); | |
649 | rlen = len + strlen (pat) + 2; | |
650 | ret = xmalloc (rlen); | |
651 | ||
652 | for (p = pat, r = ret; p && *p; ) | |
653 | { | |
654 | if (*p == '&') | |
655 | { | |
656 | ind = r - ret; | |
657 | if (glob_pattern_p (phe->line) || strchr (phe->line, '\\')) | |
658 | { | |
659 | t = quote_globbing_chars (phe->line); | |
660 | tlen = strlen (t); | |
661 | RESIZE_MALLOCED_BUFFER (ret, ind, tlen, rlen, rlen); | |
662 | r = ret + ind; /* in case reallocated */ | |
663 | strcpy (r, t); | |
664 | r += tlen; | |
665 | free (t); | |
666 | } | |
667 | else | |
668 | { | |
669 | tlen = strlen (phe->line); | |
670 | RESIZE_MALLOCED_BUFFER (ret, ind, tlen, rlen, rlen); | |
671 | r = ret + ind; /* in case reallocated */ | |
672 | strcpy (r, phe->line); | |
673 | r += len; | |
674 | } | |
675 | p++; | |
676 | continue; | |
677 | } | |
678 | ||
679 | if (*p == '\\' && p[1] == '&') | |
680 | p++; | |
681 | ||
682 | *r++ = *p++; | |
683 | } | |
684 | *r = '\0'; | |
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 | ||
cce855bc | 707 | match = fnmatch (npat, line, FNMATCH_EXTFLAG) != FNM_NOMATCH; |
ccc6cda3 JA |
708 | |
709 | if (histignore.ignores[i].flags & HIGN_EXPAND) | |
710 | free (npat); | |
711 | ||
712 | if (match) | |
713 | break; | |
714 | } | |
715 | ||
716 | return match; | |
726f6388 | 717 | } |
ccc6cda3 | 718 | #endif /* HISTORY */ |