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