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