xref: /illumos-gate/usr/src/cmd/csh/sh.file.c (revision 65b0c20e)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
167c478bd9Sstevel@tonic-gate 
177c478bd9Sstevel@tonic-gate #ifdef FILEC
187c478bd9Sstevel@tonic-gate /*
197c478bd9Sstevel@tonic-gate  * Tenex style file name recognition, .. and more.
207c478bd9Sstevel@tonic-gate  * History:
217c478bd9Sstevel@tonic-gate  *	Author: Ken Greer, Sept. 1975, CMU.
227c478bd9Sstevel@tonic-gate  *	Finally got around to adding to the Cshell., Ken Greer, Dec. 1981.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #include "sh.h"
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <dirent.h>
287c478bd9Sstevel@tonic-gate #include <pwd.h>
297c478bd9Sstevel@tonic-gate #include "sh.tconst.h"
307c478bd9Sstevel@tonic-gate 
31*65b0c20eSnakanon #define	TRUE	1
32*65b0c20eSnakanon #define	FALSE	0
33*65b0c20eSnakanon #define	ON	1
34*65b0c20eSnakanon #define	OFF	0
357c478bd9Sstevel@tonic-gate 
36*65b0c20eSnakanon #define	ESC	'\033'
377c478bd9Sstevel@tonic-gate 
386c02b4a4Smuffin extern DIR *opendir_(tchar *);
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate static char *BELL = "\07";
417c478bd9Sstevel@tonic-gate static char *CTRLR = "^R\n";
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate typedef enum {LIST, RECOGNIZE} COMMAND;
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate static jmp_buf osetexit;		/* saved setexit() state */
467c478bd9Sstevel@tonic-gate static struct termios  tty_save;	/* saved terminal state */
477c478bd9Sstevel@tonic-gate static struct termios  tty_new;		/* new terminal state */
487c478bd9Sstevel@tonic-gate 
496c02b4a4Smuffin static int	is_prefix(tchar *, tchar *);
506c02b4a4Smuffin static int	is_suffix(tchar *, tchar *);
516c02b4a4Smuffin static int	ignored(tchar *);
526c02b4a4Smuffin 
537c478bd9Sstevel@tonic-gate /*
547c478bd9Sstevel@tonic-gate  * Put this here so the binary can be patched with adb to enable file
557c478bd9Sstevel@tonic-gate  * completion by default.  Filec controls completion, nobeep controls
567c478bd9Sstevel@tonic-gate  * ringing the terminal bell on incomplete expansions.
577c478bd9Sstevel@tonic-gate  */
587c478bd9Sstevel@tonic-gate bool filec = 0;
597c478bd9Sstevel@tonic-gate 
606c02b4a4Smuffin static void
setup_tty(int on)616c02b4a4Smuffin setup_tty(int on)
627c478bd9Sstevel@tonic-gate {
637c478bd9Sstevel@tonic-gate 	int omask;
647c478bd9Sstevel@tonic-gate #ifdef TRACE
657c478bd9Sstevel@tonic-gate 	tprintf("TRACE- setup_tty()\n");
667c478bd9Sstevel@tonic-gate #endif
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate 	omask = sigblock(sigmask(SIGINT));
697c478bd9Sstevel@tonic-gate 	if (on) {
707c478bd9Sstevel@tonic-gate 		/*
717c478bd9Sstevel@tonic-gate 		 * The shell makes sure that the tty is not in some weird state
727c478bd9Sstevel@tonic-gate 		 * and fixes it if it is.  But it should be noted that the
737c478bd9Sstevel@tonic-gate 		 * tenex routine will not work correctly in CBREAK or RAW mode
747c478bd9Sstevel@tonic-gate 		 * so this code below is, therefore, mandatory.
757c478bd9Sstevel@tonic-gate 		 *
767c478bd9Sstevel@tonic-gate 		 * Also, in order to recognize the ESC (filename-completion)
777c478bd9Sstevel@tonic-gate 		 * character, set EOL to ESC.  This way, ESC will terminate
787c478bd9Sstevel@tonic-gate 		 * the line, but still be in the input stream.
797c478bd9Sstevel@tonic-gate 		 * EOT (filename list) will also terminate the line,
807c478bd9Sstevel@tonic-gate 		 * but will not appear in the input stream.
817c478bd9Sstevel@tonic-gate 		 *
827c478bd9Sstevel@tonic-gate 		 * The getexit/setexit contortions ensure that the
837c478bd9Sstevel@tonic-gate 		 * tty state will be restored if the user types ^C.
847c478bd9Sstevel@tonic-gate 		 */
857c478bd9Sstevel@tonic-gate 		(void) ioctl(SHIN, TCGETS,  (char *)&tty_save);
867c478bd9Sstevel@tonic-gate 		getexit(osetexit);
877c478bd9Sstevel@tonic-gate 		if (setjmp(reslab)) {
887c478bd9Sstevel@tonic-gate 			(void) ioctl(SHIN, TCSETSW,  (char *)&tty_save);
897c478bd9Sstevel@tonic-gate 			resexit(osetexit);
907c478bd9Sstevel@tonic-gate 			reset();
917c478bd9Sstevel@tonic-gate 		}
927c478bd9Sstevel@tonic-gate 		tty_new = tty_save;
937c478bd9Sstevel@tonic-gate 		tty_new.c_cc[VEOL] = ESC;
947c478bd9Sstevel@tonic-gate 		tty_new.c_iflag |= IMAXBEL | BRKINT | IGNPAR;
957c478bd9Sstevel@tonic-gate 		tty_new.c_lflag |= ICANON;
967c478bd9Sstevel@tonic-gate 		tty_new.c_lflag |= ECHOCTL;
977c478bd9Sstevel@tonic-gate 		tty_new.c_oflag &= ~OCRNL;
987c478bd9Sstevel@tonic-gate 		(void) ioctl(SHIN, TCSETSW,  (char *)&tty_new);
997c478bd9Sstevel@tonic-gate 	} else {
1007c478bd9Sstevel@tonic-gate 		/*
1017c478bd9Sstevel@tonic-gate 		 * Reset terminal state to what user had when invoked
1027c478bd9Sstevel@tonic-gate 		 */
1037c478bd9Sstevel@tonic-gate 		(void) ioctl(SHIN, TCSETSW,  (char *)&tty_save);
1047c478bd9Sstevel@tonic-gate 		resexit(osetexit);
1057c478bd9Sstevel@tonic-gate 	}
1067c478bd9Sstevel@tonic-gate 	(void) sigsetmask(omask);
1077c478bd9Sstevel@tonic-gate }
1087c478bd9Sstevel@tonic-gate 
1096c02b4a4Smuffin static void
termchars(void)1106c02b4a4Smuffin termchars(void)
1117c478bd9Sstevel@tonic-gate {
1127c478bd9Sstevel@tonic-gate 	extern char *tgetstr();
1136c02b4a4Smuffin 	char bp[1024];
1147c478bd9Sstevel@tonic-gate 	static char area[256];
1157c478bd9Sstevel@tonic-gate 	static int been_here = 0;
1166c02b4a4Smuffin 	char *ap = area;
1176c02b4a4Smuffin 	char *s;
1186c02b4a4Smuffin 	char *term;
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate #ifdef TRACE
1217c478bd9Sstevel@tonic-gate 	tprintf("TRACE- termchars()\n");
1227c478bd9Sstevel@tonic-gate #endif
1237c478bd9Sstevel@tonic-gate 	if (been_here)
1247c478bd9Sstevel@tonic-gate 		return;
1257c478bd9Sstevel@tonic-gate 	been_here = TRUE;
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	if ((term = getenv("TERM")) == NULL)
1287c478bd9Sstevel@tonic-gate 		return;
1297c478bd9Sstevel@tonic-gate 	if (tgetent(bp, term) != 1)
1307c478bd9Sstevel@tonic-gate 		return;
1317c478bd9Sstevel@tonic-gate 	if (s = tgetstr("vb", &ap))		/* Visible Bell */
1327c478bd9Sstevel@tonic-gate 		BELL = s;
1337c478bd9Sstevel@tonic-gate }
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate /*
1367c478bd9Sstevel@tonic-gate  * Move back to beginning of current line
1377c478bd9Sstevel@tonic-gate  */
1386c02b4a4Smuffin static void
back_to_col_1(void)1396c02b4a4Smuffin back_to_col_1(void)
1407c478bd9Sstevel@tonic-gate {
1417c478bd9Sstevel@tonic-gate 	int omask;
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate #ifdef TRACE
1447c478bd9Sstevel@tonic-gate 	tprintf("TRACE- back_to_col_1()\n");
1457c478bd9Sstevel@tonic-gate #endif
1467c478bd9Sstevel@tonic-gate 	omask = sigblock(sigmask(SIGINT));
1477c478bd9Sstevel@tonic-gate 	(void) write(SHOUT, "\r", 1);
1487c478bd9Sstevel@tonic-gate 	(void) sigsetmask(omask);
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate /*
1527c478bd9Sstevel@tonic-gate  * Push string contents back into tty queue
1537c478bd9Sstevel@tonic-gate  */
1546c02b4a4Smuffin static void
pushback(tchar * string,int echoflag)1556c02b4a4Smuffin pushback(tchar *string, int echoflag)
1567c478bd9Sstevel@tonic-gate {
1576c02b4a4Smuffin 	tchar *p;
1587c478bd9Sstevel@tonic-gate 	struct termios tty;
159*65b0c20eSnakanon 	int omask, retry = 0;
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate #ifdef TRACE
1627c478bd9Sstevel@tonic-gate 	tprintf("TRACE- pushback()\n");
1637c478bd9Sstevel@tonic-gate #endif
1647c478bd9Sstevel@tonic-gate 	omask = sigblock(sigmask(SIGINT));
1657c478bd9Sstevel@tonic-gate 	tty = tty_new;
1667c478bd9Sstevel@tonic-gate 	if (!echoflag)
1677c478bd9Sstevel@tonic-gate 		tty.c_lflag &= ~ECHO;
168*65b0c20eSnakanon 
169*65b0c20eSnakanon again:
1707c478bd9Sstevel@tonic-gate 	(void) ioctl(SHIN, TCSETSF, (char *)&tty);
1717c478bd9Sstevel@tonic-gate 
172*65b0c20eSnakanon 	for (p = string; *p; p++) {
1737c478bd9Sstevel@tonic-gate 		char	mbc[MB_LEN_MAX];
1747c478bd9Sstevel@tonic-gate 		int	i, j = wctomb(mbc, (wchar_t)*p);
175*65b0c20eSnakanon 
1767c478bd9Sstevel@tonic-gate 		if (j < 0) {
1777c478bd9Sstevel@tonic-gate 			/* Error! But else what can we do? */
1787c478bd9Sstevel@tonic-gate 			continue;
1797c478bd9Sstevel@tonic-gate 		}
1807c478bd9Sstevel@tonic-gate 		for (i = 0; i < j; ++i) {
181*65b0c20eSnakanon 			if (ioctl(SHIN, TIOCSTI, mbc + i) != 0 &&
182*65b0c20eSnakanon 			    errno == EAGAIN) {
183*65b0c20eSnakanon 				if (retry++ < 5)
184*65b0c20eSnakanon 					goto again;
185*65b0c20eSnakanon 				/* probably no worth retrying any more */
186*65b0c20eSnakanon 			}
1877c478bd9Sstevel@tonic-gate 		}
1887c478bd9Sstevel@tonic-gate 	}
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	if (tty.c_lflag != tty_new.c_lflag)
1917c478bd9Sstevel@tonic-gate 		(void) ioctl(SHIN, TCSETS,  (char *)&tty_new);
1927c478bd9Sstevel@tonic-gate 	(void) sigsetmask(omask);
1937c478bd9Sstevel@tonic-gate }
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate /*
1967c478bd9Sstevel@tonic-gate  * Concatenate src onto tail of des.
1977c478bd9Sstevel@tonic-gate  * Des is a string whose maximum length is count.
1987c478bd9Sstevel@tonic-gate  * Always null terminate.
1997c478bd9Sstevel@tonic-gate  */
2006c02b4a4Smuffin void
catn(tchar * des,tchar * src,int count)2016c02b4a4Smuffin catn(tchar *des, tchar *src, int count)
2027c478bd9Sstevel@tonic-gate {
2037c478bd9Sstevel@tonic-gate #ifdef TRACE
2047c478bd9Sstevel@tonic-gate 	tprintf("TRACE- catn()\n");
2057c478bd9Sstevel@tonic-gate #endif
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	while (--count >= 0 && *des)
2087c478bd9Sstevel@tonic-gate 		des++;
2097c478bd9Sstevel@tonic-gate 	while (--count >= 0)
2107c478bd9Sstevel@tonic-gate 		if ((*des++ = *src++) == '\0')
2117c478bd9Sstevel@tonic-gate 			return;
2127c478bd9Sstevel@tonic-gate 	*des = '\0';
2137c478bd9Sstevel@tonic-gate }
2147c478bd9Sstevel@tonic-gate 
2156c02b4a4Smuffin static int
max(a,b)2167c478bd9Sstevel@tonic-gate max(a, b)
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	return (a > b ? a : b);
2207c478bd9Sstevel@tonic-gate }
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate /*
2237c478bd9Sstevel@tonic-gate  * Like strncpy but always leave room for trailing \0
2247c478bd9Sstevel@tonic-gate  * and always null terminate.
2257c478bd9Sstevel@tonic-gate  */
2266c02b4a4Smuffin void
copyn(tchar * des,tchar * src,int count)2276c02b4a4Smuffin copyn(tchar *des, tchar *src, int count)
2287c478bd9Sstevel@tonic-gate {
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate #ifdef TRACE
2317c478bd9Sstevel@tonic-gate 	tprintf("TRACE- copyn()\n");
2327c478bd9Sstevel@tonic-gate #endif
2337c478bd9Sstevel@tonic-gate 	while (--count >= 0)
2347c478bd9Sstevel@tonic-gate 		if ((*des++ = *src++) == '\0')
2357c478bd9Sstevel@tonic-gate 			return;
2367c478bd9Sstevel@tonic-gate 	*des = '\0';
2377c478bd9Sstevel@tonic-gate }
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate /*
2407c478bd9Sstevel@tonic-gate  * For qsort()
2417c478bd9Sstevel@tonic-gate  */
2426c02b4a4Smuffin static int
fcompare(tchar ** file1,tchar ** file2)2436c02b4a4Smuffin fcompare(tchar **file1, tchar **file2)
2447c478bd9Sstevel@tonic-gate {
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate #ifdef TRACE
2477c478bd9Sstevel@tonic-gate 	tprintf("TRACE- fcompare()\n");
2487c478bd9Sstevel@tonic-gate #endif
2497c478bd9Sstevel@tonic-gate 	return (strcoll_(*file1, *file2));
2507c478bd9Sstevel@tonic-gate }
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate static char
filetype(tchar * dir,tchar * file,int nosym)2536c02b4a4Smuffin filetype(tchar *dir, tchar *file, int nosym)
2547c478bd9Sstevel@tonic-gate {
2557c478bd9Sstevel@tonic-gate 	tchar path[MAXPATHLEN + 1];
2567c478bd9Sstevel@tonic-gate 	struct stat statb;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate #ifdef TRACE
2597c478bd9Sstevel@tonic-gate 	tprintf("TRACE- filetype()\n");
2607c478bd9Sstevel@tonic-gate #endif
2617c478bd9Sstevel@tonic-gate 	if (dir) {
2627c478bd9Sstevel@tonic-gate 		catn(strcpy_(path, dir), file, MAXPATHLEN);
2637c478bd9Sstevel@tonic-gate 		if (nosym) {
2647c478bd9Sstevel@tonic-gate 			if (stat_(path, &statb) < 0)
2657c478bd9Sstevel@tonic-gate 				return (' ');
2667c478bd9Sstevel@tonic-gate 		} else {
2677c478bd9Sstevel@tonic-gate 			if (lstat_(path, &statb) < 0)
2687c478bd9Sstevel@tonic-gate 				return (' ');
2697c478bd9Sstevel@tonic-gate 		}
2707c478bd9Sstevel@tonic-gate 		if ((statb.st_mode & S_IFMT) == S_IFLNK)
2717c478bd9Sstevel@tonic-gate 			return ('@');
2727c478bd9Sstevel@tonic-gate 		if ((statb.st_mode & S_IFMT) == S_IFDIR)
2737c478bd9Sstevel@tonic-gate 			return ('/');
2747c478bd9Sstevel@tonic-gate 		if (((statb.st_mode & S_IFMT) == S_IFREG) &&
2757c478bd9Sstevel@tonic-gate 		    (statb.st_mode & 011))
2767c478bd9Sstevel@tonic-gate 			return ('*');
2777c478bd9Sstevel@tonic-gate 	}
2787c478bd9Sstevel@tonic-gate 	return (' ');
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate /*
2827c478bd9Sstevel@tonic-gate  * Print sorted down columns
2837c478bd9Sstevel@tonic-gate  */
2846c02b4a4Smuffin static void
print_by_column(tchar * dir,tchar * items[],int count,int looking_for_command)2856c02b4a4Smuffin print_by_column(tchar *dir, tchar *items[], int count, int looking_for_command)
2867c478bd9Sstevel@tonic-gate {
2876c02b4a4Smuffin 	int i, rows, r, c, maxwidth = 0, columns;
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate #ifdef TRACE
2907c478bd9Sstevel@tonic-gate 	tprintf("TRACE- print_by_column()\n");
2917c478bd9Sstevel@tonic-gate #endif
2927c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++)
2937c478bd9Sstevel@tonic-gate 		maxwidth = max(maxwidth, tswidth(items[i]));
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	/* for the file tag and space */
2967c478bd9Sstevel@tonic-gate 	maxwidth += looking_for_command ? 1 : 2;
2977c478bd9Sstevel@tonic-gate 	columns = max(78 / maxwidth, 1);
2987c478bd9Sstevel@tonic-gate 	rows = (count + (columns - 1)) / columns;
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	for (r = 0; r < rows; r++) {
3017c478bd9Sstevel@tonic-gate 		for (c = 0; c < columns; c++) {
3027c478bd9Sstevel@tonic-gate 			i = c * rows + r;
3037c478bd9Sstevel@tonic-gate 			if (i < count) {
3046c02b4a4Smuffin 				int w;
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 				/*
3077c478bd9Sstevel@tonic-gate 				 * Print filename followed by
3087c478bd9Sstevel@tonic-gate 				 * '@' or '/' or '*' or ' '
3097c478bd9Sstevel@tonic-gate 				 */
3107c478bd9Sstevel@tonic-gate 				printf("%t", items[i]);
3117c478bd9Sstevel@tonic-gate 				w = tswidth(items[i]);
3127c478bd9Sstevel@tonic-gate 				if (!looking_for_command) {
3137c478bd9Sstevel@tonic-gate 					printf("%c",
3147c478bd9Sstevel@tonic-gate 					    (tchar) filetype(dir, items[i], 0));
3157c478bd9Sstevel@tonic-gate 					w++;
3167c478bd9Sstevel@tonic-gate 				}
3177c478bd9Sstevel@tonic-gate 				if (c < columns - 1)	/* last column? */
3187c478bd9Sstevel@tonic-gate 					for (; w < maxwidth; w++)
3197c478bd9Sstevel@tonic-gate 						printf(" ");
3207c478bd9Sstevel@tonic-gate 			}
3217c478bd9Sstevel@tonic-gate 		}
3227c478bd9Sstevel@tonic-gate 		printf("\n");
3237c478bd9Sstevel@tonic-gate 	}
3247c478bd9Sstevel@tonic-gate }
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate /*
3277c478bd9Sstevel@tonic-gate  * Expand file name with possible tilde usage
3287c478bd9Sstevel@tonic-gate  *	~person/mumble
3297c478bd9Sstevel@tonic-gate  * expands to
3307c478bd9Sstevel@tonic-gate  *	home_directory_of_person/mumble
3317c478bd9Sstevel@tonic-gate  */
3327c478bd9Sstevel@tonic-gate tchar *
tilde(tchar * new,tchar * old)3336c02b4a4Smuffin tilde(tchar *new, tchar *old)
3347c478bd9Sstevel@tonic-gate {
3356c02b4a4Smuffin 	tchar *o, *p;
3366c02b4a4Smuffin 	struct passwd *pw;
3377c478bd9Sstevel@tonic-gate 	static tchar person[40];
3387c478bd9Sstevel@tonic-gate 	char person_[40];		/* work */
3397c478bd9Sstevel@tonic-gate 	tchar *pw_dir;			/* work */
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate #ifdef TRACE
3427c478bd9Sstevel@tonic-gate 	tprintf("TRACE- tilde()\n");
3437c478bd9Sstevel@tonic-gate #endif
3447c478bd9Sstevel@tonic-gate 	if (old[0] != '~')
3457c478bd9Sstevel@tonic-gate 		return (strcpy_(new, old));
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	for (p = person, o = &old[1]; *o && *o != '/'; *p++ = *o++)
3487c478bd9Sstevel@tonic-gate 		;
3497c478bd9Sstevel@tonic-gate 	*p = '\0';
3507c478bd9Sstevel@tonic-gate 	if (person[0] == '\0')
351*65b0c20eSnakanon 		(void) strcpy_(new, value(S_home /* "home" */));
3527c478bd9Sstevel@tonic-gate 	else {
353*65b0c20eSnakanon 		pw = getpwnam(tstostr(person_, person));
3547c478bd9Sstevel@tonic-gate 		if (pw == NULL)
3557c478bd9Sstevel@tonic-gate 			return (NULL);
3567c478bd9Sstevel@tonic-gate 		pw_dir = strtots((tchar *)NULL, pw->pw_dir);	/* allocate */
3577c478bd9Sstevel@tonic-gate 		(void) strcpy_(new, pw_dir);
3587c478bd9Sstevel@tonic-gate 		xfree(pw_dir);					/* free it */
3597c478bd9Sstevel@tonic-gate 	}
3607c478bd9Sstevel@tonic-gate 	(void) strcat_(new, o);
3617c478bd9Sstevel@tonic-gate 	return (new);
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate /*
3657c478bd9Sstevel@tonic-gate  * Cause pending line to be printed
3667c478bd9Sstevel@tonic-gate  */
3676c02b4a4Smuffin static void
sim_retype(void)3686c02b4a4Smuffin sim_retype(void)
3697c478bd9Sstevel@tonic-gate {
3707c478bd9Sstevel@tonic-gate #ifdef notdef
3717c478bd9Sstevel@tonic-gate 	struct termios tty_pending;
372*65b0c20eSnakanon 
3737c478bd9Sstevel@tonic-gate #ifdef TRACE
3747c478bd9Sstevel@tonic-gate 	tprintf("TRACE- sim_retypr()\n");
3757c478bd9Sstevel@tonic-gate #endif
3767c478bd9Sstevel@tonic-gate 	tty_pending = tty_new;
3777c478bd9Sstevel@tonic-gate 	tty_pending.c_lflag |= PENDIN;
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	(void) ioctl(SHIN, TCSETS,  (char *)&tty_pending);
3807c478bd9Sstevel@tonic-gate #else
3817c478bd9Sstevel@tonic-gate #ifdef TRACE
3827c478bd9Sstevel@tonic-gate 	tprintf("TRACE- sim_retype()\n");
3837c478bd9Sstevel@tonic-gate #endif
3847c478bd9Sstevel@tonic-gate 	(void) write(SHOUT, CTRLR, strlen(CTRLR));
3857c478bd9Sstevel@tonic-gate 	printprompt();
3867c478bd9Sstevel@tonic-gate #endif
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate 
3896c02b4a4Smuffin static int
beep_outc(int c)3906c02b4a4Smuffin beep_outc(int c)
3916c02b4a4Smuffin {
3927c478bd9Sstevel@tonic-gate 	char	buf[1];
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	buf[0] = c;
3957c478bd9Sstevel@tonic-gate 
396*65b0c20eSnakanon 	(void) write(SHOUT, buf, 1);
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	return 0;
3997c478bd9Sstevel@tonic-gate }
4007c478bd9Sstevel@tonic-gate 
4016c02b4a4Smuffin static void
beep(void)4026c02b4a4Smuffin beep(void)
4037c478bd9Sstevel@tonic-gate {
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate #ifdef TRACE
4067c478bd9Sstevel@tonic-gate 	tprintf("TRACE- beep()\n");
4077c478bd9Sstevel@tonic-gate #endif
408*65b0c20eSnakanon 	if (adrof(S_nobeep /* "nobeep" */) == 0)
409*65b0c20eSnakanon 		(void) tputs(BELL, 0, beep_outc);
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate /*
4137c478bd9Sstevel@tonic-gate  * Erase that silly ^[ and print the recognized part of the string.
4147c478bd9Sstevel@tonic-gate  */
4156c02b4a4Smuffin static void
print_recognized_stuff(tchar * recognized_part)4166c02b4a4Smuffin print_recognized_stuff(tchar *recognized_part)
4177c478bd9Sstevel@tonic-gate {
4187c478bd9Sstevel@tonic-gate 	int unit =  didfds ? 1 : SHOUT;
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate #ifdef TRACE
4217c478bd9Sstevel@tonic-gate 	tprintf("TRACE- print_recognized_stuff()\n");
4227c478bd9Sstevel@tonic-gate #endif
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	/*
4257c478bd9Sstevel@tonic-gate 	 * An optimized erasing of that silly ^[
4267c478bd9Sstevel@tonic-gate 	 *
4277c478bd9Sstevel@tonic-gate 	 * One would think that line speeds have become fast enough that this
4287c478bd9Sstevel@tonic-gate 	 * isn't necessary, but it turns out that the visual difference is
4297c478bd9Sstevel@tonic-gate 	 * quite noticeable.
4307c478bd9Sstevel@tonic-gate 	 */
431*65b0c20eSnakanon 	flush();
4327c478bd9Sstevel@tonic-gate 	switch (tswidth(recognized_part)) {
4337c478bd9Sstevel@tonic-gate 	case 0:
4347c478bd9Sstevel@tonic-gate 		/* erase two characters: ^[ */
4357c478bd9Sstevel@tonic-gate 		write(unit, "\b\b  \b\b", sizeof "\b\b  \b\b" - 1);
4367c478bd9Sstevel@tonic-gate 		break;
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	case 1:
4397c478bd9Sstevel@tonic-gate 		/* overstrike the ^, erase the [ */
4407c478bd9Sstevel@tonic-gate 		write(unit, "\b\b", 2);
4417c478bd9Sstevel@tonic-gate 		printf("%t", recognized_part);
4427c478bd9Sstevel@tonic-gate 		write(unit, "  \b\b", 4);
4437c478bd9Sstevel@tonic-gate 		break;
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	default:
4467c478bd9Sstevel@tonic-gate 		/* overstrike both characters ^[ */
4477c478bd9Sstevel@tonic-gate 		write(unit, "\b\b", 2);
4487c478bd9Sstevel@tonic-gate 		printf("%t", recognized_part);
4497c478bd9Sstevel@tonic-gate 		break;
4507c478bd9Sstevel@tonic-gate 	}
4517c478bd9Sstevel@tonic-gate 	flush();
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate /*
4557c478bd9Sstevel@tonic-gate  * Parse full path in file into 2 parts: directory and file names
4567c478bd9Sstevel@tonic-gate  * Should leave final slash (/) at end of dir.
4577c478bd9Sstevel@tonic-gate  */
4586c02b4a4Smuffin static void
extract_dir_and_name(tchar * path,tchar * dir,tchar * name)4596c02b4a4Smuffin extract_dir_and_name(tchar *path, tchar *dir, tchar *name)
4607c478bd9Sstevel@tonic-gate {
4616c02b4a4Smuffin 	tchar  *p;
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate #ifdef TRACE
4647c478bd9Sstevel@tonic-gate 	tprintf("TRACE- extract_dir_and_name()\n");
4657c478bd9Sstevel@tonic-gate #endif
4667c478bd9Sstevel@tonic-gate 	p = rindex_(path, '/');
4677c478bd9Sstevel@tonic-gate 	if (p == NOSTR) {
4687c478bd9Sstevel@tonic-gate 		copyn(name, path, MAXNAMLEN);
4697c478bd9Sstevel@tonic-gate 		dir[0] = '\0';
4707c478bd9Sstevel@tonic-gate 	} else {
4717c478bd9Sstevel@tonic-gate 		copyn(name, ++p, MAXNAMLEN);
4727c478bd9Sstevel@tonic-gate 		copyn(dir, path, p - path);
4737c478bd9Sstevel@tonic-gate 	}
4747c478bd9Sstevel@tonic-gate }
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate tchar *
getentry(DIR * dir_fd,int looking_for_lognames)4776c02b4a4Smuffin getentry(DIR *dir_fd, int looking_for_lognames)
4787c478bd9Sstevel@tonic-gate {
4796c02b4a4Smuffin 	struct passwd *pw;
4806c02b4a4Smuffin 	struct dirent *dirp;
4817c478bd9Sstevel@tonic-gate 	/*
4827c478bd9Sstevel@tonic-gate 	 * For char * -> tchar * Conversion
4837c478bd9Sstevel@tonic-gate 	 */
4847c478bd9Sstevel@tonic-gate 	static tchar strbuf[MAXNAMLEN+1];
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate #ifdef TRACE
4877c478bd9Sstevel@tonic-gate 	tprintf("TRACE- getentry()\n");
4887c478bd9Sstevel@tonic-gate #endif
4897c478bd9Sstevel@tonic-gate 	if (looking_for_lognames) {
490*65b0c20eSnakanon 		if ((pw = getpwent()) == NULL)
4917c478bd9Sstevel@tonic-gate 			return (NULL);
492*65b0c20eSnakanon 		return (strtots(strbuf, pw->pw_name));
4937c478bd9Sstevel@tonic-gate 	}
4947c478bd9Sstevel@tonic-gate 	if (dirp = readdir(dir_fd))
495*65b0c20eSnakanon 		return (strtots(strbuf, dirp->d_name));
4967c478bd9Sstevel@tonic-gate 	return (NULL);
4977c478bd9Sstevel@tonic-gate }
4987c478bd9Sstevel@tonic-gate 
4996c02b4a4Smuffin static void
free_items(tchar ** items)5006c02b4a4Smuffin free_items(tchar **items)
5017c478bd9Sstevel@tonic-gate {
5026c02b4a4Smuffin 	int i;
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate #ifdef TRACE
5057c478bd9Sstevel@tonic-gate 	tprintf("TRACE- free_items()\n");
5067c478bd9Sstevel@tonic-gate #endif
5077c478bd9Sstevel@tonic-gate 	for (i = 0; items[i]; i++)
508*65b0c20eSnakanon 		xfree(items[i]);
509*65b0c20eSnakanon 	xfree((char *)items);
5107c478bd9Sstevel@tonic-gate }
5117c478bd9Sstevel@tonic-gate 
512*65b0c20eSnakanon #define	FREE_ITEMS(items) { \
5137c478bd9Sstevel@tonic-gate 	int omask;\
5147c478bd9Sstevel@tonic-gate \
5157c478bd9Sstevel@tonic-gate 	omask = sigblock(sigmask(SIGINT));\
5167c478bd9Sstevel@tonic-gate 	free_items(items);\
5177c478bd9Sstevel@tonic-gate 	items = NULL;\
5187c478bd9Sstevel@tonic-gate 	(void) sigsetmask(omask);\
5197c478bd9Sstevel@tonic-gate }
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate /*
5227c478bd9Sstevel@tonic-gate  * Perform a RECOGNIZE or LIST command on string "word".
5237c478bd9Sstevel@tonic-gate  */
5246c02b4a4Smuffin static int
search2(tchar * word,COMMAND command,int max_word_length)5256c02b4a4Smuffin search2(tchar *word, COMMAND command, int max_word_length)
5267c478bd9Sstevel@tonic-gate {
5277c478bd9Sstevel@tonic-gate 	static tchar **items = NULL;
5286c02b4a4Smuffin 	DIR *dir_fd;
5296c02b4a4Smuffin 	int numitems = 0, ignoring = TRUE, nignored = 0;
5306c02b4a4Smuffin 	int name_length, looking_for_lognames;
5317c478bd9Sstevel@tonic-gate 	tchar tilded_dir[MAXPATHLEN + 1], dir[MAXPATHLEN + 1];
5327c478bd9Sstevel@tonic-gate 	tchar name[MAXNAMLEN + 1], extended_name[MAXNAMLEN+1];
5337c478bd9Sstevel@tonic-gate 	tchar *entry;
534*65b0c20eSnakanon #define	MAXITEMS 1024
5357c478bd9Sstevel@tonic-gate #ifdef TRACE
5367c478bd9Sstevel@tonic-gate 	tprintf("TRACE- search2()\n");
5377c478bd9Sstevel@tonic-gate #endif
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	if (items != NULL)
5407c478bd9Sstevel@tonic-gate 		FREE_ITEMS(items);
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	looking_for_lognames = (*word == '~') && (index_(word, '/') == NULL);
5437c478bd9Sstevel@tonic-gate 	if (looking_for_lognames) {
5447c478bd9Sstevel@tonic-gate 		(void) setpwent();
5457c478bd9Sstevel@tonic-gate 		copyn(name, &word[1], MAXNAMLEN);	/* name sans ~ */
5467c478bd9Sstevel@tonic-gate 	} else {
5477c478bd9Sstevel@tonic-gate 		extract_dir_and_name(word, dir, name);
5487c478bd9Sstevel@tonic-gate 		if (tilde(tilded_dir, dir) == 0)
5497c478bd9Sstevel@tonic-gate 			return (0);
550*65b0c20eSnakanon 		dir_fd = opendir_(*tilded_dir ? tilded_dir : S_DOT /* "." */);
5517c478bd9Sstevel@tonic-gate 		if (dir_fd == NULL)
5527c478bd9Sstevel@tonic-gate 			return (0);
5537c478bd9Sstevel@tonic-gate 	}
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate again:	/* search for matches */
5567c478bd9Sstevel@tonic-gate 	name_length = strlen_(name);
5577c478bd9Sstevel@tonic-gate 	for (numitems = 0; entry = getentry(dir_fd, looking_for_lognames); ) {
5587c478bd9Sstevel@tonic-gate 		if (!is_prefix(name, entry))
5597c478bd9Sstevel@tonic-gate 			continue;
5607c478bd9Sstevel@tonic-gate 		/* Don't match . files on null prefix match */
5617c478bd9Sstevel@tonic-gate 		if (name_length == 0 && entry[0] == '.' &&
5627c478bd9Sstevel@tonic-gate 		    !looking_for_lognames)
5637c478bd9Sstevel@tonic-gate 			continue;
5647c478bd9Sstevel@tonic-gate 		if (command == LIST) {
5657c478bd9Sstevel@tonic-gate 			if (numitems >= MAXITEMS) {
566*65b0c20eSnakanon 				printf("\nYikes!! Too many %s!!\n",
5677c478bd9Sstevel@tonic-gate 				    looking_for_lognames ?
5687c478bd9Sstevel@tonic-gate 					"names in password file":"files");
5697c478bd9Sstevel@tonic-gate 				break;
5707c478bd9Sstevel@tonic-gate 			}
5717c478bd9Sstevel@tonic-gate 			if (items == NULL)
572*65b0c20eSnakanon 				items =  (tchar **)xcalloc(sizeof (items[1]),
5737c478bd9Sstevel@tonic-gate 				    MAXITEMS+1);
574*65b0c20eSnakanon 			items[numitems] = (tchar *)xalloc((unsigned)(strlen_(entry) + 1) * sizeof (tchar));
5757c478bd9Sstevel@tonic-gate 			copyn(items[numitems], entry, MAXNAMLEN);
5767c478bd9Sstevel@tonic-gate 			numitems++;
5777c478bd9Sstevel@tonic-gate 		} else {			/* RECOGNIZE command */
5787c478bd9Sstevel@tonic-gate 			if (ignoring && ignored(entry))
5797c478bd9Sstevel@tonic-gate 				nignored++;
5807c478bd9Sstevel@tonic-gate 			else if (recognize(extended_name,
5817c478bd9Sstevel@tonic-gate 			    entry, name_length, ++numitems))
5827c478bd9Sstevel@tonic-gate 				break;
5837c478bd9Sstevel@tonic-gate 		}
5847c478bd9Sstevel@tonic-gate 	}
5857c478bd9Sstevel@tonic-gate 	if (ignoring && numitems == 0 && nignored > 0) {
5867c478bd9Sstevel@tonic-gate 		ignoring = FALSE;
5877c478bd9Sstevel@tonic-gate 		nignored = 0;
5887c478bd9Sstevel@tonic-gate 		if (looking_for_lognames)
589*65b0c20eSnakanon 			(void) setpwent();
5907c478bd9Sstevel@tonic-gate 		else
5917c478bd9Sstevel@tonic-gate 			rewinddir(dir_fd);
5927c478bd9Sstevel@tonic-gate 		goto again;
5937c478bd9Sstevel@tonic-gate 	}
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	if (looking_for_lognames)
5967c478bd9Sstevel@tonic-gate 		(void) endpwent();
5977c478bd9Sstevel@tonic-gate 	else {
5987c478bd9Sstevel@tonic-gate 		unsetfd(dir_fd->dd_fd);
5997c478bd9Sstevel@tonic-gate 		closedir_(dir_fd);
6007c478bd9Sstevel@tonic-gate 	}
6017c478bd9Sstevel@tonic-gate 	if (command == RECOGNIZE && numitems > 0) {
6027c478bd9Sstevel@tonic-gate 		if (looking_for_lognames)
603*65b0c20eSnakanon 			copyn(word, S_TIL /* "~" */, 1);
6047c478bd9Sstevel@tonic-gate 		else
6057c478bd9Sstevel@tonic-gate 			/* put back dir part */
6067c478bd9Sstevel@tonic-gate 			copyn(word, dir, max_word_length);
6077c478bd9Sstevel@tonic-gate 		/* add extended name */
6087c478bd9Sstevel@tonic-gate 		catn(word, extended_name, max_word_length);
6097c478bd9Sstevel@tonic-gate 		return (numitems);
6107c478bd9Sstevel@tonic-gate 	}
6117c478bd9Sstevel@tonic-gate 	if (command == LIST) {
612*65b0c20eSnakanon 		qsort((char *)items, numitems, sizeof (items[1]),
613*65b0c20eSnakanon 		    (int (*)(const void *, const void *))fcompare);
6147c478bd9Sstevel@tonic-gate 		/*
6157c478bd9Sstevel@tonic-gate 		 * Never looking for commands in this version, so final
6167c478bd9Sstevel@tonic-gate 		 * argument forced to 0.  If command name completion is
6177c478bd9Sstevel@tonic-gate 		 * reinstated, this must change.
6187c478bd9Sstevel@tonic-gate 		 */
6197c478bd9Sstevel@tonic-gate 		print_by_column(looking_for_lognames ? NULL : tilded_dir,
6207c478bd9Sstevel@tonic-gate 		    items, numitems, 0);
6217c478bd9Sstevel@tonic-gate 		if (items != NULL)
6227c478bd9Sstevel@tonic-gate 			FREE_ITEMS(items);
6237c478bd9Sstevel@tonic-gate 	}
6247c478bd9Sstevel@tonic-gate 	return (0);
6257c478bd9Sstevel@tonic-gate }
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate /*
6287c478bd9Sstevel@tonic-gate  * Object: extend what user typed up to an ambiguity.
6297c478bd9Sstevel@tonic-gate  * Algorithm:
630*65b0c20eSnakanon  * On first match, copy full entry (assume it'll be the only match)
6317c478bd9Sstevel@tonic-gate  * On subsequent matches, shorten extended_name to the first
6327c478bd9Sstevel@tonic-gate  * character mismatch between extended_name and entry.
6337c478bd9Sstevel@tonic-gate  * If we shorten it back to the prefix length, stop searching.
6347c478bd9Sstevel@tonic-gate  */
6356c02b4a4Smuffin int
recognize(tchar * extended_name,tchar * entry,int name_length,int numitems)6366c02b4a4Smuffin recognize(tchar *extended_name, tchar *entry, int name_length, int numitems)
6377c478bd9Sstevel@tonic-gate {
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate #ifdef TRACE
6407c478bd9Sstevel@tonic-gate 	tprintf("TRACE- recognize()\n");
6417c478bd9Sstevel@tonic-gate #endif
6427c478bd9Sstevel@tonic-gate 	if (numitems == 1)				/* 1st match */
6437c478bd9Sstevel@tonic-gate 		copyn(extended_name, entry, MAXNAMLEN);
6447c478bd9Sstevel@tonic-gate 	else {					/* 2nd and subsequent matches */
6456c02b4a4Smuffin 		tchar *x, *ent;
6466c02b4a4Smuffin 		int len = 0;
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 		x = extended_name;
6497c478bd9Sstevel@tonic-gate 		for (ent = entry; *x && *x == *ent++; x++, len++)
6507c478bd9Sstevel@tonic-gate 			;
6517c478bd9Sstevel@tonic-gate 		*x = '\0';			/* Shorten at 1st char diff */
6527c478bd9Sstevel@tonic-gate 		if (len == name_length)		/* Ambiguous to prefix? */
6537c478bd9Sstevel@tonic-gate 			return (-1);		/* So stop now and save time */
6547c478bd9Sstevel@tonic-gate 	}
6557c478bd9Sstevel@tonic-gate 	return (0);
6567c478bd9Sstevel@tonic-gate }
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate /*
6597c478bd9Sstevel@tonic-gate  * Return true if check items initial chars in template
6607c478bd9Sstevel@tonic-gate  * This differs from PWB imatch in that if check is null
6617c478bd9Sstevel@tonic-gate  * it items anything
6627c478bd9Sstevel@tonic-gate  */
6636c02b4a4Smuffin static int
is_prefix(tchar * check,tchar * template)6646c02b4a4Smuffin is_prefix(tchar *check, tchar *template)
6657c478bd9Sstevel@tonic-gate {
6667c478bd9Sstevel@tonic-gate #ifdef TRACE
6677c478bd9Sstevel@tonic-gate 	tprintf("TRACE- is_prefix()\n");
6687c478bd9Sstevel@tonic-gate #endif
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	do
6717c478bd9Sstevel@tonic-gate 		if (*check == 0)
6727c478bd9Sstevel@tonic-gate 			return (TRUE);
6737c478bd9Sstevel@tonic-gate 	while (*check++ == *template++);
6747c478bd9Sstevel@tonic-gate 	return (FALSE);
6757c478bd9Sstevel@tonic-gate }
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate /*
6787c478bd9Sstevel@tonic-gate  *  Return true if the chars in template appear at the
6797c478bd9Sstevel@tonic-gate  *  end of check, i.e., are its suffix.
6807c478bd9Sstevel@tonic-gate  */
6816c02b4a4Smuffin static int
is_suffix(tchar * check,tchar * template)6826c02b4a4Smuffin is_suffix(tchar *check, tchar *template)
6837c478bd9Sstevel@tonic-gate {
6846c02b4a4Smuffin 	tchar *c, *t;
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate #ifdef TRACE
6877c478bd9Sstevel@tonic-gate 	tprintf("TRACE- is_suffix()\n");
6887c478bd9Sstevel@tonic-gate #endif
689*65b0c20eSnakanon 	for (c = check; *c++; )
6907c478bd9Sstevel@tonic-gate 		;
691*65b0c20eSnakanon 	for (t = template; *t++; )
6927c478bd9Sstevel@tonic-gate 		;
6937c478bd9Sstevel@tonic-gate 	for (;;) {
6947c478bd9Sstevel@tonic-gate 		if (t == template)
6957c478bd9Sstevel@tonic-gate 			return (TRUE);
6967c478bd9Sstevel@tonic-gate 		if (c == check || *--t != *--c)
6977c478bd9Sstevel@tonic-gate 			return (FALSE);
6987c478bd9Sstevel@tonic-gate 	}
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate 
7016c02b4a4Smuffin int
tenex(tchar * inputline,int inputline_size)7026c02b4a4Smuffin tenex(tchar *inputline, int inputline_size)
7037c478bd9Sstevel@tonic-gate {
7046c02b4a4Smuffin 	int numitems, num_read, should_retype;
7057c478bd9Sstevel@tonic-gate 	int i;
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate #ifdef TRACE
7087c478bd9Sstevel@tonic-gate 	tprintf("TRACE- tenex()\n");
7097c478bd9Sstevel@tonic-gate #endif
7107c478bd9Sstevel@tonic-gate 	setup_tty(ON);
7117c478bd9Sstevel@tonic-gate 	termchars();
7127c478bd9Sstevel@tonic-gate 	num_read = 0;
7137c478bd9Sstevel@tonic-gate 	should_retype = FALSE;
7147c478bd9Sstevel@tonic-gate 	while ((i = read_(SHIN, inputline+num_read, inputline_size-num_read))
7157c478bd9Sstevel@tonic-gate 	    > 0) {
716*65b0c20eSnakanon 		static tchar *delims = S_DELIM /* " '\"\t;&<>()|`" */;
7176c02b4a4Smuffin 		tchar *str_end, *word_start, last_char;
7186c02b4a4Smuffin 		int space_left;
7197c478bd9Sstevel@tonic-gate 		struct termios tty;
7207c478bd9Sstevel@tonic-gate 		COMMAND command;
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 		num_read += i;
7237c478bd9Sstevel@tonic-gate 		inputline[num_read] = '\0';
7247c478bd9Sstevel@tonic-gate 		last_char = inputline[num_read - 1] & TRIM;
7257c478bd9Sstevel@tonic-gate 
726*65b0c20eSnakanon 		/*
727*65b0c20eSnakanon 		 * read_() can return more than requested size if there
728*65b0c20eSnakanon 		 * is multibyte character at the end.
729*65b0c20eSnakanon 		 */
730*65b0c20eSnakanon 		if ((num_read >= inputline_size) || (last_char == '\n'))
7317c478bd9Sstevel@tonic-gate 			break;
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 		str_end = &inputline[num_read];
7347c478bd9Sstevel@tonic-gate 		if (last_char == ESC) {
7357c478bd9Sstevel@tonic-gate 			command = RECOGNIZE;
7367c478bd9Sstevel@tonic-gate 			*--str_end = '\0';	/* wipe out trailing ESC */
7377c478bd9Sstevel@tonic-gate 		} else
7387c478bd9Sstevel@tonic-gate 			command = LIST;
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 		tty = tty_new;
7417c478bd9Sstevel@tonic-gate 		tty.c_lflag &= ~ECHO;
7427c478bd9Sstevel@tonic-gate 		(void) ioctl(SHIN, TCSETSF, (char *)&tty);
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 		if (command == LIST)
7457c478bd9Sstevel@tonic-gate 			printf("\n");
7467c478bd9Sstevel@tonic-gate 		/*
7477c478bd9Sstevel@tonic-gate 		 * Find LAST occurence of a delimiter in the inputline.
7487c478bd9Sstevel@tonic-gate 		 * The word start is one character past it.
7497c478bd9Sstevel@tonic-gate 		 */
7507c478bd9Sstevel@tonic-gate 		for (word_start = str_end; word_start > inputline;
7517c478bd9Sstevel@tonic-gate 		    --word_start) {
7527c478bd9Sstevel@tonic-gate 			if (index_(delims, word_start[-1]) ||
7537c478bd9Sstevel@tonic-gate 			    isauxsp(word_start[-1]))
7547c478bd9Sstevel@tonic-gate 				break;
7557c478bd9Sstevel@tonic-gate 		}
7567c478bd9Sstevel@tonic-gate 		space_left = inputline_size - (word_start - inputline) - 1;
7577c478bd9Sstevel@tonic-gate 		numitems = search2(word_start, command, space_left);
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 		/*
7607c478bd9Sstevel@tonic-gate 		 * Tabs in the input line cause trouble after a pushback.
7617c478bd9Sstevel@tonic-gate 		 * tty driver won't backspace over them because column
7627c478bd9Sstevel@tonic-gate 		 * positions are now incorrect. This is solved by retyping
7637c478bd9Sstevel@tonic-gate 		 * over current line.
7647c478bd9Sstevel@tonic-gate 		 */
7657c478bd9Sstevel@tonic-gate 		if (index_(inputline, '\t')) {	/* tab tchar in input line? */
7667c478bd9Sstevel@tonic-gate 			back_to_col_1();
7677c478bd9Sstevel@tonic-gate 			should_retype = TRUE;
7687c478bd9Sstevel@tonic-gate 		}
7697c478bd9Sstevel@tonic-gate 		if (command == LIST)		/* Always retype after a LIST */
7707c478bd9Sstevel@tonic-gate 			should_retype = TRUE;
7717c478bd9Sstevel@tonic-gate 		if (should_retype)
7727c478bd9Sstevel@tonic-gate 			printprompt();
7737c478bd9Sstevel@tonic-gate 		pushback(inputline, should_retype);
7747c478bd9Sstevel@tonic-gate 		num_read = 0;			/* chars will be reread */
7757c478bd9Sstevel@tonic-gate 		should_retype = FALSE;
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 		/*
7787c478bd9Sstevel@tonic-gate 		 * Avoid a race condition by echoing what we're recognized
7797c478bd9Sstevel@tonic-gate 		 * _after_ pushing back the command line.  This way, if the
7807c478bd9Sstevel@tonic-gate 		 * user waits until seeing this output before typing more
7817c478bd9Sstevel@tonic-gate 		 * stuff, the resulting keystrokes won't race with the STIed
7827c478bd9Sstevel@tonic-gate 		 * input we've pushed back.  (Of course, if the user types
7837c478bd9Sstevel@tonic-gate 		 * ahead, the race still exists and it's quite possible that
7847c478bd9Sstevel@tonic-gate 		 * the pushed back input line will interleave with the
7857c478bd9Sstevel@tonic-gate 		 * keystrokes in unexpected ways.)
7867c478bd9Sstevel@tonic-gate 		 */
7877c478bd9Sstevel@tonic-gate 		if (command == RECOGNIZE) {
7887c478bd9Sstevel@tonic-gate 			/* print from str_end on */
7897c478bd9Sstevel@tonic-gate 			print_recognized_stuff(str_end);
7907c478bd9Sstevel@tonic-gate 			if (numitems != 1)	/* Beep = No match/ambiguous */
7917c478bd9Sstevel@tonic-gate 				beep();
7927c478bd9Sstevel@tonic-gate 		}
7937c478bd9Sstevel@tonic-gate 	}
7947c478bd9Sstevel@tonic-gate 	setup_tty(OFF);
7957c478bd9Sstevel@tonic-gate 	return (num_read);
7967c478bd9Sstevel@tonic-gate }
7977c478bd9Sstevel@tonic-gate 
7986c02b4a4Smuffin static int
ignored(tchar * entry)7996c02b4a4Smuffin ignored(tchar *entry)
8007c478bd9Sstevel@tonic-gate {
8017c478bd9Sstevel@tonic-gate 	struct varent *vp;
8026c02b4a4Smuffin 	tchar **cp;
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate #ifdef TRACE
8057c478bd9Sstevel@tonic-gate 	tprintf("TRACE- ignored()\n");
8067c478bd9Sstevel@tonic-gate #endif
807*65b0c20eSnakanon 	if ((vp = adrof(S_fignore /* "fignore" */)) == NULL ||
8087c478bd9Sstevel@tonic-gate 	    (cp = vp->vec) == NULL)
8097c478bd9Sstevel@tonic-gate 		return (FALSE);
8107c478bd9Sstevel@tonic-gate 	for (; *cp != NULL; cp++)
8117c478bd9Sstevel@tonic-gate 		if (is_suffix(entry, *cp))
8127c478bd9Sstevel@tonic-gate 			return (TRUE);
8137c478bd9Sstevel@tonic-gate 	return (FALSE);
8147c478bd9Sstevel@tonic-gate }
8156c02b4a4Smuffin #endif /* FILEC */
816