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