source: trunk/third/tcsh/sh.file.c @ 12039

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