📄 expand.c
字号:
STATIC voidifsfree(void){ while (ifsfirst.next != NULL) { struct ifsregion *ifsp; INTOFF; ifsp = ifsfirst.next->next; ckfree(ifsfirst.next); ifsfirst.next = ifsp; INTON; } ifslastp = NULL; ifsfirst.next = NULL;}/* * 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(struct strlist *str, int flag){ 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(char *enddir, char *name){ char *p; const char *cp; 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 (;;) { while (*q == CTLQUOTEMARK) q++; 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 == CTLQUOTEMARK) continue; 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 == CTLQUOTEMARK) continue; if (*p == CTLESC) p++; *enddir++ = *p; if (*p == '\0') break; } if (metaflag == 0 || lstat(expdir, &statb) >= 0) addfname(expdir); return; } endname = p; if (start != name) { p = name; while (p < start) { while (*p == CTLQUOTEMARK) p++; if (*p == CTLESC) p++; *enddir++ = *p++; } } if (enddir == expdir) { cp = "."; } else if (enddir == expdir + 1 && *expdir == '/') { cp = "/"; } else { cp = expdir; enddir[-1] = '\0'; } if ((dirp = opendir(cp)) == NULL) return; if (enddir != expdir) enddir[-1] = '/'; if (*endname == 0) { atend = 1; } else { atend = 0; *endname++ = '\0'; } matchdot = 0; p = start; while (*p == CTLQUOTEMARK) p++; if (*p == CTLESC) p++; if (*p == '.') matchdot++; while (! int_pending() && (dp = readdir(dirp)) != NULL) { if (dp->d_name[0] == '.' && ! matchdot) continue; if (patmatch(start, dp->d_name, 0)) { if (atend) { scopy(dp->d_name, enddir); addfname(expdir); } else { for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';) continue; p[-1] = '/'; expmeta(p, endname); } } } closedir(dirp); if (! atend) endname[-1] = '/';}/* * Add a file name to the list. */STATIC voidaddfname(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(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(struct strlist *list, int len){ struct strlist *p, *q = NULL; 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(char *pattern, char *string, int squoted){#ifdef notdef if (pattern[0] == '!' && pattern[1] == '!') return 1 - pmatch(pattern + 2, string); else#endif return pmatch(pattern, string, squoted);}STATIC intpmatch(char *pattern, char *string, int squoted){ char *p, *q; char c; p = pattern; q = string; for (;;) { switch (c = *p++) { case '\0': goto breakloop; case CTLESC: if (squoted && *q == CTLESC) q++; if (*q++ != *p++) return 0; break; case CTLQUOTEMARK: continue; case '?': if (squoted && *q == CTLESC) q++; if (*q++ == '\0') return 0; break; case '*': c = *p; while (c == CTLQUOTEMARK || c == '*') c = *++p; if (c != CTLESC && c != CTLQUOTEMARK && c != '?' && c != '*' && c != '[') { while (*q != c) { if (squoted && *q == CTLESC && q[1] == c) break; if (*q == '\0') return 0; if (squoted && *q == CTLESC) q++; q++; } } do { if (pmatch(p, q, squoted)) return 1; if (squoted && *q == CTLESC) q++; } while (*q++ != '\0'); return 0; case '[': { char *endp; int invert, found; char chr; endp = p; if (*endp == '!') endp++; for (;;) { while (*endp == CTLQUOTEMARK) endp++; if (*endp == '\0') goto dft; /* no matching ] */ if (*endp == CTLESC) endp++; if (*++endp == ']') break; } invert = 0; if (*p == '!') { invert++; p++; } found = 0; chr = *q++; if (squoted && chr == CTLESC) chr = *q++; if (chr == '\0') return 0; c = *p++; do { if (c == CTLQUOTEMARK) continue; if (c == CTLESC) c = *p++; if (*p == '-' && p[1] != ']') { p++; while (*p == CTLQUOTEMARK) 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 (squoted && *q == CTLESC) q++; if (*q++ != c) return 0; break; } }breakloop: if (*q != '\0') return 0; return 1;}/* * Remove any CTLESC characters from a string. */voidrmescapes(char *str){ char *p, *q; p = str; while (*p != CTLESC && *p != CTLQUOTEMARK) { if (*p++ == '\0') return; } q = p; while (*p) { if (*p == CTLQUOTEMARK) { p++; continue; } if (*p == CTLESC) p++; *q++ = *p++; } *q = '\0';}/* * See if a pattern matches in a case statement. */intcasematch(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, 0); popstackmark(&smark); return result;}/* * Our own itoa(). */STATIC char *cvtnum(int num, char *buf){ char temp[32]; int neg = num < 0; char *p = temp + 31; temp[31] = '\0'; do { *--p = num % 10 + '0'; } while ((num /= 10) != 0); if (neg) *--p = '-'; while (*p) STPUTC(*p++, buf); return buf;}/* * Do most of the work for wordexp(3). */intwordexpcmd(int argc, char **argv){ size_t len; int i; out1fmt("%d", argc - 1); out1c('\0'); for (i = 1, len = 0; i < argc; i++) len += strlen(argv[i]); out1fmt("%zd", len); out1c('\0'); for (i = 1; i < argc; i++) { out1str(argv[i]); out1c('\0'); } return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -