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 1, 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
675 Mass Ave, Cambridge, MA 02139, 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 */
53
#define HISTORY_WORD_DELIMITERS " \t\n;&()|<>"
54
#define HISTORY_QUOTE_CHARACTERS "\"'`"
56
static char error_pointer;
58
static char *subst_lhs;
59
static char *subst_rhs;
60
static int subst_lhs_len;
61
static int subst_rhs_len;
63
static char *get_history_word_specifier ();
64
static char *history_find_word ();
66
extern int history_offset;
68
extern char *single_quote ();
69
static char *quote_breaks ();
71
extern char *xmalloc (), *xrealloc ();
73
/* Variables exported by this file. */
74
/* The character that represents the start of a history expansion
75
request. This is usually `!'. */
76
char history_expansion_char = '!';
78
/* The character that invokes word substitution if found at the start of
79
a line. This is usually `^'. */
80
char history_subst_char = '^';
82
/* During tokenization, if this character is seen as the first character
83
of a word, then it, and all subsequent characters upto a newline are
84
ignored. For a Bourne shell, this should be '#'. Bash special cases
85
the interactive comment character to not be a comment delimiter. */
86
char history_comment_char = '\0';
88
/* The list of characters which inhibit the expansion of text if found
89
immediately following history_expansion_char. */
90
char *history_no_expand_chars = " \t\n\r=";
92
/* If set to a non-zero value, single quotes inhibit history expansion.
94
int history_quotes_inhibit_expansion = 0;
96
/* If set, this points to a function that is called to verify that a
97
particular history expansion should be performed. */
98
Function *history_inhibit_expansion_function;
100
/* **************************************************************** */
102
/* History Expansion */
104
/* **************************************************************** */
106
/* Hairy history expansion on text, not tokens. This is of general
107
use, and thus belongs in this library. */
109
/* The last string searched for by a !?string? search. */
110
static char *search_string;
112
/* The last string matched by a !?string? search. */
113
static char *search_match;
115
/* Return the event specified at TEXT + OFFSET modifying OFFSET to
116
point to after the event specifier. Just a pointer to the history
117
line is returned; NULL is returned in the event of a bad specifier.
118
You pass STRING with *INDEX equal to the history_expansion_char that
119
begins this specification.
120
DELIMITING_QUOTE is a character that is allowed to end the string
121
specification for what to search for in addition to the normal
122
characters `:', ` ', `\t', `\n', and sometimes `?'.
123
So you might call this function like:
124
line = get_history_event ("!echo:p", &index, 0); */
126
get_history_event (string, caller_index, delimiting_quote)
129
int delimiting_quote;
134
int which, sign, local_index, substring_okay;
135
Function *search_func;
138
/* The event can be specified in a number of ways.
140
!! the previous command
142
!-n current command-line minus N
143
!str the most recent command starting with STR
145
the most recent command containing STR
147
All values N are determined via HISTORY_BASE. */
151
if (string[i] != history_expansion_char)
152
return ((char *)NULL);
154
/* Move on to the specification. */
160
#define RETURN_ENTRY(e, w) \
161
return ((e = history_get (w)) ? e->line : (char *)NULL)
163
/* Handle !! case. */
164
if (string[i] == history_expansion_char)
167
which = history_base + (history_length - 1);
169
RETURN_ENTRY (entry, which);
172
/* Hack case of numeric line specification. */
173
if (string[i] == '-')
179
if (_rl_digit_p (string[i]))
181
/* Get the extent of the digits and compute the value. */
182
for (which = 0; _rl_digit_p (string[i]); i++)
183
which = (which * 10) + _rl_digit_value (string[i]);
188
which = (history_length + history_base) - which;
190
RETURN_ENTRY (entry, which);
193
/* This must be something to search for. If the spec begins with
194
a '?', then the string may be anywhere on the line. Otherwise,
195
the string must be found at the start of a line. */
196
if (string[i] == '?')
202
/* Only a closing `?' or a newline delimit a substring search string. */
203
for (local_index = i; c = string[i]; i++)
204
if ((!substring_okay && (whitespace (c) || c == ':' ||
205
(history_search_delimiter_chars && member (c, history_search_delimiter_chars)) ||
206
string[i] == delimiting_quote)) ||
208
(substring_okay && string[i] == '?'))
211
which = i - local_index;
212
temp = xmalloc (1 + which);
214
strncpy (temp, string + local_index, which);
217
if (substring_okay && string[i] == '?')
222
#define FAIL_SEARCH() \
224
history_offset = history_length; free (temp) ; return (char *)NULL; \
227
/* If there is no search string, try to use the previous search string,
228
if one exists. If not, fail immediately. */
229
if (*temp == '\0' && substring_okay)
234
temp = savestring (search_string);
240
search_func = substring_okay ? history_search : history_search_prefix;
243
local_index = (*search_func) (temp, -1);
248
if (local_index == 0 || substring_okay)
250
entry = current_history ();
251
history_offset = history_length;
253
/* If this was a substring search, then remember the
254
string that we matched for word substitution. */
257
FREE (search_string);
258
search_string = temp;
261
search_match = history_find_word (entry->line, local_index);
266
return (entry->line);
278
/* Function for extracting single-quoted strings. Used for inhibiting
279
history expansion within single quotes. */
281
/* Extract the contents of STRING as if it is enclosed in single quotes.
282
SINDEX, when passed in, is the offset of the character immediately
283
following the opening single quote; on exit, SINDEX is left pointing
284
to the closing single quote. */
286
hist_string_extract_single_quoted (string, sindex)
292
for (i = *sindex; string[i] && string[i] != '\''; i++)
302
register char *p, *r;
306
for (p = s; p && *p; p++, len++)
310
else if (whitespace (*p) || *p == '\n')
314
r = ret = xmalloc (len);
316
for (p = s; p && *p; )
326
else if (whitespace (*p) || *p == '\n')
341
hist_error(s, start, current, errtype)
343
int start, current, errtype;
348
ll = current - start;
352
case EVENT_NOT_FOUND:
353
emsg = "event not found";
357
emsg = "bad word specifier";
361
emsg = "substitution failed";
365
emsg = "unrecognized history modifier";
369
emsg = "no previous substitution";
373
emsg = "unknown expansion error";
378
temp = xmalloc (ll + elen + 3);
379
strncpy (temp, s + start, ll);
382
strcpy (temp + ll + 2, emsg);
386
/* Get a history substitution string from STR starting at *IPTR
387
and return it. The length is returned in LENPTR.
389
A backslash can quote the delimiter. If the string is the
390
empty string, the previous pattern is used. If there is
391
no previous pattern for the lhs, the last history search
394
If IS_RHS is 1, we ignore empty strings and set the pattern
395
to "" anyway. subst_lhs is not changed if the lhs is empty;
396
subst_rhs is allowed to be set to the empty string. */
399
get_subst_pattern (str, iptr, delimiter, is_rhs, lenptr)
401
int *iptr, delimiter, is_rhs, *lenptr;
403
register int si, i, j, k;
404
char *s = (char *) NULL;
408
for (si = i; str[si] && str[si] != delimiter; si++)
409
if (str[si] == '\\' && str[si + 1] == delimiter)
412
if (si > i || is_rhs)
414
s = xmalloc (si - i + 1);
415
for (j = 0, k = i; k < si; j++, k++)
417
/* Remove a backslash quoting the search string delimiter. */
418
if (str[k] == '\\' && str[k + 1] == delimiter)
436
postproc_subst_rhs ()
441
new = xmalloc (new_size = subst_rhs_len + subst_lhs_len);
442
for (i = j = 0; i < subst_rhs_len; i++)
444
if (subst_rhs[i] == '&')
446
if (j + subst_lhs_len >= new_size)
447
new = xrealloc (new, (new_size = new_size * 2 + subst_lhs_len));
448
strcpy (new + j, subst_lhs);
453
/* a single backslash protects the `&' from lhs interpolation */
454
if (subst_rhs[i] == '\\' && subst_rhs[i + 1] == '&')
457
new = xrealloc (new, new_size *= 2);
458
new[j++] = subst_rhs[i];
467
/* Expand the bulk of a history specifier starting at STRING[START].
468
Returns 0 if everything is OK, -1 if an error occurred, and 1
469
if the `p' modifier was supplied and the caller should just print
470
the returned string. Returns the new index into string in
471
*END_INDEX_PTR, and the expanded specifier in *RET_STRING. */
473
history_expand_internal (string, start, end_index_ptr, ret_string, current_line)
475
int start, *end_index_ptr;
477
char *current_line; /* for !# */
479
int i, n, starting_index;
480
int substitute_globally, want_quotes, print_only;
481
char *event, *temp, *result, *tstr, *t, c, *word_spec;
484
result = xmalloc (result_len = 128);
488
/* If it is followed by something that starts a word specifier,
489
then !! is implied as the event specifier. */
491
if (member (string[i + 1], ":$*%^"))
496
fake_s[0] = fake_s[1] = history_expansion_char;
498
event = get_history_event (fake_s, &fake_i, 0);
500
else if (string[i + 1] == '#')
503
event = current_line;
507
int quoted_search_delimiter = 0;
509
/* If the character before this `!' is a double or single
510
quote, then this expansion takes place inside of the
511
quoted string. If we have to search for some text ("!foo"),
512
allow the delimiter to end the search string. */
513
if (i && (string[i - 1] == '\'' || string[i - 1] == '"'))
514
quoted_search_delimiter = string[i - 1];
515
event = get_history_event (string, &i, quoted_search_delimiter);
520
*ret_string = hist_error (string, start, i, EVENT_NOT_FOUND);
525
/* If a word specifier is found, then do what that requires. */
527
word_spec = get_history_word_specifier (string, event, &i);
529
/* There is no such thing as a `malformed word specifier'. However,
530
it is possible for a specifier that has no match. In that case,
532
if (word_spec == (char *)&error_pointer)
534
*ret_string = hist_error (string, starting_index, i, BAD_WORD_SPEC);
539
/* If no word specifier, than the thing of interest was the event. */
540
temp = word_spec ? savestring (word_spec) : savestring (event);
543
/* Perhaps there are other modifiers involved. Do what they say. */
544
want_quotes = substitute_globally = print_only = 0;
547
while (string[i] == ':')
553
substitute_globally = 1;
561
*ret_string = hist_error (string, i+1, i+2, BAD_MODIFIER);
574
/* :p means make this the last executed line. So we
575
return an error state after adding this line to the
581
/* :t discards all but the last part of the pathname. */
583
tstr = strrchr (temp, '/');
587
t = savestring (tstr);
593
/* :h discards the last part of a pathname. */
595
tstr = strrchr (temp, '/');
600
/* :r discards the suffix. */
602
tstr = strrchr (temp, '.');
607
/* :e discards everything but the suffix. */
609
tstr = strrchr (temp, '.');
612
t = savestring (tstr);
618
/* :s/this/that substitutes `that' for the first
619
occurrence of `this'. :gs/this/that substitutes `that'
620
for each occurrence of `this'. :& repeats the last
621
substitution. :g& repeats the last substitution
628
int delimiter, failed, si, l_temp;
632
if (i + 2 < (int)strlen (string))
633
delimiter = string[i + 2];
635
break; /* no search delimiter */
639
t = get_subst_pattern (string, &i, delimiter, 0, &subst_lhs_len);
640
/* An empty substitution lhs with no previous substitution
641
uses the last search string as the lhs. */
649
if (search_string && *search_string)
651
subst_lhs = savestring (search_string);
652
subst_lhs_len = strlen (subst_lhs);
656
subst_lhs = (char *) NULL;
662
subst_rhs = get_subst_pattern (string, &i, delimiter, 1, &subst_rhs_len);
664
/* If `&' appears in the rhs, it's supposed to be replaced
666
if (member ('&', subst_rhs))
667
postproc_subst_rhs ();
672
/* If there is no lhs, the substitution can't succeed. */
673
if (subst_lhs_len == 0)
675
*ret_string = hist_error (string, starting_index, i, NO_PREV_SUBST);
681
l_temp = strlen (temp);
682
/* Ignore impossible cases. */
683
if (subst_lhs_len > l_temp)
685
*ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
691
/* Find the first occurrence of THIS in TEMP. */
693
for (failed = 1; (si + subst_lhs_len) <= l_temp; si++)
694
if (STREQN (temp+si, subst_lhs, subst_lhs_len))
696
int len = subst_rhs_len - subst_lhs_len + l_temp;
697
new_event = xmalloc (1 + len);
698
strncpy (new_event, temp, si);
699
strncpy (new_event + si, subst_rhs, subst_rhs_len);
700
strncpy (new_event + si + subst_rhs_len,
701
temp + si + subst_lhs_len,
702
l_temp - (si + subst_lhs_len));
703
new_event[len] = '\0';
709
if (substitute_globally)
712
l_temp = strlen (temp);
713
substitute_globally++;
720
if (substitute_globally > 1)
722
substitute_globally = 0;
723
continue; /* don't want to increment i */
727
continue; /* don't want to increment i */
729
*ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
737
/* Done with modfiers. */
738
/* Believe it or not, we have to back the pointer up by one. */
745
if (want_quotes == 'q')
746
x = single_quote (temp);
747
else if (want_quotes == 'x')
748
x = quote_breaks (temp);
750
x = savestring (temp);
758
result = xrealloc (result, n + 2);
759
strcpy (result, temp);
763
*ret_string = result;
767
/* Expand the string STRING, placing the result into OUTPUT, a pointer
768
to a string. Returns:
770
-1) If there was an error in expansion.
771
0) If no expansions took place (or, if the only change in
772
the text was the de-slashifying of the history expansion
774
1) If expansions did take place
775
2) If the `p' modifier was given and the caller should print the result
777
If an error ocurred in expansion, then OUTPUT contains a descriptive
780
#define ADD_STRING(s) \
783
int sl = strlen (s); \
785
if (j >= result_len) \
787
while (j >= result_len) \
789
result = xrealloc (result, result_len); \
791
strcpy (result + j - sl, s); \
795
#define ADD_CHAR(c) \
798
if (j >= result_len - 1) \
799
result = xrealloc (result, result_len += 64); \
806
history_expand (hstring, output)
811
int i, r, l, passc, cc, modified, eindex, only_printing;
814
/* The output string, and its length. */
818
/* Used when adding the string. */
821
/* Setting the history expansion character to 0 inhibits all
822
history expansion. */
823
if (history_expansion_char == 0)
825
*output = savestring (hstring);
829
/* Prepare the buffer for printing error messages. */
830
result = xmalloc (result_len = 256);
833
only_printing = modified = 0;
834
l = strlen (hstring);
836
/* Grovel the string. Only backslash and single quotes can quote the
837
history escape character. We also handle arg specifiers. */
839
/* Before we grovel forever, see if the history_expansion_char appears
840
anywhere within the text. */
842
/* The quick substitution character is a history expansion all right. That
843
is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact,
844
that is the substitution that we do. */
845
if (hstring[0] == history_subst_char)
847
string = xmalloc (l + 5);
849
string[0] = string[1] = history_expansion_char;
852
strcpy (string + 4, hstring);
858
/* If not quick substitution, still maybe have to do expansion. */
860
/* `!' followed by one of the characters in history_no_expand_chars
861
is NOT an expansion. */
862
for (i = 0; string[i]; i++)
865
/* The history_comment_char, if set, appearing that the beginning
866
of a word signifies that the rest of the line should not have
867
history expansion performed on it.
868
Skip the rest of the line and break out of the loop. */
869
if (history_comment_char && string[i] == history_comment_char &&
870
(i == 0 || member (string[i - 1], HISTORY_WORD_DELIMITERS)))
876
else if (string[i] == history_expansion_char)
878
if (!cc || member (cc, history_no_expand_chars))
880
/* If the calling application has set
881
history_inhibit_expansion_function to a function that checks
882
for special cases that should not be history expanded,
883
call the function and skip the expansion if it returns a
885
else if (history_inhibit_expansion_function &&
886
(*history_inhibit_expansion_function) (string, i))
891
/* XXX - at some point, might want to extend this to handle
892
double quotes as well. */
893
else if (history_quotes_inhibit_expansion && string[i] == '\'')
895
/* If this is bash, single quotes inhibit history expansion. */
897
hist_string_extract_single_quoted (string, &i);
899
else if (history_quotes_inhibit_expansion && string[i] == '\\')
901
/* If this is bash, allow backslashes to quote single
902
quotes and the history expansion character. */
903
if (cc == '\'' || cc == history_expansion_char)
908
if (string[i] != history_expansion_char)
911
*output = savestring (string);
916
/* Extract and perform the substitution. */
917
for (passc = i = j = 0; i < l; i++)
919
int tchar = string[i];
928
if (tchar == history_expansion_char)
930
else if (tchar == history_comment_char)
936
ADD_CHAR (string[i]);
946
/* If history_quotes_inhibit_expansion is set, single quotes
947
inhibit history expansion. */
948
if (history_quotes_inhibit_expansion)
953
hist_string_extract_single_quoted (string, &i);
955
slen = i - quote + 2;
956
temp = xmalloc (slen);
957
strncpy (temp, string + quote, slen);
958
temp[slen - 1] = '\0';
963
ADD_CHAR (string[i]);
967
case -2: /* history_comment_char */
968
if (i == 0 || member (string[i - 1], HISTORY_WORD_DELIMITERS))
970
temp = xmalloc (l - i + 1);
971
strcpy (temp, string + i);
977
ADD_CHAR (string[i]);
980
case -3: /* history_expansion_char */
983
/* If the history_expansion_char is followed by one of the
984
characters in history_no_expand_chars, then it is not a
985
candidate for expansion of any kind. */
986
if (member (cc, history_no_expand_chars))
988
ADD_CHAR (string[i]);
992
#if defined (NO_BANG_HASH_MODIFIERS)
993
/* There is something that is listed as a `word specifier' in csh
994
documentation which means `the expanded text to this point'.
995
That is not a word specifier, it is an event specifier. If we
996
don't want to allow modifiers with `!#', just stick the current
997
output line in again. */
1002
temp = xmalloc (1 + strlen (result));
1003
strcpy (temp, result);
1012
r = history_expand_internal (string, i, &eindex, &temp, result);
1017
if (string != hstring)
1030
only_printing = r == 1;
1038
if (string != hstring)
1043
add_history (result);
1047
return (modified != 0);
1050
/* Return a consed string which is the word specified in SPEC, and found
1051
in FROM. NULL is returned if there is no spec. The address of
1052
ERROR_POINTER is returned if the word specified cannot be found.
1053
CALLER_INDEX is the offset in SPEC to start looking; it is updated
1054
to point to just after the last character parsed. */
1056
get_history_word_specifier (spec, from, caller_index)
1060
register int i = *caller_index;
1062
int expecting_word_spec = 0;
1065
/* The range of words to return doesn't exist yet. */
1067
result = (char *)NULL;
1069
/* If we found a colon, then this *must* be a word specification. If
1070
it isn't, then it is an error. */
1074
expecting_word_spec++;
1077
/* Handle special cases first. */
1079
/* `%' is the word last searched for. */
1082
*caller_index = i + 1;
1083
return (search_match ? savestring (search_match) : savestring (""));
1086
/* `*' matches all of the arguments, but not the command. */
1089
*caller_index = i + 1;
1090
result = history_arg_extract (1, '$', from);
1091
return (result ? result : savestring (""));
1094
/* `$' is last arg. */
1097
*caller_index = i + 1;
1098
return (history_arg_extract ('$', '$', from));
1101
/* Try to get FIRST and LAST figured out. */
1105
else if (spec[i] == '^')
1107
else if (_rl_digit_p (spec[i]) && expecting_word_spec)
1109
for (first = 0; _rl_digit_p (spec[i]); i++)
1110
first = (first * 10) + _rl_digit_value (spec[i]);
1113
return ((char *)NULL); /* no valid `first' for word specifier */
1115
if (spec[i] == '^' || spec[i] == '*')
1117
last = (spec[i] == '^') ? 1 : '$'; /* x* abbreviates x-$ */
1120
else if (spec[i] != '-')
1126
if (_rl_digit_p (spec[i]))
1128
for (last = 0; _rl_digit_p (spec[i]); i++)
1129
last = (last * 10) + _rl_digit_value (spec[i]);
1131
else if (spec[i] == '$')
1136
else if (!spec[i] || spec[i] == ':') /* could be modifier separator */
1137
last = -1; /* x- abbreviates x-$ omitting word `$' */
1142
if (last >= first || last == '$' || last < 0)
1143
result = history_arg_extract (first, last, from);
1145
return (result ? result : (char *)&error_pointer);
1148
/* Extract the args specified, starting at FIRST, and ending at LAST.
1149
The args are taken from STRING. If either FIRST or LAST is < 0,
1150
then make that arg count from the right (subtract from the number of
1151
tokens, so that FIRST = -1 means the next to last token on the line).
1152
If LAST is `$' the last arg from STRING is used. */
1154
history_arg_extract (first, last, string)
1158
register int i, len;
1163
/* XXX - think about making history_tokenize return a struct array,
1164
each struct in array being a string and a length to avoid the
1165
calls to strlen below. */
1166
if ((list = history_tokenize (string)) == NULL)
1167
return ((char *)NULL);
1169
for (len = 0; list[len]; len++)
1173
last = len + last - 1;
1176
first = len + first - 1;
1186
if (first >= len || last > len || first < 0 || last < 0 || first > last)
1187
result = ((char *)NULL);
1190
for (size = 0, i = first; i < last; i++)
1191
size += strlen (list[i]) + 1;
1192
result = xmalloc (size + 1);
1195
for (i = first, offset = 0; i < last; i++)
1197
strcpy (result + offset, list[i]);
1198
offset += strlen (list[i]);
1201
result[offset++] = ' ';
1207
for (i = 0; i < len; i++)
1214
#define slashify_in_quotes "\\`\"$"
1216
/* Parse STRING into tokens and return an array of strings. If WIND is
1217
not -1 and INDP is not null, we also want the word surrounding index
1218
WIND. The position in the returned array of strings is returned in
1221
history_tokenize_internal (string, wind, indp)
1226
register int i, start, result_index, size;
1229
/* Get a token, and stuff it into RESULT. The tokens are split
1230
exactly where the shell would split them. */
1231
for (i = result_index = size = 0, result = (char **)NULL; string[i]; )
1235
/* Skip leading whitespace. */
1236
for (; string[i] && whitespace (string[i]); i++)
1238
if (string[i] == 0 || string[i] == history_comment_char)
1243
if (member (string[i], "()\n"))
1249
if (member (string[i], "<>;&|$"))
1251
int peek = string[i + 1];
1253
if (peek == string[i] && peek != '$')
1255
if (peek == '<' && string[i + 2] == '-')
1262
if ((peek == '&' && (string[i] == '>' || string[i] == '<')) ||
1263
((peek == '>') && (string[i] == '&')) ||
1264
((peek == '(') && (string[i] == '$')))
1270
if (string[i] != '$')
1277
/* Get word from string + i; */
1279
if (member (string[i], HISTORY_QUOTE_CHARACTERS))
1280
delimiter = string[i++];
1282
for (; string[i]; i++)
1284
if (string[i] == '\\' && string[i + 1] == '\n')
1290
if (string[i] == '\\' && delimiter != '\'' &&
1291
(delimiter != '"' || member (string[i], slashify_in_quotes)))
1297
if (delimiter && string[i] == delimiter)
1303
if (!delimiter && (member (string[i], HISTORY_WORD_DELIMITERS)))
1306
if (!delimiter && member (string[i], HISTORY_QUOTE_CHARACTERS))
1307
delimiter = string[i];
1312
/* If we are looking for the word in which the character at a
1313
particular index falls, remember it. */
1314
if (indp && wind != -1 && wind >= start && wind < i)
1315
*indp = result_index;
1318
if (result_index + 2 >= size)
1319
result = (char **)xrealloc (result, ((size += 10) * sizeof (char *)));
1320
result[result_index] = xmalloc (1 + len);
1321
strncpy (result[result_index], string + start, len);
1322
result[result_index][len] = '\0';
1323
result[++result_index] = (char *)NULL;
1329
/* Return an array of tokens, much as the shell might. The tokens are
1330
parsed out of STRING. */
1332
history_tokenize (string)
1335
return (history_tokenize_internal (string, -1, (int *)NULL));
1338
/* Find and return the word which contains the character at index IND
1339
in the history line LINE. Used to save the word matched by the
1340
last history !?string? search. */
1342
history_find_word (line, ind)
1349
words = history_tokenize_internal (line, ind, &wind);
1351
return ((char *)NULL);
1353
for (i = 0; i < wind; i++)
1355
for (i = wind + 1; words[i]; i++)