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