~ubuntu-branches/ubuntu/utopic/gridengine/utopic

« back to all changes in this revision

Viewing changes to source/3rdparty/qtcsh/sh.file.c

  • Committer: Bazaar Package Importer
  • Author(s): Mark Hymers
  • Date: 2008-06-25 22:36:13 UTC
  • Revision ID: james.westby@ubuntu.com-20080625223613-tvd9xlhuoct9kyhm
Tags: upstream-6.2~beta2
ImportĀ upstreamĀ versionĀ 6.2~beta2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * sh.file.c: File completion for csh. This file is not used in tcsh.
 
3
 */
 
4
/*-
 
5
 * Copyright (c) 1980, 1991 The Regents of the University of California.
 
6
 * All rights reserved.
 
7
 *
 
8
 * Redistribution and use in source and binary forms, with or without
 
9
 * modification, are permitted provided that the following conditions
 
10
 * are met:
 
11
 * 1. Redistributions of source code must retain the above copyright
 
12
 *    notice, this list of conditions and the following disclaimer.
 
13
 * 2. Redistributions in binary form must reproduce the above copyright
 
14
 *    notice, this list of conditions and the following disclaimer in the
 
15
 *    documentation and/or other materials provided with the distribution.
 
16
 * 3. All advertising materials mentioning features or use of this software
 
17
 *    must display the following acknowledgement:
 
18
 *      This product includes software developed by the University of
 
19
 *      California, Berkeley and its contributors.
 
20
 * 4. Neither the name of the University nor the names of its contributors
 
21
 *    may be used to endorse or promote products derived from this software
 
22
 *    without specific prior written permission.
 
23
 *
 
24
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 
25
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
26
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
27
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 
28
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
29
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
30
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
31
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
32
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
33
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
34
 * SUCH DAMAGE.
 
35
 */
 
36
#include "sh.h"
 
37
 
 
38
RCSID("$Id$")
 
39
 
 
40
#ifdef FILEC
 
41
 
 
42
/*
 
43
 * Tenex style file name recognition, .. and more.
 
44
 * History:
 
45
 *      Author: Ken Greer, Sept. 1975, CMU.
 
46
 *      Finally got around to adding to the Cshell., Ken Greer, Dec. 1981.
 
47
 */
 
48
 
 
49
#define ON      1
 
50
#define OFF     0
 
51
#ifndef TRUE
 
52
#define TRUE 1
 
53
#endif
 
54
#ifndef FALSE
 
55
#define FALSE 0
 
56
#endif
 
57
 
 
58
#define ESC     CTL_ESC('\033')
 
59
 
 
60
typedef enum {
 
61
    LIST, RECOGNIZE
 
62
}       COMMAND;
 
63
 
 
64
static  void     setup_tty              __P((int));
 
65
static  void     back_to_col_1          __P((void));
 
66
static  void     pushback               __P((Char *));
 
67
static  void     catn                   __P((Char *, Char *, int));
 
68
static  void     copyn                  __P((Char *, Char *, int));
 
69
static  Char     filetype               __P((Char *, Char *));
 
70
static  void     print_by_column        __P((Char *, Char *[], int));
 
71
static  Char    *tilde                  __P((Char *, Char *));
 
72
static  void     retype                 __P((void));
 
73
static  void     beep                   __P((void));
 
74
static  void     print_recognized_stuff __P((Char *));
 
75
static  void     extract_dir_and_name   __P((Char *, Char *, Char *));
 
76
static  Char    *getitem                __P((DIR *, int));
 
77
static  void     free_items             __P((Char **));
 
78
static  int      tsearch                __P((Char *, COMMAND, int));
 
79
static  int      recognize              __P((Char *, Char *, int, int));
 
80
static  int      is_prefix              __P((Char *, Char *));
 
81
static  int      is_suffix              __P((Char *, Char *));
 
82
static  int      ignored                __P((Char *));
 
83
 
 
84
 
 
85
/*
 
86
 * Put this here so the binary can be patched with adb to enable file
 
87
 * completion by default.  Filec controls completion, nobeep controls
 
88
 * ringing the terminal bell on incomplete expansions.
 
89
 */
 
90
bool    filec = 0;
 
91
 
 
92
static void
 
93
setup_tty(on)
 
94
    int     on;
 
95
{
 
96
#ifdef TERMIO
 
97
# ifdef POSIX
 
98
    struct termios tchars;
 
99
# else
 
100
    struct termio tchars;
 
101
# endif /* POSIX */
 
102
 
 
103
# ifdef POSIX
 
104
    (void) tcgetattr(SHIN, &tchars);
 
105
# else
 
106
    (void) ioctl(SHIN, TCGETA, (ioctl_t) &tchars);
 
107
# endif /* POSIX */
 
108
    if (on) {
 
109
        tchars.c_cc[VEOL] = ESC;
 
110
        if (tchars.c_lflag & ICANON)
 
111
# ifdef POSIX
 
112
            on = TCSADRAIN;
 
113
# else
 
114
            on = TCSETA;
 
115
# endif /* POSIX */
 
116
        else {
 
117
# ifdef POSIX
 
118
            on = TCSAFLUSH;
 
119
# else
 
120
            on = TCSETAF;
 
121
# endif /* POSIX */
 
122
            tchars.c_lflag |= ICANON;
 
123
    
 
124
        }
 
125
    }
 
126
    else {
 
127
        tchars.c_cc[VEOL] = _POSIX_VDISABLE;
 
128
# ifdef POSIX
 
129
        on = TCSADRAIN;
 
130
# else
 
131
        on = TCSETA;
 
132
# endif /* POSIX */
 
133
    }
 
134
# ifdef POSIX
 
135
    (void) tcsetattr(SHIN, on, &tchars);
 
136
# else
 
137
    (void) ioctl(SHIN, on, (ioctl_t) &tchars);
 
138
# endif /* POSIX */
 
139
#else
 
140
    struct sgttyb sgtty;
 
141
    static struct tchars tchars;/* INT, QUIT, XON, XOFF, EOF, BRK */
 
142
 
 
143
    if (on) {
 
144
        (void) ioctl(SHIN, TIOCGETC, (ioctl_t) & tchars);
 
145
        tchars.t_brkc = ESC;
 
146
        (void) ioctl(SHIN, TIOCSETC, (ioctl_t) & tchars);
 
147
        /*
 
148
         * This must be done after every command: if the tty gets into raw or
 
149
         * cbreak mode the user can't even type 'reset'.
 
150
         */
 
151
        (void) ioctl(SHIN, TIOCGETP, (ioctl_t) & sgtty);
 
152
        if (sgtty.sg_flags & (RAW | CBREAK)) {
 
153
            sgtty.sg_flags &= ~(RAW | CBREAK);
 
154
            (void) ioctl(SHIN, TIOCSETP, (ioctl_t) & sgtty);
 
155
        }
 
156
    }
 
157
    else {
 
158
        tchars.t_brkc = -1;
 
159
        (void) ioctl(SHIN, TIOCSETC, (ioctl_t) & tchars);
 
160
    }
 
161
#endif /* TERMIO */
 
162
}
 
163
 
 
164
/*
 
165
 * Move back to beginning of current line
 
166
 */
 
167
static void
 
168
back_to_col_1()
 
169
{
 
170
#ifdef TERMIO
 
171
# ifdef POSIX
 
172
    struct termios tty, tty_normal;
 
173
# else
 
174
    struct termio tty, tty_normal;
 
175
# endif /* POSIX */
 
176
#else
 
177
    struct sgttyb tty, tty_normal;
 
178
#endif /* TERMIO */
 
179
 
 
180
# ifdef BSDSIGS
 
181
    sigmask_t omask = sigblock(sigmask(SIGINT));
 
182
# else
 
183
    (void) sighold(SIGINT);
 
184
# endif /* BSDSIGS */
 
185
 
 
186
#ifdef TERMIO
 
187
# ifdef POSIX
 
188
    (void) tcgetattr(SHOUT, &tty);
 
189
# else
 
190
    (void) ioctl(SHOUT, TCGETA, (ioctl_t) &tty_normal);
 
191
# endif /* POSIX */
 
192
    tty_normal = tty;
 
193
    tty.c_iflag &= ~INLCR;
 
194
    tty.c_oflag &= ~ONLCR;
 
195
# ifdef POSIX
 
196
    (void) tcsetattr(SHOUT, TCSANOW, &tty);
 
197
# else
 
198
    (void) ioctl(SHOUT, TCSETAW, (ioctl_t) &tty);
 
199
# endif /* POSIX */
 
200
    (void) write(SHOUT, "\r", 1);
 
201
# ifdef POSIX
 
202
    (void) tcsetattr(SHOUT, TCSANOW, &tty_normal);
 
203
# else
 
204
    (void) ioctl(SHOUT, TCSETAW, (ioctl_t) &tty_normal);
 
205
# endif /* POSIX */
 
206
#else
 
207
    (void) ioctl(SHIN, TIOCGETP, (ioctl_t) & tty);
 
208
    tty_normal = tty;
 
209
    tty.sg_flags &= ~CRMOD;
 
210
    (void) ioctl(SHIN, TIOCSETN, (ioctl_t) & tty);
 
211
    (void) write(SHOUT, "\r", 1);
 
212
    (void) ioctl(SHIN, TIOCSETN, (ioctl_t) & tty_normal);
 
213
#endif /* TERMIO */
 
214
 
 
215
# ifdef BSDSIGS
 
216
    (void) sigsetmask(omask);
 
217
# else
 
218
    (void) sigrelse(SIGINT);
 
219
# endif /* BSDISGS */
 
220
}
 
221
 
 
222
/*
 
223
 * Push string contents back into tty queue
 
224
 */
 
225
static void
 
226
pushback(string)
 
227
    Char   *string;
 
228
{
 
229
    register Char *p;
 
230
    char    c;
 
231
#ifdef TERMIO
 
232
# ifdef POSIX
 
233
    struct termios tty, tty_normal;
 
234
# else
 
235
    struct termio tty, tty_normal;
 
236
# endif /* POSIX */
 
237
#else
 
238
    struct sgttyb tty, tty_normal;
 
239
#endif /* TERMIO */
 
240
 
 
241
#ifdef BSDSIGS
 
242
    sigmask_t omask = sigblock(sigmask(SIGINT));
 
243
#else
 
244
    (void) sighold(SIGINT);
 
245
#endif /* BSDSIGS */
 
246
 
 
247
#ifdef TERMIO
 
248
# ifdef POSIX
 
249
    (void) tcgetattr(SHOUT, &tty);
 
250
# else
 
251
    (void) ioctl(SHOUT, TCSETAW, (ioctl_t) &tty);
 
252
# endif /* POSIX */
 
253
    tty_normal = tty;
 
254
#ifdef INTERIX
 
255
    tty.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ECHOCTL);
 
256
#else
 
257
    tty.c_lflag &= ~(ECHOKE | ECHO | ECHOE | ECHOK | ECHONL | ECHOPRT | ECHOCTL);
 
258
#endif
 
259
# ifdef POSIX
 
260
    (void) tcsetattr(SHOUT, TCSANOW, &tty);
 
261
# else
 
262
    (void) ioctl(SHOUT, TCSETAW, (ioctl_t) &tty);
 
263
# endif /* POSIX */
 
264
 
 
265
    for (p = string; c = *p; p++)
 
266
        (void) ioctl(SHOUT, TIOCSTI, (ioctl_t) & c);
 
267
# ifdef POSIX
 
268
    (void) tcsetattr(SHOUT, TCSANOW, &tty_normal);
 
269
# else
 
270
    (void) ioctl(SHOUT, TCSETAW, (ioctl_t) &tty_normal);
 
271
# endif /* POSIX */
 
272
    (void) sigsetmask(omask);
 
273
#else
 
274
    (void) ioctl(SHOUT, TIOCGETP, (ioctl_t) & tty);
 
275
    tty_normal = tty;
 
276
    tty.sg_flags &= ~ECHO;
 
277
    (void) ioctl(SHOUT, TIOCSETN, (ioctl_t) & tty);
 
278
 
 
279
    for (p = string; c = *p; p++)
 
280
        (void) ioctl(SHOUT, TIOCSTI, (ioctl_t) & c);
 
281
    (void) ioctl(SHOUT, TIOCSETN, (ioctl_t) & tty_normal);
 
282
#endif /* TERMIO */
 
283
 
 
284
# ifdef BSDSIGS
 
285
    (void) sigsetmask(omask);
 
286
# else
 
287
    (void) sigrelse(SIGINT);
 
288
# endif /* BSDISGS */
 
289
}
 
290
 
 
291
/*
 
292
 * Concatenate src onto tail of des.
 
293
 * Des is a string whose maximum length is count.
 
294
 * Always null terminate.
 
295
 */
 
296
static void
 
297
catn(des, src, count)
 
298
    register Char *des, *src;
 
299
    register count;
 
300
{
 
301
    while (--count >= 0 && *des)
 
302
        des++;
 
303
    while (--count >= 0)
 
304
        if ((*des++ = *src++) == 0)
 
305
            return;
 
306
    *des = '\0';
 
307
}
 
308
 
 
309
/*
 
310
 * Like strncpy but always leave room for trailing \0
 
311
 * and always null terminate.
 
312
 */
 
313
static void
 
314
copyn(des, src, count)
 
315
    register Char *des, *src;
 
316
    register count;
 
317
{
 
318
    while (--count >= 0)
 
319
        if ((*des++ = *src++) == 0)
 
320
            return;
 
321
    *des = '\0';
 
322
}
 
323
 
 
324
static  Char
 
325
filetype(dir, file)
 
326
    Char   *dir, *file;
 
327
{
 
328
    Char    path[MAXPATHLEN];
 
329
    struct stat statb;
 
330
 
 
331
    catn(Strcpy(path, dir), file, sizeof(path) / sizeof(Char));
 
332
    if (lstat(short2str(path), &statb) == 0) {
 
333
        switch (statb.st_mode & S_IFMT) {
 
334
        case S_IFDIR:
 
335
            return ('/');
 
336
 
 
337
        case S_IFLNK:
 
338
            if (stat(short2str(path), &statb) == 0 &&   /* follow it out */
 
339
                S_ISDIR(statb.st_mode))
 
340
                return ('>');
 
341
            else
 
342
                return ('@');
 
343
 
 
344
        case S_IFSOCK:
 
345
            return ('=');
 
346
 
 
347
        default:
 
348
            if (statb.st_mode & 0111)
 
349
                return ('*');
 
350
        }
 
351
    }
 
352
    return (' ');
 
353
}
 
354
 
 
355
static struct winsize win;
 
356
 
 
357
/*
 
358
 * Print sorted down columns
 
359
 */
 
360
static void
 
361
print_by_column(dir, items, count)
 
362
    Char   *dir, *items[];
 
363
    int     count;
 
364
{
 
365
    register int i, rows, r, c, maxwidth = 0, columns;
 
366
 
 
367
    if (ioctl(SHOUT, TIOCGWINSZ, (ioctl_t) & win) < 0 || win.ws_col == 0)
 
368
        win.ws_col = 80;
 
369
    for (i = 0; i < count; i++)
 
370
        maxwidth = maxwidth > (r = Strlen(items[i])) ? maxwidth : r;
 
371
    maxwidth += 2;              /* for the file tag and space */
 
372
    columns = win.ws_col / maxwidth;
 
373
    if (columns == 0)
 
374
        columns = 1;
 
375
    rows = (count + (columns - 1)) / columns;
 
376
    for (r = 0; r < rows; r++) {
 
377
        for (c = 0; c < columns; c++) {
 
378
            i = c * rows + r;
 
379
            if (i < count) {
 
380
                register int w;
 
381
 
 
382
                xprintf("%S", items[i]);
 
383
                xputchar(dir ? filetype(dir, items[i]) : ' ');
 
384
                if (c < columns - 1) {  /* last column? */
 
385
                    w = Strlen(items[i]) + 1;
 
386
                    for (; w < maxwidth; w++)
 
387
                        xputchar(' ');
 
388
                }
 
389
            }
 
390
        }
 
391
        xputchar('\r');
 
392
        xputchar('\n');
 
393
    }
 
394
}
 
395
 
 
396
/*
 
397
 * Expand file name with possible tilde usage
 
398
 *      ~person/mumble
 
399
 * expands to
 
400
 *      home_directory_of_person/mumble
 
401
 */
 
402
static Char *
 
403
tilde(new, old)
 
404
    Char   *new, *old;
 
405
{
 
406
    register Char *o, *p;
 
407
    register struct passwd *pw;
 
408
    static Char person[40];
 
409
 
 
410
    if (old[0] != '~')
 
411
        return (Strcpy(new, old));
 
412
 
 
413
    for (p = person, o = &old[1]; *o && *o != '/'; *p++ = *o++);
 
414
    *p = '\0';
 
415
    if (person[0] == '\0')
 
416
        (void) Strcpy(new, varval(STRhome));
 
417
    else {
 
418
        pw = getpwnam(short2str(person));
 
419
        if (pw == NULL)
 
420
            return (NULL);
 
421
        (void) Strcpy(new, str2short(pw->pw_dir));
 
422
    }
 
423
    (void) Strcat(new, o);
 
424
    return (new);
 
425
}
 
426
 
 
427
/*
 
428
 * Cause pending line to be printed
 
429
 */
 
430
static void
 
431
retype()
 
432
{
 
433
#ifdef TERMIO
 
434
# ifdef POSIX
 
435
    struct termios tty;
 
436
 
 
437
    (void) tcgetattr(SHOUT, &tty);
 
438
# else
 
439
    struct termio tty;
 
440
 
 
441
    (void) ioctl(SHOUT, TCGETA, (ioctl_t) &tty);
 
442
# endif /* POSIX */
 
443
 
 
444
#ifndef INTERIX
 
445
    tty.c_lflag |= PENDIN;
 
446
#endif
 
447
 
 
448
# ifdef POSIX
 
449
    (void) tcsetattr(SHOUT, TCSANOW, &tty);
 
450
# else
 
451
    (void) ioctl(SHOUT, TCSETAW, (ioctl_t) &tty);
 
452
# endif /* POSIX */
 
453
#else
 
454
    int     pending_input = LPENDIN;
 
455
 
 
456
    (void) ioctl(SHOUT, TIOCLBIS, (ioctl_t) & pending_input);
 
457
#endif /* TERMIO */
 
458
}
 
459
 
 
460
static void
 
461
beep()
 
462
{
 
463
    if (adrof(STRnobeep) == 0)
 
464
#ifndef _OSD_POSIX
 
465
        (void) write(SHOUT, "\007", 1);
 
466
#else /*_OSD_POSIX*/
 
467
    {
 
468
        unsigned char beep_ch = CTL_ESC('\007');
 
469
        (void) write(SHOUT, &beep_ch, 1);
 
470
    }
 
471
#endif /*_OSD_POSIX*/
 
472
}
 
473
 
 
474
/*
 
475
 * Erase that silly ^[ and
 
476
 * print the recognized part of the string
 
477
 */
 
478
static void
 
479
print_recognized_stuff(recognized_part)
 
480
    Char   *recognized_part;
 
481
{
 
482
    /* An optimized erasing of that silly ^[ */
 
483
    (void) putraw('\b');
 
484
    (void) putraw('\b');
 
485
    switch (Strlen(recognized_part)) {
 
486
 
 
487
    case 0:                     /* erase two Characters: ^[ */
 
488
        (void) putraw(' ');
 
489
        (void) putraw(' ');
 
490
        (void) putraw('\b');
 
491
        (void) putraw('\b');
 
492
        break;
 
493
 
 
494
    case 1:                     /* overstrike the ^, erase the [ */
 
495
        xprintf("%S", recognized_part);
 
496
        (void) putraw(' ');
 
497
        (void) putraw('\b');
 
498
        break;
 
499
 
 
500
    default:                    /* overstrike both Characters ^[ */
 
501
        xprintf("%S", recognized_part);
 
502
        break;
 
503
    }
 
504
    flush();
 
505
}
 
506
 
 
507
/*
 
508
 * Parse full path in file into 2 parts: directory and file names
 
509
 * Should leave final slash (/) at end of dir.
 
510
 */
 
511
static void
 
512
extract_dir_and_name(path, dir, name)
 
513
    Char   *path, *dir, *name;
 
514
{
 
515
    register Char *p;
 
516
 
 
517
    p = Strrchr(path, '/');
 
518
    if (p == NULL) {
 
519
        copyn(name, path, MAXNAMLEN);
 
520
        dir[0] = '\0';
 
521
    }
 
522
    else {
 
523
        copyn(name, ++p, MAXNAMLEN);
 
524
        copyn(dir, path, p - path);
 
525
    }
 
526
}
 
527
/* atp vmsposix - I need to remove all the setpwent 
 
528
 *                getpwent endpwent stuff. VMS_POSIX has getpwnam getpwuid
 
529
 *                and getlogin. This needs fixing. (There is no access to 
 
530
 *                pw->passwd in VMS - a secure system benefit :-| )
 
531
 */
 
532
static Char *
 
533
getitem(dir_fd, looking_for_lognames)
 
534
    DIR    *dir_fd;
 
535
    int     looking_for_lognames;
 
536
{
 
537
    register struct passwd *pw;
 
538
    register struct dirent *dirp;
 
539
 
 
540
    if (looking_for_lognames) {
 
541
#ifdef _VMS_POSIX
 
542
            return (NULL);
 
543
#else
 
544
        if ((pw = getpwent()) == NULL)
 
545
            return (NULL);
 
546
        return (str2short(pw->pw_name));
 
547
#endif /* atp vmsposix */
 
548
    }
 
549
    if (dirp = readdir(dir_fd))
 
550
        return (str2short(dirp->d_name));
 
551
    return (NULL);
 
552
}
 
553
 
 
554
static void
 
555
free_items(items)
 
556
    register Char **items;
 
557
{
 
558
    register int i;
 
559
 
 
560
    for (i = 0; items[i]; i++)
 
561
        xfree((ptr_t) items[i]);
 
562
    xfree((ptr_t) items);
 
563
}
 
564
 
 
565
#ifdef BSDSIGS
 
566
# define FREE_ITEMS(items) { \
 
567
        sigmask_t omask;\
 
568
\
 
569
        omask = sigblock(sigmask(SIGINT));\
 
570
        free_items(items);\
 
571
        items = NULL;\
 
572
        (void) sigsetmask(omask);\
 
573
}
 
574
#else
 
575
# define FREE_ITEMS(items) { \
 
576
        (void) sighold(SIGINT);\
 
577
        free_items(items);\
 
578
        items = NULL;\
 
579
        (void) sigrelse(SIGINT);\
 
580
}
 
581
#endif /* BSDSIGS */
 
582
 
 
583
/*
 
584
 * Perform a RECOGNIZE or LIST command on string "word".
 
585
 */
 
586
static int
 
587
tsearch(word, command, max_word_length)
 
588
    Char   *word;
 
589
    int     max_word_length;
 
590
    COMMAND command;
 
591
{
 
592
    static Char **items = NULL;
 
593
    register DIR *dir_fd;
 
594
    register numitems = 0, ignoring = TRUE, nignored = 0;
 
595
    register name_length, looking_for_lognames;
 
596
    Char    tilded_dir[MAXPATHLEN + 1], dir[MAXPATHLEN + 1];
 
597
    Char    name[MAXNAMLEN + 1], extended_name[MAXNAMLEN + 1];
 
598
    Char   *item;
 
599
 
 
600
#define MAXITEMS 1024
 
601
 
 
602
    if (items != NULL)
 
603
        FREE_ITEMS(items);
 
604
 
 
605
    looking_for_lognames = (*word == '~') && (Strchr(word, '/') == NULL);
 
606
    if (looking_for_lognames) {
 
607
#ifndef _VMS_POSIX
 
608
        (void) setpwent();
 
609
#endif /*atp vmsposix */
 
610
        copyn(name, &word[1], MAXNAMLEN);       /* name sans ~ */
 
611
        dir_fd = NULL;
 
612
    }
 
613
    else {
 
614
        extract_dir_and_name(word, dir, name);
 
615
        if (tilde(tilded_dir, dir) == 0)
 
616
            return (0);
 
617
        dir_fd = opendir(*tilded_dir ? short2str(tilded_dir) : ".");
 
618
        if (dir_fd == NULL)
 
619
            return (0);
 
620
    }
 
621
 
 
622
again:                          /* search for matches */
 
623
    name_length = Strlen(name);
 
624
    for (numitems = 0; item = getitem(dir_fd, looking_for_lognames);) {
 
625
        if (!is_prefix(name, item))
 
626
            continue;
 
627
        /* Don't match . files on null prefix match */
 
628
        if (name_length == 0 && item[0] == '.' &&
 
629
            !looking_for_lognames)
 
630
            continue;
 
631
        if (command == LIST) {
 
632
            if (numitems >= MAXITEMS) {
 
633
                xprintf(CGETS(14, 1, "\nYikes!! Too many %s!!\n"),
 
634
                        looking_for_lognames ?
 
635
                        CGETS(14, 2, "names in password file") :
 
636
                        CGETS(14, 3, "files");
 
637
                break;
 
638
            }
 
639
            /*
 
640
             * From Beto Appleton (beto@aixwiz.austin.ibm.com)
 
641
             *  typing "./control-d" will cause the csh to core-dump.
 
642
             *  the problem can be reproduce as following:
 
643
             *   1. set ignoreeof
 
644
             *   2. set filec
 
645
             *   3. create a directory with 1050 files
 
646
             *   4. typing "./control-d" will cause the csh to core-dump
 
647
             * Solution: Add + 1 to MAXITEMS
 
648
             */
 
649
            if (items == NULL)
 
650
                items = (Char **) xcalloc(sizeof(items[0]), MAXITEMS + 1);
 
651
            items[numitems] = (Char *) xmalloc((size_t) (Strlen(item) + 1) *
 
652
                                               sizeof(Char));
 
653
            copyn(items[numitems], item, MAXNAMLEN);
 
654
            numitems++;
 
655
        }
 
656
        else {                  /* RECOGNIZE command */
 
657
            if (ignoring && ignored(item))
 
658
                nignored++;
 
659
            else if (recognize(extended_name,
 
660
                               item, name_length, ++numitems))
 
661
                break;
 
662
        }
 
663
    }
 
664
    if (ignoring && numitems == 0 && nignored > 0) {
 
665
        ignoring = FALSE;
 
666
        nignored = 0;
 
667
        if (looking_for_lognames)
 
668
#ifndef _VMS_POSIX
 
669
            (void) setpwent();
 
670
#endif /* atp vmsposix */
 
671
        else
 
672
            rewinddir(dir_fd);
 
673
        goto again;
 
674
    }
 
675
 
 
676
    if (looking_for_lognames)
 
677
#ifndef _VMS_POSIX
 
678
        (void) endpwent();
 
679
#endif /*atp vmsposix */
 
680
    else
 
681
        (void) closedir(dir_fd);
 
682
    if (numitems == 0)
 
683
        return (0);
 
684
    if (command == RECOGNIZE) {
 
685
        if (looking_for_lognames)
 
686
            copyn(word, STRtilde, 1);
 
687
        else
 
688
            /* put back dir part */
 
689
            copyn(word, dir, max_word_length);
 
690
        /* add extended name */
 
691
        catn(word, extended_name, max_word_length);
 
692
        return (numitems);
 
693
    }
 
694
    else {                      /* LIST */
 
695
        qsort((ptr_t) items, (size_t) numitems, sizeof(items[0]), sortscmp);
 
696
        print_by_column(looking_for_lognames ? NULL : tilded_dir,
 
697
                        items, numitems);
 
698
        if (items != NULL)
 
699
            FREE_ITEMS(items);
 
700
    }
 
701
    return (0);
 
702
}
 
703
 
 
704
/*
 
705
 * Object: extend what user typed up to an ambiguity.
 
706
 * Algorithm:
 
707
 * On first match, copy full item (assume it'll be the only match)
 
708
 * On subsequent matches, shorten extended_name to the first
 
709
 * Character mismatch between extended_name and item.
 
710
 * If we shorten it back to the prefix length, stop searching.
 
711
 */
 
712
static int
 
713
recognize(extended_name, item, name_length, numitems)
 
714
    Char   *extended_name, *item;
 
715
    int     name_length, numitems;
 
716
{
 
717
    if (numitems == 1)          /* 1st match */
 
718
        copyn(extended_name, item, MAXNAMLEN);
 
719
    else {                      /* 2nd & subsequent matches */
 
720
        register Char *x, *ent;
 
721
        register int len = 0;
 
722
 
 
723
        x = extended_name;
 
724
        for (ent = item; *x && *x == *ent++; x++, len++);
 
725
        *x = '\0';              /* Shorten at 1st Char diff */
 
726
        if (len == name_length) /* Ambiguous to prefix? */
 
727
            return (-1);        /* So stop now and save time */
 
728
    }
 
729
    return (0);
 
730
}
 
731
 
 
732
/*
 
733
 * Return true if check matches initial Chars in template.
 
734
 * This differs from PWB imatch in that if check is null
 
735
 * it matches anything.
 
736
 */
 
737
static int
 
738
is_prefix(check, template)
 
739
    register Char *check, *template;
 
740
{
 
741
    do
 
742
        if (*check == 0)
 
743
            return (TRUE);
 
744
    while (*check++ == *template++);
 
745
    return (FALSE);
 
746
}
 
747
 
 
748
/*
 
749
 *  Return true if the Chars in template appear at the
 
750
 *  end of check, I.e., are it's suffix.
 
751
 */
 
752
static int
 
753
is_suffix(check, template)
 
754
    Char   *check, *template;
 
755
{
 
756
    register Char *c, *t;
 
757
 
 
758
    for (c = check; *c++;);
 
759
    for (t = template; *t++;);
 
760
    for (;;) {
 
761
        if (t == template)
 
762
            return 1;
 
763
        if (c == check || *--t != *--c)
 
764
            return 0;
 
765
    }
 
766
}
 
767
 
 
768
int
 
769
tenex(inputline, inputline_size)
 
770
    Char   *inputline;
 
771
    int     inputline_size;
 
772
{
 
773
    register int numitems, num_read;
 
774
    char    tinputline[BUFSIZE];
 
775
 
 
776
 
 
777
    setup_tty(ON);
 
778
 
 
779
    while ((num_read = read(SHIN, tinputline, BUFSIZE)) > 0) {
 
780
        int     i;
 
781
        static Char delims[] = {' ', '\'', '"', '\t', ';', '&', '<',
 
782
        '>', '(', ')', '|', '^', '%', '\0'};
 
783
        register Char *str_end, *word_start, last_Char, should_retype;
 
784
        register int space_left;
 
785
        COMMAND command;
 
786
 
 
787
        for (i = 0; i < num_read; i++)
 
788
            inputline[i] = (unsigned char) tinputline[i];
 
789
        last_Char = inputline[num_read - 1] & ASCII;
 
790
 
 
791
        if (last_Char == '\n' || num_read == inputline_size)
 
792
            break;
 
793
        command = (last_Char == ESC) ? RECOGNIZE : LIST;
 
794
        if (command == LIST)
 
795
            xputchar('\n');
 
796
        str_end = &inputline[num_read];
 
797
        if (last_Char == ESC)
 
798
            --str_end;          /* wipeout trailing cmd Char */
 
799
        *str_end = '\0';
 
800
        /*
 
801
         * Find LAST occurence of a delimiter in the inputline. The word start
 
802
         * is one Character past it.
 
803
         */
 
804
        for (word_start = str_end; word_start > inputline; --word_start)
 
805
            if (Strchr(delims, word_start[-1]))
 
806
                break;
 
807
        space_left = inputline_size - (word_start - inputline) - 1;
 
808
        numitems = tsearch(word_start, command, space_left);
 
809
 
 
810
        if (command == RECOGNIZE) {
 
811
            /* print from str_end on */
 
812
            print_recognized_stuff(str_end);
 
813
            if (numitems != 1)  /* Beep = No match/ambiguous */
 
814
                beep();
 
815
        }
 
816
 
 
817
        /*
 
818
         * Tabs in the input line cause trouble after a pushback. tty driver
 
819
         * won't backspace over them because column positions are now
 
820
         * incorrect. This is solved by retyping over current line.
 
821
         */
 
822
        should_retype = FALSE;
 
823
        if (Strchr(inputline, '\t')) {  /* tab Char in input line? */
 
824
            back_to_col_1();
 
825
            should_retype = TRUE;
 
826
        }
 
827
        if (command == LIST)    /* Always retype after a LIST */
 
828
            should_retype = TRUE;
 
829
        if (should_retype)
 
830
            printprompt(0, NULL);
 
831
        pushback(inputline);
 
832
        if (should_retype)
 
833
            retype();
 
834
    }
 
835
    setup_tty(OFF);
 
836
    return (num_read);
 
837
}
 
838
 
 
839
static int
 
840
ignored(item)
 
841
    register Char *item;
 
842
{
 
843
    struct varent *vp;
 
844
    register Char **cp;
 
845
 
 
846
    if ((vp = adrof(STRfignore)) == NULL || (cp = vp->vec) == NULL)
 
847
        return (FALSE);
 
848
    for (; *cp != NULL; cp++)
 
849
        if (is_suffix(item, *cp))
 
850
            return (TRUE);
 
851
    return (FALSE);
 
852
}
 
853
#endif  /* FILEC */