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