1 /* $NetBSD: readline.c,v 1.12 2000/12/23 22:02:20 jdolecek Exp $ */ 2 3 /*- 4 * Copyright (c) 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jaromir Dolecek. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 #if !defined(lint) && !defined(SCCSID) 41 __RCSID("$NetBSD: readline.c,v 1.12 2000/12/23 22:02:20 jdolecek Exp $"); 42 #endif /* not lint && not SCCSID */ 43 44 #include <sys/types.h> 45 #include <sys/stat.h> 46 #include <stdio.h> 47 #include <dirent.h> 48 #include <string.h> 49 #include <pwd.h> 50 #include <ctype.h> 51 #include <stdlib.h> 52 #include <unistd.h> 53 #include <limits.h> 54 #include "histedit.h" 55 #include "readline.h" 56 #include "sys.h" 57 #include "el.h" 58 #include "fcns.h" /* for EL_NUM_FCNS */ 59 60 /* for rl_complete() */ 61 #define TAB '\r' 62 63 /* see comment at the #ifdef for sense of this */ 64 #define GDB_411_HACK 65 66 /* readline compatibility stuff - look at readline sources/documentation */ 67 /* to see what these variables mean */ 68 const char *rl_library_version = "EditLine wrapper"; 69 char *rl_readline_name = ""; 70 FILE *rl_instream = NULL; 71 FILE *rl_outstream = NULL; 72 int rl_point = 0; 73 int rl_end = 0; 74 char *rl_line_buffer = NULL; 75 76 int history_base = 1; /* probably never subject to change */ 77 int history_length = 0; 78 int max_input_history = 0; 79 char history_expansion_char = '!'; 80 char history_subst_char = '^'; 81 char *history_no_expand_chars = " \t\n=("; 82 Function *history_inhibit_expansion_function = NULL; 83 84 int rl_inhibit_completion = 0; 85 int rl_attempted_completion_over = 0; 86 char *rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{("; 87 char *rl_completer_word_break_characters = NULL; 88 char *rl_completer_quote_characters = NULL; 89 CPFunction *rl_completion_entry_function = NULL; 90 CPPFunction *rl_attempted_completion_function = NULL; 91 92 /* 93 * This is set to character indicating type of completion being done by 94 * rl_complete_internal(); this is available for application completion 95 * functions. 96 */ 97 int rl_completion_type = 0; 98 99 /* 100 * If more than this number of items results from query for possible 101 * completions, we ask user if they are sure to really display the list. 102 */ 103 int rl_completion_query_items = 100; 104 105 /* 106 * If not zero, non-unique completions always show list of possible matches. 107 */ 108 static int _rl_complete_show_all = 0; 109 110 /* used for readline emulation */ 111 static History *h = NULL; 112 static EditLine *e = NULL; 113 static int el_rl_complete_cmdnum = 0; 114 115 /* internal functions */ 116 static unsigned char _el_rl_complete(EditLine *, int); 117 static char *_get_prompt(EditLine *); 118 static HIST_ENTRY *_move_history(int); 119 static int _history_search_gen(const char *, int, int); 120 static int _history_expand_command(const char *, size_t, char **); 121 static char *_rl_compat_sub(const char *, const char *, 122 const char *, int); 123 static int rl_complete_internal(int); 124 static int _rl_qsort_string_compare(const void *, const void *); 125 126 /* 127 * needed for prompt switching in readline() 128 */ 129 static char *el_rl_prompt = NULL; 130 131 132 /* ARGSUSED */ 133 static char * 134 _get_prompt(EditLine *el) 135 { 136 return (el_rl_prompt); 137 } 138 139 140 /* 141 * generic function for moving around history 142 */ 143 static HIST_ENTRY * 144 _move_history(int op) 145 { 146 HistEvent ev; 147 static HIST_ENTRY rl_he; 148 149 if (history(h, &ev, op) != 0) 150 return (HIST_ENTRY *) NULL; 151 152 rl_he.line = ev.str; 153 rl_he.data = ""; 154 155 return (&rl_he); 156 } 157 158 159 /* 160 * READLINE compatibility stuff 161 */ 162 163 /* 164 * initialize rl compat stuff 165 */ 166 int 167 rl_initialize(void) 168 { 169 HistEvent ev; 170 const LineInfo *li; 171 int i; 172 173 if (e != NULL) 174 el_end(e); 175 if (h != NULL) 176 history_end(h); 177 178 if (!rl_instream) 179 rl_instream = stdin; 180 if (!rl_outstream) 181 rl_outstream = stdout; 182 e = el_init(rl_readline_name, rl_instream, rl_outstream, stderr); 183 184 h = history_init(); 185 if (!e || !h) 186 return (-1); 187 188 history(h, &ev, H_SETSIZE, INT_MAX); /* unlimited */ 189 history_length = 0; 190 max_input_history = INT_MAX; 191 el_set(e, EL_HIST, history, h); 192 193 /* for proper prompt printing in readline() */ 194 el_rl_prompt = strdup(""); 195 el_set(e, EL_PROMPT, _get_prompt); 196 el_set(e, EL_SIGNAL, 1); 197 198 /* set default mode to "emacs"-style and read setting afterwards */ 199 /* so this can be overriden */ 200 el_set(e, EL_EDITOR, "emacs"); 201 202 /* 203 * Word completition - this has to go AFTER rebinding keys 204 * to emacs-style. 205 */ 206 el_set(e, EL_ADDFN, "rl_complete", 207 "ReadLine compatible completition function", 208 _el_rl_complete); 209 el_set(e, EL_BIND, "^I", "rl_complete", NULL); 210 211 /* 212 * Find out where the rl_complete function was added; this is 213 * used later to detect that lastcmd was also rl_complete. 214 */ 215 for(i=EL_NUM_FCNS; i < e->el_map.nfunc; i++) { 216 if (e->el_map.func[i] == _el_rl_complete) { 217 el_rl_complete_cmdnum = i; 218 break; 219 } 220 } 221 222 /* read settings from configuration file */ 223 el_source(e, NULL); 224 225 /* 226 * Unfortunately, some applications really do use rl_point 227 * and rl_line_buffer directly. 228 */ 229 li = el_line(e); 230 /* LINTED const cast */ 231 rl_line_buffer = (char *) li->buffer; 232 rl_point = rl_end = 0; 233 234 return (0); 235 } 236 237 238 /* 239 * read one line from input stream and return it, chomping 240 * trailing newline (if there is any) 241 */ 242 char * 243 readline(const char *prompt) 244 { 245 HistEvent ev; 246 int count; 247 const char *ret; 248 249 if (e == NULL || h == NULL) 250 rl_initialize(); 251 252 /* update prompt accordingly to what has been passed */ 253 if (!prompt) 254 prompt = ""; 255 if (strcmp(el_rl_prompt, prompt) != 0) { 256 free(el_rl_prompt); 257 el_rl_prompt = strdup(prompt); 258 } 259 /* get one line from input stream */ 260 ret = el_gets(e, &count); 261 262 if (ret && count > 0) { 263 char *foo; 264 int lastidx; 265 266 foo = strdup(ret); 267 lastidx = count - 1; 268 if (foo[lastidx] == '\n') 269 foo[lastidx] = '\0'; 270 271 ret = foo; 272 } else 273 ret = NULL; 274 275 history(h, &ev, H_GETSIZE); 276 history_length = ev.num; 277 278 /* LINTED const cast */ 279 return (char *) ret; 280 } 281 282 /* 283 * history functions 284 */ 285 286 /* 287 * is normally called before application starts to use 288 * history expansion functions 289 */ 290 void 291 using_history(void) 292 { 293 if (h == NULL || e == NULL) 294 rl_initialize(); 295 } 296 297 298 /* 299 * substitute ``what'' with ``with'', returning resulting string; if 300 * globally == 1, substitutes all occurences of what, otherwise only the 301 * first one 302 */ 303 static char * 304 _rl_compat_sub(const char *str, const char *what, const char *with, 305 int globally) 306 { 307 char *result; 308 const char *temp, *new; 309 int len, with_len, what_len, add; 310 size_t size, i; 311 312 result = malloc((size = 16)); 313 temp = str; 314 with_len = strlen(with); 315 what_len = strlen(what); 316 len = 0; 317 do { 318 new = strstr(temp, what); 319 if (new) { 320 i = new - temp; 321 add = i + with_len; 322 if (i + add + 1 >= size) { 323 size += add + 1; 324 result = realloc(result, size); 325 } 326 (void) strncpy(&result[len], temp, i); 327 len += i; 328 (void) strcpy(&result[len], with); /* safe */ 329 len += with_len; 330 temp = new + what_len; 331 } else { 332 add = strlen(temp); 333 if (len + add + 1 >= size) { 334 size += add + 1; 335 result = realloc(result, size); 336 } 337 (void) strcpy(&result[len], temp); /* safe */ 338 len += add; 339 temp = NULL; 340 } 341 } while (temp && globally); 342 result[len] = '\0'; 343 344 return (result); 345 } 346 347 348 /* 349 * the real function doing history expansion - takes as argument command 350 * to do and data upon which the command should be executed 351 * does expansion the way I've understood readline documentation 352 * word designator ``%'' isn't supported (yet ?) 353 * 354 * returns 0 if data was not modified, 1 if it was and 2 if the string 355 * should be only printed and not executed; in case of error, 356 * returns -1 and *result points to NULL 357 * it's callers responsibility to free() string returned in *result 358 */ 359 static int 360 _history_expand_command(const char *command, size_t cmdlen, char **result) 361 { 362 char **arr, *tempcmd, *line, *search = NULL, *cmd; 363 const char *event_data = NULL; 364 static char *from = NULL, *to = NULL; 365 int start = -1, end = -1, max, i, idx; 366 int h_on = 0, t_on = 0, r_on = 0, e_on = 0, p_on = 0, g_on = 0; 367 int event_num = 0, retval; 368 size_t cmdsize; 369 370 *result = NULL; 371 372 cmd = alloca(cmdlen + 1); 373 (void) strncpy(cmd, command, cmdlen); 374 cmd[cmdlen] = 0; 375 376 idx = 1; 377 /* find out which event to take */ 378 if (cmd[idx] == history_expansion_char) { 379 event_num = history_length; 380 idx++; 381 } else { 382 int off, num; 383 size_t len; 384 off = idx; 385 while (cmd[off] && !strchr(":^$*-%", cmd[off])) 386 off++; 387 num = atoi(&cmd[idx]); 388 if (num != 0) { 389 event_num = num; 390 if (num < 0) 391 event_num += history_length + 1; 392 } else { 393 int prefix = 1, curr_num; 394 HistEvent ev; 395 396 len = off - idx; 397 if (cmd[idx] == '?') { 398 idx++, len--; 399 if (cmd[off - 1] == '?') 400 len--; 401 else if (cmd[off] != '\n' && cmd[off] != '\0') 402 return (-1); 403 prefix = 0; 404 } 405 search = alloca(len + 1); 406 (void) strncpy(search, &cmd[idx], len); 407 search[len] = '\0'; 408 409 if (history(h, &ev, H_CURR) != 0) 410 return (-1); 411 curr_num = ev.num; 412 413 if (prefix) 414 retval = history_search_prefix(search, -1); 415 else 416 retval = history_search(search, -1); 417 418 if (retval == -1) { 419 fprintf(rl_outstream, "%s: Event not found\n", 420 search); 421 return (-1); 422 } 423 if (history(h, &ev, H_CURR) != 0) 424 return (-1); 425 event_data = ev.str; 426 427 /* roll back to original position */ 428 history(h, &ev, H_NEXT_EVENT, curr_num); 429 } 430 idx = off; 431 } 432 433 if (!event_data && event_num >= 0) { 434 HIST_ENTRY *rl_he; 435 rl_he = history_get(event_num); 436 if (!rl_he) 437 return (0); 438 event_data = rl_he->line; 439 } else 440 return (-1); 441 442 if (cmd[idx] != ':') 443 return (-1); 444 cmd += idx + 1; 445 446 /* recognize cmd */ 447 if (*cmd == '^') 448 start = end = 1, cmd++; 449 else if (*cmd == '$') 450 start = end = -1, cmd++; 451 else if (*cmd == '*') 452 start = 1, end = -1, cmd++; 453 else if (isdigit((unsigned char) *cmd)) { 454 const char *temp; 455 int shifted = 0; 456 457 start = atoi(cmd); 458 temp = cmd; 459 for (; isdigit((unsigned char) *cmd); cmd++); 460 if (temp != cmd) 461 shifted = 1; 462 if (shifted && *cmd == '-') { 463 if (!isdigit((unsigned char) *(cmd + 1))) 464 end = -2; 465 else { 466 end = atoi(cmd + 1); 467 for (; isdigit((unsigned char) *cmd); cmd++); 468 } 469 } else if (shifted && *cmd == '*') 470 end = -1, cmd++; 471 else if (shifted) 472 end = start; 473 } 474 if (*cmd == ':') 475 cmd++; 476 477 line = strdup(event_data); 478 for (; *cmd; cmd++) { 479 if (*cmd == ':') 480 continue; 481 else if (*cmd == 'h') 482 h_on = 1 | g_on, g_on = 0; 483 else if (*cmd == 't') 484 t_on = 1 | g_on, g_on = 0; 485 else if (*cmd == 'r') 486 r_on = 1 | g_on, g_on = 0; 487 else if (*cmd == 'e') 488 e_on = 1 | g_on, g_on = 0; 489 else if (*cmd == 'p') 490 p_on = 1 | g_on, g_on = 0; 491 else if (*cmd == 'g') 492 g_on = 2; 493 else if (*cmd == 's' || *cmd == '&') { 494 char *what, *with, delim; 495 int len, from_len; 496 size_t size; 497 498 if (*cmd == '&' && (from == NULL || to == NULL)) 499 continue; 500 else if (*cmd == 's') { 501 delim = *(++cmd), cmd++; 502 size = 16; 503 what = realloc(from, size); 504 len = 0; 505 for (; *cmd && *cmd != delim; cmd++) { 506 if (*cmd == '\\' 507 && *(cmd + 1) == delim) 508 cmd++; 509 if (len >= size) 510 what = realloc(what, 511 (size <<= 1)); 512 what[len++] = *cmd; 513 } 514 what[len] = '\0'; 515 from = what; 516 if (*what == '\0') { 517 free(what); 518 if (search) 519 from = strdup(search); 520 else { 521 from = NULL; 522 return (-1); 523 } 524 } 525 cmd++; /* shift after delim */ 526 if (!*cmd) 527 continue; 528 529 size = 16; 530 with = realloc(to, size); 531 len = 0; 532 from_len = strlen(from); 533 for (; *cmd && *cmd != delim; cmd++) { 534 if (len + from_len + 1 >= size) { 535 size += from_len + 1; 536 with = realloc(with, size); 537 } 538 if (*cmd == '&') { 539 /* safe */ 540 (void) strcpy(&with[len], from); 541 len += from_len; 542 continue; 543 } 544 if (*cmd == '\\' 545 && (*(cmd + 1) == delim 546 || *(cmd + 1) == '&')) 547 cmd++; 548 with[len++] = *cmd; 549 } 550 with[len] = '\0'; 551 to = with; 552 553 tempcmd = _rl_compat_sub(line, from, to, 554 (g_on) ? 1 : 0); 555 free(line); 556 line = tempcmd; 557 g_on = 0; 558 } 559 } 560 } 561 562 arr = history_tokenize(line); 563 free(line); /* no more needed */ 564 if (arr && *arr == NULL) 565 free(arr), arr = NULL; 566 if (!arr) 567 return (-1); 568 569 /* find out max valid idx to array of array */ 570 max = 0; 571 for (i = 0; arr[i]; i++) 572 max++; 573 max--; 574 575 /* set boundaries to something relevant */ 576 if (start < 0) 577 start = 1; 578 if (end < 0) 579 end = max - ((end < -1) ? 1 : 0); 580 581 /* check boundaries ... */ 582 if (start > max || end > max || start > end) 583 return (-1); 584 585 for (i = 0; i <= max; i++) { 586 char *temp; 587 if (h_on && (i == 1 || h_on > 1) && 588 (temp = strrchr(arr[i], '/'))) 589 *(temp + 1) = '\0'; 590 if (t_on && (i == 1 || t_on > 1) && 591 (temp = strrchr(arr[i], '/'))) 592 (void) strcpy(arr[i], temp + 1); 593 if (r_on && (i == 1 || r_on > 1) && 594 (temp = strrchr(arr[i], '.'))) 595 *temp = '\0'; 596 if (e_on && (i == 1 || e_on > 1) && 597 (temp = strrchr(arr[i], '.'))) 598 (void) strcpy(arr[i], temp); 599 } 600 601 cmdsize = 1, cmdlen = 0; 602 tempcmd = malloc(cmdsize); 603 for (i = start; start <= i && i <= end; i++) { 604 int arr_len; 605 606 arr_len = strlen(arr[i]); 607 if (cmdlen + arr_len + 1 >= cmdsize) { 608 cmdsize += arr_len + 1; 609 tempcmd = realloc(tempcmd, cmdsize); 610 } 611 (void) strcpy(&tempcmd[cmdlen], arr[i]); /* safe */ 612 cmdlen += arr_len; 613 tempcmd[cmdlen++] = ' '; /* add a space */ 614 } 615 while (cmdlen > 0 && isspace((unsigned char) tempcmd[cmdlen - 1])) 616 cmdlen--; 617 tempcmd[cmdlen] = '\0'; 618 619 *result = tempcmd; 620 621 for (i = 0; i <= max; i++) 622 free(arr[i]); 623 free(arr), arr = (char **) NULL; 624 return (p_on) ? 2 : 1; 625 } 626 627 628 /* 629 * csh-style history expansion 630 */ 631 int 632 history_expand(char *str, char **output) 633 { 634 int i, retval = 0, idx; 635 size_t size; 636 char *temp, *result; 637 638 if (h == NULL || e == NULL) 639 rl_initialize(); 640 641 *output = strdup(str); /* do it early */ 642 643 if (str[0] == history_subst_char) { 644 /* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */ 645 temp = alloca(4 + strlen(str) + 1); 646 temp[0] = temp[1] = history_expansion_char; 647 temp[2] = ':'; 648 temp[3] = 's'; 649 (void) strcpy(temp + 4, str); 650 str = temp; 651 } 652 #define ADD_STRING(what, len) \ 653 { \ 654 if (idx + len + 1 > size) \ 655 result = realloc(result, (size += len + 1)); \ 656 (void)strncpy(&result[idx], what, len); \ 657 idx += len; \ 658 result[idx] = '\0'; \ 659 } 660 661 result = NULL; 662 size = idx = 0; 663 for (i = 0; str[i];) { 664 int start, j, loop_again; 665 size_t len; 666 667 loop_again = 1; 668 start = j = i; 669 loop: 670 for (; str[j]; j++) { 671 if (str[j] == '\\' && 672 str[j + 1] == history_expansion_char) { 673 (void) strcpy(&str[j], &str[j + 1]); 674 continue; 675 } 676 if (!loop_again) { 677 if (str[j] == '?') { 678 while (str[j] && str[++j] != '?'); 679 if (str[j] == '?') 680 j++; 681 } else if (isspace((unsigned char) str[j])) 682 break; 683 } 684 if (str[j] == history_expansion_char 685 && !strchr(history_no_expand_chars, str[j + 1]) 686 && (!history_inhibit_expansion_function || 687 (*history_inhibit_expansion_function)(str, j) == 0)) 688 break; 689 } 690 691 if (str[j] && str[j + 1] != '#' && loop_again) { 692 i = j; 693 j++; 694 if (str[j] == history_expansion_char) 695 j++; 696 loop_again = 0; 697 goto loop; 698 } 699 len = i - start; 700 temp = &str[start]; 701 ADD_STRING(temp, len); 702 703 if (str[i] == '\0' || str[i] != history_expansion_char 704 || str[i + 1] == '#') { 705 len = j - i; 706 temp = &str[i]; 707 ADD_STRING(temp, len); 708 if (start == 0) 709 retval = 0; 710 else 711 retval = 1; 712 break; 713 } 714 retval = _history_expand_command(&str[i], (size_t) (j - i), 715 &temp); 716 if (retval != -1) { 717 len = strlen(temp); 718 ADD_STRING(temp, len); 719 } 720 i = j; 721 } /* for(i ...) */ 722 723 if (retval == 2) { 724 add_history(temp); 725 #ifdef GDB_411_HACK 726 /* gdb 4.11 has been shipped with readline, where */ 727 /* history_expand() returned -1 when the line */ 728 /* should not be executed; in readline 2.1+ */ 729 /* it should return 2 in such a case */ 730 retval = -1; 731 #endif 732 } 733 free(*output); 734 *output = result; 735 736 return (retval); 737 } 738 739 740 /* 741 * Parse the string into individual tokens, similarily to how shell would do it. 742 */ 743 char ** 744 history_tokenize(const char *str) 745 { 746 int size = 1, result_idx = 0, i, start; 747 size_t len; 748 char **result = NULL, *temp, delim = '\0'; 749 750 for (i = 0; str[i]; i++) { 751 while (isspace((unsigned char) str[i])) 752 i++; 753 start = i; 754 for (; str[i]; i++) { 755 if (str[i] == '\\') { 756 if (str[i] != '\0') 757 i++; 758 } else if (str[i] == delim) 759 delim = '\0'; 760 else if (!delim && 761 (isspace((unsigned char) str[i]) || 762 strchr("()<>;&|$", str[i]))) 763 break; 764 else if (!delim && strchr("'`\"", str[i])) 765 delim = str[i]; 766 } 767 768 if (result_idx + 2 >= size) { 769 size <<= 1; 770 result = realloc(result, size * sizeof(char *)); 771 } 772 len = i - start; 773 temp = malloc(len + 1); 774 (void) strncpy(temp, &str[start], len); 775 temp[len] = '\0'; 776 result[result_idx++] = temp; 777 result[result_idx] = NULL; 778 } 779 780 return (result); 781 } 782 783 784 /* 785 * limit size of history record to ``max'' events 786 */ 787 void 788 stifle_history(int max) 789 { 790 HistEvent ev; 791 792 if (h == NULL || e == NULL) 793 rl_initialize(); 794 795 if (history(h, &ev, H_SETSIZE, max) == 0) 796 max_input_history = max; 797 } 798 799 800 /* 801 * "unlimit" size of history - set the limit to maximum allowed int value 802 */ 803 int 804 unstifle_history(void) 805 { 806 HistEvent ev; 807 int omax; 808 809 history(h, &ev, H_SETSIZE, INT_MAX); 810 omax = max_input_history; 811 max_input_history = INT_MAX; 812 return (omax); /* some value _must_ be returned */ 813 } 814 815 816 int 817 history_is_stifled(void) 818 { 819 820 /* cannot return true answer */ 821 return (max_input_history != INT_MAX); 822 } 823 824 825 /* 826 * read history from a file given 827 */ 828 int 829 read_history(const char *filename) 830 { 831 HistEvent ev; 832 833 if (h == NULL || e == NULL) 834 rl_initialize(); 835 return (history(h, &ev, H_LOAD, filename)); 836 } 837 838 839 /* 840 * write history to a file given 841 */ 842 int 843 write_history(const char *filename) 844 { 845 HistEvent ev; 846 847 if (h == NULL || e == NULL) 848 rl_initialize(); 849 return (history(h, &ev, H_SAVE, filename)); 850 } 851 852 853 /* 854 * returns history ``num''th event 855 * 856 * returned pointer points to static variable 857 */ 858 HIST_ENTRY * 859 history_get(int num) 860 { 861 static HIST_ENTRY she; 862 HistEvent ev; 863 int i = 1, curr_num; 864 865 if (h == NULL || e == NULL) 866 rl_initialize(); 867 868 /* rewind to beginning */ 869 if (history(h, &ev, H_CURR) != 0) 870 return (NULL); 871 curr_num = ev.num; 872 if (history(h, &ev, H_LAST) != 0) 873 return (NULL); /* error */ 874 while (i < num && history(h, &ev, H_PREV) == 0) 875 i++; 876 if (i != num) 877 return (NULL); /* not so many entries */ 878 879 she.line = ev.str; 880 she.data = NULL; 881 882 /* rewind history to the same event it was before */ 883 (void) history(h, &ev, H_FIRST); 884 (void) history(h, &ev, H_NEXT_EVENT, curr_num); 885 886 return (&she); 887 } 888 889 890 /* 891 * add the line to history table 892 */ 893 int 894 add_history(const char *line) 895 { 896 HistEvent ev; 897 898 if (h == NULL || e == NULL) 899 rl_initialize(); 900 901 (void) history(h, &ev, H_ENTER, line); 902 if (history(h, &ev, H_GETSIZE) == 0) 903 history_length = ev.num; 904 905 return (!(history_length > 0)); /* return 0 if all is okay */ 906 } 907 908 909 /* 910 * clear the history list - delete all entries 911 */ 912 void 913 clear_history(void) 914 { 915 HistEvent ev; 916 917 history(h, &ev, H_CLEAR); 918 } 919 920 921 /* 922 * returns offset of the current history event 923 */ 924 int 925 where_history(void) 926 { 927 HistEvent ev; 928 int curr_num, off; 929 930 if (history(h, &ev, H_CURR) != 0) 931 return (0); 932 curr_num = ev.num; 933 934 history(h, &ev, H_FIRST); 935 off = 1; 936 while (ev.num != curr_num && history(h, &ev, H_NEXT) == 0) 937 off++; 938 939 return (off); 940 } 941 942 943 /* 944 * returns current history event or NULL if there is no such event 945 */ 946 HIST_ENTRY * 947 current_history(void) 948 { 949 950 return (_move_history(H_CURR)); 951 } 952 953 954 /* 955 * returns total number of bytes history events' data are using 956 */ 957 int 958 history_total_bytes(void) 959 { 960 HistEvent ev; 961 int curr_num, size; 962 963 if (history(h, &ev, H_CURR) != 0) 964 return (-1); 965 curr_num = ev.num; 966 967 history(h, &ev, H_FIRST); 968 size = 0; 969 do 970 size += strlen(ev.str); 971 while (history(h, &ev, H_NEXT) == 0); 972 973 /* get to the same position as before */ 974 history(h, &ev, H_PREV_EVENT, curr_num); 975 976 return (size); 977 } 978 979 980 /* 981 * sets the position in the history list to ``pos'' 982 */ 983 int 984 history_set_pos(int pos) 985 { 986 HistEvent ev; 987 int off, curr_num; 988 989 if (pos > history_length || pos < 0) 990 return (-1); 991 992 history(h, &ev, H_CURR); 993 curr_num = ev.num; 994 history(h, &ev, H_FIRST); 995 off = 0; 996 while (off < pos && history(h, &ev, H_NEXT) == 0) 997 off++; 998 999 if (off != pos) { /* do a rollback in case of error */ 1000 history(h, &ev, H_FIRST); 1001 history(h, &ev, H_NEXT_EVENT, curr_num); 1002 return (-1); 1003 } 1004 return (0); 1005 } 1006 1007 1008 /* 1009 * returns previous event in history and shifts pointer accordingly 1010 */ 1011 HIST_ENTRY * 1012 previous_history(void) 1013 { 1014 1015 return (_move_history(H_PREV)); 1016 } 1017 1018 1019 /* 1020 * returns next event in history and shifts pointer accordingly 1021 */ 1022 HIST_ENTRY * 1023 next_history(void) 1024 { 1025 1026 return (_move_history(H_NEXT)); 1027 } 1028 1029 1030 /* 1031 * generic history search function 1032 */ 1033 static int 1034 _history_search_gen(const char *str, int direction, int pos) 1035 { 1036 HistEvent ev; 1037 const char *strp; 1038 int curr_num; 1039 1040 if (history(h, &ev, H_CURR) != 0) 1041 return (-1); 1042 curr_num = ev.num; 1043 1044 for (;;) { 1045 strp = strstr(ev.str, str); 1046 if (strp && (pos < 0 || &ev.str[pos] == strp)) 1047 return (int) (strp - ev.str); 1048 if (history(h, &ev, direction < 0 ? H_PREV : H_NEXT) != 0) 1049 break; 1050 } 1051 1052 history(h, &ev, direction < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); 1053 1054 return (-1); 1055 } 1056 1057 1058 /* 1059 * searches for first history event containing the str 1060 */ 1061 int 1062 history_search(const char *str, int direction) 1063 { 1064 1065 return (_history_search_gen(str, direction, -1)); 1066 } 1067 1068 1069 /* 1070 * searches for first history event beginning with str 1071 */ 1072 int 1073 history_search_prefix(const char *str, int direction) 1074 { 1075 1076 return (_history_search_gen(str, direction, 0)); 1077 } 1078 1079 1080 /* 1081 * search for event in history containing str, starting at offset 1082 * abs(pos); continue backward, if pos<0, forward otherwise 1083 */ 1084 /* ARGSUSED */ 1085 int 1086 history_search_pos(const char *str, int direction, int pos) 1087 { 1088 HistEvent ev; 1089 int curr_num, off; 1090 1091 off = (pos > 0) ? pos : -pos; 1092 pos = (pos > 0) ? 1 : -1; 1093 1094 if (history(h, &ev, H_CURR) != 0) 1095 return (-1); 1096 curr_num = ev.num; 1097 1098 if (history_set_pos(off) != 0 || history(h, &ev, H_CURR) != 0) 1099 return (-1); 1100 1101 1102 for (;;) { 1103 if (strstr(ev.str, str)) 1104 return (off); 1105 if (history(h, &ev, (pos < 0) ? H_PREV : H_NEXT) != 0) 1106 break; 1107 } 1108 1109 /* set "current" pointer back to previous state */ 1110 history(h, &ev, (pos < 0) ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); 1111 1112 return (-1); 1113 } 1114 1115 1116 /********************************/ 1117 /* completition functions */ 1118 1119 /* 1120 * does tilde expansion of strings of type ``~user/foo'' 1121 * if ``user'' isn't valid user name or ``txt'' doesn't start 1122 * w/ '~', returns pointer to strdup()ed copy of ``txt'' 1123 * 1124 * it's callers's responsibility to free() returned string 1125 */ 1126 char * 1127 tilde_expand(char *txt) 1128 { 1129 struct passwd *pass; 1130 char *temp; 1131 size_t len = 0; 1132 1133 if (txt[0] != '~') 1134 return (strdup(txt)); 1135 1136 temp = strchr(txt + 1, '/'); 1137 if (temp == NULL) 1138 temp = strdup(txt + 1); 1139 else { 1140 len = temp - txt + 1; /* text until string after slash */ 1141 temp = malloc(len); 1142 (void) strncpy(temp, txt + 1, len - 2); 1143 temp[len - 2] = '\0'; 1144 } 1145 pass = getpwnam(temp); 1146 free(temp); /* value no more needed */ 1147 if (pass == NULL) 1148 return (strdup(txt)); 1149 1150 /* update pointer txt to point at string immedially following */ 1151 /* first slash */ 1152 txt += len; 1153 1154 temp = malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1); 1155 (void) sprintf(temp, "%s/%s", pass->pw_dir, txt); 1156 1157 return (temp); 1158 } 1159 1160 1161 /* 1162 * return first found file name starting by the ``text'' or NULL if no 1163 * such file can be found 1164 * value of ``state'' is ignored 1165 * 1166 * it's caller's responsibility to free returned string 1167 */ 1168 char * 1169 filename_completion_function(const char *text, int state) 1170 { 1171 static DIR *dir = NULL; 1172 static char *filename = NULL, *dirname = NULL; 1173 static size_t filename_len = 0; 1174 struct dirent *entry; 1175 char *temp; 1176 size_t len; 1177 1178 if (state == 0 || dir == NULL) { 1179 if (dir != NULL) { 1180 closedir(dir); 1181 dir = NULL; 1182 } 1183 temp = strrchr(text, '/'); 1184 if (temp) { 1185 temp++; 1186 filename = realloc(filename, strlen(temp) + 1); 1187 (void) strcpy(filename, temp); 1188 len = temp - text; /* including last slash */ 1189 dirname = realloc(dirname, len + 1); 1190 (void) strncpy(dirname, text, len); 1191 dirname[len] = '\0'; 1192 } else { 1193 filename = strdup(text); 1194 dirname = NULL; 1195 } 1196 1197 /* support for ``~user'' syntax */ 1198 if (dirname && *dirname == '~') { 1199 temp = tilde_expand(dirname); 1200 dirname = realloc(dirname, strlen(temp) + 1); 1201 (void) strcpy(dirname, temp); /* safe */ 1202 free(temp); /* no longer needed */ 1203 } 1204 /* will be used in cycle */ 1205 filename_len = strlen(filename); 1206 if (filename_len == 0) 1207 return (NULL); /* no expansion possible */ 1208 1209 dir = opendir(dirname ? dirname : "."); 1210 if (!dir) 1211 return (NULL); /* cannot open the directory */ 1212 } 1213 /* find the match */ 1214 while ((entry = readdir(dir)) != NULL) { 1215 /* otherwise, get first entry where first */ 1216 /* filename_len characters are equal */ 1217 if (entry->d_name[0] == filename[0] 1218 #if defined(__SVR4) || defined(__linux__) 1219 && strlen(entry->d_name) >= filename_len 1220 #else 1221 && entry->d_namlen >= filename_len 1222 #endif 1223 && strncmp(entry->d_name, filename, 1224 filename_len) == 0) 1225 break; 1226 } 1227 1228 if (entry) { /* match found */ 1229 1230 struct stat stbuf; 1231 #if defined(__SVR4) || defined(__linux__) 1232 len = strlen(entry->d_name) + 1233 #else 1234 len = entry->d_namlen + 1235 #endif 1236 ((dirname) ? strlen(dirname) : 0) + 1 + 1; 1237 temp = malloc(len); 1238 (void) sprintf(temp, "%s%s", 1239 dirname ? dirname : "", entry->d_name); /* safe */ 1240 1241 /* test, if it's directory */ 1242 if (stat(temp, &stbuf) == 0 && S_ISDIR(stbuf.st_mode)) 1243 strcat(temp, "/"); /* safe */ 1244 } else 1245 temp = NULL; 1246 1247 return (temp); 1248 } 1249 1250 1251 /* 1252 * a completion generator for usernames; returns _first_ username 1253 * which starts with supplied text 1254 * text contains a partial username preceded by random character 1255 * (usually '~'); state is ignored 1256 * it's callers responsibility to free returned value 1257 */ 1258 char * 1259 username_completion_function(const char *text, int state) 1260 { 1261 struct passwd *pwd; 1262 1263 if (text[0] == '\0') 1264 return (NULL); 1265 1266 if (*text == '~') 1267 text++; 1268 1269 if (state == 0) 1270 setpwent(); 1271 1272 while ((pwd = getpwent()) && text[0] == pwd->pw_name[0] 1273 && strcmp(text, pwd->pw_name) == 0); 1274 1275 if (pwd == NULL) { 1276 endpwent(); 1277 return (NULL); 1278 } 1279 return (strdup(pwd->pw_name)); 1280 } 1281 1282 1283 /* 1284 * el-compatible wrapper around rl_complete; needed for key binding 1285 */ 1286 /* ARGSUSED */ 1287 static unsigned char 1288 _el_rl_complete(EditLine *el, int ch) 1289 { 1290 return (unsigned char) rl_complete(0, ch); 1291 } 1292 1293 1294 /* 1295 * returns list of completitions for text given 1296 */ 1297 char ** 1298 completion_matches(const char *text, CPFunction *genfunc) 1299 { 1300 char **match_list = NULL, *retstr, *prevstr; 1301 size_t match_list_len, max_equal, which, i; 1302 int matches; 1303 1304 if (h == NULL || e == NULL) 1305 rl_initialize(); 1306 1307 matches = 0; 1308 match_list_len = 1; 1309 while ((retstr = (*genfunc) (text, matches)) != NULL) { 1310 if (matches + 1 >= match_list_len) { 1311 match_list_len <<= 1; 1312 match_list = realloc(match_list, 1313 match_list_len * sizeof(char *)); 1314 } 1315 match_list[++matches] = retstr; 1316 } 1317 1318 if (!match_list) 1319 return (char **) NULL; /* nothing found */ 1320 1321 /* find least denominator and insert it to match_list[0] */ 1322 which = 2; 1323 prevstr = match_list[1]; 1324 max_equal = strlen(prevstr); 1325 for (; which <= matches; which++) { 1326 for (i = 0; i < max_equal && 1327 prevstr[i] == match_list[which][i]; i++) 1328 continue; 1329 max_equal = i; 1330 } 1331 1332 retstr = malloc(max_equal + 1); 1333 (void) strncpy(retstr, match_list[1], max_equal); 1334 retstr[max_equal] = '\0'; 1335 match_list[0] = retstr; 1336 1337 /* add NULL as last pointer to the array */ 1338 if (matches + 1 >= match_list_len) 1339 match_list = realloc(match_list, 1340 (match_list_len + 1) * sizeof(char *)); 1341 match_list[matches + 1] = (char *) NULL; 1342 1343 return (match_list); 1344 } 1345 1346 /* 1347 * Sort function for qsort(). Just wrapper around strcasecmp(). 1348 */ 1349 static int 1350 _rl_qsort_string_compare(i1, i2) 1351 const void *i1, *i2; 1352 { 1353 const char *s1 = ((const char **)i1)[0]; 1354 const char *s2 = ((const char **)i1)[0]; 1355 1356 return strcasecmp(s1, s2); 1357 } 1358 1359 /* 1360 * Display list of strings in columnar format on readline's output stream. 1361 * 'matches' is list of strings, 'len' is number of strings in 'matches', 1362 * 'max' is maximum length of string in 'matches'. 1363 */ 1364 void 1365 rl_display_match_list (matches, len, max) 1366 char **matches; 1367 int len, max; 1368 { 1369 int i, idx, limit, count; 1370 int screenwidth = e->el_term.t_size.h; 1371 1372 max += 2; /* space between entries */ 1373 1374 /* find out how many entries can be put on one line */ 1375 limit = screenwidth / max; 1376 if (limit == 0) 1377 limit = 1; 1378 1379 /* how many lines of output */ 1380 count = len / limit; 1381 1382 /* Sort the items if they are not already sorted. */ 1383 qsort(matches + 1, len, sizeof(char *), _rl_qsort_string_compare); 1384 1385 idx = 1; 1386 for(; count >= 0; count--) { 1387 for(i=0; i < limit && matches[idx]; i++, idx++) 1388 fprintf(e->el_outfile, "%s ", matches[idx]); 1389 fprintf(e->el_outfile, "\n"); 1390 } 1391 } 1392 1393 /* 1394 * Complete the word at or before point, called by rl_complete() 1395 * 'what_to_do' says what to do with the completion. 1396 * `?' means list the possible completions. 1397 * TAB means do standard completion. 1398 * `*' means insert all of the possible completions. 1399 * `!' means to do standard completion, and list all possible completions if 1400 * there is more than one. 1401 * 1402 * Note: '*' support is not implemented 1403 */ 1404 static int 1405 rl_complete_internal(int what_to_do) 1406 { 1407 CPFunction *complet_func; 1408 const LineInfo *li; 1409 char *temp, **matches; 1410 const char *ctemp; 1411 size_t len; 1412 1413 rl_completion_type = what_to_do; 1414 1415 if (h == NULL || e == NULL) 1416 rl_initialize(); 1417 1418 complet_func = rl_completion_entry_function; 1419 if (!complet_func) 1420 complet_func = filename_completion_function; 1421 1422 li = el_line(e); 1423 ctemp = (char *) li->cursor; 1424 while (ctemp > li->buffer && 1425 !strchr(rl_basic_word_break_characters, *(ctemp - 1))) 1426 ctemp--; 1427 1428 len = li->cursor - ctemp; 1429 temp = alloca(len + 1); 1430 (void) strncpy(temp, ctemp, len); 1431 temp[len] = '\0'; 1432 1433 /* these can be used by function called in completion_matches() */ 1434 /* or (*rl_attempted_completion_function)() */ 1435 rl_point = li->cursor - li->buffer; 1436 rl_end = li->lastchar - li->buffer; 1437 1438 if (!rl_attempted_completion_function) 1439 matches = completion_matches(temp, complet_func); 1440 else { 1441 int end = li->cursor - li->buffer; 1442 matches = (*rl_attempted_completion_function) (temp, (int) 1443 (end - len), end); 1444 } 1445 1446 if (matches) { 1447 int i, retval = CC_REFRESH; 1448 int matches_num, maxlen, match_len, match_display=1; 1449 1450 el_deletestr(e, (int) len); 1451 el_insertstr(e, matches[0]); 1452 1453 if (what_to_do == '?') 1454 goto display_matches; 1455 1456 if (matches[2] == NULL && strcmp(matches[0], matches[1]) == 0) { 1457 /* 1458 * We found exact match. Add a space after 1459 * it, unless we do filename completition and the 1460 * object is a directory. 1461 */ 1462 size_t alen = strlen(matches[0]); 1463 if (complet_func != filename_completion_function 1464 || (alen > 0 && (matches[0])[alen - 1] != '/')) 1465 el_insertstr(e, " "); 1466 } else if (what_to_do == '!') { 1467 display_matches: 1468 /* 1469 * More than one match and requested to list possible 1470 * matches. 1471 */ 1472 1473 for(i=1, maxlen=0; matches[i]; i++) { 1474 match_len = strlen(matches[i]); 1475 if (match_len > maxlen) 1476 maxlen = match_len; 1477 } 1478 matches_num = i - 1; 1479 1480 /* newline to get on next line from command line */ 1481 fprintf(e->el_outfile, "\n"); 1482 1483 /* 1484 * If there are too many items, ask user for display 1485 * confirmation. 1486 */ 1487 if (matches_num > rl_completion_query_items) { 1488 fprintf(e->el_outfile, 1489 "Display all %d possibilities? (y or n) ", 1490 matches_num); 1491 fflush(e->el_outfile); 1492 if (getc(stdin) != 'y') 1493 match_display = 0; 1494 fprintf(e->el_outfile, "\n"); 1495 } 1496 1497 if (match_display) 1498 rl_display_match_list(matches, matches_num, 1499 maxlen); 1500 retval = CC_REDISPLAY; 1501 } else { 1502 /* lcd is not a valid object - further specification */ 1503 /* is needed */ 1504 el_beep(e); 1505 retval = CC_NORM; 1506 } 1507 1508 /* free elements of array and the array itself */ 1509 for (i = 0; matches[i]; i++) 1510 free(matches[i]); 1511 free(matches), matches = NULL; 1512 1513 return (retval); 1514 } 1515 return (CC_NORM); 1516 } 1517 1518 1519 /* 1520 * complete word at current point 1521 */ 1522 int 1523 rl_complete(int ignore, int invoking_key) 1524 { 1525 if (h == NULL || e == NULL) 1526 rl_initialize(); 1527 1528 if (rl_inhibit_completion) { 1529 rl_insert(ignore, invoking_key); 1530 return (CC_REFRESH); 1531 } else if (e->el_state.lastcmd == el_rl_complete_cmdnum) 1532 return rl_complete_internal('?'); 1533 else if (_rl_complete_show_all) 1534 return rl_complete_internal('!'); 1535 else 1536 return (rl_complete_internal(TAB)); 1537 } 1538 1539 1540 /* 1541 * misc other functions 1542 */ 1543 1544 /* 1545 * bind key c to readline-type function func 1546 */ 1547 int 1548 rl_bind_key(int c, int func(int, int)) 1549 { 1550 int retval = -1; 1551 1552 if (h == NULL || e == NULL) 1553 rl_initialize(); 1554 1555 if (func == rl_insert) { 1556 /* XXX notice there is no range checking of ``c'' */ 1557 e->el_map.key[c] = ED_INSERT; 1558 retval = 0; 1559 } 1560 return (retval); 1561 } 1562 1563 1564 /* 1565 * read one key from input - handles chars pushed back 1566 * to input stream also 1567 */ 1568 int 1569 rl_read_key(void) 1570 { 1571 char fooarr[2 * sizeof(int)]; 1572 1573 if (e == NULL || h == NULL) 1574 rl_initialize(); 1575 1576 return (el_getc(e, fooarr)); 1577 } 1578 1579 1580 /* 1581 * reset the terminal 1582 */ 1583 /* ARGSUSED */ 1584 void 1585 rl_reset_terminal(const char *p) 1586 { 1587 1588 if (h == NULL || e == NULL) 1589 rl_initialize(); 1590 el_reset(e); 1591 } 1592 1593 1594 /* 1595 * insert character ``c'' back into input stream, ``count'' times 1596 */ 1597 int 1598 rl_insert(int count, int c) 1599 { 1600 char arr[2]; 1601 1602 if (h == NULL || e == NULL) 1603 rl_initialize(); 1604 1605 /* XXX - int -> char conversion can lose on multichars */ 1606 arr[0] = c; 1607 arr[1] = '\0'; 1608 1609 for (; count > 0; count--) 1610 el_push(e, arr); 1611 1612 return (0); 1613 } 1614