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