1 /* $Header: /p/tcsh/cvsroot/tcsh/sh.func.c,v 3.162 2011/02/26 00:07:06 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.162 2011/02/26 00:07:06 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) 45 static iconv_t catgets_iconv; /* Or (iconv_t)-1 */ 46 #endif 47 48 /* 49 * C shell 50 */ 51 52 extern int MapsAreInited; 53 extern int NLSMapsAreInited; 54 extern int GotTermCaps; 55 56 static int zlast = -1; 57 58 static void islogin (void); 59 static void preread (void); 60 static void doagain (void); 61 static const char *isrchx (int); 62 static void search (int, int, Char *); 63 static int getword (struct Strbuf *); 64 static struct wordent *histgetword (struct wordent *); 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 cp = sp = strip(*v); 523 if (!letter(*cp)) 524 stderror(ERR_NAME | ERR_VARBEGIN); 525 do { 526 cp++; 527 } while (alnum(*cp)); 528 if (*cp != '\0') 529 stderror(ERR_NAME | ERR_VARALNUM); 530 cp = *v++; 531 if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') 532 stderror(ERR_NAME | ERR_NOPAREN); 533 v++; 534 gflag = tglob(v); 535 if (gflag) { 536 v = globall(v, gflag); 537 if (v == 0 && !noexec) 538 stderror(ERR_NAME | ERR_NOMATCH); 539 } 540 else { 541 v = saveblk(v); 542 trim(v); 543 } 544 nwp = xcalloc(1, sizeof *nwp); 545 nwp->w_fe = nwp->w_fe0 = v; 546 btell(&nwp->w_start); 547 nwp->w_fename = Strsave(cp); 548 nwp->w_next = whyles; 549 nwp->w_end.type = TCSH_F_SEEK; 550 whyles = nwp; 551 /* 552 * Pre-read the loop so as to be more comprehensible to a terminal user. 553 */ 554 zlast = TC_FOREACH; 555 if (intty) 556 preread(); 557 if (!noexec) 558 doagain(); 559 } 560 561 /*ARGSUSED*/ 562 void 563 dowhile(Char **v, struct command *c) 564 { 565 int status; 566 int again = whyles != 0 && 567 SEEKEQ(&whyles->w_start, &lineloc) && 568 whyles->w_fename == 0; 569 570 USE(c); 571 v++; 572 /* 573 * Implement prereading here also, taking care not to evaluate the 574 * expression before the loop has been read up from a terminal. 575 */ 576 if (noexec) 577 status = 0; 578 else if (intty && !again) 579 status = !exp0(&v, 1); 580 else 581 status = !expr(&v); 582 if (*v && !noexec) 583 stderror(ERR_NAME | ERR_EXPRESSION); 584 if (!again) { 585 struct whyle *nwp = xcalloc(1, sizeof(*nwp)); 586 587 nwp->w_start = lineloc; 588 nwp->w_end.type = TCSH_F_SEEK; 589 nwp->w_end.f_seek = 0; 590 nwp->w_end.a_seek = 0; 591 nwp->w_next = whyles; 592 whyles = nwp; 593 zlast = TC_WHILE; 594 if (intty) { 595 /* 596 * The tty preread 597 */ 598 preread(); 599 doagain(); 600 return; 601 } 602 } 603 if (status) 604 /* We ain't gonna loop no more, no more! */ 605 toend(); 606 } 607 608 static void 609 preread(void) 610 { 611 int old_pintr_disabled; 612 613 whyles->w_end.type = TCSH_I_SEEK; 614 if (setintr) 615 pintr_push_enable(&old_pintr_disabled); 616 search(TC_BREAK, 0, NULL); /* read the expression in */ 617 if (setintr) 618 cleanup_until(&old_pintr_disabled); 619 btell(&whyles->w_end); 620 } 621 622 /*ARGSUSED*/ 623 void 624 doend(Char **v, struct command *c) 625 { 626 USE(v); 627 USE(c); 628 if (!whyles) 629 stderror(ERR_NAME | ERR_NOTWHILE); 630 btell(&whyles->w_end); 631 if (!noexec) 632 doagain(); 633 } 634 635 /*ARGSUSED*/ 636 void 637 docontin(Char **v, struct command *c) 638 { 639 USE(v); 640 USE(c); 641 if (!whyles) 642 stderror(ERR_NAME | ERR_NOTWHILE); 643 if (!noexec) 644 doagain(); 645 } 646 647 static void 648 doagain(void) 649 { 650 /* Repeating a while is simple */ 651 if (whyles->w_fename == 0) { 652 bseek(&whyles->w_start); 653 return; 654 } 655 /* 656 * The foreach variable list actually has a spurious word ")" at the end of 657 * the w_fe list. Thus we are at the of the list if one word beyond this 658 * is 0. 659 */ 660 if (!whyles->w_fe[1]) { 661 dobreak(NULL, NULL); 662 return; 663 } 664 setv(whyles->w_fename, quote(Strsave(*whyles->w_fe++)), VAR_READWRITE); 665 bseek(&whyles->w_start); 666 } 667 668 void 669 dorepeat(Char **v, struct command *kp) 670 { 671 int i = 1; 672 673 do { 674 i *= getn(v[1]); 675 lshift(v, 2); 676 } while (v[0] != NULL && Strcmp(v[0], STRrepeat) == 0); 677 if (noexec) 678 i = 1; 679 680 if (setintr) { 681 pintr_disabled++; 682 cleanup_push(&pintr_disabled, disabled_cleanup); 683 } 684 while (i > 0) { 685 if (setintr && pintr_disabled == 1) { 686 cleanup_until(&pintr_disabled); 687 pintr_disabled++; 688 cleanup_push(&pintr_disabled, disabled_cleanup); 689 } 690 reexecute(kp); 691 --i; 692 } 693 if (setintr && pintr_disabled == 1) 694 cleanup_until(&pintr_disabled); 695 donefds(); 696 } 697 698 /*ARGSUSED*/ 699 void 700 doswbrk(Char **v, struct command *c) 701 { 702 USE(v); 703 USE(c); 704 if (!noexec) 705 search(TC_BRKSW, 0, NULL); 706 } 707 708 int 709 srchx(Char *cp) 710 { 711 struct srch *sp, *sp1, *sp2; 712 int i; 713 714 /* 715 * Ignore keywords inside heredocs 716 */ 717 if (inheredoc) 718 return -1; 719 720 /* 721 * Binary search Sp1 is the beginning of the current search range. Sp2 is 722 * one past the end. 723 */ 724 for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) { 725 sp = sp1 + ((sp2 - sp1) >> 1); 726 if ((i = *cp - *sp->s_name) == 0 && 727 (i = Strcmp(cp, str2short(sp->s_name))) == 0) 728 return sp->s_value; 729 if (i < 0) 730 sp2 = sp; 731 else 732 sp1 = sp + 1; 733 } 734 return (-1); 735 } 736 737 static const char * 738 isrchx(int n) 739 { 740 struct srch *sp, *sp2; 741 742 for (sp = srchn, sp2 = srchn + nsrchn; sp < sp2; sp++) 743 if (sp->s_value == n) 744 return (sp->s_name); 745 return (""); 746 } 747 748 749 static int Stype; 750 static Char *Sgoal; 751 752 static void 753 search(int type, int level, Char *goal) 754 { 755 struct Strbuf word = Strbuf_INIT; 756 Char *cp; 757 struct whyle *wp; 758 int wlevel = 0; 759 struct wordent *histent = NULL, *ohistent = NULL; 760 761 Stype = type; 762 Sgoal = goal; 763 if (type == TC_GOTO) { 764 struct Ain a; 765 a.type = TCSH_F_SEEK; 766 a.f_seek = 0; 767 a.a_seek = 0; 768 bseek(&a); 769 } 770 cleanup_push(&word, Strbuf_cleanup); 771 do { 772 773 if (intty) { 774 histent = xmalloc(sizeof(*histent)); 775 ohistent = xmalloc(sizeof(*histent)); 776 ohistent->word = STRNULL; 777 ohistent->next = histent; 778 histent->prev = ohistent; 779 } 780 781 if (intty && fseekp == feobp && aret == TCSH_F_SEEK) 782 printprompt(1, isrchx(type == TC_BREAK ? zlast : type)); 783 /* xprintf("? "), flush(); */ 784 (void) getword(&word); 785 Strbuf_terminate(&word); 786 787 if (intty && Strlen(word.s) > 0) { 788 histent->word = Strsave(word.s); 789 histent->next = xmalloc(sizeof(*histent)); 790 histent->next->prev = histent; 791 histent = histent->next; 792 } 793 794 switch (srchx(word.s)) { 795 796 case TC_ELSE: 797 if (level == 0 && type == TC_IF) 798 goto end; 799 break; 800 801 case TC_IF: 802 while (getword(&word)) 803 continue; 804 if ((type == TC_IF || type == TC_ELSE) && 805 eq(word.s, STRthen)) 806 level++; 807 break; 808 809 case TC_ENDIF: 810 if (type == TC_IF || type == TC_ELSE) 811 level--; 812 break; 813 814 case TC_FOREACH: 815 case TC_WHILE: 816 wlevel++; 817 if (type == TC_BREAK) 818 level++; 819 break; 820 821 case TC_END: 822 if (type == TC_BRKSW) { 823 if (wlevel == 0) { 824 wp = whyles; 825 if (wp) { 826 whyles = wp->w_next; 827 wpfree(wp); 828 } 829 } 830 } 831 if (type == TC_BREAK) 832 level--; 833 wlevel--; 834 break; 835 836 case TC_SWITCH: 837 if (type == TC_SWITCH || type == TC_BRKSW) 838 level++; 839 break; 840 841 case TC_ENDSW: 842 if (type == TC_SWITCH || type == TC_BRKSW) 843 level--; 844 break; 845 846 case TC_LABEL: 847 if (type == TC_GOTO && getword(&word) && eq(word.s, goal)) 848 level = -1; 849 break; 850 851 default: 852 if (type != TC_GOTO && (type != TC_SWITCH || level != 0)) 853 break; 854 if (word.len == 0 || word.s[word.len - 1] != ':') 855 break; 856 word.s[--word.len] = 0; 857 if ((type == TC_GOTO && eq(word.s, goal)) || 858 (type == TC_SWITCH && eq(word.s, STRdefault))) 859 level = -1; 860 break; 861 862 case TC_CASE: 863 if (type != TC_SWITCH || level != 0) 864 break; 865 (void) getword(&word); 866 if (word.len != 0 && word.s[word.len - 1] == ':') 867 word.s[--word.len] = 0; 868 cp = strip(Dfix1(word.s)); 869 cleanup_push(cp, xfree); 870 if (Gmatch(goal, cp)) 871 level = -1; 872 cleanup_until(cp); 873 break; 874 875 case TC_DEFAULT: 876 if (type == TC_SWITCH && level == 0) 877 level = -1; 878 break; 879 } 880 if (intty) { 881 ohistent->prev = histgetword(histent); 882 ohistent->prev->next = ohistent; 883 savehist(ohistent, 0); 884 freelex(ohistent); 885 xfree(ohistent); 886 } else 887 (void) getword(NULL); 888 } while (level >= 0); 889 end: 890 cleanup_until(&word); 891 } 892 893 static struct wordent * 894 histgetword(struct wordent *histent) 895 { 896 int found = 0, first; 897 eChar c, d; 898 int e; 899 struct Strbuf *tmp; 900 tmp = xmalloc(sizeof(*tmp)); 901 tmp->size = 0; 902 tmp->s = NULL; 903 c = readc(1); 904 d = 0; 905 e = 0; 906 for (;;) { 907 tmp->len = 0; 908 Strbuf_terminate (tmp); 909 while (c == ' ' || c == '\t') 910 c = readc(1); 911 if (c == '#') 912 do 913 c = readc(1); 914 while (c != CHAR_ERR && c != '\n'); 915 if (c == CHAR_ERR) 916 goto past; 917 if (c == '\n') 918 goto nl; 919 unreadc(c); 920 found = 1; 921 first = 1; 922 do { 923 e = (c == '\\'); 924 c = readc(1); 925 if (c == '\\' && !e) { 926 if ((c = readc(1)) == '\n') { 927 e = 1; 928 c = ' '; 929 } else { 930 unreadc(c); 931 c = '\\'; 932 } 933 } 934 if ((c == '\'' || c == '"') && !e) { 935 if (d == 0) 936 d = c; 937 else if (d == c) 938 d = 0; 939 } 940 if (c == CHAR_ERR) 941 goto past; 942 943 Strbuf_append1(tmp, (Char) c); 944 945 if (!first && !d && c == '(' && !e) { 946 break; 947 } 948 first = 0; 949 } while (d || e || (c != ' ' && c != '\t' && c != '\n')); 950 tmp->len--; 951 if (tmp->len) { 952 Strbuf_terminate(tmp); 953 histent->word = Strsave(tmp->s); 954 histent->next = xmalloc(sizeof (*histent)); 955 histent->next->prev = histent; 956 histent = histent->next; 957 } 958 if (c == '\n') { 959 nl: 960 tmp->len = 0; 961 Strbuf_append1(tmp, (Char) c); 962 Strbuf_terminate(tmp); 963 histent->word = Strsave(tmp->s); 964 return histent; 965 } 966 } 967 968 past: 969 switch (Stype) { 970 971 case TC_IF: 972 stderror(ERR_NAME | ERR_NOTFOUND, "then/endif"); 973 break; 974 975 case TC_ELSE: 976 stderror(ERR_NAME | ERR_NOTFOUND, "endif"); 977 break; 978 979 case TC_BRKSW: 980 case TC_SWITCH: 981 stderror(ERR_NAME | ERR_NOTFOUND, "endsw"); 982 break; 983 984 case TC_BREAK: 985 stderror(ERR_NAME | ERR_NOTFOUND, "end"); 986 break; 987 988 case TC_GOTO: 989 setname(short2str(Sgoal)); 990 stderror(ERR_NAME | ERR_NOTFOUND, "label"); 991 break; 992 993 default: 994 break; 995 } 996 /* NOTREACHED */ 997 return NULL; 998 } 999 1000 static int 1001 getword(struct Strbuf *wp) 1002 { 1003 int found = 0, first; 1004 eChar c, d; 1005 1006 if (wp) 1007 wp->len = 0; 1008 c = readc(1); 1009 d = 0; 1010 do { 1011 while (c == ' ' || c == '\t') 1012 c = readc(1); 1013 if (c == '#') 1014 do 1015 c = readc(1); 1016 while (c != CHAR_ERR && c != '\n'); 1017 if (c == CHAR_ERR) 1018 goto past; 1019 if (c == '\n') { 1020 if (wp) 1021 break; 1022 return (0); 1023 } 1024 unreadc(c); 1025 found = 1; 1026 first = 1; 1027 do { 1028 c = readc(1); 1029 if (c == '\\' && (c = readc(1)) == '\n') 1030 c = ' '; 1031 if (c == '\'' || c == '"') { 1032 if (d == 0) 1033 d = c; 1034 else if (d == c) 1035 d = 0; 1036 } 1037 if (c == CHAR_ERR) 1038 goto past; 1039 if (wp) 1040 Strbuf_append1(wp, (Char) c); 1041 if (!first && !d && c == '(') { 1042 if (wp) 1043 goto past_word_end; 1044 else 1045 break; 1046 } 1047 first = 0; 1048 } while ((d || (c != ' ' && c != '\t')) && c != '\n'); 1049 } while (wp == 0); 1050 1051 past_word_end: 1052 unreadc(c); 1053 if (found) { 1054 wp->len--; 1055 Strbuf_terminate(wp); 1056 } 1057 1058 return (found); 1059 1060 past: 1061 switch (Stype) { 1062 1063 case TC_IF: 1064 stderror(ERR_NAME | ERR_NOTFOUND, "then/endif"); 1065 break; 1066 1067 case TC_ELSE: 1068 stderror(ERR_NAME | ERR_NOTFOUND, "endif"); 1069 break; 1070 1071 case TC_BRKSW: 1072 case TC_SWITCH: 1073 stderror(ERR_NAME | ERR_NOTFOUND, "endsw"); 1074 break; 1075 1076 case TC_BREAK: 1077 stderror(ERR_NAME | ERR_NOTFOUND, "end"); 1078 break; 1079 1080 case TC_GOTO: 1081 setname(short2str(Sgoal)); 1082 stderror(ERR_NAME | ERR_NOTFOUND, "label"); 1083 break; 1084 1085 default: 1086 break; 1087 } 1088 /* NOTREACHED */ 1089 return (0); 1090 } 1091 1092 static void 1093 toend(void) 1094 { 1095 if (whyles->w_end.type == TCSH_F_SEEK && whyles->w_end.f_seek == 0) { 1096 search(TC_BREAK, 0, NULL); 1097 btell(&whyles->w_end); 1098 whyles->w_end.f_seek--; 1099 } 1100 else { 1101 bseek(&whyles->w_end); 1102 } 1103 wfree(); 1104 } 1105 1106 static void 1107 wpfree(struct whyle *wp) 1108 { 1109 if (wp->w_fe0) 1110 blkfree(wp->w_fe0); 1111 xfree(wp->w_fename); 1112 xfree(wp); 1113 } 1114 1115 void 1116 wfree(void) 1117 { 1118 struct Ain o; 1119 struct whyle *nwp; 1120 #ifdef lint 1121 nwp = NULL; /* sun lint is dumb! */ 1122 #endif 1123 1124 #ifdef FDEBUG 1125 static const char foo[] = "IAFE"; 1126 #endif /* FDEBUG */ 1127 1128 btell(&o); 1129 1130 #ifdef FDEBUG 1131 xprintf("o->type %c o->a_seek %d o->f_seek %d\n", 1132 foo[o.type + 1], o.a_seek, o.f_seek); 1133 #endif /* FDEBUG */ 1134 1135 for (; whyles; whyles = nwp) { 1136 struct whyle *wp = whyles; 1137 nwp = wp->w_next; 1138 1139 #ifdef FDEBUG 1140 xprintf("start->type %c start->a_seek %d start->f_seek %d\n", 1141 foo[wp->w_start.type+1], 1142 wp->w_start.a_seek, wp->w_start.f_seek); 1143 xprintf("end->type %c end->a_seek %d end->f_seek %d\n", 1144 foo[wp->w_end.type + 1], wp->w_end.a_seek, wp->w_end.f_seek); 1145 #endif /* FDEBUG */ 1146 1147 /* 1148 * XXX: We free loops that have different seek types. 1149 */ 1150 if (wp->w_end.type != TCSH_I_SEEK && wp->w_start.type == wp->w_end.type && 1151 wp->w_start.type == o.type) { 1152 if (wp->w_end.type == TCSH_F_SEEK) { 1153 if (o.f_seek >= wp->w_start.f_seek && 1154 (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek)) 1155 break; 1156 } 1157 else { 1158 if (o.a_seek >= wp->w_start.a_seek && 1159 (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek)) 1160 break; 1161 } 1162 } 1163 1164 wpfree(wp); 1165 } 1166 } 1167 1168 /*ARGSUSED*/ 1169 void 1170 doecho(Char **v, struct command *c) 1171 { 1172 USE(c); 1173 xecho(' ', v); 1174 } 1175 1176 /*ARGSUSED*/ 1177 void 1178 doglob(Char **v, struct command *c) 1179 { 1180 USE(c); 1181 xecho(0, v); 1182 flush(); 1183 } 1184 1185 static void 1186 xecho(int sep, Char **v) 1187 { 1188 Char *cp, **globbed = NULL; 1189 int nonl = 0; 1190 int echo_style = ECHO_STYLE; 1191 struct varent *vp; 1192 1193 if ((vp = adrof(STRecho_style)) != NULL && vp->vec != NULL && 1194 vp->vec[0] != NULL) { 1195 if (Strcmp(vp->vec[0], STRbsd) == 0) 1196 echo_style = BSD_ECHO; 1197 else if (Strcmp(vp->vec[0], STRsysv) == 0) 1198 echo_style = SYSV_ECHO; 1199 else if (Strcmp(vp->vec[0], STRboth) == 0) 1200 echo_style = BOTH_ECHO; 1201 else if (Strcmp(vp->vec[0], STRnone) == 0) 1202 echo_style = NONE_ECHO; 1203 } 1204 1205 v++; 1206 if (*v == 0) 1207 goto done; 1208 if (setintr) { 1209 int old_pintr_disabled; 1210 pintr_push_enable(&old_pintr_disabled); 1211 v = glob_all_or_error(v); 1212 cleanup_until(&old_pintr_disabled); 1213 } else { 1214 v = glob_all_or_error(v); 1215 } 1216 globbed = v; 1217 if (globbed != NULL) 1218 cleanup_push(globbed, blk_cleanup); 1219 1220 if ((echo_style & BSD_ECHO) != 0 && sep == ' ' && *v && eq(*v, STRmn)) 1221 nonl++, v++; 1222 1223 while ((cp = *v++) != 0) { 1224 Char c; 1225 1226 if (setintr) { 1227 int old_pintr_disabled; 1228 1229 pintr_push_enable(&old_pintr_disabled); 1230 cleanup_until(&old_pintr_disabled); 1231 } 1232 while ((c = *cp++) != 0) { 1233 if ((echo_style & SYSV_ECHO) != 0 && c == '\\') { 1234 switch (c = *cp++) { 1235 case 'a': 1236 c = '\a'; 1237 break; 1238 case 'b': 1239 c = '\b'; 1240 break; 1241 case 'c': 1242 nonl = 1; 1243 goto done; 1244 case 'e': 1245 #if 0 /* Windows does not understand \e */ 1246 c = '\e'; 1247 #else 1248 c = CTL_ESC('\033'); 1249 #endif 1250 break; 1251 case 'f': 1252 c = '\f'; 1253 break; 1254 case 'n': 1255 c = '\n'; 1256 break; 1257 case 'r': 1258 c = '\r'; 1259 break; 1260 case 't': 1261 c = '\t'; 1262 break; 1263 case 'v': 1264 c = '\v'; 1265 break; 1266 case '\\': 1267 c = '\\'; 1268 break; 1269 case '0': 1270 c = 0; 1271 if (*cp >= '0' && *cp < '8') 1272 c = c * 8 + *cp++ - '0'; 1273 if (*cp >= '0' && *cp < '8') 1274 c = c * 8 + *cp++ - '0'; 1275 if (*cp >= '0' && *cp < '8') 1276 c = c * 8 + *cp++ - '0'; 1277 break; 1278 case '\0': 1279 c = '\\'; 1280 cp--; 1281 break; 1282 default: 1283 xputchar('\\' | QUOTE); 1284 break; 1285 } 1286 } 1287 xputwchar(c | QUOTE); 1288 1289 } 1290 if (*v) 1291 xputchar(sep | QUOTE); 1292 } 1293 done: 1294 if (sep && nonl == 0) 1295 xputchar('\n'); 1296 else 1297 flush(); 1298 if (globbed != NULL) 1299 cleanup_until(globbed); 1300 } 1301 1302 /* check whether an environment variable should invoke 'set_locale()' */ 1303 static int 1304 islocale_var(Char *var) 1305 { 1306 static Char *locale_vars[] = { 1307 STRLANG, STRLC_ALL, STRLC_CTYPE, STRLC_NUMERIC, 1308 STRLC_TIME, STRLC_COLLATE, STRLC_MESSAGES, STRLC_MONETARY, 0 1309 }; 1310 Char **v; 1311 1312 for (v = locale_vars; *v; ++v) 1313 if (eq(var, *v)) 1314 return 1; 1315 return 0; 1316 } 1317 1318 static void 1319 xlate_cr_cleanup(void *dummy) 1320 { 1321 USE(dummy); 1322 xlate_cr = 0; 1323 } 1324 1325 /*ARGSUSED*/ 1326 void 1327 doprintenv(Char **v, struct command *c) 1328 { 1329 Char *e; 1330 1331 USE(c); 1332 v++; 1333 if (*v == 0) { 1334 Char **ep; 1335 1336 xlate_cr = 1; 1337 cleanup_push(&xlate_cr, xlate_cr_cleanup); 1338 for (ep = STR_environ; *ep; ep++) { 1339 if (setintr) { 1340 int old_pintr_disabled; 1341 1342 pintr_push_enable(&old_pintr_disabled); 1343 cleanup_until(&old_pintr_disabled); 1344 } 1345 xprintf("%S\n", *ep); 1346 } 1347 cleanup_until(&xlate_cr); 1348 } 1349 else if ((e = tgetenv(*v)) != NULL) { 1350 int old_output_raw; 1351 1352 old_output_raw = output_raw; 1353 output_raw = 1; 1354 cleanup_push(&old_output_raw, output_raw_restore); 1355 xprintf("%S\n", e); 1356 cleanup_until(&old_output_raw); 1357 } 1358 else 1359 setcopy(STRstatus, STR1, VAR_READWRITE); 1360 } 1361 1362 /* from "Karl Berry." <karl%mote.umb.edu@relay.cs.net> -- for NeXT things 1363 (and anything else with a modern compiler) */ 1364 1365 /*ARGSUSED*/ 1366 void 1367 dosetenv(Char **v, struct command *c) 1368 { 1369 Char *vp, *lp; 1370 1371 USE(c); 1372 if (*++v == 0) { 1373 doprintenv(--v, 0); 1374 return; 1375 } 1376 1377 vp = *v++; 1378 lp = vp; 1379 1380 if (!letter(*lp)) 1381 stderror(ERR_NAME | ERR_VARBEGIN); 1382 do { 1383 lp++; 1384 } while (alnum(*lp)); 1385 if (*lp != '\0') 1386 stderror(ERR_NAME | ERR_VARALNUM); 1387 1388 if ((lp = *v++) == 0) 1389 lp = STRNULL; 1390 1391 lp = globone(lp, G_APPEND); 1392 cleanup_push(lp, xfree); 1393 tsetenv(vp, lp); 1394 if (eq(vp, STRKPATH)) { 1395 importpath(lp); 1396 dohash(NULL, NULL); 1397 cleanup_until(lp); 1398 return; 1399 } 1400 1401 #ifdef apollo 1402 if (eq(vp, STRSYSTYPE)) { 1403 dohash(NULL, NULL); 1404 cleanup_until(lp); 1405 return; 1406 } 1407 #endif /* apollo */ 1408 1409 /* dspkanji/dspmbyte autosetting */ 1410 /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */ 1411 #if defined(DSPMBYTE) 1412 if(eq(vp, STRLANG) && !adrof(CHECK_MBYTEVAR)) { 1413 autoset_dspmbyte(lp); 1414 } 1415 #endif 1416 1417 if (islocale_var(vp)) { 1418 #ifdef NLS 1419 int k; 1420 1421 # ifdef SETLOCALEBUG 1422 dont_free = 1; 1423 # endif /* SETLOCALEBUG */ 1424 (void) setlocale(LC_ALL, ""); 1425 # ifdef LC_COLLATE 1426 (void) setlocale(LC_COLLATE, ""); 1427 # endif 1428 # ifdef LC_CTYPE 1429 (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 1430 # endif /* LC_CTYPE */ 1431 # if defined(AUTOSET_KANJI) 1432 autoset_kanji(); 1433 # endif /* AUTOSET_KANJI */ 1434 # ifdef NLS_CATALOGS 1435 # ifdef LC_MESSAGES 1436 (void) setlocale(LC_MESSAGES, ""); 1437 # endif /* LC_MESSAGES */ 1438 nlsclose(); 1439 nlsinit(); 1440 # endif /* NLS_CATALOGS */ 1441 # ifdef SETLOCALEBUG 1442 dont_free = 0; 1443 # endif /* SETLOCALEBUG */ 1444 # ifdef STRCOLLBUG 1445 fix_strcoll_bug(); 1446 # endif /* STRCOLLBUG */ 1447 tw_cmd_free(); /* since the collation sequence has changed */ 1448 for (k = 0200; k <= 0377 && !Isprint(CTL_ESC(k)); k++) 1449 continue; 1450 AsciiOnly = MB_CUR_MAX == 1 && k > 0377; 1451 #else /* !NLS */ 1452 AsciiOnly = 0; 1453 #endif /* NLS */ 1454 NLSMapsAreInited = 0; 1455 ed_Init(); 1456 if (MapsAreInited && !NLSMapsAreInited) 1457 ed_InitNLSMaps(); 1458 cleanup_until(lp); 1459 return; 1460 } 1461 1462 #ifdef NLS_CATALOGS 1463 if (eq(vp, STRNLSPATH)) { 1464 nlsclose(); 1465 nlsinit(); 1466 } 1467 #endif 1468 1469 if (eq(vp, STRNOREBIND)) { 1470 NoNLSRebind = 1; 1471 MapsAreInited = 0; 1472 NLSMapsAreInited = 0; 1473 ed_InitMaps(); 1474 cleanup_until(lp); 1475 return; 1476 } 1477 #ifdef WINNT_NATIVE 1478 if (eq(vp, STRtcshlang)) { 1479 nlsinit(); 1480 cleanup_until(lp); 1481 return; 1482 } 1483 #endif /* WINNT_NATIVE */ 1484 if (eq(vp, STRKTERM)) { 1485 char *t; 1486 1487 setv(STRterm, quote(lp), VAR_READWRITE); /* lp memory used here */ 1488 cleanup_ignore(lp); 1489 cleanup_until(lp); 1490 t = short2str(lp); 1491 if (noediting && strcmp(t, "unknown") != 0 && strcmp(t,"dumb") != 0) { 1492 editing = 1; 1493 noediting = 0; 1494 setNS(STRedit); 1495 } 1496 GotTermCaps = 0; 1497 ed_Init(); 1498 return; 1499 } 1500 1501 if (eq(vp, STRKHOME)) { 1502 Char *canon; 1503 /* 1504 * convert to canonical pathname (possibly resolving symlinks) 1505 */ 1506 canon = dcanon(lp, lp); 1507 cleanup_ignore(lp); 1508 cleanup_until(lp); 1509 cleanup_push(canon, xfree); 1510 setv(STRhome, quote(canon), VAR_READWRITE); /* lp memory used here */ 1511 cleanup_ignore(canon); 1512 cleanup_until(canon); 1513 1514 /* fix directory stack for new tilde home */ 1515 dtilde(); 1516 return; 1517 } 1518 1519 if (eq(vp, STRKSHLVL)) { 1520 setv(STRshlvl, quote(lp), VAR_READWRITE); /* lp memory used here */ 1521 cleanup_ignore(lp); 1522 cleanup_until(lp); 1523 return; 1524 } 1525 1526 if (eq(vp, STRKUSER)) { 1527 setv(STRuser, quote(lp), VAR_READWRITE); /* lp memory used here */ 1528 cleanup_ignore(lp); 1529 cleanup_until(lp); 1530 return; 1531 } 1532 1533 if (eq(vp, STRKGROUP)) { 1534 setv(STRgroup, quote(lp), VAR_READWRITE); /* lp memory used here */ 1535 cleanup_ignore(lp); 1536 cleanup_until(lp); 1537 return; 1538 } 1539 1540 #ifdef COLOR_LS_F 1541 if (eq(vp, STRLS_COLORS)) { 1542 parseLS_COLORS(lp); 1543 cleanup_until(lp); 1544 return; 1545 } 1546 #endif /* COLOR_LS_F */ 1547 1548 #ifdef SIG_WINDOW 1549 /* 1550 * Load/Update $LINES $COLUMNS 1551 */ 1552 if ((eq(lp, STRNULL) && (eq(vp, STRLINES) || eq(vp, STRCOLUMNS))) || 1553 eq(vp, STRTERMCAP)) { 1554 cleanup_until(lp); 1555 check_window_size(1); 1556 return; 1557 } 1558 1559 /* 1560 * Change the size to the one directed by $LINES and $COLUMNS 1561 */ 1562 if (eq(vp, STRLINES) || eq(vp, STRCOLUMNS)) { 1563 #if 0 1564 GotTermCaps = 0; 1565 #endif 1566 cleanup_until(lp); 1567 ed_Init(); 1568 return; 1569 } 1570 #endif /* SIG_WINDOW */ 1571 cleanup_until(lp); 1572 } 1573 1574 /*ARGSUSED*/ 1575 void 1576 dounsetenv(Char **v, struct command *c) 1577 { 1578 Char **ep, *p, *n, *name; 1579 int i, maxi; 1580 1581 USE(c); 1582 /* 1583 * Find the longest environment variable 1584 */ 1585 for (maxi = 0, ep = STR_environ; *ep; ep++) { 1586 for (i = 0, p = *ep; *p && *p != '='; p++, i++) 1587 continue; 1588 if (i > maxi) 1589 maxi = i; 1590 } 1591 1592 name = xmalloc((maxi + 1) * sizeof(Char)); 1593 cleanup_push(name, xfree); 1594 1595 while (++v && *v) 1596 for (maxi = 1; maxi;) 1597 for (maxi = 0, ep = STR_environ; *ep; ep++) { 1598 for (n = name, p = *ep; *p && *p != '='; *n++ = *p++) 1599 continue; 1600 *n = '\0'; 1601 if (!Gmatch(name, *v)) 1602 continue; 1603 maxi = 1; 1604 1605 /* Unset the name. This wasn't being done until 1606 * later but most of the stuff following won't 1607 * work (particularly the setlocale() and getenv() 1608 * stuff) as intended until the name is actually 1609 * removed. (sg) 1610 */ 1611 Unsetenv(name); 1612 1613 if (eq(name, STRNOREBIND)) { 1614 NoNLSRebind = 0; 1615 MapsAreInited = 0; 1616 NLSMapsAreInited = 0; 1617 ed_InitMaps(); 1618 } 1619 #ifdef apollo 1620 else if (eq(name, STRSYSTYPE)) 1621 dohash(NULL, NULL); 1622 #endif /* apollo */ 1623 else if (islocale_var(name)) { 1624 #ifdef NLS 1625 int k; 1626 1627 # ifdef SETLOCALEBUG 1628 dont_free = 1; 1629 # endif /* SETLOCALEBUG */ 1630 (void) setlocale(LC_ALL, ""); 1631 # ifdef LC_COLLATE 1632 (void) setlocale(LC_COLLATE, ""); 1633 # endif 1634 # ifdef LC_CTYPE 1635 (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 1636 # endif /* LC_CTYPE */ 1637 # ifdef NLS_CATALOGS 1638 # ifdef LC_MESSAGES 1639 (void) setlocale(LC_MESSAGES, ""); 1640 # endif /* LC_MESSAGES */ 1641 nlsclose(); 1642 nlsinit(); 1643 # endif /* NLS_CATALOGS */ 1644 # ifdef SETLOCALEBUG 1645 dont_free = 0; 1646 # endif /* SETLOCALEBUG */ 1647 # ifdef STRCOLLBUG 1648 fix_strcoll_bug(); 1649 # endif /* STRCOLLBUG */ 1650 tw_cmd_free();/* since the collation sequence has changed */ 1651 for (k = 0200; k <= 0377 && !Isprint(CTL_ESC(k)); k++) 1652 continue; 1653 AsciiOnly = MB_CUR_MAX == 1 && k > 0377; 1654 #else /* !NLS */ 1655 AsciiOnly = getenv("LANG") == NULL && 1656 getenv("LC_CTYPE") == NULL; 1657 #endif /* NLS */ 1658 NLSMapsAreInited = 0; 1659 ed_Init(); 1660 if (MapsAreInited && !NLSMapsAreInited) 1661 ed_InitNLSMaps(); 1662 1663 } 1664 #ifdef WINNT_NATIVE 1665 else if (eq(name,(STRtcshlang))) { 1666 nls_dll_unload(); 1667 nlsinit(); 1668 } 1669 #endif /* WINNT_NATIVE */ 1670 #ifdef COLOR_LS_F 1671 else if (eq(name, STRLS_COLORS)) 1672 parseLS_COLORS(n); 1673 #endif /* COLOR_LS_F */ 1674 #ifdef NLS_CATALOGS 1675 else if (eq(name, STRNLSPATH)) { 1676 nlsclose(); 1677 nlsinit(); 1678 } 1679 #endif 1680 /* 1681 * start again cause the environment changes 1682 */ 1683 break; 1684 } 1685 cleanup_until(name); 1686 } 1687 1688 void 1689 tsetenv(const Char *name, const Char *val) 1690 { 1691 #ifdef SETENV_IN_LIB 1692 /* 1693 * XXX: This does not work right, since tcsh cannot track changes to 1694 * the environment this way. (the builtin setenv without arguments does 1695 * not print the right stuff neither does unsetenv). This was for Mach, 1696 * it is not needed anymore. 1697 */ 1698 #undef setenv 1699 char *cname; 1700 1701 if (name == NULL) 1702 return; 1703 cname = strsave(short2str(name)); 1704 setenv(cname, short2str(val), 1); 1705 xfree(cname); 1706 #else /* !SETENV_IN_LIB */ 1707 Char **ep = STR_environ; 1708 const Char *ccp; 1709 Char *cp, *dp; 1710 Char *blk[2]; 1711 Char **oep = ep; 1712 1713 #ifdef WINNT_NATIVE 1714 nt_set_env(name,val); 1715 #endif /* WINNT_NATIVE */ 1716 for (; *ep; ep++) { 1717 #ifdef WINNT_NATIVE 1718 for (ccp = name, dp = *ep; *ccp && Tolower(*ccp & TRIM) == Tolower(*dp); 1719 ccp++, dp++) 1720 #else 1721 for (ccp = name, dp = *ep; *ccp && (*ccp & TRIM) == *dp; ccp++, dp++) 1722 #endif /* WINNT_NATIVE */ 1723 continue; 1724 if (*ccp != 0 || *dp != '=') 1725 continue; 1726 cp = Strspl(STRequal, val); 1727 xfree(*ep); 1728 *ep = strip(Strspl(name, cp)); 1729 xfree(cp); 1730 blkfree((Char **) environ); 1731 environ = short2blk(STR_environ); 1732 return; 1733 } 1734 cp = Strspl(name, STRequal); 1735 blk[0] = strip(Strspl(cp, val)); 1736 xfree(cp); 1737 blk[1] = 0; 1738 STR_environ = blkspl(STR_environ, blk); 1739 blkfree((Char **) environ); 1740 environ = short2blk(STR_environ); 1741 xfree(oep); 1742 #endif /* SETENV_IN_LIB */ 1743 } 1744 1745 void 1746 Unsetenv(Char *name) 1747 { 1748 Char **ep = STR_environ; 1749 Char *cp, *dp; 1750 Char **oep = ep; 1751 1752 #ifdef WINNT_NATIVE 1753 nt_set_env(name,NULL); 1754 #endif /*WINNT_NATIVE */ 1755 for (; *ep; ep++) { 1756 for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) 1757 continue; 1758 if (*cp != 0 || *dp != '=') 1759 continue; 1760 cp = *ep; 1761 *ep = 0; 1762 STR_environ = blkspl(STR_environ, ep + 1); 1763 blkfree((Char **) environ); 1764 environ = short2blk(STR_environ); 1765 *ep = cp; 1766 xfree(cp); 1767 xfree(oep); 1768 return; 1769 } 1770 } 1771 1772 /*ARGSUSED*/ 1773 void 1774 doumask(Char **v, struct command *c) 1775 { 1776 Char *cp = v[1]; 1777 int i; 1778 1779 USE(c); 1780 if (cp == 0) { 1781 i = (int)umask(0); 1782 (void) umask(i); 1783 xprintf("%o\n", i); 1784 return; 1785 } 1786 i = 0; 1787 while (Isdigit(*cp) && *cp != '8' && *cp != '9') 1788 i = i * 8 + *cp++ - '0'; 1789 if (*cp || i < 0 || i > 0777) 1790 stderror(ERR_NAME | ERR_MASK); 1791 (void) umask(i); 1792 } 1793 1794 #ifndef HAVENOLIMIT 1795 # ifndef BSDLIMIT 1796 typedef long RLIM_TYPE; 1797 # ifdef _OSD_POSIX /* BS2000 */ 1798 # include <ulimit.h> 1799 # endif 1800 # ifndef RLIM_INFINITY 1801 # if !defined(_MINIX) && !defined(__clipper__) && !defined(_CRAY) 1802 extern RLIM_TYPE ulimit(); 1803 # endif /* ! _MINIX && !__clipper__ */ 1804 # define RLIM_INFINITY 0x003fffff 1805 # define RLIMIT_FSIZE 1 1806 # endif /* RLIM_INFINITY */ 1807 # ifdef aiws 1808 # define toset(a) (((a) == 3) ? 1004 : (a) + 1) 1809 # define RLIMIT_DATA 3 1810 # define RLIMIT_STACK 1005 1811 # else /* aiws */ 1812 # define toset(a) ((a) + 1) 1813 # endif /* aiws */ 1814 # else /* BSDLIMIT */ 1815 # if (defined(BSD4_4) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) || (HPUXVERSION >= 1100)) && !defined(__386BSD__) 1816 typedef rlim_t RLIM_TYPE; 1817 # else 1818 # if defined(SOLARIS2) || (defined(sgi) && SYSVREL > 3) 1819 typedef rlim_t RLIM_TYPE; 1820 # else 1821 # if defined(_SX) 1822 typedef long long RLIM_TYPE; 1823 # else /* !_SX */ 1824 typedef unsigned long RLIM_TYPE; 1825 # endif /* _SX */ 1826 # endif /* SOLARIS2 || (sgi && SYSVREL > 3) */ 1827 # endif /* BSD4_4 && !__386BSD__ */ 1828 # endif /* BSDLIMIT */ 1829 1830 # if (HPUXVERSION > 700) && (HPUXVERSION < 1100) && defined(BSDLIMIT) 1831 /* Yes hpux8.0 has limits but <sys/resource.h> does not make them public */ 1832 /* Yes, we could have defined _KERNEL, and -I/etc/conf/h, but is that better? */ 1833 # ifndef RLIMIT_CPU 1834 # define RLIMIT_CPU 0 1835 # define RLIMIT_FSIZE 1 1836 # define RLIMIT_DATA 2 1837 # define RLIMIT_STACK 3 1838 # define RLIMIT_CORE 4 1839 # define RLIMIT_RSS 5 1840 # define RLIMIT_NOFILE 6 1841 # endif /* RLIMIT_CPU */ 1842 # ifndef RLIM_INFINITY 1843 # define RLIM_INFINITY 0x7fffffff 1844 # endif /* RLIM_INFINITY */ 1845 /* 1846 * old versions of HP/UX counted limits in 512 bytes 1847 */ 1848 # ifndef SIGRTMIN 1849 # define FILESIZE512 1850 # endif /* SIGRTMIN */ 1851 # endif /* (HPUXVERSION > 700) && (HPUXVERSION < 1100) && BSDLIMIT */ 1852 1853 # if SYSVREL > 3 && defined(BSDLIMIT) && !defined(_SX) 1854 /* In order to use rusage, we included "/usr/ucbinclude/sys/resource.h" in */ 1855 /* sh.h. However, some SVR4 limits are defined in <sys/resource.h>. Rather */ 1856 /* than include both and get warnings, we define the extra SVR4 limits here. */ 1857 /* XXX: I don't understand if RLIMIT_AS is defined, why don't we define */ 1858 /* RLIMIT_VMEM based on it? */ 1859 # ifndef RLIMIT_VMEM 1860 # define RLIMIT_VMEM 6 1861 # endif 1862 # ifndef RLIMIT_AS 1863 # define RLIMIT_AS RLIMIT_VMEM 1864 # endif 1865 # endif /* SYSVREL > 3 && BSDLIMIT */ 1866 1867 # if (defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) 1868 # if defined(RLIMIT_AS) && !defined(RLIMIT_VMEM) 1869 # define RLIMIT_VMEM RLIMIT_AS 1870 # endif 1871 /* 1872 * Oh well, <asm-generic/resource.h> has it, but <bits/resource.h> does not 1873 * Linux headers: When the left hand does not know what the right hand does. 1874 */ 1875 # if defined(RLIMIT_RTPRIO) && !defined(RLIMIT_RTTIME) 1876 # define RLIMIT_RTTIME (RLIMIT_RTPRIO + 1) 1877 # endif 1878 # endif 1879 1880 struct limits limits[] = 1881 { 1882 # ifdef RLIMIT_CPU 1883 { RLIMIT_CPU, "cputime", 1, "seconds" }, 1884 # endif /* RLIMIT_CPU */ 1885 1886 # ifdef RLIMIT_FSIZE 1887 # ifndef aiws 1888 { RLIMIT_FSIZE, "filesize", 1024, "kbytes" }, 1889 # else 1890 { RLIMIT_FSIZE, "filesize", 512, "blocks" }, 1891 # endif /* aiws */ 1892 # endif /* RLIMIT_FSIZE */ 1893 1894 # ifdef RLIMIT_DATA 1895 { RLIMIT_DATA, "datasize", 1024, "kbytes" }, 1896 # endif /* RLIMIT_DATA */ 1897 1898 # ifdef RLIMIT_STACK 1899 # ifndef aiws 1900 { RLIMIT_STACK, "stacksize", 1024, "kbytes" }, 1901 # else 1902 { RLIMIT_STACK, "stacksize", 1024 * 1024, "kbytes"}, 1903 # endif /* aiws */ 1904 # endif /* RLIMIT_STACK */ 1905 1906 # ifdef RLIMIT_CORE 1907 { RLIMIT_CORE, "coredumpsize", 1024, "kbytes" }, 1908 # endif /* RLIMIT_CORE */ 1909 1910 # ifdef RLIMIT_RSS 1911 { RLIMIT_RSS, "memoryuse", 1024, "kbytes" }, 1912 # endif /* RLIMIT_RSS */ 1913 1914 # ifdef RLIMIT_UMEM 1915 { RLIMIT_UMEM, "memoryuse", 1024, "kbytes" }, 1916 # endif /* RLIMIT_UMEM */ 1917 1918 # ifdef RLIMIT_VMEM 1919 { RLIMIT_VMEM, "vmemoryuse", 1024, "kbytes" }, 1920 # endif /* RLIMIT_VMEM */ 1921 1922 # if defined(RLIMIT_HEAP) /* found on BS2000/OSD systems */ 1923 { RLIMIT_HEAP, "heapsize", 1024, "kbytes" }, 1924 # endif /* RLIMIT_HEAP */ 1925 1926 # ifdef RLIMIT_NOFILE 1927 { RLIMIT_NOFILE, "descriptors", 1, "" }, 1928 # endif /* RLIMIT_NOFILE */ 1929 1930 # ifdef RLIMIT_CONCUR 1931 { RLIMIT_CONCUR, "concurrency", 1, "thread(s)" }, 1932 # endif /* RLIMIT_CONCUR */ 1933 1934 # ifdef RLIMIT_MEMLOCK 1935 { RLIMIT_MEMLOCK, "memorylocked", 1024, "kbytes" }, 1936 # endif /* RLIMIT_MEMLOCK */ 1937 1938 # ifdef RLIMIT_NPROC 1939 { RLIMIT_NPROC, "maxproc", 1, "" }, 1940 # endif /* RLIMIT_NPROC */ 1941 1942 # if defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE) 1943 { RLIMIT_OFILE, "openfiles", 1, "" }, 1944 # endif /* RLIMIT_OFILE && !defined(RLIMIT_NOFILE) */ 1945 1946 # ifdef RLIMIT_SBSIZE 1947 { RLIMIT_SBSIZE, "sbsize", 1, "" }, 1948 # endif /* RLIMIT_SBSIZE */ 1949 1950 #ifdef RLIMIT_POSIXLOCKS 1951 { RLIMIT_POSIXLOCKS, "posixlocks", 1, "" }, 1952 #endif /* RLIMIT_POSIXLOCKS */ 1953 1954 # ifdef RLIMIT_SWAP 1955 { RLIMIT_SWAP, "swapsize", 1024, "kbytes" }, 1956 # endif /* RLIMIT_SWAP */ 1957 1958 # ifdef RLIMIT_LOCKS 1959 { RLIMIT_LOCKS, "maxlocks", 1, "" }, 1960 # endif /* RLIMIT_LOCKS */ 1961 1962 # ifdef RLIMIT_SIGPENDING 1963 { RLIMIT_SIGPENDING,"maxsignal", 1, "" }, 1964 # endif /* RLIMIT_SIGPENDING */ 1965 1966 # ifdef RLIMIT_MSGQUEUE 1967 { RLIMIT_MSGQUEUE, "maxmessage", 1, "" }, 1968 # endif /* RLIMIT_MSGQUEUE */ 1969 1970 # ifdef RLIMIT_NICE 1971 { RLIMIT_NICE, "maxnice", 1, "" }, 1972 # endif /* RLIMIT_NICE */ 1973 1974 # ifdef RLIMIT_RTPRIO 1975 { RLIMIT_RTPRIO, "maxrtprio", 1, "" }, 1976 # endif /* RLIMIT_RTPRIO */ 1977 1978 # ifdef RLIMIT_RTTIME 1979 { RLIMIT_RTTIME, "maxrttime", 1, "usec" }, 1980 # endif /* RLIMIT_RTTIME */ 1981 1982 { -1, NULL, 0, NULL } 1983 }; 1984 1985 static struct limits *findlim (Char *); 1986 static RLIM_TYPE getval (struct limits *, Char **); 1987 static int strtail (Char *, const char *); 1988 static void limtail (Char *, const char *); 1989 static void limtail2 (Char *, const char *, const char *); 1990 static void plim (struct limits *, int); 1991 static int setlim (struct limits *, int, RLIM_TYPE); 1992 1993 #ifdef convex 1994 static RLIM_TYPE 1995 restrict_limit(double value) 1996 { 1997 /* 1998 * is f too large to cope with? return the maximum or minimum int 1999 */ 2000 if (value > (double) INT_MAX) 2001 return (RLIM_TYPE) INT_MAX; 2002 else if (value < (double) INT_MIN) 2003 return (RLIM_TYPE) INT_MIN; 2004 else 2005 return (RLIM_TYPE) value; 2006 } 2007 #else /* !convex */ 2008 # define restrict_limit(x) ((RLIM_TYPE) (x)) 2009 #endif /* convex */ 2010 2011 2012 static struct limits * 2013 findlim(Char *cp) 2014 { 2015 struct limits *lp, *res; 2016 2017 res = NULL; 2018 for (lp = limits; lp->limconst >= 0; lp++) 2019 if (prefix(cp, str2short(lp->limname))) { 2020 if (res) 2021 stderror(ERR_NAME | ERR_AMBIG); 2022 res = lp; 2023 } 2024 if (res) 2025 return (res); 2026 stderror(ERR_NAME | ERR_LIMIT); 2027 /* NOTREACHED */ 2028 return (0); 2029 } 2030 2031 /*ARGSUSED*/ 2032 void 2033 dolimit(Char **v, struct command *c) 2034 { 2035 struct limits *lp; 2036 RLIM_TYPE limit; 2037 int hard = 0; 2038 2039 USE(c); 2040 v++; 2041 if (*v && eq(*v, STRmh)) { 2042 hard = 1; 2043 v++; 2044 } 2045 if (*v == 0) { 2046 for (lp = limits; lp->limconst >= 0; lp++) 2047 plim(lp, hard); 2048 return; 2049 } 2050 lp = findlim(v[0]); 2051 if (v[1] == 0) { 2052 plim(lp, hard); 2053 return; 2054 } 2055 limit = getval(lp, v + 1); 2056 if (setlim(lp, hard, limit) < 0) 2057 stderror(ERR_SILENT); 2058 } 2059 2060 static RLIM_TYPE 2061 getval(struct limits *lp, Char **v) 2062 { 2063 float f; 2064 Char *cp = *v++; 2065 2066 f = atof(short2str(cp)); 2067 2068 # ifdef convex 2069 /* 2070 * is f too large to cope with. limit f to minint, maxint - X-6768 by 2071 * strike 2072 */ 2073 if ((f < (double) INT_MIN) || (f > (double) INT_MAX)) { 2074 stderror(ERR_NAME | ERR_TOOLARGE); 2075 } 2076 # endif /* convex */ 2077 2078 while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') 2079 cp++; 2080 if (*cp == 0) { 2081 if (*v == 0) 2082 return restrict_limit((f * lp->limdiv) + 0.5); 2083 cp = *v; 2084 } 2085 switch (*cp) { 2086 # ifdef RLIMIT_CPU 2087 case ':': 2088 if (lp->limconst != RLIMIT_CPU) 2089 goto badscal; 2090 return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f * 60.0 + atof(short2str(cp + 1)))); 2091 case 'h': 2092 if (lp->limconst != RLIMIT_CPU) 2093 goto badscal; 2094 limtail(cp, "hours"); 2095 f *= 3600.0; 2096 break; 2097 # endif /* RLIMIT_CPU */ 2098 case 'm': 2099 # ifdef RLIMIT_CPU 2100 if (lp->limconst == RLIMIT_CPU) { 2101 limtail(cp, "minutes"); 2102 f *= 60.0; 2103 break; 2104 } 2105 # endif /* RLIMIT_CPU */ 2106 limtail2(cp, "megabytes", "mbytes"); 2107 f *= 1024.0 * 1024.0; 2108 break; 2109 # ifdef RLIMIT_CPU 2110 case 's': 2111 if (lp->limconst != RLIMIT_CPU) 2112 goto badscal; 2113 limtail(cp, "seconds"); 2114 break; 2115 # endif /* RLIMIT_CPU */ 2116 case 'G': 2117 *cp = 'g'; 2118 /*FALLTHROUGH*/ 2119 case 'g': 2120 # ifdef RLIMIT_CPU 2121 if (lp->limconst == RLIMIT_CPU) 2122 goto badscal; 2123 # endif /* RLIMIT_CPU */ 2124 limtail2(cp, "gigabytes", "gbytes"); 2125 f *= 1024.0 * 1024.0 * 1024.0; 2126 break; 2127 case 'M': 2128 # ifdef RLIMIT_CPU 2129 if (lp->limconst == RLIMIT_CPU) 2130 goto badscal; 2131 # endif /* RLIMIT_CPU */ 2132 *cp = 'm'; 2133 limtail2(cp, "megabytes", "mbytes"); 2134 f *= 1024.0 * 1024.0; 2135 break; 2136 case 'k': 2137 # ifdef RLIMIT_CPU 2138 if (lp->limconst == RLIMIT_CPU) 2139 goto badscal; 2140 # endif /* RLIMIT_CPU */ 2141 limtail2(cp, "kilobytes", "kbytes"); 2142 f *= 1024.0; 2143 break; 2144 case 'b': 2145 # ifdef RLIMIT_CPU 2146 if (lp->limconst == RLIMIT_CPU) 2147 goto badscal; 2148 # endif /* RLIMIT_CPU */ 2149 limtail(cp, "blocks"); 2150 f *= 512.0; 2151 break; 2152 case 'u': 2153 limtail(cp, "unlimited"); 2154 return ((RLIM_TYPE) RLIM_INFINITY); 2155 default: 2156 # ifdef RLIMIT_CPU 2157 badscal: 2158 # endif /* RLIMIT_CPU */ 2159 stderror(ERR_NAME | ERR_SCALEF); 2160 } 2161 # ifdef convex 2162 return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f + 0.5)); 2163 # else 2164 f += 0.5; 2165 if (f > (float) ((RLIM_TYPE) RLIM_INFINITY)) 2166 return ((RLIM_TYPE) RLIM_INFINITY); 2167 else 2168 return ((RLIM_TYPE) f); 2169 # endif /* convex */ 2170 } 2171 2172 static int 2173 strtail(Char *cp, const char *str) 2174 { 2175 while (*cp && *cp == (Char)*str) 2176 cp++, str++; 2177 return (*cp != '\0'); 2178 } 2179 2180 static void 2181 limtail(Char *cp, const char *str) 2182 { 2183 if (strtail(cp, str)) 2184 stderror(ERR_BADSCALE, str); 2185 } 2186 2187 static void 2188 limtail2(Char *cp, const char *str1, const char *str2) 2189 { 2190 if (strtail(cp, str1) && strtail(cp, str2)) 2191 stderror(ERR_BADSCALE, str1); 2192 } 2193 2194 /*ARGSUSED*/ 2195 static void 2196 plim(struct limits *lp, int hard) 2197 { 2198 # ifdef BSDLIMIT 2199 struct rlimit rlim; 2200 # endif /* BSDLIMIT */ 2201 RLIM_TYPE limit; 2202 int xdiv = lp->limdiv; 2203 2204 xprintf("%-13.13s", lp->limname); 2205 2206 # ifndef BSDLIMIT 2207 limit = ulimit(lp->limconst, 0); 2208 # ifdef aiws 2209 if (lp->limconst == RLIMIT_DATA) 2210 limit -= 0x20000000; 2211 # endif /* aiws */ 2212 # else /* BSDLIMIT */ 2213 (void) getrlimit(lp->limconst, &rlim); 2214 limit = hard ? rlim.rlim_max : rlim.rlim_cur; 2215 # endif /* BSDLIMIT */ 2216 2217 # if !defined(BSDLIMIT) || defined(FILESIZE512) 2218 /* 2219 * Christos: filesize comes in 512 blocks. we divide by 2 to get 1024 2220 * blocks. Note we cannot pre-multiply cause we might overflow (A/UX) 2221 */ 2222 if (lp->limconst == RLIMIT_FSIZE) { 2223 if (limit >= (RLIM_INFINITY / 512)) 2224 limit = RLIM_INFINITY; 2225 else 2226 xdiv = (xdiv == 1024 ? 2 : 1); 2227 } 2228 # endif /* !BSDLIMIT || FILESIZE512 */ 2229 2230 if (limit == RLIM_INFINITY) 2231 xprintf("unlimited"); 2232 else 2233 # if defined(RLIMIT_CPU) && defined(_OSD_POSIX) 2234 if (lp->limconst == RLIMIT_CPU && 2235 (unsigned long)limit >= 0x7ffffffdUL) 2236 xprintf("unlimited"); 2237 else 2238 # endif 2239 # ifdef RLIMIT_CPU 2240 if (lp->limconst == RLIMIT_CPU) 2241 psecs(limit); 2242 else 2243 # endif /* RLIMIT_CPU */ 2244 xprintf("%ld %s", (long) (limit / xdiv), lp->limscale); 2245 xputchar('\n'); 2246 } 2247 2248 /*ARGSUSED*/ 2249 void 2250 dounlimit(Char **v, struct command *c) 2251 { 2252 struct limits *lp; 2253 int lerr = 0; 2254 int hard = 0; 2255 int force = 0; 2256 2257 USE(c); 2258 while (*++v && **v == '-') { 2259 Char *vp = *v; 2260 while (*++vp) 2261 switch (*vp) { 2262 case 'f': 2263 force = 1; 2264 break; 2265 case 'h': 2266 hard = 1; 2267 break; 2268 default: 2269 stderror(ERR_ULIMUS); 2270 break; 2271 } 2272 } 2273 2274 if (*v == 0) { 2275 for (lp = limits; lp->limconst >= 0; lp++) 2276 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0) 2277 lerr++; 2278 if (!force && lerr) 2279 stderror(ERR_SILENT); 2280 return; 2281 } 2282 while (*v) { 2283 lp = findlim(*v++); 2284 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0 && !force) 2285 stderror(ERR_SILENT); 2286 } 2287 } 2288 2289 static int 2290 setlim(struct limits *lp, int hard, RLIM_TYPE limit) 2291 { 2292 # ifdef BSDLIMIT 2293 struct rlimit rlim; 2294 2295 (void) getrlimit(lp->limconst, &rlim); 2296 2297 # ifdef FILESIZE512 2298 /* Even though hpux has setrlimit(), it expects fsize in 512 byte blocks */ 2299 if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 2300 limit /= 512; 2301 # endif /* FILESIZE512 */ 2302 if (hard) 2303 rlim.rlim_max = limit; 2304 else if (limit == RLIM_INFINITY && euid != 0) 2305 rlim.rlim_cur = rlim.rlim_max; 2306 else 2307 rlim.rlim_cur = limit; 2308 2309 if (rlim.rlim_cur > rlim.rlim_max) 2310 rlim.rlim_max = rlim.rlim_cur; 2311 2312 if (setrlimit(lp->limconst, &rlim) < 0) { 2313 # else /* BSDLIMIT */ 2314 if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 2315 limit /= 512; 2316 # ifdef aiws 2317 if (lp->limconst == RLIMIT_DATA) 2318 limit += 0x20000000; 2319 # endif /* aiws */ 2320 if (ulimit(toset(lp->limconst), limit) < 0) { 2321 # endif /* BSDLIMIT */ 2322 int err; 2323 char *op, *type; 2324 2325 err = errno; 2326 op = strsave(limit == RLIM_INFINITY ? CGETS(15, 2, "remove") : 2327 CGETS(15, 3, "set")); 2328 cleanup_push(op, xfree); 2329 type = strsave(hard ? CGETS(15, 4, " hard") : ""); 2330 cleanup_push(type, xfree); 2331 xprintf(CGETS(15, 1, "%s: %s: Can't %s%s limit (%s)\n"), bname, 2332 lp->limname, op, type, strerror(err)); 2333 cleanup_until(op); 2334 return (-1); 2335 } 2336 return (0); 2337 } 2338 2339 #endif /* !HAVENOLIMIT */ 2340 2341 /*ARGSUSED*/ 2342 void 2343 dosuspend(Char **v, struct command *c) 2344 { 2345 #ifdef BSDJOBS 2346 struct sigaction old; 2347 #endif /* BSDJOBS */ 2348 2349 USE(c); 2350 USE(v); 2351 2352 if (loginsh) 2353 stderror(ERR_SUSPLOG); 2354 untty(); 2355 2356 #ifdef BSDJOBS 2357 sigaction(SIGTSTP, NULL, &old); 2358 signal(SIGTSTP, SIG_DFL); 2359 (void) kill(0, SIGTSTP); 2360 /* the shell stops here */ 2361 sigaction(SIGTSTP, &old, NULL); 2362 #else /* !BSDJOBS */ 2363 stderror(ERR_JOBCONTROL); 2364 #endif /* BSDJOBS */ 2365 2366 #ifdef BSDJOBS 2367 if (tpgrp != -1) { 2368 if (grabpgrp(FSHTTY, opgrp) == -1) 2369 stderror(ERR_SYSTEM, "tcgetpgrp", strerror(errno)); 2370 (void) setpgid(0, shpgrp); 2371 (void) tcsetpgrp(FSHTTY, shpgrp); 2372 } 2373 #endif /* BSDJOBS */ 2374 (void) setdisc(FSHTTY); 2375 } 2376 2377 /* This is the dreaded EVAL built-in. 2378 * If you don't fiddle with file descriptors, and reset didfds, 2379 * this command will either ignore redirection inside or outside 2380 * its arguments, e.g. eval "date >x" vs. eval "date" >x 2381 * The stuff here seems to work, but I did it by trial and error rather 2382 * than really knowing what was going on. If tpgrp is zero, we are 2383 * probably a background eval, e.g. "eval date &", and we want to 2384 * make sure that any processes we start stay in our pgrp. 2385 * This is also the case for "time eval date" -- stay in same pgrp. 2386 * Otherwise, under stty tostop, processes will stop in the wrong 2387 * pgrp, with no way for the shell to get them going again. -IAN! 2388 */ 2389 2390 struct doeval_state 2391 { 2392 Char **evalvec, *evalp; 2393 int didfds; 2394 #ifndef CLOSE_ON_EXEC 2395 int didcch; 2396 #endif 2397 int saveIN, saveOUT, saveDIAG; 2398 int SHIN, SHOUT, SHDIAG; 2399 }; 2400 2401 static void 2402 doeval_cleanup(void *xstate) 2403 { 2404 struct doeval_state *state; 2405 2406 state = xstate; 2407 evalvec = state->evalvec; 2408 evalp = state->evalp; 2409 doneinp = 0; 2410 #ifndef CLOSE_ON_EXEC 2411 didcch = state->didcch; 2412 #endif /* CLOSE_ON_EXEC */ 2413 didfds = state->didfds; 2414 xclose(SHIN); 2415 xclose(SHOUT); 2416 xclose(SHDIAG); 2417 close_on_exec(SHIN = dmove(state->saveIN, state->SHIN), 1); 2418 close_on_exec(SHOUT = dmove(state->saveOUT, state->SHOUT), 1); 2419 close_on_exec(SHDIAG = dmove(state->saveDIAG, state->SHDIAG), 1); 2420 } 2421 2422 static Char **Ggv; 2423 /*ARGSUSED*/ 2424 void 2425 doeval(Char **v, struct command *c) 2426 { 2427 struct doeval_state state; 2428 int gflag, my_reenter; 2429 Char **gv; 2430 jmp_buf_t osetexit; 2431 2432 USE(c); 2433 v++; 2434 if (*v == 0) 2435 return; 2436 gflag = tglob(v); 2437 if (gflag) { 2438 gv = v = globall(v, gflag); 2439 if (v == 0) 2440 stderror(ERR_NOMATCH); 2441 cleanup_push(gv, blk_cleanup); 2442 v = copyblk(v); 2443 } 2444 else { 2445 gv = NULL; 2446 v = copyblk(v); 2447 trim(v); 2448 } 2449 2450 Ggv = gv; 2451 state.evalvec = evalvec; 2452 state.evalp = evalp; 2453 state.didfds = didfds; 2454 #ifndef CLOSE_ON_EXEC 2455 state.didcch = didcch; 2456 #endif /* CLOSE_ON_EXEC */ 2457 state.SHIN = SHIN; 2458 state.SHOUT = SHOUT; 2459 state.SHDIAG = SHDIAG; 2460 2461 (void)close_on_exec(state.saveIN = dcopy(SHIN, -1), 1); 2462 (void)close_on_exec(state.saveOUT = dcopy(SHOUT, -1), 1); 2463 (void)close_on_exec(state.saveDIAG = dcopy(SHDIAG, -1), 1); 2464 2465 cleanup_push(&state, doeval_cleanup); 2466 2467 getexit(osetexit); 2468 2469 /* PWP: setjmp/longjmp bugfix for optimizing compilers */ 2470 #ifdef cray 2471 my_reenter = 1; /* assume non-zero return val */ 2472 if (setexit() == 0) { 2473 my_reenter = 0; /* Oh well, we were wrong */ 2474 #else /* !cray */ 2475 if ((my_reenter = setexit()) == 0) { 2476 #endif /* cray */ 2477 evalvec = v; 2478 evalp = 0; 2479 (void)close_on_exec(SHIN = dcopy(0, -1), 1); 2480 (void)close_on_exec(SHOUT = dcopy(1, -1), 1); 2481 (void)close_on_exec(SHDIAG = dcopy(2, -1), 1); 2482 #ifndef CLOSE_ON_EXEC 2483 didcch = 0; 2484 #endif /* CLOSE_ON_EXEC */ 2485 didfds = 0; 2486 gv = Ggv; 2487 process(0); 2488 Ggv = gv; 2489 } 2490 2491 if (my_reenter == 0) { 2492 cleanup_until(&state); 2493 if (Ggv) 2494 cleanup_until(Ggv); 2495 } 2496 2497 resexit(osetexit); 2498 if (my_reenter) 2499 stderror(ERR_SILENT); 2500 } 2501 2502 /*************************************************************************/ 2503 /* print list of builtin commands */ 2504 2505 static void 2506 lbuffed_cleanup (void *dummy) 2507 { 2508 USE(dummy); 2509 lbuffed = 1; 2510 } 2511 2512 /*ARGSUSED*/ 2513 void 2514 dobuiltins(Char **v, struct command *c) 2515 { 2516 /* would use print_by_column() in tw.parse.c but that assumes 2517 * we have an array of Char * to pass.. (sg) 2518 */ 2519 const struct biltins *b; 2520 int row, col, columns, rows; 2521 unsigned int w, maxwidth; 2522 2523 USE(c); 2524 USE(v); 2525 lbuffed = 0; /* turn off line buffering */ 2526 cleanup_push(&lbuffed, lbuffed_cleanup); 2527 2528 /* find widest string */ 2529 for (maxwidth = 0, b = bfunc; b < &bfunc[nbfunc]; ++b) 2530 maxwidth = max(maxwidth, strlen(b->bname)); 2531 ++maxwidth; /* for space */ 2532 2533 columns = (TermH + 1) / maxwidth; /* PWP: terminal size change */ 2534 if (!columns) 2535 columns = 1; 2536 rows = (nbfunc + (columns - 1)) / columns; 2537 2538 for (b = bfunc, row = 0; row < rows; row++) { 2539 for (col = 0; col < columns; col++) { 2540 if (b < &bfunc[nbfunc]) { 2541 w = strlen(b->bname); 2542 xprintf("%s", b->bname); 2543 if (col < (columns - 1)) /* Not last column? */ 2544 for (; w < maxwidth; w++) 2545 xputchar(' '); 2546 ++b; 2547 } 2548 } 2549 if (row < (rows - 1)) { 2550 if (Tty_raw_mode) 2551 xputchar('\r'); 2552 xputchar('\n'); 2553 } 2554 } 2555 #ifdef WINNT_NATIVE 2556 nt_print_builtins(maxwidth); 2557 #else 2558 if (Tty_raw_mode) 2559 xputchar('\r'); 2560 xputchar('\n'); 2561 #endif /* WINNT_NATIVE */ 2562 2563 cleanup_until(&lbuffed); /* turn back on line buffering */ 2564 flush(); 2565 } 2566 2567 #ifdef NLS_CATALOGS 2568 char * 2569 xcatgets(nl_catd ctd, int set_id, int msg_id, const char *s) 2570 { 2571 char *res; 2572 2573 errno = 0; 2574 while ((res = catgets(ctd, set_id, msg_id, s)) == s && errno == EINTR) { 2575 handle_pending_signals(); 2576 errno = 0; 2577 } 2578 return res; 2579 } 2580 2581 2582 # if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2583 char * 2584 iconv_catgets(nl_catd ctd, int set_id, int msg_id, const char *s) 2585 { 2586 static char *buf = NULL; 2587 static size_t buf_size = 0; 2588 2589 char *orig, *dest, *p; 2590 ICONV_CONST char *src; 2591 size_t src_size, dest_size; 2592 2593 orig = xcatgets(ctd, set_id, msg_id, s); 2594 if (catgets_iconv == (iconv_t)-1 || orig == s) 2595 return orig; 2596 src = orig; 2597 src_size = strlen(src) + 1; 2598 if (buf == NULL && (buf = xmalloc(buf_size = src_size + 32)) == NULL) 2599 return orig; 2600 dest = buf; 2601 while (src_size != 0) { 2602 dest_size = buf + buf_size - dest; 2603 if (iconv(catgets_iconv, &src, &src_size, &dest, &dest_size) 2604 == (size_t)-1) { 2605 switch (errno) { 2606 case E2BIG: 2607 if ((p = xrealloc(buf, buf_size * 2)) == NULL) 2608 return orig; 2609 buf_size *= 2; 2610 dest = p + (dest - buf); 2611 buf = p; 2612 break; 2613 2614 case EILSEQ: case EINVAL: default: 2615 return orig; 2616 } 2617 } 2618 } 2619 return buf; 2620 } 2621 # endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2622 #endif /* NLS_CATALOGS */ 2623 2624 void 2625 nlsinit(void) 2626 { 2627 #ifdef NLS_CATALOGS 2628 static const char default_catalog[] = "tcsh"; 2629 2630 char *catalog = (char *)(intptr_t)default_catalog; 2631 2632 if (adrof(STRcatalog) != NULL) 2633 catalog = xasprintf("tcsh.%s", short2str(varval(STRcatalog))); 2634 #ifdef NL_CAT_LOCALE /* POSIX-compliant. */ 2635 /* 2636 * Check if LC_MESSAGES is set in the environment and use it, if so. 2637 * If not, fall back to the setting of LANG. 2638 */ 2639 catd = catopen(catalog, tgetenv(STRLC_MESSAGES) ? NL_CAT_LOCALE : 0); 2640 #else /* pre-POSIX */ 2641 # ifndef MCLoadBySet 2642 # define MCLoadBySet 0 2643 # endif 2644 catd = catopen(catalog, MCLoadBySet); 2645 #endif 2646 if (catalog != default_catalog) 2647 xfree(catalog); 2648 #if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2649 /* xcatgets (), not CGETS, the charset name should be in ASCII anyway. */ 2650 catgets_iconv = iconv_open (nl_langinfo (CODESET), 2651 xcatgets(catd, 255, 1, "UTF-8")); 2652 #endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2653 #endif /* NLS_CATALOGS */ 2654 #ifdef WINNT_NATIVE 2655 nls_dll_init(); 2656 #endif /* WINNT_NATIVE */ 2657 errinit(); /* init the errorlist in correct locale */ 2658 mesginit(); /* init the messages for signals */ 2659 dateinit(); /* init the messages for dates */ 2660 editinit(); /* init the editor messages */ 2661 terminit(); /* init the termcap messages */ 2662 } 2663 2664 void 2665 nlsclose(void) 2666 { 2667 #ifdef NLS_CATALOGS 2668 #if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2669 if (catgets_iconv != (iconv_t)-1) { 2670 iconv_close(catgets_iconv); 2671 catgets_iconv = (iconv_t)-1; 2672 } 2673 #endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2674 if (catd != (nl_catd)-1) { 2675 /* 2676 * catclose can call other functions which can call longjmp 2677 * making us re-enter this code. Prevent infinite recursion 2678 * by resetting catd. Problem reported and solved by: 2679 * Gerhard Niklasch 2680 */ 2681 nl_catd oldcatd = catd; 2682 catd = (nl_catd)-1; 2683 while (catclose(oldcatd) == -1 && errno == EINTR) 2684 handle_pending_signals(); 2685 } 2686 #endif /* NLS_CATALOGS */ 2687 } 2688