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