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