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