1 /* histexpand.c -- history expansion. */
2 
3 /* Copyright (C) 1989-2018 Free Software Foundation, Inc.
4 
5    This file contains the GNU History Library (History), a set of
6    routines for managing the text of previously typed lines.
7 
8    History 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 3 of the License, or
11    (at your option) any later version.
12 
13    History is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with History.  If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #define READLINE_LIBRARY
23 
24 #if defined (HAVE_CONFIG_H)
25 #  include <config.h>
26 #endif
27 
28 #include <stdio.h>
29 
30 #if defined (HAVE_STDLIB_H)
31 #  include <stdlib.h>
32 #else
33 #  include "ansi_stdlib.h"
34 #endif /* HAVE_STDLIB_H */
35 
36 #if defined (HAVE_UNISTD_H)
37 #  ifndef _MINIX
38 #    include <sys/types.h>
39 #  endif
40 #  include <unistd.h>
41 #endif
42 
43 #include "rlmbutil.h"
44 
45 #include "history.h"
46 #include "histlib.h"
47 #include "chardefs.h"
48 
49 #include "rlshell.h"
50 #include "xmalloc.h"
51 
52 #define HISTORY_WORD_DELIMITERS		" \t\n;&()|<>"
53 #define HISTORY_QUOTE_CHARACTERS	"\"'`"
54 #define HISTORY_EVENT_DELIMITERS	"^$*%-"
55 
56 #define slashify_in_quotes "\\`\"$"
57 
58 #define fielddelim(c)	(whitespace(c) || (c) == '\n')
59 
60 typedef int _hist_search_func_t PARAMS((const char *, int));
61 
62 static char error_pointer;
63 
64 static char *subst_lhs;
65 static char *subst_rhs;
66 static int subst_lhs_len;
67 static int subst_rhs_len;
68 
69 /* Characters that delimit history event specifications and separate event
70    specifications from word designators.  Static for now */
71 static char *history_event_delimiter_chars = HISTORY_EVENT_DELIMITERS;
72 
73 static char *get_history_word_specifier PARAMS((char *, char *, int *));
74 static int history_tokenize_word PARAMS((const char *, int));
75 static char **history_tokenize_internal PARAMS((const char *, int, int *));
76 static char *history_substring PARAMS((const char *, int, int));
77 static void freewords PARAMS((char **, int));
78 static char *history_find_word PARAMS((char *, int));
79 
80 static char *quote_breaks PARAMS((char *));
81 
82 /* Variables exported by this file. */
83 /* The character that represents the start of a history expansion
84    request.  This is usually `!'. */
85 char history_expansion_char = '!';
86 
87 /* The character that invokes word substitution if found at the start of
88    a line.  This is usually `^'. */
89 char history_subst_char = '^';
90 
91 /* During tokenization, if this character is seen as the first character
92    of a word, then it, and all subsequent characters upto a newline are
93    ignored.  For a Bourne shell, this should be '#'.  Bash special cases
94    the interactive comment character to not be a comment delimiter. */
95 char history_comment_char = '\0';
96 
97 /* The list of characters which inhibit the expansion of text if found
98    immediately following history_expansion_char. */
99 char *history_no_expand_chars = " \t\n\r=";
100 
101 /* If set to a non-zero value, single quotes inhibit history expansion.
102    The default is 0. */
103 int history_quotes_inhibit_expansion = 0;
104 
105 /* Used to split words by history_tokenize_internal. */
106 char *history_word_delimiters = HISTORY_WORD_DELIMITERS;
107 
108 /* If set, this points to a function that is called to verify that a
109    particular history expansion should be performed. */
110 rl_linebuf_func_t *history_inhibit_expansion_function;
111 
112 int history_quoting_state = 0;
113 
114 /* **************************************************************** */
115 /*								    */
116 /*			History Expansion			    */
117 /*								    */
118 /* **************************************************************** */
119 
120 /* Hairy history expansion on text, not tokens.  This is of general
121    use, and thus belongs in this library. */
122 
123 /* The last string searched for by a !?string? search. */
124 static char *search_string;
125 /* The last string matched by a !?string? search. */
126 static char *search_match;
127 
128 /* Return the event specified at TEXT + OFFSET modifying OFFSET to
129    point to after the event specifier.  Just a pointer to the history
130    line is returned; NULL is returned in the event of a bad specifier.
131    You pass STRING with *INDEX equal to the history_expansion_char that
132    begins this specification.
133    DELIMITING_QUOTE is a character that is allowed to end the string
134    specification for what to search for in addition to the normal
135    characters `:', ` ', `\t', `\n', and sometimes `?'.
136    So you might call this function like:
137    line = get_history_event ("!echo:p", &index, 0);  */
138 char *
get_history_event(const char * string,int * caller_index,int delimiting_quote)139 get_history_event (const char *string, int *caller_index, int delimiting_quote)
140 {
141   register int i;
142   register char c;
143   HIST_ENTRY *entry;
144   int which, sign, local_index, substring_okay;
145   _hist_search_func_t *search_func;
146   char *temp;
147 
148   /* The event can be specified in a number of ways.
149 
150      !!   the previous command
151      !n   command line N
152      !-n  current command-line minus N
153      !str the most recent command starting with STR
154      !?str[?]
155 	  the most recent command containing STR
156 
157      All values N are determined via HISTORY_BASE. */
158 
159   i = *caller_index;
160 
161   if (string[i] != history_expansion_char)
162     return ((char *)NULL);
163 
164   /* Move on to the specification. */
165   i++;
166 
167   sign = 1;
168   substring_okay = 0;
169 
170 #define RETURN_ENTRY(e, w) \
171 	return ((e = history_get (w)) ? e->line : (char *)NULL)
172 
173   /* Handle !! case. */
174   if (string[i] == history_expansion_char)
175     {
176       i++;
177       which = history_base + (history_length - 1);
178       *caller_index = i;
179       RETURN_ENTRY (entry, which);
180     }
181 
182   /* Hack case of numeric line specification. */
183   if (string[i] == '-')
184     {
185       sign = -1;
186       i++;
187     }
188 
189   if (_rl_digit_p (string[i]))
190     {
191       /* Get the extent of the digits and compute the value. */
192       for (which = 0; _rl_digit_p (string[i]); i++)
193 	which = (which * 10) + _rl_digit_value (string[i]);
194 
195       *caller_index = i;
196 
197       if (sign < 0)
198 	which = (history_length + history_base) - which;
199 
200       RETURN_ENTRY (entry, which);
201     }
202 
203   /* This must be something to search for.  If the spec begins with
204      a '?', then the string may be anywhere on the line.  Otherwise,
205      the string must be found at the start of a line. */
206   if (string[i] == '?')
207     {
208       substring_okay++;
209       i++;
210     }
211 
212   /* Only a closing `?' or a newline delimit a substring search string. */
213   for (local_index = i; c = string[i]; i++)
214     {
215 #if defined (HANDLE_MULTIBYTE)
216       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
217 	{
218 	  int v;
219 	  mbstate_t ps;
220 
221 	  memset (&ps, 0, sizeof (mbstate_t));
222 	  /* These produce warnings because we're passing a const string to a
223 	     function that takes a non-const string. */
224 	  _rl_adjust_point ((char *)string, i, &ps);
225 	  if ((v = _rl_get_char_len ((char *)string + i, &ps)) > 1)
226 	    {
227 	      i += v - 1;
228 	      continue;
229 	    }
230         }
231 
232 #endif /* HANDLE_MULTIBYTE */
233       if ((!substring_okay && (whitespace (c) || c == ':' ||
234           (history_event_delimiter_chars && member (c, history_event_delimiter_chars)) ||
235 	  (history_search_delimiter_chars && member (c, history_search_delimiter_chars)) ||
236 	  string[i] == delimiting_quote)) ||
237 	  string[i] == '\n' ||
238 	  (substring_okay && string[i] == '?'))
239 	break;
240     }
241 
242   which = i - local_index;
243   temp = (char *)xmalloc (1 + which);
244   if (which)
245     strncpy (temp, string + local_index, which);
246   temp[which] = '\0';
247 
248   if (substring_okay && string[i] == '?')
249     i++;
250 
251   *caller_index = i;
252 
253 #define FAIL_SEARCH() \
254   do { \
255     history_offset = history_length; xfree (temp) ; return (char *)NULL; \
256   } while (0)
257 
258   /* If there is no search string, try to use the previous search string,
259      if one exists.  If not, fail immediately. */
260   if (*temp == '\0' && substring_okay)
261     {
262       if (search_string)
263         {
264           xfree (temp);
265           temp = savestring (search_string);
266         }
267       else
268         FAIL_SEARCH ();
269     }
270 
271   search_func = substring_okay ? history_search : history_search_prefix;
272   while (1)
273     {
274       local_index = (*search_func) (temp, -1);
275 
276       if (local_index < 0)
277 	FAIL_SEARCH ();
278 
279       if (local_index == 0 || substring_okay)
280 	{
281 	  entry = current_history ();
282 	  if (entry == 0)
283 	    FAIL_SEARCH ();
284 	  history_offset = history_length;
285 
286 	  /* If this was a substring search, then remember the
287 	     string that we matched for word substitution. */
288 	  if (substring_okay)
289 	    {
290 	      FREE (search_string);
291 	      search_string = temp;
292 
293 	      FREE (search_match);
294 	      search_match = history_find_word (entry->line, local_index);
295 	    }
296 	  else
297 	    xfree (temp);
298 
299 	  return (entry->line);
300 	}
301 
302       if (history_offset)
303 	history_offset--;
304       else
305 	FAIL_SEARCH ();
306     }
307 #undef FAIL_SEARCH
308 #undef RETURN_ENTRY
309 }
310 
311 /* Function for extracting single-quoted strings.  Used for inhibiting
312    history expansion within single quotes. */
313 
314 /* Extract the contents of STRING as if it is enclosed in single quotes.
315    SINDEX, when passed in, is the offset of the character immediately
316    following the opening single quote; on exit, SINDEX is left pointing
317    to the closing single quote.  FLAGS currently used to allow backslash
318    to escape a single quote (e.g., for bash $'...'). */
319 static void
hist_string_extract_single_quoted(char * string,int * sindex,int flags)320 hist_string_extract_single_quoted (char *string, int *sindex, int flags)
321 {
322   register int i;
323 
324   for (i = *sindex; string[i] && string[i] != '\''; i++)
325     {
326       if ((flags & 1) && string[i] == '\\' && string[i+1])
327         i++;
328     }
329 
330   *sindex = i;
331 }
332 
333 static char *
quote_breaks(char * s)334 quote_breaks (char *s)
335 {
336   register char *p, *r;
337   char *ret;
338   int len = 3;
339 
340   for (p = s; p && *p; p++, len++)
341     {
342       if (*p == '\'')
343 	len += 3;
344       else if (whitespace (*p) || *p == '\n')
345 	len += 2;
346     }
347 
348   r = ret = (char *)xmalloc (len);
349   *r++ = '\'';
350   for (p = s; p && *p; )
351     {
352       if (*p == '\'')
353 	{
354 	  *r++ = '\'';
355 	  *r++ = '\\';
356 	  *r++ = '\'';
357 	  *r++ = '\'';
358 	  p++;
359 	}
360       else if (whitespace (*p) || *p == '\n')
361 	{
362 	  *r++ = '\'';
363 	  *r++ = *p++;
364 	  *r++ = '\'';
365 	}
366       else
367 	*r++ = *p++;
368     }
369   *r++ = '\'';
370   *r = '\0';
371   return ret;
372 }
373 
374 static char *
hist_error(char * s,int start,int current,int errtype)375 hist_error(char *s, int start, int current, int errtype)
376 {
377   char *temp;
378   const char *emsg;
379   int ll, elen;
380 
381   ll = current - start;
382 
383   switch (errtype)
384     {
385     case EVENT_NOT_FOUND:
386       emsg = "event not found";
387       elen = 15;
388       break;
389     case BAD_WORD_SPEC:
390       emsg = "bad word specifier";
391       elen = 18;
392       break;
393     case SUBST_FAILED:
394       emsg = "substitution failed";
395       elen = 19;
396       break;
397     case BAD_MODIFIER:
398       emsg = "unrecognized history modifier";
399       elen = 29;
400       break;
401     case NO_PREV_SUBST:
402       emsg = "no previous substitution";
403       elen = 24;
404       break;
405     default:
406       emsg = "unknown expansion error";
407       elen = 23;
408       break;
409     }
410 
411   temp = (char *)xmalloc (ll + elen + 3);
412   strncpy (temp, s + start, ll);
413   temp[ll] = ':';
414   temp[ll + 1] = ' ';
415   strcpy (temp + ll + 2, emsg);
416   return (temp);
417 }
418 
419 /* Get a history substitution string from STR starting at *IPTR
420    and return it.  The length is returned in LENPTR.
421 
422    A backslash can quote the delimiter.  If the string is the
423    empty string, the previous pattern is used.  If there is
424    no previous pattern for the lhs, the last history search
425    string is used.
426 
427    If IS_RHS is 1, we ignore empty strings and set the pattern
428    to "" anyway.  subst_lhs is not changed if the lhs is empty;
429    subst_rhs is allowed to be set to the empty string. */
430 
431 static char *
get_subst_pattern(char * str,int * iptr,int delimiter,int is_rhs,int * lenptr)432 get_subst_pattern (char *str, int *iptr, int delimiter, int is_rhs, int *lenptr)
433 {
434   register int si, i, j, k;
435   char *s;
436 #if defined (HANDLE_MULTIBYTE)
437   mbstate_t ps;
438 #endif
439 
440   s = (char *)NULL;
441   i = *iptr;
442 
443 #if defined (HANDLE_MULTIBYTE)
444   memset (&ps, 0, sizeof (mbstate_t));
445   _rl_adjust_point (str, i, &ps);
446 #endif
447 
448   for (si = i; str[si] && str[si] != delimiter; si++)
449 #if defined (HANDLE_MULTIBYTE)
450     if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
451       {
452 	int v;
453 	if ((v = _rl_get_char_len (str + si, &ps)) > 1)
454 	  si += v - 1;
455 	else if (str[si] == '\\' && str[si + 1] == delimiter)
456 	  si++;
457       }
458     else
459 #endif /* HANDLE_MULTIBYTE */
460       if (str[si] == '\\' && str[si + 1] == delimiter)
461 	si++;
462 
463   if (si > i || is_rhs)
464     {
465       s = (char *)xmalloc (si - i + 1);
466       for (j = 0, k = i; k < si; j++, k++)
467 	{
468 	  /* Remove a backslash quoting the search string delimiter. */
469 	  if (str[k] == '\\' && str[k + 1] == delimiter)
470 	    k++;
471 	  s[j] = str[k];
472 	}
473       s[j] = '\0';
474       if (lenptr)
475 	*lenptr = j;
476     }
477 
478   i = si;
479   if (str[i])
480     i++;
481   *iptr = i;
482 
483   return s;
484 }
485 
486 static void
postproc_subst_rhs(void)487 postproc_subst_rhs (void)
488 {
489   char *new;
490   int i, j, new_size;
491 
492   new = (char *)xmalloc (new_size = subst_rhs_len + subst_lhs_len);
493   for (i = j = 0; i < subst_rhs_len; i++)
494     {
495       if (subst_rhs[i] == '&')
496 	{
497 	  if (j + subst_lhs_len >= new_size)
498 	    new = (char *)xrealloc (new, (new_size = new_size * 2 + subst_lhs_len));
499 	  strcpy (new + j, subst_lhs);
500 	  j += subst_lhs_len;
501 	}
502       else
503 	{
504 	  /* a single backslash protects the `&' from lhs interpolation */
505 	  if (subst_rhs[i] == '\\' && subst_rhs[i + 1] == '&')
506 	    i++;
507 	  if (j >= new_size)
508 	    new = (char *)xrealloc (new, new_size *= 2);
509 	  new[j++] = subst_rhs[i];
510 	}
511     }
512   new[j] = '\0';
513   xfree (subst_rhs);
514   subst_rhs = new;
515   subst_rhs_len = j;
516 }
517 
518 /* Expand the bulk of a history specifier starting at STRING[START].
519    Returns 0 if everything is OK, -1 if an error occurred, and 1
520    if the `p' modifier was supplied and the caller should just print
521    the returned string.  Returns the new index into string in
522    *END_INDEX_PTR, and the expanded specifier in *RET_STRING. */
523 /* need current line for !# */
524 static int
history_expand_internal(char * string,int start,int qc,int * end_index_ptr,char ** ret_string,char * current_line)525 history_expand_internal (char *string, int start, int qc, int *end_index_ptr, char **ret_string, char *current_line)
526 {
527   int i, n, starting_index;
528   int substitute_globally, subst_bywords, want_quotes, print_only;
529   char *event, *temp, *result, *tstr, *t, c, *word_spec;
530   int result_len;
531 #if defined (HANDLE_MULTIBYTE)
532   mbstate_t ps;
533 
534   memset (&ps, 0, sizeof (mbstate_t));
535 #endif
536 
537   result = (char *)xmalloc (result_len = 128);
538 
539   i = start;
540 
541   /* If it is followed by something that starts a word specifier,
542      then !! is implied as the event specifier. */
543 
544   if (member (string[i + 1], ":$*%^"))
545     {
546       char fake_s[3];
547       int fake_i = 0;
548       i++;
549       fake_s[0] = fake_s[1] = history_expansion_char;
550       fake_s[2] = '\0';
551       event = get_history_event (fake_s, &fake_i, 0);
552     }
553   else if (string[i + 1] == '#')
554     {
555       i += 2;
556       event = current_line;
557     }
558   else
559     event = get_history_event (string, &i, qc);
560 
561   if (event == 0)
562     {
563       *ret_string = hist_error (string, start, i, EVENT_NOT_FOUND);
564       xfree (result);
565       return (-1);
566     }
567 
568   /* If a word specifier is found, then do what that requires. */
569   starting_index = i;
570   word_spec = get_history_word_specifier (string, event, &i);
571 
572   /* There is no such thing as a `malformed word specifier'.  However,
573      it is possible for a specifier that has no match.  In that case,
574      we complain. */
575   if (word_spec == (char *)&error_pointer)
576     {
577       *ret_string = hist_error (string, starting_index, i, BAD_WORD_SPEC);
578       xfree (result);
579       return (-1);
580     }
581 
582   /* If no word specifier, than the thing of interest was the event. */
583   temp = word_spec ? savestring (word_spec) : savestring (event);
584   FREE (word_spec);
585 
586   /* Perhaps there are other modifiers involved.  Do what they say. */
587   want_quotes = substitute_globally = subst_bywords = print_only = 0;
588   starting_index = i;
589 
590   while (string[i] == ':')
591     {
592       c = string[i + 1];
593 
594       if (c == 'g' || c == 'a')
595 	{
596 	  substitute_globally = 1;
597 	  i++;
598 	  c = string[i + 1];
599 	}
600       else if (c == 'G')
601 	{
602 	  subst_bywords = 1;
603 	  i++;
604 	  c = string[i + 1];
605 	}
606 
607       switch (c)
608 	{
609 	default:
610 	  *ret_string = hist_error (string, i+1, i+2, BAD_MODIFIER);
611 	  xfree (result);
612 	  xfree (temp);
613 	  return -1;
614 
615 	case 'q':
616 	  want_quotes = 'q';
617 	  break;
618 
619 	case 'x':
620 	  want_quotes = 'x';
621 	  break;
622 
623 	  /* :p means make this the last executed line.  So we
624 	     return an error state after adding this line to the
625 	     history. */
626 	case 'p':
627 	  print_only++;
628 	  break;
629 
630 	  /* :t discards all but the last part of the pathname. */
631 	case 't':
632 	  tstr = strrchr (temp, '/');
633 	  if (tstr)
634 	    {
635 	      tstr++;
636 	      t = savestring (tstr);
637 	      xfree (temp);
638 	      temp = t;
639 	    }
640 	  break;
641 
642 	  /* :h discards the last part of a pathname. */
643 	case 'h':
644 	  tstr = strrchr (temp, '/');
645 	  if (tstr)
646 	    *tstr = '\0';
647 	  break;
648 
649 	  /* :r discards the suffix. */
650 	case 'r':
651 	  tstr = strrchr (temp, '.');
652 	  if (tstr)
653 	    *tstr = '\0';
654 	  break;
655 
656 	  /* :e discards everything but the suffix. */
657 	case 'e':
658 	  tstr = strrchr (temp, '.');
659 	  if (tstr)
660 	    {
661 	      t = savestring (tstr);
662 	      xfree (temp);
663 	      temp = t;
664 	    }
665 	  break;
666 
667 	/* :s/this/that substitutes `that' for the first
668 	   occurrence of `this'.  :gs/this/that substitutes `that'
669 	   for each occurrence of `this'.  :& repeats the last
670 	   substitution.  :g& repeats the last substitution
671 	   globally. */
672 
673 	case '&':
674 	case 's':
675 	  {
676 	    char *new_event;
677 	    int delimiter, failed, si, l_temp, ws, we;
678 
679 	    if (c == 's')
680 	      {
681 		if (i + 2 < (int)strlen (string))
682 		  {
683 #if defined (HANDLE_MULTIBYTE)
684 		    if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
685 		      {
686 			_rl_adjust_point (string, i + 2, &ps);
687 			if (_rl_get_char_len (string + i + 2, &ps) > 1)
688 			  delimiter = 0;
689 			else
690 			  delimiter = string[i + 2];
691 		      }
692 		    else
693 #endif /* HANDLE_MULTIBYTE */
694 		      delimiter = string[i + 2];
695 		  }
696 		else
697 		  break;	/* no search delimiter */
698 
699 		i += 3;
700 
701 		t = get_subst_pattern (string, &i, delimiter, 0, &subst_lhs_len);
702 		/* An empty substitution lhs with no previous substitution
703 		   uses the last search string as the lhs. */
704 		if (t)
705 		  {
706 		    FREE (subst_lhs);
707 		    subst_lhs = t;
708 		  }
709 		else if (!subst_lhs)
710 		  {
711 		    if (search_string && *search_string)
712 		      {
713 			subst_lhs = savestring (search_string);
714 			subst_lhs_len = strlen (subst_lhs);
715 		      }
716 		    else
717 		      {
718 			subst_lhs = (char *) NULL;
719 			subst_lhs_len = 0;
720 		      }
721 		  }
722 
723 		FREE (subst_rhs);
724 		subst_rhs = get_subst_pattern (string, &i, delimiter, 1, &subst_rhs_len);
725 
726 		/* If `&' appears in the rhs, it's supposed to be replaced
727 		   with the lhs. */
728 		if (member ('&', subst_rhs))
729 		  postproc_subst_rhs ();
730 	      }
731 	    else
732 	      i += 2;
733 
734 	    /* If there is no lhs, the substitution can't succeed. */
735 	    if (subst_lhs_len == 0)
736 	      {
737 		*ret_string = hist_error (string, starting_index, i, NO_PREV_SUBST);
738 		xfree (result);
739 		xfree (temp);
740 		return -1;
741 	      }
742 
743 	    l_temp = strlen (temp);
744 	    /* Ignore impossible cases. */
745 	    if (subst_lhs_len > l_temp)
746 	      {
747 		*ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
748 		xfree (result);
749 		xfree (temp);
750 		return (-1);
751 	      }
752 
753 	    /* Find the first occurrence of THIS in TEMP. */
754 	    /* Substitute SUBST_RHS for SUBST_LHS in TEMP.  There are three
755 	       cases to consider:
756 
757 		 1.  substitute_globally == subst_bywords == 0
758 		 2.  substitute_globally == 1 && subst_bywords == 0
759 		 3.  substitute_globally == 0 && subst_bywords == 1
760 
761 	       In the first case, we substitute for the first occurrence only.
762 	       In the second case, we substitute for every occurrence.
763 	       In the third case, we tokenize into words and substitute the
764 	       first occurrence of each word. */
765 
766 	    si = we = 0;
767 	    for (failed = 1; (si + subst_lhs_len) <= l_temp; si++)
768 	      {
769 		/* First skip whitespace and find word boundaries if
770 		   we're past the end of the word boundary we found
771 		   the last time. */
772 		if (subst_bywords && si > we)
773 		  {
774 		    for (; temp[si] && fielddelim (temp[si]); si++)
775 		      ;
776 		    ws = si;
777 		    we = history_tokenize_word (temp, si);
778 		  }
779 
780 		if (STREQN (temp+si, subst_lhs, subst_lhs_len))
781 		  {
782 		    int len = subst_rhs_len - subst_lhs_len + l_temp;
783 		    new_event = (char *)xmalloc (1 + len);
784 		    strncpy (new_event, temp, si);
785 		    strncpy (new_event + si, subst_rhs, subst_rhs_len);
786 		    strncpy (new_event + si + subst_rhs_len,
787 			     temp + si + subst_lhs_len,
788 			     l_temp - (si + subst_lhs_len));
789 		    new_event[len] = '\0';
790 		    xfree (temp);
791 		    temp = new_event;
792 
793 		    failed = 0;
794 
795 		    if (substitute_globally)
796 		      {
797 			/* Reported to fix a bug that causes it to skip every
798 			   other match when matching a single character.  Was
799 			   si += subst_rhs_len previously. */
800 			si += subst_rhs_len - 1;
801 			l_temp = strlen (temp);
802 			substitute_globally++;
803 			continue;
804 		      }
805 		    else if (subst_bywords)
806 		      {
807 			si = we;
808 			l_temp = strlen (temp);
809 			continue;
810 		      }
811 		    else
812 		      break;
813 		  }
814 	      }
815 
816 	    if (substitute_globally > 1)
817 	      {
818 		substitute_globally = 0;
819 		continue;	/* don't want to increment i */
820 	      }
821 
822 	    if (failed == 0)
823 	      continue;		/* don't want to increment i */
824 
825 	    *ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
826 	    xfree (result);
827 	    xfree (temp);
828 	    return (-1);
829 	  }
830 	}
831       i += 2;
832     }
833   /* Done with modifiers. */
834   /* Believe it or not, we have to back the pointer up by one. */
835   --i;
836 
837   if (want_quotes)
838     {
839       char *x;
840 
841       if (want_quotes == 'q')
842 	x = sh_single_quote (temp);
843       else if (want_quotes == 'x')
844 	x = quote_breaks (temp);
845       else
846 	x = savestring (temp);
847 
848       xfree (temp);
849       temp = x;
850     }
851 
852   n = strlen (temp);
853   if (n >= result_len)
854     result = (char *)xrealloc (result, n + 2);
855   strcpy (result, temp);
856   xfree (temp);
857 
858   *end_index_ptr = i;
859   *ret_string = result;
860   return (print_only);
861 }
862 
863 /* Expand the string STRING, placing the result into OUTPUT, a pointer
864    to a string.  Returns:
865 
866   -1) If there was an error in expansion.
867    0) If no expansions took place (or, if the only change in
868       the text was the de-slashifying of the history expansion
869       character)
870    1) If expansions did take place
871    2) If the `p' modifier was given and the caller should print the result
872 
873   If an error occurred in expansion, then OUTPUT contains a descriptive
874   error message. */
875 
876 #define ADD_STRING(s) \
877 	do \
878 	  { \
879 	    int sl = strlen (s); \
880 	    j += sl; \
881 	    if (j >= result_len) \
882 	      { \
883 		while (j >= result_len) \
884 		  result_len += 128; \
885 		result = (char *)xrealloc (result, result_len); \
886 	      } \
887 	    strcpy (result + j - sl, s); \
888 	  } \
889 	while (0)
890 
891 #define ADD_CHAR(c) \
892 	do \
893 	  { \
894 	    if (j >= result_len - 1) \
895 	      result = (char *)xrealloc (result, result_len += 64); \
896 	    result[j++] = c; \
897 	    result[j] = '\0'; \
898 	  } \
899 	while (0)
900 
901 int
history_expand(char * hstring,char ** output)902 history_expand (char *hstring, char **output)
903 {
904   register int j;
905   int i, r, l, passc, cc, modified, eindex, only_printing, dquote, squote, flag;
906   char *string;
907 
908   /* The output string, and its length. */
909   int result_len;
910   char *result;
911 
912 #if defined (HANDLE_MULTIBYTE)
913   char mb[MB_LEN_MAX];
914   mbstate_t ps;
915 #endif
916 
917   /* Used when adding the string. */
918   char *temp;
919 
920   if (output == 0)
921     return 0;
922 
923   /* Setting the history expansion character to 0 inhibits all
924      history expansion. */
925   if (history_expansion_char == 0)
926     {
927       *output = savestring (hstring);
928       return (0);
929     }
930 
931   /* Prepare the buffer for printing error messages. */
932   result = (char *)xmalloc (result_len = 256);
933   result[0] = '\0';
934 
935   only_printing = modified = 0;
936   l = strlen (hstring);
937 
938   /* Grovel the string.  Only backslash and single quotes can quote the
939      history escape character.  We also handle arg specifiers. */
940 
941   /* Before we grovel forever, see if the history_expansion_char appears
942      anywhere within the text. */
943 
944   /* The quick substitution character is a history expansion all right.  That
945      is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact,
946      that is the substitution that we do. */
947   if (hstring[0] == history_subst_char)
948     {
949       string = (char *)xmalloc (l + 5);
950 
951       string[0] = string[1] = history_expansion_char;
952       string[2] = ':';
953       string[3] = 's';
954       strcpy (string + 4, hstring);
955       l += 4;
956     }
957   else
958     {
959 #if defined (HANDLE_MULTIBYTE)
960       memset (&ps, 0, sizeof (mbstate_t));
961 #endif
962 
963       string = hstring;
964       /* If not quick substitution, still maybe have to do expansion. */
965 
966       /* `!' followed by one of the characters in history_no_expand_chars
967 	 is NOT an expansion. */
968       dquote = history_quoting_state == '"';
969       squote = history_quoting_state == '\'';
970 
971       /* If the calling application tells us we are already reading a
972 	 single-quoted string, consume the rest of the string right now
973 	 and then go on. */
974       i = 0;
975       if (squote && history_quotes_inhibit_expansion)
976 	{
977 	  hist_string_extract_single_quoted (string, &i, 0);
978 	  squote = 0;
979 	  if (string[i])
980 	    i++;
981 	}
982 
983       for ( ; string[i]; i++)
984 	{
985 #if defined (HANDLE_MULTIBYTE)
986 	  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
987 	    {
988 	      int v;
989 	      v = _rl_get_char_len (string + i, &ps);
990 	      if (v > 1)
991 		{
992 		  i += v - 1;
993 		  continue;
994 		}
995 	    }
996 #endif /* HANDLE_MULTIBYTE */
997 
998 	  cc = string[i + 1];
999 	  /* The history_comment_char, if set, appearing at the beginning
1000 	     of a word signifies that the rest of the line should not have
1001 	     history expansion performed on it.
1002 	     Skip the rest of the line and break out of the loop. */
1003 	  if (history_comment_char && string[i] == history_comment_char &&
1004 	      dquote == 0 &&
1005 	      (i == 0 || member (string[i - 1], history_word_delimiters)))
1006 	    {
1007 	      while (string[i])
1008 		i++;
1009 	      break;
1010 	    }
1011 	  else if (string[i] == history_expansion_char)
1012 	    {
1013 	      if (cc == 0 || member (cc, history_no_expand_chars))
1014 		continue;
1015 	      /* DQUOTE won't be set unless history_quotes_inhibit_expansion
1016 		 is set.  The idea here is to treat double-quoted strings the
1017 		 same as the word outside double quotes; in effect making the
1018 		 double quote part of history_no_expand_chars when DQUOTE is
1019 		 set. */
1020 	      else if (dquote && cc == '"')
1021 		continue;
1022 	      /* If the calling application has set
1023 		 history_inhibit_expansion_function to a function that checks
1024 		 for special cases that should not be history expanded,
1025 		 call the function and skip the expansion if it returns a
1026 		 non-zero value. */
1027 	      else if (history_inhibit_expansion_function &&
1028 			(*history_inhibit_expansion_function) (string, i))
1029 		continue;
1030 	      else
1031 		break;
1032 	    }
1033 	  /* Shell-like quoting: allow backslashes to quote double quotes
1034 	     inside a double-quoted string. */
1035 	  else if (dquote && string[i] == '\\' && cc == '"')
1036 	    i++;
1037 	  /* More shell-like quoting:  if we're paying attention to single
1038 	     quotes and letting them quote the history expansion character,
1039 	     then we need to pay attention to double quotes, because single
1040 	     quotes are not special inside double-quoted strings. */
1041 	  else if (history_quotes_inhibit_expansion && string[i] == '"')
1042 	    {
1043 	      dquote = 1 - dquote;
1044 	    }
1045 	  else if (dquote == 0 && history_quotes_inhibit_expansion && string[i] == '\'')
1046 	    {
1047 	      /* If this is bash, single quotes inhibit history expansion. */
1048 	      flag = (i > 0 && string[i - 1] == '$');
1049 	      i++;
1050 	      hist_string_extract_single_quoted (string, &i, flag);
1051 	    }
1052 	  else if (history_quotes_inhibit_expansion && string[i] == '\\')
1053 	    {
1054 	      /* If this is bash, allow backslashes to quote single
1055 		 quotes and the history expansion character. */
1056 	      if (cc == '\'' || cc == history_expansion_char)
1057 		i++;
1058 	    }
1059 
1060 	}
1061 
1062       if (string[i] != history_expansion_char)
1063 	{
1064 	  xfree (result);
1065 	  *output = savestring (string);
1066 	  return (0);
1067 	}
1068     }
1069 
1070   /* Extract and perform the substitution. */
1071   dquote = history_quoting_state == '"';
1072   squote = history_quoting_state == '\'';
1073 
1074   /* If the calling application tells us we are already reading a
1075      single-quoted string, consume the rest of the string right now
1076      and then go on. */
1077   i = j = 0;
1078   if (squote && history_quotes_inhibit_expansion)
1079     {
1080       int c;
1081 
1082       hist_string_extract_single_quoted (string, &i, 0);
1083       squote = 0;
1084       for (c = 0; c < i; c++)
1085 	ADD_CHAR (string[c]);
1086       if (string[i])
1087 	{
1088 	  ADD_CHAR (string[i]);
1089 	  i++;
1090 	}
1091     }
1092 
1093   for (passc = 0; i < l; i++)
1094     {
1095       int qc, tchar = string[i];
1096 
1097       if (passc)
1098 	{
1099 	  passc = 0;
1100 	  ADD_CHAR (tchar);
1101 	  continue;
1102 	}
1103 
1104 #if defined (HANDLE_MULTIBYTE)
1105       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1106 	{
1107 	  int k, c;
1108 
1109 	  c = tchar;
1110 	  memset (mb, 0, sizeof (mb));
1111 	  for (k = 0; k < MB_LEN_MAX; k++)
1112 	    {
1113 	      mb[k] = (char)c;
1114 	      memset (&ps, 0, sizeof (mbstate_t));
1115 	      if (_rl_get_char_len (mb, &ps) == -2)
1116 		c = string[++i];
1117 	      else
1118 		break;
1119 	    }
1120 	  if (strlen (mb) > 1)
1121 	    {
1122 	      ADD_STRING (mb);
1123 	      continue;
1124 	    }
1125 	}
1126 #endif /* HANDLE_MULTIBYTE */
1127 
1128       if (tchar == history_expansion_char)
1129 	tchar = -3;
1130       else if (tchar == history_comment_char)
1131 	tchar = -2;
1132 
1133       switch (tchar)
1134 	{
1135 	default:
1136 	  ADD_CHAR (string[i]);
1137 	  break;
1138 
1139 	case '\\':
1140 	  passc++;
1141 	  ADD_CHAR (tchar);
1142 	  break;
1143 
1144 	case '"':
1145 	  dquote = 1 - dquote;
1146 	  ADD_CHAR (tchar);
1147 	  break;
1148 
1149 	case '\'':
1150 	  {
1151 	    /* If history_quotes_inhibit_expansion is set, single quotes
1152 	       inhibit history expansion, otherwise they are treated like
1153 	       double quotes. */
1154 	    if (squote)
1155 	      {
1156 	        squote = 0;
1157 	        ADD_CHAR (tchar);
1158 	      }
1159 	    else if (dquote == 0 && history_quotes_inhibit_expansion)
1160 	      {
1161 		int quote, slen;
1162 
1163 		flag = (i > 0 && string[i - 1] == '$');
1164 		quote = i++;
1165 		hist_string_extract_single_quoted (string, &i, flag);
1166 
1167 		slen = i - quote + 2;
1168 		temp = (char *)xmalloc (slen);
1169 		strncpy (temp, string + quote, slen);
1170 		temp[slen - 1] = '\0';
1171 		ADD_STRING (temp);
1172 		xfree (temp);
1173 	      }
1174 	    else if (dquote == 0 && squote == 0 && history_quotes_inhibit_expansion == 0)
1175 	      {
1176 	        squote = 1;
1177 	        ADD_CHAR (string[i]);
1178 	      }
1179 	    else
1180 	      ADD_CHAR (string[i]);
1181 	    break;
1182 	  }
1183 
1184 	case -2:		/* history_comment_char */
1185 	  if ((dquote == 0 || history_quotes_inhibit_expansion == 0) &&
1186 	      (i == 0 || member (string[i - 1], history_word_delimiters)))
1187 	    {
1188 	      temp = (char *)xmalloc (l - i + 1);
1189 	      strcpy (temp, string + i);
1190 	      ADD_STRING (temp);
1191 	      xfree (temp);
1192 	      i = l;
1193 	    }
1194 	  else
1195 	    ADD_CHAR (string[i]);
1196 	  break;
1197 
1198 	case -3:		/* history_expansion_char */
1199 	  cc = string[i + 1];
1200 
1201 	  /* If the history_expansion_char is followed by one of the
1202 	     characters in history_no_expand_chars, then it is not a
1203 	     candidate for expansion of any kind. */
1204 	  if (cc == 0 || member (cc, history_no_expand_chars) ||
1205 			 (dquote && cc == '"') ||
1206 	  		 (history_inhibit_expansion_function && (*history_inhibit_expansion_function) (string, i)))
1207 	    {
1208 	      ADD_CHAR (string[i]);
1209 	      break;
1210 	    }
1211 
1212 #if defined (NO_BANG_HASH_MODIFIERS)
1213 	  /* There is something that is listed as a `word specifier' in csh
1214 	     documentation which means `the expanded text to this point'.
1215 	     That is not a word specifier, it is an event specifier.  If we
1216 	     don't want to allow modifiers with `!#', just stick the current
1217 	     output line in again. */
1218 	  if (cc == '#')
1219 	    {
1220 	      if (result)
1221 		{
1222 		  temp = (char *)xmalloc (1 + strlen (result));
1223 		  strcpy (temp, result);
1224 		  ADD_STRING (temp);
1225 		  xfree (temp);
1226 		}
1227 	      i++;
1228 	      break;
1229 	    }
1230 #endif
1231 	  qc = squote ? '\'' : (dquote ? '"' : 0);
1232 	  r = history_expand_internal (string, i, qc, &eindex, &temp, result);
1233 	  if (r < 0)
1234 	    {
1235 	      *output = temp;
1236 	      xfree (result);
1237 	      if (string != hstring)
1238 		xfree (string);
1239 	      return -1;
1240 	    }
1241 	  else
1242 	    {
1243 	      if (temp)
1244 		{
1245 		  modified++;
1246 		  if (*temp)
1247 		    ADD_STRING (temp);
1248 		  xfree (temp);
1249 		}
1250 	      only_printing += r == 1;
1251 	      i = eindex;
1252 	    }
1253 	  break;
1254 	}
1255     }
1256 
1257   *output = result;
1258   if (string != hstring)
1259     xfree (string);
1260 
1261   if (only_printing)
1262     {
1263 #if 0
1264       add_history (result);
1265 #endif
1266       return (2);
1267     }
1268 
1269   return (modified != 0);
1270 }
1271 
1272 /* Return a consed string which is the word specified in SPEC, and found
1273    in FROM.  NULL is returned if there is no spec.  The address of
1274    ERROR_POINTER is returned if the word specified cannot be found.
1275    CALLER_INDEX is the offset in SPEC to start looking; it is updated
1276    to point to just after the last character parsed. */
1277 static char *
get_history_word_specifier(char * spec,char * from,int * caller_index)1278 get_history_word_specifier (char *spec, char *from, int *caller_index)
1279 {
1280   register int i = *caller_index;
1281   int first, last;
1282   int expecting_word_spec = 0;
1283   char *result;
1284 
1285   /* The range of words to return doesn't exist yet. */
1286   first = last = 0;
1287   result = (char *)NULL;
1288 
1289   /* If we found a colon, then this *must* be a word specification.  If
1290      it isn't, then it is an error. */
1291   if (spec[i] == ':')
1292     {
1293       i++;
1294       expecting_word_spec++;
1295     }
1296 
1297   /* Handle special cases first. */
1298 
1299   /* `%' is the word last searched for. */
1300   if (spec[i] == '%')
1301     {
1302       *caller_index = i + 1;
1303       return (search_match ? savestring (search_match) : savestring (""));
1304     }
1305 
1306   /* `*' matches all of the arguments, but not the command. */
1307   if (spec[i] == '*')
1308     {
1309       *caller_index = i + 1;
1310       result = history_arg_extract (1, '$', from);
1311       return (result ? result : savestring (""));
1312     }
1313 
1314   /* `$' is last arg. */
1315   if (spec[i] == '$')
1316     {
1317       *caller_index = i + 1;
1318       return (history_arg_extract ('$', '$', from));
1319     }
1320 
1321   /* Try to get FIRST and LAST figured out. */
1322 
1323   if (spec[i] == '-')
1324     first = 0;
1325   else if (spec[i] == '^')
1326     {
1327       first = 1;
1328       i++;
1329     }
1330   else if (_rl_digit_p (spec[i]) && expecting_word_spec)
1331     {
1332       for (first = 0; _rl_digit_p (spec[i]); i++)
1333 	first = (first * 10) + _rl_digit_value (spec[i]);
1334     }
1335   else
1336     return ((char *)NULL);	/* no valid `first' for word specifier */
1337 
1338   if (spec[i] == '^' || spec[i] == '*')
1339     {
1340       last = (spec[i] == '^') ? 1 : '$';	/* x* abbreviates x-$ */
1341       i++;
1342     }
1343   else if (spec[i] != '-')
1344     last = first;
1345   else
1346     {
1347       i++;
1348 
1349       if (_rl_digit_p (spec[i]))
1350 	{
1351 	  for (last = 0; _rl_digit_p (spec[i]); i++)
1352 	    last = (last * 10) + _rl_digit_value (spec[i]);
1353 	}
1354       else if (spec[i] == '$')
1355 	{
1356 	  i++;
1357 	  last = '$';
1358 	}
1359 #if 0
1360       else if (!spec[i] || spec[i] == ':')
1361 	/* check against `:' because there could be a modifier separator */
1362 #else
1363       else
1364 	/* csh seems to allow anything to terminate the word spec here,
1365 	   leaving it as an abbreviation. */
1366 #endif
1367 	last = -1;		/* x- abbreviates x-$ omitting word `$' */
1368     }
1369 
1370   *caller_index = i;
1371 
1372   if (last >= first || last == '$' || last < 0)
1373     result = history_arg_extract (first, last, from);
1374 
1375   return (result ? result : (char *)&error_pointer);
1376 }
1377 
1378 /* Extract the args specified, starting at FIRST, and ending at LAST.
1379    The args are taken from STRING.  If either FIRST or LAST is < 0,
1380    then make that arg count from the right (subtract from the number of
1381    tokens, so that FIRST = -1 means the next to last token on the line).
1382    If LAST is `$' the last arg from STRING is used. */
1383 char *
history_arg_extract(int first,int last,const char * string)1384 history_arg_extract (int first, int last, const char *string)
1385 {
1386   register int i, len;
1387   char *result;
1388   int size, offset;
1389   char **list;
1390 
1391   /* XXX - think about making history_tokenize return a struct array,
1392      each struct in array being a string and a length to avoid the
1393      calls to strlen below. */
1394   if ((list = history_tokenize (string)) == NULL)
1395     return ((char *)NULL);
1396 
1397   for (len = 0; list[len]; len++)
1398     ;
1399 
1400   if (last < 0)
1401     last = len + last - 1;
1402 
1403   if (first < 0)
1404     first = len + first - 1;
1405 
1406   if (last == '$')
1407     last = len - 1;
1408 
1409   if (first == '$')
1410     first = len - 1;
1411 
1412   last++;
1413 
1414   if (first >= len || last > len || first < 0 || last < 0 || first > last)
1415     result = ((char *)NULL);
1416   else
1417     {
1418       for (size = 0, i = first; i < last; i++)
1419 	size += strlen (list[i]) + 1;
1420       result = (char *)xmalloc (size + 1);
1421       result[0] = '\0';
1422 
1423       for (i = first, offset = 0; i < last; i++)
1424 	{
1425 	  strcpy (result + offset, list[i]);
1426 	  offset += strlen (list[i]);
1427 	  if (i + 1 < last)
1428 	    {
1429       	      result[offset++] = ' ';
1430 	      result[offset] = 0;
1431 	    }
1432 	}
1433     }
1434 
1435   for (i = 0; i < len; i++)
1436     xfree (list[i]);
1437   xfree (list);
1438 
1439   return (result);
1440 }
1441 
1442 static int
history_tokenize_word(const char * string,int ind)1443 history_tokenize_word (const char *string, int ind)
1444 {
1445   register int i, j;
1446   int delimiter, nestdelim, delimopen;
1447 
1448   i = ind;
1449   delimiter = nestdelim = 0;
1450 
1451   if (member (string[i], "()\n"))	/* XXX - included \n, but why? been here forever */
1452     {
1453       i++;
1454       return i;
1455     }
1456 
1457   if (ISDIGIT (string[i]))
1458     {
1459       j = i;
1460       while (string[j] && ISDIGIT (string[j]))
1461 	j++;
1462       if (string[j] == 0)
1463 	return (j);
1464       if (string[j] == '<' || string[j] == '>')
1465 	i = j;			/* digit sequence is a file descriptor */
1466       else
1467 	{
1468 	  i = j;
1469 	  goto get_word;	/* digit sequence is part of a word */
1470 	}
1471     }
1472 
1473   if (member (string[i], "<>;&|"))
1474     {
1475       int peek = string[i + 1];
1476 
1477       if (peek == string[i])
1478 	{
1479 	  if (peek == '<' && string[i + 2] == '-')
1480 	    i++;
1481 	  else if (peek == '<' && string[i + 2] == '<')
1482 	    i++;
1483 	  i += 2;
1484 	  return i;
1485 	}
1486       else if (peek == '&' && (string[i] == '>' || string[i] == '<'))
1487 	{
1488 	  j = i + 2;
1489 	  while (string[j] && ISDIGIT (string[j]))	/* file descriptor */
1490 	    j++;
1491 	  if (string[j] =='-')		/* <&[digits]-, >&[digits]- */
1492 	    j++;
1493 	  return j;
1494 	}
1495       else if ((peek == '>' && string[i] == '&') || (peek == '|' && string[i] == '>'))
1496 	{
1497 	  i += 2;
1498 	  return i;
1499 	}
1500       /* XXX - process substitution -- separated out for later -- bash-4.2 */
1501       else if (peek == '(' && (string[i] == '>' || string[i] == '<')) /*)*/
1502 	{
1503 	  i += 2;
1504 	  delimopen = '(';
1505 	  delimiter = ')';
1506 	  nestdelim = 1;
1507 	  goto get_word;
1508 	}
1509 
1510       i++;
1511       return i;
1512     }
1513 
1514 get_word:
1515   /* Get word from string + i; */
1516 
1517   if (delimiter == 0 && member (string[i], HISTORY_QUOTE_CHARACTERS))
1518     delimiter = string[i++];
1519 
1520   for (; string[i]; i++)
1521     {
1522       if (string[i] == '\\' && string[i + 1] == '\n')
1523 	{
1524 	  i++;
1525 	  continue;
1526 	}
1527 
1528       if (string[i] == '\\' && delimiter != '\'' &&
1529 	  (delimiter != '"' || member (string[i], slashify_in_quotes)))
1530 	{
1531 	  i++;
1532 	  continue;
1533 	}
1534 
1535       /* delimiter must be set and set to something other than a quote if
1536 	 nestdelim is set, so these tests are safe. */
1537       if (nestdelim && string[i] == delimopen)
1538 	{
1539 	  nestdelim++;
1540 	  continue;
1541 	}
1542       if (nestdelim && string[i] == delimiter)
1543 	{
1544 	  nestdelim--;
1545 	  if (nestdelim == 0)
1546 	    delimiter = 0;
1547 	  continue;
1548 	}
1549 
1550       if (delimiter && string[i] == delimiter)
1551 	{
1552 	  delimiter = 0;
1553 	  continue;
1554 	}
1555 
1556       /* Command and process substitution; shell extended globbing patterns */
1557       if (nestdelim == 0 && delimiter == 0 && member (string[i], "<>$!@?+*") && string[i+1] == '(') /*)*/
1558 	{
1559 	  i += 2;
1560 	  delimopen = '(';
1561 	  delimiter = ')';
1562 	  nestdelim = 1;
1563 	  continue;
1564 	}
1565 
1566       if (delimiter == 0 && (member (string[i], history_word_delimiters)))
1567 	break;
1568 
1569       if (delimiter == 0 && member (string[i], HISTORY_QUOTE_CHARACTERS))
1570 	delimiter = string[i];
1571     }
1572 
1573   return i;
1574 }
1575 
1576 static char *
history_substring(const char * string,int start,int end)1577 history_substring (const char *string, int start, int end)
1578 {
1579   register int len;
1580   register char *result;
1581 
1582   len = end - start;
1583   result = (char *)xmalloc (len + 1);
1584   strncpy (result, string + start, len);
1585   result[len] = '\0';
1586   return result;
1587 }
1588 
1589 /* Parse STRING into tokens and return an array of strings.  If WIND is
1590    not -1 and INDP is not null, we also want the word surrounding index
1591    WIND.  The position in the returned array of strings is returned in
1592    *INDP. */
1593 static char **
history_tokenize_internal(const char * string,int wind,int * indp)1594 history_tokenize_internal (const char *string, int wind, int *indp)
1595 {
1596   char **result;
1597   register int i, start, result_index, size;
1598 
1599   /* If we're searching for a string that's not part of a word (e.g., " "),
1600      make sure we set *INDP to a reasonable value. */
1601   if (indp && wind != -1)
1602     *indp = -1;
1603 
1604   /* Get a token, and stuff it into RESULT.  The tokens are split
1605      exactly where the shell would split them. */
1606   for (i = result_index = size = 0, result = (char **)NULL; string[i]; )
1607     {
1608       /* Skip leading whitespace. */
1609       for (; string[i] && fielddelim (string[i]); i++)
1610 	;
1611       if (string[i] == 0 || string[i] == history_comment_char)
1612 	return (result);
1613 
1614       start = i;
1615 
1616       i = history_tokenize_word (string, start);
1617 
1618       /* If we have a non-whitespace delimiter character (which would not be
1619 	 skipped by the loop above), use it and any adjacent delimiters to
1620 	 make a separate field.  Any adjacent white space will be skipped the
1621 	 next time through the loop. */
1622       if (i == start && history_word_delimiters)
1623 	{
1624 	  i++;
1625 	  while (string[i] && member (string[i], history_word_delimiters))
1626 	    i++;
1627 	}
1628 
1629       /* If we are looking for the word in which the character at a
1630 	 particular index falls, remember it. */
1631       if (indp && wind != -1 && wind >= start && wind < i)
1632         *indp = result_index;
1633 
1634       if (result_index + 2 >= size)
1635 	result = (char **)xrealloc (result, ((size += 10) * sizeof (char *)));
1636 
1637       result[result_index++] = history_substring (string, start, i);
1638       result[result_index] = (char *)NULL;
1639     }
1640 
1641   return (result);
1642 }
1643 
1644 /* Return an array of tokens, much as the shell might.  The tokens are
1645    parsed out of STRING. */
1646 char **
history_tokenize(const char * string)1647 history_tokenize (const char *string)
1648 {
1649   return (history_tokenize_internal (string, -1, (int *)NULL));
1650 }
1651 
1652 /* Free members of WORDS from START to an empty string */
1653 static void
freewords(char ** words,int start)1654 freewords (char **words, int start)
1655 {
1656   register int i;
1657 
1658   for (i = start; words[i]; i++)
1659     xfree (words[i]);
1660 }
1661 
1662 /* Find and return the word which contains the character at index IND
1663    in the history line LINE.  Used to save the word matched by the
1664    last history !?string? search. */
1665 static char *
history_find_word(char * line,int ind)1666 history_find_word (char *line, int ind)
1667 {
1668   char **words, *s;
1669   int i, wind;
1670 
1671   words = history_tokenize_internal (line, ind, &wind);
1672   if (wind == -1 || words == 0)
1673     {
1674       if (words)
1675 	freewords (words, 0);
1676       FREE (words);
1677       return ((char *)NULL);
1678     }
1679   s = words[wind];
1680   for (i = 0; i < wind; i++)
1681     xfree (words[i]);
1682   freewords (words, wind + 1);
1683   xfree (words);
1684   return s;
1685 }
1686