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

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