xref: /illumos-gate/usr/src/cmd/csh/sh.file.c (revision 2a8bcb4e)
17c478bd9Sstevel@tonic-gate /*
26c02b4a4Smuffin  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
77c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
87c478bd9Sstevel@tonic-gate 
97c478bd9Sstevel@tonic-gate /*
107c478bd9Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
117c478bd9Sstevel@tonic-gate  * All rights reserved.  The Berkeley Software License Agreement
127c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
137c478bd9Sstevel@tonic-gate  */
147c478bd9Sstevel@tonic-gate 
157c478bd9Sstevel@tonic-gate #ifdef FILEC
167c478bd9Sstevel@tonic-gate /*
177c478bd9Sstevel@tonic-gate  * Tenex style file name recognition, .. and more.
187c478bd9Sstevel@tonic-gate  * History:
197c478bd9Sstevel@tonic-gate  *	Author: Ken Greer, Sept. 1975, CMU.
207c478bd9Sstevel@tonic-gate  *	Finally got around to adding to the Cshell., Ken Greer, Dec. 1981.
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate 
237c478bd9Sstevel@tonic-gate #include "sh.h"
247c478bd9Sstevel@tonic-gate #include <sys/types.h>
257c478bd9Sstevel@tonic-gate #include <dirent.h>
267c478bd9Sstevel@tonic-gate #include <pwd.h>
277c478bd9Sstevel@tonic-gate #include "sh.tconst.h"
287c478bd9Sstevel@tonic-gate 
29*65b0c20eSnakanon #define	TRUE	1
30*65b0c20eSnakanon #define	FALSE	0
31*65b0c20eSnakanon #define	ON	1
32*65b0c20eSnakanon #define	OFF	0
337c478bd9Sstevel@tonic-gate 
34*65b0c20eSnakanon #define	ESC	'\033'
357c478bd9Sstevel@tonic-gate 
366c02b4a4Smuffin extern DIR *opendir_(tchar *);
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate static char *BELL = "\07";
397c478bd9Sstevel@tonic-gate static char *CTRLR = "^R\n";
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate typedef enum {LIST, RECOGNIZE} COMMAND;
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate static jmp_buf osetexit;		/* saved setexit() state */
447c478bd9Sstevel@tonic-gate static struct termios  tty_save;	/* saved terminal state */
457c478bd9Sstevel@tonic-gate static struct termios  tty_new;		/* new terminal state */
467c478bd9Sstevel@tonic-gate 
476c02b4a4Smuffin static int	is_prefix(tchar *, tchar *);
486c02b4a4Smuffin static int	is_suffix(tchar *, tchar *);
496c02b4a4Smuffin static int	ignored(tchar *);
506c02b4a4Smuffin 
517c478bd9Sstevel@tonic-gate /*
527c478bd9Sstevel@tonic-gate  * Put this here so the binary can be patched with adb to enable file
537c478bd9Sstevel@tonic-gate  * completion by default.  Filec controls completion, nobeep controls
547c478bd9Sstevel@tonic-gate  * ringing the terminal bell on incomplete expansions.
557c478bd9Sstevel@tonic-gate  */
567c478bd9Sstevel@tonic-gate bool filec = 0;
577c478bd9Sstevel@tonic-gate 
586c02b4a4Smuffin static void
setup_tty(int on)596c02b4a4Smuffin setup_tty(int on)
607c478bd9Sstevel@tonic-gate {
617c478bd9Sstevel@tonic-gate 	int omask;
627c478bd9Sstevel@tonic-gate #ifdef TRACE
637c478bd9Sstevel@tonic-gate 	tprintf("TRACE- setup_tty()\n");
647c478bd9Sstevel@tonic-gate #endif
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate 	omask = sigblock(sigmask(SIGINT));
677c478bd9Sstevel@tonic-gate 	if (on) {
687c478bd9Sstevel@tonic-gate 		/*
697c478bd9Sstevel@tonic-gate 		 * The shell makes sure that the tty is not in some weird state
707c478bd9Sstevel@tonic-gate 		 * and fixes it if it is.  But it should be noted that the
717c478bd9Sstevel@tonic-gate 		 * tenex routine will not work correctly in CBREAK or RAW mode
727c478bd9Sstevel@tonic-gate 		 * so this code below is, therefore, mandatory.
737c478bd9Sstevel@tonic-gate 		 *
747c478bd9Sstevel@tonic-gate 		 * Also, in order to recognize the ESC (filename-completion)
757c478bd9Sstevel@tonic-gate 		 * character, set EOL to ESC.  This way, ESC will terminate
767c478bd9Sstevel@tonic-gate 		 * the line, but still be in the input stream.
777c478bd9Sstevel@tonic-gate 		 * EOT (filename list) will also terminate the line,
787c478bd9Sstevel@tonic-gate 		 * but will not appear in the input stream.
797c478bd9Sstevel@tonic-gate 		 *
807c478bd9Sstevel@tonic-gate 		 * The getexit/setexit contortions ensure that the
817c478bd9Sstevel@tonic-gate 		 * tty state will be restored if the user types ^C.
827c478bd9Sstevel@tonic-gate 		 */
837c478bd9Sstevel@tonic-gate 		(void) ioctl(SHIN, TCGETS,  (char *)&tty_save);
847c478bd9Sstevel@tonic-gate 		getexit(osetexit);
857c478bd9Sstevel@tonic-gate 		if (setjmp(reslab)) {
867c478bd9Sstevel@tonic-gate 			(void) ioctl(SHIN, TCSETSW,  (char *)&tty_save);
877c478bd9Sstevel@tonic-gate 			resexit(osetexit);
887c478bd9Sstevel@tonic-gate 			reset();
897c478bd9Sstevel@tonic-gate 		}
907c478bd9Sstevel@tonic-gate 		tty_new = tty_save;
917c478bd9Sstevel@tonic-gate 		tty_new.c_cc[VEOL] = ESC;
927c478bd9Sstevel@tonic-gate 		tty_new.c_iflag |= IMAXBEL | BRKINT | IGNPAR;
937c478bd9Sstevel@tonic-gate 		tty_new.c_lflag |= ICANON;
947c478bd9Sstevel@tonic-gate 		tty_new.c_lflag |= ECHOCTL;
957c478bd9Sstevel@tonic-gate 		tty_new.c_oflag &= ~OCRNL;
967c478bd9Sstevel@tonic-gate 		(void) ioctl(SHIN, TCSETSW,  (char *)&tty_new);
977c478bd9Sstevel@tonic-gate 	} else {
987c478bd9Sstevel@tonic-gate 		/*
997c478bd9Sstevel@tonic-gate 		 * Reset terminal state to what user had when invoked
1007c478bd9Sstevel@tonic-gate 		 */
1017c478bd9Sstevel@tonic-gate 		(void) ioctl(SHIN, TCSETSW,  (char *)&tty_save);
1027c478bd9Sstevel@tonic-gate 		resexit(osetexit);
1037c478bd9Sstevel@tonic-gate 	}
1047c478bd9Sstevel@tonic-gate 	(void) sigsetmask(omask);
1057c478bd9Sstevel@tonic-gate }
1067c478bd9Sstevel@tonic-gate 
1076c02b4a4Smuffin static void
termchars(void)1086c02b4a4Smuffin termchars(void)
1097c478bd9Sstevel@tonic-gate {
1107c478bd9Sstevel@tonic-gate 	extern char *tgetstr();
1116c02b4a4Smuffin 	char bp[1024];
1127c478bd9Sstevel@tonic-gate 	static char area[256];
1137c478bd9Sstevel@tonic-gate 	static int been_here = 0;
1146c02b4a4Smuffin 	char *ap = area;
1156c02b4a4Smuffin 	char *s;
1166c02b4a4Smuffin 	char *term;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate #ifdef TRACE
1197c478bd9Sstevel@tonic-gate 	tprintf("TRACE- termchars()\n");
1207c478bd9Sstevel@tonic-gate #endif
1217c478bd9Sstevel@tonic-gate 	if (been_here)
1227c478bd9Sstevel@tonic-gate 		return;
1237c478bd9Sstevel@tonic-gate 	been_here = TRUE;
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	if ((term = getenv("TERM")) == NULL)
1267c478bd9Sstevel@tonic-gate 		return;
1277c478bd9Sstevel@tonic-gate 	if (tgetent(bp, term) != 1)
1287c478bd9Sstevel@tonic-gate 		return;
1297c478bd9Sstevel@tonic-gate 	if (s = tgetstr("vb", &ap))		/* Visible Bell */
1307c478bd9Sstevel@tonic-gate 		BELL = s;
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate /*
1347c478bd9Sstevel@tonic-gate  * Move back to beginning of current line
1357c478bd9Sstevel@tonic-gate  */
1366c02b4a4Smuffin static void
back_to_col_1(void)1376c02b4a4Smuffin back_to_col_1(void)
1387c478bd9Sstevel@tonic-gate {
1397c478bd9Sstevel@tonic-gate 	int omask;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate #ifdef TRACE
1427c478bd9Sstevel@tonic-gate 	tprintf("TRACE- back_to_col_1()\n");
1437c478bd9Sstevel@tonic-gate #endif
1447c478bd9Sstevel@tonic-gate 	omask = sigblock(sigmask(SIGINT));
1457c478bd9Sstevel@tonic-gate 	(void) write(SHOUT, "\r", 1);
1467c478bd9Sstevel@tonic-gate 	(void) sigsetmask(omask);
1477c478bd9Sstevel@tonic-gate }
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate /*
1507c478bd9Sstevel@tonic-gate  * Push string contents back into tty queue
1517c478bd9Sstevel@tonic-gate  */
1526c02b4a4Smuffin static void
pushback(tchar * string,int echoflag)1536c02b4a4Smuffin pushback(tchar *string, int echoflag)
1547c478bd9Sstevel@tonic-gate {
1556c02b4a4Smuffin 	tchar *p;
1567c478bd9Sstevel@tonic-gate 	struct termios tty;
157*65b0c20eSnakanon 	int omask, retry = 0;
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate #ifdef TRACE
1607c478bd9Sstevel@tonic-gate 	tprintf("TRACE- pushback()\n");
1617c478bd9Sstevel@tonic-gate #endif
1627c478bd9Sstevel@tonic-gate 	omask = sigblock(sigmask(SIGINT));
1637c478bd9Sstevel@tonic-gate 	tty = tty_new;
1647c478bd9Sstevel@tonic-gate 	if (!echoflag)
1657c478bd9Sstevel@tonic-gate 		tty.c_lflag &= ~ECHO;
166*65b0c20eSnakanon 
167*65b0c20eSnakanon again:
1687c478bd9Sstevel@tonic-gate 	(void) ioctl(SHIN, TCSETSF, (char *)&tty);
1697c478bd9Sstevel@tonic-gate 
170*65b0c20eSnakanon 	for (p = string; *p; p++) {
1717c478bd9Sstevel@tonic-gate 		char	mbc[MB_LEN_MAX];
1727c478bd9Sstevel@tonic-gate 		int	i, j = wctomb(mbc, (wchar_t)*p);
173*65b0c20eSnakanon 
1747c478bd9Sstevel@tonic-gate 		if (j < 0) {
1757c478bd9Sstevel@tonic-gate 			/* Error! But else what can we do? */
1767c478bd9Sstevel@tonic-gate 			continue;
1777c478bd9Sstevel@tonic-gate 		}
1787c478bd9Sstevel@tonic-gate 		for (i = 0; i < j; ++i) {
179*65b0c20eSnakanon 			if (ioctl(SHIN, TIOCSTI, mbc + i) != 0 &&
180*65b0c20eSnakanon 			    errno == EAGAIN) {
181*65b0c20eSnakanon 				if (retry++ < 5)
182*65b0c20eSnakanon 					goto again;
183*65b0c20eSnakanon 				/* probably no worth retrying any more */
184*65b0c20eSnakanon 			}
1857c478bd9Sstevel@tonic-gate 		}
1867c478bd9Sstevel@tonic-gate 	}
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	if (tty.c_lflag != tty_new.c_lflag)
1897c478bd9Sstevel@tonic-gate 		(void) ioctl(SHIN, TCSETS,  (char *)&tty_new);
1907c478bd9Sstevel@tonic-gate 	(void) sigsetmask(omask);
1917c478bd9Sstevel@tonic-gate }
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate /*
1947c478bd9Sstevel@tonic-gate  * Concatenate src onto tail of des.
1957c478bd9Sstevel@tonic-gate  * Des is a string whose maximum length is count.
1967c478bd9Sstevel@tonic-gate  * Always null terminate.
1977c478bd9Sstevel@tonic-gate  */
1986c02b4a4Smuffin void
catn(tchar * des,tchar * src,int count)1996c02b4a4Smuffin catn(tchar *des, tchar *src, int count)
2007c478bd9Sstevel@tonic-gate {
2017c478bd9Sstevel@tonic-gate #ifdef TRACE
2027c478bd9Sstevel@tonic-gate 	tprintf("TRACE- catn()\n");
2037c478bd9Sstevel@tonic-gate #endif
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	while (--count >= 0 && *des)
2067c478bd9Sstevel@tonic-gate 		des++;
2077c478bd9Sstevel@tonic-gate 	while (--count >= 0)
2087c478bd9Sstevel@tonic-gate 		if ((*des++ = *src++) == '\0')
2097c478bd9Sstevel@tonic-gate 			return;
2107c478bd9Sstevel@tonic-gate 	*des = '\0';
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate 
2136c02b4a4Smuffin static int
max(a,b)2147c478bd9Sstevel@tonic-gate max(a, b)
2157c478bd9Sstevel@tonic-gate {
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	return (a > b ? a : b);
2187c478bd9Sstevel@tonic-gate }
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate /*
2217c478bd9Sstevel@tonic-gate  * Like strncpy but always leave room for trailing \0
2227c478bd9Sstevel@tonic-gate  * and always null terminate.
2237c478bd9Sstevel@tonic-gate  */
2246c02b4a4Smuffin void
copyn(tchar * des,tchar * src,int count)2256c02b4a4Smuffin copyn(tchar *des, tchar *src, int count)
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate #ifdef TRACE
2297c478bd9Sstevel@tonic-gate 	tprintf("TRACE- copyn()\n");
2307c478bd9Sstevel@tonic-gate #endif
2317c478bd9Sstevel@tonic-gate 	while (--count >= 0)
2327c478bd9Sstevel@tonic-gate 		if ((*des++ = *src++) == '\0')
2337c478bd9Sstevel@tonic-gate 			return;
2347c478bd9Sstevel@tonic-gate 	*des = '\0';
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate /*
2387c478bd9Sstevel@tonic-gate  * For qsort()
2397c478bd9Sstevel@tonic-gate  */
2406c02b4a4Smuffin static int
fcompare(tchar ** file1,tchar ** file2)2416c02b4a4Smuffin fcompare(tchar **file1, tchar **file2)
2427c478bd9Sstevel@tonic-gate {
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate #ifdef TRACE
2457c478bd9Sstevel@tonic-gate 	tprintf("TRACE- fcompare()\n");
2467c478bd9Sstevel@tonic-gate #endif
2477c478bd9Sstevel@tonic-gate 	return (strcoll_(*file1, *file2));
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate static char
filetype(tchar * dir,tchar * file,int nosym)2516c02b4a4Smuffin filetype(tchar *dir, tchar *file, int nosym)
2527c478bd9Sstevel@tonic-gate {
2537c478bd9Sstevel@tonic-gate 	tchar path[MAXPATHLEN + 1];
2547c478bd9Sstevel@tonic-gate 	struct stat statb;
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate #ifdef TRACE
2577c478bd9Sstevel@tonic-gate 	tprintf("TRACE- filetype()\n");
2587c478bd9Sstevel@tonic-gate #endif
2597c478bd9Sstevel@tonic-gate 	if (dir) {
2607c478bd9Sstevel@tonic-gate 		catn(strcpy_(path, dir), file, MAXPATHLEN);
2617c478bd9Sstevel@tonic-gate 		if (nosym) {
2627c478bd9Sstevel@tonic-gate 			if (stat_(path, &statb) < 0)
2637c478bd9Sstevel@tonic-gate 				return (' ');
2647c478bd9Sstevel@tonic-gate 		} else {
2657c478bd9Sstevel@tonic-gate 			if (lstat_(path, &statb) < 0)
2667c478bd9Sstevel@tonic-gate 				return (' ');
2677c478bd9Sstevel@tonic-gate 		}
2687c478bd9Sstevel@tonic-gate 		if ((statb.st_mode & S_IFMT) == S_IFLNK)
2697c478bd9Sstevel@tonic-gate 			return ('@');
2707c478bd9Sstevel@tonic-gate 		if ((statb.st_mode & S_IFMT) == S_IFDIR)
2717c478bd9Sstevel@tonic-gate 			return ('/');
2727c478bd9Sstevel@tonic-gate 		if (((statb.st_mode & S_IFMT) == S_IFREG) &&
2737c478bd9Sstevel@tonic-gate 		    (statb.st_mode & 011))
2747c478bd9Sstevel@tonic-gate 			return ('*');
2757c478bd9Sstevel@tonic-gate 	}
2767c478bd9Sstevel@tonic-gate 	return (' ');
2777c478bd9Sstevel@tonic-gate }
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate /*
2807c478bd9Sstevel@tonic-gate  * Print sorted down columns
2817c478bd9Sstevel@tonic-gate  */
2826c02b4a4Smuffin static void
print_by_column(tchar * dir,tchar * items[],int count,int looking_for_command)2836c02b4a4Smuffin print_by_column(tchar *dir, tchar *items[], int count, int looking_for_command)
2847c478bd9Sstevel@tonic-gate {
2856c02b4a4Smuffin 	int i, rows, r, c, maxwidth = 0, columns;
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate #ifdef TRACE
2887c478bd9Sstevel@tonic-gate 	tprintf("TRACE- print_by_column()\n");
2897c478bd9Sstevel@tonic-gate #endif
2907c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++)
2917c478bd9Sstevel@tonic-gate 		maxwidth = max(maxwidth, tswidth(items[i]));
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	/* for the file tag and space */
2947c478bd9Sstevel@tonic-gate 	maxwidth += looking_for_command ? 1 : 2;
2957c478bd9Sstevel@tonic-gate 	columns = max(78 / maxwidth, 1);
2967c478bd9Sstevel@tonic-gate 	rows = (count + (columns - 1)) / columns;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	for (r = 0; r < rows; r++) {
2997c478bd9Sstevel@tonic-gate 		for (c = 0; c < columns; c++) {
3007c478bd9Sstevel@tonic-gate 			i = c * rows + r;
3017c478bd9Sstevel@tonic-gate 			if (i < count) {
3026c02b4a4Smuffin 				int w;
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 				/*
3057c478bd9Sstevel@tonic-gate 				 * Print filename followed by
3067c478bd9Sstevel@tonic-gate 				 * '@' or '/' or '*' or ' '
3077c478bd9Sstevel@tonic-gate 				 */
3087c478bd9Sstevel@tonic-gate 				printf("%t", items[i]);
3097c478bd9Sstevel@tonic-gate 				w = tswidth(items[i]);
3107c478bd9Sstevel@tonic-gate 				if (!looking_for_command) {
3117c478bd9Sstevel@tonic-gate 					printf("%c",
3127c478bd9Sstevel@tonic-gate 					    (tchar) filetype(dir, items[i], 0));
3137c478bd9Sstevel@tonic-gate 					w++;
3147c478bd9Sstevel@tonic-gate 				}
3157c478bd9Sstevel@tonic-gate 				if (c < columns - 1)	/* last column? */
3167c478bd9Sstevel@tonic-gate 					for (; w < maxwidth; w++)
3177c478bd9Sstevel@tonic-gate 						printf(" ");
3187c478bd9Sstevel@tonic-gate 			}
3197c478bd9Sstevel@tonic-gate 		}
3207c478bd9Sstevel@tonic-gate 		printf("\n");
3217c478bd9Sstevel@tonic-gate 	}
3227c478bd9Sstevel@tonic-gate }
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate /*
3257c478bd9Sstevel@tonic-gate  * Expand file name with possible tilde usage
3267c478bd9Sstevel@tonic-gate  *	~person/mumble
3277c478bd9Sstevel@tonic-gate  * expands to
3287c478bd9Sstevel@tonic-gate  *	home_directory_of_person/mumble
3297c478bd9Sstevel@tonic-gate  */
3307c478bd9Sstevel@tonic-gate tchar *
tilde(tchar * new,tchar * old)3316c02b4a4Smuffin tilde(tchar *new, tchar *old)
3327c478bd9Sstevel@tonic-gate {
3336c02b4a4Smuffin 	tchar *o, *p;
3346c02b4a4Smuffin 	struct passwd *pw;
3357c478bd9Sstevel@tonic-gate 	static tchar person[40];
3367c478bd9Sstevel@tonic-gate 	char person_[40];		/* work */
3377c478bd9Sstevel@tonic-gate 	tchar *pw_dir;			/* work */
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate #ifdef TRACE
3407c478bd9Sstevel@tonic-gate 	tprintf("TRACE- tilde()\n");
3417c478bd9Sstevel@tonic-gate #endif
3427c478bd9Sstevel@tonic-gate 	if (old[0] != '~')
3437c478bd9Sstevel@tonic-gate 		return (strcpy_(new, old));
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	for (p = person, o = &old[1]; *o && *o != '/'; *p++ = *o++)
3467c478bd9Sstevel@tonic-gate 		;
3477c478bd9Sstevel@tonic-gate 	*p = '\0';
3487c478bd9Sstevel@tonic-gate 	if (person[0] == '\0')
349*65b0c20eSnakanon 		(void) strcpy_(new, value(S_home /* "home" */));
3507c478bd9Sstevel@tonic-gate 	else {
351*65b0c20eSnakanon 		pw = getpwnam(tstostr(person_, person));
3527c478bd9Sstevel@tonic-gate 		if (pw == NULL)
3537c478bd9Sstevel@tonic-gate 			return (NULL);
3547c478bd9Sstevel@tonic-gate 		pw_dir = strtots((tchar *)NULL, pw->pw_dir);	/* allocate */
3557c478bd9Sstevel@tonic-gate 		(void) strcpy_(new, pw_dir);
3567c478bd9Sstevel@tonic-gate 		xfree(pw_dir);					/* free it */
3577c478bd9Sstevel@tonic-gate 	}
3587c478bd9Sstevel@tonic-gate 	(void) strcat_(new, o);
3597c478bd9Sstevel@tonic-gate 	return (new);
3607c478bd9Sstevel@tonic-gate }
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate /*
3637c478bd9Sstevel@tonic-gate  * Cause pending line to be printed
3647c478bd9Sstevel@tonic-gate  */
3656c02b4a4Smuffin static void
sim_retype(void)3666c02b4a4Smuffin sim_retype(void)
3677c478bd9Sstevel@tonic-gate {
3687c478bd9Sstevel@tonic-gate #ifdef notdef
3697c478bd9Sstevel@tonic-gate 	struct termios tty_pending;
370*65b0c20eSnakanon 
3717c478bd9Sstevel@tonic-gate #ifdef TRACE
3727c478bd9Sstevel@tonic-gate 	tprintf("TRACE- sim_retypr()\n");
3737c478bd9Sstevel@tonic-gate #endif
3747c478bd9Sstevel@tonic-gate 	tty_pending = tty_new;
3757c478bd9Sstevel@tonic-gate 	tty_pending.c_lflag |= PENDIN;
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	(void) ioctl(SHIN, TCSETS,  (char *)&tty_pending);
3787c478bd9Sstevel@tonic-gate #else
3797c478bd9Sstevel@tonic-gate #ifdef TRACE
3807c478bd9Sstevel@tonic-gate 	tprintf("TRACE- sim_retype()\n");
3817c478bd9Sstevel@tonic-gate #endif
3827c478bd9Sstevel@tonic-gate 	(void) write(SHOUT, CTRLR, strlen(CTRLR));
3837c478bd9Sstevel@tonic-gate 	printprompt();
3847c478bd9Sstevel@tonic-gate #endif
3857c478bd9Sstevel@tonic-gate }
3867c478bd9Sstevel@tonic-gate 
3876c02b4a4Smuffin static int
beep_outc(int c)3886c02b4a4Smuffin beep_outc(int c)
3896c02b4a4Smuffin {
3907c478bd9Sstevel@tonic-gate 	char	buf[1];
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 	buf[0] = c;
3937c478bd9Sstevel@tonic-gate 
394*65b0c20eSnakanon 	(void) write(SHOUT, buf, 1);
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	return 0;
3977c478bd9Sstevel@tonic-gate }
3987c478bd9Sstevel@tonic-gate 
3996c02b4a4Smuffin static void
beep(void)4006c02b4a4Smuffin beep(void)
4017c478bd9Sstevel@tonic-gate {
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate #ifdef TRACE
4047c478bd9Sstevel@tonic-gate 	tprintf("TRACE- beep()\n");
4057c478bd9Sstevel@tonic-gate #endif
406*65b0c20eSnakanon 	if (adrof(S_nobeep /* "nobeep" */) == 0)
407*65b0c20eSnakanon 		(void) tputs(BELL, 0, beep_outc);
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate /*
4117c478bd9Sstevel@tonic-gate  * Erase that silly ^[ and print the recognized part of the string.
4127c478bd9Sstevel@tonic-gate  */
4136c02b4a4Smuffin static void
print_recognized_stuff(tchar * recognized_part)4146c02b4a4Smuffin print_recognized_stuff(tchar *recognized_part)
4157c478bd9Sstevel@tonic-gate {
4167c478bd9Sstevel@tonic-gate 	int unit =  didfds ? 1 : SHOUT;
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate #ifdef TRACE
4197c478bd9Sstevel@tonic-gate 	tprintf("TRACE- print_recognized_stuff()\n");
4207c478bd9Sstevel@tonic-gate #endif
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	/*
4237c478bd9Sstevel@tonic-gate 	 * An optimized erasing of that silly ^[
4247c478bd9Sstevel@tonic-gate 	 *
4257c478bd9Sstevel@tonic-gate 	 * One would think that line speeds have become fast enough that this
4267c478bd9Sstevel@tonic-gate 	 * isn't necessary, but it turns out that the visual difference is
4277c478bd9Sstevel@tonic-gate 	 * quite noticeable.
4287c478bd9Sstevel@tonic-gate 	 */
429*65b0c20eSnakanon 	flush();
4307c478bd9Sstevel@tonic-gate 	switch (tswidth(recognized_part)) {
4317c478bd9Sstevel@tonic-gate 	case 0:
4327c478bd9Sstevel@tonic-gate 		/* erase two characters: ^[ */
4337c478bd9Sstevel@tonic-gate 		write(unit, "\b\b  \b\b", sizeof "\b\b  \b\b" - 1);
4347c478bd9Sstevel@tonic-gate 		break;
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	case 1:
4377c478bd9Sstevel@tonic-gate 		/* overstrike the ^, erase the [ */
4387c478bd9Sstevel@tonic-gate 		write(unit, "\b\b", 2);
4397c478bd9Sstevel@tonic-gate 		printf("%t", recognized_part);
4407c478bd9Sstevel@tonic-gate 		write(unit, "  \b\b", 4);
4417c478bd9Sstevel@tonic-gate 		break;
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	default:
4447c478bd9Sstevel@tonic-gate 		/* overstrike both characters ^[ */
4457c478bd9Sstevel@tonic-gate 		write(unit, "\b\b", 2);
4467c478bd9Sstevel@tonic-gate 		printf("%t", recognized_part);
4477c478bd9Sstevel@tonic-gate 		break;
4487c478bd9Sstevel@tonic-gate 	}
4497c478bd9Sstevel@tonic-gate 	flush();
4507c478bd9Sstevel@tonic-gate }
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate /*
4537c478bd9Sstevel@tonic-gate  * Parse full path in file into 2 parts: directory and file names
4547c478bd9Sstevel@tonic-gate  * Should leave final slash (/) at end of dir.
4557c478bd9Sstevel@tonic-gate  */
4566c02b4a4Smuffin static void
extract_dir_and_name(tchar * path,tchar * dir,tchar * name)4576c02b4a4Smuffin extract_dir_and_name(tchar *path, tchar *dir, tchar *name)
4587c478bd9Sstevel@tonic-gate {
4596c02b4a4Smuffin 	tchar  *p;
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate #ifdef TRACE
4627c478bd9Sstevel@tonic-gate 	tprintf("TRACE- extract_dir_and_name()\n");
4637c478bd9Sstevel@tonic-gate #endif
4647c478bd9Sstevel@tonic-gate 	p = rindex_(path, '/');
4657c478bd9Sstevel@tonic-gate 	if (p == NOSTR) {
4667c478bd9Sstevel@tonic-gate 		copyn(name, path, MAXNAMLEN);
4677c478bd9Sstevel@tonic-gate 		dir[0] = '\0';
4687c478bd9Sstevel@tonic-gate 	} else {
4697c478bd9Sstevel@tonic-gate 		copyn(name, ++p, MAXNAMLEN);
4707c478bd9Sstevel@tonic-gate 		copyn(dir, path, p - path);
4717c478bd9Sstevel@tonic-gate 	}
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate tchar *
getentry(DIR * dir_fd,int looking_for_lognames)4756c02b4a4Smuffin getentry(DIR *dir_fd, int looking_for_lognames)
4767c478bd9Sstevel@tonic-gate {
4776c02b4a4Smuffin 	struct passwd *pw;
4786c02b4a4Smuffin 	struct dirent *dirp;
4797c478bd9Sstevel@tonic-gate 	/*
4807c478bd9Sstevel@tonic-gate 	 * For char * -> tchar * Conversion
4817c478bd9Sstevel@tonic-gate 	 */
4827c478bd9Sstevel@tonic-gate 	static tchar strbuf[MAXNAMLEN+1];
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate #ifdef TRACE
4857c478bd9Sstevel@tonic-gate 	tprintf("TRACE- getentry()\n");
4867c478bd9Sstevel@tonic-gate #endif
4877c478bd9Sstevel@tonic-gate 	if (looking_for_lognames) {
488*65b0c20eSnakanon 		if ((pw = getpwent()) == NULL)
4897c478bd9Sstevel@tonic-gate 			return (NULL);
490*65b0c20eSnakanon 		return (strtots(strbuf, pw->pw_name));
4917c478bd9Sstevel@tonic-gate 	}
4927c478bd9Sstevel@tonic-gate 	if (dirp = readdir(dir_fd))
493*65b0c20eSnakanon 		return (strtots(strbuf, dirp->d_name));
4947c478bd9Sstevel@tonic-gate 	return (NULL);
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate 
4976c02b4a4Smuffin static void
free_items(tchar ** items)4986c02b4a4Smuffin free_items(tchar **items)
4997c478bd9Sstevel@tonic-gate {
5006c02b4a4Smuffin 	int i;
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate #ifdef TRACE
5037c478bd9Sstevel@tonic-gate 	tprintf("TRACE- free_items()\n");
5047c478bd9Sstevel@tonic-gate #endif
5057c478bd9Sstevel@tonic-gate 	for (i = 0; items[i]; i++)
506*65b0c20eSnakanon 		xfree(items[i]);
507*65b0c20eSnakanon 	xfree((char *)items);
5087c478bd9Sstevel@tonic-gate }
5097c478bd9Sstevel@tonic-gate 
510*65b0c20eSnakanon #define	FREE_ITEMS(items) { \
5117c478bd9Sstevel@tonic-gate 	int omask;\
5127c478bd9Sstevel@tonic-gate \
5137c478bd9Sstevel@tonic-gate 	omask = sigblock(sigmask(SIGINT));\
5147c478bd9Sstevel@tonic-gate 	free_items(items);\
5157c478bd9Sstevel@tonic-gate 	items = NULL;\
5167c478bd9Sstevel@tonic-gate 	(void) sigsetmask(omask);\
5177c478bd9Sstevel@tonic-gate }
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate /*
5207c478bd9Sstevel@tonic-gate  * Perform a RECOGNIZE or LIST command on string "word".
5217c478bd9Sstevel@tonic-gate  */
5226c02b4a4Smuffin static int
search2(tchar * word,COMMAND command,int max_word_length)5236c02b4a4Smuffin search2(tchar *word, COMMAND command, int max_word_length)
5247c478bd9Sstevel@tonic-gate {
5257c478bd9Sstevel@tonic-gate 	static tchar **items = NULL;
5266c02b4a4Smuffin 	DIR *dir_fd;
5276c02b4a4Smuffin 	int numitems = 0, ignoring = TRUE, nignored = 0;
5286c02b4a4Smuffin 	int name_length, looking_for_lognames;
5297c478bd9Sstevel@tonic-gate 	tchar tilded_dir[MAXPATHLEN + 1], dir[MAXPATHLEN + 1];
5307c478bd9Sstevel@tonic-gate 	tchar name[MAXNAMLEN + 1], extended_name[MAXNAMLEN+1];
5317c478bd9Sstevel@tonic-gate 	tchar *entry;
532*65b0c20eSnakanon #define	MAXITEMS 1024
5337c478bd9Sstevel@tonic-gate #ifdef TRACE
5347c478bd9Sstevel@tonic-gate 	tprintf("TRACE- search2()\n");
5357c478bd9Sstevel@tonic-gate #endif
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 	if (items != NULL)
5387c478bd9Sstevel@tonic-gate 		FREE_ITEMS(items);
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	looking_for_lognames = (*word == '~') && (index_(word, '/') == NULL);
5417c478bd9Sstevel@tonic-gate 	if (looking_for_lognames) {
5427c478bd9Sstevel@tonic-gate 		(void) setpwent();
5437c478bd9Sstevel@tonic-gate 		copyn(name, &word[1], MAXNAMLEN);	/* name sans ~ */
5447c478bd9Sstevel@tonic-gate 	} else {
5457c478bd9Sstevel@tonic-gate 		extract_dir_and_name(word, dir, name);
5467c478bd9Sstevel@tonic-gate 		if (tilde(tilded_dir, dir) == 0)
5477c478bd9Sstevel@tonic-gate 			return (0);
548*65b0c20eSnakanon 		dir_fd = opendir_(*tilded_dir ? tilded_dir : S_DOT /* "." */);
5497c478bd9Sstevel@tonic-gate 		if (dir_fd == NULL)
5507c478bd9Sstevel@tonic-gate 			return (0);
5517c478bd9Sstevel@tonic-gate 	}
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate again:	/* search for matches */
5547c478bd9Sstevel@tonic-gate 	name_length = strlen_(name);
5557c478bd9Sstevel@tonic-gate 	for (numitems = 0; entry = getentry(dir_fd, looking_for_lognames); ) {
5567c478bd9Sstevel@tonic-gate 		if (!is_prefix(name, entry))
5577c478bd9Sstevel@tonic-gate 			continue;
5587c478bd9Sstevel@tonic-gate 		/* Don't match . files on null prefix match */
5597c478bd9Sstevel@tonic-gate 		if (name_length == 0 && entry[0] == '.' &&
5607c478bd9Sstevel@tonic-gate 		    !looking_for_lognames)
5617c478bd9Sstevel@tonic-gate 			continue;
5627c478bd9Sstevel@tonic-gate 		if (command == LIST) {
5637c478bd9Sstevel@tonic-gate 			if (numitems >= MAXITEMS) {
564*65b0c20eSnakanon 				printf("\nYikes!! Too many %s!!\n",
5657c478bd9Sstevel@tonic-gate 				    looking_for_lognames ?
5667c478bd9Sstevel@tonic-gate 					"names in password file":"files");
5677c478bd9Sstevel@tonic-gate 				break;
5687c478bd9Sstevel@tonic-gate 			}
5697c478bd9Sstevel@tonic-gate 			if (items == NULL)
570*65b0c20eSnakanon 				items =  (tchar **)xcalloc(sizeof (items[1]),
5717c478bd9Sstevel@tonic-gate 				    MAXITEMS+1);
572*65b0c20eSnakanon 			items[numitems] = (tchar *)xalloc((unsigned)(strlen_(entry) + 1) * sizeof (tchar));
5737c478bd9Sstevel@tonic-gate 			copyn(items[numitems], entry, MAXNAMLEN);
5747c478bd9Sstevel@tonic-gate 			numitems++;
5757c478bd9Sstevel@tonic-gate 		} else {			/* RECOGNIZE command */
5767c478bd9Sstevel@tonic-gate 			if (ignoring && ignored(entry))
5777c478bd9Sstevel@tonic-gate 				nignored++;
5787c478bd9Sstevel@tonic-gate 			else if (recognize(extended_name,
5797c478bd9Sstevel@tonic-gate 			    entry, name_length, ++numitems))
5807c478bd9Sstevel@tonic-gate 				break;
5817c478bd9Sstevel@tonic-gate 		}
5827c478bd9Sstevel@tonic-gate 	}
5837c478bd9Sstevel@tonic-gate 	if (ignoring && numitems == 0 && nignored > 0) {
5847c478bd9Sstevel@tonic-gate 		ignoring = FALSE;
5857c478bd9Sstevel@tonic-gate 		nignored = 0;
5867c478bd9Sstevel@tonic-gate 		if (looking_for_lognames)
587*65b0c20eSnakanon 			(void) setpwent();
5887c478bd9Sstevel@tonic-gate 		else
5897c478bd9Sstevel@tonic-gate 			rewinddir(dir_fd);
5907c478bd9Sstevel@tonic-gate 		goto again;
5917c478bd9Sstevel@tonic-gate 	}
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 	if (looking_for_lognames)
5947c478bd9Sstevel@tonic-gate 		(void) endpwent();
5957c478bd9Sstevel@tonic-gate 	else {
5967c478bd9Sstevel@tonic-gate 		unsetfd(dir_fd->dd_fd);
5977c478bd9Sstevel@tonic-gate 		closedir_(dir_fd);
5987c478bd9Sstevel@tonic-gate 	}
5997c478bd9Sstevel@tonic-gate 	if (command == RECOGNIZE && numitems > 0) {
6007c478bd9Sstevel@tonic-gate 		if (looking_for_lognames)
601*65b0c20eSnakanon 			copyn(word, S_TIL /* "~" */, 1);
6027c478bd9Sstevel@tonic-gate 		else
6037c478bd9Sstevel@tonic-gate 			/* put back dir part */
6047c478bd9Sstevel@tonic-gate 			copyn(word, dir, max_word_length);
6057c478bd9Sstevel@tonic-gate 		/* add extended name */
6067c478bd9Sstevel@tonic-gate 		catn(word, extended_name, max_word_length);
6077c478bd9Sstevel@tonic-gate 		return (numitems);
6087c478bd9Sstevel@tonic-gate 	}
6097c478bd9Sstevel@tonic-gate 	if (command == LIST) {
610*65b0c20eSnakanon 		qsort((char *)items, numitems, sizeof (items[1]),
611*65b0c20eSnakanon 		    (int (*)(const void *, const void *))fcompare);
6127c478bd9Sstevel@tonic-gate 		/*
6137c478bd9Sstevel@tonic-gate 		 * Never looking for commands in this version, so final
6147c478bd9Sstevel@tonic-gate 		 * argument forced to 0.  If command name completion is
6157c478bd9Sstevel@tonic-gate 		 * reinstated, this must change.
6167c478bd9Sstevel@tonic-gate 		 */
6177c478bd9Sstevel@tonic-gate 		print_by_column(looking_for_lognames ? NULL : tilded_dir,
6187c478bd9Sstevel@tonic-gate 		    items, numitems, 0);
6197c478bd9Sstevel@tonic-gate 		if (items != NULL)
6207c478bd9Sstevel@tonic-gate 			FREE_ITEMS(items);
6217c478bd9Sstevel@tonic-gate 	}
6227c478bd9Sstevel@tonic-gate 	return (0);
6237c478bd9Sstevel@tonic-gate }
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate /*
6267c478bd9Sstevel@tonic-gate  * Object: extend what user typed up to an ambiguity.
6277c478bd9Sstevel@tonic-gate  * Algorithm:
628*65b0c20eSnakanon  * On first match, copy full entry (assume it'll be the only match)
6297c478bd9Sstevel@tonic-gate  * On subsequent matches, shorten extended_name to the first
6307c478bd9Sstevel@tonic-gate  * character mismatch between extended_name and entry.
6317c478bd9Sstevel@tonic-gate  * If we shorten it back to the prefix length, stop searching.
6327c478bd9Sstevel@tonic-gate  */
6336c02b4a4Smuffin int
recognize(tchar * extended_name,tchar * entry,int name_length,int numitems)6346c02b4a4Smuffin recognize(tchar *extended_name, tchar *entry, int name_length, int numitems)
6357c478bd9Sstevel@tonic-gate {
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate #ifdef TRACE
6387c478bd9Sstevel@tonic-gate 	tprintf("TRACE- recognize()\n");
6397c478bd9Sstevel@tonic-gate #endif
6407c478bd9Sstevel@tonic-gate 	if (numitems == 1)				/* 1st match */
6417c478bd9Sstevel@tonic-gate 		copyn(extended_name, entry, MAXNAMLEN);
6427c478bd9Sstevel@tonic-gate 	else {					/* 2nd and subsequent matches */
6436c02b4a4Smuffin 		tchar *x, *ent;
6446c02b4a4Smuffin 		int len = 0;
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 		x = extended_name;
6477c478bd9Sstevel@tonic-gate 		for (ent = entry; *x && *x == *ent++; x++, len++)
6487c478bd9Sstevel@tonic-gate 			;
6497c478bd9Sstevel@tonic-gate 		*x = '\0';			/* Shorten at 1st char diff */
6507c478bd9Sstevel@tonic-gate 		if (len == name_length)		/* Ambiguous to prefix? */
6517c478bd9Sstevel@tonic-gate 			return (-1);		/* So stop now and save time */
6527c478bd9Sstevel@tonic-gate 	}
6537c478bd9Sstevel@tonic-gate 	return (0);
6547c478bd9Sstevel@tonic-gate }
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate /*
6577c478bd9Sstevel@tonic-gate  * Return true if check items initial chars in template
6587c478bd9Sstevel@tonic-gate  * This differs from PWB imatch in that if check is null
6597c478bd9Sstevel@tonic-gate  * it items anything
6607c478bd9Sstevel@tonic-gate  */
6616c02b4a4Smuffin static int
is_prefix(tchar * check,tchar * template)6626c02b4a4Smuffin is_prefix(tchar *check, tchar *template)
6637c478bd9Sstevel@tonic-gate {
6647c478bd9Sstevel@tonic-gate #ifdef TRACE
6657c478bd9Sstevel@tonic-gate 	tprintf("TRACE- is_prefix()\n");
6667c478bd9Sstevel@tonic-gate #endif
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	do
6697c478bd9Sstevel@tonic-gate 		if (*check == 0)
6707c478bd9Sstevel@tonic-gate 			return (TRUE);
6717c478bd9Sstevel@tonic-gate 	while (*check++ == *template++);
6727c478bd9Sstevel@tonic-gate 	return (FALSE);
6737c478bd9Sstevel@tonic-gate }
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate /*
6767c478bd9Sstevel@tonic-gate  *  Return true if the chars in template appear at the
6777c478bd9Sstevel@tonic-gate  *  end of check, i.e., are its suffix.
6787c478bd9Sstevel@tonic-gate  */
6796c02b4a4Smuffin static int
is_suffix(tchar * check,tchar * template)6806c02b4a4Smuffin is_suffix(tchar *check, tchar *template)
6817c478bd9Sstevel@tonic-gate {
6826c02b4a4Smuffin 	tchar *c, *t;
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate #ifdef TRACE
6857c478bd9Sstevel@tonic-gate 	tprintf("TRACE- is_suffix()\n");
6867c478bd9Sstevel@tonic-gate #endif
687*65b0c20eSnakanon 	for (c = check; *c++; )
6887c478bd9Sstevel@tonic-gate 		;
689*65b0c20eSnakanon 	for (t = template; *t++; )
6907c478bd9Sstevel@tonic-gate 		;
6917c478bd9Sstevel@tonic-gate 	for (;;) {
6927c478bd9Sstevel@tonic-gate 		if (t == template)
6937c478bd9Sstevel@tonic-gate 			return (TRUE);
6947c478bd9Sstevel@tonic-gate 		if (c == check || *--t != *--c)
6957c478bd9Sstevel@tonic-gate 			return (FALSE);
6967c478bd9Sstevel@tonic-gate 	}
6977c478bd9Sstevel@tonic-gate }
6987c478bd9Sstevel@tonic-gate 
6996c02b4a4Smuffin int
tenex(tchar * inputline,int inputline_size)7006c02b4a4Smuffin tenex(tchar *inputline, int inputline_size)
7017c478bd9Sstevel@tonic-gate {
7026c02b4a4Smuffin 	int numitems, num_read, should_retype;
7037c478bd9Sstevel@tonic-gate 	int i;
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate #ifdef TRACE
7067c478bd9Sstevel@tonic-gate 	tprintf("TRACE- tenex()\n");
7077c478bd9Sstevel@tonic-gate #endif
7087c478bd9Sstevel@tonic-gate 	setup_tty(ON);
7097c478bd9Sstevel@tonic-gate 	termchars();
7107c478bd9Sstevel@tonic-gate 	num_read = 0;
7117c478bd9Sstevel@tonic-gate 	should_retype = FALSE;
7127c478bd9Sstevel@tonic-gate 	while ((i = read_(SHIN, inputline+num_read, inputline_size-num_read))
7137c478bd9Sstevel@tonic-gate 	    > 0) {
714*65b0c20eSnakanon 		static tchar *delims = S_DELIM /* " '\"\t;&<>()|`" */;
7156c02b4a4Smuffin 		tchar *str_end, *word_start, last_char;
7166c02b4a4Smuffin 		int space_left;
7177c478bd9Sstevel@tonic-gate 		struct termios tty;
7187c478bd9Sstevel@tonic-gate 		COMMAND command;
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 		num_read += i;
7217c478bd9Sstevel@tonic-gate 		inputline[num_read] = '\0';
7227c478bd9Sstevel@tonic-gate 		last_char = inputline[num_read - 1] & TRIM;
7237c478bd9Sstevel@tonic-gate 
724*65b0c20eSnakanon 		/*
725*65b0c20eSnakanon 		 * read_() can return more than requested size if there
726*65b0c20eSnakanon 		 * is multibyte character at the end.
727*65b0c20eSnakanon 		 */
728*65b0c20eSnakanon 		if ((num_read >= inputline_size) || (last_char == '\n'))
7297c478bd9Sstevel@tonic-gate 			break;
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 		str_end = &inputline[num_read];
7327c478bd9Sstevel@tonic-gate 		if (last_char == ESC) {
7337c478bd9Sstevel@tonic-gate 			command = RECOGNIZE;
7347c478bd9Sstevel@tonic-gate 			*--str_end = '\0';	/* wipe out trailing ESC */
7357c478bd9Sstevel@tonic-gate 		} else
7367c478bd9Sstevel@tonic-gate 			command = LIST;
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 		tty = tty_new;
7397c478bd9Sstevel@tonic-gate 		tty.c_lflag &= ~ECHO;
7407c478bd9Sstevel@tonic-gate 		(void) ioctl(SHIN, TCSETSF, (char *)&tty);
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 		if (command == LIST)
7437c478bd9Sstevel@tonic-gate 			printf("\n");
7447c478bd9Sstevel@tonic-gate 		/*
7457c478bd9Sstevel@tonic-gate 		 * Find LAST occurence of a delimiter in the inputline.
7467c478bd9Sstevel@tonic-gate 		 * The word start is one character past it.
7477c478bd9Sstevel@tonic-gate 		 */
7487c478bd9Sstevel@tonic-gate 		for (word_start = str_end; word_start > inputline;
7497c478bd9Sstevel@tonic-gate 		    --word_start) {
7507c478bd9Sstevel@tonic-gate 			if (index_(delims, word_start[-1]) ||
7517c478bd9Sstevel@tonic-gate 			    isauxsp(word_start[-1]))
7527c478bd9Sstevel@tonic-gate 				break;
7537c478bd9Sstevel@tonic-gate 		}
7547c478bd9Sstevel@tonic-gate 		space_left = inputline_size - (word_start - inputline) - 1;
7557c478bd9Sstevel@tonic-gate 		numitems = search2(word_start, command, space_left);
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 		/*
7587c478bd9Sstevel@tonic-gate 		 * Tabs in the input line cause trouble after a pushback.
7597c478bd9Sstevel@tonic-gate 		 * tty driver won't backspace over them because column
7607c478bd9Sstevel@tonic-gate 		 * positions are now incorrect. This is solved by retyping
7617c478bd9Sstevel@tonic-gate 		 * over current line.
7627c478bd9Sstevel@tonic-gate 		 */
7637c478bd9Sstevel@tonic-gate 		if (index_(inputline, '\t')) {	/* tab tchar in input line? */
7647c478bd9Sstevel@tonic-gate 			back_to_col_1();
7657c478bd9Sstevel@tonic-gate 			should_retype = TRUE;
7667c478bd9Sstevel@tonic-gate 		}
7677c478bd9Sstevel@tonic-gate 		if (command == LIST)		/* Always retype after a LIST */
7687c478bd9Sstevel@tonic-gate 			should_retype = TRUE;
7697c478bd9Sstevel@tonic-gate 		if (should_retype)
7707c478bd9Sstevel@tonic-gate 			printprompt();
7717c478bd9Sstevel@tonic-gate 		pushback(inputline, should_retype);
7727c478bd9Sstevel@tonic-gate 		num_read = 0;			/* chars will be reread */
7737c478bd9Sstevel@tonic-gate 		should_retype = FALSE;
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 		/*
7767c478bd9Sstevel@tonic-gate 		 * Avoid a race condition by echoing what we're recognized
7777c478bd9Sstevel@tonic-gate 		 * _after_ pushing back the command line.  This way, if the
7787c478bd9Sstevel@tonic-gate 		 * user waits until seeing this output before typing more
7797c478bd9Sstevel@tonic-gate 		 * stuff, the resulting keystrokes won't race with the STIed
7807c478bd9Sstevel@tonic-gate 		 * input we've pushed back.  (Of course, if the user types
7817c478bd9Sstevel@tonic-gate 		 * ahead, the race still exists and it's quite possible that
7827c478bd9Sstevel@tonic-gate 		 * the pushed back input line will interleave with the
7837c478bd9Sstevel@tonic-gate 		 * keystrokes in unexpected ways.)
7847c478bd9Sstevel@tonic-gate 		 */
7857c478bd9Sstevel@tonic-gate 		if (command == RECOGNIZE) {
7867c478bd9Sstevel@tonic-gate 			/* print from str_end on */
7877c478bd9Sstevel@tonic-gate 			print_recognized_stuff(str_end);
7887c478bd9Sstevel@tonic-gate 			if (numitems != 1)	/* Beep = No match/ambiguous */
7897c478bd9Sstevel@tonic-gate 				beep();
7907c478bd9Sstevel@tonic-gate 		}
7917c478bd9Sstevel@tonic-gate 	}
7927c478bd9Sstevel@tonic-gate 	setup_tty(OFF);
7937c478bd9Sstevel@tonic-gate 	return (num_read);
7947c478bd9Sstevel@tonic-gate }
7957c478bd9Sstevel@tonic-gate 
7966c02b4a4Smuffin static int
ignored(tchar * entry)7976c02b4a4Smuffin ignored(tchar *entry)
7987c478bd9Sstevel@tonic-gate {
7997c478bd9Sstevel@tonic-gate 	struct varent *vp;
8006c02b4a4Smuffin 	tchar **cp;
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate #ifdef TRACE
8037c478bd9Sstevel@tonic-gate 	tprintf("TRACE- ignored()\n");
8047c478bd9Sstevel@tonic-gate #endif
805*65b0c20eSnakanon 	if ((vp = adrof(S_fignore /* "fignore" */)) == NULL ||
8067c478bd9Sstevel@tonic-gate 	    (cp = vp->vec) == NULL)
8077c478bd9Sstevel@tonic-gate 		return (FALSE);
8087c478bd9Sstevel@tonic-gate 	for (; *cp != NULL; cp++)
8097c478bd9Sstevel@tonic-gate 		if (is_suffix(entry, *cp))
8107c478bd9Sstevel@tonic-gate 			return (TRUE);
8117c478bd9Sstevel@tonic-gate 	return (FALSE);
8127c478bd9Sstevel@tonic-gate }
8136c02b4a4Smuffin #endif /* FILEC */
814