📄 edit.c
字号:
if (x_basename(words[i] + prefix_len, (char *) 0) > prefix_len) break; /* All in same directory? */ if (i == nwords) { while (prefix_len > 0 && !ISDIRSEP(words[0][prefix_len - 1])) prefix_len--; use_copy = 1; XPinit(l, nwords + 1); for (i = 0; i < nwords; i++) XPput(l, words[i] + prefix_len); XPput(l, (char *) 0); } } /* * Enumerate expansions */ x_putc('\r'); x_putc('\n'); pr_menu(use_copy ? (char **) XPptrv(l) : words); if (use_copy) XPfree(l); /* not x_free_words() */}/* * Do file globbing: * - appends * to (copy of) str if no globbing chars found * - does expansion, checks for no match, etc. * - sets *wordsp to array of matching strings * - returns number of matching strings */static intx_file_glob(flags, str, slen, wordsp) int flags; const char *str; int slen; char ***wordsp;{ char *toglob; char **words; int nwords; XPtrV w; struct source *s, *sold; if (slen < 0) return 0; toglob = add_glob(str, slen); /* * Convert "foo*" (toglob) to an array of strings (words) */ sold = source; s = pushs(SWSTR, ATEMP); s->start = s->str = toglob; source = s; if (yylex(ONEWORD) != LWORD) { source = sold; internal_errorf(0, "fileglob: substitute error"); return 0; } source = sold; XPinit(w, 32); expand(yylval.cp, &w, DOGLOB|DOTILDE|DOMARKDIRS); XPput(w, NULL); words = (char **) XPclose(w); for (nwords = 0; words[nwords]; nwords++) ; if (nwords == 1) { struct stat statb; /* Check if globbing failed (returned glob pattern), * but be careful (E.g. toglob == "ab*" when the file * "ab*" exists is not an error). * Also, check for empty result - happens if we tried * to glob something which evaluated to an empty * string (e.g., "$FOO" when there is no FOO, etc). */ if ((strcmp(words[0], toglob) == 0 && stat(words[0], &statb) < 0) || words[0][0] == '\0') { x_free_words(nwords, words); nwords = 0; } } afree(toglob, ATEMP); *wordsp = nwords ? words : (char **) 0; return nwords;}/* Data structure used in x_command_glob() */struct path_order_info { char *word; int base; int path_order;};/* Compare routine used in x_command_glob() */static intpath_order_cmp(aa, bb) const void *aa; const void *bb;{ const struct path_order_info *a = (const struct path_order_info *) aa; const struct path_order_info *b = (const struct path_order_info *) bb; int t; t = FILECMP(a->word + a->base, b->word + b->base); return t ? t : a->path_order - b->path_order;}static intx_command_glob(flags, str, slen, wordsp) int flags; const char *str; int slen; char ***wordsp;{ char *toglob; char *pat; char *fpath; int nwords; XPtrV w; struct block *l; if (slen < 0) return 0; toglob = add_glob(str, slen); /* Convert "foo*" (toglob) to a pattern for future use */ pat = evalstr(toglob, DOPAT|DOTILDE); afree(toglob, ATEMP); XPinit(w, 32); glob_table(pat, &w, &keywords); glob_table(pat, &w, &aliases); glob_table(pat, &w, &builtins); for (l = e->loc; l; l = l->next) glob_table(pat, &w, &l->funs); glob_path(flags, pat, &w, path); if ((fpath = str_val(global("FPATH"))) != null) glob_path(flags, pat, &w, fpath); nwords = XPsize(w); if (!nwords) { *wordsp = (char **) 0; XPfree(w); return 0; } /* Sort entries */ if (flags & XCF_FULLPATH) { /* Sort by basename, then path order */ struct path_order_info *info; struct path_order_info *last_info = 0; char **words = (char **) XPptrv(w); int path_order = 0; int i; info = (struct path_order_info *) alloc(sizeof(struct path_order_info) * nwords, ATEMP); for (i = 0; i < nwords; i++) { info[i].word = words[i]; info[i].base = x_basename(words[i], (char *) 0); if (!last_info || info[i].base != last_info->base || FILENCMP(words[i], last_info->word, info[i].base) != 0) { last_info = &info[i]; path_order++; } info[i].path_order = path_order; } qsort(info, nwords, sizeof(struct path_order_info), path_order_cmp); for (i = 0; i < nwords; i++) words[i] = info[i].word; afree((void *) info, ATEMP); } else { /* Sort and remove duplicate entries */ char **words = (char **) XPptrv(w); int i, j; qsortp(XPptrv(w), (size_t) nwords, xstrcmp); for (i = j = 0; i < nwords - 1; i++) { if (strcmp(words[i], words[i + 1])) words[j++] = words[i]; else afree(words[i], ATEMP); } words[j++] = words[i]; nwords = j; w.cur = (void **) &words[j]; } XPput(w, NULL); *wordsp = (char **) XPclose(w); return nwords;}#define IS_WORDC(c) !(ctype(c, C_LEX1) || (c) == '\'' || (c) == '"')static intx_locate_word(buf, buflen, pos, startp, is_commandp) const char *buf; int buflen; int pos; int *startp; int *is_commandp;{ int p; int start, end; /* Bad call? Probably should report error */ if (pos < 0 || pos > buflen) { *startp = pos; *is_commandp = 0; return 0; } /* The case where pos == buflen happens to take care of itself... */ start = pos; /* Keep going backwards to start of word (has effect of allowing * one blank after the end of a word) */ for (; start > 0 && IS_WORDC(buf[start - 1]); start--) ; /* Go forwards to end of word */ for (end = start; end < buflen && IS_WORDC(buf[end]); end++) ; if (is_commandp) { int iscmd; /* Figure out if this is a command */ for (p = start - 1; p >= 0 && isspace(buf[p]); p--) ; iscmd = p < 0 || strchr(";|&()", buf[p]); if (iscmd) { /* If command has a /, path, etc. is not searched; * only current directory is searched, which is just * like file globbing. */ for (p = start; p < end; p++) if (ISDIRSEP(buf[p])) break; iscmd = p == end; } *is_commandp = iscmd; } *startp = start; return end - start;}intx_cf_glob(flags, buf, buflen, pos, startp, endp, wordsp, is_commandp) int flags; const char *buf; int buflen; int pos; int *startp; int *endp; char ***wordsp; int *is_commandp;{ int len; int nwords; char **words; int is_command; len = x_locate_word(buf, buflen, pos, startp, &is_command); if (!(flags & XCF_COMMAND)) is_command = 0; /* Don't do command globing on zero length strings - it takes too * long and isn't very useful. File globs are more likely to be * useful, so allow these. */ if (len == 0 && is_command) return 0; nwords = (is_command ? x_command_glob : x_file_glob)(flags, buf + *startp, len, &words); if (nwords == 0) { *wordsp = (char **) 0; return 0; } if (is_commandp) *is_commandp = is_command; *wordsp = words; *endp = *startp + len; return nwords;}/* Given a string, copy it and possibly add a '*' to the end. The * new string is returned. */static char *add_glob(str, slen) const char *str; int slen;{ char *toglob; char *s; bool_t saw_slash = FALSE; if (slen < 0) return (char *) 0; toglob = str_nsave(str, slen + 1, ATEMP); /* + 1 for "*" */ toglob[slen] = '\0'; /* * If the pathname contains a wildcard (an unquoted '*', * '?', or '[') or parameter expansion ('$'), or a ~username * with no trailing slash, then it is globbed based on that * value (i.e., without the appended '*'). */ for (s = toglob; *s; s++) { if (*s == '\\' && s[1]) s++; else if (*s == '*' || *s == '[' || *s == '?' || *s == '$' || (s[1] == '(' /*)*/ && strchr("*+?@!", *s))) break; else if (ISDIRSEP(*s)) saw_slash = TRUE; } if (!*s && (*toglob != '~' || saw_slash)) { toglob[slen] = '*'; toglob[slen + 1] = '\0'; } return toglob;}/* * Find longest common prefix */intx_longest_prefix(nwords, words) int nwords; char *const *words;{ int i, j; int prefix_len; char *p; if (nwords <= 0) return 0; prefix_len = strlen(words[0]); for (i = 1; i < nwords; i++) for (j = 0, p = words[i]; j < prefix_len; j++) if (FILECHCONV(p[j]) != FILECHCONV(words[0][j])) { prefix_len = j; break; } return prefix_len;}voidx_free_words(nwords, words) int nwords; char **words;{ int i; for (i = 0; i < nwords; i++) if (words[i]) afree(words[i], ATEMP); afree(words, ATEMP);}/* Return the offset of the basename of string s (which ends at se - need not * be null terminated). Trailing slashes are ignored. If s is just a slash, * then the offset is 0 (actually, length - 1). * s Return * /etc 1 * /etc/ 1 * /etc// 1 * /etc/fo 5 * foo 0 * /// 2 * 0 */intx_basename(s, se) const char *s; const char *se;{ const char *p; if (se == (char *) 0) se = s + strlen(s); if (s == se) return 0; /* Skip trailing slashes */ for (p = se - 1; p > s && ISDIRSEP(*p); p--) ; for (; p > s && !ISDIRSEP(*p); p--) ; if (ISDIRSEP(*p) && p + 1 < se) p++; return p - s;}/* * Apply pattern matching to a table: all table entries that match a pattern * are added to wp. */static voidglob_table(pat, wp, tp) const char *pat; XPtrV *wp; struct table *tp;{ struct tstate ts; struct tbl *te; for (twalk(&ts, tp); (te = tnext(&ts)); ) { if (gmatch(te->name, pat, FALSE)) XPput(*wp, str_save(te->name, ATEMP)); }}static voidglob_path(flags, pat, wp, path) int flags; const char *pat; XPtrV *wp; const char *path;{ const char *sp, *p; char *xp; int pathlen; int patlen; int oldsize, newsize, i, j; char **words; XString xs; patlen = strlen(pat) + 1; sp = path; Xinit(xs, xp, patlen + 128, ATEMP); while (sp) { xp = Xstring(xs, xp); if (!(p = strchr(sp, PATHSEP))) p = sp + strlen(sp); pathlen = p - sp; if (pathlen) { /* Copy sp into xp, stuffing any MAGIC characters * on the way */ const char *s = sp; XcheckN(xs, xp, pathlen * 2); while (s < p) { if (ISMAGIC(*s)) *xp++ = MAGIC; *xp++ = *s++; } *xp++ = DIRSEP; pathlen++; } sp = p; XcheckN(xs, xp, patlen); memcpy(xp, pat, patlen); oldsize = XPsize(*wp); glob_str(Xstring(xs, xp), wp, 0); newsize = XPsize(*wp); /* Check that each match is executable... */ words = (char **) XPptrv(*wp); for (i = j = oldsize; i < newsize; i++) { if (search_access(words[i], X_OK, (int *) 0) >= 0) { words[j] = words[i]; if (!(flags & XCF_FULLPATH)) memmove(words[j], words[j] + pathlen, strlen(words[j] + pathlen) + 1); j++; } else afree(words[i], ATEMP); } wp->cur = (void **) &words[j]; if (!*sp++) break; } Xfree(xs, xp);}#endif /* EDIT */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -