root/src/noitedit/readline.c

Revision e06b23eaa47ce975bd25ec9124c72ab282f7ae97, 38.6 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 6 years ago)

Get ssl working. libedit was writing directly instead of using the opset. Change API and fixup libedit to support events.

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