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