1 /* histexpand.c -- history expansion. */
3 /* Copyright (C) 1989, 1992 Free Software Foundation, Inc.
5 This file contains the GNU History Library (the Library), a set of
6 routines for managing the text of previously typed lines.
8 The Library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
13 The Library is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 The GNU General Public License is often shipped with GNU software, and
19 is generally kept in a file called COPYING or LICENSE. If you do not
20 have a copy of the license, write to the Free Software Foundation,
21 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
23 #define READLINE_LIBRARY
25 #if defined (HAVE_CONFIG_H)
31 #if defined (HAVE_STDLIB_H)
34 # include "ansi_stdlib.h"
35 #endif /* HAVE_STDLIB_H */
37 #if defined (HAVE_UNISTD_H)
39 # include <sys/types.h>
44 #if defined (HAVE_STRING_H)
48 #endif /* !HAVE_STRING_H */
56 #define HISTORY_WORD_DELIMITERS " \t\n;&()|<>"
57 #define HISTORY_QUOTE_CHARACTERS "\"'`"
59 static char error_pointer;
61 static char *subst_lhs;
62 static char *subst_rhs;
63 static int subst_lhs_len;
64 static int subst_rhs_len;
66 static char *get_history_word_specifier __P((char *, char *, int *));
67 static char *history_find_word __P((char *, int));
69 static char *quote_breaks __P((char *));
71 /* Variables exported by this file. */
72 /* The character that represents the start of a history expansion
73 request. This is usually `!'. */
74 char history_expansion_char = '!';
76 /* The character that invokes word substitution if found at the start of
77 a line. This is usually `^'. */
78 char history_subst_char = '^';
80 /* During tokenization, if this character is seen as the first character
81 of a word, then it, and all subsequent characters upto a newline are
82 ignored. For a Bourne shell, this should be '#'. Bash special cases
83 the interactive comment character to not be a comment delimiter. */
84 char history_comment_char = '\0';
86 /* The list of characters which inhibit the expansion of text if found
87 immediately following history_expansion_char. */
88 char *history_no_expand_chars = " \t\n\r=";
90 /* If set to a non-zero value, single quotes inhibit history expansion.
92 int history_quotes_inhibit_expansion = 0;
94 /* If set, this points to a function that is called to verify that a
95 particular history expansion should be performed. */
96 Function *history_inhibit_expansion_function;
98 /* **************************************************************** */
100 /* History Expansion */
102 /* **************************************************************** */
104 /* Hairy history expansion on text, not tokens. This is of general
105 use, and thus belongs in this library. */
107 /* The last string searched for by a !?string? search. */
108 static char *search_string;
110 /* The last string matched by a !?string? search. */
111 static char *search_match;
113 /* Return the event specified at TEXT + OFFSET modifying OFFSET to
114 point to after the event specifier. Just a pointer to the history
115 line is returned; NULL is returned in the event of a bad specifier.
116 You pass STRING with *INDEX equal to the history_expansion_char that
117 begins this specification.
118 DELIMITING_QUOTE is a character that is allowed to end the string
119 specification for what to search for in addition to the normal
120 characters `:', ` ', `\t', `\n', and sometimes `?'.
121 So you might call this function like:
122 line = get_history_event ("!echo:p", &index, 0); */
124 get_history_event (string, caller_index, delimiting_quote)
127 int delimiting_quote;
132 int which, sign, local_index, substring_okay;
133 Function *search_func;
136 /* The event can be specified in a number of ways.
138 !! the previous command
140 !-n current command-line minus N
141 !str the most recent command starting with STR
143 the most recent command containing STR
145 All values N are determined via HISTORY_BASE. */
149 if (string[i] != history_expansion_char)
150 return ((char *)NULL);
152 /* Move on to the specification. */
158 #define RETURN_ENTRY(e, w) \
159 return ((e = history_get (w)) ? e->line : (char *)NULL)
161 /* Handle !! case. */
162 if (string[i] == history_expansion_char)
165 which = history_base + (history_length - 1);
167 RETURN_ENTRY (entry, which);
170 /* Hack case of numeric line specification. */
171 if (string[i] == '-')
177 if (_rl_digit_p (string[i]))
179 /* Get the extent of the digits and compute the value. */
180 for (which = 0; _rl_digit_p (string[i]); i++)
181 which = (which * 10) + _rl_digit_value (string[i]);
186 which = (history_length + history_base) - which;
188 RETURN_ENTRY (entry, which);
191 /* This must be something to search for. If the spec begins with
192 a '?', then the string may be anywhere on the line. Otherwise,
193 the string must be found at the start of a line. */
194 if (string[i] == '?')
200 /* Only a closing `?' or a newline delimit a substring search string. */
201 for (local_index = i; c = string[i]; i++)
202 if ((!substring_okay && (whitespace (c) || c == ':' ||
203 (history_search_delimiter_chars && member (c, history_search_delimiter_chars)) ||
204 string[i] == delimiting_quote)) ||
206 (substring_okay && string[i] == '?'))
209 which = i - local_index;
210 temp = xmalloc (1 + which);
212 strncpy (temp, string + local_index, which);
215 if (substring_okay && string[i] == '?')
220 #define FAIL_SEARCH() \
222 history_offset = history_length; free (temp) ; return (char *)NULL; \
225 /* If there is no search string, try to use the previous search string,
226 if one exists. If not, fail immediately. */
227 if (*temp == '\0' && substring_okay)
232 temp = savestring (search_string);
238 search_func = substring_okay ? history_search : history_search_prefix;
241 local_index = (*search_func) (temp, -1);
246 if (local_index == 0 || substring_okay)
248 entry = current_history ();
249 history_offset = history_length;
251 /* If this was a substring search, then remember the
252 string that we matched for word substitution. */
255 FREE (search_string);
256 search_string = temp;
259 search_match = history_find_word (entry->line, local_index);
264 return (entry->line);
276 /* Function for extracting single-quoted strings. Used for inhibiting
277 history expansion within single quotes. */
279 /* Extract the contents of STRING as if it is enclosed in single quotes.
280 SINDEX, when passed in, is the offset of the character immediately
281 following the opening single quote; on exit, SINDEX is left pointing
282 to the closing single quote. */
284 hist_string_extract_single_quoted (string, sindex)
290 for (i = *sindex; string[i] && string[i] != '\''; i++)
300 register char *p, *r;
304 for (p = s; p && *p; p++, len++)
308 else if (whitespace (*p) || *p == '\n')
312 r = ret = xmalloc (len);
314 for (p = s; p && *p; )
324 else if (whitespace (*p) || *p == '\n')
339 hist_error(s, start, current, errtype)
341 int start, current, errtype;
346 ll = current - start;
350 case EVENT_NOT_FOUND:
351 emsg = "event not found";
355 emsg = "bad word specifier";
359 emsg = "substitution failed";
363 emsg = "unrecognized history modifier";
367 emsg = "no previous substitution";
371 emsg = "unknown expansion error";
376 temp = xmalloc (ll + elen + 3);
377 strncpy (temp, s + start, ll);
380 strcpy (temp + ll + 2, emsg);
384 /* Get a history substitution string from STR starting at *IPTR
385 and return it. The length is returned in LENPTR.
387 A backslash can quote the delimiter. If the string is the
388 empty string, the previous pattern is used. If there is
389 no previous pattern for the lhs, the last history search
392 If IS_RHS is 1, we ignore empty strings and set the pattern
393 to "" anyway. subst_lhs is not changed if the lhs is empty;
394 subst_rhs is allowed to be set to the empty string. */
397 get_subst_pattern (str, iptr, delimiter, is_rhs, lenptr)
399 int *iptr, delimiter, is_rhs, *lenptr;
401 register int si, i, j, k;
402 char *s = (char *) NULL;
406 for (si = i; str[si] && str[si] != delimiter; si++)
407 if (str[si] == '\\' && str[si + 1] == delimiter)
410 if (si > i || is_rhs)
412 s = xmalloc (si - i + 1);
413 for (j = 0, k = i; k < si; j++, k++)
415 /* Remove a backslash quoting the search string delimiter. */
416 if (str[k] == '\\' && str[k + 1] == delimiter)
434 postproc_subst_rhs ()
439 new = xmalloc (new_size = subst_rhs_len + subst_lhs_len);
440 for (i = j = 0; i < subst_rhs_len; i++)
442 if (subst_rhs[i] == '&')
444 if (j + subst_lhs_len >= new_size)
445 new = xrealloc (new, (new_size = new_size * 2 + subst_lhs_len));
446 strcpy (new + j, subst_lhs);
451 /* a single backslash protects the `&' from lhs interpolation */
452 if (subst_rhs[i] == '\\' && subst_rhs[i + 1] == '&')
455 new = xrealloc (new, new_size *= 2);
456 new[j++] = subst_rhs[i];
465 /* Expand the bulk of a history specifier starting at STRING[START].
466 Returns 0 if everything is OK, -1 if an error occurred, and 1
467 if the `p' modifier was supplied and the caller should just print
468 the returned string. Returns the new index into string in
469 *END_INDEX_PTR, and the expanded specifier in *RET_STRING. */
471 history_expand_internal (string, start, end_index_ptr, ret_string, current_line)
473 int start, *end_index_ptr;
475 char *current_line; /* for !# */
477 int i, n, starting_index;
478 int substitute_globally, want_quotes, print_only;
479 char *event, *temp, *result, *tstr, *t, c, *word_spec;
482 result = xmalloc (result_len = 128);
486 /* If it is followed by something that starts a word specifier,
487 then !! is implied as the event specifier. */
489 if (member (string[i + 1], ":$*%^"))
494 fake_s[0] = fake_s[1] = history_expansion_char;
496 event = get_history_event (fake_s, &fake_i, 0);
498 else if (string[i + 1] == '#')
501 event = current_line;
505 int quoted_search_delimiter = 0;
507 /* If the character before this `!' is a double or single
508 quote, then this expansion takes place inside of the
509 quoted string. If we have to search for some text ("!foo"),
510 allow the delimiter to end the search string. */
511 if (i && (string[i - 1] == '\'' || string[i - 1] == '"'))
512 quoted_search_delimiter = string[i - 1];
513 event = get_history_event (string, &i, quoted_search_delimiter);
518 *ret_string = hist_error (string, start, i, EVENT_NOT_FOUND);
523 /* If a word specifier is found, then do what that requires. */
525 word_spec = get_history_word_specifier (string, event, &i);
527 /* There is no such thing as a `malformed word specifier'. However,
528 it is possible for a specifier that has no match. In that case,
530 if (word_spec == (char *)&error_pointer)
532 *ret_string = hist_error (string, starting_index, i, BAD_WORD_SPEC);
537 /* If no word specifier, than the thing of interest was the event. */
538 temp = word_spec ? savestring (word_spec) : savestring (event);
541 /* Perhaps there are other modifiers involved. Do what they say. */
542 want_quotes = substitute_globally = print_only = 0;
545 while (string[i] == ':')
551 substitute_globally = 1;
559 *ret_string = hist_error (string, i+1, i+2, BAD_MODIFIER);
572 /* :p means make this the last executed line. So we
573 return an error state after adding this line to the
579 /* :t discards all but the last part of the pathname. */
581 tstr = strrchr (temp, '/');
585 t = savestring (tstr);
591 /* :h discards the last part of a pathname. */
593 tstr = strrchr (temp, '/');
598 /* :r discards the suffix. */
600 tstr = strrchr (temp, '.');
605 /* :e discards everything but the suffix. */
607 tstr = strrchr (temp, '.');
610 t = savestring (tstr);
616 /* :s/this/that substitutes `that' for the first
617 occurrence of `this'. :gs/this/that substitutes `that'
618 for each occurrence of `this'. :& repeats the last
619 substitution. :g& repeats the last substitution
626 int delimiter, failed, si, l_temp;
630 if (i + 2 < (int)strlen (string))
631 delimiter = string[i + 2];
633 break; /* no search delimiter */
637 t = get_subst_pattern (string, &i, delimiter, 0, &subst_lhs_len);
638 /* An empty substitution lhs with no previous substitution
639 uses the last search string as the lhs. */
647 if (search_string && *search_string)
649 subst_lhs = savestring (search_string);
650 subst_lhs_len = strlen (subst_lhs);
654 subst_lhs = (char *) NULL;
660 subst_rhs = get_subst_pattern (string, &i, delimiter, 1, &subst_rhs_len);
662 /* If `&' appears in the rhs, it's supposed to be replaced
664 if (member ('&', subst_rhs))
665 postproc_subst_rhs ();
670 /* If there is no lhs, the substitution can't succeed. */
671 if (subst_lhs_len == 0)
673 *ret_string = hist_error (string, starting_index, i, NO_PREV_SUBST);
679 l_temp = strlen (temp);
680 /* Ignore impossible cases. */
681 if (subst_lhs_len > l_temp)
683 *ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
689 /* Find the first occurrence of THIS in TEMP. */
691 for (failed = 1; (si + subst_lhs_len) <= l_temp; si++)
692 if (STREQN (temp+si, subst_lhs, subst_lhs_len))
694 int len = subst_rhs_len - subst_lhs_len + l_temp;
695 new_event = xmalloc (1 + len);
696 strncpy (new_event, temp, si);
697 strncpy (new_event + si, subst_rhs, subst_rhs_len);
698 strncpy (new_event + si + subst_rhs_len,
699 temp + si + subst_lhs_len,
700 l_temp - (si + subst_lhs_len));
701 new_event[len] = '\0';
707 if (substitute_globally)
710 l_temp = strlen (temp);
711 substitute_globally++;
718 if (substitute_globally > 1)
720 substitute_globally = 0;
721 continue; /* don't want to increment i */
725 continue; /* don't want to increment i */
727 *ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
735 /* Done with modfiers. */
736 /* Believe it or not, we have to back the pointer up by one. */
743 if (want_quotes == 'q')
744 x = single_quote (temp);
745 else if (want_quotes == 'x')
746 x = quote_breaks (temp);
748 x = savestring (temp);
756 result = xrealloc (result, n + 2);
757 strcpy (result, temp);
761 *ret_string = result;
765 /* Expand the string STRING, placing the result into OUTPUT, a pointer
766 to a string. Returns:
768 -1) If there was an error in expansion.
769 0) If no expansions took place (or, if the only change in
770 the text was the de-slashifying of the history expansion
772 1) If expansions did take place
773 2) If the `p' modifier was given and the caller should print the result
775 If an error ocurred in expansion, then OUTPUT contains a descriptive
778 #define ADD_STRING(s) \
781 int sl = strlen (s); \
783 if (j >= result_len) \
785 while (j >= result_len) \
787 result = xrealloc (result, result_len); \
789 strcpy (result + j - sl, s); \
793 #define ADD_CHAR(c) \
796 if (j >= result_len - 1) \
797 result = xrealloc (result, result_len += 64); \
804 history_expand (hstring, output)
809 int i, r, l, passc, cc, modified, eindex, only_printing;
812 /* The output string, and its length. */
816 /* Used when adding the string. */
819 /* Setting the history expansion character to 0 inhibits all
820 history expansion. */
821 if (history_expansion_char == 0)
823 *output = savestring (hstring);
827 /* Prepare the buffer for printing error messages. */
828 result = xmalloc (result_len = 256);
831 only_printing = modified = 0;
832 l = strlen (hstring);
834 /* Grovel the string. Only backslash and single quotes can quote the
835 history escape character. We also handle arg specifiers. */
837 /* Before we grovel forever, see if the history_expansion_char appears
838 anywhere within the text. */
840 /* The quick substitution character is a history expansion all right. That
841 is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact,
842 that is the substitution that we do. */
843 if (hstring[0] == history_subst_char)
845 string = xmalloc (l + 5);
847 string[0] = string[1] = history_expansion_char;
850 strcpy (string + 4, hstring);
856 /* If not quick substitution, still maybe have to do expansion. */
858 /* `!' followed by one of the characters in history_no_expand_chars
859 is NOT an expansion. */
860 for (i = 0; string[i]; i++)
863 /* The history_comment_char, if set, appearing that the beginning
864 of a word signifies that the rest of the line should not have
865 history expansion performed on it.
866 Skip the rest of the line and break out of the loop. */
867 if (history_comment_char && string[i] == history_comment_char &&
868 (i == 0 || member (string[i - 1], HISTORY_WORD_DELIMITERS)))
874 else if (string[i] == history_expansion_char)
876 if (!cc || member (cc, history_no_expand_chars))
878 /* If the calling application has set
879 history_inhibit_expansion_function to a function that checks
880 for special cases that should not be history expanded,
881 call the function and skip the expansion if it returns a
883 else if (history_inhibit_expansion_function &&
884 (*history_inhibit_expansion_function) (string, i))
889 /* XXX - at some point, might want to extend this to handle
890 double quotes as well. */
891 else if (history_quotes_inhibit_expansion && string[i] == '\'')
893 /* If this is bash, single quotes inhibit history expansion. */
895 hist_string_extract_single_quoted (string, &i);
897 else if (history_quotes_inhibit_expansion && string[i] == '\\')
899 /* If this is bash, allow backslashes to quote single
900 quotes and the history expansion character. */
901 if (cc == '\'' || cc == history_expansion_char)
906 if (string[i] != history_expansion_char)
909 *output = savestring (string);
914 /* Extract and perform the substitution. */
915 for (passc = i = j = 0; i < l; i++)
917 int tchar = string[i];
926 if (tchar == history_expansion_char)
928 else if (tchar == history_comment_char)
934 ADD_CHAR (string[i]);
944 /* If history_quotes_inhibit_expansion is set, single quotes
945 inhibit history expansion. */
946 if (history_quotes_inhibit_expansion)
951 hist_string_extract_single_quoted (string, &i);
953 slen = i - quote + 2;
954 temp = xmalloc (slen);
955 strncpy (temp, string + quote, slen);
956 temp[slen - 1] = '\0';
961 ADD_CHAR (string[i]);
965 case -2: /* history_comment_char */
966 if (i == 0 || member (string[i - 1], HISTORY_WORD_DELIMITERS))
968 temp = xmalloc (l - i + 1);
969 strcpy (temp, string + i);
975 ADD_CHAR (string[i]);
978 case -3: /* history_expansion_char */
981 /* If the history_expansion_char is followed by one of the
982 characters in history_no_expand_chars, then it is not a
983 candidate for expansion of any kind. */
984 if (member (cc, history_no_expand_chars))
986 ADD_CHAR (string[i]);
990 #if defined (NO_BANG_HASH_MODIFIERS)
991 /* There is something that is listed as a `word specifier' in csh
992 documentation which means `the expanded text to this point'.
993 That is not a word specifier, it is an event specifier. If we
994 don't want to allow modifiers with `!#', just stick the current
995 output line in again. */
1000 temp = xmalloc (1 + strlen (result));
1001 strcpy (temp, result);
1010 r = history_expand_internal (string, i, &eindex, &temp, result);
1015 if (string != hstring)
1028 only_printing = r == 1;
1036 if (string != hstring)
1041 add_history (result);
1045 return (modified != 0);
1048 /* Return a consed string which is the word specified in SPEC, and found
1049 in FROM. NULL is returned if there is no spec. The address of
1050 ERROR_POINTER is returned if the word specified cannot be found.
1051 CALLER_INDEX is the offset in SPEC to start looking; it is updated
1052 to point to just after the last character parsed. */
1054 get_history_word_specifier (spec, from, caller_index)
1058 register int i = *caller_index;
1060 int expecting_word_spec = 0;
1063 /* The range of words to return doesn't exist yet. */
1065 result = (char *)NULL;
1067 /* If we found a colon, then this *must* be a word specification. If
1068 it isn't, then it is an error. */
1072 expecting_word_spec++;
1075 /* Handle special cases first. */
1077 /* `%' is the word last searched for. */
1080 *caller_index = i + 1;
1081 return (search_match ? savestring (search_match) : savestring (""));
1084 /* `*' matches all of the arguments, but not the command. */
1087 *caller_index = i + 1;
1088 result = history_arg_extract (1, '$', from);
1089 return (result ? result : savestring (""));
1092 /* `$' is last arg. */
1095 *caller_index = i + 1;
1096 return (history_arg_extract ('$', '$', from));
1099 /* Try to get FIRST and LAST figured out. */
1103 else if (spec[i] == '^')
1105 else if (_rl_digit_p (spec[i]) && expecting_word_spec)
1107 for (first = 0; _rl_digit_p (spec[i]); i++)
1108 first = (first * 10) + _rl_digit_value (spec[i]);
1111 return ((char *)NULL); /* no valid `first' for word specifier */
1113 if (spec[i] == '^' || spec[i] == '*')
1115 last = (spec[i] == '^') ? 1 : '$'; /* x* abbreviates x-$ */
1118 else if (spec[i] != '-')
1124 if (_rl_digit_p (spec[i]))
1126 for (last = 0; _rl_digit_p (spec[i]); i++)
1127 last = (last * 10) + _rl_digit_value (spec[i]);
1129 else if (spec[i] == '$')
1134 else if (!spec[i] || spec[i] == ':') /* could be modifier separator */
1135 last = -1; /* x- abbreviates x-$ omitting word `$' */
1140 if (last >= first || last == '$' || last < 0)
1141 result = history_arg_extract (first, last, from);
1143 return (result ? result : (char *)&error_pointer);
1146 /* Extract the args specified, starting at FIRST, and ending at LAST.
1147 The args are taken from STRING. If either FIRST or LAST is < 0,
1148 then make that arg count from the right (subtract from the number of
1149 tokens, so that FIRST = -1 means the next to last token on the line).
1150 If LAST is `$' the last arg from STRING is used. */
1152 history_arg_extract (first, last, string)
1156 register int i, len;
1161 /* XXX - think about making history_tokenize return a struct array,
1162 each struct in array being a string and a length to avoid the
1163 calls to strlen below. */
1164 if ((list = history_tokenize (string)) == NULL)
1165 return ((char *)NULL);
1167 for (len = 0; list[len]; len++)
1171 last = len + last - 1;
1174 first = len + first - 1;
1184 if (first >= len || last > len || first < 0 || last < 0 || first > last)
1185 result = ((char *)NULL);
1188 for (size = 0, i = first; i < last; i++)
1189 size += strlen (list[i]) + 1;
1190 result = xmalloc (size + 1);
1193 for (i = first, offset = 0; i < last; i++)
1195 strcpy (result + offset, list[i]);
1196 offset += strlen (list[i]);
1199 result[offset++] = ' ';
1205 for (i = 0; i < len; i++)
1212 #define slashify_in_quotes "\\`\"$"
1214 /* Parse STRING into tokens and return an array of strings. If WIND is
1215 not -1 and INDP is not null, we also want the word surrounding index
1216 WIND. The position in the returned array of strings is returned in
1219 history_tokenize_internal (string, wind, indp)
1224 register int i, start, result_index, size;
1227 /* Get a token, and stuff it into RESULT. The tokens are split
1228 exactly where the shell would split them. */
1229 for (i = result_index = size = 0, result = (char **)NULL; string[i]; )
1233 /* Skip leading whitespace. */
1234 for (; string[i] && whitespace (string[i]); i++)
1236 if (string[i] == 0 || string[i] == history_comment_char)
1241 if (member (string[i], "()\n"))
1247 if (member (string[i], "<>;&|$"))
1249 int peek = string[i + 1];
1251 if (peek == string[i] && peek != '$')
1253 if (peek == '<' && string[i + 2] == '-')
1260 if ((peek == '&' && (string[i] == '>' || string[i] == '<')) ||
1261 ((peek == '>') && (string[i] == '&')) ||
1262 ((peek == '(') && (string[i] == '$')))
1268 if (string[i] != '$')
1275 /* Get word from string + i; */
1277 if (member (string[i], HISTORY_QUOTE_CHARACTERS))
1278 delimiter = string[i++];
1280 for (; string[i]; i++)
1282 if (string[i] == '\\' && string[i + 1] == '\n')
1288 if (string[i] == '\\' && delimiter != '\'' &&
1289 (delimiter != '"' || member (string[i], slashify_in_quotes)))
1295 if (delimiter && string[i] == delimiter)
1301 if (!delimiter && (member (string[i], HISTORY_WORD_DELIMITERS)))
1304 if (!delimiter && member (string[i], HISTORY_QUOTE_CHARACTERS))
1305 delimiter = string[i];
1310 /* If we are looking for the word in which the character at a
1311 particular index falls, remember it. */
1312 if (indp && wind != -1 && wind >= start && wind < i)
1313 *indp = result_index;
1316 if (result_index + 2 >= size)
1317 result = (char **)xrealloc (result, ((size += 10) * sizeof (char *)));
1318 result[result_index] = xmalloc (1 + len);
1319 strncpy (result[result_index], string + start, len);
1320 result[result_index][len] = '\0';
1321 result[++result_index] = (char *)NULL;
1327 /* Return an array of tokens, much as the shell might. The tokens are
1328 parsed out of STRING. */
1330 history_tokenize (string)
1333 return (history_tokenize_internal (string, -1, (int *)NULL));
1336 /* Find and return the word which contains the character at index IND
1337 in the history line LINE. Used to save the word matched by the
1338 last history !?string? search. */
1340 history_find_word (line, ind)
1347 words = history_tokenize_internal (line, ind, &wind);
1349 return ((char *)NULL);
1351 for (i = 0; i < wind; i++)
1353 for (i = wind + 1; words[i]; i++)