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