sh.func.c revision 194767
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 35RCSID("$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> 46static iconv_t catgets_iconv; /* Or (iconv_t)-1 */ 47#endif 48 49/* 50 * C shell 51 */ 52 53extern int MapsAreInited; 54extern int NLSMapsAreInited; 55extern int GotTermCaps; 56 57static int zlast = -1; 58 59static void islogin (void); 60static void preread (void); 61static void doagain (void); 62static const char *isrchx (int); 63static void search (int, int, Char *); 64static int getword (struct Strbuf *); 65static void toend (void); 66static void xecho (int, Char **); 67static int islocale_var (Char *); 68static void wpfree (struct whyle *); 69 70const struct biltins * 71isbfunc(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 133void 134func(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*/ 149void 150doonintr(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*/ 181void 182donohup(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*/ 198void 199dohup(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*/ 211void 212dozip(Char **v, struct command *c) 213{ 214 USE(c); 215 USE(v); 216} 217 218/*ARGSUSED*/ 219void 220dofiletest(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 246void 247prvars(void) 248{ 249 plist(&shvhed, VAR_ALL); 250} 251 252/*ARGSUSED*/ 253void 254doalias(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*/ 280void 281unalias(Char **v, struct command *c) 282{ 283 USE(c); 284 unset1(v, &aliases); 285 tw_cmd_free(); 286} 287 288/*ARGSUSED*/ 289void 290dologout(Char **v, struct command *c) 291{ 292 USE(c); 293 USE(v); 294 islogin(); 295 goodbye(NULL, NULL); 296} 297 298/*ARGSUSED*/ 299void 300dologin(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*/ 324void 325donewgrp(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 344static void 345islogin(void) 346{ 347 if (chkstop == 0 && setintr) 348 panystop(0); 349 if (loginsh) 350 return; 351 stderror(ERR_NOTLOGIN); 352} 353 354void 355doif(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 */ 392void 393reexecute(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*/ 406void 407doelse (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*/ 416void 417dogoto(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 429void 430gotolab(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*/ 454void 455doswitch(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*/ 476void 477dobreak(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*/ 488void 489doexit(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*/ 513void 514doforeach(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*/ 561void 562dowhile(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 606static void 607preread(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*/ 621void 622doend(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*/ 634void 635docontin(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 645static void 646doagain(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 666void 667dorepeat(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*/ 696void 697doswbrk(Char **v, struct command *c) 698{ 699 USE(v); 700 USE(c); 701 if (!noexec) 702 search(TC_BRKSW, 0, NULL); 703} 704 705int 706srchx(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 734static const char * 735isrchx(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 746static int Stype; 747static Char *Sgoal; 748 749static void 750search(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 864static int 865getword(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 924past: 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 956static void 957toend(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 970static void 971wpfree(struct whyle *wp) 972{ 973 if (wp->w_fe0) 974 blkfree(wp->w_fe0); 975 xfree(wp->w_fename); 976 xfree(wp); 977} 978 979void 980wfree(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*/ 1033void 1034doecho(Char **v, struct command *c) 1035{ 1036 USE(c); 1037 xecho(' ', v); 1038} 1039 1040/*ARGSUSED*/ 1041void 1042doglob(Char **v, struct command *c) 1043{ 1044 USE(c); 1045 xecho(0, v); 1046 flush(); 1047} 1048 1049static void 1050xecho(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 } 1157done: 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()' */ 1167static int 1168islocale_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 1182static void 1183xlate_cr_cleanup(void *dummy) 1184{ 1185 USE(dummy); 1186 xlate_cr = 0; 1187} 1188 1189/*ARGSUSED*/ 1190void 1191doprintenv(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*/ 1230void 1231dosetenv(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*/ 1433void 1434dounsetenv(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 1546void 1547tsetenv(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 1603void 1604Unsetenv(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*/ 1631void 1632doumask(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 1729struct 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# ifdef RLIMIT_SWAP 1800 { RLIMIT_SWAP, "swaplimit", 1024, "kbytes" }, 1801# endif /* RLIMIT_SWAP */ 1802 1803 { -1, NULL, 0, NULL } 1804}; 1805 1806static struct limits *findlim (Char *); 1807static RLIM_TYPE getval (struct limits *, Char **); 1808static void limtail (Char *, const char *); 1809static void plim (struct limits *, int); 1810static int setlim (struct limits *, int, RLIM_TYPE); 1811 1812#ifdef convex 1813static RLIM_TYPE 1814restrict_limit(double value) 1815{ 1816 /* 1817 * is f too large to cope with? return the maximum or minimum int 1818 */ 1819 if (value > (double) INT_MAX) 1820 return (RLIM_TYPE) INT_MAX; 1821 else if (value < (double) INT_MIN) 1822 return (RLIM_TYPE) INT_MIN; 1823 else 1824 return (RLIM_TYPE) value; 1825} 1826#else /* !convex */ 1827# define restrict_limit(x) ((RLIM_TYPE) (x)) 1828#endif /* convex */ 1829 1830 1831static struct limits * 1832findlim(Char *cp) 1833{ 1834 struct limits *lp, *res; 1835 1836 res = NULL; 1837 for (lp = limits; lp->limconst >= 0; lp++) 1838 if (prefix(cp, str2short(lp->limname))) { 1839 if (res) 1840 stderror(ERR_NAME | ERR_AMBIG); 1841 res = lp; 1842 } 1843 if (res) 1844 return (res); 1845 stderror(ERR_NAME | ERR_LIMIT); 1846 /* NOTREACHED */ 1847 return (0); 1848} 1849 1850/*ARGSUSED*/ 1851void 1852dolimit(Char **v, struct command *c) 1853{ 1854 struct limits *lp; 1855 RLIM_TYPE limit; 1856 int hard = 0; 1857 1858 USE(c); 1859 v++; 1860 if (*v && eq(*v, STRmh)) { 1861 hard = 1; 1862 v++; 1863 } 1864 if (*v == 0) { 1865 for (lp = limits; lp->limconst >= 0; lp++) 1866 plim(lp, hard); 1867 return; 1868 } 1869 lp = findlim(v[0]); 1870 if (v[1] == 0) { 1871 plim(lp, hard); 1872 return; 1873 } 1874 limit = getval(lp, v + 1); 1875 if (setlim(lp, hard, limit) < 0) 1876 stderror(ERR_SILENT); 1877} 1878 1879static RLIM_TYPE 1880getval(struct limits *lp, Char **v) 1881{ 1882 float f; 1883 Char *cp = *v++; 1884 1885 f = atof(short2str(cp)); 1886 1887# ifdef convex 1888 /* 1889 * is f too large to cope with. limit f to minint, maxint - X-6768 by 1890 * strike 1891 */ 1892 if ((f < (double) INT_MIN) || (f > (double) INT_MAX)) { 1893 stderror(ERR_NAME | ERR_TOOLARGE); 1894 } 1895# endif /* convex */ 1896 1897 while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') 1898 cp++; 1899 if (*cp == 0) { 1900 if (*v == 0) 1901 return restrict_limit((f * lp->limdiv) + 0.5); 1902 cp = *v; 1903 } 1904 switch (*cp) { 1905# ifdef RLIMIT_CPU 1906 case ':': 1907 if (lp->limconst != RLIMIT_CPU) 1908 goto badscal; 1909 return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f * 60.0 + atof(short2str(cp + 1)))); 1910 case 'h': 1911 if (lp->limconst != RLIMIT_CPU) 1912 goto badscal; 1913 limtail(cp, "hours"); 1914 f *= 3600.0; 1915 break; 1916 case 'm': 1917 if (lp->limconst == RLIMIT_CPU) { 1918 limtail(cp, "minutes"); 1919 f *= 60.0; 1920 break; 1921 } 1922 *cp = 'm'; 1923 limtail(cp, "megabytes"); 1924 f *= 1024.0 * 1024.0; 1925 break; 1926 case 's': 1927 if (lp->limconst != RLIMIT_CPU) 1928 goto badscal; 1929 limtail(cp, "seconds"); 1930 break; 1931# endif /* RLIMIT_CPU */ 1932 case 'M': 1933# ifdef RLIMIT_CPU 1934 if (lp->limconst == RLIMIT_CPU) 1935 goto badscal; 1936# endif /* RLIMIT_CPU */ 1937 *cp = 'm'; 1938 limtail(cp, "megabytes"); 1939 f *= 1024.0 * 1024.0; 1940 break; 1941 case 'k': 1942# ifdef RLIMIT_CPU 1943 if (lp->limconst == RLIMIT_CPU) 1944 goto badscal; 1945# endif /* RLIMIT_CPU */ 1946 limtail(cp, "kbytes"); 1947 f *= 1024.0; 1948 break; 1949 case 'b': 1950# ifdef RLIMIT_CPU 1951 if (lp->limconst == RLIMIT_CPU) 1952 goto badscal; 1953# endif /* RLIMIT_CPU */ 1954 limtail(cp, "blocks"); 1955 f *= 512.0; 1956 break; 1957 case 'u': 1958 limtail(cp, "unlimited"); 1959 return ((RLIM_TYPE) RLIM_INFINITY); 1960 default: 1961# ifdef RLIMIT_CPU 1962badscal: 1963# endif /* RLIMIT_CPU */ 1964 stderror(ERR_NAME | ERR_SCALEF); 1965 } 1966# ifdef convex 1967 return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f + 0.5)); 1968# else 1969 f += 0.5; 1970 if (f > (float) RLIM_INFINITY) 1971 return ((RLIM_TYPE) RLIM_INFINITY); 1972 else 1973 return ((RLIM_TYPE) f); 1974# endif /* convex */ 1975} 1976 1977static void 1978limtail(Char *cp, const char *str) 1979{ 1980 const char *sp; 1981 1982 sp = str; 1983 while (*cp && *cp == (Char)*str) 1984 cp++, str++; 1985 if (*cp) 1986 stderror(ERR_BADSCALE, sp); 1987} 1988 1989 1990/*ARGSUSED*/ 1991static void 1992plim(struct limits *lp, int hard) 1993{ 1994# ifdef BSDLIMIT 1995 struct rlimit rlim; 1996# endif /* BSDLIMIT */ 1997 RLIM_TYPE limit; 1998 int xdiv = lp->limdiv; 1999 2000 xprintf("%-13.13s", lp->limname); 2001 2002# ifndef BSDLIMIT 2003 limit = ulimit(lp->limconst, 0); 2004# ifdef aiws 2005 if (lp->limconst == RLIMIT_DATA) 2006 limit -= 0x20000000; 2007# endif /* aiws */ 2008# else /* BSDLIMIT */ 2009 (void) getrlimit(lp->limconst, &rlim); 2010 limit = hard ? rlim.rlim_max : rlim.rlim_cur; 2011# endif /* BSDLIMIT */ 2012 2013# if !defined(BSDLIMIT) || defined(FILESIZE512) 2014 /* 2015 * Christos: filesize comes in 512 blocks. we divide by 2 to get 1024 2016 * blocks. Note we cannot pre-multiply cause we might overflow (A/UX) 2017 */ 2018 if (lp->limconst == RLIMIT_FSIZE) { 2019 if (limit >= (RLIM_INFINITY / 512)) 2020 limit = RLIM_INFINITY; 2021 else 2022 xdiv = (xdiv == 1024 ? 2 : 1); 2023 } 2024# endif /* !BSDLIMIT || FILESIZE512 */ 2025 2026 if (limit == RLIM_INFINITY) 2027 xprintf("unlimited"); 2028 else 2029# if defined(RLIMIT_CPU) && defined(_OSD_POSIX) 2030 if (lp->limconst == RLIMIT_CPU && 2031 (unsigned long)limit >= 0x7ffffffdUL) 2032 xprintf("unlimited"); 2033 else 2034# endif 2035# ifdef RLIMIT_CPU 2036 if (lp->limconst == RLIMIT_CPU) 2037 psecs(limit); 2038 else 2039# endif /* RLIMIT_CPU */ 2040 xprintf("%ld %s", (long) (limit / xdiv), lp->limscale); 2041 xputchar('\n'); 2042} 2043 2044/*ARGSUSED*/ 2045void 2046dounlimit(Char **v, struct command *c) 2047{ 2048 struct limits *lp; 2049 int lerr = 0; 2050 int hard = 0; 2051 int force = 0; 2052 2053 USE(c); 2054 while (*++v && **v == '-') { 2055 Char *vp = *v; 2056 while (*++vp) 2057 switch (*vp) { 2058 case 'f': 2059 force = 1; 2060 break; 2061 case 'h': 2062 hard = 1; 2063 break; 2064 default: 2065 stderror(ERR_ULIMUS); 2066 break; 2067 } 2068 } 2069 2070 if (*v == 0) { 2071 for (lp = limits; lp->limconst >= 0; lp++) 2072 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0) 2073 lerr++; 2074 if (!force && lerr) 2075 stderror(ERR_SILENT); 2076 return; 2077 } 2078 while (*v) { 2079 lp = findlim(*v++); 2080 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0 && !force) 2081 stderror(ERR_SILENT); 2082 } 2083} 2084 2085static int 2086setlim(struct limits *lp, int hard, RLIM_TYPE limit) 2087{ 2088# ifdef BSDLIMIT 2089 struct rlimit rlim; 2090 2091 (void) getrlimit(lp->limconst, &rlim); 2092 2093# ifdef FILESIZE512 2094 /* Even though hpux has setrlimit(), it expects fsize in 512 byte blocks */ 2095 if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 2096 limit /= 512; 2097# endif /* FILESIZE512 */ 2098 if (hard) 2099 rlim.rlim_max = limit; 2100 else if (limit == RLIM_INFINITY && euid != 0) 2101 rlim.rlim_cur = rlim.rlim_max; 2102 else 2103 rlim.rlim_cur = limit; 2104 2105 if (rlim.rlim_cur > rlim.rlim_max) 2106 rlim.rlim_max = rlim.rlim_cur; 2107 2108 if (setrlimit(lp->limconst, &rlim) < 0) { 2109# else /* BSDLIMIT */ 2110 if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 2111 limit /= 512; 2112# ifdef aiws 2113 if (lp->limconst == RLIMIT_DATA) 2114 limit += 0x20000000; 2115# endif /* aiws */ 2116 if (ulimit(toset(lp->limconst), limit) < 0) { 2117# endif /* BSDLIMIT */ 2118 int err; 2119 char *op, *type; 2120 2121 err = errno; 2122 op = strsave(limit == RLIM_INFINITY ? CGETS(15, 2, "remove") : 2123 CGETS(15, 3, "set")); 2124 cleanup_push(op, xfree); 2125 type = strsave(hard ? CGETS(15, 4, " hard") : ""); 2126 cleanup_push(type, xfree); 2127 xprintf(CGETS(15, 1, "%s: %s: Can't %s%s limit (%s)\n"), bname, 2128 lp->limname, op, type, strerror(err)); 2129 cleanup_until(op); 2130 return (-1); 2131 } 2132 return (0); 2133} 2134 2135#endif /* !HAVENOLIMIT */ 2136 2137/*ARGSUSED*/ 2138void 2139dosuspend(Char **v, struct command *c) 2140{ 2141#ifdef BSDJOBS 2142 int ctpgrp; 2143 struct sigaction old; 2144#endif /* BSDJOBS */ 2145 2146 USE(c); 2147 USE(v); 2148 2149 if (loginsh) 2150 stderror(ERR_SUSPLOG); 2151 untty(); 2152 2153#ifdef BSDJOBS 2154 sigaction(SIGTSTP, NULL, &old); 2155 signal(SIGTSTP, SIG_DFL); 2156 (void) kill(0, SIGTSTP); 2157 /* the shell stops here */ 2158 sigaction(SIGTSTP, &old, NULL); 2159#else /* !BSDJOBS */ 2160 stderror(ERR_JOBCONTROL); 2161#endif /* BSDJOBS */ 2162 2163#ifdef BSDJOBS 2164 if (tpgrp != -1) { 2165retry: 2166 ctpgrp = tcgetpgrp(FSHTTY); 2167 if (ctpgrp == -1) 2168 stderror(ERR_SYSTEM, "tcgetpgrp", strerror(errno)); 2169 if (ctpgrp != opgrp) { 2170 sigaction(SIGTTIN, NULL, &old); 2171 signal(SIGTTIN, SIG_DFL); 2172 (void) kill(0, SIGTTIN); 2173 sigaction(SIGTTIN, &old, NULL); 2174 goto retry; 2175 } 2176 (void) setpgid(0, shpgrp); 2177 (void) tcsetpgrp(FSHTTY, shpgrp); 2178 } 2179#endif /* BSDJOBS */ 2180 (void) setdisc(FSHTTY); 2181} 2182 2183/* This is the dreaded EVAL built-in. 2184 * If you don't fiddle with file descriptors, and reset didfds, 2185 * this command will either ignore redirection inside or outside 2186 * its arguments, e.g. eval "date >x" vs. eval "date" >x 2187 * The stuff here seems to work, but I did it by trial and error rather 2188 * than really knowing what was going on. If tpgrp is zero, we are 2189 * probably a background eval, e.g. "eval date &", and we want to 2190 * make sure that any processes we start stay in our pgrp. 2191 * This is also the case for "time eval date" -- stay in same pgrp. 2192 * Otherwise, under stty tostop, processes will stop in the wrong 2193 * pgrp, with no way for the shell to get them going again. -IAN! 2194 */ 2195 2196struct doeval_state 2197{ 2198 Char **evalvec, *evalp; 2199 int didfds; 2200#ifndef CLOSE_ON_EXEC 2201 int didcch; 2202#endif 2203 int saveIN, saveOUT, saveDIAG; 2204 int SHIN, SHOUT, SHDIAG; 2205}; 2206 2207static void 2208doeval_cleanup(void *xstate) 2209{ 2210 struct doeval_state *state; 2211 2212 state = xstate; 2213 evalvec = state->evalvec; 2214 evalp = state->evalp; 2215 doneinp = 0; 2216#ifndef CLOSE_ON_EXEC 2217 didcch = state->didcch; 2218#endif /* CLOSE_ON_EXEC */ 2219 didfds = state->didfds; 2220 xclose(SHIN); 2221 xclose(SHOUT); 2222 xclose(SHDIAG); 2223 close_on_exec(SHIN = dmove(state->saveIN, state->SHIN), 1); 2224 close_on_exec(SHOUT = dmove(state->saveOUT, state->SHOUT), 1); 2225 close_on_exec(SHDIAG = dmove(state->saveDIAG, state->SHDIAG), 1); 2226} 2227 2228/*ARGSUSED*/ 2229void 2230doeval(Char **v, struct command *c) 2231{ 2232 struct doeval_state state; 2233 int gflag; 2234 Char **gv; 2235 2236 USE(c); 2237 v++; 2238 if (*v == 0) 2239 return; 2240 gflag = tglob(v); 2241 if (gflag) { 2242 gv = v = globall(v, gflag); 2243 if (v == 0) 2244 stderror(ERR_NOMATCH); 2245 cleanup_push(gv, blk_cleanup); 2246 v = copyblk(v); 2247 } 2248 else { 2249 gv = NULL; 2250 v = copyblk(v); 2251 trim(v); 2252 } 2253 2254 state.evalvec = evalvec; 2255 state.evalp = evalp; 2256 state.didfds = didfds; 2257#ifndef CLOSE_ON_EXEC 2258 state.didcch = didcch; 2259#endif /* CLOSE_ON_EXEC */ 2260 state.SHIN = SHIN; 2261 state.SHOUT = SHOUT; 2262 state.SHDIAG = SHDIAG; 2263 2264 (void)close_on_exec(state.saveIN = dcopy(SHIN, -1), 1); 2265 (void)close_on_exec(state.saveOUT = dcopy(SHOUT, -1), 1); 2266 (void)close_on_exec(state.saveDIAG = dcopy(SHDIAG, -1), 1); 2267 2268 cleanup_push(&state, doeval_cleanup); 2269 2270 evalvec = v; 2271 evalp = 0; 2272 (void)close_on_exec(SHIN = dcopy(0, -1), 1); 2273 (void)close_on_exec(SHOUT = dcopy(1, -1), 1); 2274 (void)close_on_exec(SHDIAG = dcopy(2, -1), 1); 2275#ifndef CLOSE_ON_EXEC 2276 didcch = 0; 2277#endif /* CLOSE_ON_EXEC */ 2278 didfds = 0; 2279 process(0); 2280 2281 cleanup_until(&state); 2282 2283 if (gv) 2284 cleanup_until(gv); 2285} 2286 2287/*************************************************************************/ 2288/* print list of builtin commands */ 2289 2290static void 2291lbuffed_cleanup (void *dummy) 2292{ 2293 USE(dummy); 2294 lbuffed = 1; 2295} 2296 2297/*ARGSUSED*/ 2298void 2299dobuiltins(Char **v, struct command *c) 2300{ 2301 /* would use print_by_column() in tw.parse.c but that assumes 2302 * we have an array of Char * to pass.. (sg) 2303 */ 2304 const struct biltins *b; 2305 int row, col, columns, rows; 2306 unsigned int w, maxwidth; 2307 2308 USE(c); 2309 USE(v); 2310 lbuffed = 0; /* turn off line buffering */ 2311 cleanup_push(&lbuffed, lbuffed_cleanup); 2312 2313 /* find widest string */ 2314 for (maxwidth = 0, b = bfunc; b < &bfunc[nbfunc]; ++b) 2315 maxwidth = max(maxwidth, strlen(b->bname)); 2316 ++maxwidth; /* for space */ 2317 2318 columns = (TermH + 1) / maxwidth; /* PWP: terminal size change */ 2319 if (!columns) 2320 columns = 1; 2321 rows = (nbfunc + (columns - 1)) / columns; 2322 2323 for (b = bfunc, row = 0; row < rows; row++) { 2324 for (col = 0; col < columns; col++) { 2325 if (b < &bfunc[nbfunc]) { 2326 w = strlen(b->bname); 2327 xprintf("%s", b->bname); 2328 if (col < (columns - 1)) /* Not last column? */ 2329 for (; w < maxwidth; w++) 2330 xputchar(' '); 2331 ++b; 2332 } 2333 } 2334 if (row < (rows - 1)) { 2335 if (Tty_raw_mode) 2336 xputchar('\r'); 2337 xputchar('\n'); 2338 } 2339 } 2340#ifdef WINNT_NATIVE 2341 nt_print_builtins(maxwidth); 2342#else 2343 if (Tty_raw_mode) 2344 xputchar('\r'); 2345 xputchar('\n'); 2346#endif /* WINNT_NATIVE */ 2347 2348 cleanup_until(&lbuffed); /* turn back on line buffering */ 2349 flush(); 2350} 2351 2352#ifdef NLS_CATALOGS 2353char * 2354xcatgets(nl_catd ctd, int set_id, int msg_id, const char *s) 2355{ 2356 char *res; 2357 2358 errno = 0; 2359 while ((res = catgets(ctd, set_id, msg_id, s)) == s && errno == EINTR) { 2360 handle_pending_signals(); 2361 errno = 0; 2362 } 2363 return res; 2364} 2365 2366 2367# if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2368char * 2369iconv_catgets(nl_catd ctd, int set_id, int msg_id, const char *s) 2370{ 2371 static char *buf = NULL; 2372 static size_t buf_size = 0; 2373 2374 char *orig, *dest, *p; 2375 ICONV_CONST char *src; 2376 size_t src_size, dest_size; 2377 2378 orig = xcatgets(ctd, set_id, msg_id, s); 2379 if (catgets_iconv == (iconv_t)-1 || orig == s) 2380 return orig; 2381 src = orig; 2382 src_size = strlen(src) + 1; 2383 if (buf == NULL && (buf = xmalloc(buf_size = src_size + 32)) == NULL) 2384 return orig; 2385 dest = buf; 2386 while (src_size != 0) { 2387 dest_size = buf + buf_size - dest; 2388 if (iconv(catgets_iconv, &src, &src_size, &dest, &dest_size) 2389 == (size_t)-1) { 2390 switch (errno) { 2391 case E2BIG: 2392 if ((p = xrealloc(buf, buf_size * 2)) == NULL) 2393 return orig; 2394 buf_size *= 2; 2395 dest = p + (dest - buf); 2396 buf = p; 2397 break; 2398 2399 case EILSEQ: case EINVAL: default: 2400 return orig; 2401 } 2402 } 2403 } 2404 return buf; 2405} 2406# endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2407#endif /* NLS_CATALOGS */ 2408 2409void 2410nlsinit(void) 2411{ 2412#ifdef NLS_CATALOGS 2413 static const char default_catalog[] = "tcsh"; 2414 2415 char *catalog = (char *)(intptr_t)default_catalog; 2416 2417 if (adrof(STRcatalog) != NULL) 2418 catalog = xasprintf("tcsh.%s", short2str(varval(STRcatalog))); 2419 catd = catopen(catalog, MCLoadBySet); 2420 if (catalog != default_catalog) 2421 xfree(catalog); 2422#if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2423 /* xcatgets (), not CGETS, the charset name should be in ASCII anyway. */ 2424 catgets_iconv = iconv_open (nl_langinfo (CODESET), 2425 xcatgets(catd, 255, 1, "ASCII")); 2426#endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2427#endif /* NLS_CATALOGS */ 2428#ifdef WINNT_NATIVE 2429 nls_dll_init(); 2430#endif /* WINNT_NATIVE */ 2431 errinit(); /* init the errorlist in correct locale */ 2432 mesginit(); /* init the messages for signals */ 2433 dateinit(); /* init the messages for dates */ 2434 editinit(); /* init the editor messages */ 2435 terminit(); /* init the termcap messages */ 2436} 2437 2438void 2439nlsclose(void) 2440{ 2441#ifdef NLS_CATALOGS 2442#if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2443 if (catgets_iconv != (iconv_t)-1) { 2444 iconv_close(catgets_iconv); 2445 catgets_iconv = (iconv_t)-1; 2446 } 2447#endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2448 if (catd != (nl_catd)-1) { 2449 /* 2450 * catclose can call other functions which can call longjmp 2451 * making us re-enter this code. Prevent infinite recursion 2452 * by resetting catd. Problem reported and solved by: 2453 * Gerhard Niklasch 2454 */ 2455 nl_catd oldcatd = catd; 2456 catd = (nl_catd)-1; 2457 while (catclose(oldcatd) == -1 && errno == EINTR) 2458 handle_pending_signals(); 2459 } 2460#endif /* NLS_CATALOGS */ 2461} 2462