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