root/src/noitedit/readline.c

Revision 608338ce9708713439de95a89d46edab96cbc186, 39.1 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 4 years ago)

Safety is good, refs #284

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