~mysql/mysql-server/mysql-6.0

« back to all changes in this revision

Viewing changes to cmd-line-utils/libedit/readline.c

  • Committer: vva at r18
  • Date: 2003-01-18 16:28:48 UTC
  • mto: (1403.59.3)
  • mto: This revision was merged to the branch mainline in revision 1412.
  • Revision ID: sp1r-vva@eagle.mysql.r18.ru-20030118162848-51479
changes for readline/libedit configuration

Show diffs side-by-side

added added

removed removed

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