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