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