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