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