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