nfe_init() should be called with softc not ifnet
[dragonfly.git] / contrib / libreadline / histexpand.c
blob78da3e585a651983535fe672b05eadcaee09cfe1
1 /* histexpand.c -- history expansion. */
3 /* Copyright (C) 1989, 1992 Free Software Foundation, Inc.
5 This file contains the GNU History Library (the Library), a set of
6 routines for managing the text of previously typed lines.
8 The Library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
13 The Library is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 The GNU General Public License is often shipped with GNU software, and
19 is generally kept in a file called COPYING or LICENSE. If you do not
20 have a copy of the license, write to the Free Software Foundation,
21 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
23 #define READLINE_LIBRARY
25 #if defined (HAVE_CONFIG_H)
26 # include <config.h>
27 #endif
29 #include <stdio.h>
31 #if defined (HAVE_STDLIB_H)
32 # include <stdlib.h>
33 #else
34 # include "ansi_stdlib.h"
35 #endif /* HAVE_STDLIB_H */
37 #if defined (HAVE_UNISTD_H)
38 # ifndef _MINIX
39 # include <sys/types.h>
40 # endif
41 # include <unistd.h>
42 #endif
44 #if defined (HAVE_STRING_H)
45 # include <string.h>
46 #else
47 # include <strings.h>
48 #endif /* !HAVE_STRING_H */
50 #include "history.h"
51 #include "histlib.h"
53 #include "rlshell.h"
54 #include "xmalloc.h"
56 #define HISTORY_WORD_DELIMITERS " \t\n;&()|<>"
57 #define HISTORY_QUOTE_CHARACTERS "\"'`"
59 static char error_pointer;
61 static char *subst_lhs;
62 static char *subst_rhs;
63 static int subst_lhs_len;
64 static int subst_rhs_len;
66 static char *get_history_word_specifier __P((char *, char *, int *));
67 static char *history_find_word __P((char *, int));
69 static char *quote_breaks __P((char *));
71 /* Variables exported by this file. */
72 /* The character that represents the start of a history expansion
73 request. This is usually `!'. */
74 char history_expansion_char = '!';
76 /* The character that invokes word substitution if found at the start of
77 a line. This is usually `^'. */
78 char history_subst_char = '^';
80 /* During tokenization, if this character is seen as the first character
81 of a word, then it, and all subsequent characters upto a newline are
82 ignored. For a Bourne shell, this should be '#'. Bash special cases
83 the interactive comment character to not be a comment delimiter. */
84 char history_comment_char = '\0';
86 /* The list of characters which inhibit the expansion of text if found
87 immediately following history_expansion_char. */
88 char *history_no_expand_chars = " \t\n\r=";
90 /* If set to a non-zero value, single quotes inhibit history expansion.
91 The default is 0. */
92 int history_quotes_inhibit_expansion = 0;
94 /* If set, this points to a function that is called to verify that a
95 particular history expansion should be performed. */
96 Function *history_inhibit_expansion_function;
98 /* **************************************************************** */
99 /* */
100 /* History Expansion */
101 /* */
102 /* **************************************************************** */
104 /* Hairy history expansion on text, not tokens. This is of general
105 use, and thus belongs in this library. */
107 /* The last string searched for by a !?string? search. */
108 static char *search_string;
110 /* The last string matched by a !?string? search. */
111 static char *search_match;
113 /* Return the event specified at TEXT + OFFSET modifying OFFSET to
114 point to after the event specifier. Just a pointer to the history
115 line is returned; NULL is returned in the event of a bad specifier.
116 You pass STRING with *INDEX equal to the history_expansion_char that
117 begins this specification.
118 DELIMITING_QUOTE is a character that is allowed to end the string
119 specification for what to search for in addition to the normal
120 characters `:', ` ', `\t', `\n', and sometimes `?'.
121 So you might call this function like:
122 line = get_history_event ("!echo:p", &index, 0); */
123 char *
124 get_history_event (string, caller_index, delimiting_quote)
125 char *string;
126 int *caller_index;
127 int delimiting_quote;
129 register int i;
130 register char c;
131 HIST_ENTRY *entry;
132 int which, sign, local_index, substring_okay;
133 Function *search_func;
134 char *temp;
136 /* The event can be specified in a number of ways.
138 !! the previous command
139 !n command line N
140 !-n current command-line minus N
141 !str the most recent command starting with STR
142 !?str[?]
143 the most recent command containing STR
145 All values N are determined via HISTORY_BASE. */
147 i = *caller_index;
149 if (string[i] != history_expansion_char)
150 return ((char *)NULL);
152 /* Move on to the specification. */
153 i++;
155 sign = 1;
156 substring_okay = 0;
158 #define RETURN_ENTRY(e, w) \
159 return ((e = history_get (w)) ? e->line : (char *)NULL)
161 /* Handle !! case. */
162 if (string[i] == history_expansion_char)
164 i++;
165 which = history_base + (history_length - 1);
166 *caller_index = i;
167 RETURN_ENTRY (entry, which);
170 /* Hack case of numeric line specification. */
171 if (string[i] == '-')
173 sign = -1;
174 i++;
177 if (_rl_digit_p (string[i]))
179 /* Get the extent of the digits and compute the value. */
180 for (which = 0; _rl_digit_p (string[i]); i++)
181 which = (which * 10) + _rl_digit_value (string[i]);
183 *caller_index = i;
185 if (sign < 0)
186 which = (history_length + history_base) - which;
188 RETURN_ENTRY (entry, which);
191 /* This must be something to search for. If the spec begins with
192 a '?', then the string may be anywhere on the line. Otherwise,
193 the string must be found at the start of a line. */
194 if (string[i] == '?')
196 substring_okay++;
197 i++;
200 /* Only a closing `?' or a newline delimit a substring search string. */
201 for (local_index = i; c = string[i]; i++)
202 if ((!substring_okay && (whitespace (c) || c == ':' ||
203 (history_search_delimiter_chars && member (c, history_search_delimiter_chars)) ||
204 string[i] == delimiting_quote)) ||
205 string[i] == '\n' ||
206 (substring_okay && string[i] == '?'))
207 break;
209 which = i - local_index;
210 temp = xmalloc (1 + which);
211 if (which)
212 strncpy (temp, string + local_index, which);
213 temp[which] = '\0';
215 if (substring_okay && string[i] == '?')
216 i++;
218 *caller_index = i;
220 #define FAIL_SEARCH() \
221 do { \
222 history_offset = history_length; free (temp) ; return (char *)NULL; \
223 } while (0)
225 /* If there is no search string, try to use the previous search string,
226 if one exists. If not, fail immediately. */
227 if (*temp == '\0' && substring_okay)
229 if (search_string)
231 free (temp);
232 temp = savestring (search_string);
234 else
235 FAIL_SEARCH ();
238 search_func = substring_okay ? history_search : history_search_prefix;
239 while (1)
241 local_index = (*search_func) (temp, -1);
243 if (local_index < 0)
244 FAIL_SEARCH ();
246 if (local_index == 0 || substring_okay)
248 entry = current_history ();
249 history_offset = history_length;
251 /* If this was a substring search, then remember the
252 string that we matched for word substitution. */
253 if (substring_okay)
255 FREE (search_string);
256 search_string = temp;
258 FREE (search_match);
259 search_match = history_find_word (entry->line, local_index);
261 else
262 free (temp);
264 return (entry->line);
267 if (history_offset)
268 history_offset--;
269 else
270 FAIL_SEARCH ();
272 #undef FAIL_SEARCH
273 #undef RETURN_ENTRY
276 /* Function for extracting single-quoted strings. Used for inhibiting
277 history expansion within single quotes. */
279 /* Extract the contents of STRING as if it is enclosed in single quotes.
280 SINDEX, when passed in, is the offset of the character immediately
281 following the opening single quote; on exit, SINDEX is left pointing
282 to the closing single quote. */
283 static void
284 hist_string_extract_single_quoted (string, sindex)
285 char *string;
286 int *sindex;
288 register int i;
290 for (i = *sindex; string[i] && string[i] != '\''; i++)
293 *sindex = i;
296 static char *
297 quote_breaks (s)
298 char *s;
300 register char *p, *r;
301 char *ret;
302 int len = 3;
304 for (p = s; p && *p; p++, len++)
306 if (*p == '\'')
307 len += 3;
308 else if (whitespace (*p) || *p == '\n')
309 len += 2;
312 r = ret = xmalloc (len);
313 *r++ = '\'';
314 for (p = s; p && *p; )
316 if (*p == '\'')
318 *r++ = '\'';
319 *r++ = '\\';
320 *r++ = '\'';
321 *r++ = '\'';
322 p++;
324 else if (whitespace (*p) || *p == '\n')
326 *r++ = '\'';
327 *r++ = *p++;
328 *r++ = '\'';
330 else
331 *r++ = *p++;
333 *r++ = '\'';
334 *r = '\0';
335 return ret;
338 static char *
339 hist_error(s, start, current, errtype)
340 char *s;
341 int start, current, errtype;
343 char *temp, *emsg;
344 int ll, elen;
346 ll = current - start;
348 switch (errtype)
350 case EVENT_NOT_FOUND:
351 emsg = "event not found";
352 elen = 15;
353 break;
354 case BAD_WORD_SPEC:
355 emsg = "bad word specifier";
356 elen = 18;
357 break;
358 case SUBST_FAILED:
359 emsg = "substitution failed";
360 elen = 19;
361 break;
362 case BAD_MODIFIER:
363 emsg = "unrecognized history modifier";
364 elen = 29;
365 break;
366 case NO_PREV_SUBST:
367 emsg = "no previous substitution";
368 elen = 24;
369 break;
370 default:
371 emsg = "unknown expansion error";
372 elen = 23;
373 break;
376 temp = xmalloc (ll + elen + 3);
377 strncpy (temp, s + start, ll);
378 temp[ll] = ':';
379 temp[ll + 1] = ' ';
380 strcpy (temp + ll + 2, emsg);
381 return (temp);
384 /* Get a history substitution string from STR starting at *IPTR
385 and return it. The length is returned in LENPTR.
387 A backslash can quote the delimiter. If the string is the
388 empty string, the previous pattern is used. If there is
389 no previous pattern for the lhs, the last history search
390 string is used.
392 If IS_RHS is 1, we ignore empty strings and set the pattern
393 to "" anyway. subst_lhs is not changed if the lhs is empty;
394 subst_rhs is allowed to be set to the empty string. */
396 static char *
397 get_subst_pattern (str, iptr, delimiter, is_rhs, lenptr)
398 char *str;
399 int *iptr, delimiter, is_rhs, *lenptr;
401 register int si, i, j, k;
402 char *s = (char *) NULL;
404 i = *iptr;
406 for (si = i; str[si] && str[si] != delimiter; si++)
407 if (str[si] == '\\' && str[si + 1] == delimiter)
408 si++;
410 if (si > i || is_rhs)
412 s = xmalloc (si - i + 1);
413 for (j = 0, k = i; k < si; j++, k++)
415 /* Remove a backslash quoting the search string delimiter. */
416 if (str[k] == '\\' && str[k + 1] == delimiter)
417 k++;
418 s[j] = str[k];
420 s[j] = '\0';
421 if (lenptr)
422 *lenptr = j;
425 i = si;
426 if (str[i])
427 i++;
428 *iptr = i;
430 return s;
433 static void
434 postproc_subst_rhs ()
436 char *new;
437 int i, j, new_size;
439 new = xmalloc (new_size = subst_rhs_len + subst_lhs_len);
440 for (i = j = 0; i < subst_rhs_len; i++)
442 if (subst_rhs[i] == '&')
444 if (j + subst_lhs_len >= new_size)
445 new = xrealloc (new, (new_size = new_size * 2 + subst_lhs_len));
446 strcpy (new + j, subst_lhs);
447 j += subst_lhs_len;
449 else
451 /* a single backslash protects the `&' from lhs interpolation */
452 if (subst_rhs[i] == '\\' && subst_rhs[i + 1] == '&')
453 i++;
454 if (j >= new_size)
455 new = xrealloc (new, new_size *= 2);
456 new[j++] = subst_rhs[i];
459 new[j] = '\0';
460 free (subst_rhs);
461 subst_rhs = new;
462 subst_rhs_len = j;
465 /* Expand the bulk of a history specifier starting at STRING[START].
466 Returns 0 if everything is OK, -1 if an error occurred, and 1
467 if the `p' modifier was supplied and the caller should just print
468 the returned string. Returns the new index into string in
469 *END_INDEX_PTR, and the expanded specifier in *RET_STRING. */
470 static int
471 history_expand_internal (string, start, end_index_ptr, ret_string, current_line)
472 char *string;
473 int start, *end_index_ptr;
474 char **ret_string;
475 char *current_line; /* for !# */
477 int i, n, starting_index;
478 int substitute_globally, want_quotes, print_only;
479 char *event, *temp, *result, *tstr, *t, c, *word_spec;
480 int result_len;
482 result = xmalloc (result_len = 128);
484 i = start;
486 /* If it is followed by something that starts a word specifier,
487 then !! is implied as the event specifier. */
489 if (member (string[i + 1], ":$*%^"))
491 char fake_s[3];
492 int fake_i = 0;
493 i++;
494 fake_s[0] = fake_s[1] = history_expansion_char;
495 fake_s[2] = '\0';
496 event = get_history_event (fake_s, &fake_i, 0);
498 else if (string[i + 1] == '#')
500 i += 2;
501 event = current_line;
503 else
505 int quoted_search_delimiter = 0;
507 /* If the character before this `!' is a double or single
508 quote, then this expansion takes place inside of the
509 quoted string. If we have to search for some text ("!foo"),
510 allow the delimiter to end the search string. */
511 if (i && (string[i - 1] == '\'' || string[i - 1] == '"'))
512 quoted_search_delimiter = string[i - 1];
513 event = get_history_event (string, &i, quoted_search_delimiter);
516 if (event == 0)
518 *ret_string = hist_error (string, start, i, EVENT_NOT_FOUND);
519 free (result);
520 return (-1);
523 /* If a word specifier is found, then do what that requires. */
524 starting_index = i;
525 word_spec = get_history_word_specifier (string, event, &i);
527 /* There is no such thing as a `malformed word specifier'. However,
528 it is possible for a specifier that has no match. In that case,
529 we complain. */
530 if (word_spec == (char *)&error_pointer)
532 *ret_string = hist_error (string, starting_index, i, BAD_WORD_SPEC);
533 free (result);
534 return (-1);
537 /* If no word specifier, than the thing of interest was the event. */
538 temp = word_spec ? savestring (word_spec) : savestring (event);
539 FREE (word_spec);
541 /* Perhaps there are other modifiers involved. Do what they say. */
542 want_quotes = substitute_globally = print_only = 0;
543 starting_index = i;
545 while (string[i] == ':')
547 c = string[i + 1];
549 if (c == 'g')
551 substitute_globally = 1;
552 i++;
553 c = string[i + 1];
556 switch (c)
558 default:
559 *ret_string = hist_error (string, i+1, i+2, BAD_MODIFIER);
560 free (result);
561 free (temp);
562 return -1;
564 case 'q':
565 want_quotes = 'q';
566 break;
568 case 'x':
569 want_quotes = 'x';
570 break;
572 /* :p means make this the last executed line. So we
573 return an error state after adding this line to the
574 history. */
575 case 'p':
576 print_only++;
577 break;
579 /* :t discards all but the last part of the pathname. */
580 case 't':
581 tstr = strrchr (temp, '/');
582 if (tstr)
584 tstr++;
585 t = savestring (tstr);
586 free (temp);
587 temp = t;
589 break;
591 /* :h discards the last part of a pathname. */
592 case 'h':
593 tstr = strrchr (temp, '/');
594 if (tstr)
595 *tstr = '\0';
596 break;
598 /* :r discards the suffix. */
599 case 'r':
600 tstr = strrchr (temp, '.');
601 if (tstr)
602 *tstr = '\0';
603 break;
605 /* :e discards everything but the suffix. */
606 case 'e':
607 tstr = strrchr (temp, '.');
608 if (tstr)
610 t = savestring (tstr);
611 free (temp);
612 temp = t;
614 break;
616 /* :s/this/that substitutes `that' for the first
617 occurrence of `this'. :gs/this/that substitutes `that'
618 for each occurrence of `this'. :& repeats the last
619 substitution. :g& repeats the last substitution
620 globally. */
622 case '&':
623 case 's':
625 char *new_event, *t;
626 int delimiter, failed, si, l_temp;
628 if (c == 's')
630 if (i + 2 < (int)strlen (string))
631 delimiter = string[i + 2];
632 else
633 break; /* no search delimiter */
635 i += 3;
637 t = get_subst_pattern (string, &i, delimiter, 0, &subst_lhs_len);
638 /* An empty substitution lhs with no previous substitution
639 uses the last search string as the lhs. */
640 if (t)
642 FREE (subst_lhs);
643 subst_lhs = t;
645 else if (!subst_lhs)
647 if (search_string && *search_string)
649 subst_lhs = savestring (search_string);
650 subst_lhs_len = strlen (subst_lhs);
652 else
654 subst_lhs = (char *) NULL;
655 subst_lhs_len = 0;
659 FREE (subst_rhs);
660 subst_rhs = get_subst_pattern (string, &i, delimiter, 1, &subst_rhs_len);
662 /* If `&' appears in the rhs, it's supposed to be replaced
663 with the lhs. */
664 if (member ('&', subst_rhs))
665 postproc_subst_rhs ();
667 else
668 i += 2;
670 /* If there is no lhs, the substitution can't succeed. */
671 if (subst_lhs_len == 0)
673 *ret_string = hist_error (string, starting_index, i, NO_PREV_SUBST);
674 free (result);
675 free (temp);
676 return -1;
679 l_temp = strlen (temp);
680 /* Ignore impossible cases. */
681 if (subst_lhs_len > l_temp)
683 *ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
684 free (result);
685 free (temp);
686 return (-1);
689 /* Find the first occurrence of THIS in TEMP. */
690 si = 0;
691 for (failed = 1; (si + subst_lhs_len) <= l_temp; si++)
692 if (STREQN (temp+si, subst_lhs, subst_lhs_len))
694 int len = subst_rhs_len - subst_lhs_len + l_temp;
695 new_event = xmalloc (1 + len);
696 strncpy (new_event, temp, si);
697 strncpy (new_event + si, subst_rhs, subst_rhs_len);
698 strncpy (new_event + si + subst_rhs_len,
699 temp + si + subst_lhs_len,
700 l_temp - (si + subst_lhs_len));
701 new_event[len] = '\0';
702 free (temp);
703 temp = new_event;
705 failed = 0;
707 if (substitute_globally)
709 si += subst_rhs_len;
710 l_temp = strlen (temp);
711 substitute_globally++;
712 continue;
714 else
715 break;
718 if (substitute_globally > 1)
720 substitute_globally = 0;
721 continue; /* don't want to increment i */
724 if (failed == 0)
725 continue; /* don't want to increment i */
727 *ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
728 free (result);
729 free (temp);
730 return (-1);
733 i += 2;
735 /* Done with modfiers. */
736 /* Believe it or not, we have to back the pointer up by one. */
737 --i;
739 if (want_quotes)
741 char *x;
743 if (want_quotes == 'q')
744 x = single_quote (temp);
745 else if (want_quotes == 'x')
746 x = quote_breaks (temp);
747 else
748 x = savestring (temp);
750 free (temp);
751 temp = x;
754 n = strlen (temp);
755 if (n >= result_len)
756 result = xrealloc (result, n + 2);
757 strcpy (result, temp);
758 free (temp);
760 *end_index_ptr = i;
761 *ret_string = result;
762 return (print_only);
765 /* Expand the string STRING, placing the result into OUTPUT, a pointer
766 to a string. Returns:
768 -1) If there was an error in expansion.
769 0) If no expansions took place (or, if the only change in
770 the text was the de-slashifying of the history expansion
771 character)
772 1) If expansions did take place
773 2) If the `p' modifier was given and the caller should print the result
775 If an error ocurred in expansion, then OUTPUT contains a descriptive
776 error message. */
778 #define ADD_STRING(s) \
779 do \
781 int sl = strlen (s); \
782 j += sl; \
783 if (j >= result_len) \
785 while (j >= result_len) \
786 result_len += 128; \
787 result = xrealloc (result, result_len); \
789 strcpy (result + j - sl, s); \
791 while (0)
793 #define ADD_CHAR(c) \
794 do \
796 if (j >= result_len - 1) \
797 result = xrealloc (result, result_len += 64); \
798 result[j++] = c; \
799 result[j] = '\0'; \
801 while (0)
804 history_expand (hstring, output)
805 char *hstring;
806 char **output;
808 register int j;
809 int i, r, l, passc, cc, modified, eindex, only_printing;
810 char *string;
812 /* The output string, and its length. */
813 int result_len;
814 char *result;
816 /* Used when adding the string. */
817 char *temp;
819 /* Setting the history expansion character to 0 inhibits all
820 history expansion. */
821 if (history_expansion_char == 0)
823 *output = savestring (hstring);
824 return (0);
827 /* Prepare the buffer for printing error messages. */
828 result = xmalloc (result_len = 256);
829 result[0] = '\0';
831 only_printing = modified = 0;
832 l = strlen (hstring);
834 /* Grovel the string. Only backslash and single quotes can quote the
835 history escape character. We also handle arg specifiers. */
837 /* Before we grovel forever, see if the history_expansion_char appears
838 anywhere within the text. */
840 /* The quick substitution character is a history expansion all right. That
841 is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact,
842 that is the substitution that we do. */
843 if (hstring[0] == history_subst_char)
845 string = xmalloc (l + 5);
847 string[0] = string[1] = history_expansion_char;
848 string[2] = ':';
849 string[3] = 's';
850 strcpy (string + 4, hstring);
851 l += 4;
853 else
855 string = hstring;
856 /* If not quick substitution, still maybe have to do expansion. */
858 /* `!' followed by one of the characters in history_no_expand_chars
859 is NOT an expansion. */
860 for (i = 0; string[i]; i++)
862 cc = string[i + 1];
863 /* The history_comment_char, if set, appearing that the beginning
864 of a word signifies that the rest of the line should not have
865 history expansion performed on it.
866 Skip the rest of the line and break out of the loop. */
867 if (history_comment_char && string[i] == history_comment_char &&
868 (i == 0 || member (string[i - 1], HISTORY_WORD_DELIMITERS)))
870 while (string[i])
871 i++;
872 break;
874 else if (string[i] == history_expansion_char)
876 if (!cc || member (cc, history_no_expand_chars))
877 continue;
878 /* If the calling application has set
879 history_inhibit_expansion_function to a function that checks
880 for special cases that should not be history expanded,
881 call the function and skip the expansion if it returns a
882 non-zero value. */
883 else if (history_inhibit_expansion_function &&
884 (*history_inhibit_expansion_function) (string, i))
885 continue;
886 else
887 break;
889 /* XXX - at some point, might want to extend this to handle
890 double quotes as well. */
891 else if (history_quotes_inhibit_expansion && string[i] == '\'')
893 /* If this is bash, single quotes inhibit history expansion. */
894 i++;
895 hist_string_extract_single_quoted (string, &i);
897 else if (history_quotes_inhibit_expansion && string[i] == '\\')
899 /* If this is bash, allow backslashes to quote single
900 quotes and the history expansion character. */
901 if (cc == '\'' || cc == history_expansion_char)
902 i++;
906 if (string[i] != history_expansion_char)
908 free (result);
909 *output = savestring (string);
910 return (0);
914 /* Extract and perform the substitution. */
915 for (passc = i = j = 0; i < l; i++)
917 int tchar = string[i];
919 if (passc)
921 passc = 0;
922 ADD_CHAR (tchar);
923 continue;
926 if (tchar == history_expansion_char)
927 tchar = -3;
928 else if (tchar == history_comment_char)
929 tchar = -2;
931 switch (tchar)
933 default:
934 ADD_CHAR (string[i]);
935 break;
937 case '\\':
938 passc++;
939 ADD_CHAR (tchar);
940 break;
942 case '\'':
944 /* If history_quotes_inhibit_expansion is set, single quotes
945 inhibit history expansion. */
946 if (history_quotes_inhibit_expansion)
948 int quote, slen;
950 quote = i++;
951 hist_string_extract_single_quoted (string, &i);
953 slen = i - quote + 2;
954 temp = xmalloc (slen);
955 strncpy (temp, string + quote, slen);
956 temp[slen - 1] = '\0';
957 ADD_STRING (temp);
958 free (temp);
960 else
961 ADD_CHAR (string[i]);
962 break;
965 case -2: /* history_comment_char */
966 if (i == 0 || member (string[i - 1], HISTORY_WORD_DELIMITERS))
968 temp = xmalloc (l - i + 1);
969 strcpy (temp, string + i);
970 ADD_STRING (temp);
971 free (temp);
972 i = l;
974 else
975 ADD_CHAR (string[i]);
976 break;
978 case -3: /* history_expansion_char */
979 cc = string[i + 1];
981 /* If the history_expansion_char is followed by one of the
982 characters in history_no_expand_chars, then it is not a
983 candidate for expansion of any kind. */
984 if (member (cc, history_no_expand_chars))
986 ADD_CHAR (string[i]);
987 break;
990 #if defined (NO_BANG_HASH_MODIFIERS)
991 /* There is something that is listed as a `word specifier' in csh
992 documentation which means `the expanded text to this point'.
993 That is not a word specifier, it is an event specifier. If we
994 don't want to allow modifiers with `!#', just stick the current
995 output line in again. */
996 if (cc == '#')
998 if (result)
1000 temp = xmalloc (1 + strlen (result));
1001 strcpy (temp, result);
1002 ADD_STRING (temp);
1003 free (temp);
1005 i++;
1006 break;
1008 #endif
1010 r = history_expand_internal (string, i, &eindex, &temp, result);
1011 if (r < 0)
1013 *output = temp;
1014 free (result);
1015 if (string != hstring)
1016 free (string);
1017 return -1;
1019 else
1021 if (temp)
1023 modified++;
1024 if (*temp)
1025 ADD_STRING (temp);
1026 free (temp);
1028 only_printing = r == 1;
1029 i = eindex;
1031 break;
1035 *output = result;
1036 if (string != hstring)
1037 free (string);
1039 if (only_printing)
1041 add_history (result);
1042 return (2);
1045 return (modified != 0);
1048 /* Return a consed string which is the word specified in SPEC, and found
1049 in FROM. NULL is returned if there is no spec. The address of
1050 ERROR_POINTER is returned if the word specified cannot be found.
1051 CALLER_INDEX is the offset in SPEC to start looking; it is updated
1052 to point to just after the last character parsed. */
1053 static char *
1054 get_history_word_specifier (spec, from, caller_index)
1055 char *spec, *from;
1056 int *caller_index;
1058 register int i = *caller_index;
1059 int first, last;
1060 int expecting_word_spec = 0;
1061 char *result;
1063 /* The range of words to return doesn't exist yet. */
1064 first = last = 0;
1065 result = (char *)NULL;
1067 /* If we found a colon, then this *must* be a word specification. If
1068 it isn't, then it is an error. */
1069 if (spec[i] == ':')
1071 i++;
1072 expecting_word_spec++;
1075 /* Handle special cases first. */
1077 /* `%' is the word last searched for. */
1078 if (spec[i] == '%')
1080 *caller_index = i + 1;
1081 return (search_match ? savestring (search_match) : savestring (""));
1084 /* `*' matches all of the arguments, but not the command. */
1085 if (spec[i] == '*')
1087 *caller_index = i + 1;
1088 result = history_arg_extract (1, '$', from);
1089 return (result ? result : savestring (""));
1092 /* `$' is last arg. */
1093 if (spec[i] == '$')
1095 *caller_index = i + 1;
1096 return (history_arg_extract ('$', '$', from));
1099 /* Try to get FIRST and LAST figured out. */
1101 if (spec[i] == '-')
1102 first = 0;
1103 else if (spec[i] == '^')
1104 first = 1;
1105 else if (_rl_digit_p (spec[i]) && expecting_word_spec)
1107 for (first = 0; _rl_digit_p (spec[i]); i++)
1108 first = (first * 10) + _rl_digit_value (spec[i]);
1110 else
1111 return ((char *)NULL); /* no valid `first' for word specifier */
1113 if (spec[i] == '^' || spec[i] == '*')
1115 last = (spec[i] == '^') ? 1 : '$'; /* x* abbreviates x-$ */
1116 i++;
1118 else if (spec[i] != '-')
1119 last = first;
1120 else
1122 i++;
1124 if (_rl_digit_p (spec[i]))
1126 for (last = 0; _rl_digit_p (spec[i]); i++)
1127 last = (last * 10) + _rl_digit_value (spec[i]);
1129 else if (spec[i] == '$')
1131 i++;
1132 last = '$';
1134 else if (!spec[i] || spec[i] == ':') /* could be modifier separator */
1135 last = -1; /* x- abbreviates x-$ omitting word `$' */
1138 *caller_index = i;
1140 if (last >= first || last == '$' || last < 0)
1141 result = history_arg_extract (first, last, from);
1143 return (result ? result : (char *)&error_pointer);
1146 /* Extract the args specified, starting at FIRST, and ending at LAST.
1147 The args are taken from STRING. If either FIRST or LAST is < 0,
1148 then make that arg count from the right (subtract from the number of
1149 tokens, so that FIRST = -1 means the next to last token on the line).
1150 If LAST is `$' the last arg from STRING is used. */
1151 char *
1152 history_arg_extract (first, last, string)
1153 int first, last;
1154 char *string;
1156 register int i, len;
1157 char *result;
1158 int size, offset;
1159 char **list;
1161 /* XXX - think about making history_tokenize return a struct array,
1162 each struct in array being a string and a length to avoid the
1163 calls to strlen below. */
1164 if ((list = history_tokenize (string)) == NULL)
1165 return ((char *)NULL);
1167 for (len = 0; list[len]; len++)
1170 if (last < 0)
1171 last = len + last - 1;
1173 if (first < 0)
1174 first = len + first - 1;
1176 if (last == '$')
1177 last = len - 1;
1179 if (first == '$')
1180 first = len - 1;
1182 last++;
1184 if (first >= len || last > len || first < 0 || last < 0 || first > last)
1185 result = ((char *)NULL);
1186 else
1188 for (size = 0, i = first; i < last; i++)
1189 size += strlen (list[i]) + 1;
1190 result = xmalloc (size + 1);
1191 result[0] = '\0';
1193 for (i = first, offset = 0; i < last; i++)
1195 strcpy (result + offset, list[i]);
1196 offset += strlen (list[i]);
1197 if (i + 1 < last)
1199 result[offset++] = ' ';
1200 result[offset] = 0;
1205 for (i = 0; i < len; i++)
1206 free (list[i]);
1207 free (list);
1209 return (result);
1212 #define slashify_in_quotes "\\`\"$"
1214 /* Parse STRING into tokens and return an array of strings. If WIND is
1215 not -1 and INDP is not null, we also want the word surrounding index
1216 WIND. The position in the returned array of strings is returned in
1217 *INDP. */
1218 static char **
1219 history_tokenize_internal (string, wind, indp)
1220 char *string;
1221 int wind, *indp;
1223 char **result;
1224 register int i, start, result_index, size;
1225 int len, delimiter;
1227 /* Get a token, and stuff it into RESULT. The tokens are split
1228 exactly where the shell would split them. */
1229 for (i = result_index = size = 0, result = (char **)NULL; string[i]; )
1231 delimiter = 0;
1233 /* Skip leading whitespace. */
1234 for (; string[i] && whitespace (string[i]); i++)
1236 if (string[i] == 0 || string[i] == history_comment_char)
1237 return (result);
1239 start = i;
1241 if (member (string[i], "()\n"))
1243 i++;
1244 goto got_token;
1247 if (member (string[i], "<>;&|$"))
1249 int peek = string[i + 1];
1251 if (peek == string[i] && peek != '$')
1253 if (peek == '<' && string[i + 2] == '-')
1254 i++;
1255 i += 2;
1256 goto got_token;
1258 else
1260 if ((peek == '&' && (string[i] == '>' || string[i] == '<')) ||
1261 ((peek == '>') && (string[i] == '&')) ||
1262 ((peek == '(') && (string[i] == '$')))
1264 i += 2;
1265 goto got_token;
1268 if (string[i] != '$')
1270 i++;
1271 goto got_token;
1275 /* Get word from string + i; */
1277 if (member (string[i], HISTORY_QUOTE_CHARACTERS))
1278 delimiter = string[i++];
1280 for (; string[i]; i++)
1282 if (string[i] == '\\' && string[i + 1] == '\n')
1284 i++;
1285 continue;
1288 if (string[i] == '\\' && delimiter != '\'' &&
1289 (delimiter != '"' || member (string[i], slashify_in_quotes)))
1291 i++;
1292 continue;
1295 if (delimiter && string[i] == delimiter)
1297 delimiter = 0;
1298 continue;
1301 if (!delimiter && (member (string[i], HISTORY_WORD_DELIMITERS)))
1302 break;
1304 if (!delimiter && member (string[i], HISTORY_QUOTE_CHARACTERS))
1305 delimiter = string[i];
1308 got_token:
1310 /* If we are looking for the word in which the character at a
1311 particular index falls, remember it. */
1312 if (indp && wind != -1 && wind >= start && wind < i)
1313 *indp = result_index;
1315 len = i - start;
1316 if (result_index + 2 >= size)
1317 result = (char **)xrealloc (result, ((size += 10) * sizeof (char *)));
1318 result[result_index] = xmalloc (1 + len);
1319 strncpy (result[result_index], string + start, len);
1320 result[result_index][len] = '\0';
1321 result[++result_index] = (char *)NULL;
1324 return (result);
1327 /* Return an array of tokens, much as the shell might. The tokens are
1328 parsed out of STRING. */
1329 char **
1330 history_tokenize (string)
1331 char *string;
1333 return (history_tokenize_internal (string, -1, (int *)NULL));
1336 /* Find and return the word which contains the character at index IND
1337 in the history line LINE. Used to save the word matched by the
1338 last history !?string? search. */
1339 static char *
1340 history_find_word (line, ind)
1341 char *line;
1342 int ind;
1344 char **words, *s;
1345 int i, wind;
1347 words = history_tokenize_internal (line, ind, &wind);
1348 if (wind == -1)
1349 return ((char *)NULL);
1350 s = words[wind];
1351 for (i = 0; i < wind; i++)
1352 free (words[i]);
1353 for (i = wind + 1; words[i]; i++)
1354 free (words[i]);
1355 free (words);
1356 return s;