1 /* histexpand.c -- history expansion. */
3 /* Copyright (C) 1989-2012 Free Software Foundation, Inc.
5 This file contains the GNU History Library (History), a set of
6 routines for managing the text of previously typed lines.
8 History 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 3 of the License, or
11 (at your option) any later version.
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.
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/>.
22 #define READLINE_LIBRARY
24 #if defined (HAVE_CONFIG_H)
30 #if defined (HAVE_STDLIB_H)
33 # include "ansi_stdlib.h"
34 #endif /* HAVE_STDLIB_H */
36 #if defined (HAVE_UNISTD_H)
38 # include <sys/types.h>
51 #define HISTORY_WORD_DELIMITERS " \t\n;&()|<>"
52 #define HISTORY_QUOTE_CHARACTERS "\"'`"
54 #define slashify_in_quotes "\\`\"$"
56 typedef int _hist_search_func_t PARAMS((const char *, int));
58 static char error_pointer;
60 static char *subst_lhs;
61 static char *subst_rhs;
62 static int subst_lhs_len;
63 static int subst_rhs_len;
65 static char *get_history_word_specifier PARAMS((char *, char *, int *));
66 static int history_tokenize_word PARAMS((const char *, int));
67 static char **history_tokenize_internal PARAMS((const char *, int, int *));
68 static char *history_substring PARAMS((const char *, int, int));
69 static void freewords PARAMS((char **, int));
70 static char *history_find_word PARAMS((char *, int));
72 static char *quote_breaks PARAMS((char *));
74 /* Variables exported by this file. */
75 /* The character that represents the start of a history expansion
76 request. This is usually `!'. */
77 char history_expansion_char = '!';
79 /* The character that invokes word substitution if found at the start of
80 a line. This is usually `^'. */
81 char history_subst_char = '^';
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. */
87 char history_comment_char = '\0';
89 /* The list of characters which inhibit the expansion of text if found
90 immediately following history_expansion_char. */
91 char *history_no_expand_chars = " \t\n\r=";
93 /* If set to a non-zero value, single quotes inhibit history expansion.
95 int history_quotes_inhibit_expansion = 0;
97 /* Used to split words by history_tokenize_internal. */
98 char *history_word_delimiters = HISTORY_WORD_DELIMITERS;
100 /* If set, this points to a function that is called to verify that a
101 particular history expansion should be performed. */
102 rl_linebuf_func_t *history_inhibit_expansion_function;
104 /* **************************************************************** */
106 /* History Expansion */
108 /* **************************************************************** */
110 /* Hairy history expansion on text, not tokens. This is of general
111 use, and thus belongs in this library. */
113 /* The last string searched for by a !?string? search. */
114 static char *search_string;
116 /* The last string matched by a !?string? search. */
117 static char *search_match;
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); */
130 get_history_event (string, caller_index, delimiting_quote)
133 int delimiting_quote;
138 int which, sign, local_index, substring_okay;
139 _hist_search_func_t *search_func;
142 /* The event can be specified in a number of ways.
144 !! the previous command
146 !-n current command-line minus N
147 !str the most recent command starting with STR
149 the most recent command containing STR
151 All values N are determined via HISTORY_BASE. */
155 if (string[i] != history_expansion_char)
156 return ((char *)NULL);
158 /* Move on to the specification. */
164 #define RETURN_ENTRY(e, w) \
165 return ((e = history_get (w)) ? e->line : (char *)NULL)
167 /* Handle !! case. */
168 if (string[i] == history_expansion_char)
171 which = history_base + (history_length - 1);
173 RETURN_ENTRY (entry, which);
176 /* Hack case of numeric line specification. */
177 if (string[i] == '-')
183 if (_rl_digit_p (string[i]))
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]);
192 which = (history_length + history_base) - which;
194 RETURN_ENTRY (entry, which);
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] == '?')
206 /* Only a closing `?' or a newline delimit a substring search string. */
207 for (local_index = i; c = string[i]; i++)
209 #if defined (HANDLE_MULTIBYTE)
210 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
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)
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)) ||
231 (substring_okay && string[i] == '?'))
235 which = i - local_index;
236 temp = (char *)xmalloc (1 + which);
238 strncpy (temp, string + local_index, which);
241 if (substring_okay && string[i] == '?')
246 #define FAIL_SEARCH() \
248 history_offset = history_length; xfree (temp) ; return (char *)NULL; \
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)
258 temp = savestring (search_string);
264 search_func = substring_okay ? history_search : history_search_prefix;
267 local_index = (*search_func) (temp, -1);
272 if (local_index == 0 || substring_okay)
274 entry = current_history ();
277 history_offset = history_length;
279 /* If this was a substring search, then remember the
280 string that we matched for word substitution. */
283 FREE (search_string);
284 search_string = temp;
287 search_match = history_find_word (entry->line, local_index);
292 return (entry->line);
304 /* Function for extracting single-quoted strings. Used for inhibiting
305 history expansion within single quotes. */
307 /* Extract the contents of STRING as if it is enclosed in single quotes.
308 SINDEX, when passed in, is the offset of the character immediately
309 following the opening single quote; on exit, SINDEX is left pointing
310 to the closing single quote. FLAGS currently used to allow backslash
311 to escape a single quote (e.g., for bash $'...'). */
313 hist_string_extract_single_quoted (string, sindex, flags)
319 for (i = *sindex; string[i] && string[i] != '\''; i++)
321 if ((flags & 1) && string[i] == '\\' && string[i+1])
332 register char *p, *r;
336 for (p = s; p && *p; p++, len++)
340 else if (whitespace (*p) || *p == '\n')
344 r = ret = (char *)xmalloc (len);
346 for (p = s; p && *p; )
356 else if (whitespace (*p) || *p == '\n')
371 hist_error(s, start, current, errtype)
373 int start, current, errtype;
379 ll = current - start;
383 case EVENT_NOT_FOUND:
384 emsg = "event not found";
388 emsg = "bad word specifier";
392 emsg = "substitution failed";
396 emsg = "unrecognized history modifier";
400 emsg = "no previous substitution";
404 emsg = "unknown expansion error";
409 temp = (char *)xmalloc (ll + elen + 3);
410 strncpy (temp, s + start, ll);
413 strcpy (temp + ll + 2, emsg);
417 /* Get a history substitution string from STR starting at *IPTR
418 and return it. The length is returned in LENPTR.
420 A backslash can quote the delimiter. If the string is the
421 empty string, the previous pattern is used. If there is
422 no previous pattern for the lhs, the last history search
425 If IS_RHS is 1, we ignore empty strings and set the pattern
426 to "" anyway. subst_lhs is not changed if the lhs is empty;
427 subst_rhs is allowed to be set to the empty string. */
430 get_subst_pattern (str, iptr, delimiter, is_rhs, lenptr)
432 int *iptr, delimiter, is_rhs, *lenptr;
434 register int si, i, j, k;
436 #if defined (HANDLE_MULTIBYTE)
443 #if defined (HANDLE_MULTIBYTE)
444 memset (&ps, 0, sizeof (mbstate_t));
445 _rl_adjust_point (str, i, &ps);
448 for (si = i; str[si] && str[si] != delimiter; si++)
449 #if defined (HANDLE_MULTIBYTE)
450 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
453 if ((v = _rl_get_char_len (str + si, &ps)) > 1)
455 else if (str[si] == '\\' && str[si + 1] == delimiter)
459 #endif /* HANDLE_MULTIBYTE */
460 if (str[si] == '\\' && str[si + 1] == delimiter)
463 if (si > i || is_rhs)
465 s = (char *)xmalloc (si - i + 1);
466 for (j = 0, k = i; k < si; j++, k++)
468 /* Remove a backslash quoting the search string delimiter. */
469 if (str[k] == '\\' && str[k + 1] == delimiter)
487 postproc_subst_rhs ()
492 new = (char *)xmalloc (new_size = subst_rhs_len + subst_lhs_len);
493 for (i = j = 0; i < subst_rhs_len; i++)
495 if (subst_rhs[i] == '&')
497 if (j + subst_lhs_len >= new_size)
498 new = (char *)xrealloc (new, (new_size = new_size * 2 + subst_lhs_len));
499 strcpy (new + j, subst_lhs);
504 /* a single backslash protects the `&' from lhs interpolation */
505 if (subst_rhs[i] == '\\' && subst_rhs[i + 1] == '&')
508 new = (char *)xrealloc (new, new_size *= 2);
509 new[j++] = subst_rhs[i];
518 /* Expand the bulk of a history specifier starting at STRING[START].
519 Returns 0 if everything is OK, -1 if an error occurred, and 1
520 if the `p' modifier was supplied and the caller should just print
521 the returned string. Returns the new index into string in
522 *END_INDEX_PTR, and the expanded specifier in *RET_STRING. */
524 history_expand_internal (string, start, qc, end_index_ptr, ret_string, current_line)
526 int start, qc, *end_index_ptr;
528 char *current_line; /* for !# */
530 int i, n, starting_index;
531 int substitute_globally, subst_bywords, want_quotes, print_only;
532 char *event, *temp, *result, *tstr, *t, c, *word_spec;
534 #if defined (HANDLE_MULTIBYTE)
537 memset (&ps, 0, sizeof (mbstate_t));
540 result = (char *)xmalloc (result_len = 128);
544 /* If it is followed by something that starts a word specifier,
545 then !! is implied as the event specifier. */
547 if (member (string[i + 1], ":$*%^"))
552 fake_s[0] = fake_s[1] = history_expansion_char;
554 event = get_history_event (fake_s, &fake_i, 0);
556 else if (string[i + 1] == '#')
559 event = current_line;
562 event = get_history_event (string, &i, qc);
566 *ret_string = hist_error (string, start, i, EVENT_NOT_FOUND);
571 /* If a word specifier is found, then do what that requires. */
573 word_spec = get_history_word_specifier (string, event, &i);
575 /* There is no such thing as a `malformed word specifier'. However,
576 it is possible for a specifier that has no match. In that case,
578 if (word_spec == (char *)&error_pointer)
580 *ret_string = hist_error (string, starting_index, i, BAD_WORD_SPEC);
585 /* If no word specifier, than the thing of interest was the event. */
586 temp = word_spec ? savestring (word_spec) : savestring (event);
589 /* Perhaps there are other modifiers involved. Do what they say. */
590 want_quotes = substitute_globally = subst_bywords = print_only = 0;
593 while (string[i] == ':')
597 if (c == 'g' || c == 'a')
599 substitute_globally = 1;
613 *ret_string = hist_error (string, i+1, i+2, BAD_MODIFIER);
626 /* :p means make this the last executed line. So we
627 return an error state after adding this line to the
633 /* :t discards all but the last part of the pathname. */
635 tstr = strrchr (temp, '/');
639 t = savestring (tstr);
645 /* :h discards the last part of a pathname. */
647 tstr = strrchr (temp, '/');
652 /* :r discards the suffix. */
654 tstr = strrchr (temp, '.');
659 /* :e discards everything but the suffix. */
661 tstr = strrchr (temp, '.');
664 t = savestring (tstr);
670 /* :s/this/that substitutes `that' for the first
671 occurrence of `this'. :gs/this/that substitutes `that'
672 for each occurrence of `this'. :& repeats the last
673 substitution. :g& repeats the last substitution
680 int delimiter, failed, si, l_temp, ws, we;
684 if (i + 2 < (int)strlen (string))
686 #if defined (HANDLE_MULTIBYTE)
687 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
689 _rl_adjust_point (string, i + 2, &ps);
690 if (_rl_get_char_len (string + i + 2, &ps) > 1)
693 delimiter = string[i + 2];
696 #endif /* HANDLE_MULTIBYTE */
697 delimiter = string[i + 2];
700 break; /* no search delimiter */
704 t = get_subst_pattern (string, &i, delimiter, 0, &subst_lhs_len);
705 /* An empty substitution lhs with no previous substitution
706 uses the last search string as the lhs. */
714 if (search_string && *search_string)
716 subst_lhs = savestring (search_string);
717 subst_lhs_len = strlen (subst_lhs);
721 subst_lhs = (char *) NULL;
727 subst_rhs = get_subst_pattern (string, &i, delimiter, 1, &subst_rhs_len);
729 /* If `&' appears in the rhs, it's supposed to be replaced
731 if (member ('&', subst_rhs))
732 postproc_subst_rhs ();
737 /* If there is no lhs, the substitution can't succeed. */
738 if (subst_lhs_len == 0)
740 *ret_string = hist_error (string, starting_index, i, NO_PREV_SUBST);
746 l_temp = strlen (temp);
747 /* Ignore impossible cases. */
748 if (subst_lhs_len > l_temp)
750 *ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
756 /* Find the first occurrence of THIS in TEMP. */
757 /* Substitute SUBST_RHS for SUBST_LHS in TEMP. There are three
760 1. substitute_globally == subst_bywords == 0
761 2. substitute_globally == 1 && subst_bywords == 0
762 3. substitute_globally == 0 && subst_bywords == 1
764 In the first case, we substitute for the first occurrence only.
765 In the second case, we substitute for every occurrence.
766 In the third case, we tokenize into words and substitute the
767 first occurrence of each word. */
770 for (failed = 1; (si + subst_lhs_len) <= l_temp; si++)
772 /* First skip whitespace and find word boundaries if
773 we're past the end of the word boundary we found
775 if (subst_bywords && si > we)
777 for (; temp[si] && whitespace (temp[si]); si++)
780 we = history_tokenize_word (temp, si);
783 if (STREQN (temp+si, subst_lhs, subst_lhs_len))
785 int len = subst_rhs_len - subst_lhs_len + l_temp;
786 new_event = (char *)xmalloc (1 + len);
787 strncpy (new_event, temp, si);
788 strncpy (new_event + si, subst_rhs, subst_rhs_len);
789 strncpy (new_event + si + subst_rhs_len,
790 temp + si + subst_lhs_len,
791 l_temp - (si + subst_lhs_len));
792 new_event[len] = '\0';
798 if (substitute_globally)
800 /* Reported to fix a bug that causes it to skip every
801 other match when matching a single character. Was
802 si += subst_rhs_len previously. */
803 si += subst_rhs_len - 1;
804 l_temp = strlen (temp);
805 substitute_globally++;
808 else if (subst_bywords)
811 l_temp = strlen (temp);
819 if (substitute_globally > 1)
821 substitute_globally = 0;
822 continue; /* don't want to increment i */
826 continue; /* don't want to increment i */
828 *ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
836 /* Done with modifiers. */
837 /* Believe it or not, we have to back the pointer up by one. */
844 if (want_quotes == 'q')
845 x = sh_single_quote (temp);
846 else if (want_quotes == 'x')
847 x = quote_breaks (temp);
849 x = savestring (temp);
857 result = (char *)xrealloc (result, n + 2);
858 strcpy (result, temp);
862 *ret_string = result;
866 /* Expand the string STRING, placing the result into OUTPUT, a pointer
867 to a string. Returns:
869 -1) If there was an error in expansion.
870 0) If no expansions took place (or, if the only change in
871 the text was the de-slashifying of the history expansion
873 1) If expansions did take place
874 2) If the `p' modifier was given and the caller should print the result
876 If an error ocurred in expansion, then OUTPUT contains a descriptive
879 #define ADD_STRING(s) \
882 int sl = strlen (s); \
884 if (j >= result_len) \
886 while (j >= result_len) \
888 result = (char *)xrealloc (result, result_len); \
890 strcpy (result + j - sl, s); \
894 #define ADD_CHAR(c) \
897 if (j >= result_len - 1) \
898 result = (char *)xrealloc (result, result_len += 64); \
905 history_expand (hstring, output)
910 int i, r, l, passc, cc, modified, eindex, only_printing, dquote, squote, flag;
913 /* The output string, and its length. */
917 #if defined (HANDLE_MULTIBYTE)
922 /* Used when adding the string. */
928 /* Setting the history expansion character to 0 inhibits all
929 history expansion. */
930 if (history_expansion_char == 0)
932 *output = savestring (hstring);
936 /* Prepare the buffer for printing error messages. */
937 result = (char *)xmalloc (result_len = 256);
940 only_printing = modified = 0;
941 l = strlen (hstring);
943 /* Grovel the string. Only backslash and single quotes can quote the
944 history escape character. We also handle arg specifiers. */
946 /* Before we grovel forever, see if the history_expansion_char appears
947 anywhere within the text. */
949 /* The quick substitution character is a history expansion all right. That
950 is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact,
951 that is the substitution that we do. */
952 if (hstring[0] == history_subst_char)
954 string = (char *)xmalloc (l + 5);
956 string[0] = string[1] = history_expansion_char;
959 strcpy (string + 4, hstring);
964 #if defined (HANDLE_MULTIBYTE)
965 memset (&ps, 0, sizeof (mbstate_t));
969 /* If not quick substitution, still maybe have to do expansion. */
971 /* `!' followed by one of the characters in history_no_expand_chars
972 is NOT an expansion. */
973 for (i = dquote = squote = 0; string[i]; i++)
975 #if defined (HANDLE_MULTIBYTE)
976 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
979 v = _rl_get_char_len (string + i, &ps);
986 #endif /* HANDLE_MULTIBYTE */
989 /* The history_comment_char, if set, appearing at the beginning
990 of a word signifies that the rest of the line should not have
991 history expansion performed on it.
992 Skip the rest of the line and break out of the loop. */
993 if (history_comment_char && string[i] == history_comment_char &&
994 (i == 0 || member (string[i - 1], history_word_delimiters)))
1000 else if (string[i] == history_expansion_char)
1002 if (cc == 0 || member (cc, history_no_expand_chars))
1004 /* DQUOTE won't be set unless history_quotes_inhibit_expansion
1005 is set. The idea here is to treat double-quoted strings the
1006 same as the word outside double quotes; in effect making the
1007 double quote part of history_no_expand_chars when DQUOTE is
1009 else if (dquote && cc == '"')
1011 /* If the calling application has set
1012 history_inhibit_expansion_function to a function that checks
1013 for special cases that should not be history expanded,
1014 call the function and skip the expansion if it returns a
1016 else if (history_inhibit_expansion_function &&
1017 (*history_inhibit_expansion_function) (string, i))
1022 /* Shell-like quoting: allow backslashes to quote double quotes
1023 inside a double-quoted string. */
1024 else if (dquote && string[i] == '\\' && cc == '"')
1026 /* More shell-like quoting: if we're paying attention to single
1027 quotes and letting them quote the history expansion character,
1028 then we need to pay attention to double quotes, because single
1029 quotes are not special inside double-quoted strings. */
1030 else if (history_quotes_inhibit_expansion && string[i] == '"')
1032 dquote = 1 - dquote;
1034 else if (dquote == 0 && history_quotes_inhibit_expansion && string[i] == '\'')
1036 /* If this is bash, single quotes inhibit history expansion. */
1037 flag = (i > 0 && string[i - 1] == '$');
1039 hist_string_extract_single_quoted (string, &i, flag);
1041 else if (history_quotes_inhibit_expansion && string[i] == '\\')
1043 /* If this is bash, allow backslashes to quote single
1044 quotes and the history expansion character. */
1045 if (cc == '\'' || cc == history_expansion_char)
1051 if (string[i] != history_expansion_char)
1054 *output = savestring (string);
1059 /* Extract and perform the substitution. */
1060 for (passc = dquote = squote = i = j = 0; i < l; i++)
1062 int qc, tchar = string[i];
1071 #if defined (HANDLE_MULTIBYTE)
1072 if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1077 memset (mb, 0, sizeof (mb));
1078 for (k = 0; k < MB_LEN_MAX; k++)
1081 memset (&ps, 0, sizeof (mbstate_t));
1082 if (_rl_get_char_len (mb, &ps) == -2)
1087 if (strlen (mb) > 1)
1093 #endif /* HANDLE_MULTIBYTE */
1095 if (tchar == history_expansion_char)
1097 else if (tchar == history_comment_char)
1103 ADD_CHAR (string[i]);
1112 dquote = 1 - dquote;
1118 /* If history_quotes_inhibit_expansion is set, single quotes
1119 inhibit history expansion, otherwise they are treated like
1126 else if (dquote == 0 && history_quotes_inhibit_expansion)
1130 flag = (i > 0 && string[i - 1] == '$');
1132 hist_string_extract_single_quoted (string, &i, flag);
1134 slen = i - quote + 2;
1135 temp = (char *)xmalloc (slen);
1136 strncpy (temp, string + quote, slen);
1137 temp[slen - 1] = '\0';
1141 else if (dquote == 0 && squote == 0 && history_quotes_inhibit_expansion == 0)
1144 ADD_CHAR (string[i]);
1147 ADD_CHAR (string[i]);
1151 case -2: /* history_comment_char */
1152 if (i == 0 || member (string[i - 1], history_word_delimiters))
1154 temp = (char *)xmalloc (l - i + 1);
1155 strcpy (temp, string + i);
1161 ADD_CHAR (string[i]);
1164 case -3: /* history_expansion_char */
1167 /* If the history_expansion_char is followed by one of the
1168 characters in history_no_expand_chars, then it is not a
1169 candidate for expansion of any kind. */
1170 if (cc == 0 || member (cc, history_no_expand_chars) ||
1171 (dquote && cc == '"') ||
1172 (history_inhibit_expansion_function && (*history_inhibit_expansion_function) (string, i)))
1174 ADD_CHAR (string[i]);
1178 #if defined (NO_BANG_HASH_MODIFIERS)
1179 /* There is something that is listed as a `word specifier' in csh
1180 documentation which means `the expanded text to this point'.
1181 That is not a word specifier, it is an event specifier. If we
1182 don't want to allow modifiers with `!#', just stick the current
1183 output line in again. */
1188 temp = (char *)xmalloc (1 + strlen (result));
1189 strcpy (temp, result);
1197 qc = squote ? '\'' : (dquote ? '"' : 0);
1198 r = history_expand_internal (string, i, qc, &eindex, &temp, result);
1203 if (string != hstring)
1216 only_printing = r == 1;
1224 if (string != hstring)
1230 add_history (result);
1235 return (modified != 0);
1238 /* Return a consed string which is the word specified in SPEC, and found
1239 in FROM. NULL is returned if there is no spec. The address of
1240 ERROR_POINTER is returned if the word specified cannot be found.
1241 CALLER_INDEX is the offset in SPEC to start looking; it is updated
1242 to point to just after the last character parsed. */
1244 get_history_word_specifier (spec, from, caller_index)
1248 register int i = *caller_index;
1250 int expecting_word_spec = 0;
1253 /* The range of words to return doesn't exist yet. */
1255 result = (char *)NULL;
1257 /* If we found a colon, then this *must* be a word specification. If
1258 it isn't, then it is an error. */
1262 expecting_word_spec++;
1265 /* Handle special cases first. */
1267 /* `%' is the word last searched for. */
1270 *caller_index = i + 1;
1271 return (search_match ? savestring (search_match) : savestring (""));
1274 /* `*' matches all of the arguments, but not the command. */
1277 *caller_index = i + 1;
1278 result = history_arg_extract (1, '$', from);
1279 return (result ? result : savestring (""));
1282 /* `$' is last arg. */
1285 *caller_index = i + 1;
1286 return (history_arg_extract ('$', '$', from));
1289 /* Try to get FIRST and LAST figured out. */
1293 else if (spec[i] == '^')
1298 else if (_rl_digit_p (spec[i]) && expecting_word_spec)
1300 for (first = 0; _rl_digit_p (spec[i]); i++)
1301 first = (first * 10) + _rl_digit_value (spec[i]);
1304 return ((char *)NULL); /* no valid `first' for word specifier */
1306 if (spec[i] == '^' || spec[i] == '*')
1308 last = (spec[i] == '^') ? 1 : '$'; /* x* abbreviates x-$ */
1311 else if (spec[i] != '-')
1317 if (_rl_digit_p (spec[i]))
1319 for (last = 0; _rl_digit_p (spec[i]); i++)
1320 last = (last * 10) + _rl_digit_value (spec[i]);
1322 else if (spec[i] == '$')
1328 else if (!spec[i] || spec[i] == ':')
1329 /* check against `:' because there could be a modifier separator */
1332 /* csh seems to allow anything to terminate the word spec here,
1333 leaving it as an abbreviation. */
1335 last = -1; /* x- abbreviates x-$ omitting word `$' */
1340 if (last >= first || last == '$' || last < 0)
1341 result = history_arg_extract (first, last, from);
1343 return (result ? result : (char *)&error_pointer);
1346 /* Extract the args specified, starting at FIRST, and ending at LAST.
1347 The args are taken from STRING. If either FIRST or LAST is < 0,
1348 then make that arg count from the right (subtract from the number of
1349 tokens, so that FIRST = -1 means the next to last token on the line).
1350 If LAST is `$' the last arg from STRING is used. */
1352 history_arg_extract (first, last, string)
1356 register int i, len;
1361 /* XXX - think about making history_tokenize return a struct array,
1362 each struct in array being a string and a length to avoid the
1363 calls to strlen below. */
1364 if ((list = history_tokenize (string)) == NULL)
1365 return ((char *)NULL);
1367 for (len = 0; list[len]; len++)
1371 last = len + last - 1;
1374 first = len + first - 1;
1384 if (first >= len || last > len || first < 0 || last < 0 || first > last)
1385 result = ((char *)NULL);
1388 for (size = 0, i = first; i < last; i++)
1389 size += strlen (list[i]) + 1;
1390 result = (char *)xmalloc (size + 1);
1393 for (i = first, offset = 0; i < last; i++)
1395 strcpy (result + offset, list[i]);
1396 offset += strlen (list[i]);
1399 result[offset++] = ' ';
1405 for (i = 0; i < len; i++)
1413 history_tokenize_word (string, ind)
1418 int delimiter, nestdelim, delimopen;
1421 delimiter = nestdelim = 0;
1423 if (member (string[i], "()\n"))
1429 if (member (string[i], "<>;&|$"))
1431 int peek = string[i + 1];
1433 if (peek == string[i] && peek != '$')
1435 if (peek == '<' && string[i + 2] == '-')
1437 else if (peek == '<' && string[i + 2] == '<')
1442 else if ((peek == '&' && (string[i] == '>' || string[i] == '<')) ||
1443 (peek == '>' && string[i] == '&'))
1448 /* XXX - separated out for later -- bash-4.2 */
1449 else if ((peek == '(' && (string[i] == '>' || string[i] == '<')) || /* ) */
1450 (peek == '(' && string[i] == '$')) /*)*/
1459 else if (peek == '\'' && string[i] == '$')
1466 if (string[i] != '$')
1473 /* same code also used for $(...)/<(...)/>(...) above */
1474 if (member (string[i], "!@?+*"))
1476 int peek = string[i + 1];
1478 if (peek == '(') /*)*/
1480 /* Shell extended globbing patterns */
1483 delimiter = ')'; /* XXX - not perfect */
1489 /* Get word from string + i; */
1491 if (delimiter == 0 && member (string[i], HISTORY_QUOTE_CHARACTERS))
1492 delimiter = string[i++];
1494 for (; string[i]; i++)
1496 if (string[i] == '\\' && string[i + 1] == '\n')
1502 if (string[i] == '\\' && delimiter != '\'' &&
1503 (delimiter != '"' || member (string[i], slashify_in_quotes)))
1509 /* delimiter must be set and set to something other than a quote if
1510 nestdelim is set, so these tests are safe. */
1511 if (nestdelim && string[i] == delimopen)
1516 if (nestdelim && string[i] == delimiter)
1524 if (delimiter && string[i] == delimiter)
1530 if (delimiter == 0 && (member (string[i], history_word_delimiters)))
1533 if (delimiter == 0 && member (string[i], HISTORY_QUOTE_CHARACTERS))
1534 delimiter = string[i];
1541 history_substring (string, start, end)
1546 register char *result;
1549 result = (char *)xmalloc (len + 1);
1550 strncpy (result, string + start, len);
1555 /* Parse STRING into tokens and return an array of strings. If WIND is
1556 not -1 and INDP is not null, we also want the word surrounding index
1557 WIND. The position in the returned array of strings is returned in
1560 history_tokenize_internal (string, wind, indp)
1565 register int i, start, result_index, size;
1567 /* If we're searching for a string that's not part of a word (e.g., " "),
1568 make sure we set *INDP to a reasonable value. */
1569 if (indp && wind != -1)
1572 /* Get a token, and stuff it into RESULT. The tokens are split
1573 exactly where the shell would split them. */
1574 for (i = result_index = size = 0, result = (char **)NULL; string[i]; )
1576 /* Skip leading whitespace. */
1577 for (; string[i] && whitespace (string[i]); i++)
1579 if (string[i] == 0 || string[i] == history_comment_char)
1584 i = history_tokenize_word (string, start);
1586 /* If we have a non-whitespace delimiter character (which would not be
1587 skipped by the loop above), use it and any adjacent delimiters to
1588 make a separate field. Any adjacent white space will be skipped the
1589 next time through the loop. */
1590 if (i == start && history_word_delimiters)
1593 while (string[i] && member (string[i], history_word_delimiters))
1597 /* If we are looking for the word in which the character at a
1598 particular index falls, remember it. */
1599 if (indp && wind != -1 && wind >= start && wind < i)
1600 *indp = result_index;
1602 if (result_index + 2 >= size)
1603 result = (char **)xrealloc (result, ((size += 10) * sizeof (char *)));
1605 result[result_index++] = history_substring (string, start, i);
1606 result[result_index] = (char *)NULL;
1612 /* Return an array of tokens, much as the shell might. The tokens are
1613 parsed out of STRING. */
1615 history_tokenize (string)
1618 return (history_tokenize_internal (string, -1, (int *)NULL));
1621 /* Free members of WORDS from START to an empty string */
1623 freewords (words, start)
1629 for (i = start; words[i]; i++)
1633 /* Find and return the word which contains the character at index IND
1634 in the history line LINE. Used to save the word matched by the
1635 last history !?string? search. */
1637 history_find_word (line, ind)
1644 words = history_tokenize_internal (line, ind, &wind);
1645 if (wind == -1 || words == 0)
1648 freewords (words, 0);
1650 return ((char *)NULL);
1653 for (i = 0; i < wind; i++)
1655 freewords (words, wind + 1);