1 /* $NetBSD: c_sh.c,v 1.4 2001/02/04 19:26:04 christos Exp $ */ 2 3 /* 4 * built-in Bourne commands 5 */ 6 7 #include "sh.h" 8 #include "ksh_stat.h" /* umask() */ 9 #include "ksh_time.h" 10 #include "ksh_times.h" 11 12 static char *clocktos ARGS((clock_t t)); 13 extern clock_t j_usrtime, j_systime; /* computed by j_wait */ 14 15 16 /* :, false and true */ 17 int 18 c_label(wp) 19 char **wp; 20 { 21 return wp[0][0] == 'f' ? 1 : 0; 22 } 23 24 int 25 c_shift(wp) 26 char **wp; 27 { 28 register struct block *l = e->loc; 29 register int n; 30 long val; 31 char *arg; 32 33 if (ksh_getopt(wp, &builtin_opt, null) == '?') 34 return 1; 35 arg = wp[builtin_opt.optind]; 36 37 if (arg) { 38 evaluate(arg, &val, KSH_UNWIND_ERROR); 39 n = val; 40 } else 41 n = 1; 42 if (n < 0) { 43 bi_errorf("%s: bad number", arg); 44 return (1); 45 } 46 if (l->argc < n) { 47 bi_errorf("nothing to shift"); 48 return (1); 49 } 50 l->argv[n] = l->argv[0]; 51 l->argv += n; 52 l->argc -= n; 53 return 0; 54 } 55 56 int 57 c_umask(wp) 58 char **wp; 59 { 60 register int i; 61 register char *cp; 62 int symbolic = 0; 63 int old_umask; 64 int optc; 65 66 while ((optc = ksh_getopt(wp, &builtin_opt, "S")) != EOF) 67 switch (optc) { 68 case 'S': 69 symbolic = 1; 70 break; 71 case '?': 72 return 1; 73 } 74 cp = wp[builtin_opt.optind]; 75 if (cp == NULL) { 76 old_umask = umask(0); 77 umask(old_umask); 78 if (symbolic) { 79 char buf[18]; 80 int j; 81 82 old_umask = ~old_umask; 83 cp = buf; 84 for (i = 0; i < 3; i++) { 85 *cp++ = "ugo"[i]; 86 *cp++ = '='; 87 for (j = 0; j < 3; j++) 88 if (old_umask & (1 << (8 - (3*i + j)))) 89 *cp++ = "rwx"[j]; 90 *cp++ = ','; 91 } 92 cp[-1] = '\0'; 93 shprintf("%s\n", buf); 94 } else 95 shprintf("%#3.3o\n", old_umask); 96 } else { 97 int new_umask; 98 99 if (digit(*cp)) { 100 for (new_umask = 0; *cp >= '0' && *cp <= '7'; cp++) 101 new_umask = new_umask * 8 + (*cp - '0'); 102 if (*cp) { 103 bi_errorf("bad number"); 104 return 1; 105 } 106 } else { 107 /* symbolic format */ 108 int positions, new_val; 109 char op; 110 111 old_umask = umask(0); 112 umask(old_umask); /* in case of error */ 113 old_umask = ~old_umask; 114 new_umask = old_umask; 115 positions = 0; 116 while (*cp) { 117 while (*cp && strchr("augo", *cp)) 118 switch (*cp++) { 119 case 'a': positions |= 0111; break; 120 case 'u': positions |= 0100; break; 121 case 'g': positions |= 0010; break; 122 case 'o': positions |= 0001; break; 123 } 124 if (!positions) 125 positions = 0111; /* default is a */ 126 if (!strchr("=+-", op = *cp)) 127 break; 128 cp++; 129 new_val = 0; 130 while (*cp && strchr("rwxugoXs", *cp)) 131 switch (*cp++) { 132 case 'r': new_val |= 04; break; 133 case 'w': new_val |= 02; break; 134 case 'x': new_val |= 01; break; 135 case 'u': new_val |= old_umask >> 6; 136 break; 137 case 'g': new_val |= old_umask >> 3; 138 break; 139 case 'o': new_val |= old_umask >> 0; 140 break; 141 case 'X': if (old_umask & 0111) 142 new_val |= 01; 143 break; 144 case 's': /* ignored */ 145 break; 146 } 147 new_val = (new_val & 07) * positions; 148 switch (op) { 149 case '-': 150 new_umask &= ~new_val; 151 break; 152 case '=': 153 new_umask = new_val 154 | (new_umask & ~(positions * 07)); 155 break; 156 case '+': 157 new_umask |= new_val; 158 } 159 if (*cp == ',') { 160 positions = 0; 161 cp++; 162 } else if (!strchr("=+-", *cp)) 163 break; 164 } 165 if (*cp) { 166 bi_errorf("bad mask"); 167 return 1; 168 } 169 new_umask = ~new_umask; 170 } 171 umask(new_umask); 172 } 173 return 0; 174 } 175 176 int 177 c_dot(wp) 178 char **wp; 179 { 180 char *file, *cp; 181 char **argv; 182 int argc; 183 int i; 184 int err; 185 186 if (ksh_getopt(wp, &builtin_opt, null) == '?') 187 return 1; 188 189 if ((cp = wp[builtin_opt.optind]) == NULL) 190 return 0; 191 file = search(cp, path, R_OK, &err); 192 if (file == NULL) { 193 bi_errorf("%s: %s", cp, err ? strerror(err) : "not found"); 194 return 1; 195 } 196 197 /* Set positional parameters? */ 198 if (wp[builtin_opt.optind + 1]) { 199 argv = wp + builtin_opt.optind; 200 argv[0] = e->loc->argv[0]; /* preserve $0 */ 201 for (argc = 0; argv[argc + 1]; argc++) 202 ; 203 } else { 204 argc = 0; 205 argv = (char **) 0; 206 } 207 i = include(file, argc, argv, 0); 208 if (i < 0) { /* should not happen */ 209 bi_errorf("%s: %s", cp, strerror(errno)); 210 return 1; 211 } 212 return i; 213 } 214 215 int 216 c_wait(wp) 217 char **wp; 218 { 219 int UNINITIALIZED(rv); 220 int sig; 221 222 if (ksh_getopt(wp, &builtin_opt, null) == '?') 223 return 1; 224 wp += builtin_opt.optind; 225 if (*wp == (char *) 0) { 226 while (waitfor((char *) 0, &sig) >= 0) 227 ; 228 rv = sig; 229 } else { 230 for (; *wp; wp++) 231 rv = waitfor(*wp, &sig); 232 if (rv < 0) 233 rv = sig ? sig : 127; /* magic exit code: bad job-id */ 234 } 235 return rv; 236 } 237 238 int 239 c_read(wp) 240 char **wp; 241 { 242 register int c = 0; 243 int expand = 1, history = 0; 244 int expanding; 245 int ecode = 0; 246 register char *cp; 247 int fd = 0; 248 struct shf *shf; 249 int optc; 250 const char *emsg; 251 XString cs, xs; 252 struct tbl *vp; 253 char UNINITIALIZED(*xp); 254 255 while ((optc = ksh_getopt(wp, &builtin_opt, "prsu,")) != EOF) 256 switch (optc) { 257 #ifdef KSH 258 case 'p': 259 if ((fd = coproc_getfd(R_OK, &emsg)) < 0) { 260 bi_errorf("-p: %s", emsg); 261 return 1; 262 } 263 break; 264 #endif /* KSH */ 265 case 'r': 266 expand = 0; 267 break; 268 case 's': 269 history = 1; 270 break; 271 case 'u': 272 if (!*(cp = builtin_opt.optarg)) 273 fd = 0; 274 else if ((fd = check_fd(cp, R_OK, &emsg)) < 0) { 275 bi_errorf("-u: %s: %s", cp, emsg); 276 return 1; 277 } 278 break; 279 case '?': 280 return 1; 281 } 282 wp += builtin_opt.optind; 283 284 if (*wp == NULL) 285 *--wp = "REPLY"; 286 287 /* Since we can't necessarily seek backwards on non-regular files, 288 * don't buffer them so we can't read too much. 289 */ 290 shf = shf_reopen(fd, SHF_RD | SHF_INTERRUPT | can_seek(fd), shl_spare); 291 292 if ((cp = strchr(*wp, '?')) != NULL) { 293 *cp = 0; 294 if (isatty(fd)) { 295 /* at&t ksh says it prints prompt on fd if it's open 296 * for writing and is a tty, but it doesn't do it 297 * (it also doesn't check the interactive flag, 298 * as is indicated in the Kornshell book). 299 */ 300 shellf("%s", cp+1); 301 } 302 } 303 304 #ifdef KSH 305 /* If we are reading from the co-process for the first time, 306 * make sure the other side of the pipe is closed first. This allows 307 * the detection of eof. 308 * 309 * This is not compatiable with at&t ksh... the fd is kept so another 310 * coproc can be started with same ouput, however, this means eof 311 * can't be detected... This is why it is closed here. 312 * If this call is removed, remove the eof check below, too. 313 * coproc_readw_close(fd); 314 */ 315 #endif /* KSH */ 316 317 if (history) 318 Xinit(xs, xp, 128, ATEMP); 319 expanding = 0; 320 Xinit(cs, cp, 128, ATEMP); 321 for (; *wp != NULL; wp++) { 322 for (cp = Xstring(cs, cp); ; ) { 323 if (c == '\n' || c == EOF) 324 break; 325 while (1) { 326 c = shf_getc(shf); 327 if (c == '\0' 328 #ifdef OS2 329 || c == '\r' 330 #endif /* OS2 */ 331 ) 332 continue; 333 if (c == EOF && shf_error(shf) 334 && shf_errno(shf) == EINTR) 335 { 336 /* Was the offending signal one that 337 * would normally kill a process? 338 * If so, pretend the read was killed. 339 */ 340 ecode = fatal_trap_check(); 341 342 /* non fatal (eg, CHLD), carry on */ 343 if (!ecode) { 344 shf_clearerr(shf); 345 continue; 346 } 347 } 348 break; 349 } 350 if (history) { 351 Xcheck(xs, xp); 352 Xput(xs, xp, c); 353 } 354 Xcheck(cs, cp); 355 if (expanding) { 356 expanding = 0; 357 if (c == '\n') { 358 c = 0; 359 if (Flag(FTALKING_I) && isatty(fd)) { 360 /* set prompt in case this is 361 * called from .profile or $ENV 362 */ 363 set_prompt(PS2, (Source *) 0); 364 pprompt(prompt, 0); 365 } 366 } else if (c != EOF) 367 Xput(cs, cp, c); 368 continue; 369 } 370 if (expand && c == '\\') { 371 expanding = 1; 372 continue; 373 } 374 if (c == '\n' || c == EOF) 375 break; 376 if (ctype(c, C_IFS)) { 377 if (Xlength(cs, cp) == 0 && ctype(c, C_IFSWS)) 378 continue; 379 if (wp[1]) 380 break; 381 } 382 Xput(cs, cp, c); 383 } 384 /* strip trailing IFS white space from last variable */ 385 if (!wp[1]) 386 while (Xlength(cs, cp) && ctype(cp[-1], C_IFS) 387 && ctype(cp[-1], C_IFSWS)) 388 cp--; 389 Xput(cs, cp, '\0'); 390 vp = global(*wp); 391 /* Must be done before setting export. */ 392 if (vp->flag & RDONLY) { 393 shf_flush(shf); 394 bi_errorf("%s is read only", *wp); 395 return 1; 396 } 397 if (Flag(FEXPORT)) 398 typeset(*wp, EXPORT, 0, 0, 0); 399 if (!setstr(vp, Xstring(cs, cp), KSH_RETURN_ERROR)) { 400 shf_flush(shf); 401 return 1; 402 } 403 } 404 405 shf_flush(shf); 406 if (history) { 407 Xput(xs, xp, '\0'); 408 source->line++; 409 histsave(source->line, Xstring(xs, xp), 1); 410 Xfree(xs, xp); 411 } 412 #ifdef KSH 413 /* if this is the co-process fd, close the file descriptor 414 * (can get eof if and only if all processes are have died, ie, 415 * coproc.njobs is 0 and the pipe is closed). 416 */ 417 if (c == EOF && !ecode) 418 coproc_read_close(fd); 419 #endif /* KSH */ 420 421 return ecode ? ecode : c == EOF; 422 } 423 424 int 425 c_eval(wp) 426 char **wp; 427 { 428 register struct source *s; 429 430 if (ksh_getopt(wp, &builtin_opt, null) == '?') 431 return 1; 432 s = pushs(SWORDS, ATEMP); 433 s->u.strv = wp + builtin_opt.optind; 434 if (!Flag(FPOSIX)) { 435 /* 436 * Handle case where the command is empty due to failed 437 * command substitution, eg, eval "$(false)". 438 * In this case, shell() will not set/change exstat (because 439 * compiled tree is empty), so will use this value. 440 * subst_exstat is cleared in execute(), so should be 0 if 441 * there were no substitutions. 442 * 443 * A strict reading of POSIX says we don't do this (though 444 * it is traditionally done). [from 1003.2-1992] 445 * 3.9.1: Simple Commands 446 * ... If there is a command name, execution shall 447 * continue as described in 3.9.1.1. If there 448 * is no command name, but the command contained a command 449 * substitution, the command shall complete with the exit 450 * status of the last command substitution 451 * 3.9.1.1: Command Search and Execution 452 * ...(1)...(a) If the command name matches the name of 453 * a special built-in utility, that special built-in 454 * utility shall be invoked. 455 * 3.14.5: Eval 456 * ... If there are no arguments, or only null arguments, 457 * eval shall return an exit status of zero. 458 */ 459 exstat = subst_exstat; 460 } 461 462 return shell(s, FALSE); 463 } 464 465 int 466 c_trap(wp) 467 char **wp; 468 { 469 int i; 470 char *s; 471 register Trap *p; 472 473 if (ksh_getopt(wp, &builtin_opt, null) == '?') 474 return 1; 475 wp += builtin_opt.optind; 476 477 if (*wp == NULL) { 478 int anydfl = 0; 479 480 for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) { 481 if (p->trap == NULL) 482 anydfl = 1; 483 else { 484 shprintf("trap -- "); 485 print_value_quoted(p->trap); 486 shprintf(" %s\n", p->name); 487 } 488 } 489 #if 0 /* this is ugly and not clear POSIX needs it */ 490 /* POSIX may need this so output of trap can be saved and 491 * used to restore trap conditions 492 */ 493 if (anydfl) { 494 shprintf("trap -- -"); 495 for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) 496 if (p->trap == NULL && p->name) 497 shprintf(" %s", p->name); 498 shprintf(newline); 499 } 500 #endif 501 return 0; 502 } 503 504 /* 505 * Use case sensitive lookup for first arg so the 506 * command 'exit' isn't confused with the pseudo-signal 507 * 'EXIT'. 508 */ 509 s = (gettrap(*wp, FALSE) == NULL) ? *wp++ : NULL; /* get command */ 510 if (s != NULL && s[0] == '-' && s[1] == '\0') 511 s = NULL; 512 513 /* set/clear traps */ 514 while (*wp != NULL) { 515 p = gettrap(*wp++, TRUE); 516 if (p == NULL) { 517 bi_errorf("bad signal %s", wp[-1]); 518 return 1; 519 } 520 settrap(p, s); 521 } 522 return 0; 523 } 524 525 int 526 c_exitreturn(wp) 527 char **wp; 528 { 529 int how = LEXIT; 530 int n; 531 char *arg; 532 533 if (ksh_getopt(wp, &builtin_opt, null) == '?') 534 return 1; 535 arg = wp[builtin_opt.optind]; 536 537 if (arg) { 538 if (!getn(arg, &n)) { 539 exstat = 1; 540 warningf(TRUE, "%s: bad number", arg); 541 } else 542 exstat = n; 543 } 544 if (wp[0][0] == 'r') { /* return */ 545 struct env *ep; 546 547 /* need to tell if this is exit or return so trap exit will 548 * work right (POSIX) 549 */ 550 for (ep = e; ep; ep = ep->oenv) 551 if (STOP_RETURN(ep->type)) { 552 how = LRETURN; 553 break; 554 } 555 } 556 557 if (how == LEXIT && !really_exit && j_stopped_running()) { 558 really_exit = 1; 559 how = LSHELL; 560 } 561 562 quitenv(); /* get rid of any i/o redirections */ 563 unwind(how); 564 /*NOTREACHED*/ 565 return 0; 566 } 567 568 int 569 c_brkcont(wp) 570 char **wp; 571 { 572 int n, quit; 573 struct env *ep, *last_ep = (struct env *) 0; 574 char *arg; 575 576 if (ksh_getopt(wp, &builtin_opt, null) == '?') 577 return 1; 578 arg = wp[builtin_opt.optind]; 579 580 if (!arg) 581 n = 1; 582 else if (!bi_getn(arg, &n)) 583 return 1; 584 quit = n; 585 if (quit <= 0) { 586 /* at&t ksh does this for non-interactive shells only - weird */ 587 bi_errorf("%s: bad value", arg); 588 return 1; 589 } 590 591 /* Stop at E_NONE, E_PARSE, E_FUNC, or E_INCL */ 592 for (ep = e; ep && !STOP_BRKCONT(ep->type); ep = ep->oenv) 593 if (ep->type == E_LOOP) { 594 if (--quit == 0) 595 break; 596 ep->flags |= EF_BRKCONT_PASS; 597 last_ep = ep; 598 } 599 600 if (quit) { 601 /* at&t ksh doesn't print a message - just does what it 602 * can. We print a message 'cause it helps in debugging 603 * scripts, but don't generate an error (ie, keep going). 604 */ 605 if (n == quit) { 606 warningf(TRUE, "%s: cannot %s", wp[0], wp[0]); 607 return 0; 608 } 609 /* POSIX says if n is too big, the last enclosing loop 610 * shall be used. Doesn't say to print an error but we 611 * do anyway 'cause the user messed up. 612 */ 613 last_ep->flags &= ~EF_BRKCONT_PASS; 614 warningf(TRUE, "%s: can only %s %d level(s)", 615 wp[0], wp[0], n - quit); 616 } 617 618 unwind(*wp[0] == 'b' ? LBREAK : LCONTIN); 619 /*NOTREACHED*/ 620 } 621 622 int 623 c_set(wp) 624 char **wp; 625 { 626 int argi, setargs; 627 struct block *l = e->loc; 628 register char **owp = wp; 629 630 if (wp[1] == NULL) { 631 static const char *const args [] = { "set", "-", NULL }; 632 return c_typeset((char **) args); 633 } 634 635 argi = parse_args(wp, OF_SET, &setargs); 636 if (argi < 0) 637 return 1; 638 /* set $# and $* */ 639 if (setargs) { 640 owp = wp += argi - 1; 641 wp[0] = l->argv[0]; /* save $0 */ 642 while (*++wp != NULL) 643 *wp = str_save(*wp, &l->area); 644 l->argc = wp - owp - 1; 645 l->argv = (char **) alloc(sizeofN(char *, l->argc+2), &l->area); 646 for (wp = l->argv; (*wp++ = *owp++) != NULL; ) 647 ; 648 } 649 /* POSIX says set exit status is 0, but old scripts that use 650 * getopt(1), use the construct: set -- `getopt ab:c "$@"` 651 * which assumes the exit value set will be that of the `` 652 * (subst_exstat is cleared in execute() so that it will be 0 653 * if there are no command substitutions). 654 */ 655 return Flag(FPOSIX) ? 0 : subst_exstat; 656 } 657 658 int 659 c_unset(wp) 660 char **wp; 661 { 662 register char *id; 663 int optc, unset_var = 1; 664 int ret = 0; 665 666 while ((optc = ksh_getopt(wp, &builtin_opt, "fv")) != EOF) 667 switch (optc) { 668 case 'f': 669 unset_var = 0; 670 break; 671 case 'v': 672 unset_var = 1; 673 break; 674 case '?': 675 return 1; 676 } 677 wp += builtin_opt.optind; 678 for (; (id = *wp) != NULL; wp++) 679 if (unset_var) { /* unset variable */ 680 struct tbl *vp = global(id); 681 682 if (!(vp->flag & ISSET)) 683 ret = 1; 684 if ((vp->flag&RDONLY)) { 685 bi_errorf("%s is read only", vp->name); 686 return 1; 687 } 688 unset(vp, strchr(id, '[') ? 1 : 0); 689 } else { /* unset function */ 690 if (define(id, (struct op *) NULL)) 691 ret = 1; 692 } 693 return ret; 694 } 695 696 int 697 c_times(wp) 698 char **wp; 699 { 700 struct tms all; 701 702 (void) ksh_times(&all); 703 shprintf("Shell: %8ss user ", clocktos(all.tms_utime)); 704 shprintf("%8ss system\n", clocktos(all.tms_stime)); 705 shprintf("Kids: %8ss user ", clocktos(all.tms_cutime)); 706 shprintf("%8ss system\n", clocktos(all.tms_cstime)); 707 708 return 0; 709 } 710 711 /* 712 * time pipeline (really a statement, not a built-in command) 713 */ 714 int 715 timex(t, f) 716 struct op *t; 717 int f; 718 { 719 #define TF_NOARGS BIT(0) 720 #define TF_NOREAL BIT(1) /* don't report real time */ 721 #define TF_POSIX BIT(2) /* report in posix format */ 722 int rv = 0; 723 struct tms t0, t1, tms; 724 clock_t t0t, t1t = 0; 725 int tf = 0; 726 char opts[1]; 727 728 t0t = ksh_times(&t0); 729 if (t->left) { 730 /* 731 * Two ways of getting cpu usage of a command: just use t0 732 * and t1 (which will get cpu usage from other jobs that 733 * finish while we are executing t->left), or get the 734 * cpu usage of t->left. at&t ksh does the former, while 735 * pdksh tries to do the later (the j_usrtime hack doesn't 736 * really work as it only counts the last job). 737 */ 738 j_usrtime = j_systime = 0; 739 if (t->left->type == TCOM) 740 t->left->str = opts; 741 opts[0] = 0; 742 rv = execute(t->left, f | XTIME); 743 tf |= opts[0]; 744 t1t = ksh_times(&t1); 745 } else 746 tf = TF_NOARGS; 747 748 if (tf & TF_NOARGS) { /* ksh93 - report shell times (shell+kids) */ 749 tf |= TF_NOREAL; 750 tms.tms_utime = t0.tms_utime + t0.tms_cutime; 751 tms.tms_stime = t0.tms_stime + t0.tms_cstime; 752 } else { 753 tms.tms_utime = t1.tms_utime - t0.tms_utime + j_usrtime; 754 tms.tms_stime = t1.tms_stime - t0.tms_stime + j_systime; 755 } 756 757 if (!(tf & TF_NOREAL)) 758 shf_fprintf(shl_out, 759 tf & TF_POSIX ? "real %8s\n" : "%8ss real ", 760 clocktos(t1t - t0t)); 761 shf_fprintf(shl_out, tf & TF_POSIX ? "user %8s\n" : "%8ss user ", 762 clocktos(tms.tms_utime)); 763 shf_fprintf(shl_out, tf & TF_POSIX ? "sys %8s\n" : "%8ss system\n", 764 clocktos(tms.tms_stime)); 765 shf_flush(shl_out); 766 767 return rv; 768 } 769 770 void 771 timex_hook(t, app) 772 struct op *t; 773 char ** volatile *app; 774 { 775 char **wp = *app; 776 int optc; 777 int i, j; 778 Getopt opt; 779 780 ksh_getopt_reset(&opt, 0); 781 opt.optind = 0; /* start at the start */ 782 while ((optc = ksh_getopt(wp, &opt, ":p")) != EOF) 783 switch (optc) { 784 case 'p': 785 t->str[0] |= TF_POSIX; 786 break; 787 case '?': 788 errorf("time: -%s unknown option", opt.optarg); 789 case ':': 790 errorf("time: -%s requires an argument", 791 opt.optarg); 792 } 793 /* Copy command words down over options. */ 794 if (opt.optind != 0) { 795 for (i = 0; i < opt.optind; i++) 796 afree(wp[i], ATEMP); 797 for (i = 0, j = opt.optind; (wp[i] = wp[j]); i++, j++) 798 ; 799 } 800 if (!wp[0]) 801 t->str[0] |= TF_NOARGS; 802 *app = wp; 803 } 804 805 static char * 806 clocktos(t) 807 clock_t t; 808 { 809 static char temp[22]; /* enough for 64 bit clock_t */ 810 register int i; 811 register char *cp = temp + sizeof(temp); 812 813 /* note: posix says must use max precision, ie, if clk_tck is 814 * 1000, must print 3 places after decimal (if non-zero, else 1). 815 */ 816 if (CLK_TCK != 100) /* convert to 1/100'ths */ 817 t = (t < 1000000000/CLK_TCK) ? 818 (t * 100) / CLK_TCK : (t / CLK_TCK) * 100; 819 820 *--cp = '\0'; 821 for (i = -2; i <= 0 || t > 0; i++) { 822 if (i == 0) 823 *--cp = '.'; 824 *--cp = '0' + (char)(t%10); 825 t /= 10; 826 } 827 return cp; 828 } 829 830 /* exec with no args - args case is taken care of in comexec() */ 831 int 832 c_exec(wp) 833 char ** wp; 834 { 835 int i; 836 837 /* make sure redirects stay in place */ 838 if (e->savefd != NULL) { 839 for (i = 0; i < NUFILE; i++) { 840 if (e->savefd[i] > 0) 841 close(e->savefd[i]); 842 /* 843 * For ksh keep anything > 2 private, 844 * for sh, let them be (POSIX says what 845 * happens is unspecified and the bourne shell 846 * keeps them open). 847 */ 848 #ifdef KSH 849 if (i > 2 && e->savefd[i]) 850 fd_clexec(i); 851 #endif /* KSH */ 852 } 853 e->savefd = NULL; 854 } 855 return 0; 856 } 857 858 /* dummy function, special case in comexec() */ 859 int 860 c_builtin(wp) 861 char ** wp; 862 { 863 return 0; 864 } 865 866 /* A leading = means assignments before command are kept; 867 * a leading * means a POSIX special builtin; 868 * a leading + means a POSIX regular builtin 869 * (* and + should not be combined). 870 */ 871 const struct builtin shbuiltins [] = { 872 {"*=.", c_dot}, 873 {"*=:", c_label}, 874 {"[", c_test}, 875 {"*=break", c_brkcont}, 876 {"=builtin", c_builtin}, 877 {"*=continue", c_brkcont}, 878 {"*=eval", c_eval}, 879 {"*=exec", c_exec}, 880 {"*=exit", c_exitreturn}, 881 {"+false", c_label}, 882 {"*=return", c_exitreturn}, 883 {"*=set", c_set}, 884 {"*=shift", c_shift}, 885 {"=times", c_times}, 886 {"*=trap", c_trap}, 887 {"+=wait", c_wait}, 888 {"+read", c_read}, 889 {"test", c_test}, 890 {"+true", c_label}, 891 {"ulimit", c_ulimit}, 892 {"+umask", c_umask}, 893 {"*=unset", c_unset}, 894 #ifdef OS2 895 /* In OS2, the first line of a file can be "extproc name", which 896 * tells the command interpreter (cmd.exe) to use name to execute 897 * the file. For this to be useful, ksh must ignore commands 898 * starting with extproc and this does the trick... 899 */ 900 {"extproc", c_label}, 901 #endif /* OS2 */ 902 {NULL, NULL} 903 }; 904