root/src/noitedit/readline.c

Revision 11d2dcb8820fdb77c35384ce926e2b7014559bb0, 38.4 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 7 years ago)

replace FILEs with file descriptors

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