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