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