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