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