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