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