]> git.ipfire.org Git - thirdparty/bash.git/blame - lib/readline/histexpand.c
Imported from ../bash-2.05.tar.gz.
[thirdparty/bash.git] / lib / readline / histexpand.c
CommitLineData
ccc6cda3
JA
1/* histexpand.c -- history expansion. */
2
3/* Copyright (C) 1989, 1992 Free Software Foundation, Inc.
4
5 This file contains the GNU History Library (the Library), a set of
6 routines for managing the text of previously typed lines.
7
8 The Library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
bb70624e 10 the Free Software Foundation; either version 2, or (at your option)
ccc6cda3
JA
11 any later version.
12
13 The Library is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 The GNU General Public License is often shipped with GNU software, and
19 is generally kept in a file called COPYING or LICENSE. If you do not
20 have a copy of the license, write to the Free Software Foundation,
bb70624e 21 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
ccc6cda3
JA
22
23#define READLINE_LIBRARY
24
25#if defined (HAVE_CONFIG_H)
26# include <config.h>
27#endif
28
29#include <stdio.h>
30
31#if defined (HAVE_STDLIB_H)
32# include <stdlib.h>
33#else
34# include "ansi_stdlib.h"
35#endif /* HAVE_STDLIB_H */
36
37#if defined (HAVE_UNISTD_H)
cce855bc
JA
38# ifndef _MINIX
39# include <sys/types.h>
40# endif
ccc6cda3
JA
41# include <unistd.h>
42#endif
43
44#if defined (HAVE_STRING_H)
45# include <string.h>
46#else
47# include <strings.h>
48#endif /* !HAVE_STRING_H */
49
50#include "history.h"
51#include "histlib.h"
52
bb70624e
JA
53#include "rlshell.h"
54#include "xmalloc.h"
55
cce855bc
JA
56#define HISTORY_WORD_DELIMITERS " \t\n;&()|<>"
57#define HISTORY_QUOTE_CHARACTERS "\"'`"
58
28ef6c31
JA
59typedef int _hist_search_func_t __P((const char *, int));
60
ccc6cda3
JA
61static char error_pointer;
62
63static char *subst_lhs;
64static char *subst_rhs;
65static int subst_lhs_len;
66static int subst_rhs_len;
67
bb70624e
JA
68static char *get_history_word_specifier __P((char *, char *, int *));
69static char *history_find_word __P((char *, int));
ccc6cda3 70
bb70624e 71static char *quote_breaks __P((char *));
ccc6cda3
JA
72
73/* Variables exported by this file. */
74/* The character that represents the start of a history expansion
75 request. This is usually `!'. */
76char history_expansion_char = '!';
77
78/* The character that invokes word substitution if found at the start of
79 a line. This is usually `^'. */
80char history_subst_char = '^';
81
82/* During tokenization, if this character is seen as the first character
83 of a word, then it, and all subsequent characters upto a newline are
84 ignored. For a Bourne shell, this should be '#'. Bash special cases
85 the interactive comment character to not be a comment delimiter. */
86char history_comment_char = '\0';
87
88/* The list of characters which inhibit the expansion of text if found
89 immediately following history_expansion_char. */
90char *history_no_expand_chars = " \t\n\r=";
91
92/* If set to a non-zero value, single quotes inhibit history expansion.
93 The default is 0. */
94int history_quotes_inhibit_expansion = 0;
95
28ef6c31
JA
96/* Used to split words by history_tokenize_internal. */
97char *history_word_delimiters = HISTORY_WORD_DELIMITERS;
98
d166f048
JA
99/* If set, this points to a function that is called to verify that a
100 particular history expansion should be performed. */
28ef6c31 101rl_linebuf_func_t *history_inhibit_expansion_function;
d166f048 102
ccc6cda3
JA
103/* **************************************************************** */
104/* */
105/* History Expansion */
106/* */
107/* **************************************************************** */
108
109/* Hairy history expansion on text, not tokens. This is of general
110 use, and thus belongs in this library. */
111
112/* The last string searched for by a !?string? search. */
113static char *search_string;
114
115/* The last string matched by a !?string? search. */
116static char *search_match;
117
118/* Return the event specified at TEXT + OFFSET modifying OFFSET to
119 point to after the event specifier. Just a pointer to the history
120 line is returned; NULL is returned in the event of a bad specifier.
121 You pass STRING with *INDEX equal to the history_expansion_char that
122 begins this specification.
123 DELIMITING_QUOTE is a character that is allowed to end the string
124 specification for what to search for in addition to the normal
125 characters `:', ` ', `\t', `\n', and sometimes `?'.
126 So you might call this function like:
127 line = get_history_event ("!echo:p", &index, 0); */
128char *
129get_history_event (string, caller_index, delimiting_quote)
28ef6c31 130 const char *string;
ccc6cda3
JA
131 int *caller_index;
132 int delimiting_quote;
133{
134 register int i;
135 register char c;
136 HIST_ENTRY *entry;
137 int which, sign, local_index, substring_okay;
28ef6c31 138 _hist_search_func_t *search_func;
ccc6cda3
JA
139 char *temp;
140
141 /* The event can be specified in a number of ways.
142
143 !! the previous command
144 !n command line N
145 !-n current command-line minus N
146 !str the most recent command starting with STR
147 !?str[?]
148 the most recent command containing STR
149
150 All values N are determined via HISTORY_BASE. */
151
152 i = *caller_index;
153
154 if (string[i] != history_expansion_char)
155 return ((char *)NULL);
156
157 /* Move on to the specification. */
158 i++;
159
160 sign = 1;
161 substring_okay = 0;
162
163#define RETURN_ENTRY(e, w) \
164 return ((e = history_get (w)) ? e->line : (char *)NULL)
165
166 /* Handle !! case. */
167 if (string[i] == history_expansion_char)
168 {
169 i++;
170 which = history_base + (history_length - 1);
171 *caller_index = i;
172 RETURN_ENTRY (entry, which);
173 }
174
175 /* Hack case of numeric line specification. */
176 if (string[i] == '-')
177 {
178 sign = -1;
179 i++;
180 }
181
182 if (_rl_digit_p (string[i]))
183 {
184 /* Get the extent of the digits and compute the value. */
185 for (which = 0; _rl_digit_p (string[i]); i++)
186 which = (which * 10) + _rl_digit_value (string[i]);
187
188 *caller_index = i;
189
190 if (sign < 0)
191 which = (history_length + history_base) - which;
192
193 RETURN_ENTRY (entry, which);
194 }
195
196 /* This must be something to search for. If the spec begins with
197 a '?', then the string may be anywhere on the line. Otherwise,
198 the string must be found at the start of a line. */
199 if (string[i] == '?')
200 {
201 substring_okay++;
202 i++;
203 }
204
205 /* Only a closing `?' or a newline delimit a substring search string. */
206 for (local_index = i; c = string[i]; i++)
207 if ((!substring_okay && (whitespace (c) || c == ':' ||
208 (history_search_delimiter_chars && member (c, history_search_delimiter_chars)) ||
209 string[i] == delimiting_quote)) ||
210 string[i] == '\n' ||
211 (substring_okay && string[i] == '?'))
212 break;
213
214 which = i - local_index;
215 temp = xmalloc (1 + which);
216 if (which)
217 strncpy (temp, string + local_index, which);
218 temp[which] = '\0';
219
220 if (substring_okay && string[i] == '?')
221 i++;
222
223 *caller_index = i;
224
225#define FAIL_SEARCH() \
226 do { \
227 history_offset = history_length; free (temp) ; return (char *)NULL; \
228 } while (0)
229
230 /* If there is no search string, try to use the previous search string,
231 if one exists. If not, fail immediately. */
232 if (*temp == '\0' && substring_okay)
233 {
234 if (search_string)
235 {
236 free (temp);
237 temp = savestring (search_string);
238 }
239 else
240 FAIL_SEARCH ();
241 }
242
243 search_func = substring_okay ? history_search : history_search_prefix;
244 while (1)
245 {
246 local_index = (*search_func) (temp, -1);
247
248 if (local_index < 0)
249 FAIL_SEARCH ();
250
251 if (local_index == 0 || substring_okay)
252 {
253 entry = current_history ();
254 history_offset = history_length;
255
256 /* If this was a substring search, then remember the
257 string that we matched for word substitution. */
258 if (substring_okay)
259 {
260 FREE (search_string);
261 search_string = temp;
262
263 FREE (search_match);
264 search_match = history_find_word (entry->line, local_index);
265 }
266 else
267 free (temp);
268
269 return (entry->line);
270 }
271
272 if (history_offset)
273 history_offset--;
274 else
275 FAIL_SEARCH ();
276 }
277#undef FAIL_SEARCH
278#undef RETURN_ENTRY
279}
280
281/* Function for extracting single-quoted strings. Used for inhibiting
282 history expansion within single quotes. */
283
284/* Extract the contents of STRING as if it is enclosed in single quotes.
285 SINDEX, when passed in, is the offset of the character immediately
286 following the opening single quote; on exit, SINDEX is left pointing
287 to the closing single quote. */
288static void
289hist_string_extract_single_quoted (string, sindex)
290 char *string;
291 int *sindex;
292{
293 register int i;
294
295 for (i = *sindex; string[i] && string[i] != '\''; i++)
296 ;
297
298 *sindex = i;
299}
300
ccc6cda3
JA
301static char *
302quote_breaks (s)
303 char *s;
304{
305 register char *p, *r;
306 char *ret;
307 int len = 3;
308
309 for (p = s; p && *p; p++, len++)
310 {
311 if (*p == '\'')
312 len += 3;
313 else if (whitespace (*p) || *p == '\n')
314 len += 2;
315 }
316
317 r = ret = xmalloc (len);
318 *r++ = '\'';
319 for (p = s; p && *p; )
320 {
321 if (*p == '\'')
322 {
323 *r++ = '\'';
324 *r++ = '\\';
325 *r++ = '\'';
326 *r++ = '\'';
327 p++;
328 }
329 else if (whitespace (*p) || *p == '\n')
330 {
331 *r++ = '\'';
332 *r++ = *p++;
333 *r++ = '\'';
334 }
335 else
336 *r++ = *p++;
337 }
338 *r++ = '\'';
339 *r = '\0';
340 return ret;
341}
342
343static char *
344hist_error(s, start, current, errtype)
345 char *s;
346 int start, current, errtype;
347{
28ef6c31
JA
348 char *temp;
349 const char *emsg;
ccc6cda3
JA
350 int ll, elen;
351
352 ll = current - start;
353
354 switch (errtype)
355 {
356 case EVENT_NOT_FOUND:
357 emsg = "event not found";
358 elen = 15;
359 break;
360 case BAD_WORD_SPEC:
361 emsg = "bad word specifier";
362 elen = 18;
363 break;
364 case SUBST_FAILED:
365 emsg = "substitution failed";
366 elen = 19;
367 break;
368 case BAD_MODIFIER:
369 emsg = "unrecognized history modifier";
370 elen = 29;
371 break;
b72432fd
JA
372 case NO_PREV_SUBST:
373 emsg = "no previous substitution";
374 elen = 24;
375 break;
ccc6cda3
JA
376 default:
377 emsg = "unknown expansion error";
378 elen = 23;
379 break;
380 }
381
382 temp = xmalloc (ll + elen + 3);
383 strncpy (temp, s + start, ll);
384 temp[ll] = ':';
385 temp[ll + 1] = ' ';
386 strcpy (temp + ll + 2, emsg);
387 return (temp);
388}
389
390/* Get a history substitution string from STR starting at *IPTR
391 and return it. The length is returned in LENPTR.
392
393 A backslash can quote the delimiter. If the string is the
394 empty string, the previous pattern is used. If there is
395 no previous pattern for the lhs, the last history search
396 string is used.
397
398 If IS_RHS is 1, we ignore empty strings and set the pattern
399 to "" anyway. subst_lhs is not changed if the lhs is empty;
400 subst_rhs is allowed to be set to the empty string. */
401
402static char *
403get_subst_pattern (str, iptr, delimiter, is_rhs, lenptr)
404 char *str;
405 int *iptr, delimiter, is_rhs, *lenptr;
406{
407 register int si, i, j, k;
408 char *s = (char *) NULL;
409
410 i = *iptr;
411
412 for (si = i; str[si] && str[si] != delimiter; si++)
413 if (str[si] == '\\' && str[si + 1] == delimiter)
414 si++;
415
416 if (si > i || is_rhs)
417 {
418 s = xmalloc (si - i + 1);
419 for (j = 0, k = i; k < si; j++, k++)
420 {
421 /* Remove a backslash quoting the search string delimiter. */
422 if (str[k] == '\\' && str[k + 1] == delimiter)
423 k++;
424 s[j] = str[k];
425 }
426 s[j] = '\0';
427 if (lenptr)
428 *lenptr = j;
429 }
430
431 i = si;
432 if (str[i])
433 i++;
434 *iptr = i;
435
436 return s;
437}
438
439static void
440postproc_subst_rhs ()
441{
442 char *new;
443 int i, j, new_size;
444
445 new = xmalloc (new_size = subst_rhs_len + subst_lhs_len);
446 for (i = j = 0; i < subst_rhs_len; i++)
447 {
448 if (subst_rhs[i] == '&')
449 {
450 if (j + subst_lhs_len >= new_size)
451 new = xrealloc (new, (new_size = new_size * 2 + subst_lhs_len));
452 strcpy (new + j, subst_lhs);
453 j += subst_lhs_len;
454 }
455 else
456 {
457 /* a single backslash protects the `&' from lhs interpolation */
458 if (subst_rhs[i] == '\\' && subst_rhs[i + 1] == '&')
459 i++;
460 if (j >= new_size)
461 new = xrealloc (new, new_size *= 2);
462 new[j++] = subst_rhs[i];
463 }
464 }
465 new[j] = '\0';
466 free (subst_rhs);
467 subst_rhs = new;
468 subst_rhs_len = j;
469}
470
471/* Expand the bulk of a history specifier starting at STRING[START].
472 Returns 0 if everything is OK, -1 if an error occurred, and 1
473 if the `p' modifier was supplied and the caller should just print
474 the returned string. Returns the new index into string in
475 *END_INDEX_PTR, and the expanded specifier in *RET_STRING. */
476static int
477history_expand_internal (string, start, end_index_ptr, ret_string, current_line)
478 char *string;
479 int start, *end_index_ptr;
480 char **ret_string;
481 char *current_line; /* for !# */
482{
483 int i, n, starting_index;
484 int substitute_globally, want_quotes, print_only;
485 char *event, *temp, *result, *tstr, *t, c, *word_spec;
486 int result_len;
487
488 result = xmalloc (result_len = 128);
489
490 i = start;
491
492 /* If it is followed by something that starts a word specifier,
493 then !! is implied as the event specifier. */
494
495 if (member (string[i + 1], ":$*%^"))
496 {
497 char fake_s[3];
498 int fake_i = 0;
499 i++;
500 fake_s[0] = fake_s[1] = history_expansion_char;
501 fake_s[2] = '\0';
502 event = get_history_event (fake_s, &fake_i, 0);
503 }
504 else if (string[i + 1] == '#')
505 {
506 i += 2;
507 event = current_line;
508 }
509 else
510 {
511 int quoted_search_delimiter = 0;
512
513 /* If the character before this `!' is a double or single
514 quote, then this expansion takes place inside of the
515 quoted string. If we have to search for some text ("!foo"),
516 allow the delimiter to end the search string. */
517 if (i && (string[i - 1] == '\'' || string[i - 1] == '"'))
518 quoted_search_delimiter = string[i - 1];
519 event = get_history_event (string, &i, quoted_search_delimiter);
520 }
521
522 if (event == 0)
523 {
524 *ret_string = hist_error (string, start, i, EVENT_NOT_FOUND);
525 free (result);
526 return (-1);
527 }
528
529 /* If a word specifier is found, then do what that requires. */
530 starting_index = i;
531 word_spec = get_history_word_specifier (string, event, &i);
532
533 /* There is no such thing as a `malformed word specifier'. However,
534 it is possible for a specifier that has no match. In that case,
535 we complain. */
536 if (word_spec == (char *)&error_pointer)
537 {
538 *ret_string = hist_error (string, starting_index, i, BAD_WORD_SPEC);
539 free (result);
540 return (-1);
541 }
542
543 /* If no word specifier, than the thing of interest was the event. */
544 temp = word_spec ? savestring (word_spec) : savestring (event);
545 FREE (word_spec);
546
547 /* Perhaps there are other modifiers involved. Do what they say. */
548 want_quotes = substitute_globally = print_only = 0;
549 starting_index = i;
550
551 while (string[i] == ':')
552 {
553 c = string[i + 1];
554
555 if (c == 'g')
556 {
557 substitute_globally = 1;
558 i++;
559 c = string[i + 1];
560 }
561
562 switch (c)
563 {
564 default:
565 *ret_string = hist_error (string, i+1, i+2, BAD_MODIFIER);
566 free (result);
567 free (temp);
568 return -1;
569
570 case 'q':
571 want_quotes = 'q';
572 break;
573
574 case 'x':
575 want_quotes = 'x';
576 break;
577
578 /* :p means make this the last executed line. So we
579 return an error state after adding this line to the
580 history. */
581 case 'p':
582 print_only++;
583 break;
584
585 /* :t discards all but the last part of the pathname. */
586 case 't':
587 tstr = strrchr (temp, '/');
588 if (tstr)
589 {
590 tstr++;
591 t = savestring (tstr);
592 free (temp);
593 temp = t;
594 }
595 break;
596
597 /* :h discards the last part of a pathname. */
598 case 'h':
599 tstr = strrchr (temp, '/');
600 if (tstr)
601 *tstr = '\0';
602 break;
603
604 /* :r discards the suffix. */
605 case 'r':
606 tstr = strrchr (temp, '.');
607 if (tstr)
608 *tstr = '\0';
609 break;
610
611 /* :e discards everything but the suffix. */
612 case 'e':
613 tstr = strrchr (temp, '.');
614 if (tstr)
615 {
616 t = savestring (tstr);
617 free (temp);
618 temp = t;
619 }
620 break;
621
622 /* :s/this/that substitutes `that' for the first
623 occurrence of `this'. :gs/this/that substitutes `that'
624 for each occurrence of `this'. :& repeats the last
625 substitution. :g& repeats the last substitution
626 globally. */
627
628 case '&':
629 case 's':
630 {
28ef6c31 631 char *new_event;
ccc6cda3
JA
632 int delimiter, failed, si, l_temp;
633
634 if (c == 's')
635 {
636 if (i + 2 < (int)strlen (string))
637 delimiter = string[i + 2];
638 else
639 break; /* no search delimiter */
640
641 i += 3;
642
643 t = get_subst_pattern (string, &i, delimiter, 0, &subst_lhs_len);
644 /* An empty substitution lhs with no previous substitution
645 uses the last search string as the lhs. */
646 if (t)
647 {
648 FREE (subst_lhs);
649 subst_lhs = t;
650 }
651 else if (!subst_lhs)
652 {
653 if (search_string && *search_string)
654 {
655 subst_lhs = savestring (search_string);
656 subst_lhs_len = strlen (subst_lhs);
657 }
658 else
659 {
660 subst_lhs = (char *) NULL;
661 subst_lhs_len = 0;
662 }
663 }
664
ccc6cda3
JA
665 FREE (subst_rhs);
666 subst_rhs = get_subst_pattern (string, &i, delimiter, 1, &subst_rhs_len);
667
668 /* If `&' appears in the rhs, it's supposed to be replaced
669 with the lhs. */
670 if (member ('&', subst_rhs))
671 postproc_subst_rhs ();
672 }
673 else
674 i += 2;
675
b72432fd
JA
676 /* If there is no lhs, the substitution can't succeed. */
677 if (subst_lhs_len == 0)
678 {
679 *ret_string = hist_error (string, starting_index, i, NO_PREV_SUBST);
680 free (result);
681 free (temp);
682 return -1;
683 }
684
ccc6cda3
JA
685 l_temp = strlen (temp);
686 /* Ignore impossible cases. */
687 if (subst_lhs_len > l_temp)
688 {
689 *ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
690 free (result);
691 free (temp);
692 return (-1);
693 }
694
695 /* Find the first occurrence of THIS in TEMP. */
696 si = 0;
697 for (failed = 1; (si + subst_lhs_len) <= l_temp; si++)
698 if (STREQN (temp+si, subst_lhs, subst_lhs_len))
699 {
700 int len = subst_rhs_len - subst_lhs_len + l_temp;
701 new_event = xmalloc (1 + len);
702 strncpy (new_event, temp, si);
703 strncpy (new_event + si, subst_rhs, subst_rhs_len);
704 strncpy (new_event + si + subst_rhs_len,
705 temp + si + subst_lhs_len,
706 l_temp - (si + subst_lhs_len));
707 new_event[len] = '\0';
708 free (temp);
709 temp = new_event;
710
711 failed = 0;
712
713 if (substitute_globally)
714 {
715 si += subst_rhs_len;
716 l_temp = strlen (temp);
717 substitute_globally++;
718 continue;
719 }
720 else
721 break;
722 }
723
724 if (substitute_globally > 1)
725 {
726 substitute_globally = 0;
727 continue; /* don't want to increment i */
728 }
729
730 if (failed == 0)
731 continue; /* don't want to increment i */
732
733 *ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
734 free (result);
735 free (temp);
736 return (-1);
737 }
738 }
739 i += 2;
740 }
741 /* Done with modfiers. */
742 /* Believe it or not, we have to back the pointer up by one. */
743 --i;
744
745 if (want_quotes)
746 {
747 char *x;
748
749 if (want_quotes == 'q')
28ef6c31 750 x = sh_single_quote (temp);
ccc6cda3
JA
751 else if (want_quotes == 'x')
752 x = quote_breaks (temp);
753 else
754 x = savestring (temp);
755
756 free (temp);
757 temp = x;
758 }
759
760 n = strlen (temp);
761 if (n >= result_len)
762 result = xrealloc (result, n + 2);
763 strcpy (result, temp);
764 free (temp);
765
766 *end_index_ptr = i;
767 *ret_string = result;
768 return (print_only);
769}
770
771/* Expand the string STRING, placing the result into OUTPUT, a pointer
772 to a string. Returns:
773
774 -1) If there was an error in expansion.
775 0) If no expansions took place (or, if the only change in
776 the text was the de-slashifying of the history expansion
777 character)
778 1) If expansions did take place
779 2) If the `p' modifier was given and the caller should print the result
780
781 If an error ocurred in expansion, then OUTPUT contains a descriptive
782 error message. */
783
784#define ADD_STRING(s) \
785 do \
786 { \
787 int sl = strlen (s); \
788 j += sl; \
789 if (j >= result_len) \
790 { \
791 while (j >= result_len) \
792 result_len += 128; \
793 result = xrealloc (result, result_len); \
794 } \
795 strcpy (result + j - sl, s); \
796 } \
797 while (0)
798
799#define ADD_CHAR(c) \
800 do \
801 { \
802 if (j >= result_len - 1) \
803 result = xrealloc (result, result_len += 64); \
804 result[j++] = c; \
805 result[j] = '\0'; \
806 } \
807 while (0)
808
809int
810history_expand (hstring, output)
811 char *hstring;
812 char **output;
813{
814 register int j;
815 int i, r, l, passc, cc, modified, eindex, only_printing;
816 char *string;
817
818 /* The output string, and its length. */
819 int result_len;
820 char *result;
821
822 /* Used when adding the string. */
823 char *temp;
824
28ef6c31
JA
825 if (output == 0)
826 return 0;
827
ccc6cda3
JA
828 /* Setting the history expansion character to 0 inhibits all
829 history expansion. */
830 if (history_expansion_char == 0)
831 {
832 *output = savestring (hstring);
833 return (0);
834 }
835
836 /* Prepare the buffer for printing error messages. */
837 result = xmalloc (result_len = 256);
838 result[0] = '\0';
839
840 only_printing = modified = 0;
841 l = strlen (hstring);
842
cce855bc
JA
843 /* Grovel the string. Only backslash and single quotes can quote the
844 history escape character. We also handle arg specifiers. */
ccc6cda3
JA
845
846 /* Before we grovel forever, see if the history_expansion_char appears
847 anywhere within the text. */
848
849 /* The quick substitution character is a history expansion all right. That
850 is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact,
851 that is the substitution that we do. */
852 if (hstring[0] == history_subst_char)
853 {
854 string = xmalloc (l + 5);
855
856 string[0] = string[1] = history_expansion_char;
857 string[2] = ':';
858 string[3] = 's';
859 strcpy (string + 4, hstring);
860 l += 4;
861 }
862 else
863 {
864 string = hstring;
865 /* If not quick substitution, still maybe have to do expansion. */
866
867 /* `!' followed by one of the characters in history_no_expand_chars
868 is NOT an expansion. */
869 for (i = 0; string[i]; i++)
870 {
871 cc = string[i + 1];
cce855bc
JA
872 /* The history_comment_char, if set, appearing that the beginning
873 of a word signifies that the rest of the line should not have
874 history expansion performed on it.
875 Skip the rest of the line and break out of the loop. */
876 if (history_comment_char && string[i] == history_comment_char &&
28ef6c31 877 (i == 0 || member (string[i - 1], history_word_delimiters)))
cce855bc
JA
878 {
879 while (string[i])
880 i++;
881 break;
882 }
883 else if (string[i] == history_expansion_char)
ccc6cda3
JA
884 {
885 if (!cc || member (cc, history_no_expand_chars))
886 continue;
d166f048
JA
887 /* If the calling application has set
888 history_inhibit_expansion_function to a function that checks
889 for special cases that should not be history expanded,
890 call the function and skip the expansion if it returns a
891 non-zero value. */
892 else if (history_inhibit_expansion_function &&
893 (*history_inhibit_expansion_function) (string, i))
ccc6cda3 894 continue;
ccc6cda3
JA
895 else
896 break;
897 }
cce855bc
JA
898 /* XXX - at some point, might want to extend this to handle
899 double quotes as well. */
ccc6cda3
JA
900 else if (history_quotes_inhibit_expansion && string[i] == '\'')
901 {
902 /* If this is bash, single quotes inhibit history expansion. */
903 i++;
904 hist_string_extract_single_quoted (string, &i);
905 }
906 else if (history_quotes_inhibit_expansion && string[i] == '\\')
907 {
908 /* If this is bash, allow backslashes to quote single
909 quotes and the history expansion character. */
910 if (cc == '\'' || cc == history_expansion_char)
911 i++;
912 }
913 }
914
915 if (string[i] != history_expansion_char)
916 {
917 free (result);
918 *output = savestring (string);
919 return (0);
920 }
921 }
922
923 /* Extract and perform the substitution. */
924 for (passc = i = j = 0; i < l; i++)
925 {
926 int tchar = string[i];
927
928 if (passc)
929 {
930 passc = 0;
931 ADD_CHAR (tchar);
932 continue;
933 }
934
935 if (tchar == history_expansion_char)
936 tchar = -3;
cce855bc
JA
937 else if (tchar == history_comment_char)
938 tchar = -2;
ccc6cda3
JA
939
940 switch (tchar)
941 {
942 default:
943 ADD_CHAR (string[i]);
944 break;
945
946 case '\\':
947 passc++;
948 ADD_CHAR (tchar);
949 break;
950
951 case '\'':
952 {
953 /* If history_quotes_inhibit_expansion is set, single quotes
954 inhibit history expansion. */
955 if (history_quotes_inhibit_expansion)
956 {
957 int quote, slen;
958
959 quote = i++;
960 hist_string_extract_single_quoted (string, &i);
961
962 slen = i - quote + 2;
963 temp = xmalloc (slen);
964 strncpy (temp, string + quote, slen);
965 temp[slen - 1] = '\0';
966 ADD_STRING (temp);
967 free (temp);
968 }
969 else
970 ADD_CHAR (string[i]);
971 break;
972 }
973
cce855bc 974 case -2: /* history_comment_char */
28ef6c31 975 if (i == 0 || member (string[i - 1], history_word_delimiters))
cce855bc
JA
976 {
977 temp = xmalloc (l - i + 1);
978 strcpy (temp, string + i);
979 ADD_STRING (temp);
980 free (temp);
981 i = l;
982 }
983 else
984 ADD_CHAR (string[i]);
985 break;
986
ccc6cda3
JA
987 case -3: /* history_expansion_char */
988 cc = string[i + 1];
989
990 /* If the history_expansion_char is followed by one of the
991 characters in history_no_expand_chars, then it is not a
992 candidate for expansion of any kind. */
993 if (member (cc, history_no_expand_chars))
994 {
995 ADD_CHAR (string[i]);
996 break;
997 }
998
999#if defined (NO_BANG_HASH_MODIFIERS)
1000 /* There is something that is listed as a `word specifier' in csh
1001 documentation which means `the expanded text to this point'.
1002 That is not a word specifier, it is an event specifier. If we
1003 don't want to allow modifiers with `!#', just stick the current
1004 output line in again. */
1005 if (cc == '#')
1006 {
1007 if (result)
1008 {
1009 temp = xmalloc (1 + strlen (result));
1010 strcpy (temp, result);
1011 ADD_STRING (temp);
1012 free (temp);
1013 }
1014 i++;
1015 break;
1016 }
1017#endif
1018
1019 r = history_expand_internal (string, i, &eindex, &temp, result);
1020 if (r < 0)
1021 {
1022 *output = temp;
1023 free (result);
1024 if (string != hstring)
1025 free (string);
1026 return -1;
1027 }
1028 else
1029 {
1030 if (temp)
1031 {
1032 modified++;
1033 if (*temp)
1034 ADD_STRING (temp);
1035 free (temp);
1036 }
1037 only_printing = r == 1;
1038 i = eindex;
1039 }
1040 break;
1041 }
1042 }
1043
1044 *output = result;
1045 if (string != hstring)
1046 free (string);
1047
1048 if (only_printing)
1049 {
1050 add_history (result);
1051 return (2);
1052 }
1053
1054 return (modified != 0);
1055}
1056
1057/* Return a consed string which is the word specified in SPEC, and found
1058 in FROM. NULL is returned if there is no spec. The address of
1059 ERROR_POINTER is returned if the word specified cannot be found.
1060 CALLER_INDEX is the offset in SPEC to start looking; it is updated
1061 to point to just after the last character parsed. */
1062static char *
1063get_history_word_specifier (spec, from, caller_index)
1064 char *spec, *from;
1065 int *caller_index;
1066{
1067 register int i = *caller_index;
1068 int first, last;
1069 int expecting_word_spec = 0;
1070 char *result;
1071
1072 /* The range of words to return doesn't exist yet. */
1073 first = last = 0;
1074 result = (char *)NULL;
1075
1076 /* If we found a colon, then this *must* be a word specification. If
1077 it isn't, then it is an error. */
1078 if (spec[i] == ':')
1079 {
1080 i++;
1081 expecting_word_spec++;
1082 }
1083
1084 /* Handle special cases first. */
1085
1086 /* `%' is the word last searched for. */
1087 if (spec[i] == '%')
1088 {
1089 *caller_index = i + 1;
1090 return (search_match ? savestring (search_match) : savestring (""));
1091 }
1092
1093 /* `*' matches all of the arguments, but not the command. */
1094 if (spec[i] == '*')
1095 {
1096 *caller_index = i + 1;
1097 result = history_arg_extract (1, '$', from);
1098 return (result ? result : savestring (""));
1099 }
1100
1101 /* `$' is last arg. */
1102 if (spec[i] == '$')
1103 {
1104 *caller_index = i + 1;
1105 return (history_arg_extract ('$', '$', from));
1106 }
1107
1108 /* Try to get FIRST and LAST figured out. */
1109
1110 if (spec[i] == '-')
1111 first = 0;
1112 else if (spec[i] == '^')
1113 first = 1;
1114 else if (_rl_digit_p (spec[i]) && expecting_word_spec)
1115 {
1116 for (first = 0; _rl_digit_p (spec[i]); i++)
1117 first = (first * 10) + _rl_digit_value (spec[i]);
1118 }
1119 else
1120 return ((char *)NULL); /* no valid `first' for word specifier */
1121
1122 if (spec[i] == '^' || spec[i] == '*')
1123 {
1124 last = (spec[i] == '^') ? 1 : '$'; /* x* abbreviates x-$ */
1125 i++;
1126 }
1127 else if (spec[i] != '-')
1128 last = first;
1129 else
1130 {
1131 i++;
1132
1133 if (_rl_digit_p (spec[i]))
1134 {
1135 for (last = 0; _rl_digit_p (spec[i]); i++)
1136 last = (last * 10) + _rl_digit_value (spec[i]);
1137 }
1138 else if (spec[i] == '$')
1139 {
1140 i++;
1141 last = '$';
1142 }
1143 else if (!spec[i] || spec[i] == ':') /* could be modifier separator */
1144 last = -1; /* x- abbreviates x-$ omitting word `$' */
1145 }
1146
1147 *caller_index = i;
1148
1149 if (last >= first || last == '$' || last < 0)
1150 result = history_arg_extract (first, last, from);
1151
1152 return (result ? result : (char *)&error_pointer);
1153}
1154
1155/* Extract the args specified, starting at FIRST, and ending at LAST.
1156 The args are taken from STRING. If either FIRST or LAST is < 0,
1157 then make that arg count from the right (subtract from the number of
1158 tokens, so that FIRST = -1 means the next to last token on the line).
1159 If LAST is `$' the last arg from STRING is used. */
1160char *
1161history_arg_extract (first, last, string)
1162 int first, last;
28ef6c31 1163 const char *string;
ccc6cda3
JA
1164{
1165 register int i, len;
1166 char *result;
1167 int size, offset;
1168 char **list;
1169
1170 /* XXX - think about making history_tokenize return a struct array,
1171 each struct in array being a string and a length to avoid the
1172 calls to strlen below. */
1173 if ((list = history_tokenize (string)) == NULL)
1174 return ((char *)NULL);
1175
1176 for (len = 0; list[len]; len++)
1177 ;
1178
1179 if (last < 0)
1180 last = len + last - 1;
1181
1182 if (first < 0)
1183 first = len + first - 1;
1184
1185 if (last == '$')
1186 last = len - 1;
1187
1188 if (first == '$')
1189 first = len - 1;
1190
1191 last++;
1192
1193 if (first >= len || last > len || first < 0 || last < 0 || first > last)
1194 result = ((char *)NULL);
1195 else
1196 {
1197 for (size = 0, i = first; i < last; i++)
1198 size += strlen (list[i]) + 1;
1199 result = xmalloc (size + 1);
1200 result[0] = '\0';
1201
1202 for (i = first, offset = 0; i < last; i++)
1203 {
1204 strcpy (result + offset, list[i]);
1205 offset += strlen (list[i]);
1206 if (i + 1 < last)
1207 {
1208 result[offset++] = ' ';
1209 result[offset] = 0;
1210 }
1211 }
1212 }
1213
1214 for (i = 0; i < len; i++)
1215 free (list[i]);
1216 free (list);
1217
1218 return (result);
1219}
1220
1221#define slashify_in_quotes "\\`\"$"
1222
1223/* Parse STRING into tokens and return an array of strings. If WIND is
1224 not -1 and INDP is not null, we also want the word surrounding index
1225 WIND. The position in the returned array of strings is returned in
1226 *INDP. */
1227static char **
1228history_tokenize_internal (string, wind, indp)
28ef6c31 1229 const char *string;
ccc6cda3
JA
1230 int wind, *indp;
1231{
1232 char **result;
1233 register int i, start, result_index, size;
1234 int len, delimiter;
1235
28ef6c31
JA
1236 /* If we're searching for a string that's not part of a word (e.g., " "),
1237 make sure we set *INDP to a reasonable value. */
1238 if (indp && wind != -1)
1239 *indp = -1;
1240
ccc6cda3
JA
1241 /* Get a token, and stuff it into RESULT. The tokens are split
1242 exactly where the shell would split them. */
1243 for (i = result_index = size = 0, result = (char **)NULL; string[i]; )
1244 {
1245 delimiter = 0;
1246
1247 /* Skip leading whitespace. */
1248 for (; string[i] && whitespace (string[i]); i++)
1249 ;
1250 if (string[i] == 0 || string[i] == history_comment_char)
1251 return (result);
1252
1253 start = i;
1254
1255 if (member (string[i], "()\n"))
1256 {
1257 i++;
1258 goto got_token;
1259 }
1260
1261 if (member (string[i], "<>;&|$"))
1262 {
1263 int peek = string[i + 1];
1264
1265 if (peek == string[i] && peek != '$')
1266 {
1267 if (peek == '<' && string[i + 2] == '-')
1268 i++;
1269 i += 2;
1270 goto got_token;
1271 }
1272 else
1273 {
1274 if ((peek == '&' && (string[i] == '>' || string[i] == '<')) ||
1275 ((peek == '>') && (string[i] == '&')) ||
1276 ((peek == '(') && (string[i] == '$')))
1277 {
1278 i += 2;
1279 goto got_token;
1280 }
1281 }
1282 if (string[i] != '$')
1283 {
1284 i++;
1285 goto got_token;
1286 }
1287 }
1288
1289 /* Get word from string + i; */
1290
cce855bc 1291 if (member (string[i], HISTORY_QUOTE_CHARACTERS))
ccc6cda3
JA
1292 delimiter = string[i++];
1293
1294 for (; string[i]; i++)
1295 {
1296 if (string[i] == '\\' && string[i + 1] == '\n')
1297 {
1298 i++;
1299 continue;
1300 }
1301
1302 if (string[i] == '\\' && delimiter != '\'' &&
1303 (delimiter != '"' || member (string[i], slashify_in_quotes)))
1304 {
1305 i++;
1306 continue;
1307 }
1308
1309 if (delimiter && string[i] == delimiter)
1310 {
1311 delimiter = 0;
1312 continue;
1313 }
1314
28ef6c31 1315 if (!delimiter && (member (string[i], history_word_delimiters)))
ccc6cda3
JA
1316 break;
1317
cce855bc 1318 if (!delimiter && member (string[i], HISTORY_QUOTE_CHARACTERS))
ccc6cda3
JA
1319 delimiter = string[i];
1320 }
1321
1322 got_token:
1323
1324 /* If we are looking for the word in which the character at a
1325 particular index falls, remember it. */
1326 if (indp && wind != -1 && wind >= start && wind < i)
1327 *indp = result_index;
1328
1329 len = i - start;
1330 if (result_index + 2 >= size)
1331 result = (char **)xrealloc (result, ((size += 10) * sizeof (char *)));
1332 result[result_index] = xmalloc (1 + len);
1333 strncpy (result[result_index], string + start, len);
1334 result[result_index][len] = '\0';
1335 result[++result_index] = (char *)NULL;
1336 }
1337
1338 return (result);
1339}
1340
1341/* Return an array of tokens, much as the shell might. The tokens are
1342 parsed out of STRING. */
1343char **
1344history_tokenize (string)
28ef6c31 1345 const char *string;
ccc6cda3
JA
1346{
1347 return (history_tokenize_internal (string, -1, (int *)NULL));
1348}
1349
1350/* Find and return the word which contains the character at index IND
1351 in the history line LINE. Used to save the word matched by the
1352 last history !?string? search. */
1353static char *
1354history_find_word (line, ind)
1355 char *line;
1356 int ind;
1357{
1358 char **words, *s;
1359 int i, wind;
1360
1361 words = history_tokenize_internal (line, ind, &wind);
28ef6c31 1362 if (wind == -1 || words == 0)
ccc6cda3
JA
1363 return ((char *)NULL);
1364 s = words[wind];
1365 for (i = 0; i < wind; i++)
1366 free (words[i]);
1367 for (i = wind + 1; words[i]; i++)
1368 free (words[i]);
1369 free (words);
1370 return s;
1371}