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