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