1*d1e4d7ceSDavid van Moolenbroek /* $NetBSD: file.c,v 1.30 2013/07/16 17:47:43 christos Exp $ */
2*d1e4d7ceSDavid van Moolenbroek
3*d1e4d7ceSDavid van Moolenbroek /*-
4*d1e4d7ceSDavid van Moolenbroek * Copyright (c) 1980, 1991, 1993
5*d1e4d7ceSDavid van Moolenbroek * The Regents of the University of California. All rights reserved.
6*d1e4d7ceSDavid van Moolenbroek *
7*d1e4d7ceSDavid van Moolenbroek * Redistribution and use in source and binary forms, with or without
8*d1e4d7ceSDavid van Moolenbroek * modification, are permitted provided that the following conditions
9*d1e4d7ceSDavid van Moolenbroek * are met:
10*d1e4d7ceSDavid van Moolenbroek * 1. Redistributions of source code must retain the above copyright
11*d1e4d7ceSDavid van Moolenbroek * notice, this list of conditions and the following disclaimer.
12*d1e4d7ceSDavid van Moolenbroek * 2. Redistributions in binary form must reproduce the above copyright
13*d1e4d7ceSDavid van Moolenbroek * notice, this list of conditions and the following disclaimer in the
14*d1e4d7ceSDavid van Moolenbroek * documentation and/or other materials provided with the distribution.
15*d1e4d7ceSDavid van Moolenbroek * 3. Neither the name of the University nor the names of its contributors
16*d1e4d7ceSDavid van Moolenbroek * may be used to endorse or promote products derived from this software
17*d1e4d7ceSDavid van Moolenbroek * without specific prior written permission.
18*d1e4d7ceSDavid van Moolenbroek *
19*d1e4d7ceSDavid van Moolenbroek * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20*d1e4d7ceSDavid van Moolenbroek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*d1e4d7ceSDavid van Moolenbroek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*d1e4d7ceSDavid van Moolenbroek * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23*d1e4d7ceSDavid van Moolenbroek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24*d1e4d7ceSDavid van Moolenbroek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25*d1e4d7ceSDavid van Moolenbroek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26*d1e4d7ceSDavid van Moolenbroek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27*d1e4d7ceSDavid van Moolenbroek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*d1e4d7ceSDavid van Moolenbroek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*d1e4d7ceSDavid van Moolenbroek * SUCH DAMAGE.
30*d1e4d7ceSDavid van Moolenbroek */
31*d1e4d7ceSDavid van Moolenbroek
32*d1e4d7ceSDavid van Moolenbroek #include <sys/cdefs.h>
33*d1e4d7ceSDavid van Moolenbroek #ifndef lint
34*d1e4d7ceSDavid van Moolenbroek #if 0
35*d1e4d7ceSDavid van Moolenbroek static char sccsid[] = "@(#)file.c 8.2 (Berkeley) 3/19/94";
36*d1e4d7ceSDavid van Moolenbroek #else
37*d1e4d7ceSDavid van Moolenbroek __RCSID("$NetBSD: file.c,v 1.30 2013/07/16 17:47:43 christos Exp $");
38*d1e4d7ceSDavid van Moolenbroek #endif
39*d1e4d7ceSDavid van Moolenbroek #endif /* not lint */
40*d1e4d7ceSDavid van Moolenbroek
41*d1e4d7ceSDavid van Moolenbroek #ifdef FILEC
42*d1e4d7ceSDavid van Moolenbroek
43*d1e4d7ceSDavid van Moolenbroek #include <sys/ioctl.h>
44*d1e4d7ceSDavid van Moolenbroek #include <sys/param.h>
45*d1e4d7ceSDavid van Moolenbroek #include <sys/stat.h>
46*d1e4d7ceSDavid van Moolenbroek #include <sys/tty.h>
47*d1e4d7ceSDavid van Moolenbroek
48*d1e4d7ceSDavid van Moolenbroek #include <dirent.h>
49*d1e4d7ceSDavid van Moolenbroek #include <pwd.h>
50*d1e4d7ceSDavid van Moolenbroek #include <termios.h>
51*d1e4d7ceSDavid van Moolenbroek #include <stdarg.h>
52*d1e4d7ceSDavid van Moolenbroek #include <stdlib.h>
53*d1e4d7ceSDavid van Moolenbroek #include <unistd.h>
54*d1e4d7ceSDavid van Moolenbroek
55*d1e4d7ceSDavid van Moolenbroek #ifndef SHORT_STRINGS
56*d1e4d7ceSDavid van Moolenbroek #include <string.h>
57*d1e4d7ceSDavid van Moolenbroek #endif /* SHORT_STRINGS */
58*d1e4d7ceSDavid van Moolenbroek
59*d1e4d7ceSDavid van Moolenbroek #include "csh.h"
60*d1e4d7ceSDavid van Moolenbroek #include "extern.h"
61*d1e4d7ceSDavid van Moolenbroek
62*d1e4d7ceSDavid van Moolenbroek /*
63*d1e4d7ceSDavid van Moolenbroek * Tenex style file name recognition, .. and more.
64*d1e4d7ceSDavid van Moolenbroek * History:
65*d1e4d7ceSDavid van Moolenbroek * Author: Ken Greer, Sept. 1975, CMU.
66*d1e4d7ceSDavid van Moolenbroek * Finally got around to adding to the Cshell., Ken Greer, Dec. 1981.
67*d1e4d7ceSDavid van Moolenbroek */
68*d1e4d7ceSDavid van Moolenbroek
69*d1e4d7ceSDavid van Moolenbroek #define ON 1
70*d1e4d7ceSDavid van Moolenbroek #define OFF 0
71*d1e4d7ceSDavid van Moolenbroek #ifndef TRUE
72*d1e4d7ceSDavid van Moolenbroek #define TRUE 1
73*d1e4d7ceSDavid van Moolenbroek #endif
74*d1e4d7ceSDavid van Moolenbroek #ifndef FALSE
75*d1e4d7ceSDavid van Moolenbroek #define FALSE 0
76*d1e4d7ceSDavid van Moolenbroek #endif
77*d1e4d7ceSDavid van Moolenbroek
78*d1e4d7ceSDavid van Moolenbroek #define ESC '\033'
79*d1e4d7ceSDavid van Moolenbroek
80*d1e4d7ceSDavid van Moolenbroek typedef enum {
81*d1e4d7ceSDavid van Moolenbroek LIST, RECOGNIZE
82*d1e4d7ceSDavid van Moolenbroek } COMMAND;
83*d1e4d7ceSDavid van Moolenbroek
84*d1e4d7ceSDavid van Moolenbroek static void setup_tty(int);
85*d1e4d7ceSDavid van Moolenbroek static void back_to_col_1(void);
86*d1e4d7ceSDavid van Moolenbroek static int pushback(Char *);
87*d1e4d7ceSDavid van Moolenbroek static void catn(Char *, Char *, size_t);
88*d1e4d7ceSDavid van Moolenbroek static void copyn(Char *, Char *, size_t);
89*d1e4d7ceSDavid van Moolenbroek static Char filetype(Char *, Char *);
90*d1e4d7ceSDavid van Moolenbroek static void print_by_column(Char *, Char *[], size_t);
91*d1e4d7ceSDavid van Moolenbroek static Char *tilde(Char *, Char *);
92*d1e4d7ceSDavid van Moolenbroek static void retype(void);
93*d1e4d7ceSDavid van Moolenbroek static void beep(void);
94*d1e4d7ceSDavid van Moolenbroek static void print_recognized_stuff(Char *);
95*d1e4d7ceSDavid van Moolenbroek static void extract_dir_and_name(Char *, Char *, Char *);
96*d1e4d7ceSDavid van Moolenbroek static Char *getentry(DIR *, int);
97*d1e4d7ceSDavid van Moolenbroek static void free_items(Char **, size_t);
98*d1e4d7ceSDavid van Moolenbroek static size_t tsearch(Char *, COMMAND, size_t);
99*d1e4d7ceSDavid van Moolenbroek static int recognize(Char *, Char *, size_t, size_t);
100*d1e4d7ceSDavid van Moolenbroek static int is_prefix(Char *, Char *);
101*d1e4d7ceSDavid van Moolenbroek static int is_suffix(Char *, Char *);
102*d1e4d7ceSDavid van Moolenbroek static int ignored(Char *);
103*d1e4d7ceSDavid van Moolenbroek
104*d1e4d7ceSDavid van Moolenbroek /*
105*d1e4d7ceSDavid van Moolenbroek * Put this here so the binary can be patched with adb to enable file
106*d1e4d7ceSDavid van Moolenbroek * completion by default. Filec controls completion, nobeep controls
107*d1e4d7ceSDavid van Moolenbroek * ringing the terminal bell on incomplete expansions.
108*d1e4d7ceSDavid van Moolenbroek */
109*d1e4d7ceSDavid van Moolenbroek int filec = 0;
110*d1e4d7ceSDavid van Moolenbroek
111*d1e4d7ceSDavid van Moolenbroek static void
setup_tty(int on)112*d1e4d7ceSDavid van Moolenbroek setup_tty(int on)
113*d1e4d7ceSDavid van Moolenbroek {
114*d1e4d7ceSDavid van Moolenbroek struct termios tchars;
115*d1e4d7ceSDavid van Moolenbroek
116*d1e4d7ceSDavid van Moolenbroek (void)tcgetattr(SHIN, &tchars);
117*d1e4d7ceSDavid van Moolenbroek
118*d1e4d7ceSDavid van Moolenbroek if (on) {
119*d1e4d7ceSDavid van Moolenbroek tchars.c_cc[VEOL] = ESC;
120*d1e4d7ceSDavid van Moolenbroek if (tchars.c_lflag & ICANON)
121*d1e4d7ceSDavid van Moolenbroek on = TCSADRAIN;
122*d1e4d7ceSDavid van Moolenbroek else {
123*d1e4d7ceSDavid van Moolenbroek tchars.c_lflag |= ICANON;
124*d1e4d7ceSDavid van Moolenbroek on = TCSAFLUSH;
125*d1e4d7ceSDavid van Moolenbroek }
126*d1e4d7ceSDavid van Moolenbroek }
127*d1e4d7ceSDavid van Moolenbroek else {
128*d1e4d7ceSDavid van Moolenbroek tchars.c_cc[VEOL] = _POSIX_VDISABLE;
129*d1e4d7ceSDavid van Moolenbroek on = TCSADRAIN;
130*d1e4d7ceSDavid van Moolenbroek }
131*d1e4d7ceSDavid van Moolenbroek
132*d1e4d7ceSDavid van Moolenbroek (void)tcsetattr(SHIN, on, &tchars);
133*d1e4d7ceSDavid van Moolenbroek }
134*d1e4d7ceSDavid van Moolenbroek
135*d1e4d7ceSDavid van Moolenbroek /*
136*d1e4d7ceSDavid van Moolenbroek * Move back to beginning of current line
137*d1e4d7ceSDavid van Moolenbroek */
138*d1e4d7ceSDavid van Moolenbroek static void
back_to_col_1(void)139*d1e4d7ceSDavid van Moolenbroek back_to_col_1(void)
140*d1e4d7ceSDavid van Moolenbroek {
141*d1e4d7ceSDavid van Moolenbroek struct termios tty, tty_normal;
142*d1e4d7ceSDavid van Moolenbroek sigset_t nsigset, osigset;
143*d1e4d7ceSDavid van Moolenbroek
144*d1e4d7ceSDavid van Moolenbroek sigemptyset(&nsigset);
145*d1e4d7ceSDavid van Moolenbroek (void)sigaddset(&nsigset, SIGINT);
146*d1e4d7ceSDavid van Moolenbroek (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset);
147*d1e4d7ceSDavid van Moolenbroek (void)tcgetattr(SHOUT, &tty);
148*d1e4d7ceSDavid van Moolenbroek tty_normal = tty;
149*d1e4d7ceSDavid van Moolenbroek tty.c_iflag &= ~INLCR;
150*d1e4d7ceSDavid van Moolenbroek tty.c_oflag &= ~ONLCR;
151*d1e4d7ceSDavid van Moolenbroek (void)tcsetattr(SHOUT, TCSADRAIN, &tty);
152*d1e4d7ceSDavid van Moolenbroek (void)write(SHOUT, "\r", 1);
153*d1e4d7ceSDavid van Moolenbroek (void)tcsetattr(SHOUT, TCSADRAIN, &tty_normal);
154*d1e4d7ceSDavid van Moolenbroek (void)sigprocmask(SIG_SETMASK, &osigset, NULL);
155*d1e4d7ceSDavid van Moolenbroek }
156*d1e4d7ceSDavid van Moolenbroek
157*d1e4d7ceSDavid van Moolenbroek /*
158*d1e4d7ceSDavid van Moolenbroek * Push string contents back into tty queue
159*d1e4d7ceSDavid van Moolenbroek */
160*d1e4d7ceSDavid van Moolenbroek static int
pushback(Char * string)161*d1e4d7ceSDavid van Moolenbroek pushback(Char *string)
162*d1e4d7ceSDavid van Moolenbroek {
163*d1e4d7ceSDavid van Moolenbroek struct termios tty, tty_normal;
164*d1e4d7ceSDavid van Moolenbroek char buf[64], svchars[sizeof(buf)];
165*d1e4d7ceSDavid van Moolenbroek sigset_t nsigset, osigset;
166*d1e4d7ceSDavid van Moolenbroek Char *p;
167*d1e4d7ceSDavid van Moolenbroek size_t bufidx, i, len_str, nbuf, nsv, onsv, retrycnt;
168*d1e4d7ceSDavid van Moolenbroek char c;
169*d1e4d7ceSDavid van Moolenbroek
170*d1e4d7ceSDavid van Moolenbroek nsv = 0;
171*d1e4d7ceSDavid van Moolenbroek sigemptyset(&nsigset);
172*d1e4d7ceSDavid van Moolenbroek (void)sigaddset(&nsigset, SIGINT);
173*d1e4d7ceSDavid van Moolenbroek (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset);
174*d1e4d7ceSDavid van Moolenbroek (void)tcgetattr(SHOUT, &tty);
175*d1e4d7ceSDavid van Moolenbroek tty_normal = tty;
176*d1e4d7ceSDavid van Moolenbroek tty.c_lflag &= ~(ECHOKE | ECHO | ECHOE | ECHOK | ECHONL | ECHOPRT | ECHOCTL);
177*d1e4d7ceSDavid van Moolenbroek /* FIONREAD works only in noncanonical mode. */
178*d1e4d7ceSDavid van Moolenbroek tty.c_lflag &= ~ICANON;
179*d1e4d7ceSDavid van Moolenbroek tty.c_cc[VMIN] = 0;
180*d1e4d7ceSDavid van Moolenbroek (void)tcsetattr(SHOUT, TCSADRAIN, &tty);
181*d1e4d7ceSDavid van Moolenbroek
182*d1e4d7ceSDavid van Moolenbroek for (retrycnt = 5; ; retrycnt--) {
183*d1e4d7ceSDavid van Moolenbroek /*
184*d1e4d7ceSDavid van Moolenbroek * Push back characters.
185*d1e4d7ceSDavid van Moolenbroek */
186*d1e4d7ceSDavid van Moolenbroek for (p = string; (c = (char)*p) != '\0'; p++)
187*d1e4d7ceSDavid van Moolenbroek (void)ioctl(SHOUT, TIOCSTI, (ioctl_t) &c);
188*d1e4d7ceSDavid van Moolenbroek for (i = 0; i < nsv; i++)
189*d1e4d7ceSDavid van Moolenbroek (void)ioctl(SHOUT, TIOCSTI, (ioctl_t) &svchars[i]);
190*d1e4d7ceSDavid van Moolenbroek
191*d1e4d7ceSDavid van Moolenbroek if (retrycnt == 0)
192*d1e4d7ceSDavid van Moolenbroek break; /* give up salvaging characters */
193*d1e4d7ceSDavid van Moolenbroek
194*d1e4d7ceSDavid van Moolenbroek len_str = (size_t)(p - string);
195*d1e4d7ceSDavid van Moolenbroek
196*d1e4d7ceSDavid van Moolenbroek if (ioctl(SHOUT, FIONREAD, (ioctl_t) &nbuf) ||
197*d1e4d7ceSDavid van Moolenbroek nbuf <= len_str + nsv || /* The string fit. */
198*d1e4d7ceSDavid van Moolenbroek nbuf > sizeof(buf)) /* For future binary compatibility
199*d1e4d7ceSDavid van Moolenbroek (and safety). */
200*d1e4d7ceSDavid van Moolenbroek break;
201*d1e4d7ceSDavid van Moolenbroek
202*d1e4d7ceSDavid van Moolenbroek /*
203*d1e4d7ceSDavid van Moolenbroek * User has typed characters before the pushback finished.
204*d1e4d7ceSDavid van Moolenbroek * Salvage the characters.
205*d1e4d7ceSDavid van Moolenbroek */
206*d1e4d7ceSDavid van Moolenbroek
207*d1e4d7ceSDavid van Moolenbroek /* This read() should be in noncanonical mode. */
208*d1e4d7ceSDavid van Moolenbroek if (read(SHOUT, &buf, nbuf) != (ssize_t)nbuf)
209*d1e4d7ceSDavid van Moolenbroek continue; /* hangup? */
210*d1e4d7ceSDavid van Moolenbroek
211*d1e4d7ceSDavid van Moolenbroek onsv = nsv;
212*d1e4d7ceSDavid van Moolenbroek for (bufidx = 0, i = 0; bufidx < nbuf; bufidx++, i++) {
213*d1e4d7ceSDavid van Moolenbroek c = buf[bufidx];
214*d1e4d7ceSDavid van Moolenbroek if ((i < len_str) ? c != (char)string[i] :
215*d1e4d7ceSDavid van Moolenbroek (i < len_str + onsv) ? c != svchars[i - len_str] : 1) {
216*d1e4d7ceSDavid van Moolenbroek /* Salvage a character. */
217*d1e4d7ceSDavid van Moolenbroek if (nsv < (int)(sizeof svchars / sizeof svchars[0])) {
218*d1e4d7ceSDavid van Moolenbroek svchars[nsv++] = c;
219*d1e4d7ceSDavid van Moolenbroek i--; /* try this comparison with the next char */
220*d1e4d7ceSDavid van Moolenbroek } else
221*d1e4d7ceSDavid van Moolenbroek break; /* too many */
222*d1e4d7ceSDavid van Moolenbroek }
223*d1e4d7ceSDavid van Moolenbroek }
224*d1e4d7ceSDavid van Moolenbroek }
225*d1e4d7ceSDavid van Moolenbroek
226*d1e4d7ceSDavid van Moolenbroek #if 1
227*d1e4d7ceSDavid van Moolenbroek /*
228*d1e4d7ceSDavid van Moolenbroek * XXX Is this a bug or a feature of kernel tty driver?
229*d1e4d7ceSDavid van Moolenbroek *
230*d1e4d7ceSDavid van Moolenbroek * FIONREAD in canonical mode does not return correct byte count
231*d1e4d7ceSDavid van Moolenbroek * in tty input queue, but this is required to avoid unwanted echo.
232*d1e4d7ceSDavid van Moolenbroek */
233*d1e4d7ceSDavid van Moolenbroek tty.c_lflag |= ICANON;
234*d1e4d7ceSDavid van Moolenbroek (void)tcsetattr(SHOUT, TCSADRAIN, &tty);
235*d1e4d7ceSDavid van Moolenbroek (void)ioctl(SHOUT, FIONREAD, (ioctl_t) &i);
236*d1e4d7ceSDavid van Moolenbroek #endif
237*d1e4d7ceSDavid van Moolenbroek (void)tcsetattr(SHOUT, TCSADRAIN, &tty_normal);
238*d1e4d7ceSDavid van Moolenbroek (void)sigprocmask(SIG_SETMASK, &osigset, NULL);
239*d1e4d7ceSDavid van Moolenbroek
240*d1e4d7ceSDavid van Moolenbroek return (int)nsv;
241*d1e4d7ceSDavid van Moolenbroek }
242*d1e4d7ceSDavid van Moolenbroek
243*d1e4d7ceSDavid van Moolenbroek /*
244*d1e4d7ceSDavid van Moolenbroek * Concatenate src onto tail of des.
245*d1e4d7ceSDavid van Moolenbroek * Des is a string whose maximum length is count.
246*d1e4d7ceSDavid van Moolenbroek * Always null terminate.
247*d1e4d7ceSDavid van Moolenbroek */
248*d1e4d7ceSDavid van Moolenbroek static void
catn(Char * des,Char * src,size_t count)249*d1e4d7ceSDavid van Moolenbroek catn(Char *des, Char *src, size_t count)
250*d1e4d7ceSDavid van Moolenbroek {
251*d1e4d7ceSDavid van Moolenbroek while (count-- > 0 && *des)
252*d1e4d7ceSDavid van Moolenbroek des++;
253*d1e4d7ceSDavid van Moolenbroek while (count-- > 0)
254*d1e4d7ceSDavid van Moolenbroek if ((*des++ = *src++) == 0)
255*d1e4d7ceSDavid van Moolenbroek return;
256*d1e4d7ceSDavid van Moolenbroek *des = '\0';
257*d1e4d7ceSDavid van Moolenbroek }
258*d1e4d7ceSDavid van Moolenbroek
259*d1e4d7ceSDavid van Moolenbroek /*
260*d1e4d7ceSDavid van Moolenbroek * Like strncpy but always leave room for trailing \0
261*d1e4d7ceSDavid van Moolenbroek * and always null terminate.
262*d1e4d7ceSDavid van Moolenbroek */
263*d1e4d7ceSDavid van Moolenbroek static void
copyn(Char * des,Char * src,size_t count)264*d1e4d7ceSDavid van Moolenbroek copyn(Char *des, Char *src, size_t count)
265*d1e4d7ceSDavid van Moolenbroek {
266*d1e4d7ceSDavid van Moolenbroek while (count-- > 0)
267*d1e4d7ceSDavid van Moolenbroek if ((*des++ = *src++) == 0)
268*d1e4d7ceSDavid van Moolenbroek return;
269*d1e4d7ceSDavid van Moolenbroek *des = '\0';
270*d1e4d7ceSDavid van Moolenbroek }
271*d1e4d7ceSDavid van Moolenbroek
272*d1e4d7ceSDavid van Moolenbroek static Char
filetype(Char * dir,Char * file)273*d1e4d7ceSDavid van Moolenbroek filetype(Char *dir, Char *file)
274*d1e4d7ceSDavid van Moolenbroek {
275*d1e4d7ceSDavid van Moolenbroek struct stat statb;
276*d1e4d7ceSDavid van Moolenbroek Char path[MAXPATHLEN];
277*d1e4d7ceSDavid van Moolenbroek
278*d1e4d7ceSDavid van Moolenbroek catn(Strcpy(path, dir), file, sizeof(path) / sizeof(Char));
279*d1e4d7ceSDavid van Moolenbroek if (lstat(short2str(path), &statb) == 0) {
280*d1e4d7ceSDavid van Moolenbroek switch (statb.st_mode & S_IFMT) {
281*d1e4d7ceSDavid van Moolenbroek case S_IFDIR:
282*d1e4d7ceSDavid van Moolenbroek return ('/');
283*d1e4d7ceSDavid van Moolenbroek case S_IFLNK:
284*d1e4d7ceSDavid van Moolenbroek if (stat(short2str(path), &statb) == 0 && /* follow it out */
285*d1e4d7ceSDavid van Moolenbroek S_ISDIR(statb.st_mode))
286*d1e4d7ceSDavid van Moolenbroek return ('>');
287*d1e4d7ceSDavid van Moolenbroek else
288*d1e4d7ceSDavid van Moolenbroek return ('@');
289*d1e4d7ceSDavid van Moolenbroek case S_IFSOCK:
290*d1e4d7ceSDavid van Moolenbroek return ('=');
291*d1e4d7ceSDavid van Moolenbroek default:
292*d1e4d7ceSDavid van Moolenbroek if (statb.st_mode & 0111)
293*d1e4d7ceSDavid van Moolenbroek return ('*');
294*d1e4d7ceSDavid van Moolenbroek }
295*d1e4d7ceSDavid van Moolenbroek }
296*d1e4d7ceSDavid van Moolenbroek return (' ');
297*d1e4d7ceSDavid van Moolenbroek }
298*d1e4d7ceSDavid van Moolenbroek
299*d1e4d7ceSDavid van Moolenbroek static struct winsize win;
300*d1e4d7ceSDavid van Moolenbroek
301*d1e4d7ceSDavid van Moolenbroek /*
302*d1e4d7ceSDavid van Moolenbroek * Print sorted down columns
303*d1e4d7ceSDavid van Moolenbroek */
304*d1e4d7ceSDavid van Moolenbroek static void
print_by_column(Char * dir,Char * items[],size_t count)305*d1e4d7ceSDavid van Moolenbroek print_by_column(Char *dir, Char *items[], size_t count)
306*d1e4d7ceSDavid van Moolenbroek {
307*d1e4d7ceSDavid van Moolenbroek size_t c, columns, i, maxwidth, r, rows;
308*d1e4d7ceSDavid van Moolenbroek
309*d1e4d7ceSDavid van Moolenbroek maxwidth = 0;
310*d1e4d7ceSDavid van Moolenbroek
311*d1e4d7ceSDavid van Moolenbroek if (ioctl(SHOUT, TIOCGWINSZ, (ioctl_t) & win) < 0 || win.ws_col == 0)
312*d1e4d7ceSDavid van Moolenbroek win.ws_col = 80;
313*d1e4d7ceSDavid van Moolenbroek for (i = 0; i < count; i++)
314*d1e4d7ceSDavid van Moolenbroek maxwidth = maxwidth > (r = Strlen(items[i])) ? maxwidth : r;
315*d1e4d7ceSDavid van Moolenbroek maxwidth += 2; /* for the file tag and space */
316*d1e4d7ceSDavid van Moolenbroek columns = win.ws_col / maxwidth;
317*d1e4d7ceSDavid van Moolenbroek if (columns == 0)
318*d1e4d7ceSDavid van Moolenbroek columns = 1;
319*d1e4d7ceSDavid van Moolenbroek rows = (count + (columns - 1)) / columns;
320*d1e4d7ceSDavid van Moolenbroek for (r = 0; r < rows; r++) {
321*d1e4d7ceSDavid van Moolenbroek for (c = 0; c < columns; c++) {
322*d1e4d7ceSDavid van Moolenbroek i = c * rows + r;
323*d1e4d7ceSDavid van Moolenbroek if (i < count) {
324*d1e4d7ceSDavid van Moolenbroek size_t w;
325*d1e4d7ceSDavid van Moolenbroek
326*d1e4d7ceSDavid van Moolenbroek (void)fprintf(cshout, "%s", vis_str(items[i]));
327*d1e4d7ceSDavid van Moolenbroek (void)fputc(dir ? filetype(dir, items[i]) : ' ', cshout);
328*d1e4d7ceSDavid van Moolenbroek if (c < columns - 1) { /* last column? */
329*d1e4d7ceSDavid van Moolenbroek w = Strlen(items[i]) + 1;
330*d1e4d7ceSDavid van Moolenbroek for (; w < maxwidth; w++)
331*d1e4d7ceSDavid van Moolenbroek (void) fputc(' ', cshout);
332*d1e4d7ceSDavid van Moolenbroek }
333*d1e4d7ceSDavid van Moolenbroek }
334*d1e4d7ceSDavid van Moolenbroek }
335*d1e4d7ceSDavid van Moolenbroek (void)fputc('\r', cshout);
336*d1e4d7ceSDavid van Moolenbroek (void)fputc('\n', cshout);
337*d1e4d7ceSDavid van Moolenbroek }
338*d1e4d7ceSDavid van Moolenbroek }
339*d1e4d7ceSDavid van Moolenbroek
340*d1e4d7ceSDavid van Moolenbroek /*
341*d1e4d7ceSDavid van Moolenbroek * Expand file name with possible tilde usage
342*d1e4d7ceSDavid van Moolenbroek * ~person/mumble
343*d1e4d7ceSDavid van Moolenbroek * expands to
344*d1e4d7ceSDavid van Moolenbroek * home_directory_of_person/mumble
345*d1e4d7ceSDavid van Moolenbroek */
346*d1e4d7ceSDavid van Moolenbroek static Char *
tilde(Char * new,Char * old)347*d1e4d7ceSDavid van Moolenbroek tilde(Char *new, Char *old)
348*d1e4d7ceSDavid van Moolenbroek {
349*d1e4d7ceSDavid van Moolenbroek static Char person[40];
350*d1e4d7ceSDavid van Moolenbroek struct passwd *pw;
351*d1e4d7ceSDavid van Moolenbroek Char *o, *p;
352*d1e4d7ceSDavid van Moolenbroek
353*d1e4d7ceSDavid van Moolenbroek if (old[0] != '~')
354*d1e4d7ceSDavid van Moolenbroek return (Strcpy(new, old));
355*d1e4d7ceSDavid van Moolenbroek
356*d1e4d7ceSDavid van Moolenbroek for (p = person, o = &old[1]; *o && *o != '/'; *p++ = *o++)
357*d1e4d7ceSDavid van Moolenbroek continue;
358*d1e4d7ceSDavid van Moolenbroek *p = '\0';
359*d1e4d7ceSDavid van Moolenbroek if (person[0] == '\0')
360*d1e4d7ceSDavid van Moolenbroek (void)Strcpy(new, value(STRhome));
361*d1e4d7ceSDavid van Moolenbroek else {
362*d1e4d7ceSDavid van Moolenbroek pw = getpwnam(short2str(person));
363*d1e4d7ceSDavid van Moolenbroek if (pw == NULL)
364*d1e4d7ceSDavid van Moolenbroek return (NULL);
365*d1e4d7ceSDavid van Moolenbroek (void)Strcpy(new, str2short(pw->pw_dir));
366*d1e4d7ceSDavid van Moolenbroek }
367*d1e4d7ceSDavid van Moolenbroek (void)Strcat(new, o);
368*d1e4d7ceSDavid van Moolenbroek return (new);
369*d1e4d7ceSDavid van Moolenbroek }
370*d1e4d7ceSDavid van Moolenbroek
371*d1e4d7ceSDavid van Moolenbroek /*
372*d1e4d7ceSDavid van Moolenbroek * Cause pending line to be printed
373*d1e4d7ceSDavid van Moolenbroek */
374*d1e4d7ceSDavid van Moolenbroek static void
retype(void)375*d1e4d7ceSDavid van Moolenbroek retype(void)
376*d1e4d7ceSDavid van Moolenbroek {
377*d1e4d7ceSDavid van Moolenbroek struct termios tty;
378*d1e4d7ceSDavid van Moolenbroek
379*d1e4d7ceSDavid van Moolenbroek (void)tcgetattr(SHOUT, &tty);
380*d1e4d7ceSDavid van Moolenbroek tty.c_lflag |= PENDIN;
381*d1e4d7ceSDavid van Moolenbroek (void)tcsetattr(SHOUT, TCSADRAIN, &tty);
382*d1e4d7ceSDavid van Moolenbroek }
383*d1e4d7ceSDavid van Moolenbroek
384*d1e4d7ceSDavid van Moolenbroek static void
beep(void)385*d1e4d7ceSDavid van Moolenbroek beep(void)
386*d1e4d7ceSDavid van Moolenbroek {
387*d1e4d7ceSDavid van Moolenbroek if (adrof(STRnobeep) == 0)
388*d1e4d7ceSDavid van Moolenbroek (void)write(SHOUT, "\007", 1);
389*d1e4d7ceSDavid van Moolenbroek }
390*d1e4d7ceSDavid van Moolenbroek
391*d1e4d7ceSDavid van Moolenbroek /*
392*d1e4d7ceSDavid van Moolenbroek * Erase that silly ^[ and
393*d1e4d7ceSDavid van Moolenbroek * print the recognized part of the string
394*d1e4d7ceSDavid van Moolenbroek */
395*d1e4d7ceSDavid van Moolenbroek static void
print_recognized_stuff(Char * recognized_part)396*d1e4d7ceSDavid van Moolenbroek print_recognized_stuff(Char *recognized_part)
397*d1e4d7ceSDavid van Moolenbroek {
398*d1e4d7ceSDavid van Moolenbroek /* An optimized erasing of that silly ^[ */
399*d1e4d7ceSDavid van Moolenbroek (void)fputc('\b', cshout);
400*d1e4d7ceSDavid van Moolenbroek (void)fputc('\b', cshout);
401*d1e4d7ceSDavid van Moolenbroek switch (Strlen(recognized_part)) {
402*d1e4d7ceSDavid van Moolenbroek case 0: /* erase two Characters: ^[ */
403*d1e4d7ceSDavid van Moolenbroek (void)fputc(' ', cshout);
404*d1e4d7ceSDavid van Moolenbroek (void)fputc(' ', cshout);
405*d1e4d7ceSDavid van Moolenbroek (void)fputc('\b', cshout);
406*d1e4d7ceSDavid van Moolenbroek (void)fputc('\b', cshout);
407*d1e4d7ceSDavid van Moolenbroek break;
408*d1e4d7ceSDavid van Moolenbroek case 1: /* overstrike the ^, erase the [ */
409*d1e4d7ceSDavid van Moolenbroek (void)fprintf(cshout, "%s", vis_str(recognized_part));
410*d1e4d7ceSDavid van Moolenbroek (void)fputc(' ', cshout);
411*d1e4d7ceSDavid van Moolenbroek (void)fputc('\b', cshout);
412*d1e4d7ceSDavid van Moolenbroek break;
413*d1e4d7ceSDavid van Moolenbroek default: /* overstrike both Characters ^[ */
414*d1e4d7ceSDavid van Moolenbroek (void)fprintf(cshout, "%s", vis_str(recognized_part));
415*d1e4d7ceSDavid van Moolenbroek break;
416*d1e4d7ceSDavid van Moolenbroek }
417*d1e4d7ceSDavid van Moolenbroek (void)fflush(cshout);
418*d1e4d7ceSDavid van Moolenbroek }
419*d1e4d7ceSDavid van Moolenbroek
420*d1e4d7ceSDavid van Moolenbroek /*
421*d1e4d7ceSDavid van Moolenbroek * Parse full path in file into 2 parts: directory and file names
422*d1e4d7ceSDavid van Moolenbroek * Should leave final slash (/) at end of dir.
423*d1e4d7ceSDavid van Moolenbroek */
424*d1e4d7ceSDavid van Moolenbroek static void
extract_dir_and_name(Char * path,Char * dir,Char * name)425*d1e4d7ceSDavid van Moolenbroek extract_dir_and_name(Char *path, Char *dir, Char *name)
426*d1e4d7ceSDavid van Moolenbroek {
427*d1e4d7ceSDavid van Moolenbroek Char *p;
428*d1e4d7ceSDavid van Moolenbroek
429*d1e4d7ceSDavid van Moolenbroek p = Strrchr(path, '/');
430*d1e4d7ceSDavid van Moolenbroek if (p == NULL) {
431*d1e4d7ceSDavid van Moolenbroek copyn(name, path, MAXNAMLEN);
432*d1e4d7ceSDavid van Moolenbroek dir[0] = '\0';
433*d1e4d7ceSDavid van Moolenbroek }
434*d1e4d7ceSDavid van Moolenbroek else {
435*d1e4d7ceSDavid van Moolenbroek copyn(name, ++p, MAXNAMLEN);
436*d1e4d7ceSDavid van Moolenbroek copyn(dir, path, (size_t)(p - path));
437*d1e4d7ceSDavid van Moolenbroek }
438*d1e4d7ceSDavid van Moolenbroek }
439*d1e4d7ceSDavid van Moolenbroek
440*d1e4d7ceSDavid van Moolenbroek static Char *
getentry(DIR * dir_fd,int looking_for_lognames)441*d1e4d7ceSDavid van Moolenbroek getentry(DIR *dir_fd, int looking_for_lognames)
442*d1e4d7ceSDavid van Moolenbroek {
443*d1e4d7ceSDavid van Moolenbroek struct dirent *dirp;
444*d1e4d7ceSDavid van Moolenbroek struct passwd *pw;
445*d1e4d7ceSDavid van Moolenbroek
446*d1e4d7ceSDavid van Moolenbroek if (looking_for_lognames) {
447*d1e4d7ceSDavid van Moolenbroek if ((pw = getpwent()) == NULL)
448*d1e4d7ceSDavid van Moolenbroek return (NULL);
449*d1e4d7ceSDavid van Moolenbroek return (str2short(pw->pw_name));
450*d1e4d7ceSDavid van Moolenbroek }
451*d1e4d7ceSDavid van Moolenbroek if ((dirp = readdir(dir_fd)) != NULL)
452*d1e4d7ceSDavid van Moolenbroek return (str2short(dirp->d_name));
453*d1e4d7ceSDavid van Moolenbroek return (NULL);
454*d1e4d7ceSDavid van Moolenbroek }
455*d1e4d7ceSDavid van Moolenbroek
456*d1e4d7ceSDavid van Moolenbroek static void
free_items(Char ** items,size_t numitems)457*d1e4d7ceSDavid van Moolenbroek free_items(Char **items, size_t numitems)
458*d1e4d7ceSDavid van Moolenbroek {
459*d1e4d7ceSDavid van Moolenbroek size_t i;
460*d1e4d7ceSDavid van Moolenbroek
461*d1e4d7ceSDavid van Moolenbroek for (i = 0; i < numitems; i++)
462*d1e4d7ceSDavid van Moolenbroek xfree((ptr_t) items[i]);
463*d1e4d7ceSDavid van Moolenbroek xfree((ptr_t) items);
464*d1e4d7ceSDavid van Moolenbroek }
465*d1e4d7ceSDavid van Moolenbroek
466*d1e4d7ceSDavid van Moolenbroek #define FREE_ITEMS(items, numitems) { \
467*d1e4d7ceSDavid van Moolenbroek sigset_t nsigset, osigset;\
468*d1e4d7ceSDavid van Moolenbroek \
469*d1e4d7ceSDavid van Moolenbroek sigemptyset(&nsigset);\
470*d1e4d7ceSDavid van Moolenbroek (void) sigaddset(&nsigset, SIGINT);\
471*d1e4d7ceSDavid van Moolenbroek (void) sigprocmask(SIG_BLOCK, &nsigset, &osigset);\
472*d1e4d7ceSDavid van Moolenbroek free_items(items, numitems);\
473*d1e4d7ceSDavid van Moolenbroek (void) sigprocmask(SIG_SETMASK, &osigset, NULL);\
474*d1e4d7ceSDavid van Moolenbroek }
475*d1e4d7ceSDavid van Moolenbroek
476*d1e4d7ceSDavid van Moolenbroek /*
477*d1e4d7ceSDavid van Moolenbroek * Perform a RECOGNIZE or LIST command on string "word".
478*d1e4d7ceSDavid van Moolenbroek */
479*d1e4d7ceSDavid van Moolenbroek static size_t
tsearch(Char * word,COMMAND command,size_t max_word_length)480*d1e4d7ceSDavid van Moolenbroek tsearch(Char *word, COMMAND command, size_t max_word_length)
481*d1e4d7ceSDavid van Moolenbroek {
482*d1e4d7ceSDavid van Moolenbroek Char dir[MAXPATHLEN + 1], extended_name[MAXNAMLEN + 1];
483*d1e4d7ceSDavid van Moolenbroek Char name[MAXNAMLEN + 1], tilded_dir[MAXPATHLEN + 1];
484*d1e4d7ceSDavid van Moolenbroek DIR *dir_fd;
485*d1e4d7ceSDavid van Moolenbroek Char *entry;
486*d1e4d7ceSDavid van Moolenbroek int ignoring, looking_for_lognames;
487*d1e4d7ceSDavid van Moolenbroek size_t name_length, nignored, numitems;
488*d1e4d7ceSDavid van Moolenbroek Char **items = NULL;
489*d1e4d7ceSDavid van Moolenbroek size_t maxitems = 0;
490*d1e4d7ceSDavid van Moolenbroek
491*d1e4d7ceSDavid van Moolenbroek numitems = 0;
492*d1e4d7ceSDavid van Moolenbroek ignoring = TRUE;
493*d1e4d7ceSDavid van Moolenbroek nignored = 0;
494*d1e4d7ceSDavid van Moolenbroek
495*d1e4d7ceSDavid van Moolenbroek looking_for_lognames = (*word == '~') && (Strchr(word, '/') == NULL);
496*d1e4d7ceSDavid van Moolenbroek if (looking_for_lognames) {
497*d1e4d7ceSDavid van Moolenbroek (void)setpwent();
498*d1e4d7ceSDavid van Moolenbroek copyn(name, &word[1], MAXNAMLEN); /* name sans ~ */
499*d1e4d7ceSDavid van Moolenbroek dir_fd = NULL;
500*d1e4d7ceSDavid van Moolenbroek }
501*d1e4d7ceSDavid van Moolenbroek else {
502*d1e4d7ceSDavid van Moolenbroek extract_dir_and_name(word, dir, name);
503*d1e4d7ceSDavid van Moolenbroek if (tilde(tilded_dir, dir) == 0)
504*d1e4d7ceSDavid van Moolenbroek return (0);
505*d1e4d7ceSDavid van Moolenbroek dir_fd = opendir(*tilded_dir ? short2str(tilded_dir) : ".");
506*d1e4d7ceSDavid van Moolenbroek if (dir_fd == NULL)
507*d1e4d7ceSDavid van Moolenbroek return (0);
508*d1e4d7ceSDavid van Moolenbroek }
509*d1e4d7ceSDavid van Moolenbroek
510*d1e4d7ceSDavid van Moolenbroek again: /* search for matches */
511*d1e4d7ceSDavid van Moolenbroek name_length = Strlen(name);
512*d1e4d7ceSDavid van Moolenbroek for (numitems = 0; (entry = getentry(dir_fd, looking_for_lognames)) != NULL;) {
513*d1e4d7ceSDavid van Moolenbroek if (!is_prefix(name, entry))
514*d1e4d7ceSDavid van Moolenbroek continue;
515*d1e4d7ceSDavid van Moolenbroek /* Don't match . files on null prefix match */
516*d1e4d7ceSDavid van Moolenbroek if (name_length == 0 && entry[0] == '.' &&
517*d1e4d7ceSDavid van Moolenbroek !looking_for_lognames)
518*d1e4d7ceSDavid van Moolenbroek continue;
519*d1e4d7ceSDavid van Moolenbroek if (command == LIST) {
520*d1e4d7ceSDavid van Moolenbroek if ((size_t)numitems >= maxitems) {
521*d1e4d7ceSDavid van Moolenbroek maxitems += 1024;
522*d1e4d7ceSDavid van Moolenbroek if (items == NULL)
523*d1e4d7ceSDavid van Moolenbroek items = xmalloc(sizeof(*items) * maxitems);
524*d1e4d7ceSDavid van Moolenbroek else
525*d1e4d7ceSDavid van Moolenbroek items = xrealloc((ptr_t) items,
526*d1e4d7ceSDavid van Moolenbroek sizeof(*items) * maxitems);
527*d1e4d7ceSDavid van Moolenbroek }
528*d1e4d7ceSDavid van Moolenbroek items[numitems] = xmalloc((size_t) (Strlen(entry) + 1) *
529*d1e4d7ceSDavid van Moolenbroek sizeof(Char));
530*d1e4d7ceSDavid van Moolenbroek copyn(items[numitems], entry, MAXNAMLEN);
531*d1e4d7ceSDavid van Moolenbroek numitems++;
532*d1e4d7ceSDavid van Moolenbroek }
533*d1e4d7ceSDavid van Moolenbroek else { /* RECOGNIZE command */
534*d1e4d7ceSDavid van Moolenbroek if (ignoring && ignored(entry))
535*d1e4d7ceSDavid van Moolenbroek nignored++;
536*d1e4d7ceSDavid van Moolenbroek else if (recognize(extended_name,
537*d1e4d7ceSDavid van Moolenbroek entry, name_length, ++numitems))
538*d1e4d7ceSDavid van Moolenbroek break;
539*d1e4d7ceSDavid van Moolenbroek }
540*d1e4d7ceSDavid van Moolenbroek }
541*d1e4d7ceSDavid van Moolenbroek if (ignoring && numitems == 0 && nignored > 0) {
542*d1e4d7ceSDavid van Moolenbroek ignoring = FALSE;
543*d1e4d7ceSDavid van Moolenbroek nignored = 0;
544*d1e4d7ceSDavid van Moolenbroek if (looking_for_lognames)
545*d1e4d7ceSDavid van Moolenbroek (void)setpwent();
546*d1e4d7ceSDavid van Moolenbroek else
547*d1e4d7ceSDavid van Moolenbroek rewinddir(dir_fd);
548*d1e4d7ceSDavid van Moolenbroek goto again;
549*d1e4d7ceSDavid van Moolenbroek }
550*d1e4d7ceSDavid van Moolenbroek
551*d1e4d7ceSDavid van Moolenbroek if (looking_for_lognames)
552*d1e4d7ceSDavid van Moolenbroek (void)endpwent();
553*d1e4d7ceSDavid van Moolenbroek else
554*d1e4d7ceSDavid van Moolenbroek (void)closedir(dir_fd);
555*d1e4d7ceSDavid van Moolenbroek if (numitems == 0)
556*d1e4d7ceSDavid van Moolenbroek return (0);
557*d1e4d7ceSDavid van Moolenbroek if (command == RECOGNIZE) {
558*d1e4d7ceSDavid van Moolenbroek if (looking_for_lognames)
559*d1e4d7ceSDavid van Moolenbroek copyn(word, STRtilde, 1);
560*d1e4d7ceSDavid van Moolenbroek else
561*d1e4d7ceSDavid van Moolenbroek /* put back dir part */
562*d1e4d7ceSDavid van Moolenbroek copyn(word, dir, max_word_length);
563*d1e4d7ceSDavid van Moolenbroek /* add extended name */
564*d1e4d7ceSDavid van Moolenbroek catn(word, extended_name, max_word_length);
565*d1e4d7ceSDavid van Moolenbroek return (numitems);
566*d1e4d7ceSDavid van Moolenbroek }
567*d1e4d7ceSDavid van Moolenbroek else { /* LIST */
568*d1e4d7ceSDavid van Moolenbroek qsort((ptr_t) items, numitems, sizeof(items[0]),
569*d1e4d7ceSDavid van Moolenbroek (int (*) (const void *, const void *)) sortscmp);
570*d1e4d7ceSDavid van Moolenbroek print_by_column(looking_for_lognames ? NULL : tilded_dir,
571*d1e4d7ceSDavid van Moolenbroek items, numitems);
572*d1e4d7ceSDavid van Moolenbroek if (items != NULL)
573*d1e4d7ceSDavid van Moolenbroek FREE_ITEMS(items, numitems);
574*d1e4d7ceSDavid van Moolenbroek }
575*d1e4d7ceSDavid van Moolenbroek return (0);
576*d1e4d7ceSDavid van Moolenbroek }
577*d1e4d7ceSDavid van Moolenbroek
578*d1e4d7ceSDavid van Moolenbroek /*
579*d1e4d7ceSDavid van Moolenbroek * Object: extend what user typed up to an ambiguity.
580*d1e4d7ceSDavid van Moolenbroek * Algorithm:
581*d1e4d7ceSDavid van Moolenbroek * On first match, copy full entry (assume it'll be the only match)
582*d1e4d7ceSDavid van Moolenbroek * On subsequent matches, shorten extended_name to the first
583*d1e4d7ceSDavid van Moolenbroek * Character mismatch between extended_name and entry.
584*d1e4d7ceSDavid van Moolenbroek * If we shorten it back to the prefix length, stop searching.
585*d1e4d7ceSDavid van Moolenbroek */
586*d1e4d7ceSDavid van Moolenbroek static int
recognize(Char * extended_name,Char * entry,size_t name_length,size_t numitems)587*d1e4d7ceSDavid van Moolenbroek recognize(Char *extended_name, Char *entry, size_t name_length, size_t numitems)
588*d1e4d7ceSDavid van Moolenbroek {
589*d1e4d7ceSDavid van Moolenbroek if (numitems == 1) /* 1st match */
590*d1e4d7ceSDavid van Moolenbroek copyn(extended_name, entry, MAXNAMLEN);
591*d1e4d7ceSDavid van Moolenbroek else { /* 2nd & subsequent matches */
592*d1e4d7ceSDavid van Moolenbroek Char *ent, *x;
593*d1e4d7ceSDavid van Moolenbroek size_t len = 0;
594*d1e4d7ceSDavid van Moolenbroek
595*d1e4d7ceSDavid van Moolenbroek x = extended_name;
596*d1e4d7ceSDavid van Moolenbroek for (ent = entry; *x && *x == *ent++; x++, len++)
597*d1e4d7ceSDavid van Moolenbroek continue;
598*d1e4d7ceSDavid van Moolenbroek *x = '\0'; /* Shorten at 1st Char diff */
599*d1e4d7ceSDavid van Moolenbroek if (len == name_length) /* Ambiguous to prefix? */
600*d1e4d7ceSDavid van Moolenbroek return (-1); /* So stop now and save time */
601*d1e4d7ceSDavid van Moolenbroek }
602*d1e4d7ceSDavid van Moolenbroek return (0);
603*d1e4d7ceSDavid van Moolenbroek }
604*d1e4d7ceSDavid van Moolenbroek
605*d1e4d7ceSDavid van Moolenbroek /*
606*d1e4d7ceSDavid van Moolenbroek * Return true if check matches initial Chars in template.
607*d1e4d7ceSDavid van Moolenbroek * This differs from PWB imatch in that if check is null
608*d1e4d7ceSDavid van Moolenbroek * it matches anything.
609*d1e4d7ceSDavid van Moolenbroek */
610*d1e4d7ceSDavid van Moolenbroek static int
is_prefix(Char * check,Char * template)611*d1e4d7ceSDavid van Moolenbroek is_prefix(Char *check, Char *template)
612*d1e4d7ceSDavid van Moolenbroek {
613*d1e4d7ceSDavid van Moolenbroek do
614*d1e4d7ceSDavid van Moolenbroek if (*check == 0)
615*d1e4d7ceSDavid van Moolenbroek return (TRUE);
616*d1e4d7ceSDavid van Moolenbroek while (*check++ == *template++);
617*d1e4d7ceSDavid van Moolenbroek return (FALSE);
618*d1e4d7ceSDavid van Moolenbroek }
619*d1e4d7ceSDavid van Moolenbroek
620*d1e4d7ceSDavid van Moolenbroek /*
621*d1e4d7ceSDavid van Moolenbroek * Return true if the Chars in template appear at the
622*d1e4d7ceSDavid van Moolenbroek * end of check, I.e., are its suffix.
623*d1e4d7ceSDavid van Moolenbroek */
624*d1e4d7ceSDavid van Moolenbroek static int
is_suffix(Char * check,Char * template)625*d1e4d7ceSDavid van Moolenbroek is_suffix(Char *check, Char *template)
626*d1e4d7ceSDavid van Moolenbroek {
627*d1e4d7ceSDavid van Moolenbroek Char *c, *t;
628*d1e4d7ceSDavid van Moolenbroek
629*d1e4d7ceSDavid van Moolenbroek for (c = check; *c++;)
630*d1e4d7ceSDavid van Moolenbroek continue;
631*d1e4d7ceSDavid van Moolenbroek for (t = template; *t++;)
632*d1e4d7ceSDavid van Moolenbroek continue;
633*d1e4d7ceSDavid van Moolenbroek for (;;) {
634*d1e4d7ceSDavid van Moolenbroek if (t == template)
635*d1e4d7ceSDavid van Moolenbroek return 1;
636*d1e4d7ceSDavid van Moolenbroek if (c == check || *--t != *--c)
637*d1e4d7ceSDavid van Moolenbroek return 0;
638*d1e4d7ceSDavid van Moolenbroek }
639*d1e4d7ceSDavid van Moolenbroek }
640*d1e4d7ceSDavid van Moolenbroek
641*d1e4d7ceSDavid van Moolenbroek ssize_t
tenex(Char * inputline,size_t inputline_size)642*d1e4d7ceSDavid van Moolenbroek tenex(Char *inputline, size_t inputline_size)
643*d1e4d7ceSDavid van Moolenbroek {
644*d1e4d7ceSDavid van Moolenbroek char tinputline[BUFSIZE];
645*d1e4d7ceSDavid van Moolenbroek ssize_t num_read;
646*d1e4d7ceSDavid van Moolenbroek size_t numitems;
647*d1e4d7ceSDavid van Moolenbroek
648*d1e4d7ceSDavid van Moolenbroek setup_tty(ON);
649*d1e4d7ceSDavid van Moolenbroek
650*d1e4d7ceSDavid van Moolenbroek while ((num_read = read(SHIN, tinputline, BUFSIZE)) > 0) {
651*d1e4d7ceSDavid van Moolenbroek size_t i, nr = (size_t) num_read;
652*d1e4d7ceSDavid van Moolenbroek
653*d1e4d7ceSDavid van Moolenbroek
654*d1e4d7ceSDavid van Moolenbroek static Char delims[] = {' ', '\'', '"', '\t', ';', '&', '<',
655*d1e4d7ceSDavid van Moolenbroek '>', '(', ')', '|', '^', '%', '\0'};
656*d1e4d7ceSDavid van Moolenbroek Char *str_end, *word_start, last_Char, should_retype;
657*d1e4d7ceSDavid van Moolenbroek size_t space_left;
658*d1e4d7ceSDavid van Moolenbroek COMMAND command;
659*d1e4d7ceSDavid van Moolenbroek
660*d1e4d7ceSDavid van Moolenbroek for (i = 0; i < nr; i++)
661*d1e4d7ceSDavid van Moolenbroek inputline[i] = (unsigned char) tinputline[i];
662*d1e4d7ceSDavid van Moolenbroek last_Char = inputline[nr - 1] & ASCII;
663*d1e4d7ceSDavid van Moolenbroek
664*d1e4d7ceSDavid van Moolenbroek if (last_Char == '\n' || nr == inputline_size)
665*d1e4d7ceSDavid van Moolenbroek break;
666*d1e4d7ceSDavid van Moolenbroek command = (last_Char == ESC) ? RECOGNIZE : LIST;
667*d1e4d7ceSDavid van Moolenbroek if (command == LIST)
668*d1e4d7ceSDavid van Moolenbroek (void)fputc('\n', cshout);
669*d1e4d7ceSDavid van Moolenbroek str_end = &inputline[nr];
670*d1e4d7ceSDavid van Moolenbroek if (last_Char == ESC)
671*d1e4d7ceSDavid van Moolenbroek --str_end; /* wipeout trailing cmd Char */
672*d1e4d7ceSDavid van Moolenbroek *str_end = '\0';
673*d1e4d7ceSDavid van Moolenbroek /*
674*d1e4d7ceSDavid van Moolenbroek * Find LAST occurence of a delimiter in the inputline. The word start
675*d1e4d7ceSDavid van Moolenbroek * is one Character past it.
676*d1e4d7ceSDavid van Moolenbroek */
677*d1e4d7ceSDavid van Moolenbroek for (word_start = str_end; word_start > inputline; --word_start)
678*d1e4d7ceSDavid van Moolenbroek if (Strchr(delims, word_start[-1]))
679*d1e4d7ceSDavid van Moolenbroek break;
680*d1e4d7ceSDavid van Moolenbroek space_left = inputline_size - (size_t)(word_start - inputline) - 1;
681*d1e4d7ceSDavid van Moolenbroek numitems = tsearch(word_start, command, space_left);
682*d1e4d7ceSDavid van Moolenbroek
683*d1e4d7ceSDavid van Moolenbroek if (command == RECOGNIZE) {
684*d1e4d7ceSDavid van Moolenbroek /* print from str_end on */
685*d1e4d7ceSDavid van Moolenbroek print_recognized_stuff(str_end);
686*d1e4d7ceSDavid van Moolenbroek if (numitems != 1) /* Beep = No match/ambiguous */
687*d1e4d7ceSDavid van Moolenbroek beep();
688*d1e4d7ceSDavid van Moolenbroek }
689*d1e4d7ceSDavid van Moolenbroek
690*d1e4d7ceSDavid van Moolenbroek /*
691*d1e4d7ceSDavid van Moolenbroek * Tabs in the input line cause trouble after a pushback. tty driver
692*d1e4d7ceSDavid van Moolenbroek * won't backspace over them because column positions are now
693*d1e4d7ceSDavid van Moolenbroek * incorrect. This is solved by retyping over current line.
694*d1e4d7ceSDavid van Moolenbroek */
695*d1e4d7ceSDavid van Moolenbroek should_retype = FALSE;
696*d1e4d7ceSDavid van Moolenbroek if (Strchr(inputline, '\t')) { /* tab Char in input line? */
697*d1e4d7ceSDavid van Moolenbroek back_to_col_1();
698*d1e4d7ceSDavid van Moolenbroek should_retype = TRUE;
699*d1e4d7ceSDavid van Moolenbroek }
700*d1e4d7ceSDavid van Moolenbroek if (command == LIST) /* Always retype after a LIST */
701*d1e4d7ceSDavid van Moolenbroek should_retype = TRUE;
702*d1e4d7ceSDavid van Moolenbroek if (pushback(inputline))
703*d1e4d7ceSDavid van Moolenbroek should_retype = TRUE;
704*d1e4d7ceSDavid van Moolenbroek if (should_retype) {
705*d1e4d7ceSDavid van Moolenbroek if (command == RECOGNIZE)
706*d1e4d7ceSDavid van Moolenbroek (void) fputc('\n', cshout);
707*d1e4d7ceSDavid van Moolenbroek printprompt();
708*d1e4d7ceSDavid van Moolenbroek }
709*d1e4d7ceSDavid van Moolenbroek if (should_retype)
710*d1e4d7ceSDavid van Moolenbroek retype();
711*d1e4d7ceSDavid van Moolenbroek }
712*d1e4d7ceSDavid van Moolenbroek setup_tty(OFF);
713*d1e4d7ceSDavid van Moolenbroek return num_read;
714*d1e4d7ceSDavid van Moolenbroek }
715*d1e4d7ceSDavid van Moolenbroek
716*d1e4d7ceSDavid van Moolenbroek static int
ignored(Char * entry)717*d1e4d7ceSDavid van Moolenbroek ignored(Char *entry)
718*d1e4d7ceSDavid van Moolenbroek {
719*d1e4d7ceSDavid van Moolenbroek struct varent *vp;
720*d1e4d7ceSDavid van Moolenbroek Char **cp;
721*d1e4d7ceSDavid van Moolenbroek
722*d1e4d7ceSDavid van Moolenbroek if ((vp = adrof(STRfignore)) == NULL || (cp = vp->vec) == NULL)
723*d1e4d7ceSDavid van Moolenbroek return (FALSE);
724*d1e4d7ceSDavid van Moolenbroek for (; *cp != NULL; cp++)
725*d1e4d7ceSDavid van Moolenbroek if (is_suffix(entry, *cp))
726*d1e4d7ceSDavid van Moolenbroek return (TRUE);
727*d1e4d7ceSDavid van Moolenbroek return (FALSE);
728*d1e4d7ceSDavid van Moolenbroek }
729*d1e4d7ceSDavid van Moolenbroek #endif /* FILEC */
730