147823Sbostic /*-
260765Sbostic * Copyright (c) 1980, 1991, 1993
360765Sbostic * The Regents of the University of California. All rights reserved.
447823Sbostic *
547823Sbostic * %sccs.include.redist.c%
621932Sdist */
721932Sdist
817147Ssam #ifndef lint
9*69283Schristos static char sccsid[] = "@(#)file.c 8.4 (Berkeley) 05/06/95";
1047823Sbostic #endif /* not lint */
1115372Slayer
1217521Sedward #ifdef FILEC
1349992Sbostic
1450028Sbostic #include <sys/param.h>
1550028Sbostic #include <sys/ioctl.h>
1650028Sbostic #include <sys/stat.h>
1750028Sbostic #include <termios.h>
1850028Sbostic #include <dirent.h>
1950028Sbostic #include <pwd.h>
2050028Sbostic #include <stdlib.h>
2150028Sbostic #include <unistd.h>
2250463Schristos #ifndef SHORT_STRINGS
2350463Schristos #include <string.h>
2450463Schristos #endif /* SHORT_STRINGS */
2550033Schristos #if __STDC__
2650033Schristos # include <stdarg.h>
2750033Schristos #else
2850033Schristos # include <varargs.h>
2950033Schristos #endif
3050033Schristos
3150023Sbostic #include "csh.h"
3250023Sbostic #include "extern.h"
3349992Sbostic
3415372Slayer /*
3515372Slayer * Tenex style file name recognition, .. and more.
3615372Slayer * History:
3715372Slayer * Author: Ken Greer, Sept. 1975, CMU.
3815372Slayer * Finally got around to adding to the Cshell., Ken Greer, Dec. 1981.
3915372Slayer */
4015372Slayer
4115372Slayer #define ON 1
4215372Slayer #define OFF 0
4349992Sbostic #ifndef TRUE
4449992Sbostic #define TRUE 1
4549992Sbostic #endif
4649992Sbostic #ifndef FALSE
4749992Sbostic #define FALSE 0
4849992Sbostic #endif
4915372Slayer
5015372Slayer #define ESC '\033'
5115372Slayer
5249992Sbostic typedef enum {
5349992Sbostic LIST, RECOGNIZE
5449992Sbostic } COMMAND;
5515372Slayer
5650024Schristos static void setup_tty __P((int));
5750024Schristos static void back_to_col_1 __P((void));
5850024Schristos static void pushback __P((Char *));
5950024Schristos static void catn __P((Char *, Char *, int));
6050024Schristos static void copyn __P((Char *, Char *, int));
6150024Schristos static Char filetype __P((Char *, Char *));
6250024Schristos static void print_by_column __P((Char *, Char *[], int));
6351437Sleres static Char *tilde __P((Char *, Char *));
6450024Schristos static void retype __P((void));
6550024Schristos static void beep __P((void));
6651437Sleres static void print_recognized_stuff __P((Char *));
6750024Schristos static void extract_dir_and_name __P((Char *, Char *, Char *));
6850024Schristos static Char *getentry __P((DIR *, int));
6950024Schristos static void free_items __P((Char **));
7050027Schristos static int tsearch __P((Char *, COMMAND, int));
7150024Schristos static int recognize __P((Char *, Char *, int, int));
7250024Schristos static int is_prefix __P((Char *, Char *));
7350024Schristos static int is_suffix __P((Char *, Char *));
7450024Schristos static int ignored __P((Char *));
7528048Slepreau
7617521Sedward /*
7717521Sedward * Put this here so the binary can be patched with adb to enable file
7826144Sedward * completion by default. Filec controls completion, nobeep controls
7926144Sedward * ringing the terminal bell on incomplete expansions.
8017521Sedward */
8149992Sbostic bool filec = 0;
8217521Sedward
8349992Sbostic static void
setup_tty(on)8417147Ssam setup_tty(on)
8549992Sbostic int on;
8615372Slayer {
8749992Sbostic static struct termios tchars;
8817139Sralph
8966402Schristos (void) tcgetattr(SHIN, &tchars);
9066402Schristos
9149992Sbostic if (on) {
9249992Sbostic tchars.c_cc[VEOL] = ESC;
9349992Sbostic if (tchars.c_lflag & ICANON)
9449992Sbostic on = TCSANOW;
9549992Sbostic else {
9649992Sbostic on = TCSAFLUSH;
9749992Sbostic tchars.c_lflag |= ICANON;
9815372Slayer }
9949992Sbostic }
10049992Sbostic else {
10149992Sbostic tchars.c_cc[VEOL] = _POSIX_VDISABLE;
10266402Schristos on = TCSANOW;
10349992Sbostic }
10466402Schristos
10566402Schristos (void) tcsetattr(SHIN, TCSANOW, &tchars);
10615372Slayer }
10715372Slayer
10815372Slayer /*
10915372Slayer * Move back to beginning of current line
11015372Slayer */
11149992Sbostic static void
back_to_col_1()11217147Ssam back_to_col_1()
11315372Slayer {
11449992Sbostic struct termios tty, tty_normal;
11568576Schristos sigset_t sigset, osigset;
11617139Sralph
11768576Schristos sigemptyset(&sigset);
11868576Schristos sigaddset(&sigset, SIGINT);
11968576Schristos sigprocmask(SIG_BLOCK, &sigset, &osigset);
12049992Sbostic (void) tcgetattr(SHOUT, &tty);
12149992Sbostic tty_normal = tty;
12249992Sbostic tty.c_iflag &= ~INLCR;
12349992Sbostic tty.c_oflag &= ~ONLCR;
12449992Sbostic (void) tcsetattr(SHOUT, TCSANOW, &tty);
12549992Sbostic (void) write(SHOUT, "\r", 1);
12649992Sbostic (void) tcsetattr(SHOUT, TCSANOW, &tty_normal);
12768576Schristos sigprocmask(SIG_SETMASK, &osigset, NULL);
12815372Slayer }
12915372Slayer
13015372Slayer /*
13115372Slayer * Push string contents back into tty queue
13215372Slayer */
13349992Sbostic static void
pushback(string)13417147Ssam pushback(string)
13549992Sbostic Char *string;
13615372Slayer {
13749992Sbostic register Char *p;
13849992Sbostic struct termios tty, tty_normal;
13968576Schristos sigset_t sigset, osigset;
14049992Sbostic char c;
14115372Slayer
14268576Schristos sigemptyset(&sigset);
14368576Schristos sigaddset(&sigset, SIGINT);
14468576Schristos sigprocmask(SIG_BLOCK, &sigset, &osigset);
14549992Sbostic (void) tcgetattr(SHOUT, &tty);
14649992Sbostic tty_normal = tty;
14749992Sbostic tty.c_lflag &= ~(ECHOKE | ECHO | ECHOE | ECHOK | ECHONL | ECHOPRT | ECHOCTL);
14849992Sbostic (void) tcsetattr(SHOUT, TCSANOW, &tty);
14915372Slayer
15060237Schristos for (p = string; (c = *p) != '\0'; p++)
15149992Sbostic (void) ioctl(SHOUT, TIOCSTI, (ioctl_t) & c);
15249992Sbostic (void) tcsetattr(SHOUT, TCSANOW, &tty_normal);
15368576Schristos sigprocmask(SIG_SETMASK, &osigset, NULL);
15415372Slayer }
15515372Slayer
15615372Slayer /*
15717147Ssam * Concatenate src onto tail of des.
15815372Slayer * Des is a string whose maximum length is count.
15915372Slayer * Always null terminate.
16015372Slayer */
16149992Sbostic static void
catn(des,src,count)16217147Ssam catn(des, src, count)
16349992Sbostic register Char *des, *src;
16450024Schristos register int count;
16515372Slayer {
16649992Sbostic while (--count >= 0 && *des)
16749992Sbostic des++;
16849992Sbostic while (--count >= 0)
16949992Sbostic if ((*des++ = *src++) == 0)
17049992Sbostic return;
17149992Sbostic *des = '\0';
17215372Slayer }
17315372Slayer
17415372Slayer /*
17517147Ssam * Like strncpy but always leave room for trailing \0
17615372Slayer * and always null terminate.
17715372Slayer */
17849992Sbostic static void
copyn(des,src,count)17917147Ssam copyn(des, src, count)
18049992Sbostic register Char *des, *src;
18150024Schristos register int count;
18215372Slayer {
18349992Sbostic while (--count >= 0)
18449992Sbostic if ((*des++ = *src++) == 0)
18549992Sbostic return;
18649992Sbostic *des = '\0';
18715372Slayer }
18815372Slayer
18949992Sbostic static Char
filetype(dir,file)19017147Ssam filetype(dir, file)
19149992Sbostic Char *dir, *file;
19215372Slayer {
19349992Sbostic Char path[MAXPATHLEN];
19449992Sbostic struct stat statb;
19517147Ssam
19649992Sbostic catn(Strcpy(path, dir), file, sizeof(path) / sizeof(Char));
19749992Sbostic if (lstat(short2str(path), &statb) == 0) {
19849992Sbostic switch (statb.st_mode & S_IFMT) {
19949992Sbostic case S_IFDIR:
20049992Sbostic return ('/');
20128048Slepreau
20249992Sbostic case S_IFLNK:
20349992Sbostic if (stat(short2str(path), &statb) == 0 && /* follow it out */
20449992Sbostic S_ISDIR(statb.st_mode))
20549992Sbostic return ('>');
20649992Sbostic else
20749992Sbostic return ('@');
20828048Slepreau
20949992Sbostic case S_IFSOCK:
21049992Sbostic return ('=');
21128048Slepreau
21249992Sbostic default:
21349992Sbostic if (statb.st_mode & 0111)
21449992Sbostic return ('*');
21515372Slayer }
21649992Sbostic }
21749992Sbostic return (' ');
21815372Slayer }
21915372Slayer
22028048Slepreau static struct winsize win;
22128048Slepreau
22215372Slayer /*
22315372Slayer * Print sorted down columns
22415372Slayer */
22549992Sbostic static void
print_by_column(dir,items,count)22617147Ssam print_by_column(dir, items, count)
22749992Sbostic Char *dir, *items[];
22849992Sbostic int count;
22915372Slayer {
23049992Sbostic register int i, rows, r, c, maxwidth = 0, columns;
23117147Ssam
23249992Sbostic if (ioctl(SHOUT, TIOCGWINSZ, (ioctl_t) & win) < 0 || win.ws_col == 0)
23349992Sbostic win.ws_col = 80;
23449992Sbostic for (i = 0; i < count; i++)
23549992Sbostic maxwidth = maxwidth > (r = Strlen(items[i])) ? maxwidth : r;
23649992Sbostic maxwidth += 2; /* for the file tag and space */
23749992Sbostic columns = win.ws_col / maxwidth;
23849992Sbostic if (columns == 0)
23949992Sbostic columns = 1;
24049992Sbostic rows = (count + (columns - 1)) / columns;
24149992Sbostic for (r = 0; r < rows; r++) {
24249992Sbostic for (c = 0; c < columns; c++) {
24349992Sbostic i = c * rows + r;
24449992Sbostic if (i < count) {
24549992Sbostic register int w;
24617147Ssam
24751589Schristos (void) fprintf(cshout, "%s", vis_str(items[i]));
24850439Schristos (void) fputc(dir ? filetype(dir, items[i]) : ' ', cshout);
24949992Sbostic if (c < columns - 1) { /* last column? */
25049992Sbostic w = Strlen(items[i]) + 1;
25149992Sbostic for (; w < maxwidth; w++)
25250439Schristos (void) fputc(' ', cshout);
25317147Ssam }
25449992Sbostic }
25515372Slayer }
25650439Schristos (void) fputc('\r', cshout);
25750439Schristos (void) fputc('\n', cshout);
25849992Sbostic }
25915372Slayer }
26015372Slayer
26115372Slayer /*
26217147Ssam * Expand file name with possible tilde usage
26317147Ssam * ~person/mumble
26415372Slayer * expands to
26517147Ssam * home_directory_of_person/mumble
26615372Slayer */
26749992Sbostic static Char *
tilde(new,old)26817147Ssam tilde(new, old)
26949992Sbostic Char *new, *old;
27015372Slayer {
27149992Sbostic register Char *o, *p;
27249992Sbostic register struct passwd *pw;
27349992Sbostic static Char person[40];
27415372Slayer
27549992Sbostic if (old[0] != '~')
27649992Sbostic return (Strcpy(new, old));
27715372Slayer
27851437Sleres for (p = person, o = &old[1]; *o && *o != '/'; *p++ = *o++)
27951437Sleres continue;
28049992Sbostic *p = '\0';
28149992Sbostic if (person[0] == '\0')
28249992Sbostic (void) Strcpy(new, value(STRhome));
28349992Sbostic else {
28449992Sbostic pw = getpwnam(short2str(person));
28549992Sbostic if (pw == NULL)
28649992Sbostic return (NULL);
28749992Sbostic (void) Strcpy(new, str2short(pw->pw_dir));
28849992Sbostic }
28949992Sbostic (void) Strcat(new, o);
29049992Sbostic return (new);
29115372Slayer }
29215372Slayer
29315372Slayer /*
29415372Slayer * Cause pending line to be printed
29515372Slayer */
29649992Sbostic static void
retype()29717147Ssam retype()
29815372Slayer {
29949992Sbostic struct termios tty;
30017147Ssam
30149992Sbostic (void) tcgetattr(SHOUT, &tty);
30249992Sbostic tty.c_lflag |= PENDIN;
30349992Sbostic (void) tcsetattr(SHOUT, TCSANOW, &tty);
30415372Slayer }
30515372Slayer
30649992Sbostic static void
beep()30717147Ssam beep()
30815372Slayer {
30949992Sbostic if (adrof(STRnobeep) == 0)
31049992Sbostic (void) write(SHOUT, "\007", 1);
31115372Slayer }
31215372Slayer
31315372Slayer /*
31415372Slayer * Erase that silly ^[ and
31515372Slayer * print the recognized part of the string
31615372Slayer */
31749992Sbostic static void
print_recognized_stuff(recognized_part)31817147Ssam print_recognized_stuff(recognized_part)
31949992Sbostic Char *recognized_part;
32015372Slayer {
32149992Sbostic /* An optimized erasing of that silly ^[ */
32250439Schristos (void) fputc('\b', cshout);
32350439Schristos (void) fputc('\b', cshout);
32449992Sbostic switch (Strlen(recognized_part)) {
32517147Ssam
32649992Sbostic case 0: /* erase two Characters: ^[ */
32750439Schristos (void) fputc(' ', cshout);
32850439Schristos (void) fputc(' ', cshout);
32950439Schristos (void) fputc('\b', cshout);
33050439Schristos (void) fputc('\b', cshout);
33149992Sbostic break;
33217147Ssam
33349992Sbostic case 1: /* overstrike the ^, erase the [ */
33451589Schristos (void) fprintf(cshout, "%s", vis_str(recognized_part));
33550439Schristos (void) fputc(' ', cshout);
33650439Schristos (void) fputc('\b', cshout);
33749992Sbostic break;
33817147Ssam
33949992Sbostic default: /* overstrike both Characters ^[ */
34051589Schristos (void) fprintf(cshout, "%s", vis_str(recognized_part));
34149992Sbostic break;
34249992Sbostic }
34350439Schristos (void) fflush(cshout);
34415372Slayer }
34515372Slayer
34615372Slayer /*
34717147Ssam * Parse full path in file into 2 parts: directory and file names
34815372Slayer * Should leave final slash (/) at end of dir.
34915372Slayer */
35049992Sbostic static void
extract_dir_and_name(path,dir,name)35117147Ssam extract_dir_and_name(path, dir, name)
35249992Sbostic Char *path, *dir, *name;
35315372Slayer {
35449992Sbostic register Char *p;
35517147Ssam
35649992Sbostic p = Strrchr(path, '/');
35749992Sbostic if (p == NULL) {
35849992Sbostic copyn(name, path, MAXNAMLEN);
35949992Sbostic dir[0] = '\0';
36049992Sbostic }
36149992Sbostic else {
36249992Sbostic copyn(name, ++p, MAXNAMLEN);
36349992Sbostic copyn(dir, path, p - path);
36449992Sbostic }
36515372Slayer }
36615372Slayer
36749992Sbostic static Char *
getentry(dir_fd,looking_for_lognames)36817147Ssam getentry(dir_fd, looking_for_lognames)
36949992Sbostic DIR *dir_fd;
37049992Sbostic int looking_for_lognames;
37115372Slayer {
37249992Sbostic register struct passwd *pw;
37349992Sbostic register struct dirent *dirp;
37417147Ssam
37549992Sbostic if (looking_for_lognames) {
37649992Sbostic if ((pw = getpwent()) == NULL)
37749992Sbostic return (NULL);
37849992Sbostic return (str2short(pw->pw_name));
37949992Sbostic }
38060237Schristos if ((dirp = readdir(dir_fd)) != NULL)
38149992Sbostic return (str2short(dirp->d_name));
38249992Sbostic return (NULL);
38315372Slayer }
38415372Slayer
38549992Sbostic static void
free_items(items)38617147Ssam free_items(items)
38749992Sbostic register Char **items;
38815372Slayer {
38949992Sbostic register int i;
39017147Ssam
39149992Sbostic for (i = 0; items[i]; i++)
39249992Sbostic xfree((ptr_t) items[i]);
39349992Sbostic xfree((ptr_t) items);
39415372Slayer }
39515372Slayer
39617147Ssam #define FREE_ITEMS(items) { \
39768576Schristos sigset_t sigset, osigset;\
39817430Sbloom \
39968576Schristos sigemptyset(&sigset);\
40068576Schristos sigaddset(&sigset, SIGINT);\
40168576Schristos sigprocmask(SIG_BLOCK, &sigset, &osigset);\
40217147Ssam free_items(items);\
40317147Ssam items = NULL;\
40468576Schristos sigprocmask(SIG_SETMASK, &osigset, NULL);\
40515372Slayer }
40615372Slayer
40715372Slayer /*
40815372Slayer * Perform a RECOGNIZE or LIST command on string "word".
40915372Slayer */
41049992Sbostic static int
tsearch(word,command,max_word_length)41149992Sbostic tsearch(word, command, max_word_length)
41249992Sbostic Char *word;
41350027Schristos COMMAND command;
41449992Sbostic int max_word_length;
41515372Slayer {
41649992Sbostic static Char **items = NULL;
41749992Sbostic register DIR *dir_fd;
41849992Sbostic register numitems = 0, ignoring = TRUE, nignored = 0;
41949992Sbostic register name_length, looking_for_lognames;
42049992Sbostic Char tilded_dir[MAXPATHLEN + 1], dir[MAXPATHLEN + 1];
42149992Sbostic Char name[MAXNAMLEN + 1], extended_name[MAXNAMLEN + 1];
42249992Sbostic Char *entry;
42349992Sbostic
42417147Ssam #define MAXITEMS 1024
42515372Slayer
42649992Sbostic if (items != NULL)
42749992Sbostic FREE_ITEMS(items);
42815372Slayer
42949992Sbostic looking_for_lognames = (*word == '~') && (Strchr(word, '/') == NULL);
43049992Sbostic if (looking_for_lognames) {
43149992Sbostic (void) setpwent();
43249992Sbostic copyn(name, &word[1], MAXNAMLEN); /* name sans ~ */
43349992Sbostic dir_fd = NULL;
43449992Sbostic }
43549992Sbostic else {
43649992Sbostic extract_dir_and_name(word, dir, name);
43749992Sbostic if (tilde(tilded_dir, dir) == 0)
43849992Sbostic return (0);
43949992Sbostic dir_fd = opendir(*tilded_dir ? short2str(tilded_dir) : ".");
44049992Sbostic if (dir_fd == NULL)
44149992Sbostic return (0);
44249992Sbostic }
44326144Sedward
44449992Sbostic again: /* search for matches */
44549992Sbostic name_length = Strlen(name);
44660237Schristos for (numitems = 0; (entry = getentry(dir_fd, looking_for_lognames)) != NULL;) {
44749992Sbostic if (!is_prefix(name, entry))
44849992Sbostic continue;
44949992Sbostic /* Don't match . files on null prefix match */
45049992Sbostic if (name_length == 0 && entry[0] == '.' &&
45149992Sbostic !looking_for_lognames)
45249992Sbostic continue;
45349992Sbostic if (command == LIST) {
45449992Sbostic if (numitems >= MAXITEMS) {
45550439Schristos (void) fprintf(csherr, "\nYikes!! Too many %s!!\n",
45650439Schristos looking_for_lognames ?
45750439Schristos "names in password file" : "files");
45849992Sbostic break;
45949992Sbostic }
46049992Sbostic if (items == NULL)
46149992Sbostic items = (Char **) xcalloc(sizeof(items[0]), MAXITEMS);
46249992Sbostic items[numitems] = (Char *) xmalloc((size_t) (Strlen(entry) + 1) *
46349992Sbostic sizeof(Char));
46449992Sbostic copyn(items[numitems], entry, MAXNAMLEN);
46549992Sbostic numitems++;
46615372Slayer }
46749992Sbostic else { /* RECOGNIZE command */
46849992Sbostic if (ignoring && ignored(entry))
46949992Sbostic nignored++;
47049992Sbostic else if (recognize(extended_name,
47149992Sbostic entry, name_length, ++numitems))
47249992Sbostic break;
47326144Sedward }
47449992Sbostic }
47549992Sbostic if (ignoring && numitems == 0 && nignored > 0) {
47649992Sbostic ignoring = FALSE;
47749992Sbostic nignored = 0;
47849992Sbostic if (looking_for_lognames)
47949992Sbostic (void) setpwent();
48049992Sbostic else
48149992Sbostic rewinddir(dir_fd);
48249992Sbostic goto again;
48349992Sbostic }
48426144Sedward
48549992Sbostic if (looking_for_lognames)
48649992Sbostic (void) endpwent();
48749992Sbostic else
48849992Sbostic (void) closedir(dir_fd);
48949992Sbostic if (numitems == 0)
49049992Sbostic return (0);
49149992Sbostic if (command == RECOGNIZE) {
49215372Slayer if (looking_for_lognames)
49349992Sbostic copyn(word, STRtilde, 1);
49415372Slayer else
49549992Sbostic /* put back dir part */
49649992Sbostic copyn(word, dir, max_word_length);
49749992Sbostic /* add extended name */
49849992Sbostic catn(word, extended_name, max_word_length);
49949992Sbostic return (numitems);
50049992Sbostic }
50149992Sbostic else { /* LIST */
50252369Schristos qsort((ptr_t) items, numitems, sizeof(items[0]),
50352369Schristos (int (*) __P((const void *, const void *))) sortscmp);
50449992Sbostic print_by_column(looking_for_lognames ? NULL : tilded_dir,
50549992Sbostic items, numitems);
50649992Sbostic if (items != NULL)
50749992Sbostic FREE_ITEMS(items);
50849992Sbostic }
50949992Sbostic return (0);
51015372Slayer }
51115372Slayer
51215372Slayer /*
51315372Slayer * Object: extend what user typed up to an ambiguity.
51415372Slayer * Algorithm:
51549992Sbostic * On first match, copy full entry (assume it'll be the only match)
51615372Slayer * On subsequent matches, shorten extended_name to the first
51749992Sbostic * Character mismatch between extended_name and entry.
51815372Slayer * If we shorten it back to the prefix length, stop searching.
51915372Slayer */
52049992Sbostic static int
recognize(extended_name,entry,name_length,numitems)52117147Ssam recognize(extended_name, entry, name_length, numitems)
52249992Sbostic Char *extended_name, *entry;
52349992Sbostic int name_length, numitems;
52415372Slayer {
52549992Sbostic if (numitems == 1) /* 1st match */
52649992Sbostic copyn(extended_name, entry, MAXNAMLEN);
52749992Sbostic else { /* 2nd & subsequent matches */
52849992Sbostic register Char *x, *ent;
52949992Sbostic register int len = 0;
53017147Ssam
53149992Sbostic x = extended_name;
53251437Sleres for (ent = entry; *x && *x == *ent++; x++, len++)
53351437Sleres continue;
53449992Sbostic *x = '\0'; /* Shorten at 1st Char diff */
53549992Sbostic if (len == name_length) /* Ambiguous to prefix? */
53649992Sbostic return (-1); /* So stop now and save time */
53749992Sbostic }
53849992Sbostic return (0);
53915372Slayer }
54015372Slayer
54115372Slayer /*
54249992Sbostic * Return true if check matches initial Chars in template.
54315372Slayer * This differs from PWB imatch in that if check is null
54426969Slepreau * it matches anything.
54515372Slayer */
54649992Sbostic static int
is_prefix(check,template)54717147Ssam is_prefix(check, template)
54849992Sbostic register Char *check, *template;
54915372Slayer {
55049992Sbostic do
55149992Sbostic if (*check == 0)
55249992Sbostic return (TRUE);
55349992Sbostic while (*check++ == *template++);
55449992Sbostic return (FALSE);
55515372Slayer }
55615372Slayer
55726144Sedward /*
55849992Sbostic * Return true if the Chars in template appear at the
55926144Sedward * end of check, I.e., are it's suffix.
56026144Sedward */
56149992Sbostic static int
is_suffix(check,template)56226144Sedward is_suffix(check, template)
56349992Sbostic Char *check, *template;
56426144Sedward {
56549992Sbostic register Char *c, *t;
56626144Sedward
56751437Sleres for (c = check; *c++;)
56851437Sleres continue;
56951437Sleres for (t = template; *t++;)
57051437Sleres continue;
57149992Sbostic for (;;) {
57249992Sbostic if (t == template)
57349992Sbostic return 1;
57449992Sbostic if (c == check || *--t != *--c)
57549992Sbostic return 0;
57649992Sbostic }
57726144Sedward }
57826144Sedward
57949992Sbostic int
tenex(inputline,inputline_size)58017147Ssam tenex(inputline, inputline_size)
58149992Sbostic Char *inputline;
58249992Sbostic int inputline_size;
58315372Slayer {
58449992Sbostic register int numitems, num_read;
58549992Sbostic char tinputline[BUFSIZ];
58615372Slayer
58715372Slayer
58849992Sbostic setup_tty(ON);
58915372Slayer
59049992Sbostic while ((num_read = read(SHIN, tinputline, BUFSIZ)) > 0) {
59149992Sbostic int i;
59249992Sbostic static Char delims[] = {' ', '\'', '"', '\t', ';', '&', '<',
59349992Sbostic '>', '(', ')', '|', '^', '%', '\0'};
59449992Sbostic register Char *str_end, *word_start, last_Char, should_retype;
59549992Sbostic register int space_left;
59649992Sbostic COMMAND command;
59715372Slayer
59849992Sbostic for (i = 0; i < num_read; i++)
59949992Sbostic inputline[i] = (unsigned char) tinputline[i];
60049992Sbostic last_Char = inputline[num_read - 1] & ASCII;
60115372Slayer
60249992Sbostic if (last_Char == '\n' || num_read == inputline_size)
60349992Sbostic break;
60449992Sbostic command = (last_Char == ESC) ? RECOGNIZE : LIST;
60549992Sbostic if (command == LIST)
60650439Schristos (void) fputc('\n', cshout);
60749992Sbostic str_end = &inputline[num_read];
60849992Sbostic if (last_Char == ESC)
60949992Sbostic --str_end; /* wipeout trailing cmd Char */
61049992Sbostic *str_end = '\0';
61149992Sbostic /*
61249992Sbostic * Find LAST occurence of a delimiter in the inputline. The word start
61349992Sbostic * is one Character past it.
61449992Sbostic */
61549992Sbostic for (word_start = str_end; word_start > inputline; --word_start)
61649992Sbostic if (Strchr(delims, word_start[-1]))
61749992Sbostic break;
61849992Sbostic space_left = inputline_size - (word_start - inputline) - 1;
61949992Sbostic numitems = tsearch(word_start, command, space_left);
62049992Sbostic
62149992Sbostic if (command == RECOGNIZE) {
62249992Sbostic /* print from str_end on */
62349992Sbostic print_recognized_stuff(str_end);
62449992Sbostic if (numitems != 1) /* Beep = No match/ambiguous */
62549992Sbostic beep();
62615372Slayer }
62749992Sbostic
62849992Sbostic /*
62949992Sbostic * Tabs in the input line cause trouble after a pushback. tty driver
63049992Sbostic * won't backspace over them because column positions are now
63149992Sbostic * incorrect. This is solved by retyping over current line.
63249992Sbostic */
63349992Sbostic should_retype = FALSE;
63449992Sbostic if (Strchr(inputline, '\t')) { /* tab Char in input line? */
63549992Sbostic back_to_col_1();
63649992Sbostic should_retype = TRUE;
63749992Sbostic }
63849992Sbostic if (command == LIST) /* Always retype after a LIST */
63949992Sbostic should_retype = TRUE;
64049992Sbostic if (should_retype)
64149992Sbostic printprompt();
64249992Sbostic pushback(inputline);
64349992Sbostic if (should_retype)
64449992Sbostic retype();
64549992Sbostic }
64649992Sbostic setup_tty(OFF);
64749992Sbostic return (num_read);
64815372Slayer }
64926144Sedward
65049992Sbostic static int
ignored(entry)65126144Sedward ignored(entry)
65249992Sbostic register Char *entry;
65326144Sedward {
65449992Sbostic struct varent *vp;
65549992Sbostic register Char **cp;
65626144Sedward
65749992Sbostic if ((vp = adrof(STRfignore)) == NULL || (cp = vp->vec) == NULL)
65826144Sedward return (FALSE);
65949992Sbostic for (; *cp != NULL; cp++)
66049992Sbostic if (is_suffix(entry, *cp))
66149992Sbostic return (TRUE);
66249992Sbostic return (FALSE);
66326144Sedward }
66449992Sbostic #endif /* FILEC */
665