00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #ifndef lint
00038 static char sccsid[] = "@(#)expand.c 5.1 (Berkeley) 3/7/91";
00039 #endif
00040
00041
00042
00043
00044
00045
00046 #include "shell.h"
00047 #include "main.h"
00048 #include "nodes.h"
00049 #include "eval.h"
00050 #include "expand.h"
00051 #include "syntax.h"
00052 #include "parser.h"
00053 #include "jobs.h"
00054 #include "options.h"
00055 #include "var.h"
00056 #include "input.h"
00057 #include "output.h"
00058 #include "memalloc.h"
00059 #include "error.h"
00060 #include "mystring.h"
00061 #include <sys/types.h>
00062 #include <sys/stat.h>
00063 #include <errno.h>
00064 #include <dirent.h>
00065 #if USEGETPW
00066 #include <pwd.h>
00067 #endif
00068
00069
00070
00071
00072
00073
00074 struct ifsregion {
00075 struct ifsregion *next;
00076 int begoff;
00077 int endoff;
00078 int nulonly;
00079 };
00080
00081
00082 char *expdest;
00083 struct nodelist *argbackq;
00084 struct ifsregion ifsfirst;
00085 struct ifsregion *ifslastp;
00086 struct arglist exparg;
00087 #if UDIR || TILDE
00088
00089
00090
00091
00092 int didudir;
00093 #endif
00094
00095 #ifdef __STDC__
00096 STATIC void argstr(char *, int);
00097 STATIC void expbackq(union node *, int, int);
00098 STATIC char *evalvar(char *, int);
00099 STATIC int varisset(int);
00100 STATIC void varvalue(int, int, int);
00101 STATIC void recordregion(int, int, int);
00102 STATIC void ifsbreakup(char *, struct arglist *);
00103 STATIC void expandmeta(struct strlist *);
00104 STATIC void expmeta(char *, char *);
00105 STATIC void addfname(char *);
00106 STATIC struct strlist *expsort(struct strlist *);
00107 STATIC struct strlist *msort(struct strlist *, int);
00108 STATIC int pmatch(char *, char *);
00109 #else
00110 STATIC void argstr();
00111 STATIC void expbackq();
00112 STATIC char *evalvar();
00113 STATIC int varisset();
00114 STATIC void varvalue();
00115 STATIC void recordregion();
00116 STATIC void ifsbreakup();
00117 STATIC void expandmeta();
00118 STATIC void expmeta();
00119 STATIC void addfname();
00120 STATIC struct strlist *expsort();
00121 STATIC struct strlist *msort();
00122 STATIC int pmatch();
00123 #endif
00124 #if UDIR || TILDE
00125 #ifdef __STDC__
00126 STATIC char *expudir(char *);
00127 #else
00128 STATIC char *expudir();
00129 #endif
00130 #endif
00131
00132
00133
00134
00135
00136
00137
00138 void
00139 expandhere(arg, fd)
00140 union node *arg;
00141 int fd;
00142 {
00143 herefd = fd;
00144 expandarg(arg, (struct arglist *)NULL, 0);
00145 xwrite(fd, stackblock(), expdest - stackblock());
00146 }
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156 void
00157 expandarg(arg, arglist, full)
00158 union node *arg;
00159 struct arglist *arglist;
00160 {
00161 struct strlist *sp;
00162 char *p;
00163
00164 #if UDIR || TILDE
00165 didudir = 0;
00166 #endif
00167 argbackq = arg->narg.backquote;
00168 STARTSTACKSTR(expdest);
00169 ifsfirst.next = NULL;
00170 ifslastp = NULL;
00171 argstr(arg->narg.text, full);
00172 if (arglist == NULL)
00173 return;
00174 STPUTC('\0', expdest);
00175 p = grabstackstr(expdest);
00176 exparg.lastp = &exparg.list;
00177 if (full) {
00178 ifsbreakup(p, &exparg);
00179 *exparg.lastp = NULL;
00180 exparg.lastp = &exparg.list;
00181 expandmeta(exparg.list);
00182 } else {
00183 sp = (struct strlist *)stalloc(sizeof (struct strlist));
00184 sp->text = p;
00185 *exparg.lastp = sp;
00186 exparg.lastp = &sp->next;
00187 }
00188 while (ifsfirst.next != NULL) {
00189 struct ifsregion *ifsp;
00190 INTOFF;
00191 ifsp = ifsfirst.next->next;
00192 ckfree(ifsfirst.next);
00193 ifsfirst.next = ifsp;
00194 INTON;
00195 }
00196 *exparg.lastp = NULL;
00197 if (exparg.list) {
00198 *arglist->lastp = exparg.list;
00199 arglist->lastp = exparg.lastp;
00200 }
00201 }
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211 STATIC void
00212 argstr(p, full)
00213 register char *p;
00214 {
00215 char c;
00216
00217 for (;;) {
00218 switch (c = *p++) {
00219 case '\0':
00220 case CTLENDVAR:
00221 goto breakloop;
00222 case CTLESC:
00223 if (full)
00224 STPUTC(c, expdest);
00225 c = *p++;
00226 STPUTC(c, expdest);
00227 break;
00228 case CTLVAR:
00229 p = evalvar(p, full);
00230 break;
00231 case CTLBACKQ:
00232 case CTLBACKQ|CTLQUOTE:
00233 expbackq(argbackq->n, c & CTLQUOTE, full);
00234 argbackq = argbackq->next;
00235 break;
00236 default:
00237 STPUTC(c, expdest);
00238 }
00239 }
00240 breakloop:;
00241 }
00242
00243
00244
00245
00246
00247
00248 STATIC void
00249 expbackq(cmd, quoted, full)
00250 union node *cmd;
00251 {
00252 struct backcmd in;
00253 int i;
00254 char buf[128];
00255 char *p;
00256 char *dest = expdest;
00257 struct ifsregion saveifs, *savelastp;
00258 struct nodelist *saveargbackq;
00259 char lastc;
00260 int startloc = dest - stackblock();
00261 char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
00262 int saveherefd;
00263
00264 INTOFF;
00265 saveifs = ifsfirst;
00266 savelastp = ifslastp;
00267 saveargbackq = argbackq;
00268 saveherefd = herefd;
00269 herefd = -1;
00270 p = grabstackstr(dest);
00271 evalbackcmd(cmd, &in);
00272 ungrabstackstr(p, dest);
00273 ifsfirst = saveifs;
00274 ifslastp = savelastp;
00275 argbackq = saveargbackq;
00276 herefd = saveherefd;
00277
00278 p = in.buf;
00279 lastc = '\0';
00280 for (;;) {
00281 if (--in.nleft < 0) {
00282 if (in.fd < 0)
00283 break;
00284 while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
00285 TRACE(("expbackq: read returns %d\n", i));
00286 if (i <= 0)
00287 break;
00288 p = buf;
00289 in.nleft = i - 1;
00290 }
00291 lastc = *p++;
00292 if (lastc != '\0') {
00293 if (full && syntax[lastc] == CCTL)
00294 STPUTC(CTLESC, dest);
00295 STPUTC(lastc, dest);
00296 }
00297 }
00298 if (lastc == '\n') {
00299 STUNPUTC(dest);
00300 }
00301 if (in.fd >= 0)
00302 close(in.fd);
00303 if (in.buf)
00304 ckfree(in.buf);
00305 if (in.jp)
00306 exitstatus = waitforjob(in.jp);
00307 if (quoted == 0)
00308 recordregion(startloc, dest - stackblock(), 0);
00309 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
00310 (dest - stackblock()) - startloc,
00311 (dest - stackblock()) - startloc,
00312 stackblock() + startloc));
00313 expdest = dest;
00314 INTON;
00315 }
00316
00317
00318
00319
00320
00321
00322
00323
00324 STATIC char *
00325 evalvar(p, full)
00326 char *p;
00327 {
00328 int subtype;
00329 int flags;
00330 char *var;
00331 char *val;
00332 int c;
00333 int set;
00334 int special;
00335 int startloc;
00336
00337 flags = *p++;
00338 subtype = flags & VSTYPE;
00339 var = p;
00340 special = 0;
00341 if (! is_name(*p))
00342 special = 1;
00343 p = strchr(p, '=') + 1;
00344 again:
00345 if (special) {
00346 set = varisset(*var);
00347 val = NULL;
00348 } else {
00349 val = lookupvar(var);
00350 if (val == NULL || (flags & VSNUL) && val[0] == '\0') {
00351 val = NULL;
00352 set = 0;
00353 } else
00354 set = 1;
00355 }
00356 startloc = expdest - stackblock();
00357 if (set && subtype != VSPLUS) {
00358
00359 if (special) {
00360 varvalue(*var, flags & VSQUOTE, full);
00361 } else {
00362 char const *syntax = (flags & VSQUOTE)? DQSYNTAX : BASESYNTAX;
00363
00364 while (*val) {
00365 if (full && syntax[*val] == CCTL)
00366 STPUTC(CTLESC, expdest);
00367 STPUTC(*val++, expdest);
00368 }
00369 }
00370 }
00371 if (subtype == VSPLUS)
00372 set = ! set;
00373 if (((flags & VSQUOTE) == 0 || (*var == '@' && shellparam.nparam != 1))
00374 && (set || subtype == VSNORMAL))
00375 recordregion(startloc, expdest - stackblock(), flags & VSQUOTE);
00376 if (! set && subtype != VSNORMAL) {
00377 if (subtype == VSPLUS || subtype == VSMINUS) {
00378 argstr(p, full);
00379 } else {
00380 char *startp;
00381 int saveherefd = herefd;
00382 herefd = -1;
00383 argstr(p, 0);
00384 STACKSTRNUL(expdest);
00385 herefd = saveherefd;
00386 startp = stackblock() + startloc;
00387 if (subtype == VSASSIGN) {
00388 setvar(var, startp, 0);
00389 STADJUST(startp - expdest, expdest);
00390 flags &=~ VSNUL;
00391 goto again;
00392 }
00393
00394 if (*p != CTLENDVAR) {
00395 outfmt(&errout, "%s\n", startp);
00396 error((char *)NULL);
00397 }
00398 error("%.*s: parameter %snot set", p - var - 1,
00399 var, (flags & VSNUL)? "null or " : nullstr);
00400 }
00401 }
00402 if (subtype != VSNORMAL) {
00403 int nesting = 1;
00404 for (;;) {
00405 if ((c = *p++) == CTLESC)
00406 p++;
00407 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
00408 if (set) {
00409 if (argbackq != NULL)
00410 argbackq = argbackq->next;
00411 }
00412 } else if (c == CTLVAR) {
00413 if ((*p++ & VSTYPE) != VSNORMAL)
00414 nesting++;
00415 } else if (c == CTLENDVAR) {
00416 if (--nesting == 0)
00417 break;
00418 }
00419 }
00420 }
00421 return p;
00422 }
00423
00424
00425
00426
00427
00428
00429
00430 STATIC int
00431 varisset(name)
00432 char name;
00433 {
00434 char **ap;
00435
00436 if (name == '!') {
00437 if (backgndpid == -1)
00438 return 0;
00439 } else if (name == '@' || name == '*') {
00440 if (*shellparam.p == NULL)
00441 return 0;
00442 } else if ((unsigned)(name -= '1') <= '9' - '1') {
00443 ap = shellparam.p;
00444 do {
00445 if (*ap++ == NULL)
00446 return 0;
00447 } while (--name >= 0);
00448 }
00449 return 1;
00450 }
00451
00452
00453
00454
00455
00456
00457
00458 STATIC void
00459 varvalue(name, quoted, allow_split)
00460 char name;
00461 {
00462 int num;
00463 char temp[32];
00464 char *p;
00465 int i;
00466 extern int oexitstatus;
00467 char sep;
00468 char **ap;
00469 char const *syntax;
00470
00471 switch (name) {
00472 case '$':
00473 num = rootpid;
00474 goto numvar;
00475 case '?':
00476 num = oexitstatus;
00477 goto numvar;
00478 case '#':
00479 num = shellparam.nparam;
00480 goto numvar;
00481 case '!':
00482 num = backgndpid;
00483 numvar:
00484 p = temp + 31;
00485 temp[31] = '\0';
00486 do {
00487 *--p = num % 10 + '0';
00488 } while ((num /= 10) != 0);
00489 while (*p)
00490 STPUTC(*p++, expdest);
00491 break;
00492 case '-':
00493 for (i = 0 ; optchar[i] ; i++) {
00494 if (optval[i])
00495 STPUTC(optchar[i], expdest);
00496 }
00497 break;
00498 case '@':
00499 if (allow_split) {
00500 sep = '\0';
00501 goto allargs;
00502 }
00503
00504 case '*':
00505 sep = ' ';
00506 allargs:
00507
00508
00509 syntax = quoted && allow_split ? DQSYNTAX : BASESYNTAX;
00510 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
00511
00512 while (*p) {
00513 if (syntax[*p] == CCTL)
00514 STPUTC(CTLESC, expdest);
00515 STPUTC(*p++, expdest);
00516 }
00517 if (*ap)
00518 STPUTC(sep, expdest);
00519 }
00520 break;
00521 case '0':
00522 p = arg0;
00523 string:
00524
00525
00526 syntax = quoted && allow_split ? DQSYNTAX : BASESYNTAX;
00527 while (*p) {
00528 if (syntax[*p] == CCTL)
00529 STPUTC(CTLESC, expdest);
00530 STPUTC(*p++, expdest);
00531 }
00532 break;
00533 default:
00534 if ((unsigned)(name -= '1') <= '9' - '1') {
00535 p = shellparam.p[name];
00536 goto string;
00537 }
00538 break;
00539 }
00540 }
00541
00542
00543
00544
00545
00546
00547
00548
00549 STATIC void
00550 recordregion(start, end, nulonly) {
00551 register struct ifsregion *ifsp;
00552
00553 if (ifslastp == NULL) {
00554 ifsp = &ifsfirst;
00555 } else {
00556 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
00557 ifslastp->next = ifsp;
00558 }
00559 ifslastp = ifsp;
00560 ifslastp->next = NULL;
00561 ifslastp->begoff = start;
00562 ifslastp->endoff = end;
00563 ifslastp->nulonly = nulonly;
00564 }
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574 STATIC void
00575 ifsbreakup(string, arglist)
00576 char *string;
00577 struct arglist *arglist;
00578 {
00579 struct ifsregion *ifsp;
00580 struct strlist *sp;
00581 char *start;
00582 register char *p;
00583 char *q;
00584 char *ifs;
00585
00586 start = string;
00587 if (ifslastp != NULL) {
00588 ifsp = &ifsfirst;
00589 do {
00590 p = string + ifsp->begoff;
00591 ifs = ifsp->nulonly? nullstr : ifsval();
00592 while (p < string + ifsp->endoff) {
00593 q = p;
00594 if (*p == CTLESC)
00595 p++;
00596 if (strchr(ifs, *p++)) {
00597 if (q > start || *ifs != ' ') {
00598 *q = '\0';
00599 sp = (struct strlist *)stalloc(sizeof *sp);
00600 sp->text = start;
00601 *arglist->lastp = sp;
00602 arglist->lastp = &sp->next;
00603 }
00604 if (*ifs == ' ') {
00605 for (;;) {
00606 if (p >= string + ifsp->endoff)
00607 break;
00608 q = p;
00609 if (*p == CTLESC)
00610 p++;
00611 if (strchr(ifs, *p++) == NULL) {
00612 p = q;
00613 break;
00614 }
00615 }
00616 }
00617 start = p;
00618 }
00619 }
00620 } while ((ifsp = ifsp->next) != NULL);
00621 if (*start || (*ifs != ' ' && start > string)) {
00622 sp = (struct strlist *)stalloc(sizeof *sp);
00623 sp->text = start;
00624 *arglist->lastp = sp;
00625 arglist->lastp = &sp->next;
00626 }
00627 } else {
00628 sp = (struct strlist *)stalloc(sizeof *sp);
00629 sp->text = start;
00630 *arglist->lastp = sp;
00631 arglist->lastp = &sp->next;
00632 }
00633 }
00634
00635
00636
00637
00638
00639
00640
00641
00642 char *expdir;
00643
00644
00645 STATIC void
00646 expandmeta(str)
00647 struct strlist *str;
00648 {
00649 char *p;
00650 struct strlist **savelastp;
00651 struct strlist *sp;
00652 char c;
00653
00654 while (str) {
00655 if (fflag)
00656 goto nometa;
00657 p = str->text;
00658 #if UDIR
00659 if (p[0] == '/' && p[1] == 'u' && p[2] == '/')
00660 str->text = p = expudir(p);
00661 #endif
00662 #if TILDE
00663 if (p[0] == '~')
00664 str->text = p = expudir(p);
00665 #endif
00666 for (;;) {
00667 if ((c = *p++) == '\0')
00668 goto nometa;
00669 if (c == '*' || c == '?' || c == '[' || c == '!')
00670 break;
00671 }
00672 savelastp = exparg.lastp;
00673 INTOFF;
00674 if (expdir == NULL)
00675 {
00676 int i = strlen(str->text);
00677 expdir = ckmalloc(i < 2048 ? 2048 : i);
00678 }
00679 expmeta(expdir, str->text);
00680 ckfree(expdir);
00681 expdir = NULL;
00682 INTON;
00683 if (exparg.lastp == savelastp) {
00684 if (! zflag) {
00685 nometa:
00686 *exparg.lastp = str;
00687 rmescapes(str->text);
00688 exparg.lastp = &str->next;
00689 }
00690 } else {
00691 *exparg.lastp = NULL;
00692 *savelastp = sp = expsort(*savelastp);
00693 while (sp->next != NULL)
00694 sp = sp->next;
00695 exparg.lastp = &sp->next;
00696 }
00697 str = str->next;
00698 }
00699 }
00700
00701
00702 #if UDIR || TILDE
00703
00704
00705
00706
00707
00708
00709
00710
00711 #define MAXLOGNAME 32
00712 #define MAXPWLINE 128
00713
00714 char *pfgets();
00715
00716
00717 STATIC char *
00718 expudir(path)
00719 char *path;
00720 {
00721 register char *p, *q, *r;
00722 char name[MAXLOGNAME];
00723 char line[MAXPWLINE];
00724 int i;
00725 #if USEGETPW
00726 struct passwd *pw;
00727 #endif
00728
00729 r = path;
00730 p = r + (*r == '~' ? 1 : 3);
00731 q = name;
00732 while (*p && *p != '/') {
00733 if (q >= name + MAXLOGNAME - 1)
00734 return r;
00735 *q++ = *p++;
00736 }
00737 *q = '\0';
00738
00739 #if TILDE
00740 if (*name == 0 && *r == '~') {
00741
00742 if ((q = lookupvar("HOME")) == NULL)
00743 return r;
00744 i = strlen(q);
00745 r = stalloc(i + strlen(p) + 1);
00746 scopy(q, r);
00747 scopy(p, r + i);
00748 TRACE(("expudir converts %s to %s\n", path, r));
00749 didudir = 1;
00750 path = r;
00751 return r;
00752 }
00753 #endif
00754 #if !USEGETPW
00755 setinputfile("/etc/passwd", 1);
00756 q = line + strlen(name);
00757 while (pfgets(line, MAXPWLINE) != NULL) {
00758 if (line[0] == name[0] && prefix(name, line) && *q == ':') {
00759
00760 i = 4;
00761 do {
00762 while (*++q && *q != ':');
00763 } while (--i > 0);
00764 if (*q == '\0')
00765 break;
00766 q++;
00767 for (r = q ; *r && *r != '\n' && *r != ':' ; r++);
00768 *r = '\0';
00769 i = r - q;
00770 r = stalloc(i + strlen(p) + 1);
00771 scopy(q, r);
00772 scopy(p, r + i);
00773 TRACE(("expudir converts %s to %s\n", path, r));
00774 didudir = 1;
00775 path = r;
00776 break;
00777 }
00778 }
00779 popfile();
00780 #else
00781 if ((pw = getpwnam(name)) != NULL) {
00782
00783 q = pw->pw_dir;
00784 i = strlen(q);
00785 r = stalloc(i + strlen(p) + 1);
00786 scopy(q, r);
00787 scopy(p, r + i);
00788 TRACE(("expudir converts %s to %s\n", path, r));
00789 didudir = 1;
00790 path = r;
00791 }
00792 endpwent();
00793 #endif
00794
00795 return r;
00796 }
00797 #endif
00798
00799
00800
00801
00802
00803
00804 STATIC void
00805 expmeta(enddir, name)
00806 char *enddir;
00807 char *name;
00808 {
00809 register char *p;
00810 char *q;
00811 char *start;
00812 char *endname;
00813 int metaflag;
00814 struct stat statb;
00815 DIR *dirp;
00816 struct dirent *dp;
00817 int atend;
00818 int matchdot;
00819
00820 metaflag = 0;
00821 start = name;
00822 for (p = name ; ; p++) {
00823 if (*p == '*' || *p == '?')
00824 metaflag = 1;
00825 else if (*p == '[') {
00826 q = p + 1;
00827 if (*q == '!')
00828 q++;
00829 for (;;) {
00830 if (*q == CTLESC)
00831 q++;
00832 if (*q == '/' || *q == '\0')
00833 break;
00834 if (*++q == ']') {
00835 metaflag = 1;
00836 break;
00837 }
00838 }
00839 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
00840 metaflag = 1;
00841 } else if (*p == '\0')
00842 break;
00843 else if (*p == CTLESC)
00844 p++;
00845 if (*p == '/') {
00846 if (metaflag)
00847 break;
00848 start = p + 1;
00849 }
00850 }
00851 if (metaflag == 0) {
00852 if (enddir != expdir)
00853 metaflag++;
00854 for (p = name ; ; p++) {
00855 if (*p == CTLESC)
00856 p++;
00857 *enddir++ = *p;
00858 if (*p == '\0')
00859 break;
00860 }
00861 if (metaflag == 0 || stat(expdir, &statb) >= 0)
00862 addfname(expdir);
00863 return;
00864 }
00865 endname = p;
00866 if (start != name) {
00867 p = name;
00868 while (p < start) {
00869 if (*p == CTLESC)
00870 p++;
00871 *enddir++ = *p++;
00872 }
00873 }
00874 if (enddir == expdir) {
00875 p = ".";
00876 } else if (enddir == expdir + 1 && *expdir == '/') {
00877 p = "/";
00878 } else {
00879 p = expdir;
00880 enddir[-1] = '\0';
00881 }
00882 if ((dirp = opendir(p)) == NULL)
00883 return;
00884 if (enddir != expdir)
00885 enddir[-1] = '/';
00886 if (*endname == 0) {
00887 atend = 1;
00888 } else {
00889 atend = 0;
00890 *endname++ = '\0';
00891 }
00892 matchdot = 0;
00893 if (start[0] == '.' || start[0] == CTLESC && start[1] == '.')
00894 matchdot++;
00895 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
00896 if (dp->d_name[0] == '.' && ! matchdot)
00897 continue;
00898 if (patmatch(start, dp->d_name)) {
00899 if (atend) {
00900 scopy(dp->d_name, enddir);
00901 addfname(expdir);
00902 } else {
00903 char *q;
00904 for (p = enddir, q = dp->d_name ; *p++ = *q++ ;);
00905 p[-1] = '/';
00906 expmeta(p, endname);
00907 }
00908 }
00909 }
00910 closedir(dirp);
00911 if (! atend)
00912 endname[-1] = '/';
00913 }
00914
00915
00916
00917
00918
00919
00920 STATIC void
00921 addfname(name)
00922 char *name;
00923 {
00924 char *p;
00925 struct strlist *sp;
00926
00927 p = stalloc(strlen(name) + 1);
00928 scopy(name, p);
00929 sp = (struct strlist *)stalloc(sizeof *sp);
00930 sp->text = p;
00931 *exparg.lastp = sp;
00932 exparg.lastp = &sp->next;
00933 }
00934
00935
00936
00937
00938
00939
00940
00941
00942 STATIC struct strlist *
00943 expsort(str)
00944 struct strlist *str;
00945 {
00946 int len;
00947 struct strlist *sp;
00948
00949 len = 0;
00950 for (sp = str ; sp ; sp = sp->next)
00951 len++;
00952 return msort(str, len);
00953 }
00954
00955
00956 STATIC struct strlist *
00957 msort(list, len)
00958 struct strlist *list;
00959 {
00960 struct strlist *p, *q;
00961 struct strlist **lpp;
00962 int half;
00963 int n;
00964
00965 if (len <= 1)
00966 return list;
00967 half = len >> 1;
00968 p = list;
00969 for (n = half ; --n >= 0 ; ) {
00970 q = p;
00971 p = p->next;
00972 }
00973 q->next = NULL;
00974 q = msort(list, half);
00975 p = msort(p, len - half);
00976 lpp = &list;
00977 for (;;) {
00978 if (strcmp(p->text, q->text) < 0) {
00979 *lpp = p;
00980 lpp = &p->next;
00981 if ((p = *lpp) == NULL) {
00982 *lpp = q;
00983 break;
00984 }
00985 } else {
00986 *lpp = q;
00987 lpp = &q->next;
00988 if ((q = *lpp) == NULL) {
00989 *lpp = p;
00990 break;
00991 }
00992 }
00993 }
00994 return list;
00995 }
00996
00997
00998
00999
01000
01001
01002
01003 int
01004 patmatch(pattern, string)
01005 char *pattern;
01006 char *string;
01007 {
01008 if (pattern[0] == '!' && pattern[1] == '!')
01009 return 1 - pmatch(pattern + 2, string);
01010 else
01011 return pmatch(pattern, string);
01012 }
01013
01014
01015 STATIC int
01016 pmatch(pattern, string)
01017 char *pattern;
01018 char *string;
01019 {
01020 register char *p, *q;
01021 register char c;
01022
01023 p = pattern;
01024 q = string;
01025 for (;;) {
01026 switch (c = *p++) {
01027 case '\0':
01028 goto breakloop;
01029 case CTLESC:
01030 if (*q++ != *p++)
01031 return 0;
01032 break;
01033 case '?':
01034 if (*q++ == '\0')
01035 return 0;
01036 break;
01037 case '*':
01038 c = *p;
01039 if (c != CTLESC && c != '?' && c != '*' && c != '[') {
01040 while (*q != c) {
01041 if (*q == '\0')
01042 return 0;
01043 q++;
01044 }
01045 }
01046 do {
01047 if (pmatch(p, q))
01048 return 1;
01049 } while (*q++ != '\0');
01050 return 0;
01051 case '[': {
01052 char *endp;
01053 int invert, found;
01054 char chr;
01055
01056 endp = p;
01057 if (*endp == '!')
01058 endp++;
01059 for (;;) {
01060 if (*endp == '\0')
01061 goto dft;
01062 if (*endp == CTLESC)
01063 endp++;
01064 if (*++endp == ']')
01065 break;
01066 }
01067 invert = 0;
01068 if (*p == '!') {
01069 invert++;
01070 p++;
01071 }
01072 found = 0;
01073 chr = *q++;
01074 c = *p++;
01075 do {
01076 if (c == CTLESC)
01077 c = *p++;
01078 if (*p == '-' && p[1] != ']') {
01079 p++;
01080 if (*p == CTLESC)
01081 p++;
01082 if (chr >= c && chr <= *p)
01083 found = 1;
01084 p++;
01085 } else {
01086 if (chr == c)
01087 found = 1;
01088 }
01089 } while ((c = *p++) != ']');
01090 if (found == invert)
01091 return 0;
01092 break;
01093 }
01094 dft: default:
01095 if (*q++ != c)
01096 return 0;
01097 break;
01098 }
01099 }
01100 breakloop:
01101 if (*q != '\0')
01102 return 0;
01103 return 1;
01104 }
01105
01106
01107
01108
01109
01110
01111
01112 void
01113 rmescapes(str)
01114 char *str;
01115 {
01116 register char *p, *q;
01117
01118 p = str;
01119 while (*p != CTLESC) {
01120 if (*p++ == '\0')
01121 return;
01122 }
01123 q = p;
01124 while (*p) {
01125 if (*p == CTLESC)
01126 p++;
01127 *q++ = *p++;
01128 }
01129 *q = '\0';
01130 }
01131
01132
01133
01134
01135
01136
01137
01138 int
01139 casematch(pattern, val)
01140 union node *pattern;
01141 char *val;
01142 {
01143 struct stackmark smark;
01144 int result;
01145 char *p;
01146
01147 setstackmark(&smark);
01148 argbackq = pattern->narg.backquote;
01149 STARTSTACKSTR(expdest);
01150 ifslastp = NULL;
01151
01152
01153 argstr(pattern->narg.text, 1);
01154 STPUTC('\0', expdest);
01155 p = grabstackstr(expdest);
01156 result = patmatch(p, val);
01157 popstackmark(&smark);
01158 return result;
01159 }