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