1 /* $Header: /src/pub/tcsh/sh.func.c,v 3.93 2001/03/13 12:53:50 christos Exp $ */ 2 /* 3 * sh.func.c: csh builtin functions 4 */ 5 /*- 6 * Copyright (c) 1980, 1991 The Regents of the University of California. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the University of 20 * California, Berkeley and its contributors. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 #include "sh.h" 38 39 RCSID("$Id: sh.func.c,v 3.93 2001/03/13 12:53:50 christos Exp $") 40 41 #include "ed.h" 42 #include "tw.h" 43 #include "tc.h" 44 #ifdef WINNT_NATIVE 45 #include "nt.const.h" 46 #endif /* WINNT_NATIVE */ 47 48 /* 49 * C shell 50 */ 51 extern int just_signaled; 52 extern char **environ; 53 54 extern bool MapsAreInited; 55 extern bool NLSMapsAreInited; 56 extern bool NoNLSRebind; 57 extern bool GotTermCaps; 58 59 static int zlast = -1; 60 61 static void islogin __P((void)); 62 static void preread __P((void)); 63 static void doagain __P((void)); 64 static char *isrchx __P((int)); 65 static void search __P((int, int, Char *)); 66 static int getword __P((Char *)); 67 static void toend __P((void)); 68 static void xecho __P((int, Char **)); 69 static bool islocale_var __P((Char *)); 70 71 struct biltins * 72 isbfunc(t) 73 struct command *t; 74 { 75 register Char *cp = t->t_dcom[0]; 76 register struct biltins *bp, *bp1, *bp2; 77 static struct biltins label = {"", dozip, 0, 0}; 78 static struct biltins foregnd = {"%job", dofg1, 0, 0}; 79 static struct biltins backgnd = {"%job &", dobg1, 0, 0}; 80 81 /* 82 * We never match a builtin that has quoted the first 83 * character; this has been the traditional way to escape 84 * builtin commands. 85 */ 86 if (*cp & QUOTE) 87 return NULL; 88 89 if (*cp != ':' && lastchr(cp) == ':') { 90 label.bname = short2str(cp); 91 return (&label); 92 } 93 if (*cp == '%') { 94 if (t->t_dflg & F_AMPERSAND) { 95 t->t_dflg &= ~F_AMPERSAND; 96 backgnd.bname = short2str(cp); 97 return (&backgnd); 98 } 99 foregnd.bname = short2str(cp); 100 return (&foregnd); 101 } 102 #ifdef WARP 103 /* 104 * This is a perhaps kludgy way to determine if the warp builtin is to be 105 * acknowledged or not. If checkwarp() fails, then we are to assume that 106 * the warp command is invalid, and carry on as we would handle any other 107 * non-builtin command. -- JDK 2/4/88 108 */ 109 if (eq(STRwarp, cp) && !checkwarp()) { 110 return (0); /* this builtin disabled */ 111 } 112 #endif /* WARP */ 113 /* 114 * Binary search Bp1 is the beginning of the current search range. Bp2 is 115 * one past the end. 116 */ 117 for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) { 118 int i; 119 120 bp = bp1 + ((bp2 - bp1) >> 1); 121 if ((i = ((char) *cp) - *bp->bname) == 0 && 122 (i = StrQcmp(cp, str2short(bp->bname))) == 0) 123 return bp; 124 if (i < 0) 125 bp2 = bp; 126 else 127 bp1 = bp + 1; 128 } 129 #ifdef WINNT_NATIVE 130 return nt_check_additional_builtins(cp); 131 #endif /*WINNT_NATIVE*/ 132 return (0); 133 } 134 135 void 136 func(t, bp) 137 register struct command *t; 138 register struct biltins *bp; 139 { 140 int i; 141 142 xechoit(t->t_dcom); 143 setname(bp->bname); 144 i = blklen(t->t_dcom) - 1; 145 if (i < bp->minargs) 146 stderror(ERR_NAME | ERR_TOOFEW); 147 if (i > bp->maxargs) 148 stderror(ERR_NAME | ERR_TOOMANY); 149 (*bp->bfunct) (t->t_dcom, t); 150 } 151 152 /*ARGSUSED*/ 153 void 154 doonintr(v, c) 155 Char **v; 156 struct command *c; 157 { 158 register Char *cp; 159 register Char *vv = v[1]; 160 161 USE(c); 162 if (parintr == SIG_IGN) 163 return; 164 if (setintr && intty) 165 stderror(ERR_NAME | ERR_TERMINAL); 166 cp = gointr; 167 gointr = 0; 168 xfree((ptr_t) cp); 169 if (vv == 0) { 170 #ifdef BSDSIGS 171 if (setintr) { 172 (void) sigblock(sigmask(SIGINT)); 173 (void) signal(SIGINT, pintr); 174 } 175 else 176 (void) signal(SIGINT, SIG_DFL); 177 #else /* !BSDSIGS */ 178 if (setintr) { 179 (void) sighold(SIGINT); 180 (void) sigset(SIGINT, pintr); 181 } 182 else 183 (void) sigset(SIGINT, SIG_DFL); 184 #endif /* BSDSIGS */ 185 gointr = 0; 186 } 187 else if (eq((vv = strip(vv)), STRminus)) { 188 #ifdef BSDSIGS 189 (void) signal(SIGINT, SIG_IGN); 190 #else /* !BSDSIGS */ 191 (void) sigset(SIGINT, SIG_IGN); 192 #endif /* BSDSIGS */ 193 gointr = Strsave(STRminus); 194 } 195 else { 196 gointr = Strsave(vv); 197 #ifdef BSDSIGS 198 (void) signal(SIGINT, pintr); 199 #else /* !BSDSIGS */ 200 (void) sigset(SIGINT, pintr); 201 #endif /* BSDSIGS */ 202 } 203 } 204 205 /*ARGSUSED*/ 206 void 207 donohup(v, c) 208 Char **v; 209 struct command *c; 210 { 211 USE(c); 212 USE(v); 213 if (intty) 214 stderror(ERR_NAME | ERR_TERMINAL); 215 if (setintr == 0) { 216 (void) signal(SIGHUP, SIG_IGN); 217 #ifdef CC 218 submit(getpid()); 219 #endif /* CC */ 220 } 221 } 222 223 /*ARGSUSED*/ 224 void 225 dohup(v, c) 226 Char **v; 227 struct command *c; 228 { 229 USE(c); 230 USE(v); 231 if (intty) 232 stderror(ERR_NAME | ERR_TERMINAL); 233 if (setintr == 0) 234 (void) signal(SIGHUP, SIG_DFL); 235 } 236 237 238 /*ARGSUSED*/ 239 void 240 dozip(v, c) 241 Char **v; 242 struct command *c; 243 { 244 USE(c); 245 USE(v); 246 } 247 248 /*ARGSUSED*/ 249 void 250 dofiletest(v, c) 251 Char **v; 252 struct command *c; 253 { 254 Char **fileptr, *ftest, *res; 255 256 if (*(ftest = *++v) != '-') 257 stderror(ERR_NAME | ERR_FILEINQ); 258 ++v; 259 260 gflag = 0; 261 tglob(v); 262 if (gflag) { 263 v = globall(v); 264 if (v == 0) 265 stderror(ERR_NAME | ERR_NOMATCH); 266 } 267 else 268 v = gargv = saveblk(v); 269 trim(v); 270 271 while (*(fileptr = v++) != '\0') { 272 xprintf("%S", res = filetest(ftest, &fileptr, 0)); 273 xfree((ptr_t) res); 274 if (*v) 275 xprintf(" "); 276 } 277 xprintf("\n"); 278 279 if (gargv) { 280 blkfree(gargv); 281 gargv = 0; 282 } 283 } 284 285 void 286 prvars() 287 { 288 plist(&shvhed, VAR_ALL); 289 } 290 291 /*ARGSUSED*/ 292 void 293 doalias(v, c) 294 register Char **v; 295 struct command *c; 296 { 297 register struct varent *vp; 298 register Char *p; 299 300 USE(c); 301 v++; 302 p = *v++; 303 if (p == 0) 304 plist(&aliases, VAR_ALL); 305 else if (*v == 0) { 306 vp = adrof1(strip(p), &aliases); 307 if (vp) 308 blkpr(vp->vec), xputchar('\n'); 309 } 310 else { 311 if (eq(p, STRalias) || eq(p, STRunalias)) { 312 setname(short2str(p)); 313 stderror(ERR_NAME | ERR_DANGER); 314 } 315 set1(strip(p), saveblk(v), &aliases, VAR_READWRITE); 316 tw_cmd_free(); 317 } 318 } 319 320 /*ARGSUSED*/ 321 void 322 unalias(v, c) 323 Char **v; 324 struct command *c; 325 { 326 USE(c); 327 unset1(v, &aliases); 328 tw_cmd_free(); 329 } 330 331 /*ARGSUSED*/ 332 void 333 dologout(v, c) 334 Char **v; 335 struct command *c; 336 { 337 USE(c); 338 USE(v); 339 islogin(); 340 goodbye(NULL, NULL); 341 } 342 343 /*ARGSUSED*/ 344 void 345 dologin(v, c) 346 Char **v; 347 struct command *c; 348 { 349 USE(c); 350 #ifdef WINNT_NATIVE 351 USE(v); 352 #else /* !WINNT_NATIVE */ 353 islogin(); 354 rechist(NULL, adrof(STRsavehist) != NULL); 355 (void) signal(SIGTERM, parterm); 356 (void) execl(_PATH_BIN_LOGIN, "login", short2str(v[1]), NULL); 357 (void) execl(_PATH_USRBIN_LOGIN, "login", short2str(v[1]), NULL); 358 untty(); 359 xexit(1); 360 #endif /* !WINNT_NATIVE */ 361 } 362 363 364 #ifdef NEWGRP 365 /*ARGSUSED*/ 366 void 367 donewgrp(v, c) 368 Char **v; 369 struct command *c; 370 { 371 char **p; 372 if (chkstop == 0 && setintr) 373 panystop(0); 374 (void) signal(SIGTERM, parterm); 375 p = short2blk(v); 376 /* 377 * From Beto Appleton (beto@aixwiz.austin.ibm.com) 378 * Newgrp can take 2 arguments... 379 */ 380 (void) execv(_PATH_BIN_NEWGRP, p); 381 (void) execv(_PATH_USRBIN_NEWGRP, p); 382 blkfree((Char **) p); 383 untty(); 384 xexit(1); 385 } 386 #endif /* NEWGRP */ 387 388 static void 389 islogin() 390 { 391 if (chkstop == 0 && setintr) 392 panystop(0); 393 if (loginsh) 394 return; 395 stderror(ERR_NOTLOGIN); 396 } 397 398 void 399 doif(v, kp) 400 Char **v; 401 struct command *kp; 402 { 403 register int i; 404 register Char **vv; 405 406 v++; 407 i = expr(&v); 408 vv = v; 409 if (*vv == NULL) 410 stderror(ERR_NAME | ERR_EMPTYIF); 411 if (eq(*vv, STRthen)) { 412 if (*++vv) 413 stderror(ERR_NAME | ERR_IMPRTHEN); 414 setname(short2str(STRthen)); 415 /* 416 * If expression was zero, then scan to else , otherwise just fall into 417 * following code. 418 */ 419 if (!i) 420 search(TC_IF, 0, NULL); 421 return; 422 } 423 /* 424 * Simple command attached to this if. Left shift the node in this tree, 425 * munging it so we can reexecute it. 426 */ 427 if (i) { 428 lshift(kp->t_dcom, vv - kp->t_dcom); 429 reexecute(kp); 430 donefds(); 431 } 432 } 433 434 /* 435 * Reexecute a command, being careful not 436 * to redo i/o redirection, which is already set up. 437 */ 438 void 439 reexecute(kp) 440 register struct command *kp; 441 { 442 kp->t_dflg &= F_SAVE; 443 kp->t_dflg |= F_REPEAT; 444 /* 445 * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set 446 * pgrp's as the jobs would then have no way to get the tty (we can't give 447 * it to them, and our parent wouldn't know their pgrp, etc. 448 */ 449 execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL); 450 } 451 452 /*ARGSUSED*/ 453 void 454 doelse (v, c) 455 Char **v; 456 struct command *c; 457 { 458 USE(c); 459 USE(v); 460 search(TC_ELSE, 0, NULL); 461 } 462 463 /*ARGSUSED*/ 464 void 465 dogoto(v, c) 466 Char **v; 467 struct command *c; 468 { 469 Char *lp; 470 471 USE(c); 472 gotolab(lp = globone(v[1], G_ERROR)); 473 xfree((ptr_t) lp); 474 } 475 476 void 477 gotolab(lab) 478 Char *lab; 479 { 480 register struct whyle *wp; 481 /* 482 * While we still can, locate any unknown ends of existing loops. This 483 * obscure code is the WORST result of the fact that we don't really parse. 484 */ 485 zlast = TC_GOTO; 486 for (wp = whyles; wp; wp = wp->w_next) 487 if (wp->w_end.type == TCSH_F_SEEK && wp->w_end.f_seek == 0) { 488 search(TC_BREAK, 0, NULL); 489 btell(&wp->w_end); 490 } 491 else { 492 bseek(&wp->w_end); 493 } 494 search(TC_GOTO, 0, lab); 495 /* 496 * Eliminate loops which were exited. 497 */ 498 wfree(); 499 } 500 501 /*ARGSUSED*/ 502 void 503 doswitch(v, c) 504 register Char **v; 505 struct command *c; 506 { 507 register Char *cp, *lp; 508 509 USE(c); 510 v++; 511 if (!*v || *(*v++) != '(') 512 stderror(ERR_SYNTAX); 513 cp = **v == ')' ? STRNULL : *v++; 514 if (*(*v++) != ')') 515 v--; 516 if (*v) 517 stderror(ERR_SYNTAX); 518 search(TC_SWITCH, 0, lp = globone(cp, G_ERROR)); 519 xfree((ptr_t) lp); 520 } 521 522 /*ARGSUSED*/ 523 void 524 dobreak(v, c) 525 Char **v; 526 struct command *c; 527 { 528 USE(v); 529 USE(c); 530 if (whyles) 531 toend(); 532 else 533 stderror(ERR_NAME | ERR_NOTWHILE); 534 } 535 536 /*ARGSUSED*/ 537 void 538 doexit(v, c) 539 Char **v; 540 struct command *c; 541 { 542 USE(c); 543 544 if (chkstop == 0 && (intty || intact) && evalvec == 0) 545 panystop(0); 546 /* 547 * Don't DEMAND parentheses here either. 548 */ 549 v++; 550 if (*v) { 551 set(STRstatus, putn(expr(&v)), VAR_READWRITE); 552 if (*v) 553 stderror(ERR_NAME | ERR_EXPRESSION); 554 } 555 btoeof(); 556 #if 0 557 if (intty) 558 #endif 559 /* Always close, why only on ttys? */ 560 (void) close(SHIN); 561 } 562 563 /*ARGSUSED*/ 564 void 565 doforeach(v, c) 566 register Char **v; 567 struct command *c; 568 { 569 register Char *cp, *sp; 570 register struct whyle *nwp; 571 572 USE(c); 573 v++; 574 sp = cp = strip(*v); 575 if (!letter(*sp)) 576 stderror(ERR_NAME | ERR_VARBEGIN); 577 while (*cp && alnum(*cp)) 578 cp++; 579 if (*cp) 580 stderror(ERR_NAME | ERR_VARALNUM); 581 if ((cp - sp) > MAXVARLEN) 582 stderror(ERR_NAME | ERR_VARTOOLONG); 583 cp = *v++; 584 if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') 585 stderror(ERR_NAME | ERR_NOPAREN); 586 v++; 587 gflag = 0, tglob(v); 588 if (gflag) { 589 v = globall(v); 590 if (v == 0) 591 stderror(ERR_NAME | ERR_NOMATCH); 592 } 593 else { 594 v = gargv = saveblk(v); 595 trim(v); 596 } 597 nwp = (struct whyle *) xcalloc(1, sizeof *nwp); 598 nwp->w_fe = nwp->w_fe0 = v; 599 gargv = 0; 600 btell(&nwp->w_start); 601 nwp->w_fename = Strsave(cp); 602 nwp->w_next = whyles; 603 nwp->w_end.type = TCSH_F_SEEK; 604 whyles = nwp; 605 /* 606 * Pre-read the loop so as to be more comprehensible to a terminal user. 607 */ 608 zlast = TC_FOREACH; 609 if (intty) 610 preread(); 611 doagain(); 612 } 613 614 /*ARGSUSED*/ 615 void 616 dowhile(v, c) 617 Char **v; 618 struct command *c; 619 { 620 register int status; 621 register bool again = whyles != 0 && 622 SEEKEQ(&whyles->w_start, &lineloc) && 623 whyles->w_fename == 0; 624 625 USE(c); 626 v++; 627 /* 628 * Implement prereading here also, taking care not to evaluate the 629 * expression before the loop has been read up from a terminal. 630 */ 631 if (intty && !again) 632 status = !exp0(&v, 1); 633 else 634 status = !expr(&v); 635 if (*v) 636 stderror(ERR_NAME | ERR_EXPRESSION); 637 if (!again) { 638 register struct whyle *nwp = 639 (struct whyle *) xcalloc(1, sizeof(*nwp)); 640 641 nwp->w_start = lineloc; 642 nwp->w_end.type = TCSH_F_SEEK; 643 nwp->w_end.f_seek = 0; 644 nwp->w_next = whyles; 645 whyles = nwp; 646 zlast = TC_WHILE; 647 if (intty) { 648 /* 649 * The tty preread 650 */ 651 preread(); 652 doagain(); 653 return; 654 } 655 } 656 if (status) 657 /* We ain't gonna loop no more, no more! */ 658 toend(); 659 } 660 661 static void 662 preread() 663 { 664 whyles->w_end.type = TCSH_I_SEEK; 665 if (setintr) 666 #ifdef BSDSIGS 667 (void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT)); 668 #else /* !BSDSIGS */ 669 (void) sigrelse (SIGINT); 670 #endif /* BSDSIGS */ 671 search(TC_BREAK, 0, NULL); /* read the expression in */ 672 if (setintr) 673 #ifdef BSDSIGS 674 (void) sigblock(sigmask(SIGINT)); 675 #else /* !BSDSIGS */ 676 (void) sighold(SIGINT); 677 #endif /* BSDSIGS */ 678 btell(&whyles->w_end); 679 } 680 681 /*ARGSUSED*/ 682 void 683 doend(v, c) 684 Char **v; 685 struct command *c; 686 { 687 USE(v); 688 USE(c); 689 if (!whyles) 690 stderror(ERR_NAME | ERR_NOTWHILE); 691 btell(&whyles->w_end); 692 doagain(); 693 } 694 695 /*ARGSUSED*/ 696 void 697 docontin(v, c) 698 Char **v; 699 struct command *c; 700 { 701 USE(v); 702 USE(c); 703 if (!whyles) 704 stderror(ERR_NAME | ERR_NOTWHILE); 705 doagain(); 706 } 707 708 static void 709 doagain() 710 { 711 /* Repeating a while is simple */ 712 if (whyles->w_fename == 0) { 713 bseek(&whyles->w_start); 714 return; 715 } 716 /* 717 * The foreach variable list actually has a spurious word ")" at the end of 718 * the w_fe list. Thus we are at the of the list if one word beyond this 719 * is 0. 720 */ 721 if (!whyles->w_fe[1]) { 722 dobreak(NULL, NULL); 723 return; 724 } 725 set(whyles->w_fename, quote(Strsave(*whyles->w_fe++)), VAR_READWRITE); 726 bseek(&whyles->w_start); 727 } 728 729 void 730 dorepeat(v, kp) 731 Char **v; 732 struct command *kp; 733 { 734 register int i; 735 736 #ifdef BSDSIGS 737 register sigmask_t omask = 0; 738 739 #endif /* BSDSIGS */ 740 741 i = getn(v[1]); 742 if (setintr) 743 #ifdef BSDSIGS 744 omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT); 745 #else /* !BSDSIGS */ 746 (void) sighold(SIGINT); 747 #endif /* BSDSIGS */ 748 lshift(v, 2); 749 while (i > 0) { 750 if (setintr) 751 #ifdef BSDSIGS 752 (void) sigsetmask(omask); 753 #else /* !BSDSIGS */ 754 (void) sigrelse (SIGINT); 755 #endif /* BSDSIGS */ 756 reexecute(kp); 757 --i; 758 } 759 donefds(); 760 if (setintr) 761 #ifdef BSDSIGS 762 (void) sigsetmask(omask); 763 #else /* !BSDSIGS */ 764 (void) sigrelse (SIGINT); 765 #endif /* BSDSIGS */ 766 } 767 768 /*ARGSUSED*/ 769 void 770 doswbrk(v, c) 771 Char **v; 772 struct command *c; 773 { 774 USE(v); 775 USE(c); 776 search(TC_BRKSW, 0, NULL); 777 } 778 779 int 780 srchx(cp) 781 Char *cp; 782 { 783 struct srch *sp, *sp1, *sp2; 784 int i; 785 786 /* 787 * Ignore keywords inside heredocs 788 */ 789 if (inheredoc) 790 return -1; 791 792 /* 793 * Binary search Sp1 is the beginning of the current search range. Sp2 is 794 * one past the end. 795 */ 796 for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) { 797 sp = sp1 + ((sp2 - sp1) >> 1); 798 if ((i = *cp - *sp->s_name) == 0 && 799 (i = Strcmp(cp, str2short(sp->s_name))) == 0) 800 return sp->s_value; 801 if (i < 0) 802 sp2 = sp; 803 else 804 sp1 = sp + 1; 805 } 806 return (-1); 807 } 808 809 static char * 810 isrchx(n) 811 register int n; 812 { 813 register struct srch *sp, *sp2; 814 815 for (sp = srchn, sp2 = srchn + nsrchn; sp < sp2; sp++) 816 if (sp->s_value == n) 817 return (sp->s_name); 818 return (""); 819 } 820 821 822 static Char Stype; 823 static Char *Sgoal; 824 825 static void 826 search(type, level, goal) 827 int type; 828 register int level; 829 Char *goal; 830 { 831 Char wordbuf[BUFSIZE]; 832 register Char *aword = wordbuf; 833 register Char *cp; 834 835 Stype = (Char) type; 836 Sgoal = goal; 837 if (type == TC_GOTO) { 838 struct Ain a; 839 a.type = TCSH_F_SEEK; 840 a.f_seek = 0; 841 bseek(&a); 842 } 843 do { 844 if (intty && fseekp == feobp && aret == TCSH_F_SEEK) 845 printprompt(1, isrchx(type == TC_BREAK ? zlast : type)); 846 /* xprintf("? "), flush(); */ 847 aword[0] = 0; 848 (void) getword(aword); 849 switch (srchx(aword)) { 850 851 case TC_ELSE: 852 if (level == 0 && type == TC_IF) 853 return; 854 break; 855 856 case TC_IF: 857 while (getword(aword)) 858 continue; 859 if ((type == TC_IF || type == TC_ELSE) && 860 eq(aword, STRthen)) 861 level++; 862 break; 863 864 case TC_ENDIF: 865 if (type == TC_IF || type == TC_ELSE) 866 level--; 867 break; 868 869 case TC_FOREACH: 870 case TC_WHILE: 871 if (type == TC_BREAK) 872 level++; 873 break; 874 875 case TC_END: 876 if (type == TC_BREAK) 877 level--; 878 break; 879 880 case TC_SWITCH: 881 if (type == TC_SWITCH || type == TC_BRKSW) 882 level++; 883 break; 884 885 case TC_ENDSW: 886 if (type == TC_SWITCH || type == TC_BRKSW) 887 level--; 888 break; 889 890 case TC_LABEL: 891 if (type == TC_GOTO && getword(aword) && eq(aword, goal)) 892 level = -1; 893 break; 894 895 default: 896 if (type != TC_GOTO && (type != TC_SWITCH || level != 0)) 897 break; 898 if (lastchr(aword) != ':') 899 break; 900 aword[Strlen(aword) - 1] = 0; 901 if ((type == TC_GOTO && eq(aword, goal)) || 902 (type == TC_SWITCH && eq(aword, STRdefault))) 903 level = -1; 904 break; 905 906 case TC_CASE: 907 if (type != TC_SWITCH || level != 0) 908 break; 909 (void) getword(aword); 910 if (lastchr(aword) == ':') 911 aword[Strlen(aword) - 1] = 0; 912 cp = strip(Dfix1(aword)); 913 if (Gmatch(goal, cp)) 914 level = -1; 915 xfree((ptr_t) cp); 916 break; 917 918 case TC_DEFAULT: 919 if (type == TC_SWITCH && level == 0) 920 level = -1; 921 break; 922 } 923 (void) getword(NULL); 924 } while (level >= 0); 925 } 926 927 static int 928 getword(wp) 929 register Char *wp; 930 { 931 int found = 0, first; 932 int c, d; 933 934 c = readc(1); 935 d = 0; 936 do { 937 while (c == ' ' || c == '\t') 938 c = readc(1); 939 if (c == '#') 940 do 941 c = readc(1); 942 while (c >= 0 && c != '\n'); 943 if (c < 0) 944 goto past; 945 if (c == '\n') { 946 if (wp) 947 break; 948 return (0); 949 } 950 unreadc(c); 951 found = 1; 952 first = 1; 953 do { 954 c = readc(1); 955 if (c == '\\' && (c = readc(1)) == '\n') 956 c = ' '; 957 if (c == '\'' || c == '"') { 958 if (d == 0) 959 d = c; 960 else if (d == c) 961 d = 0; 962 } 963 if (c < 0) 964 goto past; 965 if (wp) { 966 *wp++ = (Char) c; 967 *wp = '\0'; 968 } 969 if (!first && !d && c == '(') { 970 if (wp) { 971 unreadc(c); 972 *--wp = '\0'; 973 return found; 974 } 975 else 976 break; 977 } 978 first = 0; 979 } while ((d || (c != ' ' && c != '\t')) && c != '\n'); 980 } while (wp == 0); 981 982 unreadc(c); 983 if (found) 984 *--wp = '\0'; 985 986 return (found); 987 988 past: 989 switch (Stype) { 990 991 case TC_IF: 992 stderror(ERR_NAME | ERR_NOTFOUND, "then/endif"); 993 break; 994 995 case TC_ELSE: 996 stderror(ERR_NAME | ERR_NOTFOUND, "endif"); 997 break; 998 999 case TC_BRKSW: 1000 case TC_SWITCH: 1001 stderror(ERR_NAME | ERR_NOTFOUND, "endsw"); 1002 break; 1003 1004 case TC_BREAK: 1005 stderror(ERR_NAME | ERR_NOTFOUND, "end"); 1006 break; 1007 1008 case TC_GOTO: 1009 setname(short2str(Sgoal)); 1010 stderror(ERR_NAME | ERR_NOTFOUND, "label"); 1011 break; 1012 1013 default: 1014 break; 1015 } 1016 /* NOTREACHED */ 1017 return (0); 1018 } 1019 1020 static void 1021 toend() 1022 { 1023 if (whyles->w_end.type == TCSH_F_SEEK && whyles->w_end.f_seek == 0) { 1024 search(TC_BREAK, 0, NULL); 1025 btell(&whyles->w_end); 1026 whyles->w_end.f_seek--; 1027 } 1028 else { 1029 bseek(&whyles->w_end); 1030 } 1031 wfree(); 1032 } 1033 1034 void 1035 wfree() 1036 { 1037 struct Ain o; 1038 struct whyle *nwp; 1039 #ifdef lint 1040 nwp = NULL; /* sun lint is dumb! */ 1041 #endif 1042 1043 #ifdef FDEBUG 1044 static char foo[] = "IAFE"; 1045 #endif /* FDEBUG */ 1046 1047 btell(&o); 1048 1049 #ifdef FDEBUG 1050 xprintf("o->type %c o->a_seek %d o->f_seek %d\n", 1051 foo[o.type + 1], o.a_seek, o.f_seek); 1052 #endif /* FDEBUG */ 1053 1054 for (; whyles; whyles = nwp) { 1055 register struct whyle *wp = whyles; 1056 nwp = wp->w_next; 1057 1058 #ifdef FDEBUG 1059 xprintf("start->type %c start->a_seek %d start->f_seek %d\n", 1060 foo[wp->w_start.type+1], 1061 wp->w_start.a_seek, wp->w_start.f_seek); 1062 xprintf("end->type %c end->a_seek %d end->f_seek %d\n", 1063 foo[wp->w_end.type + 1], wp->w_end.a_seek, wp->w_end.f_seek); 1064 #endif /* FDEBUG */ 1065 1066 /* 1067 * XXX: We free loops that have different seek types. 1068 */ 1069 if (wp->w_end.type != TCSH_I_SEEK && wp->w_start.type == wp->w_end.type && 1070 wp->w_start.type == o.type) { 1071 if (wp->w_end.type == TCSH_F_SEEK) { 1072 if (o.f_seek >= wp->w_start.f_seek && 1073 (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek)) 1074 break; 1075 } 1076 else { 1077 if (o.a_seek >= wp->w_start.a_seek && 1078 (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek)) 1079 break; 1080 } 1081 } 1082 1083 if (wp->w_fe0) 1084 blkfree(wp->w_fe0); 1085 if (wp->w_fename) 1086 xfree((ptr_t) wp->w_fename); 1087 xfree((ptr_t) wp); 1088 } 1089 } 1090 1091 /*ARGSUSED*/ 1092 void 1093 doecho(v, c) 1094 Char **v; 1095 struct command *c; 1096 { 1097 USE(c); 1098 xecho(' ', v); 1099 } 1100 1101 /*ARGSUSED*/ 1102 void 1103 doglob(v, c) 1104 Char **v; 1105 struct command *c; 1106 { 1107 USE(c); 1108 xecho(0, v); 1109 flush(); 1110 } 1111 1112 static void 1113 xecho(sep, v) 1114 int sep; 1115 register Char **v; 1116 { 1117 register Char *cp; 1118 int nonl = 0; 1119 #ifdef ECHO_STYLE 1120 int echo_style = ECHO_STYLE; 1121 #else /* !ECHO_STYLE */ 1122 # if SYSVREL > 0 1123 int echo_style = SYSV_ECHO; 1124 # else /* SYSVREL == 0 */ 1125 int echo_style = BSD_ECHO; 1126 # endif /* SYSVREL */ 1127 #endif /* ECHO_STYLE */ 1128 struct varent *vp; 1129 1130 if ((vp = adrof(STRecho_style)) != NULL && vp->vec != NULL && 1131 vp->vec[0] != NULL) { 1132 if (Strcmp(vp->vec[0], STRbsd) == 0) 1133 echo_style = BSD_ECHO; 1134 else if (Strcmp(vp->vec[0], STRsysv) == 0) 1135 echo_style = SYSV_ECHO; 1136 else if (Strcmp(vp->vec[0], STRboth) == 0) 1137 echo_style = BOTH_ECHO; 1138 else if (Strcmp(vp->vec[0], STRnone) == 0) 1139 echo_style = NONE_ECHO; 1140 } 1141 1142 if (setintr) 1143 #ifdef BSDSIGS 1144 (void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT)); 1145 #else /* !BSDSIGS */ 1146 (void) sigrelse (SIGINT); 1147 #endif /* BSDSIGS */ 1148 v++; 1149 if (*v == 0) 1150 goto done; 1151 gflag = 0, tglob(v); 1152 if (gflag) { 1153 v = globall(v); 1154 if (v == 0) 1155 stderror(ERR_NAME | ERR_NOMATCH); 1156 } 1157 else { 1158 v = gargv = saveblk(v); 1159 trim(v); 1160 } 1161 1162 if ((echo_style & BSD_ECHO) != 0 && sep == ' ' && *v && eq(*v, STRmn)) 1163 nonl++, v++; 1164 1165 while ((cp = *v++) != 0) { 1166 register int c; 1167 1168 while ((c = *cp++) != 0) { 1169 if ((echo_style & SYSV_ECHO) != 0 && c == '\\') { 1170 switch (c = *cp++) { 1171 case 'a': 1172 c = '\a'; 1173 break; 1174 case 'b': 1175 c = '\b'; 1176 break; 1177 case 'c': 1178 nonl = 1; 1179 goto done; 1180 case 'e': 1181 #if 0 /* Windows does not understand \e */ 1182 c = '\e'; 1183 #else 1184 c = '\033'; 1185 #endif 1186 break; 1187 case 'f': 1188 c = '\f'; 1189 break; 1190 case 'n': 1191 c = '\n'; 1192 break; 1193 case 'r': 1194 c = '\r'; 1195 break; 1196 case 't': 1197 c = '\t'; 1198 break; 1199 case 'v': 1200 c = '\v'; 1201 break; 1202 case '\\': 1203 c = '\\'; 1204 break; 1205 case '0': 1206 c = 0; 1207 if (*cp >= '0' && *cp < '8') 1208 c = c * 8 + *cp++ - '0'; 1209 if (*cp >= '0' && *cp < '8') 1210 c = c * 8 + *cp++ - '0'; 1211 if (*cp >= '0' && *cp < '8') 1212 c = c * 8 + *cp++ - '0'; 1213 break; 1214 case '\0': 1215 c = '\\'; 1216 cp--; 1217 break; 1218 default: 1219 xputchar('\\' | QUOTE); 1220 break; 1221 } 1222 } 1223 xputchar(c | QUOTE); 1224 1225 } 1226 if (*v) 1227 xputchar(sep | QUOTE); 1228 } 1229 done: 1230 if (sep && nonl == 0) 1231 xputchar('\n'); 1232 else 1233 flush(); 1234 if (setintr) 1235 #ifdef BSDSIGS 1236 (void) sigblock(sigmask(SIGINT)); 1237 #else /* !BSDSIGS */ 1238 (void) sighold(SIGINT); 1239 #endif /* BSDSIGS */ 1240 if (gargv) 1241 blkfree(gargv), gargv = 0; 1242 } 1243 1244 /* check whether an environment variable should invoke 'set_locale()' */ 1245 static bool 1246 islocale_var(var) 1247 Char *var; 1248 { 1249 static Char *locale_vars[] = { 1250 STRLANG, STRLC_CTYPE, STRLC_NUMERIC, STRLC_TIME, 1251 STRLC_COLLATE, STRLC_MESSAGES, STRLC_MONETARY, 0 1252 }; 1253 register Char **v; 1254 1255 for (v = locale_vars; *v; ++v) 1256 if (eq(var, *v)) 1257 return 1; 1258 return 0; 1259 } 1260 1261 /*ARGSUSED*/ 1262 void 1263 doprintenv(v, c) 1264 register Char **v; 1265 struct command *c; 1266 { 1267 Char *e; 1268 extern bool output_raw; 1269 extern bool xlate_cr; 1270 1271 USE(c); 1272 if (setintr) 1273 #ifdef BSDSIGS 1274 (void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT)); 1275 #else /* !BSDSIGS */ 1276 (void) sigrelse (SIGINT); 1277 #endif /* BSDSIGS */ 1278 1279 v++; 1280 if (*v == 0) { 1281 register Char **ep; 1282 1283 xlate_cr = 1; 1284 for (ep = STR_environ; *ep; ep++) 1285 xprintf("%S\n", *ep); 1286 xlate_cr = 0; 1287 } 1288 else if ((e = tgetenv(*v)) != NULL) { 1289 output_raw = 1; 1290 xprintf("%S\n", e); 1291 output_raw = 0; 1292 } 1293 else 1294 set(STRstatus, Strsave(STR1), VAR_READWRITE); 1295 } 1296 1297 /* from "Karl Berry." <karl%mote.umb.edu@relay.cs.net> -- for NeXT things 1298 (and anything else with a modern compiler) */ 1299 1300 /*ARGSUSED*/ 1301 void 1302 dosetenv(v, c) 1303 register Char **v; 1304 struct command *c; 1305 { 1306 Char *vp, *lp; 1307 1308 USE(c); 1309 if (*++v == 0) { 1310 doprintenv(--v, 0); 1311 return; 1312 } 1313 1314 vp = *v++; 1315 1316 if ((lp = *v++) == 0) 1317 lp = STRNULL; 1318 1319 tsetenv(vp, lp = globone(lp, G_APPEND)); 1320 if (eq(vp, STRKPATH)) { 1321 importpath(lp); 1322 dohash(NULL, NULL); 1323 xfree((ptr_t) lp); 1324 return; 1325 } 1326 1327 #ifdef apollo 1328 if (eq(vp, STRSYSTYPE)) { 1329 dohash(NULL, NULL); 1330 xfree((ptr_t) lp); 1331 return; 1332 } 1333 #endif /* apollo */ 1334 1335 /* dspkanji/dspmbyte autosetting */ 1336 /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */ 1337 #if defined(DSPMBYTE) 1338 if(eq(vp, STRLANG) && !adrof(CHECK_MBYTEVAR)) { 1339 autoset_dspmbyte(lp); 1340 } 1341 #endif 1342 1343 if (islocale_var(vp)) { 1344 #ifdef NLS 1345 int k; 1346 1347 # ifdef SETLOCALEBUG 1348 dont_free = 1; 1349 # endif /* SETLOCALEBUG */ 1350 (void) setlocale(LC_ALL, ""); 1351 # ifdef LC_COLLATE 1352 (void) setlocale(LC_COLLATE, ""); 1353 # endif 1354 # ifdef NLS_CATALOGS 1355 # ifdef LC_MESSAGES 1356 (void) setlocale(LC_MESSAGES, ""); 1357 # endif /* LC_MESSAGES */ 1358 (void) catclose(catd); 1359 nlsinit(); 1360 # endif /* NLS_CATALOGS */ 1361 # ifdef LC_CTYPE 1362 (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 1363 # endif /* LC_CTYPE */ 1364 # ifdef SETLOCALEBUG 1365 dont_free = 0; 1366 # endif /* SETLOCALEBUG */ 1367 # ifdef STRCOLLBUG 1368 fix_strcoll_bug(); 1369 # endif /* STRCOLLBUG */ 1370 tw_cmd_free(); /* since the collation sequence has changed */ 1371 for (k = 0200; k <= 0377 && !Isprint(k); k++) 1372 continue; 1373 AsciiOnly = k > 0377; 1374 #else /* !NLS */ 1375 AsciiOnly = 0; 1376 #endif /* NLS */ 1377 NLSMapsAreInited = 0; 1378 ed_Init(); 1379 if (MapsAreInited && !NLSMapsAreInited) 1380 ed_InitNLSMaps(); 1381 xfree((ptr_t) lp); 1382 return; 1383 } 1384 1385 if (eq(vp, STRNOREBIND)) { 1386 NoNLSRebind = 1; 1387 MapsAreInited = 0; 1388 NLSMapsAreInited = 0; 1389 ed_InitMaps(); 1390 xfree((ptr_t) lp); 1391 return; 1392 } 1393 #ifdef WINNT_NATIVE 1394 if (eq(vp, STRtcshlang)) { 1395 nlsinit(); 1396 xfree((ptr_t) lp); 1397 return; 1398 } 1399 #endif /* WINNT_NATIVE */ 1400 if (eq(vp, STRKTERM)) { 1401 char *t; 1402 set(STRterm, quote(lp), VAR_READWRITE); /* lp memory used here */ 1403 t = short2str(lp); 1404 if (noediting && strcmp(t, "unknown") != 0 && strcmp(t,"dumb") != 0) { 1405 editing = 1; 1406 noediting = 0; 1407 set(STRedit, Strsave(STRNULL), VAR_READWRITE); 1408 } 1409 GotTermCaps = 0; 1410 ed_Init(); 1411 return; 1412 } 1413 1414 if (eq(vp, STRKHOME)) { 1415 /* 1416 * convert to canonical pathname (possibly resolving symlinks) 1417 */ 1418 lp = dcanon(lp, lp); 1419 set(STRhome, quote(lp), VAR_READWRITE); /* cp memory used here */ 1420 1421 /* fix directory stack for new tilde home */ 1422 dtilde(); 1423 return; 1424 } 1425 1426 if (eq(vp, STRKSHLVL)) { 1427 /* lp memory used here */ 1428 set(STRshlvl, quote(lp), VAR_READWRITE); 1429 return; 1430 } 1431 1432 if (eq(vp, STRKUSER)) { 1433 set(STRuser, quote(lp), VAR_READWRITE); /* lp memory used here */ 1434 return; 1435 } 1436 1437 if (eq(vp, STRKGROUP)) { 1438 set(STRgroup, quote(lp), VAR_READWRITE); /* lp memory used here */ 1439 return; 1440 } 1441 1442 #ifdef COLOR_LS_F 1443 if (eq(vp, STRLS_COLORS)) { 1444 parseLS_COLORS(lp); 1445 return; 1446 } 1447 #endif /* COLOR_LS_F */ 1448 1449 #ifdef SIG_WINDOW 1450 /* 1451 * Load/Update $LINES $COLUMNS 1452 */ 1453 if ((eq(lp, STRNULL) && (eq(vp, STRLINES) || eq(vp, STRCOLUMNS))) || 1454 eq(vp, STRTERMCAP)) { 1455 xfree((ptr_t) lp); 1456 check_window_size(1); 1457 return; 1458 } 1459 1460 /* 1461 * Change the size to the one directed by $LINES and $COLUMNS 1462 */ 1463 if (eq(vp, STRLINES) || eq(vp, STRCOLUMNS)) { 1464 #if 0 1465 GotTermCaps = 0; 1466 #endif 1467 xfree((ptr_t) lp); 1468 ed_Init(); 1469 return; 1470 } 1471 #endif /* SIG_WINDOW */ 1472 xfree((ptr_t) lp); 1473 } 1474 1475 /*ARGSUSED*/ 1476 void 1477 dounsetenv(v, c) 1478 register Char **v; 1479 struct command *c; 1480 { 1481 Char **ep, *p, *n; 1482 int i, maxi; 1483 static Char *name = NULL; 1484 1485 USE(c); 1486 if (name) 1487 xfree((ptr_t) name); 1488 /* 1489 * Find the longest environment variable 1490 */ 1491 for (maxi = 0, ep = STR_environ; *ep; ep++) { 1492 for (i = 0, p = *ep; *p && *p != '='; p++, i++) 1493 continue; 1494 if (i > maxi) 1495 maxi = i; 1496 } 1497 1498 name = (Char *) xmalloc((size_t) ((maxi + 1) * sizeof(Char))); 1499 1500 while (++v && *v) 1501 for (maxi = 1; maxi;) 1502 for (maxi = 0, ep = STR_environ; *ep; ep++) { 1503 for (n = name, p = *ep; *p && *p != '='; *n++ = *p++) 1504 continue; 1505 *n = '\0'; 1506 if (!Gmatch(name, *v)) 1507 continue; 1508 maxi = 1; 1509 1510 /* Unset the name. This wasn't being done until 1511 * later but most of the stuff following won't 1512 * work (particularly the setlocale() and getenv() 1513 * stuff) as intended until the name is actually 1514 * removed. (sg) 1515 */ 1516 Unsetenv(name); 1517 1518 if (eq(name, STRNOREBIND)) { 1519 NoNLSRebind = 0; 1520 MapsAreInited = 0; 1521 NLSMapsAreInited = 0; 1522 ed_InitMaps(); 1523 } 1524 #ifdef apollo 1525 else if (eq(name, STRSYSTYPE)) 1526 dohash(NULL, NULL); 1527 #endif /* apollo */ 1528 else if (islocale_var(name)) { 1529 #ifdef NLS 1530 int k; 1531 1532 # ifdef SETLOCALEBUG 1533 dont_free = 1; 1534 # endif /* SETLOCALEBUG */ 1535 (void) setlocale(LC_ALL, ""); 1536 # ifdef LC_COLLATE 1537 (void) setlocale(LC_COLLATE, ""); 1538 # endif 1539 # ifdef NLS_CATALOGS 1540 # ifdef LC_MESSAGES 1541 (void) setlocale(LC_MESSAGES, ""); 1542 # endif /* LC_MESSAGES */ 1543 (void) catclose(catd); 1544 nlsinit(); 1545 # endif /* NLS_CATALOGS */ 1546 # ifdef LC_CTYPE 1547 (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 1548 # endif /* LC_CTYPE */ 1549 # ifdef SETLOCALEBUG 1550 dont_free = 0; 1551 # endif /* SETLOCALEBUG */ 1552 # ifdef STRCOLLBUG 1553 fix_strcoll_bug(); 1554 # endif /* STRCOLLBUG */ 1555 tw_cmd_free();/* since the collation sequence has changed */ 1556 for (k = 0200; k <= 0377 && !Isprint(k); k++) 1557 continue; 1558 AsciiOnly = k > 0377; 1559 #else /* !NLS */ 1560 AsciiOnly = getenv("LANG") == NULL && 1561 getenv("LC_CTYPE") == NULL; 1562 #endif /* NLS */ 1563 NLSMapsAreInited = 0; 1564 ed_Init(); 1565 if (MapsAreInited && !NLSMapsAreInited) 1566 ed_InitNLSMaps(); 1567 1568 } 1569 #ifdef WINNT_NATIVE 1570 else if (eq(name,(STRtcshlang))) { 1571 nls_dll_unload(); 1572 nlsinit(); 1573 } 1574 #endif /* WINNT_NATIVE */ 1575 #ifdef COLOR_LS_F 1576 else if (eq(name, STRLS_COLORS)) 1577 parseLS_COLORS(n); 1578 #endif /* COLOR_LS_F */ 1579 /* 1580 * start again cause the environment changes 1581 */ 1582 break; 1583 } 1584 xfree((ptr_t) name); name = NULL; 1585 } 1586 1587 void 1588 tsetenv(name, val) 1589 Char *name, *val; 1590 { 1591 #ifdef SETENV_IN_LIB 1592 /* 1593 * XXX: This does not work right, since tcsh cannot track changes to 1594 * the environment this way. (the builtin setenv without arguments does 1595 * not print the right stuff neither does unsetenv). This was for Mach, 1596 * it is not needed anymore. 1597 */ 1598 #undef setenv 1599 char nameBuf[BUFSIZE]; 1600 char *cname = short2str(name); 1601 1602 if (cname == NULL) 1603 return; 1604 (void) strcpy(nameBuf, cname); 1605 setenv(nameBuf, short2str(val), 1); 1606 #else /* !SETENV_IN_LIB */ 1607 register Char **ep = STR_environ; 1608 register Char *cp, *dp; 1609 Char *blk[2]; 1610 Char **oep = ep; 1611 1612 #ifdef WINNT_NATIVE 1613 nt_set_env(name,val); 1614 #endif /* WINNT_NATIVE */ 1615 for (; *ep; ep++) { 1616 #ifdef WINNT_NATIVE 1617 for (cp = name, dp = *ep; *cp && Tolower(*cp & TRIM) == Tolower(*dp); 1618 cp++, dp++) 1619 #else 1620 for (cp = name, dp = *ep; *cp && (*cp & TRIM) == *dp; cp++, dp++) 1621 #endif /* WINNT_NATIVE */ 1622 continue; 1623 if (*cp != 0 || *dp != '=') 1624 continue; 1625 cp = Strspl(STRequal, val); 1626 xfree((ptr_t) * ep); 1627 *ep = strip(Strspl(name, cp)); 1628 xfree((ptr_t) cp); 1629 blkfree((Char **) environ); 1630 environ = short2blk(STR_environ); 1631 return; 1632 } 1633 cp = Strspl(name, STRequal); 1634 blk[0] = strip(Strspl(cp, val)); 1635 xfree((ptr_t) cp); 1636 blk[1] = 0; 1637 STR_environ = blkspl(STR_environ, blk); 1638 blkfree((Char **) environ); 1639 environ = short2blk(STR_environ); 1640 xfree((ptr_t) oep); 1641 #endif /* SETENV_IN_LIB */ 1642 } 1643 1644 void 1645 Unsetenv(name) 1646 Char *name; 1647 { 1648 register Char **ep = STR_environ; 1649 register Char *cp, *dp; 1650 Char **oep = ep; 1651 1652 #ifdef WINNT_NATIVE 1653 nt_set_env(name,NULL); 1654 #endif /*WINNT_NATIVE */ 1655 for (; *ep; ep++) { 1656 for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) 1657 continue; 1658 if (*cp != 0 || *dp != '=') 1659 continue; 1660 cp = *ep; 1661 *ep = 0; 1662 STR_environ = blkspl(STR_environ, ep + 1); 1663 blkfree((Char **) environ); 1664 environ = short2blk(STR_environ); 1665 *ep = cp; 1666 xfree((ptr_t) cp); 1667 xfree((ptr_t) oep); 1668 return; 1669 } 1670 } 1671 1672 /*ARGSUSED*/ 1673 void 1674 doumask(v, c) 1675 register Char **v; 1676 struct command *c; 1677 { 1678 register Char *cp = v[1]; 1679 register int i; 1680 1681 USE(c); 1682 if (cp == 0) { 1683 i = (int)umask(0); 1684 (void) umask(i); 1685 xprintf("%o\n", i); 1686 return; 1687 } 1688 i = 0; 1689 while (Isdigit(*cp) && *cp != '8' && *cp != '9') 1690 i = i * 8 + *cp++ - '0'; 1691 if (*cp || i < 0 || i > 0777) 1692 stderror(ERR_NAME | ERR_MASK); 1693 (void) umask(i); 1694 } 1695 1696 #ifndef HAVENOLIMIT 1697 # ifndef BSDLIMIT 1698 typedef long RLIM_TYPE; 1699 # ifndef RLIM_INFINITY 1700 # if !defined(_MINIX) && !defined(__clipper__) && !defined(_CRAY) 1701 extern RLIM_TYPE ulimit(); 1702 # endif /* ! _MINIX && !__clipper__ */ 1703 # define RLIM_INFINITY 0x003fffff 1704 # define RLIMIT_FSIZE 1 1705 # endif /* RLIM_INFINITY */ 1706 # ifdef aiws 1707 # define toset(a) (((a) == 3) ? 1004 : (a) + 1) 1708 # define RLIMIT_DATA 3 1709 # define RLIMIT_STACK 1005 1710 # else /* aiws */ 1711 # define toset(a) ((a) + 1) 1712 # endif /* aiws */ 1713 # else /* BSDLIMIT */ 1714 # if defined(BSD4_4) && !defined(__386BSD__) 1715 typedef quad_t RLIM_TYPE; 1716 # else 1717 # if defined(SOLARIS2) || (defined(sgi) && SYSVREL > 3) 1718 typedef rlim_t RLIM_TYPE; 1719 # else 1720 # if defined(_SX) 1721 typedef long long RLIM_TYPE; 1722 # else /* _SX */ 1723 typedef unsigned long RLIM_TYPE; 1724 # endif /* _SX */ 1725 # endif /* SOLARIS2 || (sgi && SYSVREL > 3) */ 1726 # endif /* BSD4_4 && !__386BSD__ */ 1727 # endif /* BSDLIMIT */ 1728 1729 # if (HPUXVERSION > 700) && defined(BSDLIMIT) 1730 /* Yes hpux8.0 has limits but <sys/resource.h> does not make them public */ 1731 /* Yes, we could have defined _KERNEL, and -I/etc/conf/h, but is that better? */ 1732 # ifndef RLIMIT_CPU 1733 # define RLIMIT_CPU 0 1734 # define RLIMIT_FSIZE 1 1735 # define RLIMIT_DATA 2 1736 # define RLIMIT_STACK 3 1737 # define RLIMIT_CORE 4 1738 # define RLIMIT_RSS 5 1739 # define RLIMIT_NOFILE 6 1740 # endif /* RLIMIT_CPU */ 1741 # ifndef RLIM_INFINITY 1742 # define RLIM_INFINITY 0x7fffffff 1743 # endif /* RLIM_INFINITY */ 1744 /* 1745 * old versions of HP/UX counted limits in 512 bytes 1746 */ 1747 # ifndef SIGRTMIN 1748 # define FILESIZE512 1749 # endif /* SIGRTMIN */ 1750 # endif /* (HPUXVERSION > 700) && BSDLIMIT */ 1751 1752 # if SYSVREL > 3 && defined(BSDLIMIT) && !defined(_SX) 1753 /* In order to use rusage, we included "/usr/ucbinclude/sys/resource.h" in */ 1754 /* sh.h. However, some SVR4 limits are defined in <sys/resource.h>. Rather */ 1755 /* than include both and get warnings, we define the extra SVR4 limits here. */ 1756 /* XXX: I don't understand if RLIMIT_AS is defined, why don't we define */ 1757 /* RLIMIT_VMEM based on it? */ 1758 # ifndef RLIMIT_VMEM 1759 # define RLIMIT_VMEM 6 1760 # endif 1761 # ifndef RLIMIT_AS 1762 # define RLIMIT_AS RLIMIT_VMEM 1763 # endif 1764 # endif /* SYSVREL > 3 && BSDLIMIT */ 1765 1766 # if defined(__linux__) && defined(RLIMIT_AS) && !defined(RLIMIT_VMEM) 1767 # define RLIMIT_VMEM RLIMIT_AS 1768 # endif 1769 1770 struct limits limits[] = 1771 { 1772 # ifdef RLIMIT_CPU 1773 { RLIMIT_CPU, "cputime", 1, "seconds" }, 1774 # endif /* RLIMIT_CPU */ 1775 1776 # ifdef RLIMIT_FSIZE 1777 # ifndef aiws 1778 { RLIMIT_FSIZE, "filesize", 1024, "kbytes" }, 1779 # else 1780 { RLIMIT_FSIZE, "filesize", 512, "blocks" }, 1781 # endif /* aiws */ 1782 # endif /* RLIMIT_FSIZE */ 1783 1784 # ifdef RLIMIT_DATA 1785 { RLIMIT_DATA, "datasize", 1024, "kbytes" }, 1786 # endif /* RLIMIT_DATA */ 1787 1788 # ifdef RLIMIT_STACK 1789 # ifndef aiws 1790 { RLIMIT_STACK, "stacksize", 1024, "kbytes" }, 1791 # else 1792 { RLIMIT_STACK, "stacksize", 1024 * 1024, "kbytes"}, 1793 # endif /* aiws */ 1794 # endif /* RLIMIT_STACK */ 1795 1796 # ifdef RLIMIT_CORE 1797 { RLIMIT_CORE, "coredumpsize", 1024, "kbytes" }, 1798 # endif /* RLIMIT_CORE */ 1799 1800 # ifdef RLIMIT_RSS 1801 { RLIMIT_RSS, "memoryuse", 1024, "kbytes" }, 1802 # endif /* RLIMIT_RSS */ 1803 1804 # ifdef RLIMIT_UMEM 1805 { RLIMIT_UMEM, "memoryuse", 1024, "kbytes" }, 1806 # endif /* RLIMIT_UMEM */ 1807 1808 # ifdef RLIMIT_VMEM 1809 { RLIMIT_VMEM, "vmemoryuse", 1024, "kbytes" }, 1810 # endif /* RLIMIT_VMEM */ 1811 1812 # ifdef RLIMIT_NOFILE 1813 { RLIMIT_NOFILE, "descriptors", 1, "" }, 1814 # endif /* RLIMIT_NOFILE */ 1815 1816 # ifdef RLIMIT_CONCUR 1817 { RLIMIT_CONCUR, "concurrency", 1, "thread(s)" }, 1818 # endif /* RLIMIT_CONCUR */ 1819 1820 # ifdef RLIMIT_MEMLOCK 1821 { RLIMIT_MEMLOCK, "memorylocked", 1024, "kbytes" }, 1822 # endif /* RLIMIT_MEMLOCK */ 1823 1824 # ifdef RLIMIT_NPROC 1825 { RLIMIT_NPROC, "maxproc", 1, "" }, 1826 # endif /* RLIMIT_NPROC */ 1827 1828 # ifdef RLIMIT_OFILE 1829 { RLIMIT_OFILE, "openfiles", 1, "" }, 1830 # endif /* RLIMIT_OFILE */ 1831 1832 { -1, NULL, 0, NULL } 1833 }; 1834 1835 static struct limits *findlim __P((Char *)); 1836 static RLIM_TYPE getval __P((struct limits *, Char **)); 1837 static void limtail __P((Char *, char*)); 1838 static void plim __P((struct limits *, int)); 1839 static int setlim __P((struct limits *, int, RLIM_TYPE)); 1840 1841 #ifdef convex 1842 static RLIM_TYPE 1843 restrict_limit(value) 1844 double value; 1845 { 1846 /* 1847 * is f too large to cope with? return the maximum or minimum int 1848 */ 1849 if (value > (double) INT_MAX) 1850 return (RLIM_TYPE) INT_MAX; 1851 else if (value < (double) INT_MIN) 1852 return (RLIM_TYPE) INT_MIN; 1853 else 1854 return (RLIM_TYPE) value; 1855 } 1856 #else /* !convex */ 1857 # define restrict_limit(x) ((RLIM_TYPE) (x)) 1858 #endif /* convex */ 1859 1860 1861 static struct limits * 1862 findlim(cp) 1863 Char *cp; 1864 { 1865 register struct limits *lp, *res; 1866 1867 res = (struct limits *) NULL; 1868 for (lp = limits; lp->limconst >= 0; lp++) 1869 if (prefix(cp, str2short(lp->limname))) { 1870 if (res) 1871 stderror(ERR_NAME | ERR_AMBIG); 1872 res = lp; 1873 } 1874 if (res) 1875 return (res); 1876 stderror(ERR_NAME | ERR_LIMIT); 1877 /* NOTREACHED */ 1878 return (0); 1879 } 1880 1881 /*ARGSUSED*/ 1882 void 1883 dolimit(v, c) 1884 register Char **v; 1885 struct command *c; 1886 { 1887 register struct limits *lp; 1888 register RLIM_TYPE limit; 1889 int hard = 0; 1890 1891 USE(c); 1892 v++; 1893 if (*v && eq(*v, STRmh)) { 1894 hard = 1; 1895 v++; 1896 } 1897 if (*v == 0) { 1898 for (lp = limits; lp->limconst >= 0; lp++) 1899 plim(lp, hard); 1900 return; 1901 } 1902 lp = findlim(v[0]); 1903 if (v[1] == 0) { 1904 plim(lp, hard); 1905 return; 1906 } 1907 limit = getval(lp, v + 1); 1908 if (setlim(lp, hard, limit) < 0) 1909 stderror(ERR_SILENT); 1910 } 1911 1912 static RLIM_TYPE 1913 getval(lp, v) 1914 register struct limits *lp; 1915 Char **v; 1916 { 1917 register float f; 1918 #ifndef atof /* This can be a macro on linux */ 1919 extern double atof __P((const char *)); 1920 #endif /* atof */ 1921 Char *cp = *v++; 1922 1923 f = atof(short2str(cp)); 1924 1925 # ifdef convex 1926 /* 1927 * is f too large to cope with. limit f to minint, maxint - X-6768 by 1928 * strike 1929 */ 1930 if ((f < (double) INT_MIN) || (f > (double) INT_MAX)) { 1931 stderror(ERR_NAME | ERR_TOOLARGE); 1932 } 1933 # endif /* convex */ 1934 1935 while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') 1936 cp++; 1937 if (*cp == 0) { 1938 if (*v == 0) 1939 return restrict_limit((f * lp->limdiv) + 0.5); 1940 cp = *v; 1941 } 1942 switch (*cp) { 1943 # ifdef RLIMIT_CPU 1944 case ':': 1945 if (lp->limconst != RLIMIT_CPU) 1946 goto badscal; 1947 return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f * 60.0 + atof(short2str(cp + 1)))); 1948 case 'h': 1949 if (lp->limconst != RLIMIT_CPU) 1950 goto badscal; 1951 limtail(cp, "hours"); 1952 f *= 3600.0; 1953 break; 1954 case 'm': 1955 if (lp->limconst == RLIMIT_CPU) { 1956 limtail(cp, "minutes"); 1957 f *= 60.0; 1958 break; 1959 } 1960 *cp = 'm'; 1961 limtail(cp, "megabytes"); 1962 f *= 1024.0 * 1024.0; 1963 break; 1964 case 's': 1965 if (lp->limconst != RLIMIT_CPU) 1966 goto badscal; 1967 limtail(cp, "seconds"); 1968 break; 1969 # endif /* RLIMIT_CPU */ 1970 case 'M': 1971 # ifdef RLIMIT_CPU 1972 if (lp->limconst == RLIMIT_CPU) 1973 goto badscal; 1974 # endif /* RLIMIT_CPU */ 1975 *cp = 'm'; 1976 limtail(cp, "megabytes"); 1977 f *= 1024.0 * 1024.0; 1978 break; 1979 case 'k': 1980 # ifdef RLIMIT_CPU 1981 if (lp->limconst == RLIMIT_CPU) 1982 goto badscal; 1983 # endif /* RLIMIT_CPU */ 1984 limtail(cp, "kbytes"); 1985 f *= 1024.0; 1986 break; 1987 case 'b': 1988 # ifdef RLIMIT_CPU 1989 if (lp->limconst == RLIMIT_CPU) 1990 goto badscal; 1991 # endif /* RLIMIT_CPU */ 1992 limtail(cp, "blocks"); 1993 f *= 512.0; 1994 break; 1995 case 'u': 1996 limtail(cp, "unlimited"); 1997 return ((RLIM_TYPE) RLIM_INFINITY); 1998 default: 1999 # ifdef RLIMIT_CPU 2000 badscal: 2001 # endif /* RLIMIT_CPU */ 2002 stderror(ERR_NAME | ERR_SCALEF); 2003 } 2004 # ifdef convex 2005 return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f + 0.5)); 2006 # else 2007 f += 0.5; 2008 if (f > (float) RLIM_INFINITY) 2009 return ((RLIM_TYPE) RLIM_INFINITY); 2010 else 2011 return ((RLIM_TYPE) f); 2012 # endif /* convex */ 2013 } 2014 2015 static void 2016 limtail(cp, str) 2017 Char *cp; 2018 char *str; 2019 { 2020 char *sp; 2021 2022 sp = str; 2023 while (*cp && *cp == *str) 2024 cp++, str++; 2025 if (*cp) 2026 stderror(ERR_BADSCALE, sp); 2027 } 2028 2029 2030 /*ARGSUSED*/ 2031 static void 2032 plim(lp, hard) 2033 register struct limits *lp; 2034 int hard; 2035 { 2036 # ifdef BSDLIMIT 2037 struct rlimit rlim; 2038 # endif /* BSDLIMIT */ 2039 RLIM_TYPE limit; 2040 int div = lp->limdiv; 2041 2042 xprintf("%s \t", lp->limname); 2043 2044 # ifndef BSDLIMIT 2045 limit = ulimit(lp->limconst, 0); 2046 # ifdef aiws 2047 if (lp->limconst == RLIMIT_DATA) 2048 limit -= 0x20000000; 2049 # endif /* aiws */ 2050 # else /* BSDLIMIT */ 2051 (void) getrlimit(lp->limconst, &rlim); 2052 limit = hard ? rlim.rlim_max : rlim.rlim_cur; 2053 # endif /* BSDLIMIT */ 2054 2055 # if !defined(BSDLIMIT) || defined(FILESIZE512) 2056 /* 2057 * Christos: filesize comes in 512 blocks. we divide by 2 to get 1024 2058 * blocks. Note we cannot pre-multiply cause we might overflow (A/UX) 2059 */ 2060 if (lp->limconst == RLIMIT_FSIZE) { 2061 if (limit >= (RLIM_INFINITY / 512)) 2062 limit = RLIM_INFINITY; 2063 else 2064 div = (div == 1024 ? 2 : 1); 2065 } 2066 # endif /* !BSDLIMIT || FILESIZE512 */ 2067 2068 if (limit == RLIM_INFINITY) 2069 xprintf("unlimited"); 2070 else 2071 # ifdef RLIMIT_CPU 2072 if (lp->limconst == RLIMIT_CPU) 2073 psecs((long) limit); 2074 else 2075 # endif /* RLIMIT_CPU */ 2076 xprintf("%ld %s", (long) (limit / div), lp->limscale); 2077 xputchar('\n'); 2078 } 2079 2080 /*ARGSUSED*/ 2081 void 2082 dounlimit(v, c) 2083 register Char **v; 2084 struct command *c; 2085 { 2086 register struct limits *lp; 2087 int lerr = 0; 2088 int hard = 0; 2089 int force = 0; 2090 2091 USE(c); 2092 while (*++v && **v == '-') { 2093 Char *vp = *v; 2094 while (*++vp) 2095 switch (*vp) { 2096 case 'f': 2097 force = 1; 2098 break; 2099 case 'h': 2100 hard = 1; 2101 break; 2102 default: 2103 stderror(ERR_ULIMUS); 2104 break; 2105 } 2106 } 2107 2108 if (*v == 0) { 2109 for (lp = limits; lp->limconst >= 0; lp++) 2110 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0) 2111 lerr++; 2112 if (!force && lerr) 2113 stderror(ERR_SILENT); 2114 return; 2115 } 2116 while (*v) { 2117 lp = findlim(*v++); 2118 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0 && !force) 2119 stderror(ERR_SILENT); 2120 } 2121 } 2122 2123 static int 2124 setlim(lp, hard, limit) 2125 register struct limits *lp; 2126 int hard; 2127 RLIM_TYPE limit; 2128 { 2129 # ifdef BSDLIMIT 2130 struct rlimit rlim; 2131 2132 (void) getrlimit(lp->limconst, &rlim); 2133 2134 # ifdef FILESIZE512 2135 /* Even though hpux has setrlimit(), it expects fsize in 512 byte blocks */ 2136 if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 2137 limit /= 512; 2138 # endif /* FILESIZE512 */ 2139 if (hard) 2140 rlim.rlim_max = limit; 2141 else if (limit == RLIM_INFINITY && euid != 0) 2142 rlim.rlim_cur = rlim.rlim_max; 2143 else 2144 rlim.rlim_cur = limit; 2145 2146 if (setrlimit(lp->limconst, &rlim) < 0) { 2147 # else /* BSDLIMIT */ 2148 if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 2149 limit /= 512; 2150 # ifdef aiws 2151 if (lp->limconst == RLIMIT_DATA) 2152 limit += 0x20000000; 2153 # endif /* aiws */ 2154 if (ulimit(toset(lp->limconst), limit) < 0) { 2155 # endif /* BSDLIMIT */ 2156 xprintf(CGETS(15, 1, "%s: %s: Can't %s%s limit\n"), bname, lp->limname, 2157 limit == RLIM_INFINITY ? CGETS(15, 2, "remove") : 2158 CGETS(15, 3, "set"), 2159 hard ? CGETS(14, 4, " hard") : ""); 2160 return (-1); 2161 } 2162 return (0); 2163 } 2164 2165 #endif /* !HAVENOLIMIT */ 2166 2167 /*ARGSUSED*/ 2168 void 2169 dosuspend(v, c) 2170 Char **v; 2171 struct command *c; 2172 { 2173 #ifdef BSDJOBS 2174 int ctpgrp; 2175 2176 signalfun_t old; 2177 #endif /* BSDJOBS */ 2178 2179 USE(c); 2180 USE(v); 2181 2182 if (loginsh) 2183 stderror(ERR_SUSPLOG); 2184 untty(); 2185 2186 #ifdef BSDJOBS 2187 old = signal(SIGTSTP, SIG_DFL); 2188 (void) kill(0, SIGTSTP); 2189 /* the shell stops here */ 2190 (void) signal(SIGTSTP, old); 2191 #else /* !BSDJOBS */ 2192 stderror(ERR_JOBCONTROL); 2193 #endif /* BSDJOBS */ 2194 2195 #ifdef BSDJOBS 2196 if (tpgrp != -1) { 2197 retry: 2198 ctpgrp = tcgetpgrp(FSHTTY); 2199 if (ctpgrp != opgrp) { 2200 old = signal(SIGTTIN, SIG_DFL); 2201 (void) kill(0, SIGTTIN); 2202 (void) signal(SIGTTIN, old); 2203 goto retry; 2204 } 2205 (void) setpgid(0, shpgrp); 2206 (void) tcsetpgrp(FSHTTY, shpgrp); 2207 } 2208 #endif /* BSDJOBS */ 2209 (void) setdisc(FSHTTY); 2210 } 2211 2212 /* This is the dreaded EVAL built-in. 2213 * If you don't fiddle with file descriptors, and reset didfds, 2214 * this command will either ignore redirection inside or outside 2215 * its arguments, e.g. eval "date >x" vs. eval "date" >x 2216 * The stuff here seems to work, but I did it by trial and error rather 2217 * than really knowing what was going on. If tpgrp is zero, we are 2218 * probably a background eval, e.g. "eval date &", and we want to 2219 * make sure that any processes we start stay in our pgrp. 2220 * This is also the case for "time eval date" -- stay in same pgrp. 2221 * Otherwise, under stty tostop, processes will stop in the wrong 2222 * pgrp, with no way for the shell to get them going again. -IAN! 2223 */ 2224 2225 static Char **gv = NULL, **gav = NULL; 2226 2227 /*ARGSUSED*/ 2228 void 2229 doeval(v, c) 2230 Char **v; 2231 struct command *c; 2232 { 2233 Char **oevalvec; 2234 Char *oevalp; 2235 int odidfds; 2236 #ifndef CLOSE_ON_EXEC 2237 int odidcch; 2238 #endif /* CLOSE_ON_EXEC */ 2239 jmp_buf_t osetexit; 2240 int my_reenter; 2241 Char **savegv; 2242 int saveIN, saveOUT, saveDIAG; 2243 int oSHIN, oSHOUT, oSHDIAG; 2244 2245 USE(c); 2246 oevalvec = evalvec; 2247 oevalp = evalp; 2248 odidfds = didfds; 2249 #ifndef CLOSE_ON_EXEC 2250 odidcch = didcch; 2251 #endif /* CLOSE_ON_EXEC */ 2252 oSHIN = SHIN; 2253 oSHOUT = SHOUT; 2254 oSHDIAG = SHDIAG; 2255 2256 savegv = gv; 2257 gav = v; 2258 2259 gav++; 2260 if (*gav == 0) 2261 return; 2262 gflag = 0, tglob(gav); 2263 if (gflag) { 2264 gv = gav = globall(gav); 2265 gargv = 0; 2266 if (gav == 0) 2267 stderror(ERR_NOMATCH); 2268 gav = copyblk(gav); 2269 } 2270 else { 2271 gv = NULL; 2272 gav = copyblk(gav); 2273 trim(gav); 2274 } 2275 2276 saveIN = dcopy(SHIN, -1); 2277 saveOUT = dcopy(SHOUT, -1); 2278 saveDIAG = dcopy(SHDIAG, -1); 2279 2280 getexit(osetexit); 2281 2282 /* PWP: setjmp/longjmp bugfix for optimizing compilers */ 2283 #ifdef cray 2284 my_reenter = 1; /* assume non-zero return val */ 2285 if (setexit() == 0) { 2286 my_reenter = 0; /* Oh well, we were wrong */ 2287 #else /* !cray */ 2288 if ((my_reenter = setexit()) == 0) { 2289 #endif /* cray */ 2290 evalvec = gav; 2291 evalp = 0; 2292 SHIN = dcopy(0, -1); 2293 SHOUT = dcopy(1, -1); 2294 SHDIAG = dcopy(2, -1); 2295 #ifndef CLOSE_ON_EXEC 2296 didcch = 0; 2297 #endif /* CLOSE_ON_EXEC */ 2298 didfds = 0; 2299 process(0); 2300 } 2301 2302 evalvec = oevalvec; 2303 evalp = oevalp; 2304 doneinp = 0; 2305 #ifndef CLOSE_ON_EXEC 2306 didcch = odidcch; 2307 #endif /* CLOSE_ON_EXEC */ 2308 didfds = odidfds; 2309 (void) close(SHIN); 2310 (void) close(SHOUT); 2311 (void) close(SHDIAG); 2312 SHIN = dmove(saveIN, oSHIN); 2313 SHOUT = dmove(saveOUT, oSHOUT); 2314 SHDIAG = dmove(saveDIAG, oSHDIAG); 2315 2316 if (gv) 2317 blkfree(gv); 2318 2319 gv = savegv; 2320 resexit(osetexit); 2321 if (my_reenter) 2322 stderror(ERR_SILENT); 2323 } 2324 2325 /*************************************************************************/ 2326 /* print list of builtin commands */ 2327 2328 /*ARGSUSED*/ 2329 void 2330 dobuiltins(v, c) 2331 Char **v; 2332 struct command *c; 2333 { 2334 /* would use print_by_column() in tw.parse.c but that assumes 2335 * we have an array of Char * to pass.. (sg) 2336 */ 2337 extern int Tty_raw_mode; 2338 extern int TermH; /* from the editor routines */ 2339 extern int lbuffed; /* from sh.print.c */ 2340 2341 register struct biltins *b; 2342 register int row, col, columns, rows; 2343 unsigned int w, maxwidth; 2344 2345 USE(c); 2346 USE(v); 2347 lbuffed = 0; /* turn off line buffering */ 2348 2349 /* find widest string */ 2350 for (maxwidth = 0, b = bfunc; b < &bfunc[nbfunc]; ++b) 2351 maxwidth = max(maxwidth, strlen(b->bname)); 2352 ++maxwidth; /* for space */ 2353 2354 columns = (TermH + 1) / maxwidth; /* PWP: terminal size change */ 2355 if (!columns) 2356 columns = 1; 2357 rows = (nbfunc + (columns - 1)) / columns; 2358 2359 for (b = bfunc, row = 0; row < rows; row++) { 2360 for (col = 0; col < columns; col++) { 2361 if (b < &bfunc[nbfunc]) { 2362 w = strlen(b->bname); 2363 xprintf("%s", b->bname); 2364 if (col < (columns - 1)) /* Not last column? */ 2365 for (; w < maxwidth; w++) 2366 xputchar(' '); 2367 ++b; 2368 } 2369 } 2370 if (row < (rows - 1)) { 2371 if (Tty_raw_mode) 2372 xputchar('\r'); 2373 xputchar('\n'); 2374 } 2375 } 2376 #ifdef WINNT_NATIVE 2377 nt_print_builtins(maxwidth); 2378 #else 2379 if (Tty_raw_mode) 2380 xputchar('\r'); 2381 xputchar('\n'); 2382 #endif /* WINNT_NATIVE */ 2383 2384 lbuffed = 1; /* turn back on line buffering */ 2385 flush(); 2386 } 2387 2388 void 2389 nlsinit() 2390 { 2391 #ifdef NLS_CATALOGS 2392 char catalog[ 256 ] = { 't', 'c', 's', 'h', '\0' }; 2393 2394 if (adrof(STRcatalog) != NULL) 2395 xsnprintf((char *)catalog, sizeof(catalog), "tcsh.%s", 2396 short2str(varval(STRcatalog))); 2397 catd = catopen(catalog, MCLoadBySet); 2398 #endif /* NLS_CATALOGS */ 2399 #ifdef WINNT_NATIVE 2400 nls_dll_init(); 2401 #endif /* WINNT_NATIVE */ 2402 errinit(); /* init the errorlist in correct locale */ 2403 mesginit(); /* init the messages for signals */ 2404 dateinit(); /* init the messages for dates */ 2405 editinit(); /* init the editor messages */ 2406 terminit(); /* init the termcap messages */ 2407 } 2408