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