📄 c_sh.c
字号:
* eval shall return an exit status of zero. */ exstat = subst_exstat; } return shell(s, FALSE);}intc_trap(wp) char **wp;{ int i; char *s; register Trap *p; if (ksh_getopt(wp, &builtin_opt, null) == '?') return 1; wp += builtin_opt.optind; if (*wp == NULL) { int anydfl = 0; for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) { if (p->trap == NULL) anydfl = 1; else { shprintf("trap -- "); print_value_quoted(p->trap); shprintf(" %s\n", p->name); } }#if 0 /* this is ugly and not clear POSIX needs it */ /* POSIX may need this so output of trap can be saved and * used to restore trap conditions */ if (anydfl) { shprintf("trap -- -"); for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) if (p->trap == NULL && p->name) shprintf(" %s", p->name); shprintf(newline); }#endif return 0; } /* * Use case sensitive lookup for first arg so the * command 'exit' isn't confused with the pseudo-signal * 'EXIT'. */ s = (gettrap(*wp, FALSE) == NULL) ? *wp++ : NULL; /* get command */ if (s != NULL && s[0] == '-' && s[1] == '\0') s = NULL; /* set/clear traps */ while (*wp != NULL) { p = gettrap(*wp++, TRUE); if (p == NULL) { bi_errorf("bad signal %s", wp[-1]); return 1; } settrap(p, s); } return 0;}intc_exitreturn(wp) char **wp;{ int how = LEXIT; int n; char *arg; if (ksh_getopt(wp, &builtin_opt, null) == '?') return 1; arg = wp[builtin_opt.optind]; if (arg) { if (!getn(arg, &n)) { exstat = 1; warningf(TRUE, "%s: bad number", arg); } else exstat = n; } if (wp[0][0] == 'r') { /* return */ struct env *ep; /* need to tell if this is exit or return so trap exit will * work right (POSIX) */ for (ep = e; ep; ep = ep->oenv) if (STOP_RETURN(ep->type)) { how = LRETURN; break; } } if (how == LEXIT && !really_exit && j_stopped_running()) { really_exit = 1; how = LSHELL; } quitenv(); /* get rid of any i/o redirections */ unwind(how); /*NOTREACHED*/ return 0;}intc_brkcont(wp) char **wp;{ int n, quit; struct env *ep, *last_ep = (struct env *) 0; char *arg; if (ksh_getopt(wp, &builtin_opt, null) == '?') return 1; arg = wp[builtin_opt.optind]; if (!arg) n = 1; else if (!bi_getn(arg, &n)) return 1; quit = n; if (quit <= 0) { /* at&t ksh does this for non-interactive shells only - weird */ bi_errorf("%s: bad value", arg); return 1; } /* Stop at E_NONE, E_PARSE, E_FUNC, or E_INCL */ for (ep = e; ep && !STOP_BRKCONT(ep->type); ep = ep->oenv) if (ep->type == E_LOOP) { if (--quit == 0) break; ep->flags |= EF_BRKCONT_PASS; last_ep = ep; } if (quit) { /* at&t ksh doesn't print a message - just does what it * can. We print a message 'cause it helps in debugging * scripts, but don't generate an error (ie, keep going). */ if (n == quit) { warningf(TRUE, "%s: cannot %s", wp[0], wp[0]); return 0; } /* POSIX says if n is too big, the last enclosing loop * shall be used. Doesn't say to print an error but we * do anyway 'cause the user messed up. */ last_ep->flags &= ~EF_BRKCONT_PASS; warningf(TRUE, "%s: can only %s %d level(s)", wp[0], wp[0], n - quit); } unwind(*wp[0] == 'b' ? LBREAK : LCONTIN); /*NOTREACHED*/}intc_set(wp) char **wp;{ int argi, setargs; struct block *l = e->loc; register char **owp = wp; if (wp[1] == NULL) { static const char *const args [] = { "set", "-", NULL }; return c_typeset((char **) args); } argi = parse_args(wp, OF_SET, &setargs); if (argi < 0) return 1; /* set $# and $* */ if (setargs) { owp = wp += argi - 1; wp[0] = l->argv[0]; /* save $0 */ while (*++wp != NULL) *wp = str_save(*wp, &l->area); l->argc = wp - owp - 1; l->argv = (char **) alloc(sizeofN(char *, l->argc+2), &l->area); for (wp = l->argv; (*wp++ = *owp++) != NULL; ) ; } /* POSIX says set exit status is 0, but old scripts that use * getopt(1), use the construct: set -- `getopt ab:c "$@"` * which assumes the exit value set will be that of the `` * (subst_exstat is cleared in execute() so that it will be 0 * if there are no command substitutions). */ return Flag(FPOSIX) ? 0 : subst_exstat;}intc_unset(wp) char **wp;{ register char *id; int optc, unset_var = 1; int ret = 0; while ((optc = ksh_getopt(wp, &builtin_opt, "fv")) != EOF) switch (optc) { case 'f': unset_var = 0; break; case 'v': unset_var = 1; break; case '?': return 1; } wp += builtin_opt.optind; for (; (id = *wp) != NULL; wp++) if (unset_var) { /* unset variable */ struct tbl *vp = global(id); if (!(vp->flag & ISSET)) ret = 1; if ((vp->flag&RDONLY)) { bi_errorf("%s is read only", vp->name); return 1; } unset(vp, strchr(id, '[') ? 1 : 0); } else { /* unset function */ if (define(id, (struct op *) NULL)) ret = 1; } return ret;}intc_times(wp) char **wp;{ struct tms all; (void) ksh_times(&all); shprintf("Shell: %8ss user ", clocktos(all.tms_utime)); shprintf("%8ss system\n", clocktos(all.tms_stime)); shprintf("Kids: %8ss user ", clocktos(all.tms_cutime)); shprintf("%8ss system\n", clocktos(all.tms_cstime)); return 0;}/* * time pipeline (really a statement, not a built-in command) */inttimex(t, f) struct op *t; int f;{#define TF_NOARGS BIT(0)#define TF_NOREAL BIT(1) /* don't report real time */#define TF_POSIX BIT(2) /* report in posix format */ int rv = 0; struct tms t0, t1, tms; clock_t t0t, t1t = 0; int tf = 0; extern clock_t j_usrtime, j_systime; /* computed by j_wait */ char opts[1]; t0t = ksh_times(&t0); if (t->left) { /* * Two ways of getting cpu usage of a command: just use t0 * and t1 (which will get cpu usage from other jobs that * finish while we are executing t->left), or get the * cpu usage of t->left. at&t ksh does the former, while * pdksh tries to do the later (the j_usrtime hack doesn't * really work as it only counts the last job). */ j_usrtime = j_systime = 0; if (t->left->type == TCOM) t->left->str = opts; opts[0] = 0; rv = execute(t->left, f | XTIME); tf |= opts[0]; t1t = ksh_times(&t1); } else tf = TF_NOARGS; if (tf & TF_NOARGS) { /* ksh93 - report shell times (shell+kids) */ tf |= TF_NOREAL; tms.tms_utime = t0.tms_utime + t0.tms_cutime; tms.tms_stime = t0.tms_stime + t0.tms_cstime; } else { tms.tms_utime = t1.tms_utime - t0.tms_utime + j_usrtime; tms.tms_stime = t1.tms_stime - t0.tms_stime + j_systime; } if (!(tf & TF_NOREAL)) shf_fprintf(shl_out, tf & TF_POSIX ? "real %8s\n" : "%8ss real ", clocktos(t1t - t0t)); shf_fprintf(shl_out, tf & TF_POSIX ? "user %8s\n" : "%8ss user ", clocktos(tms.tms_utime)); shf_fprintf(shl_out, tf & TF_POSIX ? "sys %8s\n" : "%8ss system\n", clocktos(tms.tms_stime)); shf_flush(shl_out); return rv;}voidtimex_hook(t, app) struct op *t; char ** volatile *app;{ char **wp = *app; int optc; int i, j; Getopt opt; ksh_getopt_reset(&opt, 0); opt.optind = 0; /* start at the start */ while ((optc = ksh_getopt(wp, &opt, ":p")) != EOF) switch (optc) { case 'p': t->str[0] |= TF_POSIX; break; case '?': errorf("time: -%s unknown option", opt.optarg); case ':': errorf("time: -%s requires an argument", opt.optarg); } /* Copy command words down over options. */ if (opt.optind != 0) { for (i = 0; i < opt.optind; i++) afree(wp[i], ATEMP); for (i = 0, j = opt.optind; (wp[i] = wp[j]); i++, j++) ; } if (!wp[0]) t->str[0] |= TF_NOARGS; *app = wp;}static char *clocktos(t) clock_t t;{ static char temp[22]; /* enough for 64 bit clock_t */ register int i; register char *cp = temp + sizeof(temp); /* note: posix says must use max precision, ie, if clk_tck is * 1000, must print 3 places after decimal (if non-zero, else 1). */ if (CLK_TCK != 100) /* convert to 1/100'ths */ t = (t < 1000000000/CLK_TCK) ? (t * 100) / CLK_TCK : (t / CLK_TCK) * 100; *--cp = '\0'; for (i = -2; i <= 0 || t > 0; i++) { if (i == 0) *--cp = '.'; *--cp = '0' + (char)(t%10); t /= 10; } return cp;}/* exec with no args - args case is taken care of in comexec() */intc_exec(wp) char ** wp;{ int i; /* make sure redirects stay in place */ if (e->savefd != NULL) { for (i = 0; i < NUFILE; i++) { if (e->savefd[i] > 0) close(e->savefd[i]); /* * For ksh keep anything > 2 private, * for sh, let them be (POSIX says what * happens is unspecified and the bourne shell * keeps them open). */#ifdef KSH if (i > 2 && e->savefd[i]) fd_clexec(i);#endif /* KSH */ } e->savefd = NULL; } return 0;}/* dummy function, special case in comexec() */intc_builtin(wp) char ** wp;{ return 0;}extern int c_test ARGS((char **wp)); /* in c_test.c */extern int c_ulimit ARGS((char **wp)); /* in c_ulimit.c *//* A leading = means assignments before command are kept; * a leading * means a POSIX special builtin; * a leading + means a POSIX regular builtin * (* and + should not be combined). */const struct builtin shbuiltins [] = { {"*=.", c_dot}, {"*=:", c_label}, {"[", c_test}, {"*=break", c_brkcont}, {"=builtin", c_builtin}, {"*=continue", c_brkcont}, {"*=eval", c_eval}, {"*=exec", c_exec}, {"*=exit", c_exitreturn}, {"+false", c_label}, {"*=return", c_exitreturn}, {"*=set", c_set}, {"*=shift", c_shift}, {"=times", c_times}, {"*=trap", c_trap}, {"+=wait", c_wait}, {"+read", c_read}, {"test", c_test}, {"+true", c_label}, {"ulimit", c_ulimit}, {"+umask", c_umask}, {"*=unset", c_unset},#ifdef OS2 /* In OS2, the first line of a file can be "extproc name", which * tells the command interpreter (cmd.exe) to use name to execute * the file. For this to be useful, ksh must ignore commands * starting with extproc and this does the trick... */ {"extproc", c_label},#endif /* OS2 */ {NULL, NULL}};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -