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 2, or (at your option) 11 any later version. 12 13 The Library is distributed in the hope that it will be useful, but 14 WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 General Public License for more details. 17 18 The GNU General Public License is often shipped with GNU software, and 19 is generally kept in a file called COPYING or LICENSE. If you do not 20 have a copy of the license, write to the Free Software Foundation, 21 59 Temple Place, Suite 330, Boston, MA 02111 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 #include "rlshell.h" 54 #include "xmalloc.h" 55 56 #define HISTORY_WORD_DELIMITERS " \t\n;&()|<>" 57 #define HISTORY_QUOTE_CHARACTERS "\"'`" 58 59 static char error_pointer; 60 61 static char *subst_lhs; 62 static char *subst_rhs; 63 static int subst_lhs_len; 64 static int subst_rhs_len; 65 66 static char *get_history_word_specifier __P((char *, char *, int *)); 67 static char *history_find_word __P((char *, int)); 68 69 static char *quote_breaks __P((char *)); 70 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 = '!'; 75 76 /* The character that invokes word substitution if found at the start of 77 a line. This is usually `^'. */ 78 char history_subst_char = '^'; 79 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'; 85 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="; 89 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; 93 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; 97 98 /* **************************************************************** */ 99 /* */ 100 /* History Expansion */ 101 /* */ 102 /* **************************************************************** */ 103 104 /* Hairy history expansion on text, not tokens. This is of general 105 use, and thus belongs in this library. */ 106 107 /* The last string searched for by a !?string? search. */ 108 static char *search_string; 109 110 /* The last string matched by a !?string? search. */ 111 static char *search_match; 112 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; 128 { 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; 135 136 /* The event can be specified in a number of ways. 137 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 144 145 All values N are determined via HISTORY_BASE. */ 146 147 i = *caller_index; 148 149 if (string[i] != history_expansion_char) 150 return ((char *)NULL); 151 152 /* Move on to the specification. */ 153 i++; 154 155 sign = 1; 156 substring_okay = 0; 157 158 #define RETURN_ENTRY(e, w) \ 159 return ((e = history_get (w)) ? e->line : (char *)NULL) 160 161 /* Handle !! case. */ 162 if (string[i] == history_expansion_char) 163 { 164 i++; 165 which = history_base + (history_length - 1); 166 *caller_index = i; 167 RETURN_ENTRY (entry, which); 168 } 169 170 /* Hack case of numeric line specification. */ 171 if (string[i] == '-') 172 { 173 sign = -1; 174 i++; 175 } 176 177 if (_rl_digit_p (string[i])) 178 { 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]); 182 183 *caller_index = i; 184 185 if (sign < 0) 186 which = (history_length + history_base) - which; 187 188 RETURN_ENTRY (entry, which); 189 } 190 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] == '?') 195 { 196 substring_okay++; 197 i++; 198 } 199 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; 208 209 which = i - local_index; 210 temp = xmalloc (1 + which); 211 if (which) 212 strncpy (temp, string + local_index, which); 213 temp[which] = '\0'; 214 215 if (substring_okay && string[i] == '?') 216 i++; 217 218 *caller_index = i; 219 220 #define FAIL_SEARCH() \ 221 do { \ 222 history_offset = history_length; free (temp) ; return (char *)NULL; \ 223 } while (0) 224 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) 228 { 229 if (search_string) 230 { 231 free (temp); 232 temp = savestring (search_string); 233 } 234 else 235 FAIL_SEARCH (); 236 } 237 238 search_func = substring_okay ? history_search : history_search_prefix; 239 while (1) 240 { 241 local_index = (*search_func) (temp, -1); 242 243 if (local_index < 0) 244 FAIL_SEARCH (); 245 246 if (local_index == 0 || substring_okay) 247 { 248 entry = current_history (); 249 history_offset = history_length; 250 251 /* If this was a substring search, then remember the 252 string that we matched for word substitution. */ 253 if (substring_okay) 254 { 255 FREE (search_string); 256 search_string = temp; 257 258 FREE (search_match); 259 search_match = history_find_word (entry->line, local_index); 260 } 261 else 262 free (temp); 263 264 return (entry->line); 265 } 266 267 if (history_offset) 268 history_offset--; 269 else 270 FAIL_SEARCH (); 271 } 272 #undef FAIL_SEARCH 273 #undef RETURN_ENTRY 274 } 275 276 /* Function for extracting single-quoted strings. Used for inhibiting 277 history expansion within single quotes. */ 278 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; 287 { 288 register int i; 289 290 for (i = *sindex; string[i] && string[i] != '\''; i++) 291 ; 292 293 *sindex = i; 294 } 295 296 static char * 297 quote_breaks (s) 298 char *s; 299 { 300 register char *p, *r; 301 char *ret; 302 int len = 3; 303 304 for (p = s; p && *p; p++, len++) 305 { 306 if (*p == '\'') 307 len += 3; 308 else if (whitespace (*p) || *p == '\n') 309 len += 2; 310 } 311 312 r = ret = xmalloc (len); 313 *r++ = '\''; 314 for (p = s; p && *p; ) 315 { 316 if (*p == '\'') 317 { 318 *r++ = '\''; 319 *r++ = '\\'; 320 *r++ = '\''; 321 *r++ = '\''; 322 p++; 323 } 324 else if (whitespace (*p) || *p == '\n') 325 { 326 *r++ = '\''; 327 *r++ = *p++; 328 *r++ = '\''; 329 } 330 else 331 *r++ = *p++; 332 } 333 *r++ = '\''; 334 *r = '\0'; 335 return ret; 336 } 337 338 static char * 339 hist_error(s, start, current, errtype) 340 char *s; 341 int start, current, errtype; 342 { 343 char *temp, *emsg; 344 int ll, elen, len; 345 346 ll = current - start; 347 348 switch (errtype) 349 { 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; 374 } 375 376 len = ll + elen + 3; 377 temp = xmalloc (len); 378 strncpy (temp, s + start, ll); 379 strlcat (temp, ": ", len); 380 strlcat (temp, emsg, len); 381 return (temp); 382 } 383 384 /* Get a history substitution string from STR starting at *IPTR 385 and return it. The length is returned in LENPTR. 386 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. 391 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. */ 395 396 static char * 397 get_subst_pattern (str, iptr, delimiter, is_rhs, lenptr) 398 char *str; 399 int *iptr, delimiter, is_rhs, *lenptr; 400 { 401 register int si, i, j, k; 402 char *s = (char *) NULL; 403 404 i = *iptr; 405 406 for (si = i; str[si] && str[si] != delimiter; si++) 407 if (str[si] == '\\' && str[si + 1] == delimiter) 408 si++; 409 410 if (si > i || is_rhs) 411 { 412 s = xmalloc (si - i + 1); 413 for (j = 0, k = i; k < si; j++, k++) 414 { 415 /* Remove a backslash quoting the search string delimiter. */ 416 if (str[k] == '\\' && str[k + 1] == delimiter) 417 k++; 418 s[j] = str[k]; 419 } 420 s[j] = '\0'; 421 if (lenptr) 422 *lenptr = j; 423 } 424 425 i = si; 426 if (str[i]) 427 i++; 428 *iptr = i; 429 430 return s; 431 } 432 433 static void 434 postproc_subst_rhs () 435 { 436 char *new; 437 int i, j, new_size; 438 439 new = xmalloc (new_size = subst_rhs_len + subst_lhs_len); 440 for (i = j = 0; i < subst_rhs_len; i++) 441 { 442 if (subst_rhs[i] == '&') 443 { 444 if (j + subst_lhs_len >= new_size) 445 new = xrealloc (new, (new_size = new_size * 2 + subst_lhs_len)); 446 strlcpy (new + j, subst_lhs, new_size - j); 447 j += subst_lhs_len; 448 } 449 else 450 { 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]; 457 } 458 } 459 new[j] = '\0'; 460 free (subst_rhs); 461 subst_rhs = new; 462 subst_rhs_len = j; 463 } 464 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 !# */ 476 { 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; 481 482 result = xmalloc (result_len = 128); 483 484 i = start; 485 486 /* If it is followed by something that starts a word specifier, 487 then !! is implied as the event specifier. */ 488 489 if (member (string[i + 1], ":$*%^")) 490 { 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); 497 } 498 else if (string[i + 1] == '#') 499 { 500 i += 2; 501 event = current_line; 502 } 503 else 504 { 505 int quoted_search_delimiter = 0; 506 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); 514 } 515 516 if (event == 0) 517 { 518 *ret_string = hist_error (string, start, i, EVENT_NOT_FOUND); 519 free (result); 520 return (-1); 521 } 522 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); 526 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) 531 { 532 *ret_string = hist_error (string, starting_index, i, BAD_WORD_SPEC); 533 free (result); 534 return (-1); 535 } 536 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); 540 541 /* Perhaps there are other modifiers involved. Do what they say. */ 542 want_quotes = substitute_globally = print_only = 0; 543 starting_index = i; 544 545 while (string[i] == ':') 546 { 547 c = string[i + 1]; 548 549 if (c == 'g') 550 { 551 substitute_globally = 1; 552 i++; 553 c = string[i + 1]; 554 } 555 556 switch (c) 557 { 558 default: 559 *ret_string = hist_error (string, i+1, i+2, BAD_MODIFIER); 560 free (result); 561 free (temp); 562 return -1; 563 564 case 'q': 565 want_quotes = 'q'; 566 break; 567 568 case 'x': 569 want_quotes = 'x'; 570 break; 571 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; 578 579 /* :t discards all but the last part of the pathname. */ 580 case 't': 581 tstr = strrchr (temp, '/'); 582 if (tstr) 583 { 584 tstr++; 585 t = savestring (tstr); 586 free (temp); 587 temp = t; 588 } 589 break; 590 591 /* :h discards the last part of a pathname. */ 592 case 'h': 593 tstr = strrchr (temp, '/'); 594 if (tstr) 595 *tstr = '\0'; 596 break; 597 598 /* :r discards the suffix. */ 599 case 'r': 600 tstr = strrchr (temp, '.'); 601 if (tstr) 602 *tstr = '\0'; 603 break; 604 605 /* :e discards everything but the suffix. */ 606 case 'e': 607 tstr = strrchr (temp, '.'); 608 if (tstr) 609 { 610 t = savestring (tstr); 611 free (temp); 612 temp = t; 613 } 614 break; 615 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. */ 621 622 case '&': 623 case 's': 624 { 625 char *new_event, *t; 626 int delimiter, failed, si, l_temp; 627 628 if (c == 's') 629 { 630 if (i + 2 < (int)strlen (string)) 631 delimiter = string[i + 2]; 632 else 633 break; /* no search delimiter */ 634 635 i += 3; 636 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) 641 { 642 FREE (subst_lhs); 643 subst_lhs = t; 644 } 645 else if (!subst_lhs) 646 { 647 if (search_string && *search_string) 648 { 649 subst_lhs = savestring (search_string); 650 subst_lhs_len = strlen (subst_lhs); 651 } 652 else 653 { 654 subst_lhs = (char *) NULL; 655 subst_lhs_len = 0; 656 } 657 } 658 659 FREE (subst_rhs); 660 subst_rhs = get_subst_pattern (string, &i, delimiter, 1, &subst_rhs_len); 661 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 (); 666 } 667 else 668 i += 2; 669 670 /* If there is no lhs, the substitution can't succeed. */ 671 if (subst_lhs_len == 0) 672 { 673 *ret_string = hist_error (string, starting_index, i, NO_PREV_SUBST); 674 free (result); 675 free (temp); 676 return -1; 677 } 678 679 l_temp = strlen (temp); 680 /* Ignore impossible cases. */ 681 if (subst_lhs_len > l_temp) 682 { 683 *ret_string = hist_error (string, starting_index, i, SUBST_FAILED); 684 free (result); 685 free (temp); 686 return (-1); 687 } 688 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)) 693 { 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; 704 705 failed = 0; 706 707 if (substitute_globally) 708 { 709 si += subst_rhs_len; 710 l_temp = strlen (temp); 711 substitute_globally++; 712 continue; 713 } 714 else 715 break; 716 } 717 718 if (substitute_globally > 1) 719 { 720 substitute_globally = 0; 721 continue; /* don't want to increment i */ 722 } 723 724 if (failed == 0) 725 continue; /* don't want to increment i */ 726 727 *ret_string = hist_error (string, starting_index, i, SUBST_FAILED); 728 free (result); 729 free (temp); 730 return (-1); 731 } 732 } 733 i += 2; 734 } 735 /* Done with modfiers. */ 736 /* Believe it or not, we have to back the pointer up by one. */ 737 --i; 738 739 if (want_quotes) 740 { 741 char *x; 742 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); 749 750 free (temp); 751 temp = x; 752 } 753 754 n = strlen (temp); 755 if (n >= result_len) 756 result = xrealloc (result, n + 2); 757 strlcpy (result, temp, n + 2); 758 free (temp); 759 760 *end_index_ptr = i; 761 *ret_string = result; 762 return (print_only); 763 } 764 765 /* Expand the string STRING, placing the result into OUTPUT, a pointer 766 to a string. Returns: 767 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 774 775 If an error ocurred in expansion, then OUTPUT contains a descriptive 776 error message. */ 777 778 #define ADD_STRING(s) \ 779 do \ 780 { \ 781 int sl = strlen (s); \ 782 j += sl; \ 783 if (j >= result_len) \ 784 { \ 785 while (j >= result_len) \ 786 result_len += 128; \ 787 result = xrealloc (result, result_len); \ 788 } \ 789 strlcpy (result + j - sl, s, result_len - j + sl); \ 790 } \ 791 while (0) 792 793 #define ADD_CHAR(c) \ 794 do \ 795 { \ 796 if (j >= result_len - 1) \ 797 result = xrealloc (result, result_len += 64); \ 798 result[j++] = c; \ 799 result[j] = '\0'; \ 800 } \ 801 while (0) 802 803 int 804 history_expand (hstring, output) 805 char *hstring; 806 char **output; 807 { 808 register int j; 809 int i, r, l, passc, cc, modified, eindex, only_printing; 810 char *string; 811 812 /* The output string, and its length. */ 813 int result_len; 814 char *result; 815 816 /* Used when adding the string. */ 817 char *temp; 818 819 /* Setting the history expansion character to 0 inhibits all 820 history expansion. */ 821 if (history_expansion_char == 0) 822 { 823 *output = savestring (hstring); 824 return (0); 825 } 826 827 /* Prepare the buffer for printing error messages. */ 828 result = xmalloc (result_len = 256); 829 result[0] = '\0'; 830 831 only_printing = modified = 0; 832 l = strlen (hstring); 833 834 /* Grovel the string. Only backslash and single quotes can quote the 835 history escape character. We also handle arg specifiers. */ 836 837 /* Before we grovel forever, see if the history_expansion_char appears 838 anywhere within the text. */ 839 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) 844 { 845 string = xmalloc (l + 5); 846 847 string[0] = string[1] = history_expansion_char; 848 string[2] = ':'; 849 string[3] = 's'; 850 strlcpy (string + 4, hstring, l + 1); 851 l += 4; 852 } 853 else 854 { 855 string = hstring; 856 /* If not quick substitution, still maybe have to do expansion. */ 857 858 /* `!' followed by one of the characters in history_no_expand_chars 859 is NOT an expansion. */ 860 for (i = 0; string[i]; i++) 861 { 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))) 869 { 870 while (string[i]) 871 i++; 872 break; 873 } 874 else if (string[i] == history_expansion_char) 875 { 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; 888 } 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] == '\'') 892 { 893 /* If this is bash, single quotes inhibit history expansion. */ 894 i++; 895 hist_string_extract_single_quoted (string, &i); 896 } 897 else if (history_quotes_inhibit_expansion && string[i] == '\\') 898 { 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++; 903 } 904 } 905 906 if (string[i] != history_expansion_char) 907 { 908 free (result); 909 *output = savestring (string); 910 return (0); 911 } 912 } 913 914 /* Extract and perform the substitution. */ 915 for (passc = i = j = 0; i < l; i++) 916 { 917 int tchar = string[i]; 918 919 if (passc) 920 { 921 passc = 0; 922 ADD_CHAR (tchar); 923 continue; 924 } 925 926 if (tchar == history_expansion_char) 927 tchar = -3; 928 else if (tchar == history_comment_char) 929 tchar = -2; 930 931 switch (tchar) 932 { 933 default: 934 ADD_CHAR (string[i]); 935 break; 936 937 case '\\': 938 passc++; 939 ADD_CHAR (tchar); 940 break; 941 942 case '\'': 943 { 944 /* If history_quotes_inhibit_expansion is set, single quotes 945 inhibit history expansion. */ 946 if (history_quotes_inhibit_expansion) 947 { 948 int quote, slen; 949 950 quote = i++; 951 hist_string_extract_single_quoted (string, &i); 952 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); 959 } 960 else 961 ADD_CHAR (string[i]); 962 break; 963 } 964 965 case -2: /* history_comment_char */ 966 if (i == 0 || member (string[i - 1], HISTORY_WORD_DELIMITERS)) 967 { 968 temp = xmalloc (l - i + 1); 969 strlcpy (temp, string + i, l - i + 1); 970 ADD_STRING (temp); 971 free (temp); 972 i = l; 973 } 974 else 975 ADD_CHAR (string[i]); 976 break; 977 978 case -3: /* history_expansion_char */ 979 cc = string[i + 1]; 980 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)) 985 { 986 ADD_CHAR (string[i]); 987 break; 988 } 989 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 == '#') 997 { 998 if (result) 999 { 1000 temp = xmalloc (1 + strlen (result)); 1001 strlcpy (temp, result, 1 + strlen(result)); 1002 ADD_STRING (temp); 1003 free (temp); 1004 } 1005 i++; 1006 break; 1007 } 1008 #endif 1009 1010 r = history_expand_internal (string, i, &eindex, &temp, result); 1011 if (r < 0) 1012 { 1013 *output = temp; 1014 free (result); 1015 if (string != hstring) 1016 free (string); 1017 return -1; 1018 } 1019 else 1020 { 1021 if (temp) 1022 { 1023 modified++; 1024 if (*temp) 1025 ADD_STRING (temp); 1026 free (temp); 1027 } 1028 only_printing = r == 1; 1029 i = eindex; 1030 } 1031 break; 1032 } 1033 } 1034 1035 *output = result; 1036 if (string != hstring) 1037 free (string); 1038 1039 if (only_printing) 1040 { 1041 add_history (result); 1042 return (2); 1043 } 1044 1045 return (modified != 0); 1046 } 1047 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; 1057 { 1058 register int i = *caller_index; 1059 int first, last; 1060 int expecting_word_spec = 0; 1061 char *result; 1062 1063 /* The range of words to return doesn't exist yet. */ 1064 first = last = 0; 1065 result = (char *)NULL; 1066 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] == ':') 1070 { 1071 i++; 1072 expecting_word_spec++; 1073 } 1074 1075 /* Handle special cases first. */ 1076 1077 /* `%' is the word last searched for. */ 1078 if (spec[i] == '%') 1079 { 1080 *caller_index = i + 1; 1081 return (search_match ? savestring (search_match) : savestring ("")); 1082 } 1083 1084 /* `*' matches all of the arguments, but not the command. */ 1085 if (spec[i] == '*') 1086 { 1087 *caller_index = i + 1; 1088 result = history_arg_extract (1, '$', from); 1089 return (result ? result : savestring ("")); 1090 } 1091 1092 /* `$' is last arg. */ 1093 if (spec[i] == '$') 1094 { 1095 *caller_index = i + 1; 1096 return (history_arg_extract ('$', '$', from)); 1097 } 1098 1099 /* Try to get FIRST and LAST figured out. */ 1100 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) 1106 { 1107 for (first = 0; _rl_digit_p (spec[i]); i++) 1108 first = (first * 10) + _rl_digit_value (spec[i]); 1109 } 1110 else 1111 return ((char *)NULL); /* no valid `first' for word specifier */ 1112 1113 if (spec[i] == '^' || spec[i] == '*') 1114 { 1115 last = (spec[i] == '^') ? 1 : '$'; /* x* abbreviates x-$ */ 1116 i++; 1117 } 1118 else if (spec[i] != '-') 1119 last = first; 1120 else 1121 { 1122 i++; 1123 1124 if (_rl_digit_p (spec[i])) 1125 { 1126 for (last = 0; _rl_digit_p (spec[i]); i++) 1127 last = (last * 10) + _rl_digit_value (spec[i]); 1128 } 1129 else if (spec[i] == '$') 1130 { 1131 i++; 1132 last = '$'; 1133 } 1134 else if (!spec[i] || spec[i] == ':') /* could be modifier separator */ 1135 last = -1; /* x- abbreviates x-$ omitting word `$' */ 1136 } 1137 1138 *caller_index = i; 1139 1140 if (last >= first || last == '$' || last < 0) 1141 result = history_arg_extract (first, last, from); 1142 1143 return (result ? result : (char *)&error_pointer); 1144 } 1145 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; 1155 { 1156 register int i, len; 1157 char *result; 1158 int size, offset; 1159 char **list; 1160 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); 1166 1167 for (len = 0; list[len]; len++) 1168 ; 1169 1170 if (last < 0) 1171 last = len + last - 1; 1172 1173 if (first < 0) 1174 first = len + first - 1; 1175 1176 if (last == '$') 1177 last = len - 1; 1178 1179 if (first == '$') 1180 first = len - 1; 1181 1182 last++; 1183 1184 if (first >= len || last > len || first < 0 || last < 0 || first > last) 1185 result = ((char *)NULL); 1186 else 1187 { 1188 for (size = 0, i = first; i < last; i++) 1189 size += strlen (list[i]) + 1; 1190 result = xmalloc (size + 1); 1191 result[0] = '\0'; 1192 1193 for (i = first, offset = 0; i < last; i++) 1194 { 1195 strlcpy (result + offset, list[i], size + 1 - offset); 1196 offset += strlen (list[i]); 1197 if (i + 1 < last) 1198 { 1199 result[offset++] = ' '; 1200 result[offset] = 0; 1201 } 1202 } 1203 } 1204 1205 for (i = 0; i < len; i++) 1206 free (list[i]); 1207 free (list); 1208 1209 return (result); 1210 } 1211 1212 #define slashify_in_quotes "\\`\"$" 1213 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; 1222 { 1223 char **result; 1224 register int i, start, result_index, size; 1225 int len, delimiter; 1226 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]; ) 1230 { 1231 delimiter = 0; 1232 1233 /* Skip leading whitespace. */ 1234 for (; string[i] && whitespace (string[i]); i++) 1235 ; 1236 if (string[i] == 0 || string[i] == history_comment_char) 1237 return (result); 1238 1239 start = i; 1240 1241 if (member (string[i], "()\n")) 1242 { 1243 i++; 1244 goto got_token; 1245 } 1246 1247 if (member (string[i], "<>;&|$")) 1248 { 1249 int peek = string[i + 1]; 1250 1251 if (peek == string[i] && peek != '$') 1252 { 1253 if (peek == '<' && string[i + 2] == '-') 1254 i++; 1255 i += 2; 1256 goto got_token; 1257 } 1258 else 1259 { 1260 if ((peek == '&' && (string[i] == '>' || string[i] == '<')) || 1261 ((peek == '>') && (string[i] == '&')) || 1262 ((peek == '(') && (string[i] == '$'))) 1263 { 1264 i += 2; 1265 goto got_token; 1266 } 1267 } 1268 if (string[i] != '$') 1269 { 1270 i++; 1271 goto got_token; 1272 } 1273 } 1274 1275 /* Get word from string + i; */ 1276 1277 if (member (string[i], HISTORY_QUOTE_CHARACTERS)) 1278 delimiter = string[i++]; 1279 1280 for (; string[i]; i++) 1281 { 1282 if (string[i] == '\\' && string[i + 1] == '\n') 1283 { 1284 i++; 1285 continue; 1286 } 1287 1288 if (string[i] == '\\' && delimiter != '\'' && 1289 (delimiter != '"' || member (string[i], slashify_in_quotes))) 1290 { 1291 i++; 1292 continue; 1293 } 1294 1295 if (delimiter && string[i] == delimiter) 1296 { 1297 delimiter = 0; 1298 continue; 1299 } 1300 1301 if (!delimiter && (member (string[i], HISTORY_WORD_DELIMITERS))) 1302 break; 1303 1304 if (!delimiter && member (string[i], HISTORY_QUOTE_CHARACTERS)) 1305 delimiter = string[i]; 1306 } 1307 1308 got_token: 1309 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; 1314 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; 1322 } 1323 1324 return (result); 1325 } 1326 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; 1332 { 1333 return (history_tokenize_internal (string, -1, (int *)NULL)); 1334 } 1335 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; 1343 { 1344 char **words, *s; 1345 int i, wind; 1346 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; 1357 } 1358