xref: /titanic_52/usr/src/cmd/csh/sh.file.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
3*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate 
6*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
7*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
8*7c478bd9Sstevel@tonic-gate 
9*7c478bd9Sstevel@tonic-gate /*
10*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
11*7c478bd9Sstevel@tonic-gate  * All rights reserved.  The Berkeley Software License Agreement
12*7c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
13*7c478bd9Sstevel@tonic-gate  */
14*7c478bd9Sstevel@tonic-gate 
15*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
16*7c478bd9Sstevel@tonic-gate 
17*7c478bd9Sstevel@tonic-gate #ifdef FILEC
18*7c478bd9Sstevel@tonic-gate /*
19*7c478bd9Sstevel@tonic-gate  * Tenex style file name recognition, .. and more.
20*7c478bd9Sstevel@tonic-gate  * History:
21*7c478bd9Sstevel@tonic-gate  *	Author: Ken Greer, Sept. 1975, CMU.
22*7c478bd9Sstevel@tonic-gate  *	Finally got around to adding to the Cshell., Ken Greer, Dec. 1981.
23*7c478bd9Sstevel@tonic-gate  */
24*7c478bd9Sstevel@tonic-gate 
25*7c478bd9Sstevel@tonic-gate #include "sh.h"
26*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
27*7c478bd9Sstevel@tonic-gate #include <dirent.h>
28*7c478bd9Sstevel@tonic-gate #include <pwd.h>
29*7c478bd9Sstevel@tonic-gate #include "sh.tconst.h"
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #define TRUE	1
32*7c478bd9Sstevel@tonic-gate #define FALSE	0
33*7c478bd9Sstevel@tonic-gate #define ON	1
34*7c478bd9Sstevel@tonic-gate #define OFF	0
35*7c478bd9Sstevel@tonic-gate 
36*7c478bd9Sstevel@tonic-gate #define ESC	'\033'
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate extern DIR *opendir_();
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate static char *BELL = "\07";
41*7c478bd9Sstevel@tonic-gate static char *CTRLR = "^R\n";
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate typedef enum {LIST, RECOGNIZE} COMMAND;
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate static jmp_buf osetexit;		/* saved setexit() state */
46*7c478bd9Sstevel@tonic-gate static struct termios  tty_save;	/* saved terminal state */
47*7c478bd9Sstevel@tonic-gate static struct termios  tty_new;		/* new terminal state */
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate /*
50*7c478bd9Sstevel@tonic-gate  * Put this here so the binary can be patched with adb to enable file
51*7c478bd9Sstevel@tonic-gate  * completion by default.  Filec controls completion, nobeep controls
52*7c478bd9Sstevel@tonic-gate  * ringing the terminal bell on incomplete expansions.
53*7c478bd9Sstevel@tonic-gate  */
54*7c478bd9Sstevel@tonic-gate bool filec = 0;
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate static
57*7c478bd9Sstevel@tonic-gate setup_tty(on)
58*7c478bd9Sstevel@tonic-gate 	int on;
59*7c478bd9Sstevel@tonic-gate {
60*7c478bd9Sstevel@tonic-gate 	int omask;
61*7c478bd9Sstevel@tonic-gate #ifdef TRACE
62*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- setup_tty()\n");
63*7c478bd9Sstevel@tonic-gate #endif
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate 	omask = sigblock(sigmask(SIGINT));
66*7c478bd9Sstevel@tonic-gate 	if (on) {
67*7c478bd9Sstevel@tonic-gate 		/*
68*7c478bd9Sstevel@tonic-gate 		 * The shell makes sure that the tty is not in some weird state
69*7c478bd9Sstevel@tonic-gate 		 * and fixes it if it is.  But it should be noted that the
70*7c478bd9Sstevel@tonic-gate 		 * tenex routine will not work correctly in CBREAK or RAW mode
71*7c478bd9Sstevel@tonic-gate 		 * so this code below is, therefore, mandatory.
72*7c478bd9Sstevel@tonic-gate 		 *
73*7c478bd9Sstevel@tonic-gate 		 * Also, in order to recognize the ESC (filename-completion)
74*7c478bd9Sstevel@tonic-gate 		 * character, set EOL to ESC.  This way, ESC will terminate
75*7c478bd9Sstevel@tonic-gate 		 * the line, but still be in the input stream.
76*7c478bd9Sstevel@tonic-gate 		 * EOT (filename list) will also terminate the line,
77*7c478bd9Sstevel@tonic-gate 		 * but will not appear in the input stream.
78*7c478bd9Sstevel@tonic-gate 		 *
79*7c478bd9Sstevel@tonic-gate 		 * The getexit/setexit contortions ensure that the
80*7c478bd9Sstevel@tonic-gate 		 * tty state will be restored if the user types ^C.
81*7c478bd9Sstevel@tonic-gate 		 */
82*7c478bd9Sstevel@tonic-gate 		(void) ioctl(SHIN, TCGETS,  (char *)&tty_save);
83*7c478bd9Sstevel@tonic-gate 		getexit(osetexit);
84*7c478bd9Sstevel@tonic-gate 		if (setjmp(reslab)) {
85*7c478bd9Sstevel@tonic-gate 			(void) ioctl(SHIN, TCSETSW,  (char *)&tty_save);
86*7c478bd9Sstevel@tonic-gate 			resexit(osetexit);
87*7c478bd9Sstevel@tonic-gate 			reset();
88*7c478bd9Sstevel@tonic-gate 		}
89*7c478bd9Sstevel@tonic-gate 		tty_new = tty_save;
90*7c478bd9Sstevel@tonic-gate 		tty_new.c_cc[VEOL] = ESC;
91*7c478bd9Sstevel@tonic-gate 		tty_new.c_iflag |= IMAXBEL | BRKINT | IGNPAR;
92*7c478bd9Sstevel@tonic-gate 		tty_new.c_lflag |= ICANON;
93*7c478bd9Sstevel@tonic-gate 		tty_new.c_lflag |= ECHOCTL;
94*7c478bd9Sstevel@tonic-gate 		tty_new.c_oflag &= ~OCRNL;
95*7c478bd9Sstevel@tonic-gate 		(void) ioctl(SHIN, TCSETSW,  (char *)&tty_new);
96*7c478bd9Sstevel@tonic-gate 	} else {
97*7c478bd9Sstevel@tonic-gate 		/*
98*7c478bd9Sstevel@tonic-gate 		 * Reset terminal state to what user had when invoked
99*7c478bd9Sstevel@tonic-gate 		 */
100*7c478bd9Sstevel@tonic-gate 		(void) ioctl(SHIN, TCSETSW,  (char *)&tty_save);
101*7c478bd9Sstevel@tonic-gate 		resexit(osetexit);
102*7c478bd9Sstevel@tonic-gate 	}
103*7c478bd9Sstevel@tonic-gate 	(void) sigsetmask(omask);
104*7c478bd9Sstevel@tonic-gate }
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate static
107*7c478bd9Sstevel@tonic-gate termchars()
108*7c478bd9Sstevel@tonic-gate {
109*7c478bd9Sstevel@tonic-gate 	extern char *tgetstr();
110*7c478bd9Sstevel@tonic-gate 	 char bp[1024];
111*7c478bd9Sstevel@tonic-gate 	static char area[256];
112*7c478bd9Sstevel@tonic-gate 	static int been_here = 0;
113*7c478bd9Sstevel@tonic-gate 	 char *ap = area;
114*7c478bd9Sstevel@tonic-gate 	register char *s;
115*7c478bd9Sstevel@tonic-gate 	 char *term;
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate #ifdef TRACE
118*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- termchars()\n");
119*7c478bd9Sstevel@tonic-gate #endif
120*7c478bd9Sstevel@tonic-gate 	if (been_here)
121*7c478bd9Sstevel@tonic-gate 		return;
122*7c478bd9Sstevel@tonic-gate 	been_here = TRUE;
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate 	if ((term = getenv("TERM")) == NULL)
125*7c478bd9Sstevel@tonic-gate 		return;
126*7c478bd9Sstevel@tonic-gate 	if (tgetent(bp, term) != 1)
127*7c478bd9Sstevel@tonic-gate 		return;
128*7c478bd9Sstevel@tonic-gate 	if (s = tgetstr("vb", &ap))		/* Visible Bell */
129*7c478bd9Sstevel@tonic-gate 		BELL = s;
130*7c478bd9Sstevel@tonic-gate }
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate /*
133*7c478bd9Sstevel@tonic-gate  * Move back to beginning of current line
134*7c478bd9Sstevel@tonic-gate  */
135*7c478bd9Sstevel@tonic-gate static
136*7c478bd9Sstevel@tonic-gate back_to_col_1()
137*7c478bd9Sstevel@tonic-gate {
138*7c478bd9Sstevel@tonic-gate 	int omask;
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate #ifdef TRACE
141*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- back_to_col_1()\n");
142*7c478bd9Sstevel@tonic-gate #endif
143*7c478bd9Sstevel@tonic-gate 	omask = sigblock(sigmask(SIGINT));
144*7c478bd9Sstevel@tonic-gate 	(void) write(SHOUT, "\r", 1);
145*7c478bd9Sstevel@tonic-gate 	(void) sigsetmask(omask);
146*7c478bd9Sstevel@tonic-gate }
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate /*
149*7c478bd9Sstevel@tonic-gate  * Push string contents back into tty queue
150*7c478bd9Sstevel@tonic-gate  */
151*7c478bd9Sstevel@tonic-gate static
152*7c478bd9Sstevel@tonic-gate pushback(string, echoflag)
153*7c478bd9Sstevel@tonic-gate 	tchar *string;
154*7c478bd9Sstevel@tonic-gate 	int echoflag;
155*7c478bd9Sstevel@tonic-gate {
156*7c478bd9Sstevel@tonic-gate 	register tchar *p;
157*7c478bd9Sstevel@tonic-gate 	struct termios tty;
158*7c478bd9Sstevel@tonic-gate 	int omask;
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate #ifdef TRACE
161*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- pushback()\n");
162*7c478bd9Sstevel@tonic-gate #endif
163*7c478bd9Sstevel@tonic-gate 	omask = sigblock(sigmask(SIGINT));
164*7c478bd9Sstevel@tonic-gate 	tty = tty_new;
165*7c478bd9Sstevel@tonic-gate 	if (!echoflag)
166*7c478bd9Sstevel@tonic-gate 		tty.c_lflag &= ~ECHO;
167*7c478bd9Sstevel@tonic-gate 	(void) ioctl(SHIN, TCSETSF, (char *)&tty);
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 	for (p = string; *p; p++){
170*7c478bd9Sstevel@tonic-gate 		char	mbc[MB_LEN_MAX];
171*7c478bd9Sstevel@tonic-gate 		int	i, j = wctomb(mbc, (wchar_t)*p);
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate 		if (j < 0) {
174*7c478bd9Sstevel@tonic-gate 			/* Error! But else what can we do? */
175*7c478bd9Sstevel@tonic-gate 			continue;
176*7c478bd9Sstevel@tonic-gate 		}
177*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < j; ++i) {
178*7c478bd9Sstevel@tonic-gate 			/* XXX: no error recovery provision. */
179*7c478bd9Sstevel@tonic-gate 			(void) ioctl(SHIN, TIOCSTI, mbc + i);
180*7c478bd9Sstevel@tonic-gate 		}
181*7c478bd9Sstevel@tonic-gate 	}
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 	if (tty.c_lflag != tty_new.c_lflag)
184*7c478bd9Sstevel@tonic-gate 		(void) ioctl(SHIN, TCSETS,  (char *)&tty_new);
185*7c478bd9Sstevel@tonic-gate 	(void) sigsetmask(omask);
186*7c478bd9Sstevel@tonic-gate }
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate /*
189*7c478bd9Sstevel@tonic-gate  * Concatenate src onto tail of des.
190*7c478bd9Sstevel@tonic-gate  * Des is a string whose maximum length is count.
191*7c478bd9Sstevel@tonic-gate  * Always null terminate.
192*7c478bd9Sstevel@tonic-gate  */
193*7c478bd9Sstevel@tonic-gate catn(des, src, count)
194*7c478bd9Sstevel@tonic-gate 	register tchar *des, *src;
195*7c478bd9Sstevel@tonic-gate 	register count;
196*7c478bd9Sstevel@tonic-gate {
197*7c478bd9Sstevel@tonic-gate #ifdef TRACE
198*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- catn()\n");
199*7c478bd9Sstevel@tonic-gate #endif
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate 	while (--count >= 0 && *des)
202*7c478bd9Sstevel@tonic-gate 		des++;
203*7c478bd9Sstevel@tonic-gate 	while (--count >= 0)
204*7c478bd9Sstevel@tonic-gate 		if ((*des++ = *src++) == '\0')
205*7c478bd9Sstevel@tonic-gate 			return;
206*7c478bd9Sstevel@tonic-gate 	*des = '\0';
207*7c478bd9Sstevel@tonic-gate }
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate static
210*7c478bd9Sstevel@tonic-gate max(a, b)
211*7c478bd9Sstevel@tonic-gate {
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 	return (a > b ? a : b);
214*7c478bd9Sstevel@tonic-gate }
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate /*
217*7c478bd9Sstevel@tonic-gate  * Like strncpy but always leave room for trailing \0
218*7c478bd9Sstevel@tonic-gate  * and always null terminate.
219*7c478bd9Sstevel@tonic-gate  */
220*7c478bd9Sstevel@tonic-gate copyn(des, src, count)
221*7c478bd9Sstevel@tonic-gate 	register tchar *des, *src;
222*7c478bd9Sstevel@tonic-gate 	register count;
223*7c478bd9Sstevel@tonic-gate {
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate #ifdef TRACE
226*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- copyn()\n");
227*7c478bd9Sstevel@tonic-gate #endif
228*7c478bd9Sstevel@tonic-gate 	while (--count >= 0)
229*7c478bd9Sstevel@tonic-gate 		if ((*des++ = *src++) == '\0')
230*7c478bd9Sstevel@tonic-gate 			return;
231*7c478bd9Sstevel@tonic-gate 	*des = '\0';
232*7c478bd9Sstevel@tonic-gate }
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate /*
235*7c478bd9Sstevel@tonic-gate  * For qsort()
236*7c478bd9Sstevel@tonic-gate  */
237*7c478bd9Sstevel@tonic-gate static
238*7c478bd9Sstevel@tonic-gate fcompare(file1, file2)
239*7c478bd9Sstevel@tonic-gate 	tchar **file1, **file2;
240*7c478bd9Sstevel@tonic-gate {
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate #ifdef TRACE
243*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- fcompare()\n");
244*7c478bd9Sstevel@tonic-gate #endif
245*7c478bd9Sstevel@tonic-gate 	return (strcoll_(*file1, *file2));
246*7c478bd9Sstevel@tonic-gate }
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate static char
249*7c478bd9Sstevel@tonic-gate filetype(dir, file, nosym)
250*7c478bd9Sstevel@tonic-gate 	tchar *dir, *file;
251*7c478bd9Sstevel@tonic-gate 	int nosym;
252*7c478bd9Sstevel@tonic-gate {
253*7c478bd9Sstevel@tonic-gate 	tchar path[MAXPATHLEN + 1];
254*7c478bd9Sstevel@tonic-gate 	struct stat statb;
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate #ifdef TRACE
257*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- filetype()\n");
258*7c478bd9Sstevel@tonic-gate #endif
259*7c478bd9Sstevel@tonic-gate 	if (dir) {
260*7c478bd9Sstevel@tonic-gate 		catn(strcpy_(path, dir), file, MAXPATHLEN);
261*7c478bd9Sstevel@tonic-gate 		if (nosym) {
262*7c478bd9Sstevel@tonic-gate 			if (stat_(path, &statb) < 0)
263*7c478bd9Sstevel@tonic-gate 				return (' ');
264*7c478bd9Sstevel@tonic-gate 		} else {
265*7c478bd9Sstevel@tonic-gate 			if (lstat_(path, &statb) < 0)
266*7c478bd9Sstevel@tonic-gate 				return (' ');
267*7c478bd9Sstevel@tonic-gate 		}
268*7c478bd9Sstevel@tonic-gate 		if ((statb.st_mode & S_IFMT) == S_IFLNK)
269*7c478bd9Sstevel@tonic-gate 			return ('@');
270*7c478bd9Sstevel@tonic-gate 		if ((statb.st_mode & S_IFMT) == S_IFDIR)
271*7c478bd9Sstevel@tonic-gate 			return ('/');
272*7c478bd9Sstevel@tonic-gate 		if (((statb.st_mode & S_IFMT) == S_IFREG) &&
273*7c478bd9Sstevel@tonic-gate 		    (statb.st_mode & 011))
274*7c478bd9Sstevel@tonic-gate 			return ('*');
275*7c478bd9Sstevel@tonic-gate 	}
276*7c478bd9Sstevel@tonic-gate 	return (' ');
277*7c478bd9Sstevel@tonic-gate }
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate /*
280*7c478bd9Sstevel@tonic-gate  * Print sorted down columns
281*7c478bd9Sstevel@tonic-gate  */
282*7c478bd9Sstevel@tonic-gate static
283*7c478bd9Sstevel@tonic-gate print_by_column(dir, items, count, looking_for_command)
284*7c478bd9Sstevel@tonic-gate 	tchar *dir, *items[];
285*7c478bd9Sstevel@tonic-gate 	int looking_for_command;
286*7c478bd9Sstevel@tonic-gate {
287*7c478bd9Sstevel@tonic-gate 	register int i, rows, r, c, maxwidth = 0, columns;
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate #ifdef TRACE
290*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- print_by_column()\n");
291*7c478bd9Sstevel@tonic-gate #endif
292*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++)
293*7c478bd9Sstevel@tonic-gate 		maxwidth = max(maxwidth, tswidth(items[i]));
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 	/* for the file tag and space */
296*7c478bd9Sstevel@tonic-gate 	maxwidth += looking_for_command ? 1 : 2;
297*7c478bd9Sstevel@tonic-gate 	columns = max(78 / maxwidth, 1);
298*7c478bd9Sstevel@tonic-gate 	rows = (count + (columns - 1)) / columns;
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate 	for (r = 0; r < rows; r++) {
301*7c478bd9Sstevel@tonic-gate 		for (c = 0; c < columns; c++) {
302*7c478bd9Sstevel@tonic-gate 			i = c * rows + r;
303*7c478bd9Sstevel@tonic-gate 			if (i < count) {
304*7c478bd9Sstevel@tonic-gate 				register int w;
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 				/*
307*7c478bd9Sstevel@tonic-gate 				 * Print filename followed by
308*7c478bd9Sstevel@tonic-gate 				 * '@' or '/' or '*' or ' '
309*7c478bd9Sstevel@tonic-gate 				 */
310*7c478bd9Sstevel@tonic-gate 				printf("%t", items[i]);
311*7c478bd9Sstevel@tonic-gate 				w = tswidth(items[i]);
312*7c478bd9Sstevel@tonic-gate 				if (!looking_for_command) {
313*7c478bd9Sstevel@tonic-gate 					printf("%c",
314*7c478bd9Sstevel@tonic-gate 					    (tchar) filetype(dir, items[i], 0));
315*7c478bd9Sstevel@tonic-gate 					w++;
316*7c478bd9Sstevel@tonic-gate 				}
317*7c478bd9Sstevel@tonic-gate 				if (c < columns - 1)	/* last column? */
318*7c478bd9Sstevel@tonic-gate 					for (; w < maxwidth; w++)
319*7c478bd9Sstevel@tonic-gate 						printf(" ");
320*7c478bd9Sstevel@tonic-gate 			}
321*7c478bd9Sstevel@tonic-gate 		}
322*7c478bd9Sstevel@tonic-gate 		printf("\n");
323*7c478bd9Sstevel@tonic-gate 	}
324*7c478bd9Sstevel@tonic-gate }
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate /*
327*7c478bd9Sstevel@tonic-gate  * Expand file name with possible tilde usage
328*7c478bd9Sstevel@tonic-gate  *	~person/mumble
329*7c478bd9Sstevel@tonic-gate  * expands to
330*7c478bd9Sstevel@tonic-gate  *	home_directory_of_person/mumble
331*7c478bd9Sstevel@tonic-gate  */
332*7c478bd9Sstevel@tonic-gate tchar *
333*7c478bd9Sstevel@tonic-gate tilde(new, old)
334*7c478bd9Sstevel@tonic-gate 	tchar *new, *old;
335*7c478bd9Sstevel@tonic-gate {
336*7c478bd9Sstevel@tonic-gate 	register tchar *o, *p;
337*7c478bd9Sstevel@tonic-gate 	register struct passwd *pw;
338*7c478bd9Sstevel@tonic-gate 	static tchar person[40];
339*7c478bd9Sstevel@tonic-gate 	char person_[40];		/* work */
340*7c478bd9Sstevel@tonic-gate 	tchar *pw_dir;			/* work */
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate #ifdef TRACE
343*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- tilde()\n");
344*7c478bd9Sstevel@tonic-gate #endif
345*7c478bd9Sstevel@tonic-gate 	if (old[0] != '~')
346*7c478bd9Sstevel@tonic-gate 		return (strcpy_(new, old));
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 	for (p = person, o = &old[1]; *o && *o != '/'; *p++ = *o++)
349*7c478bd9Sstevel@tonic-gate 		;
350*7c478bd9Sstevel@tonic-gate 	*p = '\0';
351*7c478bd9Sstevel@tonic-gate 	if (person[0] == '\0')
352*7c478bd9Sstevel@tonic-gate 		(void) strcpy_(new, value(S_home /*"home"*/));
353*7c478bd9Sstevel@tonic-gate 	else {
354*7c478bd9Sstevel@tonic-gate 		pw = getpwnam(tstostr(person_,person));
355*7c478bd9Sstevel@tonic-gate 		if (pw == NULL)
356*7c478bd9Sstevel@tonic-gate 			return (NULL);
357*7c478bd9Sstevel@tonic-gate 		pw_dir = strtots((tchar *)NULL, pw->pw_dir);	/* allocate */
358*7c478bd9Sstevel@tonic-gate 		(void) strcpy_(new, pw_dir);
359*7c478bd9Sstevel@tonic-gate 		xfree(pw_dir);					/* free it */
360*7c478bd9Sstevel@tonic-gate 	}
361*7c478bd9Sstevel@tonic-gate 	(void) strcat_(new, o);
362*7c478bd9Sstevel@tonic-gate 	return (new);
363*7c478bd9Sstevel@tonic-gate }
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate /*
366*7c478bd9Sstevel@tonic-gate  * Cause pending line to be printed
367*7c478bd9Sstevel@tonic-gate  */
368*7c478bd9Sstevel@tonic-gate static
369*7c478bd9Sstevel@tonic-gate sim_retype()
370*7c478bd9Sstevel@tonic-gate {
371*7c478bd9Sstevel@tonic-gate #ifdef notdef
372*7c478bd9Sstevel@tonic-gate 	struct termios tty_pending;
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate #ifdef TRACE
375*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- sim_retypr()\n");
376*7c478bd9Sstevel@tonic-gate #endif
377*7c478bd9Sstevel@tonic-gate 	tty_pending = tty_new;
378*7c478bd9Sstevel@tonic-gate 	tty_pending.c_lflag |= PENDIN;
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 	(void) ioctl(SHIN, TCSETS,  (char *)&tty_pending);
381*7c478bd9Sstevel@tonic-gate #else
382*7c478bd9Sstevel@tonic-gate #ifdef TRACE
383*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- sim_retype()\n");
384*7c478bd9Sstevel@tonic-gate #endif
385*7c478bd9Sstevel@tonic-gate 	(void) write(SHOUT, CTRLR, strlen(CTRLR));
386*7c478bd9Sstevel@tonic-gate 	printprompt();
387*7c478bd9Sstevel@tonic-gate #endif
388*7c478bd9Sstevel@tonic-gate }
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate static
391*7c478bd9Sstevel@tonic-gate beep_outc (c) {
392*7c478bd9Sstevel@tonic-gate 	char	buf[1];
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	buf[0] = c;
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 	(void) write (SHOUT, buf, 1);
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate 	return 0;
399*7c478bd9Sstevel@tonic-gate }
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate static
402*7c478bd9Sstevel@tonic-gate beep()
403*7c478bd9Sstevel@tonic-gate {
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate #ifdef TRACE
406*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- beep()\n");
407*7c478bd9Sstevel@tonic-gate #endif
408*7c478bd9Sstevel@tonic-gate 	if (adrof(S_nobeep /*"nobeep" */) == 0)
409*7c478bd9Sstevel@tonic-gate 		(void) tputs (BELL, 0, beep_outc);
410*7c478bd9Sstevel@tonic-gate }
411*7c478bd9Sstevel@tonic-gate 
412*7c478bd9Sstevel@tonic-gate /*
413*7c478bd9Sstevel@tonic-gate  * Erase that silly ^[ and print the recognized part of the string.
414*7c478bd9Sstevel@tonic-gate  */
415*7c478bd9Sstevel@tonic-gate static
416*7c478bd9Sstevel@tonic-gate print_recognized_stuff(recognized_part)
417*7c478bd9Sstevel@tonic-gate 	tchar *recognized_part;
418*7c478bd9Sstevel@tonic-gate {
419*7c478bd9Sstevel@tonic-gate 	int unit =  didfds ? 1 : SHOUT;
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate #ifdef TRACE
422*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- print_recognized_stuff()\n");
423*7c478bd9Sstevel@tonic-gate #endif
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate 	/*
426*7c478bd9Sstevel@tonic-gate 	 * An optimized erasing of that silly ^[
427*7c478bd9Sstevel@tonic-gate 	 *
428*7c478bd9Sstevel@tonic-gate 	 * One would think that line speeds have become fast enough that this
429*7c478bd9Sstevel@tonic-gate 	 * isn't necessary, but it turns out that the visual difference is
430*7c478bd9Sstevel@tonic-gate 	 * quite noticeable.
431*7c478bd9Sstevel@tonic-gate 	 */
432*7c478bd9Sstevel@tonic-gate 	flush();
433*7c478bd9Sstevel@tonic-gate 	switch (tswidth(recognized_part)) {
434*7c478bd9Sstevel@tonic-gate 	case 0:
435*7c478bd9Sstevel@tonic-gate 		/* erase two characters: ^[ */
436*7c478bd9Sstevel@tonic-gate 		write(unit, "\b\b  \b\b", sizeof "\b\b  \b\b" - 1);
437*7c478bd9Sstevel@tonic-gate 		break;
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate 	case 1:
440*7c478bd9Sstevel@tonic-gate 		/* overstrike the ^, erase the [ */
441*7c478bd9Sstevel@tonic-gate 		write(unit, "\b\b", 2);
442*7c478bd9Sstevel@tonic-gate 		printf("%t", recognized_part);
443*7c478bd9Sstevel@tonic-gate 		write(unit, "  \b\b", 4);
444*7c478bd9Sstevel@tonic-gate 		break;
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 	default:
447*7c478bd9Sstevel@tonic-gate 		/* overstrike both characters ^[ */
448*7c478bd9Sstevel@tonic-gate 		write(unit, "\b\b", 2);
449*7c478bd9Sstevel@tonic-gate 		printf("%t", recognized_part);
450*7c478bd9Sstevel@tonic-gate 		break;
451*7c478bd9Sstevel@tonic-gate 	}
452*7c478bd9Sstevel@tonic-gate 	flush();
453*7c478bd9Sstevel@tonic-gate }
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate /*
456*7c478bd9Sstevel@tonic-gate  * Parse full path in file into 2 parts: directory and file names
457*7c478bd9Sstevel@tonic-gate  * Should leave final slash (/) at end of dir.
458*7c478bd9Sstevel@tonic-gate  */
459*7c478bd9Sstevel@tonic-gate static
460*7c478bd9Sstevel@tonic-gate extract_dir_and_name(path, dir, name)
461*7c478bd9Sstevel@tonic-gate 	tchar *path, *dir, *name;
462*7c478bd9Sstevel@tonic-gate {
463*7c478bd9Sstevel@tonic-gate 	register tchar  *p;
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate #ifdef TRACE
466*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- extract_dir_and_name()\n");
467*7c478bd9Sstevel@tonic-gate #endif
468*7c478bd9Sstevel@tonic-gate 	p = rindex_(path, '/');
469*7c478bd9Sstevel@tonic-gate 	if (p == NOSTR) {
470*7c478bd9Sstevel@tonic-gate 		copyn(name, path, MAXNAMLEN);
471*7c478bd9Sstevel@tonic-gate 		dir[0] = '\0';
472*7c478bd9Sstevel@tonic-gate 	} else {
473*7c478bd9Sstevel@tonic-gate 		copyn(name, ++p, MAXNAMLEN);
474*7c478bd9Sstevel@tonic-gate 		copyn(dir, path, p - path);
475*7c478bd9Sstevel@tonic-gate 	}
476*7c478bd9Sstevel@tonic-gate }
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate tchar *
479*7c478bd9Sstevel@tonic-gate getentry(dir_fd, looking_for_lognames)
480*7c478bd9Sstevel@tonic-gate 	DIR *dir_fd;
481*7c478bd9Sstevel@tonic-gate {
482*7c478bd9Sstevel@tonic-gate 	register struct passwd *pw;
483*7c478bd9Sstevel@tonic-gate 	register struct dirent *dirp;
484*7c478bd9Sstevel@tonic-gate 	/*
485*7c478bd9Sstevel@tonic-gate 	 * For char * -> tchar * Conversion
486*7c478bd9Sstevel@tonic-gate 	 */
487*7c478bd9Sstevel@tonic-gate 	static tchar strbuf[MAXNAMLEN+1];
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate #ifdef TRACE
490*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- getentry()\n");
491*7c478bd9Sstevel@tonic-gate #endif
492*7c478bd9Sstevel@tonic-gate 	if (looking_for_lognames) {
493*7c478bd9Sstevel@tonic-gate 		if ((pw = getpwent ()) == NULL)
494*7c478bd9Sstevel@tonic-gate 			return (NULL);
495*7c478bd9Sstevel@tonic-gate 		return (strtots(strbuf,pw->pw_name));
496*7c478bd9Sstevel@tonic-gate 	}
497*7c478bd9Sstevel@tonic-gate 	if (dirp = readdir(dir_fd))
498*7c478bd9Sstevel@tonic-gate 		return (strtots(strbuf,dirp->d_name));
499*7c478bd9Sstevel@tonic-gate 	return (NULL);
500*7c478bd9Sstevel@tonic-gate }
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate static
503*7c478bd9Sstevel@tonic-gate free_items(items)
504*7c478bd9Sstevel@tonic-gate 	register tchar **items;
505*7c478bd9Sstevel@tonic-gate {
506*7c478bd9Sstevel@tonic-gate 	register int i;
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate #ifdef TRACE
509*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- free_items()\n");
510*7c478bd9Sstevel@tonic-gate #endif
511*7c478bd9Sstevel@tonic-gate 	for (i = 0; items[i]; i++)
512*7c478bd9Sstevel@tonic-gate 		free(items[i]);
513*7c478bd9Sstevel@tonic-gate 	free( (char *)items);
514*7c478bd9Sstevel@tonic-gate }
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate #define FREE_ITEMS(items) { \
517*7c478bd9Sstevel@tonic-gate 	int omask;\
518*7c478bd9Sstevel@tonic-gate \
519*7c478bd9Sstevel@tonic-gate 	omask = sigblock(sigmask(SIGINT));\
520*7c478bd9Sstevel@tonic-gate 	free_items(items);\
521*7c478bd9Sstevel@tonic-gate 	items = NULL;\
522*7c478bd9Sstevel@tonic-gate 	(void) sigsetmask(omask);\
523*7c478bd9Sstevel@tonic-gate }
524*7c478bd9Sstevel@tonic-gate 
525*7c478bd9Sstevel@tonic-gate /*
526*7c478bd9Sstevel@tonic-gate  * Perform a RECOGNIZE or LIST command on string "word".
527*7c478bd9Sstevel@tonic-gate  */
528*7c478bd9Sstevel@tonic-gate static
529*7c478bd9Sstevel@tonic-gate search2(word, command, max_word_length)
530*7c478bd9Sstevel@tonic-gate 	tchar *word;
531*7c478bd9Sstevel@tonic-gate 	COMMAND command;
532*7c478bd9Sstevel@tonic-gate {
533*7c478bd9Sstevel@tonic-gate 	static tchar **items = NULL;
534*7c478bd9Sstevel@tonic-gate 	register DIR *dir_fd;
535*7c478bd9Sstevel@tonic-gate 	register numitems = 0, ignoring = TRUE, nignored = 0;
536*7c478bd9Sstevel@tonic-gate 	register name_length, looking_for_lognames;
537*7c478bd9Sstevel@tonic-gate 	tchar tilded_dir[MAXPATHLEN + 1], dir[MAXPATHLEN + 1];
538*7c478bd9Sstevel@tonic-gate 	tchar name[MAXNAMLEN + 1], extended_name[MAXNAMLEN+1];
539*7c478bd9Sstevel@tonic-gate 	tchar *entry;
540*7c478bd9Sstevel@tonic-gate #define MAXITEMS 1024
541*7c478bd9Sstevel@tonic-gate #ifdef TRACE
542*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- search2()\n");
543*7c478bd9Sstevel@tonic-gate #endif
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate 	if (items != NULL)
546*7c478bd9Sstevel@tonic-gate 		FREE_ITEMS(items);
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 	looking_for_lognames = (*word == '~') && (index_(word, '/') == NULL);
549*7c478bd9Sstevel@tonic-gate 	if (looking_for_lognames) {
550*7c478bd9Sstevel@tonic-gate 		(void) setpwent();
551*7c478bd9Sstevel@tonic-gate 		copyn(name, &word[1], MAXNAMLEN);	/* name sans ~ */
552*7c478bd9Sstevel@tonic-gate 	} else {
553*7c478bd9Sstevel@tonic-gate 		extract_dir_and_name(word, dir, name);
554*7c478bd9Sstevel@tonic-gate 		if (tilde(tilded_dir, dir) == 0)
555*7c478bd9Sstevel@tonic-gate 			return (0);
556*7c478bd9Sstevel@tonic-gate 		dir_fd = opendir_(*tilded_dir ? tilded_dir : S_DOT /*"."*/);
557*7c478bd9Sstevel@tonic-gate 		if (dir_fd == NULL)
558*7c478bd9Sstevel@tonic-gate 			return (0);
559*7c478bd9Sstevel@tonic-gate 	}
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate again:	/* search for matches */
562*7c478bd9Sstevel@tonic-gate 	name_length = strlen_(name);
563*7c478bd9Sstevel@tonic-gate 	for (numitems = 0; entry = getentry(dir_fd, looking_for_lognames); ) {
564*7c478bd9Sstevel@tonic-gate 		if (!is_prefix(name, entry))
565*7c478bd9Sstevel@tonic-gate 			continue;
566*7c478bd9Sstevel@tonic-gate 		/* Don't match . files on null prefix match */
567*7c478bd9Sstevel@tonic-gate 		if (name_length == 0 && entry[0] == '.' &&
568*7c478bd9Sstevel@tonic-gate 		    !looking_for_lognames)
569*7c478bd9Sstevel@tonic-gate 			continue;
570*7c478bd9Sstevel@tonic-gate 		if (command == LIST) {
571*7c478bd9Sstevel@tonic-gate 			if (numitems >= MAXITEMS) {
572*7c478bd9Sstevel@tonic-gate 				printf ("\nYikes!! Too many %s!!\n",
573*7c478bd9Sstevel@tonic-gate 				    looking_for_lognames ?
574*7c478bd9Sstevel@tonic-gate 					"names in password file":"files");
575*7c478bd9Sstevel@tonic-gate 				break;
576*7c478bd9Sstevel@tonic-gate 			}
577*7c478bd9Sstevel@tonic-gate 			if (items == NULL)
578*7c478bd9Sstevel@tonic-gate 				items =  (tchar **) calloc(sizeof (items[1]),
579*7c478bd9Sstevel@tonic-gate 				    MAXITEMS+1);
580*7c478bd9Sstevel@tonic-gate 			items[numitems] = (tchar *)xalloc((unsigned)(strlen_(entry) + 1)*sizeof(tchar));
581*7c478bd9Sstevel@tonic-gate 			copyn(items[numitems], entry, MAXNAMLEN);
582*7c478bd9Sstevel@tonic-gate 			numitems++;
583*7c478bd9Sstevel@tonic-gate 		} else {			/* RECOGNIZE command */
584*7c478bd9Sstevel@tonic-gate 			if (ignoring && ignored(entry))
585*7c478bd9Sstevel@tonic-gate 				nignored++;
586*7c478bd9Sstevel@tonic-gate 			else if (recognize(extended_name,
587*7c478bd9Sstevel@tonic-gate 			    entry, name_length, ++numitems))
588*7c478bd9Sstevel@tonic-gate 				break;
589*7c478bd9Sstevel@tonic-gate 		}
590*7c478bd9Sstevel@tonic-gate 	}
591*7c478bd9Sstevel@tonic-gate 	if (ignoring && numitems == 0 && nignored > 0) {
592*7c478bd9Sstevel@tonic-gate 		ignoring = FALSE;
593*7c478bd9Sstevel@tonic-gate 		nignored = 0;
594*7c478bd9Sstevel@tonic-gate 		if (looking_for_lognames)
595*7c478bd9Sstevel@tonic-gate 			(void)setpwent();
596*7c478bd9Sstevel@tonic-gate 		else
597*7c478bd9Sstevel@tonic-gate 			rewinddir(dir_fd);
598*7c478bd9Sstevel@tonic-gate 		goto again;
599*7c478bd9Sstevel@tonic-gate 	}
600*7c478bd9Sstevel@tonic-gate 
601*7c478bd9Sstevel@tonic-gate 	if (looking_for_lognames)
602*7c478bd9Sstevel@tonic-gate 		(void) endpwent();
603*7c478bd9Sstevel@tonic-gate 	else {
604*7c478bd9Sstevel@tonic-gate 		unsetfd(dir_fd->dd_fd);
605*7c478bd9Sstevel@tonic-gate 		closedir_(dir_fd);
606*7c478bd9Sstevel@tonic-gate 	}
607*7c478bd9Sstevel@tonic-gate 	if (command == RECOGNIZE && numitems > 0) {
608*7c478bd9Sstevel@tonic-gate 		if (looking_for_lognames)
609*7c478bd9Sstevel@tonic-gate 			 copyn(word, S_TIL /*"~" */, 1);
610*7c478bd9Sstevel@tonic-gate 		else
611*7c478bd9Sstevel@tonic-gate 			/* put back dir part */
612*7c478bd9Sstevel@tonic-gate 			copyn(word, dir, max_word_length);
613*7c478bd9Sstevel@tonic-gate 		/* add extended name */
614*7c478bd9Sstevel@tonic-gate 		catn(word, extended_name, max_word_length);
615*7c478bd9Sstevel@tonic-gate 		return (numitems);
616*7c478bd9Sstevel@tonic-gate 	}
617*7c478bd9Sstevel@tonic-gate 	if (command == LIST) {
618*7c478bd9Sstevel@tonic-gate 		qsort( (char *)items, numitems, sizeof(items[1]),
619*7c478bd9Sstevel@tonic-gate 		      (int (*)(const void *, const void *))fcompare);
620*7c478bd9Sstevel@tonic-gate 		/*
621*7c478bd9Sstevel@tonic-gate 		 * Never looking for commands in this version, so final
622*7c478bd9Sstevel@tonic-gate 		 * argument forced to 0.  If command name completion is
623*7c478bd9Sstevel@tonic-gate 		 * reinstated, this must change.
624*7c478bd9Sstevel@tonic-gate 		 */
625*7c478bd9Sstevel@tonic-gate 		print_by_column(looking_for_lognames ? NULL : tilded_dir,
626*7c478bd9Sstevel@tonic-gate 		    items, numitems, 0);
627*7c478bd9Sstevel@tonic-gate 		if (items != NULL)
628*7c478bd9Sstevel@tonic-gate 			FREE_ITEMS(items);
629*7c478bd9Sstevel@tonic-gate 	}
630*7c478bd9Sstevel@tonic-gate 	return (0);
631*7c478bd9Sstevel@tonic-gate }
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate /*
634*7c478bd9Sstevel@tonic-gate  * Object: extend what user typed up to an ambiguity.
635*7c478bd9Sstevel@tonic-gate  * Algorithm:
636*7c478bd9Sstevel@tonic-gate  * On first match, copy full entry (assume it'll be the only match)
637*7c478bd9Sstevel@tonic-gate  * On subsequent matches, shorten extended_name to the first
638*7c478bd9Sstevel@tonic-gate  * character mismatch between extended_name and entry.
639*7c478bd9Sstevel@tonic-gate  * If we shorten it back to the prefix length, stop searching.
640*7c478bd9Sstevel@tonic-gate  */
641*7c478bd9Sstevel@tonic-gate recognize(extended_name, entry, name_length, numitems)
642*7c478bd9Sstevel@tonic-gate 	tchar *extended_name, *entry;
643*7c478bd9Sstevel@tonic-gate {
644*7c478bd9Sstevel@tonic-gate 
645*7c478bd9Sstevel@tonic-gate #ifdef TRACE
646*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- recognize()\n");
647*7c478bd9Sstevel@tonic-gate #endif
648*7c478bd9Sstevel@tonic-gate 	if (numitems == 1)				/* 1st match */
649*7c478bd9Sstevel@tonic-gate 		copyn(extended_name, entry, MAXNAMLEN);
650*7c478bd9Sstevel@tonic-gate 	else {					/* 2nd and subsequent matches */
651*7c478bd9Sstevel@tonic-gate 		register tchar *x, *ent;
652*7c478bd9Sstevel@tonic-gate 		register int len = 0;
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate 		x = extended_name;
655*7c478bd9Sstevel@tonic-gate 		for (ent = entry; *x && *x == *ent++; x++, len++)
656*7c478bd9Sstevel@tonic-gate 			;
657*7c478bd9Sstevel@tonic-gate 		*x = '\0';			/* Shorten at 1st char diff */
658*7c478bd9Sstevel@tonic-gate 		if (len == name_length)		/* Ambiguous to prefix? */
659*7c478bd9Sstevel@tonic-gate 			return (-1);		/* So stop now and save time */
660*7c478bd9Sstevel@tonic-gate 	}
661*7c478bd9Sstevel@tonic-gate 	return (0);
662*7c478bd9Sstevel@tonic-gate }
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate /*
665*7c478bd9Sstevel@tonic-gate  * Return true if check items initial chars in template
666*7c478bd9Sstevel@tonic-gate  * This differs from PWB imatch in that if check is null
667*7c478bd9Sstevel@tonic-gate  * it items anything
668*7c478bd9Sstevel@tonic-gate  */
669*7c478bd9Sstevel@tonic-gate static
670*7c478bd9Sstevel@tonic-gate is_prefix(check, template)
671*7c478bd9Sstevel@tonic-gate 	register tchar *check, *template;
672*7c478bd9Sstevel@tonic-gate {
673*7c478bd9Sstevel@tonic-gate #ifdef TRACE
674*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- is_prefix()\n");
675*7c478bd9Sstevel@tonic-gate #endif
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate 	do
678*7c478bd9Sstevel@tonic-gate 		if (*check == 0)
679*7c478bd9Sstevel@tonic-gate 			return (TRUE);
680*7c478bd9Sstevel@tonic-gate 	while (*check++ == *template++);
681*7c478bd9Sstevel@tonic-gate 	return (FALSE);
682*7c478bd9Sstevel@tonic-gate }
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate /*
685*7c478bd9Sstevel@tonic-gate  *  Return true if the chars in template appear at the
686*7c478bd9Sstevel@tonic-gate  *  end of check, i.e., are its suffix.
687*7c478bd9Sstevel@tonic-gate  */
688*7c478bd9Sstevel@tonic-gate static
689*7c478bd9Sstevel@tonic-gate is_suffix(check, template)
690*7c478bd9Sstevel@tonic-gate 	tchar *check, *template;
691*7c478bd9Sstevel@tonic-gate {
692*7c478bd9Sstevel@tonic-gate 	register tchar *c, *t;
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate #ifdef TRACE
695*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- is_suffix()\n");
696*7c478bd9Sstevel@tonic-gate #endif
697*7c478bd9Sstevel@tonic-gate 	for (c = check; *c++;)
698*7c478bd9Sstevel@tonic-gate 		;
699*7c478bd9Sstevel@tonic-gate 	for (t = template; *t++;)
700*7c478bd9Sstevel@tonic-gate 		;
701*7c478bd9Sstevel@tonic-gate 	for (;;) {
702*7c478bd9Sstevel@tonic-gate 		if (t == template)
703*7c478bd9Sstevel@tonic-gate 			return (TRUE);
704*7c478bd9Sstevel@tonic-gate 		if (c == check || *--t != *--c)
705*7c478bd9Sstevel@tonic-gate 			return (FALSE);
706*7c478bd9Sstevel@tonic-gate 	}
707*7c478bd9Sstevel@tonic-gate }
708*7c478bd9Sstevel@tonic-gate 
709*7c478bd9Sstevel@tonic-gate tenex(inputline, inputline_size)
710*7c478bd9Sstevel@tonic-gate 	tchar *inputline;
711*7c478bd9Sstevel@tonic-gate 	int inputline_size;
712*7c478bd9Sstevel@tonic-gate {
713*7c478bd9Sstevel@tonic-gate 	register int numitems, num_read, should_retype;
714*7c478bd9Sstevel@tonic-gate 	int i;
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate #ifdef TRACE
717*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- tenex()\n");
718*7c478bd9Sstevel@tonic-gate #endif
719*7c478bd9Sstevel@tonic-gate 	setup_tty(ON);
720*7c478bd9Sstevel@tonic-gate 	termchars();
721*7c478bd9Sstevel@tonic-gate 	num_read = 0;
722*7c478bd9Sstevel@tonic-gate 	should_retype = FALSE;
723*7c478bd9Sstevel@tonic-gate 	while ((i = read_(SHIN, inputline+num_read, inputline_size-num_read))
724*7c478bd9Sstevel@tonic-gate 	    > 0) {
725*7c478bd9Sstevel@tonic-gate 		static tchar *delims = S_DELIM /*" '\"\t;&<>()|`"*/;
726*7c478bd9Sstevel@tonic-gate 		register tchar *str_end, *word_start, last_char;
727*7c478bd9Sstevel@tonic-gate 		register int space_left;
728*7c478bd9Sstevel@tonic-gate 		struct termios tty;
729*7c478bd9Sstevel@tonic-gate 		COMMAND command;
730*7c478bd9Sstevel@tonic-gate 
731*7c478bd9Sstevel@tonic-gate 		num_read += i;
732*7c478bd9Sstevel@tonic-gate 		inputline[num_read] = '\0';
733*7c478bd9Sstevel@tonic-gate 		last_char = inputline[num_read - 1] & TRIM;
734*7c478bd9Sstevel@tonic-gate 
735*7c478bd9Sstevel@tonic-gate 		if ((num_read == inputline_size) || (last_char == '\n'))
736*7c478bd9Sstevel@tonic-gate 			break;
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate 		str_end = &inputline[num_read];
739*7c478bd9Sstevel@tonic-gate 		if (last_char == ESC) {
740*7c478bd9Sstevel@tonic-gate 			command = RECOGNIZE;
741*7c478bd9Sstevel@tonic-gate 			*--str_end = '\0';	/* wipe out trailing ESC */
742*7c478bd9Sstevel@tonic-gate 		} else
743*7c478bd9Sstevel@tonic-gate 			command = LIST;
744*7c478bd9Sstevel@tonic-gate 
745*7c478bd9Sstevel@tonic-gate 		tty = tty_new;
746*7c478bd9Sstevel@tonic-gate 		tty.c_lflag &= ~ECHO;
747*7c478bd9Sstevel@tonic-gate 		(void) ioctl(SHIN, TCSETSF, (char *)&tty);
748*7c478bd9Sstevel@tonic-gate 
749*7c478bd9Sstevel@tonic-gate 		if (command == LIST)
750*7c478bd9Sstevel@tonic-gate 			printf("\n");
751*7c478bd9Sstevel@tonic-gate 		/*
752*7c478bd9Sstevel@tonic-gate 		 * Find LAST occurence of a delimiter in the inputline.
753*7c478bd9Sstevel@tonic-gate 		 * The word start is one character past it.
754*7c478bd9Sstevel@tonic-gate 		 */
755*7c478bd9Sstevel@tonic-gate 		for (word_start = str_end; word_start > inputline;
756*7c478bd9Sstevel@tonic-gate 		    --word_start) {
757*7c478bd9Sstevel@tonic-gate 			if (index_(delims, word_start[-1]) ||
758*7c478bd9Sstevel@tonic-gate 			    isauxsp(word_start[-1]))
759*7c478bd9Sstevel@tonic-gate 				break;
760*7c478bd9Sstevel@tonic-gate 		}
761*7c478bd9Sstevel@tonic-gate 		space_left = inputline_size - (word_start - inputline) - 1;
762*7c478bd9Sstevel@tonic-gate 		numitems = search2(word_start, command, space_left);
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate 		/*
765*7c478bd9Sstevel@tonic-gate 		 * Tabs in the input line cause trouble after a pushback.
766*7c478bd9Sstevel@tonic-gate 		 * tty driver won't backspace over them because column
767*7c478bd9Sstevel@tonic-gate 		 * positions are now incorrect. This is solved by retyping
768*7c478bd9Sstevel@tonic-gate 		 * over current line.
769*7c478bd9Sstevel@tonic-gate 		 */
770*7c478bd9Sstevel@tonic-gate 		if (index_(inputline, '\t')) {	/* tab tchar in input line? */
771*7c478bd9Sstevel@tonic-gate 			back_to_col_1();
772*7c478bd9Sstevel@tonic-gate 			should_retype = TRUE;
773*7c478bd9Sstevel@tonic-gate 		}
774*7c478bd9Sstevel@tonic-gate 		if (command == LIST)		/* Always retype after a LIST */
775*7c478bd9Sstevel@tonic-gate 			should_retype = TRUE;
776*7c478bd9Sstevel@tonic-gate 		if (should_retype)
777*7c478bd9Sstevel@tonic-gate 			printprompt();
778*7c478bd9Sstevel@tonic-gate 		pushback(inputline, should_retype);
779*7c478bd9Sstevel@tonic-gate 		num_read = 0;			/* chars will be reread */
780*7c478bd9Sstevel@tonic-gate 		should_retype = FALSE;
781*7c478bd9Sstevel@tonic-gate 
782*7c478bd9Sstevel@tonic-gate 		/*
783*7c478bd9Sstevel@tonic-gate 		 * Avoid a race condition by echoing what we're recognized
784*7c478bd9Sstevel@tonic-gate 		 * _after_ pushing back the command line.  This way, if the
785*7c478bd9Sstevel@tonic-gate 		 * user waits until seeing this output before typing more
786*7c478bd9Sstevel@tonic-gate 		 * stuff, the resulting keystrokes won't race with the STIed
787*7c478bd9Sstevel@tonic-gate 		 * input we've pushed back.  (Of course, if the user types
788*7c478bd9Sstevel@tonic-gate 		 * ahead, the race still exists and it's quite possible that
789*7c478bd9Sstevel@tonic-gate 		 * the pushed back input line will interleave with the
790*7c478bd9Sstevel@tonic-gate 		 * keystrokes in unexpected ways.)
791*7c478bd9Sstevel@tonic-gate 		 */
792*7c478bd9Sstevel@tonic-gate 		if (command == RECOGNIZE) {
793*7c478bd9Sstevel@tonic-gate 			/* print from str_end on */
794*7c478bd9Sstevel@tonic-gate 			print_recognized_stuff(str_end);
795*7c478bd9Sstevel@tonic-gate 			if (numitems != 1)	/* Beep = No match/ambiguous */
796*7c478bd9Sstevel@tonic-gate 				beep();
797*7c478bd9Sstevel@tonic-gate 		}
798*7c478bd9Sstevel@tonic-gate 	}
799*7c478bd9Sstevel@tonic-gate 	setup_tty(OFF);
800*7c478bd9Sstevel@tonic-gate 	return (num_read);
801*7c478bd9Sstevel@tonic-gate }
802*7c478bd9Sstevel@tonic-gate 
803*7c478bd9Sstevel@tonic-gate static
804*7c478bd9Sstevel@tonic-gate ignored(entry)
805*7c478bd9Sstevel@tonic-gate 	register tchar *entry;
806*7c478bd9Sstevel@tonic-gate {
807*7c478bd9Sstevel@tonic-gate 	struct varent *vp;
808*7c478bd9Sstevel@tonic-gate 	register tchar **cp;
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate #ifdef TRACE
811*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- ignored()\n");
812*7c478bd9Sstevel@tonic-gate #endif
813*7c478bd9Sstevel@tonic-gate 	if ((vp = adrof(S_fignore /*"fignore"*/)) == NULL ||
814*7c478bd9Sstevel@tonic-gate 	    (cp = vp->vec) == NULL)
815*7c478bd9Sstevel@tonic-gate 		return (FALSE);
816*7c478bd9Sstevel@tonic-gate 	for (; *cp != NULL; cp++)
817*7c478bd9Sstevel@tonic-gate 		if (is_suffix(entry, *cp))
818*7c478bd9Sstevel@tonic-gate 			return (TRUE);
819*7c478bd9Sstevel@tonic-gate 	return (FALSE);
820*7c478bd9Sstevel@tonic-gate }
821*7c478bd9Sstevel@tonic-gate #endif FILEC
822