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