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