Commit | Line | Data |
---|---|---|
ecc449eb KB |
1 | /*- |
2 | * Copyright (c) 1980, 1991 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * %sccs.include.redist.c% | |
b79f4fa9 DF |
6 | */ |
7 | ||
5b182e7a | 8 | #ifndef lint |
2cc4d01b | 9 | static char sccsid[] = "@(#)file.c 5.23 (Berkeley) %G%"; |
ecc449eb | 10 | #endif /* not lint */ |
d8bd96dd | 11 | |
35371dec | 12 | #ifdef FILEC |
6e37afca | 13 | |
b9c4f741 KB |
14 | #include <sys/param.h> |
15 | #include <sys/ioctl.h> | |
16 | #include <sys/stat.h> | |
17 | #include <termios.h> | |
18 | #include <dirent.h> | |
19 | #include <pwd.h> | |
20 | #include <stdlib.h> | |
21 | #include <unistd.h> | |
8e3354ca CZ |
22 | #ifndef SHORT_STRINGS |
23 | #include <string.h> | |
24 | #endif /* SHORT_STRINGS */ | |
4df6491c CZ |
25 | #if __STDC__ |
26 | # include <stdarg.h> | |
27 | #else | |
28 | # include <varargs.h> | |
29 | #endif | |
30 | ||
4d7b2685 KB |
31 | #include "csh.h" |
32 | #include "extern.h" | |
6e37afca | 33 | |
d8bd96dd KL |
34 | /* |
35 | * Tenex style file name recognition, .. and more. | |
36 | * History: | |
37 | * Author: Ken Greer, Sept. 1975, CMU. | |
38 | * Finally got around to adding to the Cshell., Ken Greer, Dec. 1981. | |
39 | */ | |
40 | ||
d8bd96dd KL |
41 | #define ON 1 |
42 | #define OFF 0 | |
6e37afca KB |
43 | #ifndef TRUE |
44 | #define TRUE 1 | |
45 | #endif | |
46 | #ifndef FALSE | |
47 | #define FALSE 0 | |
48 | #endif | |
d8bd96dd KL |
49 | |
50 | #define ESC '\033' | |
51 | ||
6e37afca KB |
52 | typedef enum { |
53 | LIST, RECOGNIZE | |
54 | } COMMAND; | |
55 | ||
0aec749d CZ |
56 | static void setup_tty __P((int)); |
57 | static void back_to_col_1 __P((void)); | |
58 | static void pushback __P((Char *)); | |
59 | static void catn __P((Char *, Char *, int)); | |
60 | static void copyn __P((Char *, Char *, int)); | |
61 | static Char filetype __P((Char *, Char *)); | |
62 | static void print_by_column __P((Char *, Char *[], int)); | |
c28e64a2 | 63 | static Char *tilde __P((Char *, Char *)); |
0aec749d CZ |
64 | static void retype __P((void)); |
65 | static void beep __P((void)); | |
c28e64a2 | 66 | static void print_recognized_stuff __P((Char *)); |
0aec749d CZ |
67 | static void extract_dir_and_name __P((Char *, Char *, Char *)); |
68 | static Char *getentry __P((DIR *, int)); | |
69 | static void free_items __P((Char **)); | |
dcce770e | 70 | static int tsearch __P((Char *, COMMAND, int)); |
0aec749d CZ |
71 | static int recognize __P((Char *, Char *, int, int)); |
72 | static int is_prefix __P((Char *, Char *)); | |
73 | static int is_suffix __P((Char *, Char *)); | |
74 | static int ignored __P((Char *)); | |
b1c9ab11 | 75 | |
35371dec EW |
76 | /* |
77 | * Put this here so the binary can be patched with adb to enable file | |
4d9099d4 EW |
78 | * completion by default. Filec controls completion, nobeep controls |
79 | * ringing the terminal bell on incomplete expansions. | |
35371dec | 80 | */ |
6e37afca | 81 | bool filec = 0; |
35371dec | 82 | |
6e37afca | 83 | static void |
5b182e7a | 84 | setup_tty(on) |
6e37afca | 85 | int on; |
d8bd96dd | 86 | { |
6e37afca KB |
87 | static struct termios tchars; |
88 | ||
89 | if (on) { | |
90 | (void) tcgetattr(SHIN, &tchars); | |
91 | tchars.c_cc[VEOL] = ESC; | |
92 | if (tchars.c_lflag & ICANON) | |
93 | on = TCSANOW; | |
94 | else { | |
95 | on = TCSAFLUSH; | |
96 | tchars.c_lflag |= ICANON; | |
d8bd96dd | 97 | } |
6e37afca KB |
98 | (void) tcsetattr(SHIN, on, &tchars); |
99 | } | |
100 | else { | |
101 | tchars.c_cc[VEOL] = _POSIX_VDISABLE; | |
102 | (void) tcsetattr(SHIN, TCSANOW, &tchars); | |
103 | } | |
d8bd96dd KL |
104 | } |
105 | ||
106 | /* | |
107 | * Move back to beginning of current line | |
108 | */ | |
6e37afca | 109 | static void |
5b182e7a | 110 | back_to_col_1() |
d8bd96dd | 111 | { |
6e37afca KB |
112 | struct termios tty, tty_normal; |
113 | int omask; | |
114 | ||
115 | omask = sigblock(sigmask(SIGINT)); | |
116 | (void) tcgetattr(SHOUT, &tty); | |
117 | tty_normal = tty; | |
118 | tty.c_iflag &= ~INLCR; | |
119 | tty.c_oflag &= ~ONLCR; | |
120 | (void) tcsetattr(SHOUT, TCSANOW, &tty); | |
121 | (void) write(SHOUT, "\r", 1); | |
122 | (void) tcsetattr(SHOUT, TCSANOW, &tty_normal); | |
123 | (void) sigsetmask(omask); | |
d8bd96dd KL |
124 | } |
125 | ||
126 | /* | |
127 | * Push string contents back into tty queue | |
128 | */ | |
6e37afca | 129 | static void |
5b182e7a | 130 | pushback(string) |
6e37afca | 131 | Char *string; |
d8bd96dd | 132 | { |
6e37afca KB |
133 | register Char *p; |
134 | struct termios tty, tty_normal; | |
135 | int omask; | |
136 | char c; | |
137 | ||
138 | omask = sigblock(sigmask(SIGINT)); | |
139 | (void) tcgetattr(SHOUT, &tty); | |
140 | tty_normal = tty; | |
141 | tty.c_lflag &= ~(ECHOKE | ECHO | ECHOE | ECHOK | ECHONL | ECHOPRT | ECHOCTL); | |
142 | (void) tcsetattr(SHOUT, TCSANOW, &tty); | |
143 | ||
144 | for (p = string; c = *p; p++) | |
145 | (void) ioctl(SHOUT, TIOCSTI, (ioctl_t) & c); | |
146 | (void) tcsetattr(SHOUT, TCSANOW, &tty_normal); | |
147 | (void) sigsetmask(omask); | |
d8bd96dd KL |
148 | } |
149 | ||
150 | /* | |
5b182e7a | 151 | * Concatenate src onto tail of des. |
d8bd96dd KL |
152 | * Des is a string whose maximum length is count. |
153 | * Always null terminate. | |
154 | */ | |
6e37afca | 155 | static void |
5b182e7a | 156 | catn(des, src, count) |
6e37afca | 157 | register Char *des, *src; |
0aec749d | 158 | register int count; |
d8bd96dd | 159 | { |
6e37afca KB |
160 | while (--count >= 0 && *des) |
161 | des++; | |
162 | while (--count >= 0) | |
163 | if ((*des++ = *src++) == 0) | |
164 | return; | |
165 | *des = '\0'; | |
d8bd96dd KL |
166 | } |
167 | ||
d8bd96dd | 168 | /* |
5b182e7a | 169 | * Like strncpy but always leave room for trailing \0 |
d8bd96dd KL |
170 | * and always null terminate. |
171 | */ | |
6e37afca | 172 | static void |
5b182e7a | 173 | copyn(des, src, count) |
6e37afca | 174 | register Char *des, *src; |
0aec749d | 175 | register int count; |
d8bd96dd | 176 | { |
6e37afca KB |
177 | while (--count >= 0) |
178 | if ((*des++ = *src++) == 0) | |
179 | return; | |
180 | *des = '\0'; | |
d8bd96dd KL |
181 | } |
182 | ||
6e37afca | 183 | static Char |
5b182e7a | 184 | filetype(dir, file) |
6e37afca | 185 | Char *dir, *file; |
d8bd96dd | 186 | { |
6e37afca KB |
187 | Char path[MAXPATHLEN]; |
188 | struct stat statb; | |
189 | ||
190 | catn(Strcpy(path, dir), file, sizeof(path) / sizeof(Char)); | |
191 | if (lstat(short2str(path), &statb) == 0) { | |
192 | switch (statb.st_mode & S_IFMT) { | |
193 | case S_IFDIR: | |
194 | return ('/'); | |
195 | ||
196 | case S_IFLNK: | |
197 | if (stat(short2str(path), &statb) == 0 && /* follow it out */ | |
198 | S_ISDIR(statb.st_mode)) | |
199 | return ('>'); | |
200 | else | |
201 | return ('@'); | |
202 | ||
203 | case S_IFSOCK: | |
204 | return ('='); | |
205 | ||
206 | default: | |
207 | if (statb.st_mode & 0111) | |
208 | return ('*'); | |
d8bd96dd | 209 | } |
6e37afca KB |
210 | } |
211 | return (' '); | |
d8bd96dd KL |
212 | } |
213 | ||
b1c9ab11 JL |
214 | static struct winsize win; |
215 | ||
d8bd96dd KL |
216 | /* |
217 | * Print sorted down columns | |
218 | */ | |
6e37afca | 219 | static void |
5b182e7a | 220 | print_by_column(dir, items, count) |
6e37afca KB |
221 | Char *dir, *items[]; |
222 | int count; | |
d8bd96dd | 223 | { |
6e37afca KB |
224 | register int i, rows, r, c, maxwidth = 0, columns; |
225 | ||
226 | if (ioctl(SHOUT, TIOCGWINSZ, (ioctl_t) & win) < 0 || win.ws_col == 0) | |
227 | win.ws_col = 80; | |
228 | for (i = 0; i < count; i++) | |
229 | maxwidth = maxwidth > (r = Strlen(items[i])) ? maxwidth : r; | |
230 | maxwidth += 2; /* for the file tag and space */ | |
231 | columns = win.ws_col / maxwidth; | |
232 | if (columns == 0) | |
233 | columns = 1; | |
234 | rows = (count + (columns - 1)) / columns; | |
235 | for (r = 0; r < rows; r++) { | |
236 | for (c = 0; c < columns; c++) { | |
237 | i = c * rows + r; | |
238 | if (i < count) { | |
239 | register int w; | |
240 | ||
abf583a4 | 241 | (void) fprintf(cshout, "%s", vis_str(items[i])); |
454c2aa3 | 242 | (void) fputc(dir ? filetype(dir, items[i]) : ' ', cshout); |
6e37afca KB |
243 | if (c < columns - 1) { /* last column? */ |
244 | w = Strlen(items[i]) + 1; | |
245 | for (; w < maxwidth; w++) | |
454c2aa3 | 246 | (void) fputc(' ', cshout); |
5b182e7a | 247 | } |
6e37afca | 248 | } |
d8bd96dd | 249 | } |
454c2aa3 CZ |
250 | (void) fputc('\r', cshout); |
251 | (void) fputc('\n', cshout); | |
6e37afca | 252 | } |
d8bd96dd KL |
253 | } |
254 | ||
255 | /* | |
5b182e7a SL |
256 | * Expand file name with possible tilde usage |
257 | * ~person/mumble | |
d8bd96dd | 258 | * expands to |
5b182e7a | 259 | * home_directory_of_person/mumble |
d8bd96dd | 260 | */ |
6e37afca | 261 | static Char * |
5b182e7a | 262 | tilde(new, old) |
6e37afca | 263 | Char *new, *old; |
d8bd96dd | 264 | { |
6e37afca KB |
265 | register Char *o, *p; |
266 | register struct passwd *pw; | |
267 | static Char person[40]; | |
268 | ||
269 | if (old[0] != '~') | |
270 | return (Strcpy(new, old)); | |
271 | ||
c28e64a2 CL |
272 | for (p = person, o = &old[1]; *o && *o != '/'; *p++ = *o++) |
273 | continue; | |
6e37afca KB |
274 | *p = '\0'; |
275 | if (person[0] == '\0') | |
276 | (void) Strcpy(new, value(STRhome)); | |
277 | else { | |
278 | pw = getpwnam(short2str(person)); | |
279 | if (pw == NULL) | |
280 | return (NULL); | |
281 | (void) Strcpy(new, str2short(pw->pw_dir)); | |
282 | } | |
283 | (void) Strcat(new, o); | |
284 | return (new); | |
d8bd96dd KL |
285 | } |
286 | ||
287 | /* | |
288 | * Cause pending line to be printed | |
289 | */ | |
6e37afca | 290 | static void |
5b182e7a | 291 | retype() |
d8bd96dd | 292 | { |
6e37afca KB |
293 | struct termios tty; |
294 | ||
295 | (void) tcgetattr(SHOUT, &tty); | |
296 | tty.c_lflag |= PENDIN; | |
297 | (void) tcsetattr(SHOUT, TCSANOW, &tty); | |
d8bd96dd KL |
298 | } |
299 | ||
6e37afca | 300 | static void |
5b182e7a | 301 | beep() |
d8bd96dd | 302 | { |
6e37afca KB |
303 | if (adrof(STRnobeep) == 0) |
304 | (void) write(SHOUT, "\007", 1); | |
d8bd96dd KL |
305 | } |
306 | ||
307 | /* | |
308 | * Erase that silly ^[ and | |
309 | * print the recognized part of the string | |
310 | */ | |
6e37afca | 311 | static void |
5b182e7a | 312 | print_recognized_stuff(recognized_part) |
6e37afca | 313 | Char *recognized_part; |
d8bd96dd | 314 | { |
6e37afca | 315 | /* An optimized erasing of that silly ^[ */ |
454c2aa3 CZ |
316 | (void) fputc('\b', cshout); |
317 | (void) fputc('\b', cshout); | |
6e37afca KB |
318 | switch (Strlen(recognized_part)) { |
319 | ||
320 | case 0: /* erase two Characters: ^[ */ | |
454c2aa3 CZ |
321 | (void) fputc(' ', cshout); |
322 | (void) fputc(' ', cshout); | |
323 | (void) fputc('\b', cshout); | |
324 | (void) fputc('\b', cshout); | |
6e37afca KB |
325 | break; |
326 | ||
327 | case 1: /* overstrike the ^, erase the [ */ | |
abf583a4 | 328 | (void) fprintf(cshout, "%s", vis_str(recognized_part)); |
454c2aa3 CZ |
329 | (void) fputc(' ', cshout); |
330 | (void) fputc('\b', cshout); | |
6e37afca KB |
331 | break; |
332 | ||
333 | default: /* overstrike both Characters ^[ */ | |
abf583a4 | 334 | (void) fprintf(cshout, "%s", vis_str(recognized_part)); |
6e37afca KB |
335 | break; |
336 | } | |
454c2aa3 | 337 | (void) fflush(cshout); |
d8bd96dd KL |
338 | } |
339 | ||
340 | /* | |
5b182e7a | 341 | * Parse full path in file into 2 parts: directory and file names |
d8bd96dd KL |
342 | * Should leave final slash (/) at end of dir. |
343 | */ | |
6e37afca | 344 | static void |
5b182e7a | 345 | extract_dir_and_name(path, dir, name) |
6e37afca | 346 | Char *path, *dir, *name; |
d8bd96dd | 347 | { |
6e37afca KB |
348 | register Char *p; |
349 | ||
350 | p = Strrchr(path, '/'); | |
351 | if (p == NULL) { | |
352 | copyn(name, path, MAXNAMLEN); | |
353 | dir[0] = '\0'; | |
354 | } | |
355 | else { | |
356 | copyn(name, ++p, MAXNAMLEN); | |
357 | copyn(dir, path, p - path); | |
358 | } | |
d8bd96dd KL |
359 | } |
360 | ||
6e37afca | 361 | static Char * |
5b182e7a | 362 | getentry(dir_fd, looking_for_lognames) |
6e37afca KB |
363 | DIR *dir_fd; |
364 | int looking_for_lognames; | |
d8bd96dd | 365 | { |
6e37afca KB |
366 | register struct passwd *pw; |
367 | register struct dirent *dirp; | |
368 | ||
369 | if (looking_for_lognames) { | |
370 | if ((pw = getpwent()) == NULL) | |
371 | return (NULL); | |
372 | return (str2short(pw->pw_name)); | |
373 | } | |
374 | if (dirp = readdir(dir_fd)) | |
375 | return (str2short(dirp->d_name)); | |
376 | return (NULL); | |
d8bd96dd KL |
377 | } |
378 | ||
6e37afca | 379 | static void |
5b182e7a | 380 | free_items(items) |
6e37afca | 381 | register Char **items; |
d8bd96dd | 382 | { |
6e37afca | 383 | register int i; |
5b182e7a | 384 | |
6e37afca KB |
385 | for (i = 0; items[i]; i++) |
386 | xfree((ptr_t) items[i]); | |
387 | xfree((ptr_t) items); | |
d8bd96dd KL |
388 | } |
389 | ||
5b182e7a | 390 | #define FREE_ITEMS(items) { \ |
6e37afca | 391 | int omask;\ |
9208cf61 | 392 | \ |
5b182e7a SL |
393 | omask = sigblock(sigmask(SIGINT));\ |
394 | free_items(items);\ | |
395 | items = NULL;\ | |
35371dec | 396 | (void) sigsetmask(omask);\ |
d8bd96dd KL |
397 | } |
398 | ||
399 | /* | |
400 | * Perform a RECOGNIZE or LIST command on string "word". | |
401 | */ | |
6e37afca KB |
402 | static int |
403 | tsearch(word, command, max_word_length) | |
404 | Char *word; | |
6e37afca | 405 | COMMAND command; |
dcce770e | 406 | int max_word_length; |
d8bd96dd | 407 | { |
6e37afca KB |
408 | static Char **items = NULL; |
409 | register DIR *dir_fd; | |
410 | register numitems = 0, ignoring = TRUE, nignored = 0; | |
411 | register name_length, looking_for_lognames; | |
412 | Char tilded_dir[MAXPATHLEN + 1], dir[MAXPATHLEN + 1]; | |
413 | Char name[MAXNAMLEN + 1], extended_name[MAXNAMLEN + 1]; | |
414 | Char *entry; | |
d8bd96dd | 415 | |
6e37afca | 416 | #define MAXITEMS 1024 |
4d9099d4 | 417 | |
6e37afca KB |
418 | if (items != NULL) |
419 | FREE_ITEMS(items); | |
420 | ||
421 | looking_for_lognames = (*word == '~') && (Strchr(word, '/') == NULL); | |
422 | if (looking_for_lognames) { | |
423 | (void) setpwent(); | |
424 | copyn(name, &word[1], MAXNAMLEN); /* name sans ~ */ | |
425 | dir_fd = NULL; | |
426 | } | |
427 | else { | |
428 | extract_dir_and_name(word, dir, name); | |
429 | if (tilde(tilded_dir, dir) == 0) | |
430 | return (0); | |
431 | dir_fd = opendir(*tilded_dir ? short2str(tilded_dir) : "."); | |
432 | if (dir_fd == NULL) | |
433 | return (0); | |
434 | } | |
435 | ||
436 | again: /* search for matches */ | |
437 | name_length = Strlen(name); | |
438 | for (numitems = 0; entry = getentry(dir_fd, looking_for_lognames);) { | |
439 | if (!is_prefix(name, entry)) | |
440 | continue; | |
441 | /* Don't match . files on null prefix match */ | |
442 | if (name_length == 0 && entry[0] == '.' && | |
443 | !looking_for_lognames) | |
444 | continue; | |
445 | if (command == LIST) { | |
446 | if (numitems >= MAXITEMS) { | |
454c2aa3 CZ |
447 | (void) fprintf(csherr, "\nYikes!! Too many %s!!\n", |
448 | looking_for_lognames ? | |
449 | "names in password file" : "files"); | |
6e37afca KB |
450 | break; |
451 | } | |
452 | if (items == NULL) | |
453 | items = (Char **) xcalloc(sizeof(items[0]), MAXITEMS); | |
454 | items[numitems] = (Char *) xmalloc((size_t) (Strlen(entry) + 1) * | |
455 | sizeof(Char)); | |
456 | copyn(items[numitems], entry, MAXNAMLEN); | |
457 | numitems++; | |
5b182e7a | 458 | } |
6e37afca KB |
459 | else { /* RECOGNIZE command */ |
460 | if (ignoring && ignored(entry)) | |
461 | nignored++; | |
462 | else if (recognize(extended_name, | |
463 | entry, name_length, ++numitems)) | |
464 | break; | |
4d9099d4 | 465 | } |
6e37afca KB |
466 | } |
467 | if (ignoring && numitems == 0 && nignored > 0) { | |
468 | ignoring = FALSE; | |
469 | nignored = 0; | |
d8bd96dd | 470 | if (looking_for_lognames) |
6e37afca | 471 | (void) setpwent(); |
d8bd96dd | 472 | else |
6e37afca KB |
473 | rewinddir(dir_fd); |
474 | goto again; | |
475 | } | |
476 | ||
477 | if (looking_for_lognames) | |
478 | (void) endpwent(); | |
479 | else | |
480 | (void) closedir(dir_fd); | |
481 | if (numitems == 0) | |
5b182e7a | 482 | return (0); |
6e37afca KB |
483 | if (command == RECOGNIZE) { |
484 | if (looking_for_lognames) | |
485 | copyn(word, STRtilde, 1); | |
486 | else | |
487 | /* put back dir part */ | |
488 | copyn(word, dir, max_word_length); | |
489 | /* add extended name */ | |
490 | catn(word, extended_name, max_word_length); | |
491 | return (numitems); | |
492 | } | |
493 | else { /* LIST */ | |
2cc4d01b CZ |
494 | qsort((ptr_t) items, numitems, sizeof(items[0]), |
495 | (int (*) __P((const void *, const void *))) sortscmp); | |
6e37afca KB |
496 | print_by_column(looking_for_lognames ? NULL : tilded_dir, |
497 | items, numitems); | |
498 | if (items != NULL) | |
499 | FREE_ITEMS(items); | |
500 | } | |
501 | return (0); | |
d8bd96dd KL |
502 | } |
503 | ||
504 | /* | |
505 | * Object: extend what user typed up to an ambiguity. | |
506 | * Algorithm: | |
6e37afca | 507 | * On first match, copy full entry (assume it'll be the only match) |
d8bd96dd | 508 | * On subsequent matches, shorten extended_name to the first |
6e37afca | 509 | * Character mismatch between extended_name and entry. |
d8bd96dd KL |
510 | * If we shorten it back to the prefix length, stop searching. |
511 | */ | |
6e37afca | 512 | static int |
5b182e7a | 513 | recognize(extended_name, entry, name_length, numitems) |
6e37afca KB |
514 | Char *extended_name, *entry; |
515 | int name_length, numitems; | |
d8bd96dd | 516 | { |
6e37afca KB |
517 | if (numitems == 1) /* 1st match */ |
518 | copyn(extended_name, entry, MAXNAMLEN); | |
519 | else { /* 2nd & subsequent matches */ | |
520 | register Char *x, *ent; | |
521 | register int len = 0; | |
522 | ||
523 | x = extended_name; | |
c28e64a2 CL |
524 | for (ent = entry; *x && *x == *ent++; x++, len++) |
525 | continue; | |
6e37afca KB |
526 | *x = '\0'; /* Shorten at 1st Char diff */ |
527 | if (len == name_length) /* Ambiguous to prefix? */ | |
528 | return (-1); /* So stop now and save time */ | |
529 | } | |
530 | return (0); | |
d8bd96dd KL |
531 | } |
532 | ||
533 | /* | |
6e37afca | 534 | * Return true if check matches initial Chars in template. |
d8bd96dd | 535 | * This differs from PWB imatch in that if check is null |
6722a695 | 536 | * it matches anything. |
d8bd96dd | 537 | */ |
6e37afca | 538 | static int |
5b182e7a | 539 | is_prefix(check, template) |
6e37afca | 540 | register Char *check, *template; |
d8bd96dd | 541 | { |
6e37afca KB |
542 | do |
543 | if (*check == 0) | |
544 | return (TRUE); | |
545 | while (*check++ == *template++); | |
546 | return (FALSE); | |
d8bd96dd KL |
547 | } |
548 | ||
4d9099d4 | 549 | /* |
6e37afca | 550 | * Return true if the Chars in template appear at the |
4d9099d4 EW |
551 | * end of check, I.e., are it's suffix. |
552 | */ | |
6e37afca | 553 | static int |
4d9099d4 | 554 | is_suffix(check, template) |
6e37afca | 555 | Char *check, *template; |
4d9099d4 | 556 | { |
6e37afca KB |
557 | register Char *c, *t; |
558 | ||
c28e64a2 CL |
559 | for (c = check; *c++;) |
560 | continue; | |
561 | for (t = template; *t++;) | |
562 | continue; | |
6e37afca KB |
563 | for (;;) { |
564 | if (t == template) | |
565 | return 1; | |
566 | if (c == check || *--t != *--c) | |
567 | return 0; | |
568 | } | |
4d9099d4 EW |
569 | } |
570 | ||
6e37afca | 571 | int |
5b182e7a | 572 | tenex(inputline, inputline_size) |
6e37afca KB |
573 | Char *inputline; |
574 | int inputline_size; | |
d8bd96dd | 575 | { |
6e37afca KB |
576 | register int numitems, num_read; |
577 | char tinputline[BUFSIZ]; | |
5b182e7a | 578 | |
6e37afca KB |
579 | |
580 | setup_tty(ON); | |
581 | ||
582 | while ((num_read = read(SHIN, tinputline, BUFSIZ)) > 0) { | |
583 | int i; | |
584 | static Char delims[] = {' ', '\'', '"', '\t', ';', '&', '<', | |
585 | '>', '(', ')', '|', '^', '%', '\0'}; | |
586 | register Char *str_end, *word_start, last_Char, should_retype; | |
587 | register int space_left; | |
588 | COMMAND command; | |
589 | ||
590 | for (i = 0; i < num_read; i++) | |
591 | inputline[i] = (unsigned char) tinputline[i]; | |
592 | last_Char = inputline[num_read - 1] & ASCII; | |
593 | ||
594 | if (last_Char == '\n' || num_read == inputline_size) | |
595 | break; | |
596 | command = (last_Char == ESC) ? RECOGNIZE : LIST; | |
597 | if (command == LIST) | |
454c2aa3 | 598 | (void) fputc('\n', cshout); |
6e37afca KB |
599 | str_end = &inputline[num_read]; |
600 | if (last_Char == ESC) | |
601 | --str_end; /* wipeout trailing cmd Char */ | |
602 | *str_end = '\0'; | |
603 | /* | |
604 | * Find LAST occurence of a delimiter in the inputline. The word start | |
605 | * is one Character past it. | |
606 | */ | |
607 | for (word_start = str_end; word_start > inputline; --word_start) | |
608 | if (Strchr(delims, word_start[-1])) | |
609 | break; | |
610 | space_left = inputline_size - (word_start - inputline) - 1; | |
611 | numitems = tsearch(word_start, command, space_left); | |
612 | ||
613 | if (command == RECOGNIZE) { | |
614 | /* print from str_end on */ | |
615 | print_recognized_stuff(str_end); | |
616 | if (numitems != 1) /* Beep = No match/ambiguous */ | |
617 | beep(); | |
d8bd96dd | 618 | } |
6e37afca KB |
619 | |
620 | /* | |
621 | * Tabs in the input line cause trouble after a pushback. tty driver | |
622 | * won't backspace over them because column positions are now | |
623 | * incorrect. This is solved by retyping over current line. | |
624 | */ | |
625 | should_retype = FALSE; | |
626 | if (Strchr(inputline, '\t')) { /* tab Char in input line? */ | |
627 | back_to_col_1(); | |
628 | should_retype = TRUE; | |
629 | } | |
630 | if (command == LIST) /* Always retype after a LIST */ | |
631 | should_retype = TRUE; | |
632 | if (should_retype) | |
633 | printprompt(); | |
634 | pushback(inputline); | |
635 | if (should_retype) | |
636 | retype(); | |
637 | } | |
638 | setup_tty(OFF); | |
639 | return (num_read); | |
d8bd96dd | 640 | } |
4d9099d4 | 641 | |
6e37afca | 642 | static int |
4d9099d4 | 643 | ignored(entry) |
6e37afca | 644 | register Char *entry; |
4d9099d4 | 645 | { |
6e37afca KB |
646 | struct varent *vp; |
647 | register Char **cp; | |
648 | ||
649 | if ((vp = adrof(STRfignore)) == NULL || (cp = vp->vec) == NULL) | |
4d9099d4 | 650 | return (FALSE); |
6e37afca KB |
651 | for (; *cp != NULL; cp++) |
652 | if (is_suffix(entry, *cp)) | |
653 | return (TRUE); | |
654 | return (FALSE); | |
4d9099d4 | 655 | } |
6e37afca | 656 | #endif /* FILEC */ |