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_SWAP 1951 { RLIMIT_SWAP, "swapsize", 1024, "kbytes" }, 1952 # endif /* RLIMIT_SWAP */ 1953 1954 # ifdef RLIMIT_LOCKS 1955 { RLIMIT_LOCKS, "maxlocks", 1, "" }, 1956 # endif /* RLIMIT_LOCKS */ 1957 1958 # ifdef RLIMIT_SIGPENDING 1959 { RLIMIT_SIGPENDING,"maxsignal", 1, "" }, 1960 # endif /* RLIMIT_SIGPENDING */ 1961 1962 # ifdef RLIMIT_MSGQUEUE 1963 { RLIMIT_MSGQUEUE, "maxmessage", 1, "" }, 1964 # endif /* RLIMIT_MSGQUEUE */ 1965 1966 # ifdef RLIMIT_NICE 1967 { RLIMIT_NICE, "maxnice", 1, "" }, 1968 # endif /* RLIMIT_NICE */ 1969 1970 # ifdef RLIMIT_RTPRIO 1971 { RLIMIT_RTPRIO, "maxrtprio", 1, "" }, 1972 # endif /* RLIMIT_RTPRIO */ 1973 1974 # ifdef RLIMIT_RTTIME 1975 { RLIMIT_RTTIME, "maxrttime", 1, "usec" }, 1976 # endif /* RLIMIT_RTTIME */ 1977 1978 { -1, NULL, 0, NULL } 1979 }; 1980 1981 static struct limits *findlim (Char *); 1982 static RLIM_TYPE getval (struct limits *, Char **); 1983 static int strtail (Char *, const char *); 1984 static void limtail (Char *, const char *); 1985 static void limtail2 (Char *, const char *, const char *); 1986 static void plim (struct limits *, int); 1987 static int setlim (struct limits *, int, RLIM_TYPE); 1988 1989 #ifdef convex 1990 static RLIM_TYPE 1991 restrict_limit(double value) 1992 { 1993 /* 1994 * is f too large to cope with? return the maximum or minimum int 1995 */ 1996 if (value > (double) INT_MAX) 1997 return (RLIM_TYPE) INT_MAX; 1998 else if (value < (double) INT_MIN) 1999 return (RLIM_TYPE) INT_MIN; 2000 else 2001 return (RLIM_TYPE) value; 2002 } 2003 #else /* !convex */ 2004 # define restrict_limit(x) ((RLIM_TYPE) (x)) 2005 #endif /* convex */ 2006 2007 2008 static struct limits * 2009 findlim(Char *cp) 2010 { 2011 struct limits *lp, *res; 2012 2013 res = NULL; 2014 for (lp = limits; lp->limconst >= 0; lp++) 2015 if (prefix(cp, str2short(lp->limname))) { 2016 if (res) 2017 stderror(ERR_NAME | ERR_AMBIG); 2018 res = lp; 2019 } 2020 if (res) 2021 return (res); 2022 stderror(ERR_NAME | ERR_LIMIT); 2023 /* NOTREACHED */ 2024 return (0); 2025 } 2026 2027 /*ARGSUSED*/ 2028 void 2029 dolimit(Char **v, struct command *c) 2030 { 2031 struct limits *lp; 2032 RLIM_TYPE limit; 2033 int hard = 0; 2034 2035 USE(c); 2036 v++; 2037 if (*v && eq(*v, STRmh)) { 2038 hard = 1; 2039 v++; 2040 } 2041 if (*v == 0) { 2042 for (lp = limits; lp->limconst >= 0; lp++) 2043 plim(lp, hard); 2044 return; 2045 } 2046 lp = findlim(v[0]); 2047 if (v[1] == 0) { 2048 plim(lp, hard); 2049 return; 2050 } 2051 limit = getval(lp, v + 1); 2052 if (setlim(lp, hard, limit) < 0) 2053 stderror(ERR_SILENT); 2054 } 2055 2056 static RLIM_TYPE 2057 getval(struct limits *lp, Char **v) 2058 { 2059 float f; 2060 Char *cp = *v++; 2061 2062 f = atof(short2str(cp)); 2063 2064 # ifdef convex 2065 /* 2066 * is f too large to cope with. limit f to minint, maxint - X-6768 by 2067 * strike 2068 */ 2069 if ((f < (double) INT_MIN) || (f > (double) INT_MAX)) { 2070 stderror(ERR_NAME | ERR_TOOLARGE); 2071 } 2072 # endif /* convex */ 2073 2074 while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') 2075 cp++; 2076 if (*cp == 0) { 2077 if (*v == 0) 2078 return restrict_limit((f * lp->limdiv) + 0.5); 2079 cp = *v; 2080 } 2081 switch (*cp) { 2082 # ifdef RLIMIT_CPU 2083 case ':': 2084 if (lp->limconst != RLIMIT_CPU) 2085 goto badscal; 2086 return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f * 60.0 + atof(short2str(cp + 1)))); 2087 case 'h': 2088 if (lp->limconst != RLIMIT_CPU) 2089 goto badscal; 2090 limtail(cp, "hours"); 2091 f *= 3600.0; 2092 break; 2093 # endif /* RLIMIT_CPU */ 2094 case 'm': 2095 # ifdef RLIMIT_CPU 2096 if (lp->limconst == RLIMIT_CPU) { 2097 limtail(cp, "minutes"); 2098 f *= 60.0; 2099 break; 2100 } 2101 # endif /* RLIMIT_CPU */ 2102 limtail2(cp, "megabytes", "mbytes"); 2103 f *= 1024.0 * 1024.0; 2104 break; 2105 # ifdef RLIMIT_CPU 2106 case 's': 2107 if (lp->limconst != RLIMIT_CPU) 2108 goto badscal; 2109 limtail(cp, "seconds"); 2110 break; 2111 # endif /* RLIMIT_CPU */ 2112 case 'G': 2113 *cp = 'g'; 2114 /*FALLTHROUGH*/ 2115 case 'g': 2116 # ifdef RLIMIT_CPU 2117 if (lp->limconst == RLIMIT_CPU) 2118 goto badscal; 2119 # endif /* RLIMIT_CPU */ 2120 limtail2(cp, "gigabytes", "gbytes"); 2121 f *= 1024.0 * 1024.0 * 1024.0; 2122 break; 2123 case 'M': 2124 # ifdef RLIMIT_CPU 2125 if (lp->limconst == RLIMIT_CPU) 2126 goto badscal; 2127 # endif /* RLIMIT_CPU */ 2128 *cp = 'm'; 2129 limtail2(cp, "megabytes", "mbytes"); 2130 f *= 1024.0 * 1024.0; 2131 break; 2132 case 'k': 2133 # ifdef RLIMIT_CPU 2134 if (lp->limconst == RLIMIT_CPU) 2135 goto badscal; 2136 # endif /* RLIMIT_CPU */ 2137 limtail2(cp, "kilobytes", "kbytes"); 2138 f *= 1024.0; 2139 break; 2140 case 'b': 2141 # ifdef RLIMIT_CPU 2142 if (lp->limconst == RLIMIT_CPU) 2143 goto badscal; 2144 # endif /* RLIMIT_CPU */ 2145 limtail(cp, "blocks"); 2146 f *= 512.0; 2147 break; 2148 case 'u': 2149 limtail(cp, "unlimited"); 2150 return ((RLIM_TYPE) RLIM_INFINITY); 2151 default: 2152 # ifdef RLIMIT_CPU 2153 badscal: 2154 # endif /* RLIMIT_CPU */ 2155 stderror(ERR_NAME | ERR_SCALEF); 2156 } 2157 # ifdef convex 2158 return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f + 0.5)); 2159 # else 2160 f += 0.5; 2161 if (f > (float) ((RLIM_TYPE) RLIM_INFINITY)) 2162 return ((RLIM_TYPE) RLIM_INFINITY); 2163 else 2164 return ((RLIM_TYPE) f); 2165 # endif /* convex */ 2166 } 2167 2168 static int 2169 strtail(Char *cp, const char *str) 2170 { 2171 while (*cp && *cp == (Char)*str) 2172 cp++, str++; 2173 return (*cp != '\0'); 2174 } 2175 2176 static void 2177 limtail(Char *cp, const char *str) 2178 { 2179 if (strtail(cp, str)) 2180 stderror(ERR_BADSCALE, str); 2181 } 2182 2183 static void 2184 limtail2(Char *cp, const char *str1, const char *str2) 2185 { 2186 if (strtail(cp, str1) && strtail(cp, str2)) 2187 stderror(ERR_BADSCALE, str1); 2188 } 2189 2190 /*ARGSUSED*/ 2191 static void 2192 plim(struct limits *lp, int hard) 2193 { 2194 # ifdef BSDLIMIT 2195 struct rlimit rlim; 2196 # endif /* BSDLIMIT */ 2197 RLIM_TYPE limit; 2198 int xdiv = lp->limdiv; 2199 2200 xprintf("%-13.13s", lp->limname); 2201 2202 # ifndef BSDLIMIT 2203 limit = ulimit(lp->limconst, 0); 2204 # ifdef aiws 2205 if (lp->limconst == RLIMIT_DATA) 2206 limit -= 0x20000000; 2207 # endif /* aiws */ 2208 # else /* BSDLIMIT */ 2209 (void) getrlimit(lp->limconst, &rlim); 2210 limit = hard ? rlim.rlim_max : rlim.rlim_cur; 2211 # endif /* BSDLIMIT */ 2212 2213 # if !defined(BSDLIMIT) || defined(FILESIZE512) 2214 /* 2215 * Christos: filesize comes in 512 blocks. we divide by 2 to get 1024 2216 * blocks. Note we cannot pre-multiply cause we might overflow (A/UX) 2217 */ 2218 if (lp->limconst == RLIMIT_FSIZE) { 2219 if (limit >= (RLIM_INFINITY / 512)) 2220 limit = RLIM_INFINITY; 2221 else 2222 xdiv = (xdiv == 1024 ? 2 : 1); 2223 } 2224 # endif /* !BSDLIMIT || FILESIZE512 */ 2225 2226 if (limit == RLIM_INFINITY) 2227 xprintf("unlimited"); 2228 else 2229 # if defined(RLIMIT_CPU) && defined(_OSD_POSIX) 2230 if (lp->limconst == RLIMIT_CPU && 2231 (unsigned long)limit >= 0x7ffffffdUL) 2232 xprintf("unlimited"); 2233 else 2234 # endif 2235 # ifdef RLIMIT_CPU 2236 if (lp->limconst == RLIMIT_CPU) 2237 psecs(limit); 2238 else 2239 # endif /* RLIMIT_CPU */ 2240 xprintf("%ld %s", (long) (limit / xdiv), lp->limscale); 2241 xputchar('\n'); 2242 } 2243 2244 /*ARGSUSED*/ 2245 void 2246 dounlimit(Char **v, struct command *c) 2247 { 2248 struct limits *lp; 2249 int lerr = 0; 2250 int hard = 0; 2251 int force = 0; 2252 2253 USE(c); 2254 while (*++v && **v == '-') { 2255 Char *vp = *v; 2256 while (*++vp) 2257 switch (*vp) { 2258 case 'f': 2259 force = 1; 2260 break; 2261 case 'h': 2262 hard = 1; 2263 break; 2264 default: 2265 stderror(ERR_ULIMUS); 2266 break; 2267 } 2268 } 2269 2270 if (*v == 0) { 2271 for (lp = limits; lp->limconst >= 0; lp++) 2272 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0) 2273 lerr++; 2274 if (!force && lerr) 2275 stderror(ERR_SILENT); 2276 return; 2277 } 2278 while (*v) { 2279 lp = findlim(*v++); 2280 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0 && !force) 2281 stderror(ERR_SILENT); 2282 } 2283 } 2284 2285 static int 2286 setlim(struct limits *lp, int hard, RLIM_TYPE limit) 2287 { 2288 # ifdef BSDLIMIT 2289 struct rlimit rlim; 2290 2291 (void) getrlimit(lp->limconst, &rlim); 2292 2293 # ifdef FILESIZE512 2294 /* Even though hpux has setrlimit(), it expects fsize in 512 byte blocks */ 2295 if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 2296 limit /= 512; 2297 # endif /* FILESIZE512 */ 2298 if (hard) 2299 rlim.rlim_max = limit; 2300 else if (limit == RLIM_INFINITY && euid != 0) 2301 rlim.rlim_cur = rlim.rlim_max; 2302 else 2303 rlim.rlim_cur = limit; 2304 2305 if (rlim.rlim_cur > rlim.rlim_max) 2306 rlim.rlim_max = rlim.rlim_cur; 2307 2308 if (setrlimit(lp->limconst, &rlim) < 0) { 2309 # else /* BSDLIMIT */ 2310 if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 2311 limit /= 512; 2312 # ifdef aiws 2313 if (lp->limconst == RLIMIT_DATA) 2314 limit += 0x20000000; 2315 # endif /* aiws */ 2316 if (ulimit(toset(lp->limconst), limit) < 0) { 2317 # endif /* BSDLIMIT */ 2318 int err; 2319 char *op, *type; 2320 2321 err = errno; 2322 op = strsave(limit == RLIM_INFINITY ? CGETS(15, 2, "remove") : 2323 CGETS(15, 3, "set")); 2324 cleanup_push(op, xfree); 2325 type = strsave(hard ? CGETS(15, 4, " hard") : ""); 2326 cleanup_push(type, xfree); 2327 xprintf(CGETS(15, 1, "%s: %s: Can't %s%s limit (%s)\n"), bname, 2328 lp->limname, op, type, strerror(err)); 2329 cleanup_until(op); 2330 return (-1); 2331 } 2332 return (0); 2333 } 2334 2335 #endif /* !HAVENOLIMIT */ 2336 2337 /*ARGSUSED*/ 2338 void 2339 dosuspend(Char **v, struct command *c) 2340 { 2341 #ifdef BSDJOBS 2342 struct sigaction old; 2343 #endif /* BSDJOBS */ 2344 2345 USE(c); 2346 USE(v); 2347 2348 if (loginsh) 2349 stderror(ERR_SUSPLOG); 2350 untty(); 2351 2352 #ifdef BSDJOBS 2353 sigaction(SIGTSTP, NULL, &old); 2354 signal(SIGTSTP, SIG_DFL); 2355 (void) kill(0, SIGTSTP); 2356 /* the shell stops here */ 2357 sigaction(SIGTSTP, &old, NULL); 2358 #else /* !BSDJOBS */ 2359 stderror(ERR_JOBCONTROL); 2360 #endif /* BSDJOBS */ 2361 2362 #ifdef BSDJOBS 2363 if (tpgrp != -1) { 2364 if (grabpgrp(FSHTTY, opgrp) == -1) 2365 stderror(ERR_SYSTEM, "tcgetpgrp", strerror(errno)); 2366 (void) setpgid(0, shpgrp); 2367 (void) tcsetpgrp(FSHTTY, shpgrp); 2368 } 2369 #endif /* BSDJOBS */ 2370 (void) setdisc(FSHTTY); 2371 } 2372 2373 /* This is the dreaded EVAL built-in. 2374 * If you don't fiddle with file descriptors, and reset didfds, 2375 * this command will either ignore redirection inside or outside 2376 * its arguments, e.g. eval "date >x" vs. eval "date" >x 2377 * The stuff here seems to work, but I did it by trial and error rather 2378 * than really knowing what was going on. If tpgrp is zero, we are 2379 * probably a background eval, e.g. "eval date &", and we want to 2380 * make sure that any processes we start stay in our pgrp. 2381 * This is also the case for "time eval date" -- stay in same pgrp. 2382 * Otherwise, under stty tostop, processes will stop in the wrong 2383 * pgrp, with no way for the shell to get them going again. -IAN! 2384 */ 2385 2386 struct doeval_state 2387 { 2388 Char **evalvec, *evalp; 2389 int didfds; 2390 #ifndef CLOSE_ON_EXEC 2391 int didcch; 2392 #endif 2393 int saveIN, saveOUT, saveDIAG; 2394 int SHIN, SHOUT, SHDIAG; 2395 }; 2396 2397 static void 2398 doeval_cleanup(void *xstate) 2399 { 2400 struct doeval_state *state; 2401 2402 state = xstate; 2403 evalvec = state->evalvec; 2404 evalp = state->evalp; 2405 doneinp = 0; 2406 #ifndef CLOSE_ON_EXEC 2407 didcch = state->didcch; 2408 #endif /* CLOSE_ON_EXEC */ 2409 didfds = state->didfds; 2410 xclose(SHIN); 2411 xclose(SHOUT); 2412 xclose(SHDIAG); 2413 close_on_exec(SHIN = dmove(state->saveIN, state->SHIN), 1); 2414 close_on_exec(SHOUT = dmove(state->saveOUT, state->SHOUT), 1); 2415 close_on_exec(SHDIAG = dmove(state->saveDIAG, state->SHDIAG), 1); 2416 } 2417 2418 static Char **Ggv; 2419 /*ARGSUSED*/ 2420 void 2421 doeval(Char **v, struct command *c) 2422 { 2423 struct doeval_state state; 2424 int gflag, my_reenter; 2425 Char **gv; 2426 jmp_buf_t osetexit; 2427 2428 USE(c); 2429 v++; 2430 if (*v == 0) 2431 return; 2432 gflag = tglob(v); 2433 if (gflag) { 2434 gv = v = globall(v, gflag); 2435 if (v == 0) 2436 stderror(ERR_NOMATCH); 2437 cleanup_push(gv, blk_cleanup); 2438 v = copyblk(v); 2439 } 2440 else { 2441 gv = NULL; 2442 v = copyblk(v); 2443 trim(v); 2444 } 2445 2446 Ggv = gv; 2447 state.evalvec = evalvec; 2448 state.evalp = evalp; 2449 state.didfds = didfds; 2450 #ifndef CLOSE_ON_EXEC 2451 state.didcch = didcch; 2452 #endif /* CLOSE_ON_EXEC */ 2453 state.SHIN = SHIN; 2454 state.SHOUT = SHOUT; 2455 state.SHDIAG = SHDIAG; 2456 2457 (void)close_on_exec(state.saveIN = dcopy(SHIN, -1), 1); 2458 (void)close_on_exec(state.saveOUT = dcopy(SHOUT, -1), 1); 2459 (void)close_on_exec(state.saveDIAG = dcopy(SHDIAG, -1), 1); 2460 2461 cleanup_push(&state, doeval_cleanup); 2462 2463 getexit(osetexit); 2464 2465 /* PWP: setjmp/longjmp bugfix for optimizing compilers */ 2466 #ifdef cray 2467 my_reenter = 1; /* assume non-zero return val */ 2468 if (setexit() == 0) { 2469 my_reenter = 0; /* Oh well, we were wrong */ 2470 #else /* !cray */ 2471 if ((my_reenter = setexit()) == 0) { 2472 #endif /* cray */ 2473 evalvec = v; 2474 evalp = 0; 2475 (void)close_on_exec(SHIN = dcopy(0, -1), 1); 2476 (void)close_on_exec(SHOUT = dcopy(1, -1), 1); 2477 (void)close_on_exec(SHDIAG = dcopy(2, -1), 1); 2478 #ifndef CLOSE_ON_EXEC 2479 didcch = 0; 2480 #endif /* CLOSE_ON_EXEC */ 2481 didfds = 0; 2482 gv = Ggv; 2483 process(0); 2484 Ggv = gv; 2485 } 2486 2487 if (my_reenter == 0) { 2488 cleanup_until(&state); 2489 if (Ggv) 2490 cleanup_until(Ggv); 2491 } 2492 2493 resexit(osetexit); 2494 if (my_reenter) 2495 stderror(ERR_SILENT); 2496 } 2497 2498 /*************************************************************************/ 2499 /* print list of builtin commands */ 2500 2501 static void 2502 lbuffed_cleanup (void *dummy) 2503 { 2504 USE(dummy); 2505 lbuffed = 1; 2506 } 2507 2508 /*ARGSUSED*/ 2509 void 2510 dobuiltins(Char **v, struct command *c) 2511 { 2512 /* would use print_by_column() in tw.parse.c but that assumes 2513 * we have an array of Char * to pass.. (sg) 2514 */ 2515 const struct biltins *b; 2516 int row, col, columns, rows; 2517 unsigned int w, maxwidth; 2518 2519 USE(c); 2520 USE(v); 2521 lbuffed = 0; /* turn off line buffering */ 2522 cleanup_push(&lbuffed, lbuffed_cleanup); 2523 2524 /* find widest string */ 2525 for (maxwidth = 0, b = bfunc; b < &bfunc[nbfunc]; ++b) 2526 maxwidth = max(maxwidth, strlen(b->bname)); 2527 ++maxwidth; /* for space */ 2528 2529 columns = (TermH + 1) / maxwidth; /* PWP: terminal size change */ 2530 if (!columns) 2531 columns = 1; 2532 rows = (nbfunc + (columns - 1)) / columns; 2533 2534 for (b = bfunc, row = 0; row < rows; row++) { 2535 for (col = 0; col < columns; col++) { 2536 if (b < &bfunc[nbfunc]) { 2537 w = strlen(b->bname); 2538 xprintf("%s", b->bname); 2539 if (col < (columns - 1)) /* Not last column? */ 2540 for (; w < maxwidth; w++) 2541 xputchar(' '); 2542 ++b; 2543 } 2544 } 2545 if (row < (rows - 1)) { 2546 if (Tty_raw_mode) 2547 xputchar('\r'); 2548 xputchar('\n'); 2549 } 2550 } 2551 #ifdef WINNT_NATIVE 2552 nt_print_builtins(maxwidth); 2553 #else 2554 if (Tty_raw_mode) 2555 xputchar('\r'); 2556 xputchar('\n'); 2557 #endif /* WINNT_NATIVE */ 2558 2559 cleanup_until(&lbuffed); /* turn back on line buffering */ 2560 flush(); 2561 } 2562 2563 #ifdef NLS_CATALOGS 2564 char * 2565 xcatgets(nl_catd ctd, int set_id, int msg_id, const char *s) 2566 { 2567 char *res; 2568 2569 errno = 0; 2570 while ((res = catgets(ctd, set_id, msg_id, s)) == s && errno == EINTR) { 2571 handle_pending_signals(); 2572 errno = 0; 2573 } 2574 return res; 2575 } 2576 2577 2578 # if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2579 char * 2580 iconv_catgets(nl_catd ctd, int set_id, int msg_id, const char *s) 2581 { 2582 static char *buf = NULL; 2583 static size_t buf_size = 0; 2584 2585 char *orig, *dest, *p; 2586 ICONV_CONST char *src; 2587 size_t src_size, dest_size; 2588 2589 orig = xcatgets(ctd, set_id, msg_id, s); 2590 if (catgets_iconv == (iconv_t)-1 || orig == s) 2591 return orig; 2592 src = orig; 2593 src_size = strlen(src) + 1; 2594 if (buf == NULL && (buf = xmalloc(buf_size = src_size + 32)) == NULL) 2595 return orig; 2596 dest = buf; 2597 while (src_size != 0) { 2598 dest_size = buf + buf_size - dest; 2599 if (iconv(catgets_iconv, &src, &src_size, &dest, &dest_size) 2600 == (size_t)-1) { 2601 switch (errno) { 2602 case E2BIG: 2603 if ((p = xrealloc(buf, buf_size * 2)) == NULL) 2604 return orig; 2605 buf_size *= 2; 2606 dest = p + (dest - buf); 2607 buf = p; 2608 break; 2609 2610 case EILSEQ: case EINVAL: default: 2611 return orig; 2612 } 2613 } 2614 } 2615 return buf; 2616 } 2617 # endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2618 #endif /* NLS_CATALOGS */ 2619 2620 void 2621 nlsinit(void) 2622 { 2623 #ifdef NLS_CATALOGS 2624 static const char default_catalog[] = "tcsh"; 2625 2626 char *catalog = (char *)(intptr_t)default_catalog; 2627 2628 if (adrof(STRcatalog) != NULL) 2629 catalog = xasprintf("tcsh.%s", short2str(varval(STRcatalog))); 2630 #ifdef NL_CAT_LOCALE /* POSIX-compliant. */ 2631 /* 2632 * Check if LC_MESSAGES is set in the environment and use it, if so. 2633 * If not, fall back to the setting of LANG. 2634 */ 2635 catd = catopen(catalog, tgetenv(STRLC_MESSAGES) ? NL_CAT_LOCALE : 0); 2636 #else /* pre-POSIX */ 2637 # ifndef MCLoadBySet 2638 # define MCLoadBySet 0 2639 # endif 2640 catd = catopen(catalog, MCLoadBySet); 2641 #endif 2642 if (catalog != default_catalog) 2643 xfree(catalog); 2644 #if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2645 /* xcatgets (), not CGETS, the charset name should be in ASCII anyway. */ 2646 catgets_iconv = iconv_open (nl_langinfo (CODESET), 2647 xcatgets(catd, 255, 1, "UTF-8")); 2648 #endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2649 #endif /* NLS_CATALOGS */ 2650 #ifdef WINNT_NATIVE 2651 nls_dll_init(); 2652 #endif /* WINNT_NATIVE */ 2653 errinit(); /* init the errorlist in correct locale */ 2654 mesginit(); /* init the messages for signals */ 2655 dateinit(); /* init the messages for dates */ 2656 editinit(); /* init the editor messages */ 2657 terminit(); /* init the termcap messages */ 2658 } 2659 2660 void 2661 nlsclose(void) 2662 { 2663 #ifdef NLS_CATALOGS 2664 #if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2665 if (catgets_iconv != (iconv_t)-1) { 2666 iconv_close(catgets_iconv); 2667 catgets_iconv = (iconv_t)-1; 2668 } 2669 #endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2670 if (catd != (nl_catd)-1) { 2671 /* 2672 * catclose can call other functions which can call longjmp 2673 * making us re-enter this code. Prevent infinite recursion 2674 * by resetting catd. Problem reported and solved by: 2675 * Gerhard Niklasch 2676 */ 2677 nl_catd oldcatd = catd; 2678 catd = (nl_catd)-1; 2679 while (catclose(oldcatd) == -1 && errno == EINTR) 2680 handle_pending_signals(); 2681 } 2682 #endif /* NLS_CATALOGS */ 2683 } 2684