📄 expand.c
字号:
if (syntax[*p] == CCTL) \ STPUTC(CTLESC, expdest); \ STPUTC(*p++, expdest); \ } \ } else \ while (*p) \ STPUTC(*p++, expdest); \ } while (0) switch (name) { case '$': num = rootpid; goto numvar; case '?': num = exitstatus; goto numvar; case '#': num = shellparam.nparam; goto numvar; case '!': num = backgndpid;numvar: p = temp + 31; temp[31] = '\0'; do { *--p = num % 10 + '0'; } while ((num /= 10) != 0); while (*p) STPUTC(*p++, expdest); break; case '-': for (i = 0 ; i < NOPTS ; i++) { if (optlist[i].val) STPUTC(optlist[i].letter, expdest); } break; case '@': if (allow_split) { sep = '\0'; goto allargs; } /* fall through */ case '*': sep = ' ';allargs: for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { STRTODEST(p); if (*ap) STPUTC(sep, expdest); } break; case '0': p = arg0; STRTODEST(p); break; default: if ((unsigned)(name -= '1') <= '9' - '1') { p = shellparam.p[name]; STRTODEST(p); } break; }}/* * Record the the fact that we have to scan this region of the * string for IFS characters. */STATIC voidrecordregion(start, end, nulonly) { register struct ifsregion *ifsp; if (ifslastp == NULL) { ifsp = &ifsfirst; } else { ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion)); ifslastp->next = ifsp; } ifslastp = ifsp; ifslastp->next = NULL; ifslastp->begoff = start; ifslastp->endoff = end; ifslastp->nulonly = nulonly;}/* * Break the argument string into pieces based upon IFS and add the * strings to the argument list. The regions of the string to be * searched for IFS characters have been stored by recordregion. */STATIC voidifsbreakup(string, arglist) char *string; struct arglist *arglist; { struct ifsregion *ifsp; struct strlist *sp; char *start; register char *p; char *q; char *ifs; start = string; if (ifslastp != NULL) { ifsp = &ifsfirst; do { p = string + ifsp->begoff; ifs = ifsp->nulonly? nullstr : ifsval(); while (p < string + ifsp->endoff) { q = p; if (*p == CTLESC) p++; if (strchr(ifs, *p++)) { if (q > start || *ifs != ' ') { *q = '\0'; sp = (struct strlist *)stalloc(sizeof *sp); sp->text = start; *arglist->lastp = sp; arglist->lastp = &sp->next; } if (*ifs == ' ') { for (;;) { if (p >= string + ifsp->endoff) break; q = p; if (*p == CTLESC) p++; if (strchr(ifs, *p++) == NULL) { p = q; break; } } } start = p; } } } while ((ifsp = ifsp->next) != NULL); if (*start || (*ifs != ' ' && start > string)) { sp = (struct strlist *)stalloc(sizeof *sp); sp->text = start; *arglist->lastp = sp; arglist->lastp = &sp->next; } } else { sp = (struct strlist *)stalloc(sizeof *sp); sp->text = start; *arglist->lastp = sp; arglist->lastp = &sp->next; }}/* * Expand shell metacharacters. At this point, the only control characters * should be escapes. The results are stored in the list exparg. */char *expdir;STATIC voidexpandmeta(str, flag) struct strlist *str; { char *p; struct strlist **savelastp; struct strlist *sp; char c; /* TODO - EXP_REDIR */ while (str) { if (fflag) goto nometa; p = str->text; for (;;) { /* fast check for meta chars */ if ((c = *p++) == '\0') goto nometa; if (c == '*' || c == '?' || c == '[' || c == '!') break; } savelastp = exparg.lastp; INTOFF; if (expdir == NULL) { int i = strlen(str->text); expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ } expmeta(expdir, str->text); ckfree(expdir); expdir = NULL; INTON; if (exparg.lastp == savelastp) { /* * no matches */nometa: *exparg.lastp = str; rmescapes(str->text); exparg.lastp = &str->next; } else { *exparg.lastp = NULL; *savelastp = sp = expsort(*savelastp); while (sp->next != NULL) sp = sp->next; exparg.lastp = &sp->next; } str = str->next; }}/* * Do metacharacter (i.e. *, ?, [...]) expansion. */STATIC voidexpmeta(enddir, name) char *enddir; char *name; { register char *p; char *q; char *start; char *endname; int metaflag; struct stat statb; DIR *dirp; struct dirent *dp; int atend; int matchdot; metaflag = 0; start = name; for (p = name ; ; p++) { if (*p == '*' || *p == '?') metaflag = 1; else if (*p == '[') { q = p + 1; if (*q == '!') q++; for (;;) { if (*q == CTLESC) q++; if (*q == '/' || *q == '\0') break; if (*++q == ']') { metaflag = 1; break; } } } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) { metaflag = 1; } else if (*p == '\0') break; else if (*p == CTLESC) p++; if (*p == '/') { if (metaflag) break; start = p + 1; } } if (metaflag == 0) { /* we've reached the end of the file name */ if (enddir != expdir) metaflag++; for (p = name ; ; p++) { if (*p == CTLESC) p++; *enddir++ = *p; if (*p == '\0') break; } if (metaflag == 0 || stat(expdir, &statb) >= 0) addfname(expdir); return; } endname = p; if (start != name) { p = name; while (p < start) { if (*p == CTLESC) p++; *enddir++ = *p++; } } if (enddir == expdir) { p = "."; } else if (enddir == expdir + 1 && *expdir == '/') { p = "/"; } else { p = expdir; enddir[-1] = '\0'; } if ((dirp = opendir(p)) == NULL) return; if (enddir != expdir) enddir[-1] = '/'; if (*endname == 0) { atend = 1; } else { atend = 0; *endname++ = '\0'; } matchdot = 0; if (start[0] == '.' || start[0] == CTLESC && start[1] == '.') matchdot++; while (! int_pending() && (dp = readdir(dirp)) != NULL) { if (dp->d_name[0] == '.' && ! matchdot) continue; if (patmatch(start, dp->d_name)) { if (atend) { scopy(dp->d_name, enddir); addfname(expdir); } else { char *q; for (p = enddir, q = dp->d_name ; *p++ = *q++ ;); p[-1] = '/'; expmeta(p, endname); } } } closedir(dirp); if (! atend) endname[-1] = '/';}/* * Add a file name to the list. */STATIC voidaddfname(name) char *name; { char *p; struct strlist *sp; p = stalloc(strlen(name) + 1); scopy(name, p); sp = (struct strlist *)stalloc(sizeof *sp); sp->text = p; *exparg.lastp = sp; exparg.lastp = &sp->next;}/* * Sort the results of file name expansion. It calculates the number of * strings to sort and then calls msort (short for merge sort) to do the * work. */STATIC struct strlist *expsort(str) struct strlist *str; { int len; struct strlist *sp; len = 0; for (sp = str ; sp ; sp = sp->next) len++; return msort(str, len);}STATIC struct strlist *msort(list, len) struct strlist *list; { struct strlist *p, *q; struct strlist **lpp; int half; int n; if (len <= 1) return list; half = len >> 1; p = list; for (n = half ; --n >= 0 ; ) { q = p; p = p->next; } q->next = NULL; /* terminate first half of list */ q = msort(list, half); /* sort first half of list */ p = msort(p, len - half); /* sort second half */ lpp = &list; for (;;) { if (strcmp(p->text, q->text) < 0) { *lpp = p; lpp = &p->next; if ((p = *lpp) == NULL) { *lpp = q; break; } } else { *lpp = q; lpp = &q->next; if ((q = *lpp) == NULL) { *lpp = p; break; } } } return list;}/* * Returns true if the pattern matches the string. */intpatmatch(pattern, string) char *pattern; char *string; {#ifdef notdef if (pattern[0] == '!' && pattern[1] == '!') return 1 - pmatch(pattern + 2, string); else#endif return pmatch(pattern, string);}STATIC intpmatch(pattern, string) char *pattern; char *string; { register char *p, *q; register char c; p = pattern; q = string; for (;;) { switch (c = *p++) { case '\0': goto breakloop; case CTLESC: if (*q++ != *p++) return 0; break; case '?': if (*q++ == '\0') return 0; break; case '*': c = *p; if (c != CTLESC && c != '?' && c != '*' && c != '[') { while (*q != c) { if (*q == '\0') return 0; q++; } } do { if (pmatch(p, q)) return 1; } while (*q++ != '\0'); return 0; case '[': { char *endp; int invert, found; char chr; endp = p; if (*endp == '!') endp++; for (;;) { if (*endp == '\0') goto dft; /* no matching ] */ if (*endp == CTLESC) endp++; if (*++endp == ']') break; } invert = 0; if (*p == '!') { invert++; p++; } found = 0; chr = *q++; c = *p++; do { if (c == CTLESC) c = *p++; if (*p == '-' && p[1] != ']') { p++; if (*p == CTLESC) p++; if (chr >= c && chr <= *p) found = 1; p++; } else { if (chr == c) found = 1; } } while ((c = *p++) != ']'); if (found == invert) return 0; break; }dft: default: if (*q++ != c) return 0; break; } }breakloop: if (*q != '\0') return 0; return 1;}/* * Remove any CTLESC characters from a string. */voidrmescapes(str) char *str; { register char *p, *q; p = str; while (*p != CTLESC) { if (*p++ == '\0') return; } q = p; while (*p) { if (*p == CTLESC) p++; *q++ = *p++; } *q = '\0';}/* * See if a pattern matches in a case statement. */intcasematch(pattern, val) union node *pattern; char *val; { struct stackmark smark; int result; char *p; setstackmark(&smark); argbackq = pattern->narg.backquote; STARTSTACKSTR(expdest); ifslastp = NULL; argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); STPUTC('\0', expdest); p = grabstackstr(expdest); result = patmatch(p, val); popstackmark(&smark); return result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -