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