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