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