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