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