1 /* $Header: /p/tcsh/cvsroot/tcsh/sh.func.c,v 3.153 2009/06/25 21:15:37 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.153 2009/06/25 21:15:37 christos Exp $") 36 37 #include "ed.h" 38 #include "tw.h" 39 #include "tc.h" 40 #ifdef WINNT_NATIVE 41 #include "nt.const.h" 42 #endif /* WINNT_NATIVE */ 43 44 #if defined (NLS_CATALOGS) && defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 45 #include <langinfo.h> 46 static iconv_t catgets_iconv; /* Or (iconv_t)-1 */ 47 #endif 48 49 /* 50 * C shell 51 */ 52 53 extern int MapsAreInited; 54 extern int NLSMapsAreInited; 55 extern int GotTermCaps; 56 57 static int zlast = -1; 58 59 static void islogin (void); 60 static void preread (void); 61 static void doagain (void); 62 static const char *isrchx (int); 63 static void search (int, int, Char *); 64 static int getword (struct Strbuf *); 65 static struct wordent *histgetword (struct wordent *); 66 static void toend (void); 67 static void xecho (int, Char **); 68 static int islocale_var (Char *); 69 static void wpfree (struct whyle *); 70 71 const struct biltins * 72 isbfunc(struct command *t) 73 { 74 Char *cp = t->t_dcom[0]; 75 const struct biltins *bp, *bp1, *bp2; 76 static struct biltins label = {"", dozip, 0, 0}; 77 static struct biltins foregnd = {"%job", dofg1, 0, 0}; 78 static struct biltins backgnd = {"%job &", dobg1, 0, 0}; 79 80 /* 81 * We never match a builtin that has quoted the first 82 * character; this has been the traditional way to escape 83 * builtin commands. 84 */ 85 if (*cp & QUOTE) 86 return NULL; 87 88 if (*cp != ':' && lastchr(cp) == ':') { 89 label.bname = short2str(cp); 90 return (&label); 91 } 92 if (*cp == '%') { 93 if (t->t_dflg & F_AMPERSAND) { 94 t->t_dflg &= ~F_AMPERSAND; 95 backgnd.bname = short2str(cp); 96 return (&backgnd); 97 } 98 foregnd.bname = short2str(cp); 99 return (&foregnd); 100 } 101 #ifdef WARP 102 /* 103 * This is a perhaps kludgy way to determine if the warp builtin is to be 104 * acknowledged or not. If checkwarp() fails, then we are to assume that 105 * the warp command is invalid, and carry on as we would handle any other 106 * non-builtin command. -- JDK 2/4/88 107 */ 108 if (eq(STRwarp, cp) && !checkwarp()) { 109 return (0); /* this builtin disabled */ 110 } 111 #endif /* WARP */ 112 /* 113 * Binary search Bp1 is the beginning of the current search range. Bp2 is 114 * one past the end. 115 */ 116 for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) { 117 int i; 118 119 bp = bp1 + ((bp2 - bp1) >> 1); 120 if ((i = ((char) *cp) - *bp->bname) == 0 && 121 (i = StrQcmp(cp, str2short(bp->bname))) == 0) 122 return bp; 123 if (i < 0) 124 bp2 = bp; 125 else 126 bp1 = bp + 1; 127 } 128 #ifdef WINNT_NATIVE 129 return nt_check_additional_builtins(cp); 130 #endif /*WINNT_NATIVE*/ 131 return (0); 132 } 133 134 void 135 func(struct command *t, const struct biltins *bp) 136 { 137 int i; 138 139 xechoit(t->t_dcom); 140 setname(bp->bname); 141 i = blklen(t->t_dcom) - 1; 142 if (i < bp->minargs) 143 stderror(ERR_NAME | ERR_TOOFEW); 144 if (i > bp->maxargs) 145 stderror(ERR_NAME | ERR_TOOMANY); 146 (*bp->bfunct) (t->t_dcom, t); 147 } 148 149 /*ARGSUSED*/ 150 void 151 doonintr(Char **v, struct command *c) 152 { 153 Char *cp; 154 Char *vv = v[1]; 155 156 USE(c); 157 if (parintr.sa_handler == SIG_IGN) 158 return; 159 if (setintr && intty) 160 stderror(ERR_NAME | ERR_TERMINAL); 161 cp = gointr; 162 gointr = 0; 163 xfree(cp); 164 if (vv == 0) { 165 if (setintr) 166 sigset_interrupting(SIGINT, queue_pintr); 167 else 168 (void) signal(SIGINT, SIG_DFL); 169 gointr = 0; 170 } 171 else if (eq((vv = strip(vv)), STRminus)) { 172 (void) signal(SIGINT, SIG_IGN); 173 gointr = Strsave(STRminus); 174 } 175 else { 176 gointr = Strsave(vv); 177 sigset_interrupting(SIGINT, queue_pintr); 178 } 179 } 180 181 /*ARGSUSED*/ 182 void 183 donohup(Char **v, struct command *c) 184 { 185 USE(c); 186 USE(v); 187 if (intty) 188 stderror(ERR_NAME | ERR_TERMINAL); 189 if (setintr == 0) { 190 (void) signal(SIGHUP, SIG_IGN); 191 phup_disabled = 1; 192 #ifdef CC 193 submit(getpid()); 194 #endif /* CC */ 195 } 196 } 197 198 /*ARGSUSED*/ 199 void 200 dohup(Char **v, struct command *c) 201 { 202 USE(c); 203 USE(v); 204 if (intty) 205 stderror(ERR_NAME | ERR_TERMINAL); 206 if (setintr == 0) 207 (void) signal(SIGHUP, SIG_DFL); 208 } 209 210 211 /*ARGSUSED*/ 212 void 213 dozip(Char **v, struct command *c) 214 { 215 USE(c); 216 USE(v); 217 } 218 219 /*ARGSUSED*/ 220 void 221 dofiletest(Char **v, struct command *c) 222 { 223 Char **globbed, **fileptr, *ftest, *res; 224 225 USE(c); 226 if (*(ftest = *++v) != '-') 227 stderror(ERR_NAME | ERR_FILEINQ); 228 ++v; 229 230 v = glob_all_or_error(v); 231 globbed = v; 232 cleanup_push(globbed, blk_cleanup); 233 234 while (*(fileptr = v++) != '\0') { 235 res = filetest(ftest, &fileptr, 0); 236 cleanup_push(res, xfree); 237 xprintf("%S", res); 238 cleanup_until(res); 239 if (*v) 240 xprintf(" "); 241 } 242 xprintf("\n"); 243 244 cleanup_until(globbed); 245 } 246 247 void 248 prvars(void) 249 { 250 plist(&shvhed, VAR_ALL); 251 } 252 253 /*ARGSUSED*/ 254 void 255 doalias(Char **v, struct command *c) 256 { 257 struct varent *vp; 258 Char *p; 259 260 USE(c); 261 v++; 262 p = *v++; 263 if (p == 0) 264 plist(&aliases, VAR_ALL); 265 else if (*v == 0) { 266 vp = adrof1(strip(p), &aliases); 267 if (vp && vp->vec) 268 blkpr(vp->vec), xputchar('\n'); 269 } 270 else { 271 if (eq(p, STRalias) || eq(p, STRunalias)) { 272 setname(short2str(p)); 273 stderror(ERR_NAME | ERR_DANGER); 274 } 275 set1(strip(p), saveblk(v), &aliases, VAR_READWRITE); 276 tw_cmd_free(); 277 } 278 } 279 280 /*ARGSUSED*/ 281 void 282 unalias(Char **v, struct command *c) 283 { 284 USE(c); 285 unset1(v, &aliases); 286 tw_cmd_free(); 287 } 288 289 /*ARGSUSED*/ 290 void 291 dologout(Char **v, struct command *c) 292 { 293 USE(c); 294 USE(v); 295 islogin(); 296 goodbye(NULL, NULL); 297 } 298 299 /*ARGSUSED*/ 300 void 301 dologin(Char **v, struct command *c) 302 { 303 #ifdef WINNT_NATIVE 304 USE(c); 305 USE(v); 306 #else /* !WINNT_NATIVE */ 307 char **p = short2blk(v); 308 309 USE(c); 310 cleanup_push((Char **)p, blk_cleanup); 311 islogin(); 312 rechist(NULL, adrof(STRsavehist) != NULL); 313 sigaction(SIGTERM, &parterm, NULL); 314 (void) execv(_PATH_BIN_LOGIN, p); 315 (void) execv(_PATH_USRBIN_LOGIN, p); 316 cleanup_until((Char **)p); 317 untty(); 318 xexit(1); 319 #endif /* !WINNT_NATIVE */ 320 } 321 322 323 #ifdef NEWGRP 324 /*ARGSUSED*/ 325 void 326 donewgrp(Char **v, struct command *c) 327 { 328 char **p; 329 if (chkstop == 0 && setintr) 330 panystop(0); 331 sigaction(SIGTERM, &parterm, NULL); 332 p = short2blk(v); 333 /* 334 * From Beto Appleton (beto@aixwiz.austin.ibm.com) 335 * Newgrp can take 2 arguments... 336 */ 337 (void) execv(_PATH_BIN_NEWGRP, p); 338 (void) execv(_PATH_USRBIN_NEWGRP, p); 339 blkfree((Char **) p); 340 untty(); 341 xexit(1); 342 } 343 #endif /* NEWGRP */ 344 345 static void 346 islogin(void) 347 { 348 if (chkstop == 0 && setintr) 349 panystop(0); 350 if (loginsh) 351 return; 352 stderror(ERR_NOTLOGIN); 353 } 354 355 void 356 doif(Char **v, struct command *kp) 357 { 358 int i; 359 Char **vv; 360 361 v++; 362 i = noexec ? 1 : expr(&v); 363 vv = v; 364 if (*vv == NULL) 365 stderror(ERR_NAME | ERR_EMPTYIF); 366 if (eq(*vv, STRthen)) { 367 if (*++vv) 368 stderror(ERR_NAME | ERR_IMPRTHEN); 369 setname(short2str(STRthen)); 370 /* 371 * If expression was zero, then scan to else , otherwise just fall into 372 * following code. 373 */ 374 if (!i) 375 search(TC_IF, 0, NULL); 376 return; 377 } 378 /* 379 * Simple command attached to this if. Left shift the node in this tree, 380 * munging it so we can reexecute it. 381 */ 382 if (i) { 383 lshift(kp->t_dcom, vv - kp->t_dcom); 384 reexecute(kp); 385 donefds(); 386 } 387 } 388 389 /* 390 * Reexecute a command, being careful not 391 * to redo i/o redirection, which is already set up. 392 */ 393 void 394 reexecute(struct command *kp) 395 { 396 kp->t_dflg &= F_SAVE; 397 kp->t_dflg |= F_REPEAT; 398 /* 399 * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set 400 * pgrp's as the jobs would then have no way to get the tty (we can't give 401 * it to them, and our parent wouldn't know their pgrp, etc. 402 */ 403 execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL, TRUE); 404 } 405 406 /*ARGSUSED*/ 407 void 408 doelse (Char **v, struct command *c) 409 { 410 USE(c); 411 USE(v); 412 if (!noexec) 413 search(TC_ELSE, 0, NULL); 414 } 415 416 /*ARGSUSED*/ 417 void 418 dogoto(Char **v, struct command *c) 419 { 420 Char *lp; 421 422 USE(c); 423 lp = globone(v[1], G_ERROR); 424 cleanup_push(lp, xfree); 425 if (!noexec) 426 gotolab(lp); 427 cleanup_until(lp); 428 } 429 430 void 431 gotolab(Char *lab) 432 { 433 struct whyle *wp; 434 /* 435 * While we still can, locate any unknown ends of existing loops. This 436 * obscure code is the WORST result of the fact that we don't really parse. 437 */ 438 zlast = TC_GOTO; 439 for (wp = whyles; wp; wp = wp->w_next) 440 if (wp->w_end.type == TCSH_F_SEEK && wp->w_end.f_seek == 0) { 441 search(TC_BREAK, 0, NULL); 442 btell(&wp->w_end); 443 } 444 else { 445 bseek(&wp->w_end); 446 } 447 search(TC_GOTO, 0, lab); 448 /* 449 * Eliminate loops which were exited. 450 */ 451 wfree(); 452 } 453 454 /*ARGSUSED*/ 455 void 456 doswitch(Char **v, struct command *c) 457 { 458 Char *cp, *lp; 459 460 USE(c); 461 v++; 462 if (!*v || *(*v++) != '(') 463 stderror(ERR_SYNTAX); 464 cp = **v == ')' ? STRNULL : *v++; 465 if (*(*v++) != ')') 466 v--; 467 if (*v) 468 stderror(ERR_SYNTAX); 469 lp = globone(cp, G_ERROR); 470 cleanup_push(lp, xfree); 471 if (!noexec) 472 search(TC_SWITCH, 0, lp); 473 cleanup_until(lp); 474 } 475 476 /*ARGSUSED*/ 477 void 478 dobreak(Char **v, struct command *c) 479 { 480 USE(v); 481 USE(c); 482 if (whyles == NULL) 483 stderror(ERR_NAME | ERR_NOTWHILE); 484 if (!noexec) 485 toend(); 486 } 487 488 /*ARGSUSED*/ 489 void 490 doexit(Char **v, struct command *c) 491 { 492 USE(c); 493 494 if (chkstop == 0 && (intty || intact) && evalvec == 0) 495 panystop(0); 496 /* 497 * Don't DEMAND parentheses here either. 498 */ 499 v++; 500 if (*v) { 501 setv(STRstatus, putn(expr(&v)), VAR_READWRITE); 502 if (*v) 503 stderror(ERR_NAME | ERR_EXPRESSION); 504 } 505 btoeof(); 506 #if 0 507 if (intty) 508 #endif 509 /* Always close, why only on ttys? */ 510 xclose(SHIN); 511 } 512 513 /*ARGSUSED*/ 514 void 515 doforeach(Char **v, struct command *c) 516 { 517 Char *cp, *sp; 518 struct whyle *nwp; 519 int gflag; 520 521 USE(c); 522 v++; 523 sp = cp = strip(*v); 524 if (!letter(*sp)) 525 stderror(ERR_NAME | ERR_VARBEGIN); 526 while (*cp && alnum(*cp)) 527 cp++; 528 if (*cp) 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_next = whyles; 591 whyles = nwp; 592 zlast = TC_WHILE; 593 if (intty) { 594 /* 595 * The tty preread 596 */ 597 preread(); 598 doagain(); 599 return; 600 } 601 } 602 if (status) 603 /* We ain't gonna loop no more, no more! */ 604 toend(); 605 } 606 607 static void 608 preread(void) 609 { 610 int old_pintr_disabled; 611 612 whyles->w_end.type = TCSH_I_SEEK; 613 if (setintr) 614 pintr_push_enable(&old_pintr_disabled); 615 search(TC_BREAK, 0, NULL); /* read the expression in */ 616 if (setintr) 617 cleanup_until(&old_pintr_disabled); 618 btell(&whyles->w_end); 619 } 620 621 /*ARGSUSED*/ 622 void 623 doend(Char **v, struct command *c) 624 { 625 USE(v); 626 USE(c); 627 if (!whyles) 628 stderror(ERR_NAME | ERR_NOTWHILE); 629 btell(&whyles->w_end); 630 if (!noexec) 631 doagain(); 632 } 633 634 /*ARGSUSED*/ 635 void 636 docontin(Char **v, struct command *c) 637 { 638 USE(v); 639 USE(c); 640 if (!whyles) 641 stderror(ERR_NAME | ERR_NOTWHILE); 642 if (!noexec) 643 doagain(); 644 } 645 646 static void 647 doagain(void) 648 { 649 /* Repeating a while is simple */ 650 if (whyles->w_fename == 0) { 651 bseek(&whyles->w_start); 652 return; 653 } 654 /* 655 * The foreach variable list actually has a spurious word ")" at the end of 656 * the w_fe list. Thus we are at the of the list if one word beyond this 657 * is 0. 658 */ 659 if (!whyles->w_fe[1]) { 660 dobreak(NULL, NULL); 661 return; 662 } 663 setv(whyles->w_fename, quote(Strsave(*whyles->w_fe++)), VAR_READWRITE); 664 bseek(&whyles->w_start); 665 } 666 667 void 668 dorepeat(Char **v, struct command *kp) 669 { 670 int i = 1; 671 672 do { 673 i *= getn(v[1]); 674 lshift(v, 2); 675 } while (v[0] != NULL && Strcmp(v[0], STRrepeat) == 0); 676 if (noexec) 677 i = 1; 678 679 if (setintr) { 680 pintr_disabled++; 681 cleanup_push(&pintr_disabled, disabled_cleanup); 682 } 683 while (i > 0) { 684 if (setintr && pintr_disabled == 1) { 685 cleanup_until(&pintr_disabled); 686 pintr_disabled++; 687 cleanup_push(&pintr_disabled, disabled_cleanup); 688 } 689 reexecute(kp); 690 --i; 691 } 692 if (setintr && pintr_disabled == 1) 693 cleanup_until(&pintr_disabled); 694 donefds(); 695 } 696 697 /*ARGSUSED*/ 698 void 699 doswbrk(Char **v, struct command *c) 700 { 701 USE(v); 702 USE(c); 703 if (!noexec) 704 search(TC_BRKSW, 0, NULL); 705 } 706 707 int 708 srchx(Char *cp) 709 { 710 struct srch *sp, *sp1, *sp2; 711 int i; 712 713 /* 714 * Ignore keywords inside heredocs 715 */ 716 if (inheredoc) 717 return -1; 718 719 /* 720 * Binary search Sp1 is the beginning of the current search range. Sp2 is 721 * one past the end. 722 */ 723 for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) { 724 sp = sp1 + ((sp2 - sp1) >> 1); 725 if ((i = *cp - *sp->s_name) == 0 && 726 (i = Strcmp(cp, str2short(sp->s_name))) == 0) 727 return sp->s_value; 728 if (i < 0) 729 sp2 = sp; 730 else 731 sp1 = sp + 1; 732 } 733 return (-1); 734 } 735 736 static const char * 737 isrchx(int n) 738 { 739 struct srch *sp, *sp2; 740 741 for (sp = srchn, sp2 = srchn + nsrchn; sp < sp2; sp++) 742 if (sp->s_value == n) 743 return (sp->s_name); 744 return (""); 745 } 746 747 748 static int Stype; 749 static Char *Sgoal; 750 751 static void 752 search(int type, int level, Char *goal) 753 { 754 struct Strbuf word = Strbuf_INIT; 755 Char *cp; 756 struct whyle *wp; 757 int wlevel = 0; 758 struct wordent *histent = NULL, *ohistent = NULL; 759 760 Stype = type; 761 Sgoal = goal; 762 if (type == TC_GOTO) { 763 struct Ain a; 764 a.type = TCSH_F_SEEK; 765 a.f_seek = 0; 766 bseek(&a); 767 } 768 cleanup_push(&word, Strbuf_cleanup); 769 do { 770 771 if (intty) { 772 histent = xmalloc(sizeof(*histent)); 773 ohistent = xmalloc(sizeof(*histent)); 774 ohistent->word = STRNULL; 775 ohistent->next = histent; 776 histent->prev = ohistent; 777 } 778 779 if (intty && fseekp == feobp && aret == TCSH_F_SEEK) 780 printprompt(1, isrchx(type == TC_BREAK ? zlast : type)); 781 /* xprintf("? "), flush(); */ 782 (void) getword(&word); 783 Strbuf_terminate(&word); 784 785 if (intty && Strlen(word.s) > 0) { 786 histent->word = Strsave(word.s); 787 histent->next = xmalloc(sizeof(*histent)); 788 histent->next->prev = histent; 789 histent = histent->next; 790 } 791 792 switch (srchx(word.s)) { 793 794 case TC_ELSE: 795 if (level == 0 && type == TC_IF) 796 goto end; 797 break; 798 799 case TC_IF: 800 while (getword(&word)) 801 continue; 802 if ((type == TC_IF || type == TC_ELSE) && 803 eq(word.s, STRthen)) 804 level++; 805 break; 806 807 case TC_ENDIF: 808 if (type == TC_IF || type == TC_ELSE) 809 level--; 810 break; 811 812 case TC_FOREACH: 813 case TC_WHILE: 814 wlevel++; 815 if (type == TC_BREAK) 816 level++; 817 break; 818 819 case TC_END: 820 if (type == TC_BRKSW) { 821 if (wlevel == 0) { 822 wp = whyles; 823 if (wp) { 824 whyles = wp->w_next; 825 wpfree(wp); 826 } 827 } 828 } 829 if (type == TC_BREAK) 830 level--; 831 wlevel--; 832 break; 833 834 case TC_SWITCH: 835 if (type == TC_SWITCH || type == TC_BRKSW) 836 level++; 837 break; 838 839 case TC_ENDSW: 840 if (type == TC_SWITCH || type == TC_BRKSW) 841 level--; 842 break; 843 844 case TC_LABEL: 845 if (type == TC_GOTO && getword(&word) && eq(word.s, goal)) 846 level = -1; 847 break; 848 849 default: 850 if (type != TC_GOTO && (type != TC_SWITCH || level != 0)) 851 break; 852 if (word.len == 0 || word.s[word.len - 1] != ':') 853 break; 854 word.s[--word.len] = 0; 855 if ((type == TC_GOTO && eq(word.s, goal)) || 856 (type == TC_SWITCH && eq(word.s, STRdefault))) 857 level = -1; 858 break; 859 860 case TC_CASE: 861 if (type != TC_SWITCH || level != 0) 862 break; 863 (void) getword(&word); 864 if (word.len != 0 && word.s[word.len - 1] == ':') 865 word.s[--word.len] = 0; 866 cp = strip(Dfix1(word.s)); 867 cleanup_push(cp, xfree); 868 if (Gmatch(goal, cp)) 869 level = -1; 870 cleanup_until(cp); 871 break; 872 873 case TC_DEFAULT: 874 if (type == TC_SWITCH && level == 0) 875 level = -1; 876 break; 877 } 878 if (intty) { 879 ohistent->prev = histgetword(histent); 880 ohistent->prev->next = ohistent; 881 savehist(ohistent, 0); 882 freelex(ohistent); 883 xfree(ohistent); 884 } else 885 (void) getword(NULL); 886 } while (level >= 0); 887 end: 888 cleanup_until(&word); 889 } 890 891 static struct wordent * 892 histgetword(struct wordent *histent) 893 { 894 int found = 0, first; 895 eChar c, d; 896 int e; 897 struct Strbuf *tmp; 898 tmp = xmalloc(sizeof(*tmp)); 899 tmp->size = 0; 900 tmp->s = NULL; 901 c = readc(1); 902 d = 0; 903 e = 0; 904 for (;;) { 905 tmp->len = 0; 906 Strbuf_terminate (tmp); 907 while (c == ' ' || c == '\t') 908 c = readc(1); 909 if (c == '#') 910 do 911 c = readc(1); 912 while (c != CHAR_ERR && c != '\n'); 913 if (c == CHAR_ERR) 914 goto past; 915 if (c == '\n') 916 goto nl; 917 unreadc(c); 918 found = 1; 919 first = 1; 920 do { 921 e = (c == '\\'); 922 c = readc(1); 923 if (c == '\\' && !e) { 924 if ((c = readc(1)) == '\n') { 925 e = 1; 926 c = ' '; 927 } else { 928 unreadc(c); 929 c = '\\'; 930 } 931 } 932 if ((c == '\'' || c == '"') && !e) { 933 if (d == 0) 934 d = c; 935 else if (d == c) 936 d = 0; 937 } 938 if (c == CHAR_ERR) 939 goto past; 940 941 Strbuf_append1(tmp, (Char) c); 942 943 if (!first && !d && c == '(' && !e) { 944 break; 945 } 946 first = 0; 947 } while (d || e || (c != ' ' && c != '\t' && c != '\n')); 948 tmp->len--; 949 if (tmp->len) { 950 Strbuf_terminate(tmp); 951 histent->word = Strsave(tmp->s); 952 histent->next = xmalloc(sizeof (*histent)); 953 histent->next->prev = histent; 954 histent = histent->next; 955 } 956 if (c == '\n') { 957 nl: 958 tmp->len = 0; 959 Strbuf_append1(tmp, (Char) c); 960 Strbuf_terminate(tmp); 961 histent->word = Strsave(tmp->s); 962 return histent; 963 } 964 } 965 966 unreadc(c); 967 return histent; 968 969 past: 970 switch (Stype) { 971 972 case TC_IF: 973 stderror(ERR_NAME | ERR_NOTFOUND, "then/endif"); 974 break; 975 976 case TC_ELSE: 977 stderror(ERR_NAME | ERR_NOTFOUND, "endif"); 978 break; 979 980 case TC_BRKSW: 981 case TC_SWITCH: 982 stderror(ERR_NAME | ERR_NOTFOUND, "endsw"); 983 break; 984 985 case TC_BREAK: 986 stderror(ERR_NAME | ERR_NOTFOUND, "end"); 987 break; 988 989 case TC_GOTO: 990 setname(short2str(Sgoal)); 991 stderror(ERR_NAME | ERR_NOTFOUND, "label"); 992 break; 993 994 default: 995 break; 996 } 997 /* NOTREACHED */ 998 return NULL; 999 } 1000 1001 static int 1002 getword(struct Strbuf *wp) 1003 { 1004 int found = 0, first; 1005 eChar c, d; 1006 1007 if (wp) 1008 wp->len = 0; 1009 c = readc(1); 1010 d = 0; 1011 do { 1012 while (c == ' ' || c == '\t') 1013 c = readc(1); 1014 if (c == '#') 1015 do 1016 c = readc(1); 1017 while (c != CHAR_ERR && c != '\n'); 1018 if (c == CHAR_ERR) 1019 goto past; 1020 if (c == '\n') { 1021 if (wp) 1022 break; 1023 return (0); 1024 } 1025 unreadc(c); 1026 found = 1; 1027 first = 1; 1028 do { 1029 c = readc(1); 1030 if (c == '\\' && (c = readc(1)) == '\n') 1031 c = ' '; 1032 if (c == '\'' || c == '"') { 1033 if (d == 0) 1034 d = c; 1035 else if (d == c) 1036 d = 0; 1037 } 1038 if (c == CHAR_ERR) 1039 goto past; 1040 if (wp) 1041 Strbuf_append1(wp, (Char) c); 1042 if (!first && !d && c == '(') { 1043 if (wp) 1044 goto past_word_end; 1045 else 1046 break; 1047 } 1048 first = 0; 1049 } while ((d || (c != ' ' && c != '\t')) && c != '\n'); 1050 } while (wp == 0); 1051 1052 past_word_end: 1053 unreadc(c); 1054 if (found) { 1055 wp->len--; 1056 Strbuf_terminate(wp); 1057 } 1058 1059 return (found); 1060 1061 past: 1062 switch (Stype) { 1063 1064 case TC_IF: 1065 stderror(ERR_NAME | ERR_NOTFOUND, "then/endif"); 1066 break; 1067 1068 case TC_ELSE: 1069 stderror(ERR_NAME | ERR_NOTFOUND, "endif"); 1070 break; 1071 1072 case TC_BRKSW: 1073 case TC_SWITCH: 1074 stderror(ERR_NAME | ERR_NOTFOUND, "endsw"); 1075 break; 1076 1077 case TC_BREAK: 1078 stderror(ERR_NAME | ERR_NOTFOUND, "end"); 1079 break; 1080 1081 case TC_GOTO: 1082 setname(short2str(Sgoal)); 1083 stderror(ERR_NAME | ERR_NOTFOUND, "label"); 1084 break; 1085 1086 default: 1087 break; 1088 } 1089 /* NOTREACHED */ 1090 return (0); 1091 } 1092 1093 static void 1094 toend(void) 1095 { 1096 if (whyles->w_end.type == TCSH_F_SEEK && whyles->w_end.f_seek == 0) { 1097 search(TC_BREAK, 0, NULL); 1098 btell(&whyles->w_end); 1099 whyles->w_end.f_seek--; 1100 } 1101 else { 1102 bseek(&whyles->w_end); 1103 } 1104 wfree(); 1105 } 1106 1107 static void 1108 wpfree(struct whyle *wp) 1109 { 1110 if (wp->w_fe0) 1111 blkfree(wp->w_fe0); 1112 xfree(wp->w_fename); 1113 xfree(wp); 1114 } 1115 1116 void 1117 wfree(void) 1118 { 1119 struct Ain o; 1120 struct whyle *nwp; 1121 #ifdef lint 1122 nwp = NULL; /* sun lint is dumb! */ 1123 #endif 1124 1125 #ifdef FDEBUG 1126 static const char foo[] = "IAFE"; 1127 #endif /* FDEBUG */ 1128 1129 btell(&o); 1130 1131 #ifdef FDEBUG 1132 xprintf("o->type %c o->a_seek %d o->f_seek %d\n", 1133 foo[o.type + 1], o.a_seek, o.f_seek); 1134 #endif /* FDEBUG */ 1135 1136 for (; whyles; whyles = nwp) { 1137 struct whyle *wp = whyles; 1138 nwp = wp->w_next; 1139 1140 #ifdef FDEBUG 1141 xprintf("start->type %c start->a_seek %d start->f_seek %d\n", 1142 foo[wp->w_start.type+1], 1143 wp->w_start.a_seek, wp->w_start.f_seek); 1144 xprintf("end->type %c end->a_seek %d end->f_seek %d\n", 1145 foo[wp->w_end.type + 1], wp->w_end.a_seek, wp->w_end.f_seek); 1146 #endif /* FDEBUG */ 1147 1148 /* 1149 * XXX: We free loops that have different seek types. 1150 */ 1151 if (wp->w_end.type != TCSH_I_SEEK && wp->w_start.type == wp->w_end.type && 1152 wp->w_start.type == o.type) { 1153 if (wp->w_end.type == TCSH_F_SEEK) { 1154 if (o.f_seek >= wp->w_start.f_seek && 1155 (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek)) 1156 break; 1157 } 1158 else { 1159 if (o.a_seek >= wp->w_start.a_seek && 1160 (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek)) 1161 break; 1162 } 1163 } 1164 1165 wpfree(wp); 1166 } 1167 } 1168 1169 /*ARGSUSED*/ 1170 void 1171 doecho(Char **v, struct command *c) 1172 { 1173 USE(c); 1174 xecho(' ', v); 1175 } 1176 1177 /*ARGSUSED*/ 1178 void 1179 doglob(Char **v, struct command *c) 1180 { 1181 USE(c); 1182 xecho(0, v); 1183 flush(); 1184 } 1185 1186 static void 1187 xecho(int sep, Char **v) 1188 { 1189 Char *cp, **globbed = NULL; 1190 int nonl = 0; 1191 int echo_style = ECHO_STYLE; 1192 struct varent *vp; 1193 1194 if ((vp = adrof(STRecho_style)) != NULL && vp->vec != NULL && 1195 vp->vec[0] != NULL) { 1196 if (Strcmp(vp->vec[0], STRbsd) == 0) 1197 echo_style = BSD_ECHO; 1198 else if (Strcmp(vp->vec[0], STRsysv) == 0) 1199 echo_style = SYSV_ECHO; 1200 else if (Strcmp(vp->vec[0], STRboth) == 0) 1201 echo_style = BOTH_ECHO; 1202 else if (Strcmp(vp->vec[0], STRnone) == 0) 1203 echo_style = NONE_ECHO; 1204 } 1205 1206 v++; 1207 if (*v == 0) 1208 goto done; 1209 if (setintr) { 1210 int old_pintr_disabled; 1211 pintr_push_enable(&old_pintr_disabled); 1212 v = glob_all_or_error(v); 1213 cleanup_until(&old_pintr_disabled); 1214 } else { 1215 v = glob_all_or_error(v); 1216 } 1217 globbed = v; 1218 if (globbed != NULL) 1219 cleanup_push(globbed, blk_cleanup); 1220 1221 if ((echo_style & BSD_ECHO) != 0 && sep == ' ' && *v && eq(*v, STRmn)) 1222 nonl++, v++; 1223 1224 while ((cp = *v++) != 0) { 1225 Char c; 1226 1227 if (setintr) { 1228 int old_pintr_disabled; 1229 1230 pintr_push_enable(&old_pintr_disabled); 1231 cleanup_until(&old_pintr_disabled); 1232 } 1233 while ((c = *cp++) != 0) { 1234 if ((echo_style & SYSV_ECHO) != 0 && c == '\\') { 1235 switch (c = *cp++) { 1236 case 'a': 1237 c = '\a'; 1238 break; 1239 case 'b': 1240 c = '\b'; 1241 break; 1242 case 'c': 1243 nonl = 1; 1244 goto done; 1245 case 'e': 1246 #if 0 /* Windows does not understand \e */ 1247 c = '\e'; 1248 #else 1249 c = CTL_ESC('\033'); 1250 #endif 1251 break; 1252 case 'f': 1253 c = '\f'; 1254 break; 1255 case 'n': 1256 c = '\n'; 1257 break; 1258 case 'r': 1259 c = '\r'; 1260 break; 1261 case 't': 1262 c = '\t'; 1263 break; 1264 case 'v': 1265 c = '\v'; 1266 break; 1267 case '\\': 1268 c = '\\'; 1269 break; 1270 case '0': 1271 c = 0; 1272 if (*cp >= '0' && *cp < '8') 1273 c = c * 8 + *cp++ - '0'; 1274 if (*cp >= '0' && *cp < '8') 1275 c = c * 8 + *cp++ - '0'; 1276 if (*cp >= '0' && *cp < '8') 1277 c = c * 8 + *cp++ - '0'; 1278 break; 1279 case '\0': 1280 c = '\\'; 1281 cp--; 1282 break; 1283 default: 1284 xputchar('\\' | QUOTE); 1285 break; 1286 } 1287 } 1288 xputwchar(c | QUOTE); 1289 1290 } 1291 if (*v) 1292 xputchar(sep | QUOTE); 1293 } 1294 done: 1295 if (sep && nonl == 0) 1296 xputchar('\n'); 1297 else 1298 flush(); 1299 if (globbed != NULL) 1300 cleanup_until(globbed); 1301 } 1302 1303 /* check whether an environment variable should invoke 'set_locale()' */ 1304 static int 1305 islocale_var(Char *var) 1306 { 1307 static Char *locale_vars[] = { 1308 STRLANG, STRLC_ALL, STRLC_CTYPE, STRLC_NUMERIC, 1309 STRLC_TIME, STRLC_COLLATE, STRLC_MESSAGES, STRLC_MONETARY, 0 1310 }; 1311 Char **v; 1312 1313 for (v = locale_vars; *v; ++v) 1314 if (eq(var, *v)) 1315 return 1; 1316 return 0; 1317 } 1318 1319 static void 1320 xlate_cr_cleanup(void *dummy) 1321 { 1322 USE(dummy); 1323 xlate_cr = 0; 1324 } 1325 1326 /*ARGSUSED*/ 1327 void 1328 doprintenv(Char **v, struct command *c) 1329 { 1330 Char *e; 1331 1332 USE(c); 1333 v++; 1334 if (*v == 0) { 1335 Char **ep; 1336 1337 xlate_cr = 1; 1338 cleanup_push(&xlate_cr, xlate_cr_cleanup); 1339 for (ep = STR_environ; *ep; ep++) { 1340 if (setintr) { 1341 int old_pintr_disabled; 1342 1343 pintr_push_enable(&old_pintr_disabled); 1344 cleanup_until(&old_pintr_disabled); 1345 } 1346 xprintf("%S\n", *ep); 1347 } 1348 cleanup_until(&xlate_cr); 1349 } 1350 else if ((e = tgetenv(*v)) != NULL) { 1351 int old_output_raw; 1352 1353 old_output_raw = output_raw; 1354 output_raw = 1; 1355 cleanup_push(&old_output_raw, output_raw_restore); 1356 xprintf("%S\n", e); 1357 cleanup_until(&old_output_raw); 1358 } 1359 else 1360 setcopy(STRstatus, STR1, VAR_READWRITE); 1361 } 1362 1363 /* from "Karl Berry." <karl%mote.umb.edu@relay.cs.net> -- for NeXT things 1364 (and anything else with a modern compiler) */ 1365 1366 /*ARGSUSED*/ 1367 void 1368 dosetenv(Char **v, struct command *c) 1369 { 1370 Char *vp, *lp; 1371 1372 USE(c); 1373 if (*++v == 0) { 1374 doprintenv(--v, 0); 1375 return; 1376 } 1377 1378 vp = *v++; 1379 1380 lp = vp; 1381 1382 for (; *lp != '\0' ; lp++) { 1383 if (*lp == '=') 1384 stderror(ERR_NAME | ERR_SYNTAX); 1385 } 1386 if ((lp = *v++) == 0) 1387 lp = STRNULL; 1388 1389 lp = globone(lp, G_APPEND); 1390 cleanup_push(lp, xfree); 1391 tsetenv(vp, lp); 1392 if (eq(vp, STRKPATH)) { 1393 importpath(lp); 1394 dohash(NULL, NULL); 1395 cleanup_until(lp); 1396 return; 1397 } 1398 1399 #ifdef apollo 1400 if (eq(vp, STRSYSTYPE)) { 1401 dohash(NULL, NULL); 1402 cleanup_until(lp); 1403 return; 1404 } 1405 #endif /* apollo */ 1406 1407 /* dspkanji/dspmbyte autosetting */ 1408 /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */ 1409 #if defined(DSPMBYTE) 1410 if(eq(vp, STRLANG) && !adrof(CHECK_MBYTEVAR)) { 1411 autoset_dspmbyte(lp); 1412 } 1413 #endif 1414 1415 if (islocale_var(vp)) { 1416 #ifdef NLS 1417 int k; 1418 1419 # ifdef SETLOCALEBUG 1420 dont_free = 1; 1421 # endif /* SETLOCALEBUG */ 1422 (void) setlocale(LC_ALL, ""); 1423 # ifdef LC_COLLATE 1424 (void) setlocale(LC_COLLATE, ""); 1425 # endif 1426 # ifdef LC_CTYPE 1427 (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 1428 # endif /* LC_CTYPE */ 1429 # ifdef NLS_CATALOGS 1430 # ifdef LC_MESSAGES 1431 (void) setlocale(LC_MESSAGES, ""); 1432 # endif /* LC_MESSAGES */ 1433 nlsclose(); 1434 nlsinit(); 1435 # endif /* NLS_CATALOGS */ 1436 # ifdef SETLOCALEBUG 1437 dont_free = 0; 1438 # endif /* SETLOCALEBUG */ 1439 # ifdef STRCOLLBUG 1440 fix_strcoll_bug(); 1441 # endif /* STRCOLLBUG */ 1442 tw_cmd_free(); /* since the collation sequence has changed */ 1443 for (k = 0200; k <= 0377 && !Isprint(CTL_ESC(k)); k++) 1444 continue; 1445 AsciiOnly = MB_CUR_MAX == 1 && k > 0377; 1446 #else /* !NLS */ 1447 AsciiOnly = 0; 1448 #endif /* NLS */ 1449 NLSMapsAreInited = 0; 1450 ed_Init(); 1451 if (MapsAreInited && !NLSMapsAreInited) 1452 ed_InitNLSMaps(); 1453 cleanup_until(lp); 1454 return; 1455 } 1456 1457 #ifdef NLS_CATALOGS 1458 if (eq(vp, STRNLSPATH)) { 1459 nlsclose(); 1460 nlsinit(); 1461 } 1462 #endif 1463 1464 if (eq(vp, STRNOREBIND)) { 1465 NoNLSRebind = 1; 1466 MapsAreInited = 0; 1467 NLSMapsAreInited = 0; 1468 ed_InitMaps(); 1469 cleanup_until(lp); 1470 return; 1471 } 1472 #ifdef WINNT_NATIVE 1473 if (eq(vp, STRtcshlang)) { 1474 nlsinit(); 1475 cleanup_until(lp); 1476 return; 1477 } 1478 #endif /* WINNT_NATIVE */ 1479 if (eq(vp, STRKTERM)) { 1480 char *t; 1481 1482 setv(STRterm, quote(lp), VAR_READWRITE); /* lp memory used here */ 1483 cleanup_ignore(lp); 1484 cleanup_until(lp); 1485 t = short2str(lp); 1486 if (noediting && strcmp(t, "unknown") != 0 && strcmp(t,"dumb") != 0) { 1487 editing = 1; 1488 noediting = 0; 1489 setNS(STRedit); 1490 } 1491 GotTermCaps = 0; 1492 ed_Init(); 1493 return; 1494 } 1495 1496 if (eq(vp, STRKHOME)) { 1497 Char *canon; 1498 /* 1499 * convert to canonical pathname (possibly resolving symlinks) 1500 */ 1501 canon = dcanon(lp, lp); 1502 cleanup_ignore(lp); 1503 cleanup_until(lp); 1504 cleanup_push(canon, xfree); 1505 setv(STRhome, quote(canon), VAR_READWRITE); /* lp memory used here */ 1506 cleanup_ignore(canon); 1507 cleanup_until(canon); 1508 1509 /* fix directory stack for new tilde home */ 1510 dtilde(); 1511 return; 1512 } 1513 1514 if (eq(vp, STRKSHLVL)) { 1515 setv(STRshlvl, quote(lp), VAR_READWRITE); /* lp memory used here */ 1516 cleanup_ignore(lp); 1517 cleanup_until(lp); 1518 return; 1519 } 1520 1521 if (eq(vp, STRKUSER)) { 1522 setv(STRuser, quote(lp), VAR_READWRITE); /* lp memory used here */ 1523 cleanup_ignore(lp); 1524 cleanup_until(lp); 1525 return; 1526 } 1527 1528 if (eq(vp, STRKGROUP)) { 1529 setv(STRgroup, quote(lp), VAR_READWRITE); /* lp memory used here */ 1530 cleanup_ignore(lp); 1531 cleanup_until(lp); 1532 return; 1533 } 1534 1535 #ifdef COLOR_LS_F 1536 if (eq(vp, STRLS_COLORS)) { 1537 parseLS_COLORS(lp); 1538 cleanup_until(lp); 1539 return; 1540 } 1541 #endif /* COLOR_LS_F */ 1542 1543 #ifdef SIG_WINDOW 1544 /* 1545 * Load/Update $LINES $COLUMNS 1546 */ 1547 if ((eq(lp, STRNULL) && (eq(vp, STRLINES) || eq(vp, STRCOLUMNS))) || 1548 eq(vp, STRTERMCAP)) { 1549 cleanup_until(lp); 1550 check_window_size(1); 1551 return; 1552 } 1553 1554 /* 1555 * Change the size to the one directed by $LINES and $COLUMNS 1556 */ 1557 if (eq(vp, STRLINES) || eq(vp, STRCOLUMNS)) { 1558 #if 0 1559 GotTermCaps = 0; 1560 #endif 1561 cleanup_until(lp); 1562 ed_Init(); 1563 return; 1564 } 1565 #endif /* SIG_WINDOW */ 1566 cleanup_until(lp); 1567 } 1568 1569 /*ARGSUSED*/ 1570 void 1571 dounsetenv(Char **v, struct command *c) 1572 { 1573 Char **ep, *p, *n, *name; 1574 int i, maxi; 1575 1576 USE(c); 1577 /* 1578 * Find the longest environment variable 1579 */ 1580 for (maxi = 0, ep = STR_environ; *ep; ep++) { 1581 for (i = 0, p = *ep; *p && *p != '='; p++, i++) 1582 continue; 1583 if (i > maxi) 1584 maxi = i; 1585 } 1586 1587 name = xmalloc((maxi + 1) * sizeof(Char)); 1588 cleanup_push(name, xfree); 1589 1590 while (++v && *v) 1591 for (maxi = 1; maxi;) 1592 for (maxi = 0, ep = STR_environ; *ep; ep++) { 1593 for (n = name, p = *ep; *p && *p != '='; *n++ = *p++) 1594 continue; 1595 *n = '\0'; 1596 if (!Gmatch(name, *v)) 1597 continue; 1598 maxi = 1; 1599 1600 /* Unset the name. This wasn't being done until 1601 * later but most of the stuff following won't 1602 * work (particularly the setlocale() and getenv() 1603 * stuff) as intended until the name is actually 1604 * removed. (sg) 1605 */ 1606 Unsetenv(name); 1607 1608 if (eq(name, STRNOREBIND)) { 1609 NoNLSRebind = 0; 1610 MapsAreInited = 0; 1611 NLSMapsAreInited = 0; 1612 ed_InitMaps(); 1613 } 1614 #ifdef apollo 1615 else if (eq(name, STRSYSTYPE)) 1616 dohash(NULL, NULL); 1617 #endif /* apollo */ 1618 else if (islocale_var(name)) { 1619 #ifdef NLS 1620 int k; 1621 1622 # ifdef SETLOCALEBUG 1623 dont_free = 1; 1624 # endif /* SETLOCALEBUG */ 1625 (void) setlocale(LC_ALL, ""); 1626 # ifdef LC_COLLATE 1627 (void) setlocale(LC_COLLATE, ""); 1628 # endif 1629 # ifdef LC_CTYPE 1630 (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 1631 # endif /* LC_CTYPE */ 1632 # ifdef NLS_CATALOGS 1633 # ifdef LC_MESSAGES 1634 (void) setlocale(LC_MESSAGES, ""); 1635 # endif /* LC_MESSAGES */ 1636 nlsclose(); 1637 nlsinit(); 1638 # endif /* NLS_CATALOGS */ 1639 # ifdef SETLOCALEBUG 1640 dont_free = 0; 1641 # endif /* SETLOCALEBUG */ 1642 # ifdef STRCOLLBUG 1643 fix_strcoll_bug(); 1644 # endif /* STRCOLLBUG */ 1645 tw_cmd_free();/* since the collation sequence has changed */ 1646 for (k = 0200; k <= 0377 && !Isprint(CTL_ESC(k)); k++) 1647 continue; 1648 AsciiOnly = MB_CUR_MAX == 1 && k > 0377; 1649 #else /* !NLS */ 1650 AsciiOnly = getenv("LANG") == NULL && 1651 getenv("LC_CTYPE") == NULL; 1652 #endif /* NLS */ 1653 NLSMapsAreInited = 0; 1654 ed_Init(); 1655 if (MapsAreInited && !NLSMapsAreInited) 1656 ed_InitNLSMaps(); 1657 1658 } 1659 #ifdef WINNT_NATIVE 1660 else if (eq(name,(STRtcshlang))) { 1661 nls_dll_unload(); 1662 nlsinit(); 1663 } 1664 #endif /* WINNT_NATIVE */ 1665 #ifdef COLOR_LS_F 1666 else if (eq(name, STRLS_COLORS)) 1667 parseLS_COLORS(n); 1668 #endif /* COLOR_LS_F */ 1669 #ifdef NLS_CATALOGS 1670 else if (eq(name, STRNLSPATH)) { 1671 nlsclose(); 1672 nlsinit(); 1673 } 1674 #endif 1675 /* 1676 * start again cause the environment changes 1677 */ 1678 break; 1679 } 1680 cleanup_until(name); 1681 } 1682 1683 void 1684 tsetenv(const Char *name, const Char *val) 1685 { 1686 #ifdef SETENV_IN_LIB 1687 /* 1688 * XXX: This does not work right, since tcsh cannot track changes to 1689 * the environment this way. (the builtin setenv without arguments does 1690 * not print the right stuff neither does unsetenv). This was for Mach, 1691 * it is not needed anymore. 1692 */ 1693 #undef setenv 1694 char *cname; 1695 1696 if (name == NULL) 1697 return; 1698 cname = strsave(short2str(name)); 1699 setenv(cname, short2str(val), 1); 1700 xfree(cname); 1701 #else /* !SETENV_IN_LIB */ 1702 Char **ep = STR_environ; 1703 const Char *ccp; 1704 Char *cp, *dp; 1705 Char *blk[2]; 1706 Char **oep = ep; 1707 1708 #ifdef WINNT_NATIVE 1709 nt_set_env(name,val); 1710 #endif /* WINNT_NATIVE */ 1711 for (; *ep; ep++) { 1712 #ifdef WINNT_NATIVE 1713 for (ccp = name, dp = *ep; *ccp && Tolower(*ccp & TRIM) == Tolower(*dp); 1714 ccp++, dp++) 1715 #else 1716 for (ccp = name, dp = *ep; *ccp && (*ccp & TRIM) == *dp; ccp++, dp++) 1717 #endif /* WINNT_NATIVE */ 1718 continue; 1719 if (*ccp != 0 || *dp != '=') 1720 continue; 1721 cp = Strspl(STRequal, val); 1722 xfree(*ep); 1723 *ep = strip(Strspl(name, cp)); 1724 xfree(cp); 1725 blkfree((Char **) environ); 1726 environ = short2blk(STR_environ); 1727 return; 1728 } 1729 cp = Strspl(name, STRequal); 1730 blk[0] = strip(Strspl(cp, val)); 1731 xfree(cp); 1732 blk[1] = 0; 1733 STR_environ = blkspl(STR_environ, blk); 1734 blkfree((Char **) environ); 1735 environ = short2blk(STR_environ); 1736 xfree(oep); 1737 #endif /* SETENV_IN_LIB */ 1738 } 1739 1740 void 1741 Unsetenv(Char *name) 1742 { 1743 Char **ep = STR_environ; 1744 Char *cp, *dp; 1745 Char **oep = ep; 1746 1747 #ifdef WINNT_NATIVE 1748 nt_set_env(name,NULL); 1749 #endif /*WINNT_NATIVE */ 1750 for (; *ep; ep++) { 1751 for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) 1752 continue; 1753 if (*cp != 0 || *dp != '=') 1754 continue; 1755 cp = *ep; 1756 *ep = 0; 1757 STR_environ = blkspl(STR_environ, ep + 1); 1758 blkfree((Char **) environ); 1759 environ = short2blk(STR_environ); 1760 *ep = cp; 1761 xfree(cp); 1762 xfree(oep); 1763 return; 1764 } 1765 } 1766 1767 /*ARGSUSED*/ 1768 void 1769 doumask(Char **v, struct command *c) 1770 { 1771 Char *cp = v[1]; 1772 int i; 1773 1774 USE(c); 1775 if (cp == 0) { 1776 i = (int)umask(0); 1777 (void) umask(i); 1778 xprintf("%o\n", i); 1779 return; 1780 } 1781 i = 0; 1782 while (Isdigit(*cp) && *cp != '8' && *cp != '9') 1783 i = i * 8 + *cp++ - '0'; 1784 if (*cp || i < 0 || i > 0777) 1785 stderror(ERR_NAME | ERR_MASK); 1786 (void) umask(i); 1787 } 1788 1789 #ifndef HAVENOLIMIT 1790 # ifndef BSDLIMIT 1791 typedef long RLIM_TYPE; 1792 # ifdef _OSD_POSIX /* BS2000 */ 1793 # include <ulimit.h> 1794 # endif 1795 # ifndef RLIM_INFINITY 1796 # if !defined(_MINIX) && !defined(__clipper__) && !defined(_CRAY) 1797 extern RLIM_TYPE ulimit(); 1798 # endif /* ! _MINIX && !__clipper__ */ 1799 # define RLIM_INFINITY 0x003fffff 1800 # define RLIMIT_FSIZE 1 1801 # endif /* RLIM_INFINITY */ 1802 # ifdef aiws 1803 # define toset(a) (((a) == 3) ? 1004 : (a) + 1) 1804 # define RLIMIT_DATA 3 1805 # define RLIMIT_STACK 1005 1806 # else /* aiws */ 1807 # define toset(a) ((a) + 1) 1808 # endif /* aiws */ 1809 # else /* BSDLIMIT */ 1810 # if (defined(BSD4_4) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) || (HPUXVERSION >= 1100)) && !defined(__386BSD__) 1811 typedef rlim_t RLIM_TYPE; 1812 # else 1813 # if defined(SOLARIS2) || (defined(sgi) && SYSVREL > 3) 1814 typedef rlim_t RLIM_TYPE; 1815 # else 1816 # if defined(_SX) 1817 typedef long long RLIM_TYPE; 1818 # else /* !_SX */ 1819 typedef unsigned long RLIM_TYPE; 1820 # endif /* _SX */ 1821 # endif /* SOLARIS2 || (sgi && SYSVREL > 3) */ 1822 # endif /* BSD4_4 && !__386BSD__ */ 1823 # endif /* BSDLIMIT */ 1824 1825 # if (HPUXVERSION > 700) && (HPUXVERSION < 1100) && defined(BSDLIMIT) 1826 /* Yes hpux8.0 has limits but <sys/resource.h> does not make them public */ 1827 /* Yes, we could have defined _KERNEL, and -I/etc/conf/h, but is that better? */ 1828 # ifndef RLIMIT_CPU 1829 # define RLIMIT_CPU 0 1830 # define RLIMIT_FSIZE 1 1831 # define RLIMIT_DATA 2 1832 # define RLIMIT_STACK 3 1833 # define RLIMIT_CORE 4 1834 # define RLIMIT_RSS 5 1835 # define RLIMIT_NOFILE 6 1836 # endif /* RLIMIT_CPU */ 1837 # ifndef RLIM_INFINITY 1838 # define RLIM_INFINITY 0x7fffffff 1839 # endif /* RLIM_INFINITY */ 1840 /* 1841 * old versions of HP/UX counted limits in 512 bytes 1842 */ 1843 # ifndef SIGRTMIN 1844 # define FILESIZE512 1845 # endif /* SIGRTMIN */ 1846 # endif /* (HPUXVERSION > 700) && (HPUXVERSION < 1100) && BSDLIMIT */ 1847 1848 # if SYSVREL > 3 && defined(BSDLIMIT) && !defined(_SX) 1849 /* In order to use rusage, we included "/usr/ucbinclude/sys/resource.h" in */ 1850 /* sh.h. However, some SVR4 limits are defined in <sys/resource.h>. Rather */ 1851 /* than include both and get warnings, we define the extra SVR4 limits here. */ 1852 /* XXX: I don't understand if RLIMIT_AS is defined, why don't we define */ 1853 /* RLIMIT_VMEM based on it? */ 1854 # ifndef RLIMIT_VMEM 1855 # define RLIMIT_VMEM 6 1856 # endif 1857 # ifndef RLIMIT_AS 1858 # define RLIMIT_AS RLIMIT_VMEM 1859 # endif 1860 # endif /* SYSVREL > 3 && BSDLIMIT */ 1861 1862 # if (defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) && defined(RLIMIT_AS) && !defined(RLIMIT_VMEM) 1863 # define RLIMIT_VMEM RLIMIT_AS 1864 # endif 1865 1866 struct limits limits[] = 1867 { 1868 # ifdef RLIMIT_CPU 1869 { RLIMIT_CPU, "cputime", 1, "seconds" }, 1870 # endif /* RLIMIT_CPU */ 1871 1872 # ifdef RLIMIT_FSIZE 1873 # ifndef aiws 1874 { RLIMIT_FSIZE, "filesize", 1024, "kbytes" }, 1875 # else 1876 { RLIMIT_FSIZE, "filesize", 512, "blocks" }, 1877 # endif /* aiws */ 1878 # endif /* RLIMIT_FSIZE */ 1879 1880 # ifdef RLIMIT_DATA 1881 { RLIMIT_DATA, "datasize", 1024, "kbytes" }, 1882 # endif /* RLIMIT_DATA */ 1883 1884 # ifdef RLIMIT_STACK 1885 # ifndef aiws 1886 { RLIMIT_STACK, "stacksize", 1024, "kbytes" }, 1887 # else 1888 { RLIMIT_STACK, "stacksize", 1024 * 1024, "kbytes"}, 1889 # endif /* aiws */ 1890 # endif /* RLIMIT_STACK */ 1891 1892 # ifdef RLIMIT_CORE 1893 { RLIMIT_CORE, "coredumpsize", 1024, "kbytes" }, 1894 # endif /* RLIMIT_CORE */ 1895 1896 # ifdef RLIMIT_RSS 1897 { RLIMIT_RSS, "memoryuse", 1024, "kbytes" }, 1898 # endif /* RLIMIT_RSS */ 1899 1900 # ifdef RLIMIT_UMEM 1901 { RLIMIT_UMEM, "memoryuse", 1024, "kbytes" }, 1902 # endif /* RLIMIT_UMEM */ 1903 1904 # ifdef RLIMIT_VMEM 1905 { RLIMIT_VMEM, "vmemoryuse", 1024, "kbytes" }, 1906 # endif /* RLIMIT_VMEM */ 1907 1908 # if defined(RLIMIT_HEAP) /* found on BS2000/OSD systems */ 1909 { RLIMIT_HEAP, "heapsize", 1024, "kbytes" }, 1910 # endif /* RLIMIT_HEAP */ 1911 1912 # ifdef RLIMIT_NOFILE 1913 { RLIMIT_NOFILE, "descriptors", 1, "" }, 1914 # endif /* RLIMIT_NOFILE */ 1915 1916 # ifdef RLIMIT_CONCUR 1917 { RLIMIT_CONCUR, "concurrency", 1, "thread(s)" }, 1918 # endif /* RLIMIT_CONCUR */ 1919 1920 # ifdef RLIMIT_MEMLOCK 1921 { RLIMIT_MEMLOCK, "memorylocked", 1024, "kbytes" }, 1922 # endif /* RLIMIT_MEMLOCK */ 1923 1924 # ifdef RLIMIT_NPROC 1925 { RLIMIT_NPROC, "maxproc", 1, "" }, 1926 # endif /* RLIMIT_NPROC */ 1927 1928 # if defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE) 1929 { RLIMIT_OFILE, "openfiles", 1, "" }, 1930 # endif /* RLIMIT_OFILE && !defined(RLIMIT_NOFILE) */ 1931 1932 # ifdef RLIMIT_SBSIZE 1933 { RLIMIT_SBSIZE, "sbsize", 1, "" }, 1934 # endif /* RLIMIT_SBSIZE */ 1935 1936 #ifdef RLIMIT_POSIXLOCKS 1937 { RLIMIT_POSIXLOCKS, "posixlocks", 1, "" }, 1938 #endif /* RLIMIT_POSIXLOCKS */ 1939 1940 # ifdef RLIMIT_SWAP 1941 { RLIMIT_SWAP, "swapsize", 1024, "kbytes" }, 1942 # endif /* RLIMIT_SWAP */ 1943 1944 { -1, NULL, 0, NULL } 1945 }; 1946 1947 static struct limits *findlim (Char *); 1948 static RLIM_TYPE getval (struct limits *, Char **); 1949 static void limtail (Char *, const char *); 1950 static void plim (struct limits *, int); 1951 static int setlim (struct limits *, int, RLIM_TYPE); 1952 1953 #ifdef convex 1954 static RLIM_TYPE 1955 restrict_limit(double value) 1956 { 1957 /* 1958 * is f too large to cope with? return the maximum or minimum int 1959 */ 1960 if (value > (double) INT_MAX) 1961 return (RLIM_TYPE) INT_MAX; 1962 else if (value < (double) INT_MIN) 1963 return (RLIM_TYPE) INT_MIN; 1964 else 1965 return (RLIM_TYPE) value; 1966 } 1967 #else /* !convex */ 1968 # define restrict_limit(x) ((RLIM_TYPE) (x)) 1969 #endif /* convex */ 1970 1971 1972 static struct limits * 1973 findlim(Char *cp) 1974 { 1975 struct limits *lp, *res; 1976 1977 res = NULL; 1978 for (lp = limits; lp->limconst >= 0; lp++) 1979 if (prefix(cp, str2short(lp->limname))) { 1980 if (res) 1981 stderror(ERR_NAME | ERR_AMBIG); 1982 res = lp; 1983 } 1984 if (res) 1985 return (res); 1986 stderror(ERR_NAME | ERR_LIMIT); 1987 /* NOTREACHED */ 1988 return (0); 1989 } 1990 1991 /*ARGSUSED*/ 1992 void 1993 dolimit(Char **v, struct command *c) 1994 { 1995 struct limits *lp; 1996 RLIM_TYPE limit; 1997 int hard = 0; 1998 1999 USE(c); 2000 v++; 2001 if (*v && eq(*v, STRmh)) { 2002 hard = 1; 2003 v++; 2004 } 2005 if (*v == 0) { 2006 for (lp = limits; lp->limconst >= 0; lp++) 2007 plim(lp, hard); 2008 return; 2009 } 2010 lp = findlim(v[0]); 2011 if (v[1] == 0) { 2012 plim(lp, hard); 2013 return; 2014 } 2015 limit = getval(lp, v + 1); 2016 if (setlim(lp, hard, limit) < 0) 2017 stderror(ERR_SILENT); 2018 } 2019 2020 static RLIM_TYPE 2021 getval(struct limits *lp, Char **v) 2022 { 2023 float f; 2024 Char *cp = *v++; 2025 2026 f = atof(short2str(cp)); 2027 2028 # ifdef convex 2029 /* 2030 * is f too large to cope with. limit f to minint, maxint - X-6768 by 2031 * strike 2032 */ 2033 if ((f < (double) INT_MIN) || (f > (double) INT_MAX)) { 2034 stderror(ERR_NAME | ERR_TOOLARGE); 2035 } 2036 # endif /* convex */ 2037 2038 while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') 2039 cp++; 2040 if (*cp == 0) { 2041 if (*v == 0) 2042 return restrict_limit((f * lp->limdiv) + 0.5); 2043 cp = *v; 2044 } 2045 switch (*cp) { 2046 # ifdef RLIMIT_CPU 2047 case ':': 2048 if (lp->limconst != RLIMIT_CPU) 2049 goto badscal; 2050 return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f * 60.0 + atof(short2str(cp + 1)))); 2051 case 'h': 2052 if (lp->limconst != RLIMIT_CPU) 2053 goto badscal; 2054 limtail(cp, "hours"); 2055 f *= 3600.0; 2056 break; 2057 case 'm': 2058 if (lp->limconst == RLIMIT_CPU) { 2059 limtail(cp, "minutes"); 2060 f *= 60.0; 2061 break; 2062 } 2063 *cp = 'm'; 2064 limtail(cp, "megabytes"); 2065 f *= 1024.0 * 1024.0; 2066 break; 2067 case 's': 2068 if (lp->limconst != RLIMIT_CPU) 2069 goto badscal; 2070 limtail(cp, "seconds"); 2071 break; 2072 # endif /* RLIMIT_CPU */ 2073 case 'M': 2074 # ifdef RLIMIT_CPU 2075 if (lp->limconst == RLIMIT_CPU) 2076 goto badscal; 2077 # endif /* RLIMIT_CPU */ 2078 *cp = 'm'; 2079 limtail(cp, "megabytes"); 2080 f *= 1024.0 * 1024.0; 2081 break; 2082 case 'k': 2083 # ifdef RLIMIT_CPU 2084 if (lp->limconst == RLIMIT_CPU) 2085 goto badscal; 2086 # endif /* RLIMIT_CPU */ 2087 limtail(cp, "kbytes"); 2088 f *= 1024.0; 2089 break; 2090 case 'b': 2091 # ifdef RLIMIT_CPU 2092 if (lp->limconst == RLIMIT_CPU) 2093 goto badscal; 2094 # endif /* RLIMIT_CPU */ 2095 limtail(cp, "blocks"); 2096 f *= 512.0; 2097 break; 2098 case 'u': 2099 limtail(cp, "unlimited"); 2100 return ((RLIM_TYPE) RLIM_INFINITY); 2101 default: 2102 # ifdef RLIMIT_CPU 2103 badscal: 2104 # endif /* RLIMIT_CPU */ 2105 stderror(ERR_NAME | ERR_SCALEF); 2106 } 2107 # ifdef convex 2108 return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f + 0.5)); 2109 # else 2110 f += 0.5; 2111 if (f > (float) RLIM_INFINITY) 2112 return ((RLIM_TYPE) RLIM_INFINITY); 2113 else 2114 return ((RLIM_TYPE) f); 2115 # endif /* convex */ 2116 } 2117 2118 static void 2119 limtail(Char *cp, const char *str) 2120 { 2121 const char *sp; 2122 2123 sp = str; 2124 while (*cp && *cp == (Char)*str) 2125 cp++, str++; 2126 if (*cp) 2127 stderror(ERR_BADSCALE, sp); 2128 } 2129 2130 2131 /*ARGSUSED*/ 2132 static void 2133 plim(struct limits *lp, int hard) 2134 { 2135 # ifdef BSDLIMIT 2136 struct rlimit rlim; 2137 # endif /* BSDLIMIT */ 2138 RLIM_TYPE limit; 2139 int xdiv = lp->limdiv; 2140 2141 xprintf("%-13.13s", lp->limname); 2142 2143 # ifndef BSDLIMIT 2144 limit = ulimit(lp->limconst, 0); 2145 # ifdef aiws 2146 if (lp->limconst == RLIMIT_DATA) 2147 limit -= 0x20000000; 2148 # endif /* aiws */ 2149 # else /* BSDLIMIT */ 2150 (void) getrlimit(lp->limconst, &rlim); 2151 limit = hard ? rlim.rlim_max : rlim.rlim_cur; 2152 # endif /* BSDLIMIT */ 2153 2154 # if !defined(BSDLIMIT) || defined(FILESIZE512) 2155 /* 2156 * Christos: filesize comes in 512 blocks. we divide by 2 to get 1024 2157 * blocks. Note we cannot pre-multiply cause we might overflow (A/UX) 2158 */ 2159 if (lp->limconst == RLIMIT_FSIZE) { 2160 if (limit >= (RLIM_INFINITY / 512)) 2161 limit = RLIM_INFINITY; 2162 else 2163 xdiv = (xdiv == 1024 ? 2 : 1); 2164 } 2165 # endif /* !BSDLIMIT || FILESIZE512 */ 2166 2167 if (limit == RLIM_INFINITY) 2168 xprintf("unlimited"); 2169 else 2170 # if defined(RLIMIT_CPU) && defined(_OSD_POSIX) 2171 if (lp->limconst == RLIMIT_CPU && 2172 (unsigned long)limit >= 0x7ffffffdUL) 2173 xprintf("unlimited"); 2174 else 2175 # endif 2176 # ifdef RLIMIT_CPU 2177 if (lp->limconst == RLIMIT_CPU) 2178 psecs(limit); 2179 else 2180 # endif /* RLIMIT_CPU */ 2181 xprintf("%ld %s", (long) (limit / xdiv), lp->limscale); 2182 xputchar('\n'); 2183 } 2184 2185 /*ARGSUSED*/ 2186 void 2187 dounlimit(Char **v, struct command *c) 2188 { 2189 struct limits *lp; 2190 int lerr = 0; 2191 int hard = 0; 2192 int force = 0; 2193 2194 USE(c); 2195 while (*++v && **v == '-') { 2196 Char *vp = *v; 2197 while (*++vp) 2198 switch (*vp) { 2199 case 'f': 2200 force = 1; 2201 break; 2202 case 'h': 2203 hard = 1; 2204 break; 2205 default: 2206 stderror(ERR_ULIMUS); 2207 break; 2208 } 2209 } 2210 2211 if (*v == 0) { 2212 for (lp = limits; lp->limconst >= 0; lp++) 2213 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0) 2214 lerr++; 2215 if (!force && lerr) 2216 stderror(ERR_SILENT); 2217 return; 2218 } 2219 while (*v) { 2220 lp = findlim(*v++); 2221 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0 && !force) 2222 stderror(ERR_SILENT); 2223 } 2224 } 2225 2226 static int 2227 setlim(struct limits *lp, int hard, RLIM_TYPE limit) 2228 { 2229 # ifdef BSDLIMIT 2230 struct rlimit rlim; 2231 2232 (void) getrlimit(lp->limconst, &rlim); 2233 2234 # ifdef FILESIZE512 2235 /* Even though hpux has setrlimit(), it expects fsize in 512 byte blocks */ 2236 if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 2237 limit /= 512; 2238 # endif /* FILESIZE512 */ 2239 if (hard) 2240 rlim.rlim_max = limit; 2241 else if (limit == RLIM_INFINITY && euid != 0) 2242 rlim.rlim_cur = rlim.rlim_max; 2243 else 2244 rlim.rlim_cur = limit; 2245 2246 if (rlim.rlim_cur > rlim.rlim_max) 2247 rlim.rlim_max = rlim.rlim_cur; 2248 2249 if (setrlimit(lp->limconst, &rlim) < 0) { 2250 # else /* BSDLIMIT */ 2251 if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 2252 limit /= 512; 2253 # ifdef aiws 2254 if (lp->limconst == RLIMIT_DATA) 2255 limit += 0x20000000; 2256 # endif /* aiws */ 2257 if (ulimit(toset(lp->limconst), limit) < 0) { 2258 # endif /* BSDLIMIT */ 2259 int err; 2260 char *op, *type; 2261 2262 err = errno; 2263 op = strsave(limit == RLIM_INFINITY ? CGETS(15, 2, "remove") : 2264 CGETS(15, 3, "set")); 2265 cleanup_push(op, xfree); 2266 type = strsave(hard ? CGETS(15, 4, " hard") : ""); 2267 cleanup_push(type, xfree); 2268 xprintf(CGETS(15, 1, "%s: %s: Can't %s%s limit (%s)\n"), bname, 2269 lp->limname, op, type, strerror(err)); 2270 cleanup_until(op); 2271 return (-1); 2272 } 2273 return (0); 2274 } 2275 2276 #endif /* !HAVENOLIMIT */ 2277 2278 /*ARGSUSED*/ 2279 void 2280 dosuspend(Char **v, struct command *c) 2281 { 2282 #ifdef BSDJOBS 2283 struct sigaction old; 2284 #endif /* BSDJOBS */ 2285 2286 USE(c); 2287 USE(v); 2288 2289 if (loginsh) 2290 stderror(ERR_SUSPLOG); 2291 untty(); 2292 2293 #ifdef BSDJOBS 2294 sigaction(SIGTSTP, NULL, &old); 2295 signal(SIGTSTP, SIG_DFL); 2296 (void) kill(0, SIGTSTP); 2297 /* the shell stops here */ 2298 sigaction(SIGTSTP, &old, NULL); 2299 #else /* !BSDJOBS */ 2300 stderror(ERR_JOBCONTROL); 2301 #endif /* BSDJOBS */ 2302 2303 #ifdef BSDJOBS 2304 if (tpgrp != -1) { 2305 if (grabpgrp(FSHTTY, opgrp) == -1) 2306 stderror(ERR_SYSTEM, "tcgetpgrp", strerror(errno)); 2307 (void) setpgid(0, shpgrp); 2308 (void) tcsetpgrp(FSHTTY, shpgrp); 2309 } 2310 #endif /* BSDJOBS */ 2311 (void) setdisc(FSHTTY); 2312 } 2313 2314 /* This is the dreaded EVAL built-in. 2315 * If you don't fiddle with file descriptors, and reset didfds, 2316 * this command will either ignore redirection inside or outside 2317 * its arguments, e.g. eval "date >x" vs. eval "date" >x 2318 * The stuff here seems to work, but I did it by trial and error rather 2319 * than really knowing what was going on. If tpgrp is zero, we are 2320 * probably a background eval, e.g. "eval date &", and we want to 2321 * make sure that any processes we start stay in our pgrp. 2322 * This is also the case for "time eval date" -- stay in same pgrp. 2323 * Otherwise, under stty tostop, processes will stop in the wrong 2324 * pgrp, with no way for the shell to get them going again. -IAN! 2325 */ 2326 2327 struct doeval_state 2328 { 2329 Char **evalvec, *evalp; 2330 int didfds; 2331 #ifndef CLOSE_ON_EXEC 2332 int didcch; 2333 #endif 2334 int saveIN, saveOUT, saveDIAG; 2335 int SHIN, SHOUT, SHDIAG; 2336 }; 2337 2338 static void 2339 doeval_cleanup(void *xstate) 2340 { 2341 struct doeval_state *state; 2342 2343 state = xstate; 2344 evalvec = state->evalvec; 2345 evalp = state->evalp; 2346 doneinp = 0; 2347 #ifndef CLOSE_ON_EXEC 2348 didcch = state->didcch; 2349 #endif /* CLOSE_ON_EXEC */ 2350 didfds = state->didfds; 2351 xclose(SHIN); 2352 xclose(SHOUT); 2353 xclose(SHDIAG); 2354 close_on_exec(SHIN = dmove(state->saveIN, state->SHIN), 1); 2355 close_on_exec(SHOUT = dmove(state->saveOUT, state->SHOUT), 1); 2356 close_on_exec(SHDIAG = dmove(state->saveDIAG, state->SHDIAG), 1); 2357 } 2358 2359 static Char **Ggv; 2360 /*ARGSUSED*/ 2361 void 2362 doeval(Char **v, struct command *c) 2363 { 2364 struct doeval_state state; 2365 int gflag, my_reenter; 2366 Char **gv; 2367 jmp_buf_t osetexit; 2368 2369 USE(c); 2370 v++; 2371 if (*v == 0) 2372 return; 2373 gflag = tglob(v); 2374 if (gflag) { 2375 gv = v = globall(v, gflag); 2376 if (v == 0) 2377 stderror(ERR_NOMATCH); 2378 cleanup_push(gv, blk_cleanup); 2379 v = copyblk(v); 2380 } 2381 else { 2382 gv = NULL; 2383 v = copyblk(v); 2384 trim(v); 2385 } 2386 2387 Ggv = gv; 2388 state.evalvec = evalvec; 2389 state.evalp = evalp; 2390 state.didfds = didfds; 2391 #ifndef CLOSE_ON_EXEC 2392 state.didcch = didcch; 2393 #endif /* CLOSE_ON_EXEC */ 2394 state.SHIN = SHIN; 2395 state.SHOUT = SHOUT; 2396 state.SHDIAG = SHDIAG; 2397 2398 (void)close_on_exec(state.saveIN = dcopy(SHIN, -1), 1); 2399 (void)close_on_exec(state.saveOUT = dcopy(SHOUT, -1), 1); 2400 (void)close_on_exec(state.saveDIAG = dcopy(SHDIAG, -1), 1); 2401 2402 cleanup_push(&state, doeval_cleanup); 2403 2404 getexit(osetexit); 2405 2406 /* PWP: setjmp/longjmp bugfix for optimizing compilers */ 2407 #ifdef cray 2408 my_reenter = 1; /* assume non-zero return val */ 2409 if (setexit() == 0) { 2410 my_reenter = 0; /* Oh well, we were wrong */ 2411 #else /* !cray */ 2412 if ((my_reenter = setexit()) == 0) { 2413 #endif /* cray */ 2414 evalvec = v; 2415 evalp = 0; 2416 (void)close_on_exec(SHIN = dcopy(0, -1), 1); 2417 (void)close_on_exec(SHOUT = dcopy(1, -1), 1); 2418 (void)close_on_exec(SHDIAG = dcopy(2, -1), 1); 2419 #ifndef CLOSE_ON_EXEC 2420 didcch = 0; 2421 #endif /* CLOSE_ON_EXEC */ 2422 didfds = 0; 2423 gv = Ggv; 2424 process(0); 2425 Ggv = gv; 2426 } 2427 2428 if (my_reenter == 0) { 2429 cleanup_until(&state); 2430 if (Ggv) 2431 cleanup_until(Ggv); 2432 } 2433 2434 resexit(osetexit); 2435 if (my_reenter) 2436 stderror(ERR_SILENT); 2437 } 2438 2439 /*************************************************************************/ 2440 /* print list of builtin commands */ 2441 2442 static void 2443 lbuffed_cleanup (void *dummy) 2444 { 2445 USE(dummy); 2446 lbuffed = 1; 2447 } 2448 2449 /*ARGSUSED*/ 2450 void 2451 dobuiltins(Char **v, struct command *c) 2452 { 2453 /* would use print_by_column() in tw.parse.c but that assumes 2454 * we have an array of Char * to pass.. (sg) 2455 */ 2456 const struct biltins *b; 2457 int row, col, columns, rows; 2458 unsigned int w, maxwidth; 2459 2460 USE(c); 2461 USE(v); 2462 lbuffed = 0; /* turn off line buffering */ 2463 cleanup_push(&lbuffed, lbuffed_cleanup); 2464 2465 /* find widest string */ 2466 for (maxwidth = 0, b = bfunc; b < &bfunc[nbfunc]; ++b) 2467 maxwidth = max(maxwidth, strlen(b->bname)); 2468 ++maxwidth; /* for space */ 2469 2470 columns = (TermH + 1) / maxwidth; /* PWP: terminal size change */ 2471 if (!columns) 2472 columns = 1; 2473 rows = (nbfunc + (columns - 1)) / columns; 2474 2475 for (b = bfunc, row = 0; row < rows; row++) { 2476 for (col = 0; col < columns; col++) { 2477 if (b < &bfunc[nbfunc]) { 2478 w = strlen(b->bname); 2479 xprintf("%s", b->bname); 2480 if (col < (columns - 1)) /* Not last column? */ 2481 for (; w < maxwidth; w++) 2482 xputchar(' '); 2483 ++b; 2484 } 2485 } 2486 if (row < (rows - 1)) { 2487 if (Tty_raw_mode) 2488 xputchar('\r'); 2489 xputchar('\n'); 2490 } 2491 } 2492 #ifdef WINNT_NATIVE 2493 nt_print_builtins(maxwidth); 2494 #else 2495 if (Tty_raw_mode) 2496 xputchar('\r'); 2497 xputchar('\n'); 2498 #endif /* WINNT_NATIVE */ 2499 2500 cleanup_until(&lbuffed); /* turn back on line buffering */ 2501 flush(); 2502 } 2503 2504 #ifdef NLS_CATALOGS 2505 char * 2506 xcatgets(nl_catd ctd, int set_id, int msg_id, const char *s) 2507 { 2508 char *res; 2509 2510 errno = 0; 2511 while ((res = catgets(ctd, set_id, msg_id, s)) == s && errno == EINTR) { 2512 handle_pending_signals(); 2513 errno = 0; 2514 } 2515 return res; 2516 } 2517 2518 2519 # if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2520 char * 2521 iconv_catgets(nl_catd ctd, int set_id, int msg_id, const char *s) 2522 { 2523 static char *buf = NULL; 2524 static size_t buf_size = 0; 2525 2526 char *orig, *dest, *p; 2527 ICONV_CONST char *src; 2528 size_t src_size, dest_size; 2529 2530 orig = xcatgets(ctd, set_id, msg_id, s); 2531 if (catgets_iconv == (iconv_t)-1 || orig == s) 2532 return orig; 2533 src = orig; 2534 src_size = strlen(src) + 1; 2535 if (buf == NULL && (buf = xmalloc(buf_size = src_size + 32)) == NULL) 2536 return orig; 2537 dest = buf; 2538 while (src_size != 0) { 2539 dest_size = buf + buf_size - dest; 2540 if (iconv(catgets_iconv, &src, &src_size, &dest, &dest_size) 2541 == (size_t)-1) { 2542 switch (errno) { 2543 case E2BIG: 2544 if ((p = xrealloc(buf, buf_size * 2)) == NULL) 2545 return orig; 2546 buf_size *= 2; 2547 dest = p + (dest - buf); 2548 buf = p; 2549 break; 2550 2551 case EILSEQ: case EINVAL: default: 2552 return orig; 2553 } 2554 } 2555 } 2556 return buf; 2557 } 2558 # endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2559 #endif /* NLS_CATALOGS */ 2560 2561 void 2562 nlsinit(void) 2563 { 2564 #ifdef NLS_CATALOGS 2565 static const char default_catalog[] = "tcsh"; 2566 2567 char *catalog = (char *)(intptr_t)default_catalog; 2568 2569 if (adrof(STRcatalog) != NULL) 2570 catalog = xasprintf("tcsh.%s", short2str(varval(STRcatalog))); 2571 catd = catopen(catalog, MCLoadBySet); 2572 if (catalog != default_catalog) 2573 xfree(catalog); 2574 #if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2575 /* xcatgets (), not CGETS, the charset name should be in ASCII anyway. */ 2576 catgets_iconv = iconv_open (nl_langinfo (CODESET), 2577 xcatgets(catd, 255, 1, "ASCII")); 2578 #endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2579 #endif /* NLS_CATALOGS */ 2580 #ifdef WINNT_NATIVE 2581 nls_dll_init(); 2582 #endif /* WINNT_NATIVE */ 2583 errinit(); /* init the errorlist in correct locale */ 2584 mesginit(); /* init the messages for signals */ 2585 dateinit(); /* init the messages for dates */ 2586 editinit(); /* init the editor messages */ 2587 terminit(); /* init the termcap messages */ 2588 } 2589 2590 void 2591 nlsclose(void) 2592 { 2593 #ifdef NLS_CATALOGS 2594 #if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2595 if (catgets_iconv != (iconv_t)-1) { 2596 iconv_close(catgets_iconv); 2597 catgets_iconv = (iconv_t)-1; 2598 } 2599 #endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2600 if (catd != (nl_catd)-1) { 2601 /* 2602 * catclose can call other functions which can call longjmp 2603 * making us re-enter this code. Prevent infinite recursion 2604 * by resetting catd. Problem reported and solved by: 2605 * Gerhard Niklasch 2606 */ 2607 nl_catd oldcatd = catd; 2608 catd = (nl_catd)-1; 2609 while (catclose(oldcatd) == -1 && errno == EINTR) 2610 handle_pending_signals(); 2611 } 2612 #endif /* NLS_CATALOGS */ 2613 } 2614