1*47116Sbostic /*- 2*47116Sbostic * Copyright (c) 1991 The Regents of the University of California. 3*47116Sbostic * All rights reserved. 4*47116Sbostic * 5*47116Sbostic * This code is derived from software contributed to Berkeley by 6*47116Sbostic * Kenneth Almquist. 7*47116Sbostic * 8*47116Sbostic * %sccs.include.redist.c% 9*47116Sbostic */ 10*47116Sbostic 11*47116Sbostic #ifndef lint 12*47116Sbostic static char sccsid[] = "@(#)expand.c 5.1 (Berkeley) 03/07/91"; 13*47116Sbostic #endif /* not lint */ 14*47116Sbostic 15*47116Sbostic /* 16*47116Sbostic * Routines to expand arguments to commands. We have to deal with 17*47116Sbostic * backquotes, shell variables, and file metacharacters. 18*47116Sbostic */ 19*47116Sbostic 20*47116Sbostic #include "shell.h" 21*47116Sbostic #include "main.h" 22*47116Sbostic #include "nodes.h" 23*47116Sbostic #include "eval.h" 24*47116Sbostic #include "expand.h" 25*47116Sbostic #include "syntax.h" 26*47116Sbostic #include "parser.h" 27*47116Sbostic #include "jobs.h" 28*47116Sbostic #include "options.h" 29*47116Sbostic #include "var.h" 30*47116Sbostic #include "input.h" 31*47116Sbostic #include "output.h" 32*47116Sbostic #include "memalloc.h" 33*47116Sbostic #include "error.h" 34*47116Sbostic #include "mystring.h" 35*47116Sbostic #include <sys/types.h> 36*47116Sbostic #include <sys/stat.h> 37*47116Sbostic #include <errno.h> 38*47116Sbostic #include <dirent.h> 39*47116Sbostic 40*47116Sbostic /* 41*47116Sbostic * Structure specifying which parts of the string should be searched 42*47116Sbostic * for IFS characters. 43*47116Sbostic */ 44*47116Sbostic 45*47116Sbostic struct ifsregion { 46*47116Sbostic struct ifsregion *next; /* next region in list */ 47*47116Sbostic int begoff; /* offset of start of region */ 48*47116Sbostic int endoff; /* offset of end of region */ 49*47116Sbostic int nulonly; /* search for nul bytes only */ 50*47116Sbostic }; 51*47116Sbostic 52*47116Sbostic 53*47116Sbostic char *expdest; /* output of current string */ 54*47116Sbostic struct nodelist *argbackq; /* list of back quote expressions */ 55*47116Sbostic struct ifsregion ifsfirst; /* first struct in list of ifs regions */ 56*47116Sbostic struct ifsregion *ifslastp; /* last struct in list */ 57*47116Sbostic struct arglist exparg; /* holds expanded arg list */ 58*47116Sbostic #if UDIR 59*47116Sbostic /* 60*47116Sbostic * Set if the last argument processed had /u/logname expanded. This 61*47116Sbostic * variable is read by the cd command. 62*47116Sbostic */ 63*47116Sbostic int didudir; 64*47116Sbostic #endif 65*47116Sbostic 66*47116Sbostic #ifdef __STDC__ 67*47116Sbostic STATIC void argstr(char *, int); 68*47116Sbostic STATIC void expbackq(union node *, int, int); 69*47116Sbostic STATIC char *evalvar(char *, int); 70*47116Sbostic STATIC int varisset(int); 71*47116Sbostic STATIC void varvalue(int, int, int); 72*47116Sbostic STATIC void recordregion(int, int, int); 73*47116Sbostic STATIC void ifsbreakup(char *, struct arglist *); 74*47116Sbostic STATIC void expandmeta(struct strlist *); 75*47116Sbostic STATIC void expmeta(char *, char *); 76*47116Sbostic STATIC void addfname(char *); 77*47116Sbostic STATIC struct strlist *expsort(struct strlist *); 78*47116Sbostic STATIC struct strlist *msort(struct strlist *, int); 79*47116Sbostic STATIC int pmatch(char *, char *); 80*47116Sbostic #else 81*47116Sbostic STATIC void argstr(); 82*47116Sbostic STATIC void expbackq(); 83*47116Sbostic STATIC char *evalvar(); 84*47116Sbostic STATIC int varisset(); 85*47116Sbostic STATIC void varvalue(); 86*47116Sbostic STATIC void recordregion(); 87*47116Sbostic STATIC void ifsbreakup(); 88*47116Sbostic STATIC void expandmeta(); 89*47116Sbostic STATIC void expmeta(); 90*47116Sbostic STATIC void addfname(); 91*47116Sbostic STATIC struct strlist *expsort(); 92*47116Sbostic STATIC struct strlist *msort(); 93*47116Sbostic STATIC int pmatch(); 94*47116Sbostic #endif 95*47116Sbostic #if UDIR 96*47116Sbostic #ifdef __STDC__ 97*47116Sbostic STATIC char *expudir(char *); 98*47116Sbostic #else 99*47116Sbostic STATIC char *expudir(); 100*47116Sbostic #endif 101*47116Sbostic #endif /* UDIR */ 102*47116Sbostic 103*47116Sbostic 104*47116Sbostic 105*47116Sbostic /* 106*47116Sbostic * Expand shell variables and backquotes inside a here document. 107*47116Sbostic */ 108*47116Sbostic 109*47116Sbostic void 110*47116Sbostic expandhere(arg, fd) 111*47116Sbostic union node *arg; /* the document */ 112*47116Sbostic int fd; /* where to write the expanded version */ 113*47116Sbostic { 114*47116Sbostic herefd = fd; 115*47116Sbostic expandarg(arg, (struct arglist *)NULL, 0); 116*47116Sbostic xwrite(fd, stackblock(), expdest - stackblock()); 117*47116Sbostic } 118*47116Sbostic 119*47116Sbostic 120*47116Sbostic /* 121*47116Sbostic * Perform variable substitution and command substitution on an argument, 122*47116Sbostic * placing the resulting list of arguments in arglist. If full is true, 123*47116Sbostic * perform splitting and file name expansion. When arglist is NULL, perform 124*47116Sbostic * here document expansion. 125*47116Sbostic */ 126*47116Sbostic 127*47116Sbostic void 128*47116Sbostic expandarg(arg, arglist, full) 129*47116Sbostic union node *arg; 130*47116Sbostic struct arglist *arglist; 131*47116Sbostic { 132*47116Sbostic struct strlist *sp; 133*47116Sbostic char *p; 134*47116Sbostic 135*47116Sbostic #if UDIR 136*47116Sbostic didudir = 0; 137*47116Sbostic #endif 138*47116Sbostic argbackq = arg->narg.backquote; 139*47116Sbostic STARTSTACKSTR(expdest); 140*47116Sbostic ifsfirst.next = NULL; 141*47116Sbostic ifslastp = NULL; 142*47116Sbostic argstr(arg->narg.text, full); 143*47116Sbostic if (arglist == NULL) 144*47116Sbostic return; /* here document expanded */ 145*47116Sbostic STPUTC('\0', expdest); 146*47116Sbostic p = grabstackstr(expdest); 147*47116Sbostic exparg.lastp = &exparg.list; 148*47116Sbostic if (full) { 149*47116Sbostic ifsbreakup(p, &exparg); 150*47116Sbostic *exparg.lastp = NULL; 151*47116Sbostic exparg.lastp = &exparg.list; 152*47116Sbostic expandmeta(exparg.list); 153*47116Sbostic } else { 154*47116Sbostic sp = (struct strlist *)stalloc(sizeof (struct strlist)); 155*47116Sbostic sp->text = p; 156*47116Sbostic *exparg.lastp = sp; 157*47116Sbostic exparg.lastp = &sp->next; 158*47116Sbostic } 159*47116Sbostic while (ifsfirst.next != NULL) { 160*47116Sbostic struct ifsregion *ifsp; 161*47116Sbostic INTOFF; 162*47116Sbostic ifsp = ifsfirst.next->next; 163*47116Sbostic ckfree(ifsfirst.next); 164*47116Sbostic ifsfirst.next = ifsp; 165*47116Sbostic INTON; 166*47116Sbostic } 167*47116Sbostic *exparg.lastp = NULL; 168*47116Sbostic if (exparg.list) { 169*47116Sbostic *arglist->lastp = exparg.list; 170*47116Sbostic arglist->lastp = exparg.lastp; 171*47116Sbostic } 172*47116Sbostic } 173*47116Sbostic 174*47116Sbostic 175*47116Sbostic 176*47116Sbostic /* 177*47116Sbostic * Perform variable and command substitution. If full is set, output CTLESC 178*47116Sbostic * characters to allow for further processing. If full is not set, treat 179*47116Sbostic * $@ like $* since no splitting will be performed. 180*47116Sbostic */ 181*47116Sbostic 182*47116Sbostic STATIC void 183*47116Sbostic argstr(p, full) 184*47116Sbostic register char *p; 185*47116Sbostic { 186*47116Sbostic char c; 187*47116Sbostic 188*47116Sbostic for (;;) { 189*47116Sbostic switch (c = *p++) { 190*47116Sbostic case '\0': 191*47116Sbostic case CTLENDVAR: 192*47116Sbostic goto breakloop; 193*47116Sbostic case CTLESC: 194*47116Sbostic if (full) 195*47116Sbostic STPUTC(c, expdest); 196*47116Sbostic c = *p++; 197*47116Sbostic STPUTC(c, expdest); 198*47116Sbostic break; 199*47116Sbostic case CTLVAR: 200*47116Sbostic p = evalvar(p, full); 201*47116Sbostic break; 202*47116Sbostic case CTLBACKQ: 203*47116Sbostic case CTLBACKQ|CTLQUOTE: 204*47116Sbostic expbackq(argbackq->n, c & CTLQUOTE, full); 205*47116Sbostic argbackq = argbackq->next; 206*47116Sbostic break; 207*47116Sbostic default: 208*47116Sbostic STPUTC(c, expdest); 209*47116Sbostic } 210*47116Sbostic } 211*47116Sbostic breakloop:; 212*47116Sbostic } 213*47116Sbostic 214*47116Sbostic 215*47116Sbostic /* 216*47116Sbostic * Expand stuff in backwards quotes. 217*47116Sbostic */ 218*47116Sbostic 219*47116Sbostic STATIC void 220*47116Sbostic expbackq(cmd, quoted, full) 221*47116Sbostic union node *cmd; 222*47116Sbostic { 223*47116Sbostic struct backcmd in; 224*47116Sbostic int i; 225*47116Sbostic char buf[128]; 226*47116Sbostic char *p; 227*47116Sbostic char *dest = expdest; 228*47116Sbostic struct ifsregion saveifs, *savelastp; 229*47116Sbostic struct nodelist *saveargbackq; 230*47116Sbostic char lastc; 231*47116Sbostic int startloc = dest - stackblock(); 232*47116Sbostic char const *syntax = quoted? DQSYNTAX : BASESYNTAX; 233*47116Sbostic int saveherefd; 234*47116Sbostic 235*47116Sbostic INTOFF; 236*47116Sbostic saveifs = ifsfirst; 237*47116Sbostic savelastp = ifslastp; 238*47116Sbostic saveargbackq = argbackq; 239*47116Sbostic saveherefd = herefd; 240*47116Sbostic herefd = -1; 241*47116Sbostic p = grabstackstr(dest); 242*47116Sbostic evalbackcmd(cmd, &in); 243*47116Sbostic ungrabstackstr(p, dest); 244*47116Sbostic ifsfirst = saveifs; 245*47116Sbostic ifslastp = savelastp; 246*47116Sbostic argbackq = saveargbackq; 247*47116Sbostic herefd = saveherefd; 248*47116Sbostic 249*47116Sbostic p = in.buf; 250*47116Sbostic lastc = '\0'; 251*47116Sbostic for (;;) { 252*47116Sbostic if (--in.nleft < 0) { 253*47116Sbostic if (in.fd < 0) 254*47116Sbostic break; 255*47116Sbostic while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR); 256*47116Sbostic TRACE(("expbackq: read returns %d\n", i)); 257*47116Sbostic if (i <= 0) 258*47116Sbostic break; 259*47116Sbostic p = buf; 260*47116Sbostic in.nleft = i - 1; 261*47116Sbostic } 262*47116Sbostic lastc = *p++; 263*47116Sbostic if (lastc != '\0') { 264*47116Sbostic if (full && syntax[lastc] == CCTL) 265*47116Sbostic STPUTC(CTLESC, dest); 266*47116Sbostic STPUTC(lastc, dest); 267*47116Sbostic } 268*47116Sbostic } 269*47116Sbostic if (lastc == '\n') { 270*47116Sbostic STUNPUTC(dest); 271*47116Sbostic } 272*47116Sbostic if (in.fd >= 0) 273*47116Sbostic close(in.fd); 274*47116Sbostic if (in.buf) 275*47116Sbostic ckfree(in.buf); 276*47116Sbostic if (in.jp) 277*47116Sbostic waitforjob(in.jp); 278*47116Sbostic if (quoted == 0) 279*47116Sbostic recordregion(startloc, dest - stackblock(), 0); 280*47116Sbostic TRACE(("evalbackq: size=%d: \"%.*s\"\n", 281*47116Sbostic (dest - stackblock()) - startloc, 282*47116Sbostic (dest - stackblock()) - startloc, 283*47116Sbostic stackblock() + startloc)); 284*47116Sbostic expdest = dest; 285*47116Sbostic INTON; 286*47116Sbostic } 287*47116Sbostic 288*47116Sbostic 289*47116Sbostic 290*47116Sbostic /* 291*47116Sbostic * Expand a variable, and return a pointer to the next character in the 292*47116Sbostic * input string. 293*47116Sbostic */ 294*47116Sbostic 295*47116Sbostic STATIC char * 296*47116Sbostic evalvar(p, full) 297*47116Sbostic char *p; 298*47116Sbostic { 299*47116Sbostic int subtype; 300*47116Sbostic int flags; 301*47116Sbostic char *var; 302*47116Sbostic char *val; 303*47116Sbostic int c; 304*47116Sbostic int set; 305*47116Sbostic int special; 306*47116Sbostic int startloc; 307*47116Sbostic 308*47116Sbostic flags = *p++; 309*47116Sbostic subtype = flags & VSTYPE; 310*47116Sbostic var = p; 311*47116Sbostic special = 0; 312*47116Sbostic if (! is_name(*p)) 313*47116Sbostic special = 1; 314*47116Sbostic p = strchr(p, '=') + 1; 315*47116Sbostic again: /* jump here after setting a variable with ${var=text} */ 316*47116Sbostic if (special) { 317*47116Sbostic set = varisset(*var); 318*47116Sbostic val = NULL; 319*47116Sbostic } else { 320*47116Sbostic val = lookupvar(var); 321*47116Sbostic if (val == NULL || (flags & VSNUL) && val[0] == '\0') { 322*47116Sbostic val = NULL; 323*47116Sbostic set = 0; 324*47116Sbostic } else 325*47116Sbostic set = 1; 326*47116Sbostic } 327*47116Sbostic startloc = expdest - stackblock(); 328*47116Sbostic if (set && subtype != VSPLUS) { 329*47116Sbostic /* insert the value of the variable */ 330*47116Sbostic if (special) { 331*47116Sbostic varvalue(*var, flags & VSQUOTE, full); 332*47116Sbostic } else { 333*47116Sbostic char const *syntax = (flags & VSQUOTE)? DQSYNTAX : BASESYNTAX; 334*47116Sbostic 335*47116Sbostic while (*val) { 336*47116Sbostic if (full && syntax[*val] == CCTL) 337*47116Sbostic STPUTC(CTLESC, expdest); 338*47116Sbostic STPUTC(*val++, expdest); 339*47116Sbostic } 340*47116Sbostic } 341*47116Sbostic } 342*47116Sbostic if (subtype == VSPLUS) 343*47116Sbostic set = ! set; 344*47116Sbostic if (((flags & VSQUOTE) == 0 || (*var == '@' && shellparam.nparam != 1)) 345*47116Sbostic && (set || subtype == VSNORMAL)) 346*47116Sbostic recordregion(startloc, expdest - stackblock(), flags & VSQUOTE); 347*47116Sbostic if (! set && subtype != VSNORMAL) { 348*47116Sbostic if (subtype == VSPLUS || subtype == VSMINUS) { 349*47116Sbostic argstr(p, full); 350*47116Sbostic } else { 351*47116Sbostic char *startp; 352*47116Sbostic int saveherefd = herefd; 353*47116Sbostic herefd = -1; 354*47116Sbostic argstr(p, 0); 355*47116Sbostic STACKSTRNUL(expdest); 356*47116Sbostic herefd = saveherefd; 357*47116Sbostic startp = stackblock() + startloc; 358*47116Sbostic if (subtype == VSASSIGN) { 359*47116Sbostic setvar(var, startp, 0); 360*47116Sbostic STADJUST(startp - expdest, expdest); 361*47116Sbostic flags &=~ VSNUL; 362*47116Sbostic goto again; 363*47116Sbostic } 364*47116Sbostic /* subtype == VSQUESTION */ 365*47116Sbostic if (*p != CTLENDVAR) { 366*47116Sbostic outfmt(&errout, "%s\n", startp); 367*47116Sbostic error((char *)NULL); 368*47116Sbostic } 369*47116Sbostic error("%.*s: parameter %snot set", p - var - 1, 370*47116Sbostic var, (flags & VSNUL)? "null or " : nullstr); 371*47116Sbostic } 372*47116Sbostic } 373*47116Sbostic if (subtype != VSNORMAL) { /* skip to end of alternative */ 374*47116Sbostic int nesting = 1; 375*47116Sbostic for (;;) { 376*47116Sbostic if ((c = *p++) == CTLESC) 377*47116Sbostic p++; 378*47116Sbostic else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { 379*47116Sbostic if (set) 380*47116Sbostic argbackq = argbackq->next; 381*47116Sbostic } else if (c == CTLVAR) { 382*47116Sbostic if ((*p++ & VSTYPE) != VSNORMAL) 383*47116Sbostic nesting++; 384*47116Sbostic } else if (c == CTLENDVAR) { 385*47116Sbostic if (--nesting == 0) 386*47116Sbostic break; 387*47116Sbostic } 388*47116Sbostic } 389*47116Sbostic } 390*47116Sbostic return p; 391*47116Sbostic } 392*47116Sbostic 393*47116Sbostic 394*47116Sbostic 395*47116Sbostic /* 396*47116Sbostic * Test whether a specialized variable is set. 397*47116Sbostic */ 398*47116Sbostic 399*47116Sbostic STATIC int 400*47116Sbostic varisset(name) 401*47116Sbostic char name; 402*47116Sbostic { 403*47116Sbostic char **ap; 404*47116Sbostic 405*47116Sbostic if (name == '!') { 406*47116Sbostic if (backgndpid == -1) 407*47116Sbostic return 0; 408*47116Sbostic } else if (name == '@' || name == '*') { 409*47116Sbostic if (*shellparam.p == NULL) 410*47116Sbostic return 0; 411*47116Sbostic } else if ((unsigned)(name -= '1') <= '9' - '1') { 412*47116Sbostic ap = shellparam.p; 413*47116Sbostic do { 414*47116Sbostic if (*ap++ == NULL) 415*47116Sbostic return 0; 416*47116Sbostic } while (--name >= 0); 417*47116Sbostic } 418*47116Sbostic return 1; 419*47116Sbostic } 420*47116Sbostic 421*47116Sbostic 422*47116Sbostic 423*47116Sbostic /* 424*47116Sbostic * Add the value of a specialized variable to the stack string. 425*47116Sbostic */ 426*47116Sbostic 427*47116Sbostic STATIC void 428*47116Sbostic varvalue(name, quoted, allow_split) 429*47116Sbostic char name; 430*47116Sbostic { 431*47116Sbostic int num; 432*47116Sbostic char temp[32]; 433*47116Sbostic char *p; 434*47116Sbostic int i; 435*47116Sbostic extern int exitstatus; 436*47116Sbostic char sep; 437*47116Sbostic char **ap; 438*47116Sbostic char const *syntax; 439*47116Sbostic 440*47116Sbostic switch (name) { 441*47116Sbostic case '$': 442*47116Sbostic num = rootpid; 443*47116Sbostic goto numvar; 444*47116Sbostic case '?': 445*47116Sbostic num = exitstatus; 446*47116Sbostic goto numvar; 447*47116Sbostic case '#': 448*47116Sbostic num = shellparam.nparam; 449*47116Sbostic goto numvar; 450*47116Sbostic case '!': 451*47116Sbostic num = backgndpid; 452*47116Sbostic numvar: 453*47116Sbostic p = temp + 31; 454*47116Sbostic temp[31] = '\0'; 455*47116Sbostic do { 456*47116Sbostic *--p = num % 10 + '0'; 457*47116Sbostic } while ((num /= 10) != 0); 458*47116Sbostic while (*p) 459*47116Sbostic STPUTC(*p++, expdest); 460*47116Sbostic break; 461*47116Sbostic case '-': 462*47116Sbostic for (i = 0 ; optchar[i] ; i++) { 463*47116Sbostic if (optval[i]) 464*47116Sbostic STPUTC(optchar[i], expdest); 465*47116Sbostic } 466*47116Sbostic break; 467*47116Sbostic case '@': 468*47116Sbostic if (allow_split) { 469*47116Sbostic sep = '\0'; 470*47116Sbostic goto allargs; 471*47116Sbostic } 472*47116Sbostic /* fall through */ 473*47116Sbostic case '*': 474*47116Sbostic sep = ' '; 475*47116Sbostic allargs: 476*47116Sbostic syntax = quoted? DQSYNTAX : BASESYNTAX; 477*47116Sbostic for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { 478*47116Sbostic /* should insert CTLESC characters */ 479*47116Sbostic while (*p) { 480*47116Sbostic if (syntax[*p] == CCTL) 481*47116Sbostic STPUTC(CTLESC, expdest); 482*47116Sbostic STPUTC(*p++, expdest); 483*47116Sbostic } 484*47116Sbostic if (*ap) 485*47116Sbostic STPUTC(sep, expdest); 486*47116Sbostic } 487*47116Sbostic break; 488*47116Sbostic case '0': 489*47116Sbostic p = arg0; 490*47116Sbostic string: 491*47116Sbostic syntax = quoted? DQSYNTAX : BASESYNTAX; 492*47116Sbostic while (*p) { 493*47116Sbostic if (syntax[*p] == CCTL) 494*47116Sbostic STPUTC(CTLESC, expdest); 495*47116Sbostic STPUTC(*p++, expdest); 496*47116Sbostic } 497*47116Sbostic break; 498*47116Sbostic default: 499*47116Sbostic if ((unsigned)(name -= '1') <= '9' - '1') { 500*47116Sbostic p = shellparam.p[name]; 501*47116Sbostic goto string; 502*47116Sbostic } 503*47116Sbostic break; 504*47116Sbostic } 505*47116Sbostic } 506*47116Sbostic 507*47116Sbostic 508*47116Sbostic 509*47116Sbostic /* 510*47116Sbostic * Record the the fact that we have to scan this region of the 511*47116Sbostic * string for IFS characters. 512*47116Sbostic */ 513*47116Sbostic 514*47116Sbostic STATIC void 515*47116Sbostic recordregion(start, end, nulonly) { 516*47116Sbostic register struct ifsregion *ifsp; 517*47116Sbostic 518*47116Sbostic if (ifslastp == NULL) { 519*47116Sbostic ifsp = &ifsfirst; 520*47116Sbostic } else { 521*47116Sbostic ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion)); 522*47116Sbostic ifslastp->next = ifsp; 523*47116Sbostic } 524*47116Sbostic ifslastp = ifsp; 525*47116Sbostic ifslastp->next = NULL; 526*47116Sbostic ifslastp->begoff = start; 527*47116Sbostic ifslastp->endoff = end; 528*47116Sbostic ifslastp->nulonly = nulonly; 529*47116Sbostic } 530*47116Sbostic 531*47116Sbostic 532*47116Sbostic 533*47116Sbostic /* 534*47116Sbostic * Break the argument string into pieces based upon IFS and add the 535*47116Sbostic * strings to the argument list. The regions of the string to be 536*47116Sbostic * searched for IFS characters have been stored by recordregion. 537*47116Sbostic */ 538*47116Sbostic 539*47116Sbostic STATIC void 540*47116Sbostic ifsbreakup(string, arglist) 541*47116Sbostic char *string; 542*47116Sbostic struct arglist *arglist; 543*47116Sbostic { 544*47116Sbostic struct ifsregion *ifsp; 545*47116Sbostic struct strlist *sp; 546*47116Sbostic char *start; 547*47116Sbostic register char *p; 548*47116Sbostic char *q; 549*47116Sbostic char *ifs; 550*47116Sbostic 551*47116Sbostic start = string; 552*47116Sbostic if (ifslastp != NULL) { 553*47116Sbostic ifsp = &ifsfirst; 554*47116Sbostic do { 555*47116Sbostic p = string + ifsp->begoff; 556*47116Sbostic ifs = ifsp->nulonly? nullstr : ifsval(); 557*47116Sbostic while (p < string + ifsp->endoff) { 558*47116Sbostic q = p; 559*47116Sbostic if (*p == CTLESC) 560*47116Sbostic p++; 561*47116Sbostic if (strchr(ifs, *p++)) { 562*47116Sbostic if (q > start || *ifs != ' ') { 563*47116Sbostic *q = '\0'; 564*47116Sbostic sp = (struct strlist *)stalloc(sizeof *sp); 565*47116Sbostic sp->text = start; 566*47116Sbostic *arglist->lastp = sp; 567*47116Sbostic arglist->lastp = &sp->next; 568*47116Sbostic } 569*47116Sbostic if (*ifs == ' ') { 570*47116Sbostic for (;;) { 571*47116Sbostic if (p >= string + ifsp->endoff) 572*47116Sbostic break; 573*47116Sbostic q = p; 574*47116Sbostic if (*p == CTLESC) 575*47116Sbostic p++; 576*47116Sbostic if (strchr(ifs, *p++) == NULL) { 577*47116Sbostic p = q; 578*47116Sbostic break; 579*47116Sbostic } 580*47116Sbostic } 581*47116Sbostic } 582*47116Sbostic start = p; 583*47116Sbostic } 584*47116Sbostic } 585*47116Sbostic } while ((ifsp = ifsp->next) != NULL); 586*47116Sbostic if (*start || (*ifs != ' ' && start > string)) { 587*47116Sbostic sp = (struct strlist *)stalloc(sizeof *sp); 588*47116Sbostic sp->text = start; 589*47116Sbostic *arglist->lastp = sp; 590*47116Sbostic arglist->lastp = &sp->next; 591*47116Sbostic } 592*47116Sbostic } else { 593*47116Sbostic sp = (struct strlist *)stalloc(sizeof *sp); 594*47116Sbostic sp->text = start; 595*47116Sbostic *arglist->lastp = sp; 596*47116Sbostic arglist->lastp = &sp->next; 597*47116Sbostic } 598*47116Sbostic } 599*47116Sbostic 600*47116Sbostic 601*47116Sbostic 602*47116Sbostic /* 603*47116Sbostic * Expand shell metacharacters. At this point, the only control characters 604*47116Sbostic * should be escapes. The results are stored in the list exparg. 605*47116Sbostic */ 606*47116Sbostic 607*47116Sbostic char *expdir; 608*47116Sbostic 609*47116Sbostic 610*47116Sbostic STATIC void 611*47116Sbostic expandmeta(str) 612*47116Sbostic struct strlist *str; 613*47116Sbostic { 614*47116Sbostic char *p; 615*47116Sbostic struct strlist **savelastp; 616*47116Sbostic struct strlist *sp; 617*47116Sbostic char c; 618*47116Sbostic 619*47116Sbostic while (str) { 620*47116Sbostic if (fflag) 621*47116Sbostic goto nometa; 622*47116Sbostic p = str->text; 623*47116Sbostic #if UDIR 624*47116Sbostic if (p[0] == '/' && p[1] == 'u' && p[2] == '/') 625*47116Sbostic str->text = p = expudir(p); 626*47116Sbostic #endif 627*47116Sbostic for (;;) { /* fast check for meta chars */ 628*47116Sbostic if ((c = *p++) == '\0') 629*47116Sbostic goto nometa; 630*47116Sbostic if (c == '*' || c == '?' || c == '[' || c == '!') 631*47116Sbostic break; 632*47116Sbostic } 633*47116Sbostic savelastp = exparg.lastp; 634*47116Sbostic INTOFF; 635*47116Sbostic if (expdir == NULL) 636*47116Sbostic expdir = ckmalloc(1024); /* I hope this is big enough */ 637*47116Sbostic expmeta(expdir, str->text); 638*47116Sbostic ckfree(expdir); 639*47116Sbostic expdir = NULL; 640*47116Sbostic INTON; 641*47116Sbostic if (exparg.lastp == savelastp) { 642*47116Sbostic if (! zflag) { 643*47116Sbostic nometa: 644*47116Sbostic *exparg.lastp = str; 645*47116Sbostic rmescapes(str->text); 646*47116Sbostic exparg.lastp = &str->next; 647*47116Sbostic } 648*47116Sbostic } else { 649*47116Sbostic *exparg.lastp = NULL; 650*47116Sbostic *savelastp = sp = expsort(*savelastp); 651*47116Sbostic while (sp->next != NULL) 652*47116Sbostic sp = sp->next; 653*47116Sbostic exparg.lastp = &sp->next; 654*47116Sbostic } 655*47116Sbostic str = str->next; 656*47116Sbostic } 657*47116Sbostic } 658*47116Sbostic 659*47116Sbostic 660*47116Sbostic #if UDIR 661*47116Sbostic /* 662*47116Sbostic * Expand /u/username into the home directory for the specified user. 663*47116Sbostic * We could use the getpw stuff here, but then we would have to load 664*47116Sbostic * in stdio and who knows what else. 665*47116Sbostic */ 666*47116Sbostic 667*47116Sbostic #define MAXLOGNAME 32 668*47116Sbostic #define MAXPWLINE 128 669*47116Sbostic 670*47116Sbostic char *pfgets(); 671*47116Sbostic 672*47116Sbostic 673*47116Sbostic STATIC char * 674*47116Sbostic expudir(path) 675*47116Sbostic char *path; 676*47116Sbostic { 677*47116Sbostic register char *p, *q, *r; 678*47116Sbostic char name[MAXLOGNAME]; 679*47116Sbostic char line[MAXPWLINE]; 680*47116Sbostic int i; 681*47116Sbostic 682*47116Sbostic r = path; /* result on failure */ 683*47116Sbostic p = r + 3; /* the 3 skips "/u/" */ 684*47116Sbostic q = name; 685*47116Sbostic while (*p && *p != '/') { 686*47116Sbostic if (q >= name + MAXLOGNAME - 1) 687*47116Sbostic return r; /* fail, name too long */ 688*47116Sbostic *q++ = *p++; 689*47116Sbostic } 690*47116Sbostic *q = '\0'; 691*47116Sbostic setinputfile("/etc/passwd", 1); 692*47116Sbostic q = line + strlen(name); 693*47116Sbostic while (pfgets(line, MAXPWLINE) != NULL) { 694*47116Sbostic if (line[0] == name[0] && prefix(name, line) && *q == ':') { 695*47116Sbostic /* skip to start of home directory */ 696*47116Sbostic i = 4; 697*47116Sbostic do { 698*47116Sbostic while (*++q && *q != ':'); 699*47116Sbostic } while (--i > 0); 700*47116Sbostic if (*q == '\0') 701*47116Sbostic break; /* fail, corrupted /etc/passwd */ 702*47116Sbostic q++; 703*47116Sbostic for (r = q ; *r && *r != '\n' && *r != ':' ; r++); 704*47116Sbostic *r = '\0'; /* nul terminate home directory */ 705*47116Sbostic i = r - q; /* i = strlen(q) */ 706*47116Sbostic r = stalloc(i + strlen(p) + 1); 707*47116Sbostic scopy(q, r); 708*47116Sbostic scopy(p, r + i); 709*47116Sbostic TRACE(("expudir converts %s to %s\n", path, r)); 710*47116Sbostic didudir = 1; 711*47116Sbostic path = r; /* succeed */ 712*47116Sbostic break; 713*47116Sbostic } 714*47116Sbostic } 715*47116Sbostic popfile(); 716*47116Sbostic return r; 717*47116Sbostic } 718*47116Sbostic #endif 719*47116Sbostic 720*47116Sbostic 721*47116Sbostic /* 722*47116Sbostic * Do metacharacter (i.e. *, ?, [...]) expansion. 723*47116Sbostic */ 724*47116Sbostic 725*47116Sbostic STATIC void 726*47116Sbostic expmeta(enddir, name) 727*47116Sbostic char *enddir; 728*47116Sbostic char *name; 729*47116Sbostic { 730*47116Sbostic register char *p; 731*47116Sbostic char *q; 732*47116Sbostic char *start; 733*47116Sbostic char *endname; 734*47116Sbostic int metaflag; 735*47116Sbostic struct stat statb; 736*47116Sbostic DIR *dirp; 737*47116Sbostic struct dirent *dp; 738*47116Sbostic int atend; 739*47116Sbostic int matchdot; 740*47116Sbostic 741*47116Sbostic metaflag = 0; 742*47116Sbostic start = name; 743*47116Sbostic for (p = name ; ; p++) { 744*47116Sbostic if (*p == '*' || *p == '?') 745*47116Sbostic metaflag = 1; 746*47116Sbostic else if (*p == '[') { 747*47116Sbostic q = p + 1; 748*47116Sbostic if (*q == '!') 749*47116Sbostic q++; 750*47116Sbostic for (;;) { 751*47116Sbostic if (*q == CTLESC) 752*47116Sbostic q++; 753*47116Sbostic if (*q == '/' || *q == '\0') 754*47116Sbostic break; 755*47116Sbostic if (*++q == ']') { 756*47116Sbostic metaflag = 1; 757*47116Sbostic break; 758*47116Sbostic } 759*47116Sbostic } 760*47116Sbostic } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) { 761*47116Sbostic metaflag = 1; 762*47116Sbostic } else if (*p == '\0') 763*47116Sbostic break; 764*47116Sbostic else if (*p == CTLESC) 765*47116Sbostic p++; 766*47116Sbostic if (*p == '/') { 767*47116Sbostic if (metaflag) 768*47116Sbostic break; 769*47116Sbostic start = p + 1; 770*47116Sbostic } 771*47116Sbostic } 772*47116Sbostic if (metaflag == 0) { /* we've reached the end of the file name */ 773*47116Sbostic if (enddir != expdir) 774*47116Sbostic metaflag++; 775*47116Sbostic for (p = name ; ; p++) { 776*47116Sbostic if (*p == CTLESC) 777*47116Sbostic p++; 778*47116Sbostic *enddir++ = *p; 779*47116Sbostic if (*p == '\0') 780*47116Sbostic break; 781*47116Sbostic } 782*47116Sbostic if (metaflag == 0 || stat(expdir, &statb) >= 0) 783*47116Sbostic addfname(expdir); 784*47116Sbostic return; 785*47116Sbostic } 786*47116Sbostic endname = p; 787*47116Sbostic if (start != name) { 788*47116Sbostic p = name; 789*47116Sbostic while (p < start) { 790*47116Sbostic if (*p == CTLESC) 791*47116Sbostic p++; 792*47116Sbostic *enddir++ = *p++; 793*47116Sbostic } 794*47116Sbostic } 795*47116Sbostic if (enddir == expdir) { 796*47116Sbostic p = "."; 797*47116Sbostic } else if (enddir == expdir + 1 && *expdir == '/') { 798*47116Sbostic p = "/"; 799*47116Sbostic } else { 800*47116Sbostic p = expdir; 801*47116Sbostic enddir[-1] = '\0'; 802*47116Sbostic } 803*47116Sbostic if ((dirp = opendir(p)) == NULL) 804*47116Sbostic return; 805*47116Sbostic if (enddir != expdir) 806*47116Sbostic enddir[-1] = '/'; 807*47116Sbostic if (*endname == 0) { 808*47116Sbostic atend = 1; 809*47116Sbostic } else { 810*47116Sbostic atend = 0; 811*47116Sbostic *endname++ = '\0'; 812*47116Sbostic } 813*47116Sbostic matchdot = 0; 814*47116Sbostic if (start[0] == '.' || start[0] == CTLESC && start[1] == '.') 815*47116Sbostic matchdot++; 816*47116Sbostic while (! int_pending() && (dp = readdir(dirp)) != NULL) { 817*47116Sbostic if (dp->d_name[0] == '.' && ! matchdot) 818*47116Sbostic continue; 819*47116Sbostic if (patmatch(start, dp->d_name)) { 820*47116Sbostic if (atend) { 821*47116Sbostic scopy(dp->d_name, enddir); 822*47116Sbostic addfname(expdir); 823*47116Sbostic } else { 824*47116Sbostic char *q; 825*47116Sbostic for (p = enddir, q = dp->d_name ; *p++ = *q++ ;); 826*47116Sbostic p[-1] = '/'; 827*47116Sbostic expmeta(p, endname); 828*47116Sbostic } 829*47116Sbostic } 830*47116Sbostic } 831*47116Sbostic closedir(dirp); 832*47116Sbostic if (! atend) 833*47116Sbostic endname[-1] = '/'; 834*47116Sbostic } 835*47116Sbostic 836*47116Sbostic 837*47116Sbostic /* 838*47116Sbostic * Add a file name to the list. 839*47116Sbostic */ 840*47116Sbostic 841*47116Sbostic STATIC void 842*47116Sbostic addfname(name) 843*47116Sbostic char *name; 844*47116Sbostic { 845*47116Sbostic char *p; 846*47116Sbostic struct strlist *sp; 847*47116Sbostic 848*47116Sbostic p = stalloc(strlen(name) + 1); 849*47116Sbostic scopy(name, p); 850*47116Sbostic sp = (struct strlist *)stalloc(sizeof *sp); 851*47116Sbostic sp->text = p; 852*47116Sbostic *exparg.lastp = sp; 853*47116Sbostic exparg.lastp = &sp->next; 854*47116Sbostic } 855*47116Sbostic 856*47116Sbostic 857*47116Sbostic /* 858*47116Sbostic * Sort the results of file name expansion. It calculates the number of 859*47116Sbostic * strings to sort and then calls msort (short for merge sort) to do the 860*47116Sbostic * work. 861*47116Sbostic */ 862*47116Sbostic 863*47116Sbostic STATIC struct strlist * 864*47116Sbostic expsort(str) 865*47116Sbostic struct strlist *str; 866*47116Sbostic { 867*47116Sbostic int len; 868*47116Sbostic struct strlist *sp; 869*47116Sbostic 870*47116Sbostic len = 0; 871*47116Sbostic for (sp = str ; sp ; sp = sp->next) 872*47116Sbostic len++; 873*47116Sbostic return msort(str, len); 874*47116Sbostic } 875*47116Sbostic 876*47116Sbostic 877*47116Sbostic STATIC struct strlist * 878*47116Sbostic msort(list, len) 879*47116Sbostic struct strlist *list; 880*47116Sbostic { 881*47116Sbostic struct strlist *p, *q; 882*47116Sbostic struct strlist **lpp; 883*47116Sbostic int half; 884*47116Sbostic int n; 885*47116Sbostic 886*47116Sbostic if (len <= 1) 887*47116Sbostic return list; 888*47116Sbostic half = len >> 1; 889*47116Sbostic p = list; 890*47116Sbostic for (n = half ; --n >= 0 ; ) { 891*47116Sbostic q = p; 892*47116Sbostic p = p->next; 893*47116Sbostic } 894*47116Sbostic q->next = NULL; /* terminate first half of list */ 895*47116Sbostic q = msort(list, half); /* sort first half of list */ 896*47116Sbostic p = msort(p, len - half); /* sort second half */ 897*47116Sbostic lpp = &list; 898*47116Sbostic for (;;) { 899*47116Sbostic if (strcmp(p->text, q->text) < 0) { 900*47116Sbostic *lpp = p; 901*47116Sbostic lpp = &p->next; 902*47116Sbostic if ((p = *lpp) == NULL) { 903*47116Sbostic *lpp = q; 904*47116Sbostic break; 905*47116Sbostic } 906*47116Sbostic } else { 907*47116Sbostic *lpp = q; 908*47116Sbostic lpp = &q->next; 909*47116Sbostic if ((q = *lpp) == NULL) { 910*47116Sbostic *lpp = p; 911*47116Sbostic break; 912*47116Sbostic } 913*47116Sbostic } 914*47116Sbostic } 915*47116Sbostic return list; 916*47116Sbostic } 917*47116Sbostic 918*47116Sbostic 919*47116Sbostic 920*47116Sbostic /* 921*47116Sbostic * Returns true if the pattern matches the string. 922*47116Sbostic */ 923*47116Sbostic 924*47116Sbostic int 925*47116Sbostic patmatch(pattern, string) 926*47116Sbostic char *pattern; 927*47116Sbostic char *string; 928*47116Sbostic { 929*47116Sbostic if (pattern[0] == '!' && pattern[1] == '!') 930*47116Sbostic return 1 - pmatch(pattern + 2, string); 931*47116Sbostic else 932*47116Sbostic return pmatch(pattern, string); 933*47116Sbostic } 934*47116Sbostic 935*47116Sbostic 936*47116Sbostic STATIC int 937*47116Sbostic pmatch(pattern, string) 938*47116Sbostic char *pattern; 939*47116Sbostic char *string; 940*47116Sbostic { 941*47116Sbostic register char *p, *q; 942*47116Sbostic register char c; 943*47116Sbostic 944*47116Sbostic p = pattern; 945*47116Sbostic q = string; 946*47116Sbostic for (;;) { 947*47116Sbostic switch (c = *p++) { 948*47116Sbostic case '\0': 949*47116Sbostic goto breakloop; 950*47116Sbostic case CTLESC: 951*47116Sbostic if (*q++ != *p++) 952*47116Sbostic return 0; 953*47116Sbostic break; 954*47116Sbostic case '?': 955*47116Sbostic if (*q++ == '\0') 956*47116Sbostic return 0; 957*47116Sbostic break; 958*47116Sbostic case '*': 959*47116Sbostic c = *p; 960*47116Sbostic if (c != CTLESC && c != '?' && c != '*' && c != '[') { 961*47116Sbostic while (*q != c) { 962*47116Sbostic if (*q == '\0') 963*47116Sbostic return 0; 964*47116Sbostic q++; 965*47116Sbostic } 966*47116Sbostic } 967*47116Sbostic do { 968*47116Sbostic if (pmatch(p, q)) 969*47116Sbostic return 1; 970*47116Sbostic } while (*q++ != '\0'); 971*47116Sbostic return 0; 972*47116Sbostic case '[': { 973*47116Sbostic char *endp; 974*47116Sbostic int invert, found; 975*47116Sbostic char chr; 976*47116Sbostic 977*47116Sbostic endp = p; 978*47116Sbostic if (*endp == '!') 979*47116Sbostic endp++; 980*47116Sbostic for (;;) { 981*47116Sbostic if (*endp == '\0') 982*47116Sbostic goto dft; /* no matching ] */ 983*47116Sbostic if (*endp == CTLESC) 984*47116Sbostic endp++; 985*47116Sbostic if (*++endp == ']') 986*47116Sbostic break; 987*47116Sbostic } 988*47116Sbostic invert = 0; 989*47116Sbostic if (*p == '!') { 990*47116Sbostic invert++; 991*47116Sbostic p++; 992*47116Sbostic } 993*47116Sbostic found = 0; 994*47116Sbostic chr = *q++; 995*47116Sbostic c = *p++; 996*47116Sbostic do { 997*47116Sbostic if (c == CTLESC) 998*47116Sbostic c = *p++; 999*47116Sbostic if (*p == '-' && p[1] != ']') { 1000*47116Sbostic p++; 1001*47116Sbostic if (*p == CTLESC) 1002*47116Sbostic p++; 1003*47116Sbostic if (chr >= c && chr <= *p) 1004*47116Sbostic found = 1; 1005*47116Sbostic p++; 1006*47116Sbostic } else { 1007*47116Sbostic if (chr == c) 1008*47116Sbostic found = 1; 1009*47116Sbostic } 1010*47116Sbostic } while ((c = *p++) != ']'); 1011*47116Sbostic if (found == invert) 1012*47116Sbostic return 0; 1013*47116Sbostic break; 1014*47116Sbostic } 1015*47116Sbostic dft: default: 1016*47116Sbostic if (*q++ != c) 1017*47116Sbostic return 0; 1018*47116Sbostic break; 1019*47116Sbostic } 1020*47116Sbostic } 1021*47116Sbostic breakloop: 1022*47116Sbostic if (*q != '\0') 1023*47116Sbostic return 0; 1024*47116Sbostic return 1; 1025*47116Sbostic } 1026*47116Sbostic 1027*47116Sbostic 1028*47116Sbostic 1029*47116Sbostic /* 1030*47116Sbostic * Remove any CTLESC characters from a string. 1031*47116Sbostic */ 1032*47116Sbostic 1033*47116Sbostic void 1034*47116Sbostic rmescapes(str) 1035*47116Sbostic char *str; 1036*47116Sbostic { 1037*47116Sbostic register char *p, *q; 1038*47116Sbostic 1039*47116Sbostic p = str; 1040*47116Sbostic while (*p != CTLESC) { 1041*47116Sbostic if (*p++ == '\0') 1042*47116Sbostic return; 1043*47116Sbostic } 1044*47116Sbostic q = p; 1045*47116Sbostic while (*p) { 1046*47116Sbostic if (*p == CTLESC) 1047*47116Sbostic p++; 1048*47116Sbostic *q++ = *p++; 1049*47116Sbostic } 1050*47116Sbostic *q = '\0'; 1051*47116Sbostic } 1052*47116Sbostic 1053*47116Sbostic 1054*47116Sbostic 1055*47116Sbostic /* 1056*47116Sbostic * See if a pattern matches in a case statement. 1057*47116Sbostic */ 1058*47116Sbostic 1059*47116Sbostic int 1060*47116Sbostic casematch(pattern, val) 1061*47116Sbostic union node *pattern; 1062*47116Sbostic char *val; 1063*47116Sbostic { 1064*47116Sbostic struct stackmark smark; 1065*47116Sbostic int result; 1066*47116Sbostic char *p; 1067*47116Sbostic 1068*47116Sbostic setstackmark(&smark); 1069*47116Sbostic argbackq = pattern->narg.backquote; 1070*47116Sbostic STARTSTACKSTR(expdest); 1071*47116Sbostic ifslastp = NULL; 1072*47116Sbostic argstr(pattern->narg.text, 0); 1073*47116Sbostic STPUTC('\0', expdest); 1074*47116Sbostic p = grabstackstr(expdest); 1075*47116Sbostic result = patmatch(p, val); 1076*47116Sbostic popstackmark(&smark); 1077*47116Sbostic return result; 1078*47116Sbostic } 1079