1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 4*7c478bd9Sstevel@tonic-gate */ 5*7c478bd9Sstevel@tonic-gate 6*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 7*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 8*7c478bd9Sstevel@tonic-gate 9*7c478bd9Sstevel@tonic-gate /* 10*7c478bd9Sstevel@tonic-gate * Copyright (c) 1980 Regents of the University of California. 11*7c478bd9Sstevel@tonic-gate * All rights reserved. The Berkeley Software License Agreement 12*7c478bd9Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 13*7c478bd9Sstevel@tonic-gate */ 14*7c478bd9Sstevel@tonic-gate 15*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 16*7c478bd9Sstevel@tonic-gate 17*7c478bd9Sstevel@tonic-gate #ifdef FILEC 18*7c478bd9Sstevel@tonic-gate /* 19*7c478bd9Sstevel@tonic-gate * Tenex style file name recognition, .. and more. 20*7c478bd9Sstevel@tonic-gate * History: 21*7c478bd9Sstevel@tonic-gate * Author: Ken Greer, Sept. 1975, CMU. 22*7c478bd9Sstevel@tonic-gate * Finally got around to adding to the Cshell., Ken Greer, Dec. 1981. 23*7c478bd9Sstevel@tonic-gate */ 24*7c478bd9Sstevel@tonic-gate 25*7c478bd9Sstevel@tonic-gate #include "sh.h" 26*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 27*7c478bd9Sstevel@tonic-gate #include <dirent.h> 28*7c478bd9Sstevel@tonic-gate #include <pwd.h> 29*7c478bd9Sstevel@tonic-gate #include "sh.tconst.h" 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate #define TRUE 1 32*7c478bd9Sstevel@tonic-gate #define FALSE 0 33*7c478bd9Sstevel@tonic-gate #define ON 1 34*7c478bd9Sstevel@tonic-gate #define OFF 0 35*7c478bd9Sstevel@tonic-gate 36*7c478bd9Sstevel@tonic-gate #define ESC '\033' 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate extern DIR *opendir_(); 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate static char *BELL = "\07"; 41*7c478bd9Sstevel@tonic-gate static char *CTRLR = "^R\n"; 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate typedef enum {LIST, RECOGNIZE} COMMAND; 44*7c478bd9Sstevel@tonic-gate 45*7c478bd9Sstevel@tonic-gate static jmp_buf osetexit; /* saved setexit() state */ 46*7c478bd9Sstevel@tonic-gate static struct termios tty_save; /* saved terminal state */ 47*7c478bd9Sstevel@tonic-gate static struct termios tty_new; /* new terminal state */ 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate /* 50*7c478bd9Sstevel@tonic-gate * Put this here so the binary can be patched with adb to enable file 51*7c478bd9Sstevel@tonic-gate * completion by default. Filec controls completion, nobeep controls 52*7c478bd9Sstevel@tonic-gate * ringing the terminal bell on incomplete expansions. 53*7c478bd9Sstevel@tonic-gate */ 54*7c478bd9Sstevel@tonic-gate bool filec = 0; 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate static 57*7c478bd9Sstevel@tonic-gate setup_tty(on) 58*7c478bd9Sstevel@tonic-gate int on; 59*7c478bd9Sstevel@tonic-gate { 60*7c478bd9Sstevel@tonic-gate int omask; 61*7c478bd9Sstevel@tonic-gate #ifdef TRACE 62*7c478bd9Sstevel@tonic-gate tprintf("TRACE- setup_tty()\n"); 63*7c478bd9Sstevel@tonic-gate #endif 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate omask = sigblock(sigmask(SIGINT)); 66*7c478bd9Sstevel@tonic-gate if (on) { 67*7c478bd9Sstevel@tonic-gate /* 68*7c478bd9Sstevel@tonic-gate * The shell makes sure that the tty is not in some weird state 69*7c478bd9Sstevel@tonic-gate * and fixes it if it is. But it should be noted that the 70*7c478bd9Sstevel@tonic-gate * tenex routine will not work correctly in CBREAK or RAW mode 71*7c478bd9Sstevel@tonic-gate * so this code below is, therefore, mandatory. 72*7c478bd9Sstevel@tonic-gate * 73*7c478bd9Sstevel@tonic-gate * Also, in order to recognize the ESC (filename-completion) 74*7c478bd9Sstevel@tonic-gate * character, set EOL to ESC. This way, ESC will terminate 75*7c478bd9Sstevel@tonic-gate * the line, but still be in the input stream. 76*7c478bd9Sstevel@tonic-gate * EOT (filename list) will also terminate the line, 77*7c478bd9Sstevel@tonic-gate * but will not appear in the input stream. 78*7c478bd9Sstevel@tonic-gate * 79*7c478bd9Sstevel@tonic-gate * The getexit/setexit contortions ensure that the 80*7c478bd9Sstevel@tonic-gate * tty state will be restored if the user types ^C. 81*7c478bd9Sstevel@tonic-gate */ 82*7c478bd9Sstevel@tonic-gate (void) ioctl(SHIN, TCGETS, (char *)&tty_save); 83*7c478bd9Sstevel@tonic-gate getexit(osetexit); 84*7c478bd9Sstevel@tonic-gate if (setjmp(reslab)) { 85*7c478bd9Sstevel@tonic-gate (void) ioctl(SHIN, TCSETSW, (char *)&tty_save); 86*7c478bd9Sstevel@tonic-gate resexit(osetexit); 87*7c478bd9Sstevel@tonic-gate reset(); 88*7c478bd9Sstevel@tonic-gate } 89*7c478bd9Sstevel@tonic-gate tty_new = tty_save; 90*7c478bd9Sstevel@tonic-gate tty_new.c_cc[VEOL] = ESC; 91*7c478bd9Sstevel@tonic-gate tty_new.c_iflag |= IMAXBEL | BRKINT | IGNPAR; 92*7c478bd9Sstevel@tonic-gate tty_new.c_lflag |= ICANON; 93*7c478bd9Sstevel@tonic-gate tty_new.c_lflag |= ECHOCTL; 94*7c478bd9Sstevel@tonic-gate tty_new.c_oflag &= ~OCRNL; 95*7c478bd9Sstevel@tonic-gate (void) ioctl(SHIN, TCSETSW, (char *)&tty_new); 96*7c478bd9Sstevel@tonic-gate } else { 97*7c478bd9Sstevel@tonic-gate /* 98*7c478bd9Sstevel@tonic-gate * Reset terminal state to what user had when invoked 99*7c478bd9Sstevel@tonic-gate */ 100*7c478bd9Sstevel@tonic-gate (void) ioctl(SHIN, TCSETSW, (char *)&tty_save); 101*7c478bd9Sstevel@tonic-gate resexit(osetexit); 102*7c478bd9Sstevel@tonic-gate } 103*7c478bd9Sstevel@tonic-gate (void) sigsetmask(omask); 104*7c478bd9Sstevel@tonic-gate } 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate static 107*7c478bd9Sstevel@tonic-gate termchars() 108*7c478bd9Sstevel@tonic-gate { 109*7c478bd9Sstevel@tonic-gate extern char *tgetstr(); 110*7c478bd9Sstevel@tonic-gate char bp[1024]; 111*7c478bd9Sstevel@tonic-gate static char area[256]; 112*7c478bd9Sstevel@tonic-gate static int been_here = 0; 113*7c478bd9Sstevel@tonic-gate char *ap = area; 114*7c478bd9Sstevel@tonic-gate register char *s; 115*7c478bd9Sstevel@tonic-gate char *term; 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate #ifdef TRACE 118*7c478bd9Sstevel@tonic-gate tprintf("TRACE- termchars()\n"); 119*7c478bd9Sstevel@tonic-gate #endif 120*7c478bd9Sstevel@tonic-gate if (been_here) 121*7c478bd9Sstevel@tonic-gate return; 122*7c478bd9Sstevel@tonic-gate been_here = TRUE; 123*7c478bd9Sstevel@tonic-gate 124*7c478bd9Sstevel@tonic-gate if ((term = getenv("TERM")) == NULL) 125*7c478bd9Sstevel@tonic-gate return; 126*7c478bd9Sstevel@tonic-gate if (tgetent(bp, term) != 1) 127*7c478bd9Sstevel@tonic-gate return; 128*7c478bd9Sstevel@tonic-gate if (s = tgetstr("vb", &ap)) /* Visible Bell */ 129*7c478bd9Sstevel@tonic-gate BELL = s; 130*7c478bd9Sstevel@tonic-gate } 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate /* 133*7c478bd9Sstevel@tonic-gate * Move back to beginning of current line 134*7c478bd9Sstevel@tonic-gate */ 135*7c478bd9Sstevel@tonic-gate static 136*7c478bd9Sstevel@tonic-gate back_to_col_1() 137*7c478bd9Sstevel@tonic-gate { 138*7c478bd9Sstevel@tonic-gate int omask; 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate #ifdef TRACE 141*7c478bd9Sstevel@tonic-gate tprintf("TRACE- back_to_col_1()\n"); 142*7c478bd9Sstevel@tonic-gate #endif 143*7c478bd9Sstevel@tonic-gate omask = sigblock(sigmask(SIGINT)); 144*7c478bd9Sstevel@tonic-gate (void) write(SHOUT, "\r", 1); 145*7c478bd9Sstevel@tonic-gate (void) sigsetmask(omask); 146*7c478bd9Sstevel@tonic-gate } 147*7c478bd9Sstevel@tonic-gate 148*7c478bd9Sstevel@tonic-gate /* 149*7c478bd9Sstevel@tonic-gate * Push string contents back into tty queue 150*7c478bd9Sstevel@tonic-gate */ 151*7c478bd9Sstevel@tonic-gate static 152*7c478bd9Sstevel@tonic-gate pushback(string, echoflag) 153*7c478bd9Sstevel@tonic-gate tchar *string; 154*7c478bd9Sstevel@tonic-gate int echoflag; 155*7c478bd9Sstevel@tonic-gate { 156*7c478bd9Sstevel@tonic-gate register tchar *p; 157*7c478bd9Sstevel@tonic-gate struct termios tty; 158*7c478bd9Sstevel@tonic-gate int omask; 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate #ifdef TRACE 161*7c478bd9Sstevel@tonic-gate tprintf("TRACE- pushback()\n"); 162*7c478bd9Sstevel@tonic-gate #endif 163*7c478bd9Sstevel@tonic-gate omask = sigblock(sigmask(SIGINT)); 164*7c478bd9Sstevel@tonic-gate tty = tty_new; 165*7c478bd9Sstevel@tonic-gate if (!echoflag) 166*7c478bd9Sstevel@tonic-gate tty.c_lflag &= ~ECHO; 167*7c478bd9Sstevel@tonic-gate (void) ioctl(SHIN, TCSETSF, (char *)&tty); 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate for (p = string; *p; p++){ 170*7c478bd9Sstevel@tonic-gate char mbc[MB_LEN_MAX]; 171*7c478bd9Sstevel@tonic-gate int i, j = wctomb(mbc, (wchar_t)*p); 172*7c478bd9Sstevel@tonic-gate 173*7c478bd9Sstevel@tonic-gate if (j < 0) { 174*7c478bd9Sstevel@tonic-gate /* Error! But else what can we do? */ 175*7c478bd9Sstevel@tonic-gate continue; 176*7c478bd9Sstevel@tonic-gate } 177*7c478bd9Sstevel@tonic-gate for (i = 0; i < j; ++i) { 178*7c478bd9Sstevel@tonic-gate /* XXX: no error recovery provision. */ 179*7c478bd9Sstevel@tonic-gate (void) ioctl(SHIN, TIOCSTI, mbc + i); 180*7c478bd9Sstevel@tonic-gate } 181*7c478bd9Sstevel@tonic-gate } 182*7c478bd9Sstevel@tonic-gate 183*7c478bd9Sstevel@tonic-gate if (tty.c_lflag != tty_new.c_lflag) 184*7c478bd9Sstevel@tonic-gate (void) ioctl(SHIN, TCSETS, (char *)&tty_new); 185*7c478bd9Sstevel@tonic-gate (void) sigsetmask(omask); 186*7c478bd9Sstevel@tonic-gate } 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate /* 189*7c478bd9Sstevel@tonic-gate * Concatenate src onto tail of des. 190*7c478bd9Sstevel@tonic-gate * Des is a string whose maximum length is count. 191*7c478bd9Sstevel@tonic-gate * Always null terminate. 192*7c478bd9Sstevel@tonic-gate */ 193*7c478bd9Sstevel@tonic-gate catn(des, src, count) 194*7c478bd9Sstevel@tonic-gate register tchar *des, *src; 195*7c478bd9Sstevel@tonic-gate register count; 196*7c478bd9Sstevel@tonic-gate { 197*7c478bd9Sstevel@tonic-gate #ifdef TRACE 198*7c478bd9Sstevel@tonic-gate tprintf("TRACE- catn()\n"); 199*7c478bd9Sstevel@tonic-gate #endif 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate while (--count >= 0 && *des) 202*7c478bd9Sstevel@tonic-gate des++; 203*7c478bd9Sstevel@tonic-gate while (--count >= 0) 204*7c478bd9Sstevel@tonic-gate if ((*des++ = *src++) == '\0') 205*7c478bd9Sstevel@tonic-gate return; 206*7c478bd9Sstevel@tonic-gate *des = '\0'; 207*7c478bd9Sstevel@tonic-gate } 208*7c478bd9Sstevel@tonic-gate 209*7c478bd9Sstevel@tonic-gate static 210*7c478bd9Sstevel@tonic-gate max(a, b) 211*7c478bd9Sstevel@tonic-gate { 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate return (a > b ? a : b); 214*7c478bd9Sstevel@tonic-gate } 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate /* 217*7c478bd9Sstevel@tonic-gate * Like strncpy but always leave room for trailing \0 218*7c478bd9Sstevel@tonic-gate * and always null terminate. 219*7c478bd9Sstevel@tonic-gate */ 220*7c478bd9Sstevel@tonic-gate copyn(des, src, count) 221*7c478bd9Sstevel@tonic-gate register tchar *des, *src; 222*7c478bd9Sstevel@tonic-gate register count; 223*7c478bd9Sstevel@tonic-gate { 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate #ifdef TRACE 226*7c478bd9Sstevel@tonic-gate tprintf("TRACE- copyn()\n"); 227*7c478bd9Sstevel@tonic-gate #endif 228*7c478bd9Sstevel@tonic-gate while (--count >= 0) 229*7c478bd9Sstevel@tonic-gate if ((*des++ = *src++) == '\0') 230*7c478bd9Sstevel@tonic-gate return; 231*7c478bd9Sstevel@tonic-gate *des = '\0'; 232*7c478bd9Sstevel@tonic-gate } 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate /* 235*7c478bd9Sstevel@tonic-gate * For qsort() 236*7c478bd9Sstevel@tonic-gate */ 237*7c478bd9Sstevel@tonic-gate static 238*7c478bd9Sstevel@tonic-gate fcompare(file1, file2) 239*7c478bd9Sstevel@tonic-gate tchar **file1, **file2; 240*7c478bd9Sstevel@tonic-gate { 241*7c478bd9Sstevel@tonic-gate 242*7c478bd9Sstevel@tonic-gate #ifdef TRACE 243*7c478bd9Sstevel@tonic-gate tprintf("TRACE- fcompare()\n"); 244*7c478bd9Sstevel@tonic-gate #endif 245*7c478bd9Sstevel@tonic-gate return (strcoll_(*file1, *file2)); 246*7c478bd9Sstevel@tonic-gate } 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate static char 249*7c478bd9Sstevel@tonic-gate filetype(dir, file, nosym) 250*7c478bd9Sstevel@tonic-gate tchar *dir, *file; 251*7c478bd9Sstevel@tonic-gate int nosym; 252*7c478bd9Sstevel@tonic-gate { 253*7c478bd9Sstevel@tonic-gate tchar path[MAXPATHLEN + 1]; 254*7c478bd9Sstevel@tonic-gate struct stat statb; 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate #ifdef TRACE 257*7c478bd9Sstevel@tonic-gate tprintf("TRACE- filetype()\n"); 258*7c478bd9Sstevel@tonic-gate #endif 259*7c478bd9Sstevel@tonic-gate if (dir) { 260*7c478bd9Sstevel@tonic-gate catn(strcpy_(path, dir), file, MAXPATHLEN); 261*7c478bd9Sstevel@tonic-gate if (nosym) { 262*7c478bd9Sstevel@tonic-gate if (stat_(path, &statb) < 0) 263*7c478bd9Sstevel@tonic-gate return (' '); 264*7c478bd9Sstevel@tonic-gate } else { 265*7c478bd9Sstevel@tonic-gate if (lstat_(path, &statb) < 0) 266*7c478bd9Sstevel@tonic-gate return (' '); 267*7c478bd9Sstevel@tonic-gate } 268*7c478bd9Sstevel@tonic-gate if ((statb.st_mode & S_IFMT) == S_IFLNK) 269*7c478bd9Sstevel@tonic-gate return ('@'); 270*7c478bd9Sstevel@tonic-gate if ((statb.st_mode & S_IFMT) == S_IFDIR) 271*7c478bd9Sstevel@tonic-gate return ('/'); 272*7c478bd9Sstevel@tonic-gate if (((statb.st_mode & S_IFMT) == S_IFREG) && 273*7c478bd9Sstevel@tonic-gate (statb.st_mode & 011)) 274*7c478bd9Sstevel@tonic-gate return ('*'); 275*7c478bd9Sstevel@tonic-gate } 276*7c478bd9Sstevel@tonic-gate return (' '); 277*7c478bd9Sstevel@tonic-gate } 278*7c478bd9Sstevel@tonic-gate 279*7c478bd9Sstevel@tonic-gate /* 280*7c478bd9Sstevel@tonic-gate * Print sorted down columns 281*7c478bd9Sstevel@tonic-gate */ 282*7c478bd9Sstevel@tonic-gate static 283*7c478bd9Sstevel@tonic-gate print_by_column(dir, items, count, looking_for_command) 284*7c478bd9Sstevel@tonic-gate tchar *dir, *items[]; 285*7c478bd9Sstevel@tonic-gate int looking_for_command; 286*7c478bd9Sstevel@tonic-gate { 287*7c478bd9Sstevel@tonic-gate register int i, rows, r, c, maxwidth = 0, columns; 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate #ifdef TRACE 290*7c478bd9Sstevel@tonic-gate tprintf("TRACE- print_by_column()\n"); 291*7c478bd9Sstevel@tonic-gate #endif 292*7c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) 293*7c478bd9Sstevel@tonic-gate maxwidth = max(maxwidth, tswidth(items[i])); 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate /* for the file tag and space */ 296*7c478bd9Sstevel@tonic-gate maxwidth += looking_for_command ? 1 : 2; 297*7c478bd9Sstevel@tonic-gate columns = max(78 / maxwidth, 1); 298*7c478bd9Sstevel@tonic-gate rows = (count + (columns - 1)) / columns; 299*7c478bd9Sstevel@tonic-gate 300*7c478bd9Sstevel@tonic-gate for (r = 0; r < rows; r++) { 301*7c478bd9Sstevel@tonic-gate for (c = 0; c < columns; c++) { 302*7c478bd9Sstevel@tonic-gate i = c * rows + r; 303*7c478bd9Sstevel@tonic-gate if (i < count) { 304*7c478bd9Sstevel@tonic-gate register int w; 305*7c478bd9Sstevel@tonic-gate 306*7c478bd9Sstevel@tonic-gate /* 307*7c478bd9Sstevel@tonic-gate * Print filename followed by 308*7c478bd9Sstevel@tonic-gate * '@' or '/' or '*' or ' ' 309*7c478bd9Sstevel@tonic-gate */ 310*7c478bd9Sstevel@tonic-gate printf("%t", items[i]); 311*7c478bd9Sstevel@tonic-gate w = tswidth(items[i]); 312*7c478bd9Sstevel@tonic-gate if (!looking_for_command) { 313*7c478bd9Sstevel@tonic-gate printf("%c", 314*7c478bd9Sstevel@tonic-gate (tchar) filetype(dir, items[i], 0)); 315*7c478bd9Sstevel@tonic-gate w++; 316*7c478bd9Sstevel@tonic-gate } 317*7c478bd9Sstevel@tonic-gate if (c < columns - 1) /* last column? */ 318*7c478bd9Sstevel@tonic-gate for (; w < maxwidth; w++) 319*7c478bd9Sstevel@tonic-gate printf(" "); 320*7c478bd9Sstevel@tonic-gate } 321*7c478bd9Sstevel@tonic-gate } 322*7c478bd9Sstevel@tonic-gate printf("\n"); 323*7c478bd9Sstevel@tonic-gate } 324*7c478bd9Sstevel@tonic-gate } 325*7c478bd9Sstevel@tonic-gate 326*7c478bd9Sstevel@tonic-gate /* 327*7c478bd9Sstevel@tonic-gate * Expand file name with possible tilde usage 328*7c478bd9Sstevel@tonic-gate * ~person/mumble 329*7c478bd9Sstevel@tonic-gate * expands to 330*7c478bd9Sstevel@tonic-gate * home_directory_of_person/mumble 331*7c478bd9Sstevel@tonic-gate */ 332*7c478bd9Sstevel@tonic-gate tchar * 333*7c478bd9Sstevel@tonic-gate tilde(new, old) 334*7c478bd9Sstevel@tonic-gate tchar *new, *old; 335*7c478bd9Sstevel@tonic-gate { 336*7c478bd9Sstevel@tonic-gate register tchar *o, *p; 337*7c478bd9Sstevel@tonic-gate register struct passwd *pw; 338*7c478bd9Sstevel@tonic-gate static tchar person[40]; 339*7c478bd9Sstevel@tonic-gate char person_[40]; /* work */ 340*7c478bd9Sstevel@tonic-gate tchar *pw_dir; /* work */ 341*7c478bd9Sstevel@tonic-gate 342*7c478bd9Sstevel@tonic-gate #ifdef TRACE 343*7c478bd9Sstevel@tonic-gate tprintf("TRACE- tilde()\n"); 344*7c478bd9Sstevel@tonic-gate #endif 345*7c478bd9Sstevel@tonic-gate if (old[0] != '~') 346*7c478bd9Sstevel@tonic-gate return (strcpy_(new, old)); 347*7c478bd9Sstevel@tonic-gate 348*7c478bd9Sstevel@tonic-gate for (p = person, o = &old[1]; *o && *o != '/'; *p++ = *o++) 349*7c478bd9Sstevel@tonic-gate ; 350*7c478bd9Sstevel@tonic-gate *p = '\0'; 351*7c478bd9Sstevel@tonic-gate if (person[0] == '\0') 352*7c478bd9Sstevel@tonic-gate (void) strcpy_(new, value(S_home /*"home"*/)); 353*7c478bd9Sstevel@tonic-gate else { 354*7c478bd9Sstevel@tonic-gate pw = getpwnam(tstostr(person_,person)); 355*7c478bd9Sstevel@tonic-gate if (pw == NULL) 356*7c478bd9Sstevel@tonic-gate return (NULL); 357*7c478bd9Sstevel@tonic-gate pw_dir = strtots((tchar *)NULL, pw->pw_dir); /* allocate */ 358*7c478bd9Sstevel@tonic-gate (void) strcpy_(new, pw_dir); 359*7c478bd9Sstevel@tonic-gate xfree(pw_dir); /* free it */ 360*7c478bd9Sstevel@tonic-gate } 361*7c478bd9Sstevel@tonic-gate (void) strcat_(new, o); 362*7c478bd9Sstevel@tonic-gate return (new); 363*7c478bd9Sstevel@tonic-gate } 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate /* 366*7c478bd9Sstevel@tonic-gate * Cause pending line to be printed 367*7c478bd9Sstevel@tonic-gate */ 368*7c478bd9Sstevel@tonic-gate static 369*7c478bd9Sstevel@tonic-gate sim_retype() 370*7c478bd9Sstevel@tonic-gate { 371*7c478bd9Sstevel@tonic-gate #ifdef notdef 372*7c478bd9Sstevel@tonic-gate struct termios tty_pending; 373*7c478bd9Sstevel@tonic-gate 374*7c478bd9Sstevel@tonic-gate #ifdef TRACE 375*7c478bd9Sstevel@tonic-gate tprintf("TRACE- sim_retypr()\n"); 376*7c478bd9Sstevel@tonic-gate #endif 377*7c478bd9Sstevel@tonic-gate tty_pending = tty_new; 378*7c478bd9Sstevel@tonic-gate tty_pending.c_lflag |= PENDIN; 379*7c478bd9Sstevel@tonic-gate 380*7c478bd9Sstevel@tonic-gate (void) ioctl(SHIN, TCSETS, (char *)&tty_pending); 381*7c478bd9Sstevel@tonic-gate #else 382*7c478bd9Sstevel@tonic-gate #ifdef TRACE 383*7c478bd9Sstevel@tonic-gate tprintf("TRACE- sim_retype()\n"); 384*7c478bd9Sstevel@tonic-gate #endif 385*7c478bd9Sstevel@tonic-gate (void) write(SHOUT, CTRLR, strlen(CTRLR)); 386*7c478bd9Sstevel@tonic-gate printprompt(); 387*7c478bd9Sstevel@tonic-gate #endif 388*7c478bd9Sstevel@tonic-gate } 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate static 391*7c478bd9Sstevel@tonic-gate beep_outc (c) { 392*7c478bd9Sstevel@tonic-gate char buf[1]; 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate buf[0] = c; 395*7c478bd9Sstevel@tonic-gate 396*7c478bd9Sstevel@tonic-gate (void) write (SHOUT, buf, 1); 397*7c478bd9Sstevel@tonic-gate 398*7c478bd9Sstevel@tonic-gate return 0; 399*7c478bd9Sstevel@tonic-gate } 400*7c478bd9Sstevel@tonic-gate 401*7c478bd9Sstevel@tonic-gate static 402*7c478bd9Sstevel@tonic-gate beep() 403*7c478bd9Sstevel@tonic-gate { 404*7c478bd9Sstevel@tonic-gate 405*7c478bd9Sstevel@tonic-gate #ifdef TRACE 406*7c478bd9Sstevel@tonic-gate tprintf("TRACE- beep()\n"); 407*7c478bd9Sstevel@tonic-gate #endif 408*7c478bd9Sstevel@tonic-gate if (adrof(S_nobeep /*"nobeep" */) == 0) 409*7c478bd9Sstevel@tonic-gate (void) tputs (BELL, 0, beep_outc); 410*7c478bd9Sstevel@tonic-gate } 411*7c478bd9Sstevel@tonic-gate 412*7c478bd9Sstevel@tonic-gate /* 413*7c478bd9Sstevel@tonic-gate * Erase that silly ^[ and print the recognized part of the string. 414*7c478bd9Sstevel@tonic-gate */ 415*7c478bd9Sstevel@tonic-gate static 416*7c478bd9Sstevel@tonic-gate print_recognized_stuff(recognized_part) 417*7c478bd9Sstevel@tonic-gate tchar *recognized_part; 418*7c478bd9Sstevel@tonic-gate { 419*7c478bd9Sstevel@tonic-gate int unit = didfds ? 1 : SHOUT; 420*7c478bd9Sstevel@tonic-gate 421*7c478bd9Sstevel@tonic-gate #ifdef TRACE 422*7c478bd9Sstevel@tonic-gate tprintf("TRACE- print_recognized_stuff()\n"); 423*7c478bd9Sstevel@tonic-gate #endif 424*7c478bd9Sstevel@tonic-gate 425*7c478bd9Sstevel@tonic-gate /* 426*7c478bd9Sstevel@tonic-gate * An optimized erasing of that silly ^[ 427*7c478bd9Sstevel@tonic-gate * 428*7c478bd9Sstevel@tonic-gate * One would think that line speeds have become fast enough that this 429*7c478bd9Sstevel@tonic-gate * isn't necessary, but it turns out that the visual difference is 430*7c478bd9Sstevel@tonic-gate * quite noticeable. 431*7c478bd9Sstevel@tonic-gate */ 432*7c478bd9Sstevel@tonic-gate flush(); 433*7c478bd9Sstevel@tonic-gate switch (tswidth(recognized_part)) { 434*7c478bd9Sstevel@tonic-gate case 0: 435*7c478bd9Sstevel@tonic-gate /* erase two characters: ^[ */ 436*7c478bd9Sstevel@tonic-gate write(unit, "\b\b \b\b", sizeof "\b\b \b\b" - 1); 437*7c478bd9Sstevel@tonic-gate break; 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate case 1: 440*7c478bd9Sstevel@tonic-gate /* overstrike the ^, erase the [ */ 441*7c478bd9Sstevel@tonic-gate write(unit, "\b\b", 2); 442*7c478bd9Sstevel@tonic-gate printf("%t", recognized_part); 443*7c478bd9Sstevel@tonic-gate write(unit, " \b\b", 4); 444*7c478bd9Sstevel@tonic-gate break; 445*7c478bd9Sstevel@tonic-gate 446*7c478bd9Sstevel@tonic-gate default: 447*7c478bd9Sstevel@tonic-gate /* overstrike both characters ^[ */ 448*7c478bd9Sstevel@tonic-gate write(unit, "\b\b", 2); 449*7c478bd9Sstevel@tonic-gate printf("%t", recognized_part); 450*7c478bd9Sstevel@tonic-gate break; 451*7c478bd9Sstevel@tonic-gate } 452*7c478bd9Sstevel@tonic-gate flush(); 453*7c478bd9Sstevel@tonic-gate } 454*7c478bd9Sstevel@tonic-gate 455*7c478bd9Sstevel@tonic-gate /* 456*7c478bd9Sstevel@tonic-gate * Parse full path in file into 2 parts: directory and file names 457*7c478bd9Sstevel@tonic-gate * Should leave final slash (/) at end of dir. 458*7c478bd9Sstevel@tonic-gate */ 459*7c478bd9Sstevel@tonic-gate static 460*7c478bd9Sstevel@tonic-gate extract_dir_and_name(path, dir, name) 461*7c478bd9Sstevel@tonic-gate tchar *path, *dir, *name; 462*7c478bd9Sstevel@tonic-gate { 463*7c478bd9Sstevel@tonic-gate register tchar *p; 464*7c478bd9Sstevel@tonic-gate 465*7c478bd9Sstevel@tonic-gate #ifdef TRACE 466*7c478bd9Sstevel@tonic-gate tprintf("TRACE- extract_dir_and_name()\n"); 467*7c478bd9Sstevel@tonic-gate #endif 468*7c478bd9Sstevel@tonic-gate p = rindex_(path, '/'); 469*7c478bd9Sstevel@tonic-gate if (p == NOSTR) { 470*7c478bd9Sstevel@tonic-gate copyn(name, path, MAXNAMLEN); 471*7c478bd9Sstevel@tonic-gate dir[0] = '\0'; 472*7c478bd9Sstevel@tonic-gate } else { 473*7c478bd9Sstevel@tonic-gate copyn(name, ++p, MAXNAMLEN); 474*7c478bd9Sstevel@tonic-gate copyn(dir, path, p - path); 475*7c478bd9Sstevel@tonic-gate } 476*7c478bd9Sstevel@tonic-gate } 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate tchar * 479*7c478bd9Sstevel@tonic-gate getentry(dir_fd, looking_for_lognames) 480*7c478bd9Sstevel@tonic-gate DIR *dir_fd; 481*7c478bd9Sstevel@tonic-gate { 482*7c478bd9Sstevel@tonic-gate register struct passwd *pw; 483*7c478bd9Sstevel@tonic-gate register struct dirent *dirp; 484*7c478bd9Sstevel@tonic-gate /* 485*7c478bd9Sstevel@tonic-gate * For char * -> tchar * Conversion 486*7c478bd9Sstevel@tonic-gate */ 487*7c478bd9Sstevel@tonic-gate static tchar strbuf[MAXNAMLEN+1]; 488*7c478bd9Sstevel@tonic-gate 489*7c478bd9Sstevel@tonic-gate #ifdef TRACE 490*7c478bd9Sstevel@tonic-gate tprintf("TRACE- getentry()\n"); 491*7c478bd9Sstevel@tonic-gate #endif 492*7c478bd9Sstevel@tonic-gate if (looking_for_lognames) { 493*7c478bd9Sstevel@tonic-gate if ((pw = getpwent ()) == NULL) 494*7c478bd9Sstevel@tonic-gate return (NULL); 495*7c478bd9Sstevel@tonic-gate return (strtots(strbuf,pw->pw_name)); 496*7c478bd9Sstevel@tonic-gate } 497*7c478bd9Sstevel@tonic-gate if (dirp = readdir(dir_fd)) 498*7c478bd9Sstevel@tonic-gate return (strtots(strbuf,dirp->d_name)); 499*7c478bd9Sstevel@tonic-gate return (NULL); 500*7c478bd9Sstevel@tonic-gate } 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate static 503*7c478bd9Sstevel@tonic-gate free_items(items) 504*7c478bd9Sstevel@tonic-gate register tchar **items; 505*7c478bd9Sstevel@tonic-gate { 506*7c478bd9Sstevel@tonic-gate register int i; 507*7c478bd9Sstevel@tonic-gate 508*7c478bd9Sstevel@tonic-gate #ifdef TRACE 509*7c478bd9Sstevel@tonic-gate tprintf("TRACE- free_items()\n"); 510*7c478bd9Sstevel@tonic-gate #endif 511*7c478bd9Sstevel@tonic-gate for (i = 0; items[i]; i++) 512*7c478bd9Sstevel@tonic-gate free(items[i]); 513*7c478bd9Sstevel@tonic-gate free( (char *)items); 514*7c478bd9Sstevel@tonic-gate } 515*7c478bd9Sstevel@tonic-gate 516*7c478bd9Sstevel@tonic-gate #define FREE_ITEMS(items) { \ 517*7c478bd9Sstevel@tonic-gate int omask;\ 518*7c478bd9Sstevel@tonic-gate \ 519*7c478bd9Sstevel@tonic-gate omask = sigblock(sigmask(SIGINT));\ 520*7c478bd9Sstevel@tonic-gate free_items(items);\ 521*7c478bd9Sstevel@tonic-gate items = NULL;\ 522*7c478bd9Sstevel@tonic-gate (void) sigsetmask(omask);\ 523*7c478bd9Sstevel@tonic-gate } 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate /* 526*7c478bd9Sstevel@tonic-gate * Perform a RECOGNIZE or LIST command on string "word". 527*7c478bd9Sstevel@tonic-gate */ 528*7c478bd9Sstevel@tonic-gate static 529*7c478bd9Sstevel@tonic-gate search2(word, command, max_word_length) 530*7c478bd9Sstevel@tonic-gate tchar *word; 531*7c478bd9Sstevel@tonic-gate COMMAND command; 532*7c478bd9Sstevel@tonic-gate { 533*7c478bd9Sstevel@tonic-gate static tchar **items = NULL; 534*7c478bd9Sstevel@tonic-gate register DIR *dir_fd; 535*7c478bd9Sstevel@tonic-gate register numitems = 0, ignoring = TRUE, nignored = 0; 536*7c478bd9Sstevel@tonic-gate register name_length, looking_for_lognames; 537*7c478bd9Sstevel@tonic-gate tchar tilded_dir[MAXPATHLEN + 1], dir[MAXPATHLEN + 1]; 538*7c478bd9Sstevel@tonic-gate tchar name[MAXNAMLEN + 1], extended_name[MAXNAMLEN+1]; 539*7c478bd9Sstevel@tonic-gate tchar *entry; 540*7c478bd9Sstevel@tonic-gate #define MAXITEMS 1024 541*7c478bd9Sstevel@tonic-gate #ifdef TRACE 542*7c478bd9Sstevel@tonic-gate tprintf("TRACE- search2()\n"); 543*7c478bd9Sstevel@tonic-gate #endif 544*7c478bd9Sstevel@tonic-gate 545*7c478bd9Sstevel@tonic-gate if (items != NULL) 546*7c478bd9Sstevel@tonic-gate FREE_ITEMS(items); 547*7c478bd9Sstevel@tonic-gate 548*7c478bd9Sstevel@tonic-gate looking_for_lognames = (*word == '~') && (index_(word, '/') == NULL); 549*7c478bd9Sstevel@tonic-gate if (looking_for_lognames) { 550*7c478bd9Sstevel@tonic-gate (void) setpwent(); 551*7c478bd9Sstevel@tonic-gate copyn(name, &word[1], MAXNAMLEN); /* name sans ~ */ 552*7c478bd9Sstevel@tonic-gate } else { 553*7c478bd9Sstevel@tonic-gate extract_dir_and_name(word, dir, name); 554*7c478bd9Sstevel@tonic-gate if (tilde(tilded_dir, dir) == 0) 555*7c478bd9Sstevel@tonic-gate return (0); 556*7c478bd9Sstevel@tonic-gate dir_fd = opendir_(*tilded_dir ? tilded_dir : S_DOT /*"."*/); 557*7c478bd9Sstevel@tonic-gate if (dir_fd == NULL) 558*7c478bd9Sstevel@tonic-gate return (0); 559*7c478bd9Sstevel@tonic-gate } 560*7c478bd9Sstevel@tonic-gate 561*7c478bd9Sstevel@tonic-gate again: /* search for matches */ 562*7c478bd9Sstevel@tonic-gate name_length = strlen_(name); 563*7c478bd9Sstevel@tonic-gate for (numitems = 0; entry = getentry(dir_fd, looking_for_lognames); ) { 564*7c478bd9Sstevel@tonic-gate if (!is_prefix(name, entry)) 565*7c478bd9Sstevel@tonic-gate continue; 566*7c478bd9Sstevel@tonic-gate /* Don't match . files on null prefix match */ 567*7c478bd9Sstevel@tonic-gate if (name_length == 0 && entry[0] == '.' && 568*7c478bd9Sstevel@tonic-gate !looking_for_lognames) 569*7c478bd9Sstevel@tonic-gate continue; 570*7c478bd9Sstevel@tonic-gate if (command == LIST) { 571*7c478bd9Sstevel@tonic-gate if (numitems >= MAXITEMS) { 572*7c478bd9Sstevel@tonic-gate printf ("\nYikes!! Too many %s!!\n", 573*7c478bd9Sstevel@tonic-gate looking_for_lognames ? 574*7c478bd9Sstevel@tonic-gate "names in password file":"files"); 575*7c478bd9Sstevel@tonic-gate break; 576*7c478bd9Sstevel@tonic-gate } 577*7c478bd9Sstevel@tonic-gate if (items == NULL) 578*7c478bd9Sstevel@tonic-gate items = (tchar **) calloc(sizeof (items[1]), 579*7c478bd9Sstevel@tonic-gate MAXITEMS+1); 580*7c478bd9Sstevel@tonic-gate items[numitems] = (tchar *)xalloc((unsigned)(strlen_(entry) + 1)*sizeof(tchar)); 581*7c478bd9Sstevel@tonic-gate copyn(items[numitems], entry, MAXNAMLEN); 582*7c478bd9Sstevel@tonic-gate numitems++; 583*7c478bd9Sstevel@tonic-gate } else { /* RECOGNIZE command */ 584*7c478bd9Sstevel@tonic-gate if (ignoring && ignored(entry)) 585*7c478bd9Sstevel@tonic-gate nignored++; 586*7c478bd9Sstevel@tonic-gate else if (recognize(extended_name, 587*7c478bd9Sstevel@tonic-gate entry, name_length, ++numitems)) 588*7c478bd9Sstevel@tonic-gate break; 589*7c478bd9Sstevel@tonic-gate } 590*7c478bd9Sstevel@tonic-gate } 591*7c478bd9Sstevel@tonic-gate if (ignoring && numitems == 0 && nignored > 0) { 592*7c478bd9Sstevel@tonic-gate ignoring = FALSE; 593*7c478bd9Sstevel@tonic-gate nignored = 0; 594*7c478bd9Sstevel@tonic-gate if (looking_for_lognames) 595*7c478bd9Sstevel@tonic-gate (void)setpwent(); 596*7c478bd9Sstevel@tonic-gate else 597*7c478bd9Sstevel@tonic-gate rewinddir(dir_fd); 598*7c478bd9Sstevel@tonic-gate goto again; 599*7c478bd9Sstevel@tonic-gate } 600*7c478bd9Sstevel@tonic-gate 601*7c478bd9Sstevel@tonic-gate if (looking_for_lognames) 602*7c478bd9Sstevel@tonic-gate (void) endpwent(); 603*7c478bd9Sstevel@tonic-gate else { 604*7c478bd9Sstevel@tonic-gate unsetfd(dir_fd->dd_fd); 605*7c478bd9Sstevel@tonic-gate closedir_(dir_fd); 606*7c478bd9Sstevel@tonic-gate } 607*7c478bd9Sstevel@tonic-gate if (command == RECOGNIZE && numitems > 0) { 608*7c478bd9Sstevel@tonic-gate if (looking_for_lognames) 609*7c478bd9Sstevel@tonic-gate copyn(word, S_TIL /*"~" */, 1); 610*7c478bd9Sstevel@tonic-gate else 611*7c478bd9Sstevel@tonic-gate /* put back dir part */ 612*7c478bd9Sstevel@tonic-gate copyn(word, dir, max_word_length); 613*7c478bd9Sstevel@tonic-gate /* add extended name */ 614*7c478bd9Sstevel@tonic-gate catn(word, extended_name, max_word_length); 615*7c478bd9Sstevel@tonic-gate return (numitems); 616*7c478bd9Sstevel@tonic-gate } 617*7c478bd9Sstevel@tonic-gate if (command == LIST) { 618*7c478bd9Sstevel@tonic-gate qsort( (char *)items, numitems, sizeof(items[1]), 619*7c478bd9Sstevel@tonic-gate (int (*)(const void *, const void *))fcompare); 620*7c478bd9Sstevel@tonic-gate /* 621*7c478bd9Sstevel@tonic-gate * Never looking for commands in this version, so final 622*7c478bd9Sstevel@tonic-gate * argument forced to 0. If command name completion is 623*7c478bd9Sstevel@tonic-gate * reinstated, this must change. 624*7c478bd9Sstevel@tonic-gate */ 625*7c478bd9Sstevel@tonic-gate print_by_column(looking_for_lognames ? NULL : tilded_dir, 626*7c478bd9Sstevel@tonic-gate items, numitems, 0); 627*7c478bd9Sstevel@tonic-gate if (items != NULL) 628*7c478bd9Sstevel@tonic-gate FREE_ITEMS(items); 629*7c478bd9Sstevel@tonic-gate } 630*7c478bd9Sstevel@tonic-gate return (0); 631*7c478bd9Sstevel@tonic-gate } 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate /* 634*7c478bd9Sstevel@tonic-gate * Object: extend what user typed up to an ambiguity. 635*7c478bd9Sstevel@tonic-gate * Algorithm: 636*7c478bd9Sstevel@tonic-gate * On first match, copy full entry (assume it'll be the only match) 637*7c478bd9Sstevel@tonic-gate * On subsequent matches, shorten extended_name to the first 638*7c478bd9Sstevel@tonic-gate * character mismatch between extended_name and entry. 639*7c478bd9Sstevel@tonic-gate * If we shorten it back to the prefix length, stop searching. 640*7c478bd9Sstevel@tonic-gate */ 641*7c478bd9Sstevel@tonic-gate recognize(extended_name, entry, name_length, numitems) 642*7c478bd9Sstevel@tonic-gate tchar *extended_name, *entry; 643*7c478bd9Sstevel@tonic-gate { 644*7c478bd9Sstevel@tonic-gate 645*7c478bd9Sstevel@tonic-gate #ifdef TRACE 646*7c478bd9Sstevel@tonic-gate tprintf("TRACE- recognize()\n"); 647*7c478bd9Sstevel@tonic-gate #endif 648*7c478bd9Sstevel@tonic-gate if (numitems == 1) /* 1st match */ 649*7c478bd9Sstevel@tonic-gate copyn(extended_name, entry, MAXNAMLEN); 650*7c478bd9Sstevel@tonic-gate else { /* 2nd and subsequent matches */ 651*7c478bd9Sstevel@tonic-gate register tchar *x, *ent; 652*7c478bd9Sstevel@tonic-gate register int len = 0; 653*7c478bd9Sstevel@tonic-gate 654*7c478bd9Sstevel@tonic-gate x = extended_name; 655*7c478bd9Sstevel@tonic-gate for (ent = entry; *x && *x == *ent++; x++, len++) 656*7c478bd9Sstevel@tonic-gate ; 657*7c478bd9Sstevel@tonic-gate *x = '\0'; /* Shorten at 1st char diff */ 658*7c478bd9Sstevel@tonic-gate if (len == name_length) /* Ambiguous to prefix? */ 659*7c478bd9Sstevel@tonic-gate return (-1); /* So stop now and save time */ 660*7c478bd9Sstevel@tonic-gate } 661*7c478bd9Sstevel@tonic-gate return (0); 662*7c478bd9Sstevel@tonic-gate } 663*7c478bd9Sstevel@tonic-gate 664*7c478bd9Sstevel@tonic-gate /* 665*7c478bd9Sstevel@tonic-gate * Return true if check items initial chars in template 666*7c478bd9Sstevel@tonic-gate * This differs from PWB imatch in that if check is null 667*7c478bd9Sstevel@tonic-gate * it items anything 668*7c478bd9Sstevel@tonic-gate */ 669*7c478bd9Sstevel@tonic-gate static 670*7c478bd9Sstevel@tonic-gate is_prefix(check, template) 671*7c478bd9Sstevel@tonic-gate register tchar *check, *template; 672*7c478bd9Sstevel@tonic-gate { 673*7c478bd9Sstevel@tonic-gate #ifdef TRACE 674*7c478bd9Sstevel@tonic-gate tprintf("TRACE- is_prefix()\n"); 675*7c478bd9Sstevel@tonic-gate #endif 676*7c478bd9Sstevel@tonic-gate 677*7c478bd9Sstevel@tonic-gate do 678*7c478bd9Sstevel@tonic-gate if (*check == 0) 679*7c478bd9Sstevel@tonic-gate return (TRUE); 680*7c478bd9Sstevel@tonic-gate while (*check++ == *template++); 681*7c478bd9Sstevel@tonic-gate return (FALSE); 682*7c478bd9Sstevel@tonic-gate } 683*7c478bd9Sstevel@tonic-gate 684*7c478bd9Sstevel@tonic-gate /* 685*7c478bd9Sstevel@tonic-gate * Return true if the chars in template appear at the 686*7c478bd9Sstevel@tonic-gate * end of check, i.e., are its suffix. 687*7c478bd9Sstevel@tonic-gate */ 688*7c478bd9Sstevel@tonic-gate static 689*7c478bd9Sstevel@tonic-gate is_suffix(check, template) 690*7c478bd9Sstevel@tonic-gate tchar *check, *template; 691*7c478bd9Sstevel@tonic-gate { 692*7c478bd9Sstevel@tonic-gate register tchar *c, *t; 693*7c478bd9Sstevel@tonic-gate 694*7c478bd9Sstevel@tonic-gate #ifdef TRACE 695*7c478bd9Sstevel@tonic-gate tprintf("TRACE- is_suffix()\n"); 696*7c478bd9Sstevel@tonic-gate #endif 697*7c478bd9Sstevel@tonic-gate for (c = check; *c++;) 698*7c478bd9Sstevel@tonic-gate ; 699*7c478bd9Sstevel@tonic-gate for (t = template; *t++;) 700*7c478bd9Sstevel@tonic-gate ; 701*7c478bd9Sstevel@tonic-gate for (;;) { 702*7c478bd9Sstevel@tonic-gate if (t == template) 703*7c478bd9Sstevel@tonic-gate return (TRUE); 704*7c478bd9Sstevel@tonic-gate if (c == check || *--t != *--c) 705*7c478bd9Sstevel@tonic-gate return (FALSE); 706*7c478bd9Sstevel@tonic-gate } 707*7c478bd9Sstevel@tonic-gate } 708*7c478bd9Sstevel@tonic-gate 709*7c478bd9Sstevel@tonic-gate tenex(inputline, inputline_size) 710*7c478bd9Sstevel@tonic-gate tchar *inputline; 711*7c478bd9Sstevel@tonic-gate int inputline_size; 712*7c478bd9Sstevel@tonic-gate { 713*7c478bd9Sstevel@tonic-gate register int numitems, num_read, should_retype; 714*7c478bd9Sstevel@tonic-gate int i; 715*7c478bd9Sstevel@tonic-gate 716*7c478bd9Sstevel@tonic-gate #ifdef TRACE 717*7c478bd9Sstevel@tonic-gate tprintf("TRACE- tenex()\n"); 718*7c478bd9Sstevel@tonic-gate #endif 719*7c478bd9Sstevel@tonic-gate setup_tty(ON); 720*7c478bd9Sstevel@tonic-gate termchars(); 721*7c478bd9Sstevel@tonic-gate num_read = 0; 722*7c478bd9Sstevel@tonic-gate should_retype = FALSE; 723*7c478bd9Sstevel@tonic-gate while ((i = read_(SHIN, inputline+num_read, inputline_size-num_read)) 724*7c478bd9Sstevel@tonic-gate > 0) { 725*7c478bd9Sstevel@tonic-gate static tchar *delims = S_DELIM /*" '\"\t;&<>()|`"*/; 726*7c478bd9Sstevel@tonic-gate register tchar *str_end, *word_start, last_char; 727*7c478bd9Sstevel@tonic-gate register int space_left; 728*7c478bd9Sstevel@tonic-gate struct termios tty; 729*7c478bd9Sstevel@tonic-gate COMMAND command; 730*7c478bd9Sstevel@tonic-gate 731*7c478bd9Sstevel@tonic-gate num_read += i; 732*7c478bd9Sstevel@tonic-gate inputline[num_read] = '\0'; 733*7c478bd9Sstevel@tonic-gate last_char = inputline[num_read - 1] & TRIM; 734*7c478bd9Sstevel@tonic-gate 735*7c478bd9Sstevel@tonic-gate if ((num_read == inputline_size) || (last_char == '\n')) 736*7c478bd9Sstevel@tonic-gate break; 737*7c478bd9Sstevel@tonic-gate 738*7c478bd9Sstevel@tonic-gate str_end = &inputline[num_read]; 739*7c478bd9Sstevel@tonic-gate if (last_char == ESC) { 740*7c478bd9Sstevel@tonic-gate command = RECOGNIZE; 741*7c478bd9Sstevel@tonic-gate *--str_end = '\0'; /* wipe out trailing ESC */ 742*7c478bd9Sstevel@tonic-gate } else 743*7c478bd9Sstevel@tonic-gate command = LIST; 744*7c478bd9Sstevel@tonic-gate 745*7c478bd9Sstevel@tonic-gate tty = tty_new; 746*7c478bd9Sstevel@tonic-gate tty.c_lflag &= ~ECHO; 747*7c478bd9Sstevel@tonic-gate (void) ioctl(SHIN, TCSETSF, (char *)&tty); 748*7c478bd9Sstevel@tonic-gate 749*7c478bd9Sstevel@tonic-gate if (command == LIST) 750*7c478bd9Sstevel@tonic-gate printf("\n"); 751*7c478bd9Sstevel@tonic-gate /* 752*7c478bd9Sstevel@tonic-gate * Find LAST occurence of a delimiter in the inputline. 753*7c478bd9Sstevel@tonic-gate * The word start is one character past it. 754*7c478bd9Sstevel@tonic-gate */ 755*7c478bd9Sstevel@tonic-gate for (word_start = str_end; word_start > inputline; 756*7c478bd9Sstevel@tonic-gate --word_start) { 757*7c478bd9Sstevel@tonic-gate if (index_(delims, word_start[-1]) || 758*7c478bd9Sstevel@tonic-gate isauxsp(word_start[-1])) 759*7c478bd9Sstevel@tonic-gate break; 760*7c478bd9Sstevel@tonic-gate } 761*7c478bd9Sstevel@tonic-gate space_left = inputline_size - (word_start - inputline) - 1; 762*7c478bd9Sstevel@tonic-gate numitems = search2(word_start, command, space_left); 763*7c478bd9Sstevel@tonic-gate 764*7c478bd9Sstevel@tonic-gate /* 765*7c478bd9Sstevel@tonic-gate * Tabs in the input line cause trouble after a pushback. 766*7c478bd9Sstevel@tonic-gate * tty driver won't backspace over them because column 767*7c478bd9Sstevel@tonic-gate * positions are now incorrect. This is solved by retyping 768*7c478bd9Sstevel@tonic-gate * over current line. 769*7c478bd9Sstevel@tonic-gate */ 770*7c478bd9Sstevel@tonic-gate if (index_(inputline, '\t')) { /* tab tchar in input line? */ 771*7c478bd9Sstevel@tonic-gate back_to_col_1(); 772*7c478bd9Sstevel@tonic-gate should_retype = TRUE; 773*7c478bd9Sstevel@tonic-gate } 774*7c478bd9Sstevel@tonic-gate if (command == LIST) /* Always retype after a LIST */ 775*7c478bd9Sstevel@tonic-gate should_retype = TRUE; 776*7c478bd9Sstevel@tonic-gate if (should_retype) 777*7c478bd9Sstevel@tonic-gate printprompt(); 778*7c478bd9Sstevel@tonic-gate pushback(inputline, should_retype); 779*7c478bd9Sstevel@tonic-gate num_read = 0; /* chars will be reread */ 780*7c478bd9Sstevel@tonic-gate should_retype = FALSE; 781*7c478bd9Sstevel@tonic-gate 782*7c478bd9Sstevel@tonic-gate /* 783*7c478bd9Sstevel@tonic-gate * Avoid a race condition by echoing what we're recognized 784*7c478bd9Sstevel@tonic-gate * _after_ pushing back the command line. This way, if the 785*7c478bd9Sstevel@tonic-gate * user waits until seeing this output before typing more 786*7c478bd9Sstevel@tonic-gate * stuff, the resulting keystrokes won't race with the STIed 787*7c478bd9Sstevel@tonic-gate * input we've pushed back. (Of course, if the user types 788*7c478bd9Sstevel@tonic-gate * ahead, the race still exists and it's quite possible that 789*7c478bd9Sstevel@tonic-gate * the pushed back input line will interleave with the 790*7c478bd9Sstevel@tonic-gate * keystrokes in unexpected ways.) 791*7c478bd9Sstevel@tonic-gate */ 792*7c478bd9Sstevel@tonic-gate if (command == RECOGNIZE) { 793*7c478bd9Sstevel@tonic-gate /* print from str_end on */ 794*7c478bd9Sstevel@tonic-gate print_recognized_stuff(str_end); 795*7c478bd9Sstevel@tonic-gate if (numitems != 1) /* Beep = No match/ambiguous */ 796*7c478bd9Sstevel@tonic-gate beep(); 797*7c478bd9Sstevel@tonic-gate } 798*7c478bd9Sstevel@tonic-gate } 799*7c478bd9Sstevel@tonic-gate setup_tty(OFF); 800*7c478bd9Sstevel@tonic-gate return (num_read); 801*7c478bd9Sstevel@tonic-gate } 802*7c478bd9Sstevel@tonic-gate 803*7c478bd9Sstevel@tonic-gate static 804*7c478bd9Sstevel@tonic-gate ignored(entry) 805*7c478bd9Sstevel@tonic-gate register tchar *entry; 806*7c478bd9Sstevel@tonic-gate { 807*7c478bd9Sstevel@tonic-gate struct varent *vp; 808*7c478bd9Sstevel@tonic-gate register tchar **cp; 809*7c478bd9Sstevel@tonic-gate 810*7c478bd9Sstevel@tonic-gate #ifdef TRACE 811*7c478bd9Sstevel@tonic-gate tprintf("TRACE- ignored()\n"); 812*7c478bd9Sstevel@tonic-gate #endif 813*7c478bd9Sstevel@tonic-gate if ((vp = adrof(S_fignore /*"fignore"*/)) == NULL || 814*7c478bd9Sstevel@tonic-gate (cp = vp->vec) == NULL) 815*7c478bd9Sstevel@tonic-gate return (FALSE); 816*7c478bd9Sstevel@tonic-gate for (; *cp != NULL; cp++) 817*7c478bd9Sstevel@tonic-gate if (is_suffix(entry, *cp)) 818*7c478bd9Sstevel@tonic-gate return (TRUE); 819*7c478bd9Sstevel@tonic-gate return (FALSE); 820*7c478bd9Sstevel@tonic-gate } 821*7c478bd9Sstevel@tonic-gate #endif FILEC 822