📄 c_ksh.c
字号:
/* * built-in Korn commands: c_* */#include "sh.h"#include "ksh_stat.h"#include <ctype.h>#ifdef __CYGWIN__#include <sys/cygwin.h>#endif /* __CYGWIN__ */intc_cd(wp) char **wp;{ int optc; int physical = Flag(FPHYSICAL); int cdnode; /* was a node from cdpath added in? */ int printpath = 0; /* print where we cd'd? */ int rval; struct tbl *pwd_s, *oldpwd_s; XString xs; char *xp; char *dir, *try, *pwd; int phys_path; char *cdpath; while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != EOF) switch (optc) { case 'L': physical = 0; break; case 'P': physical = 1; break; case '?': return 1; } wp += builtin_opt.optind; if (Flag(FRESTRICTED)) { bi_errorf("restricted shell - can't cd"); return 1; } pwd_s = global("PWD"); oldpwd_s = global("OLDPWD"); if (!wp[0]) { /* No arguments - go home */ if ((dir = str_val(global("HOME"))) == null) { bi_errorf("no home directory (HOME not set)"); return 1; } } else if (!wp[1]) { /* One argument: - or dir */ dir = wp[0]; if (strcmp(dir, "-") == 0) { dir = str_val(oldpwd_s); if (dir == null) { bi_errorf("no OLDPWD"); return 1; } printpath++; } } else if (!wp[2]) { /* Two arguments - substitute arg1 in PWD for arg2 */ int ilen, olen, nlen, elen; char *cp; if (!current_wd[0]) { bi_errorf("don't know current directory"); return 1; } /* substitue arg1 for arg2 in current path. * if the first substitution fails because the cd fails * we could try to find another substitution. For now * we don't */ if ((cp = strstr(current_wd, wp[0])) == (char *) 0) { bi_errorf("bad substitution"); return 1; } ilen = cp - current_wd; olen = strlen(wp[0]); nlen = strlen(wp[1]); elen = strlen(current_wd + ilen + olen) + 1; dir = alloc(ilen + nlen + elen, ATEMP); memcpy(dir, current_wd, ilen); memcpy(dir + ilen, wp[1], nlen); memcpy(dir + ilen + nlen, current_wd + ilen + olen, elen); printpath++; } else { bi_errorf("too many arguments"); return 1; } Xinit(xs, xp, PATH, ATEMP); /* xp will have a bogus value after make_path() - set it to 0 * so that if it's used, it will cause a dump */ xp = (char *) 0; cdpath = str_val(global("CDPATH")); do { cdnode = make_path(current_wd, dir, &cdpath, &xs, &phys_path);#ifdef S_ISLNK if (physical) rval = chdir(try = Xstring(xs, xp) + phys_path); else#endif /* S_ISLNK */ { simplify_path(Xstring(xs, xp)); rval = chdir(try = Xstring(xs, xp)); } } while (rval < 0 && cdpath != (char *) 0); if (rval < 0) { if (cdnode) bi_errorf("%s: bad directory", dir); else bi_errorf("%s - %s", try, strerror(errno)); return 1; } /* Clear out tracked aliases with relative paths */ flushcom(0); /* Set OLDPWD (note: unsetting OLDPWD does not disable this * setting in at&t ksh) */ if (current_wd[0]) /* Ignore failure (happens if readonly or integer) */ setstr(oldpwd_s, current_wd, KSH_RETURN_ERROR); if (!ISABSPATH(Xstring(xs, xp))) {#ifdef OS2 /* simplify_path() doesn't know about os/2's drive contexts, * so it can't set current_wd when changing to a:foo. * Handle this by calling getcwd()... */ pwd = ksh_get_wd((char *) 0, 0);#else /* OS2 */ pwd = (char *) 0;#endif /* OS2 */ } else#ifdef S_ISLNK if (!physical || !(pwd = get_phys_path(Xstring(xs, xp))))#endif /* S_ISLNK */ pwd = Xstring(xs, xp); /* Set PWD */ if (pwd) {#ifdef __CYGWIN__ char ptmp[PATH]; /* larger than MAX_PATH */ cygwin_conv_to_full_posix_path(pwd, ptmp);#else /* __CYGWIN__ */ char *ptmp = pwd;#endif /* __CYGWIN__ */ set_current_wd(ptmp); /* Ignore failure (happens if readonly or integer) */ setstr(pwd_s, ptmp, KSH_RETURN_ERROR); } else { set_current_wd(null); pwd = Xstring(xs, xp); /* XXX unset $PWD? */ } if (printpath || cdnode) shprintf("%s\n", pwd); return 0;}intc_pwd(wp) char **wp;{ int optc; int physical = Flag(FPHYSICAL); char *p; while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != EOF) switch (optc) { case 'L': physical = 0; break; case 'P': physical = 1; break; case '?': return 1; } wp += builtin_opt.optind; if (wp[0]) { bi_errorf("too many arguments"); return 1; }#ifdef S_ISLNK p = current_wd[0] ? (physical ? get_phys_path(current_wd) : current_wd) : (char *) 0;#else /* S_ISLNK */ p = current_wd[0] ? current_wd : (char *) 0;#endif /* S_ISLNK */ if (p && eaccess(p, R_OK) < 0) p = (char *) 0; if (!p) { p = ksh_get_wd((char *) 0, 0); if (!p) { bi_errorf("can't get current directory - %s", strerror(errno)); return 1; } } shprintf("%s\n", p); return 0;}intc_print(wp) char **wp;{#define PO_NL BIT(0) /* print newline */#define PO_EXPAND BIT(1) /* expand backslash sequences */#define PO_PMINUSMINUS BIT(2) /* print a -- argument */#define PO_HIST BIT(3) /* print to history instead of stdout */#define PO_COPROC BIT(4) /* printing to coprocess: block SIGPIPE */#define PO_FSLASH BIT(5) /* swap slash for backslash (for os2 ) */ int fd = 1; int flags = PO_EXPAND|PO_NL; char *s; const char *emsg; XString xs; char *xp; if (wp[0][0] == 'e') { /* echo command */ int nflags = flags; /* A compromise between sysV and BSD echo commands: * escape sequences are enabled by default, and * -n, -e and -E are recognized if they appear * in arguments with no illegal options (ie, echo -nq * will print -nq). * Different from sysV echo since options are recognized, * different from BSD echo since escape sequences are enabled * by default. */ wp += 1; while ((s = *wp) && *s == '-' && s[1]) { while (*++s) if (*s == 'n') nflags &= ~PO_NL; else if (*s == 'e') nflags |= PO_EXPAND; else if (*s == 'E') nflags &= ~PO_EXPAND; else /* bad option: don't use nflags, print * argument */ break; if (*s) break; wp++; flags = nflags; } } else { int optc;#if OS2 const char *options = "Rnpfrsu,"; /* added f flag */#else const char *options = "Rnprsu,";#endif while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF) switch (optc) { case 'R': /* fake BSD echo command */ flags |= PO_PMINUSMINUS; flags &= ~PO_EXPAND; options = "ne"; break; case 'e': flags |= PO_EXPAND; break;#ifdef OS2 case 'f': flags |= PO_FSLASH; break;#endif case 'n': flags &= ~PO_NL; break;#ifdef KSH case 'p': if ((fd = coproc_getfd(W_OK, &emsg)) < 0) { bi_errorf("-p: %s", emsg); return 1; } break;#endif /* KSH */ case 'r': flags &= ~PO_EXPAND; break; case 's': flags |= PO_HIST; break; case 'u': if (!*(s = builtin_opt.optarg)) fd = 0; else if ((fd = check_fd(s, W_OK, &emsg)) < 0) { bi_errorf("-u: %s: %s", s, emsg); return 1; } break; case '?': return 1; } if (!(builtin_opt.info & GI_MINUSMINUS)) { /* treat a lone - like -- */ if (wp[builtin_opt.optind] && strcmp(wp[builtin_opt.optind], "-") == 0) builtin_opt.optind++; } else if (flags & PO_PMINUSMINUS) builtin_opt.optind--; wp += builtin_opt.optind; } Xinit(xs, xp, 128, ATEMP); while (*wp != NULL) { register int c; s = *wp; while ((c = *s++) != '\0') { Xcheck(xs, xp);#ifdef OS2 if ((flags & PO_FSLASH) && c == '\\') if (*s == '\\') *s++; else c = '/';#endif /* OS2 */ if ((flags & PO_EXPAND) && c == '\\') { int i; switch ((c = *s++)) { /* Oddly enough, \007 seems more portable than * \a (due to HP-UX cc, Ultrix cc, old pcc's, * etc.). */ case 'a': c = '\007'; break; case 'b': c = '\b'; break; case 'c': flags &= ~PO_NL; continue; /* AT&T brain damage */ case 'f': c = '\f'; break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'v': c = 0x0B; break; case '0': /* Look for an octal number: can have * three digits (not counting the * leading 0). Truely burnt. */ c = 0; for (i = 0; i < 3; i++) { if (*s >= '0' && *s <= '7') c = c*8 + *s++ - '0'; else break; } break; case '\0': s--; c = '\\'; break; case '\\': break; default: Xput(xs, xp, '\\'); } } Xput(xs, xp, c); } if (*++wp != NULL) Xput(xs, xp, ' '); } if (flags & PO_NL) Xput(xs, xp, '\n'); if (flags & PO_HIST) { Xput(xs, xp, '\0'); source->line++; histsave(source->line, Xstring(xs, xp), 1); Xfree(xs, xp); } else { int n, len = Xlength(xs, xp);#ifdef KSH int UNINITIALIZED(opipe); /* Ensure we aren't killed by a SIGPIPE while writing to * a coprocess. at&t ksh doesn't seem to do this (seems * to just check that the co-process is alive, which is * not enough). */ if (coproc.write >= 0 && coproc.write == fd) { flags |= PO_COPROC; opipe = block_pipe(); }#endif /* KSH */ for (s = Xstring(xs, xp); len > 0; ) { n = write(fd, s, len); if (n < 0) {#ifdef KSH if (flags & PO_COPROC) restore_pipe(opipe);#endif /* KSH */ if (errno == EINTR) { /* allow user to ^C out */ intrcheck();#ifdef KSH if (flags & PO_COPROC) opipe = block_pipe();#endif /* KSH */ continue; }#ifdef KSH /* This doesn't really make sense - could * break scripts (print -p generates * error message). *if (errno == EPIPE) * coproc_write_close(fd); */#endif /* KSH */ return 1; } s += n; len -= n; }#ifdef KSH if (flags & PO_COPROC) restore_pipe(opipe);#endif /* KSH */ } return 0;}intc_whence(wp) char **wp;{ struct tbl *tp; char *id; int pflag = 0, vflag = 0, Vflag = 0; int ret = 0; int optc; int iam_whence = wp[0][0] == 'w'; int fcflags; const char *options = iam_whence ? "pv" : "pvV"; while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF) switch (optc) { case 'p': pflag = 1; break; case 'v': vflag = 1; break; case 'V': Vflag = 1; break; case '?': return 1; } wp += builtin_opt.optind; fcflags = FC_BI | FC_PATH | FC_FUNC; if (!iam_whence) { /* Note that -p on its own is deal with in comexec() */ if (pflag) fcflags |= FC_DEFPATH; /* Convert command options to whence options - note that * command -pV uses a different path search than whence -v * or whence -pv. This should be considered a feature. */ vflag = Vflag; } if (pflag) fcflags &= ~(FC_BI | FC_FUNC); while ((vflag || ret == 0) && (id = *wp++) != NULL) { tp = NULL; if ((iam_whence || vflag) && !pflag) tp = tsearch(&keywords, id, hash(id));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -