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