sh.func.c revision 59243
1/* $Header: /src/pub/tcsh/sh.func.c,v 3.85 1999/08/16 20:05:49 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.85 1999/08/16 20:05:49 christos Exp $") 40 41#include "ed.h" 42#include "tw.h" 43#include "tc.h" 44#ifdef WINNT 45#include "nt.const.h" 46#endif /* WINNT */ 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 130 return nt_check_additional_builtins(cp); 131#endif /*WINNT*/ 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 351 USE(v); 352#else /* !WINNT */ 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 */ 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 == 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 = 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 = 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 = 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 = F_SEEK; 840 a.f_seek = 0; 841 bseek(&a); 842 } 843 do { 844 if (intty && fseekp == feobp && aret == 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 == 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 != I_SEEK && wp->w_start.type == wp->w_end.type && 1070 wp->w_start.type == o.type) { 1071 if (wp->w_end.type == 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 return; 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 1394 if (eq(vp, STRtcshlang)) { 1395 nlsinit(); 1396 xfree((ptr_t) lp); 1397 return; 1398 } 1399 if (eq(vp, STRtcshonlystartexes)) { 1400 __nt_only_start_exes = 1; 1401 xfree((ptr_t) lp); 1402 return; 1403 } 1404#endif /* WINNT */ 1405 if (eq(vp, STRKTERM)) { 1406 char *t; 1407 set(STRterm, quote(lp), VAR_READWRITE); /* lp memory used here */ 1408 t = short2str(lp); 1409 if (noediting && strcmp(t, "unknown") != 0 && strcmp(t,"dumb") != 0) { 1410 editing = 1; 1411 noediting = 0; 1412 set(STRedit, Strsave(STRNULL), VAR_READWRITE); 1413 } 1414 GotTermCaps = 0; 1415 ed_Init(); 1416 return; 1417 } 1418 1419 if (eq(vp, STRKHOME)) { 1420 /* 1421 * convert to canonical pathname (possibly resolving symlinks) 1422 */ 1423 lp = dcanon(lp, lp); 1424 set(STRhome, quote(lp), VAR_READWRITE); /* cp memory used here */ 1425 1426 /* fix directory stack for new tilde home */ 1427 dtilde(); 1428 return; 1429 } 1430 1431 if (eq(vp, STRKSHLVL)) { 1432 /* lp memory used here */ 1433 set(STRshlvl, quote(lp), VAR_READWRITE); 1434 return; 1435 } 1436 1437 if (eq(vp, STRKUSER)) { 1438 set(STRuser, quote(lp), VAR_READWRITE); /* lp memory used here */ 1439 return; 1440 } 1441 1442 if (eq(vp, STRKGROUP)) { 1443 set(STRgroup, quote(lp), VAR_READWRITE); /* lp memory used here */ 1444 return; 1445 } 1446 1447#ifdef COLOR_LS_F 1448 if (eq(vp, STRLS_COLORS)) { 1449 parseLS_COLORS(lp); 1450 return; 1451 } 1452#endif /* COLOR_LS_F */ 1453 1454#ifdef SIG_WINDOW 1455 /* 1456 * Load/Update $LINES $COLUMNS 1457 */ 1458 if ((eq(lp, STRNULL) && (eq(vp, STRLINES) || eq(vp, STRCOLUMNS))) || 1459 eq(vp, STRTERMCAP)) { 1460 xfree((ptr_t) lp); 1461 check_window_size(1); 1462 return; 1463 } 1464 1465 /* 1466 * Change the size to the one directed by $LINES and $COLUMNS 1467 */ 1468 if (eq(vp, STRLINES) || eq(vp, STRCOLUMNS)) { 1469#if 0 1470 GotTermCaps = 0; 1471#endif 1472 xfree((ptr_t) lp); 1473 ed_Init(); 1474 return; 1475 } 1476#endif /* SIG_WINDOW */ 1477 xfree((ptr_t) lp); 1478} 1479 1480/*ARGSUSED*/ 1481void 1482dounsetenv(v, c) 1483 register Char **v; 1484 struct command *c; 1485{ 1486 Char **ep, *p, *n; 1487 int i, maxi; 1488 static Char *name = NULL; 1489 1490 USE(c); 1491 if (name) 1492 xfree((ptr_t) name); 1493 /* 1494 * Find the longest environment variable 1495 */ 1496 for (maxi = 0, ep = STR_environ; *ep; ep++) { 1497 for (i = 0, p = *ep; *p && *p != '='; p++, i++) 1498 continue; 1499 if (i > maxi) 1500 maxi = i; 1501 } 1502 1503 name = (Char *) xmalloc((size_t) ((maxi + 1) * sizeof(Char))); 1504 1505 while (++v && *v) 1506 for (maxi = 1; maxi;) 1507 for (maxi = 0, ep = STR_environ; *ep; ep++) { 1508 for (n = name, p = *ep; *p && *p != '='; *n++ = *p++) 1509 continue; 1510 *n = '\0'; 1511 if (!Gmatch(name, *v)) 1512 continue; 1513 maxi = 1; 1514 1515 /* Unset the name. This wasn't being done until 1516 * later but most of the stuff following won't 1517 * work (particularly the setlocale() and getenv() 1518 * stuff) as intended until the name is actually 1519 * removed. (sg) 1520 */ 1521 Unsetenv(name); 1522 1523 if (eq(name, STRNOREBIND)) { 1524 NoNLSRebind = 0; 1525 MapsAreInited = 0; 1526 NLSMapsAreInited = 0; 1527 ed_InitMaps(); 1528 } 1529#ifdef apollo 1530 else if (eq(name, STRSYSTYPE)) 1531 dohash(NULL, NULL); 1532#endif /* apollo */ 1533 else if (islocale_var(name)) { 1534#ifdef NLS 1535 int k; 1536 1537# ifdef SETLOCALEBUG 1538 dont_free = 1; 1539# endif /* SETLOCALEBUG */ 1540 (void) setlocale(LC_ALL, ""); 1541# ifdef LC_COLLATE 1542 (void) setlocale(LC_COLLATE, ""); 1543# endif 1544# ifdef NLS_CATALOGS 1545# ifdef LC_MESSAGES 1546 (void) setlocale(LC_MESSAGES, ""); 1547# endif /* LC_MESSAGES */ 1548 (void) catclose(catd); 1549 nlsinit(); 1550# endif /* NLS_CATALOGS */ 1551# ifdef LC_CTYPE 1552 (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 1553# endif /* LC_CTYPE */ 1554# ifdef SETLOCALEBUG 1555 dont_free = 0; 1556# endif /* SETLOCALEBUG */ 1557# ifdef STRCOLLBUG 1558 fix_strcoll_bug(); 1559# endif /* STRCOLLBUG */ 1560 tw_cmd_free();/* since the collation sequence has changed */ 1561 for (k = 0200; k <= 0377 && !Isprint(k); k++) 1562 continue; 1563 AsciiOnly = k > 0377; 1564#else /* !NLS */ 1565 AsciiOnly = getenv("LANG") == NULL && 1566 getenv("LC_CTYPE") == NULL; 1567#endif /* NLS */ 1568 NLSMapsAreInited = 0; 1569 ed_Init(); 1570 if (MapsAreInited && !NLSMapsAreInited) 1571 ed_InitNLSMaps(); 1572 1573 } 1574#ifdef WINNT 1575 else if (eq(name,(STRtcshlang))) { 1576 nls_dll_unload(); 1577 nlsinit(); 1578 } 1579 else if (eq(name,(STRtcshonlystartexes))) { 1580 __nt_only_start_exes = 0; 1581 } 1582#endif /* WINNT */ 1583#ifdef COLOR_LS_F 1584 else if (eq(name, STRLS_COLORS)) 1585 parseLS_COLORS(n); 1586#endif /* COLOR_LS_F */ 1587 /* 1588 * start again cause the environment changes 1589 */ 1590 break; 1591 } 1592 xfree((ptr_t) name); name = NULL; 1593} 1594 1595void 1596tsetenv(name, val) 1597 Char *name, *val; 1598{ 1599#ifdef SETENV_IN_LIB 1600/* 1601 * XXX: This does not work right, since tcsh cannot track changes to 1602 * the environment this way. (the builtin setenv without arguments does 1603 * not print the right stuff neither does unsetenv). This was for Mach, 1604 * it is not needed anymore. 1605 */ 1606#undef setenv 1607 char nameBuf[BUFSIZE]; 1608 char *cname = short2str(name); 1609 1610 if (cname == NULL) 1611 return; 1612 (void) strcpy(nameBuf, cname); 1613 setenv(nameBuf, short2str(val), 1); 1614#else /* !SETENV_IN_LIB */ 1615 register Char **ep = STR_environ; 1616 register Char *cp, *dp; 1617 Char *blk[2]; 1618 Char **oep = ep; 1619 1620#ifdef WINNT 1621 nt_set_env(name,val); 1622#endif /* WINNT */ 1623 for (; *ep; ep++) { 1624#ifdef WINNT 1625 for (cp = name, dp = *ep; *cp && Tolower(*cp & TRIM) == Tolower(*dp); 1626 cp++, dp++) 1627#else 1628 for (cp = name, dp = *ep; *cp && (*cp & TRIM) == *dp; cp++, dp++) 1629#endif /* WINNT */ 1630 continue; 1631 if (*cp != 0 || *dp != '=') 1632 continue; 1633 cp = Strspl(STRequal, val); 1634 xfree((ptr_t) * ep); 1635 *ep = strip(Strspl(name, cp)); 1636 xfree((ptr_t) cp); 1637 blkfree((Char **) environ); 1638 environ = short2blk(STR_environ); 1639 return; 1640 } 1641 cp = Strspl(name, STRequal); 1642 blk[0] = strip(Strspl(cp, val)); 1643 xfree((ptr_t) cp); 1644 blk[1] = 0; 1645 STR_environ = blkspl(STR_environ, blk); 1646 blkfree((Char **) environ); 1647 environ = short2blk(STR_environ); 1648 xfree((ptr_t) oep); 1649#endif /* SETENV_IN_LIB */ 1650} 1651 1652void 1653Unsetenv(name) 1654 Char *name; 1655{ 1656 register Char **ep = STR_environ; 1657 register Char *cp, *dp; 1658 Char **oep = ep; 1659 1660#ifdef WINNT 1661 nt_set_env(name,NULL); 1662#endif /*WINNT */ 1663 for (; *ep; ep++) { 1664 for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) 1665 continue; 1666 if (*cp != 0 || *dp != '=') 1667 continue; 1668 cp = *ep; 1669 *ep = 0; 1670 STR_environ = blkspl(STR_environ, ep + 1); 1671 blkfree((Char **) environ); 1672 environ = short2blk(STR_environ); 1673 *ep = cp; 1674 xfree((ptr_t) cp); 1675 xfree((ptr_t) oep); 1676 return; 1677 } 1678} 1679 1680/*ARGSUSED*/ 1681void 1682doumask(v, c) 1683 register Char **v; 1684 struct command *c; 1685{ 1686 register Char *cp = v[1]; 1687 register int i; 1688 1689 USE(c); 1690 if (cp == 0) { 1691 i = umask(0); 1692 (void) umask(i); 1693 xprintf("%o\n", i); 1694 return; 1695 } 1696 i = 0; 1697 while (Isdigit(*cp) && *cp != '8' && *cp != '9') 1698 i = i * 8 + *cp++ - '0'; 1699 if (*cp || i < 0 || i > 0777) 1700 stderror(ERR_NAME | ERR_MASK); 1701 (void) umask(i); 1702} 1703 1704#ifndef HAVENOLIMIT 1705# ifndef BSDLIMIT 1706 typedef long RLIM_TYPE; 1707# ifndef RLIM_INFINITY 1708# if !defined(_MINIX) && !defined(__clipper__) && !defined(_CRAY) 1709 extern RLIM_TYPE ulimit(); 1710# endif /* ! _MINIX && !__clipper__ */ 1711# define RLIM_INFINITY 0x003fffff 1712# define RLIMIT_FSIZE 1 1713# endif /* RLIM_INFINITY */ 1714# ifdef aiws 1715# define toset(a) (((a) == 3) ? 1004 : (a) + 1) 1716# define RLIMIT_DATA 3 1717# define RLIMIT_STACK 1005 1718# else /* aiws */ 1719# define toset(a) ((a) + 1) 1720# endif /* aiws */ 1721# else /* BSDLIMIT */ 1722# if defined(BSD4_4) && !defined(__386BSD__) 1723 typedef quad_t RLIM_TYPE; 1724# else 1725# if defined(SOLARIS2) || (defined(sgi) && SYSVREL > 3) 1726 typedef rlim_t RLIM_TYPE; 1727# else 1728# if defined(_SX) 1729 typedef long long RLIM_TYPE; 1730# else /* _SX */ 1731 typedef unsigned long RLIM_TYPE; 1732# endif /* _SX */ 1733# endif /* SOLARIS2 || (sgi && SYSVREL > 3) */ 1734# endif /* BSD4_4 && !__386BSD__ */ 1735# endif /* BSDLIMIT */ 1736 1737# if (HPUXVERSION > 700) && defined(BSDLIMIT) 1738/* Yes hpux8.0 has limits but <sys/resource.h> does not make them public */ 1739/* Yes, we could have defined _KERNEL, and -I/etc/conf/h, but is that better? */ 1740# ifndef RLIMIT_CPU 1741# define RLIMIT_CPU 0 1742# define RLIMIT_FSIZE 1 1743# define RLIMIT_DATA 2 1744# define RLIMIT_STACK 3 1745# define RLIMIT_CORE 4 1746# define RLIMIT_RSS 5 1747# define RLIMIT_NOFILE 6 1748# endif /* RLIMIT_CPU */ 1749# ifndef RLIM_INFINITY 1750# define RLIM_INFINITY 0x7fffffff 1751# endif /* RLIM_INFINITY */ 1752 /* 1753 * old versions of HP/UX counted limits in 512 bytes 1754 */ 1755# ifndef SIGRTMIN 1756# define FILESIZE512 1757# endif /* SIGRTMIN */ 1758# endif /* (HPUXVERSION > 700) && BSDLIMIT */ 1759 1760# if SYSVREL > 3 && defined(BSDLIMIT) && !defined(_SX) 1761/* In order to use rusage, we included "/usr/ucbinclude/sys/resource.h" in */ 1762/* sh.h. However, some SVR4 limits are defined in <sys/resource.h>. Rather */ 1763/* than include both and get warnings, we define the extra SVR4 limits here. */ 1764# ifndef RLIMIT_VMEM 1765# define RLIMIT_VMEM 6 1766# endif 1767# ifndef RLIMIT_AS 1768# define RLIMIT_AS RLIMIT_VMEM 1769# endif 1770# endif /* SYSVREL > 3 && BSDLIMIT */ 1771 1772struct limits limits[] = 1773{ 1774# ifdef RLIMIT_CPU 1775 { RLIMIT_CPU, "cputime", 1, "seconds" }, 1776# endif /* RLIMIT_CPU */ 1777 1778# ifdef RLIMIT_FSIZE 1779# ifndef aiws 1780 { RLIMIT_FSIZE, "filesize", 1024, "kbytes" }, 1781# else 1782 { RLIMIT_FSIZE, "filesize", 512, "blocks" }, 1783# endif /* aiws */ 1784# endif /* RLIMIT_FSIZE */ 1785 1786# ifdef RLIMIT_DATA 1787 { RLIMIT_DATA, "datasize", 1024, "kbytes" }, 1788# endif /* RLIMIT_DATA */ 1789 1790# ifdef RLIMIT_STACK 1791# ifndef aiws 1792 { RLIMIT_STACK, "stacksize", 1024, "kbytes" }, 1793# else 1794 { RLIMIT_STACK, "stacksize", 1024 * 1024, "kbytes"}, 1795# endif /* aiws */ 1796# endif /* RLIMIT_STACK */ 1797 1798# ifdef RLIMIT_CORE 1799 { RLIMIT_CORE, "coredumpsize", 1024, "kbytes" }, 1800# endif /* RLIMIT_CORE */ 1801 1802# ifdef RLIMIT_RSS 1803 { RLIMIT_RSS, "memoryuse", 1024, "kbytes" }, 1804# endif /* RLIMIT_RSS */ 1805 1806# ifdef RLIMIT_UMEM 1807 { RLIMIT_UMEM, "memoryuse", 1024, "kbytes" }, 1808# endif /* RLIMIT_UMEM */ 1809 1810# ifdef RLIMIT_VMEM 1811 { RLIMIT_VMEM, "vmemoryuse", 1024, "kbytes" }, 1812# endif /* RLIMIT_VMEM */ 1813 1814# ifdef RLIMIT_NOFILE 1815 { RLIMIT_NOFILE, "descriptors", 1, "" }, 1816# endif /* RLIMIT_NOFILE */ 1817 1818# ifdef RLIMIT_CONCUR 1819 { RLIMIT_CONCUR, "concurrency", 1, "thread(s)" }, 1820# endif /* RLIMIT_CONCUR */ 1821 1822# ifdef RLIMIT_MEMLOCK 1823 { RLIMIT_MEMLOCK, "memorylocked", 1024, "kbytes" }, 1824# endif /* RLIMIT_MEMLOCK */ 1825 1826# ifdef RLIMIT_NPROC 1827 { RLIMIT_NPROC, "maxproc", 1, "" }, 1828# endif /* RLIMIT_NPROC */ 1829 1830# ifdef RLIMIT_OFILE 1831 { RLIMIT_OFILE, "openfiles", 1, "" }, 1832# endif /* RLIMIT_OFILE */ 1833 1834 { -1, NULL, 0, NULL } 1835}; 1836 1837static struct limits *findlim __P((Char *)); 1838static RLIM_TYPE getval __P((struct limits *, Char **)); 1839static void limtail __P((Char *, char*)); 1840static void plim __P((struct limits *, int)); 1841static int setlim __P((struct limits *, int, RLIM_TYPE)); 1842 1843#ifdef convex 1844static RLIM_TYPE 1845restrict_limit(value) 1846 double value; 1847{ 1848 /* 1849 * is f too large to cope with? return the maximum or minimum int 1850 */ 1851 if (value > (double) INT_MAX) 1852 return (RLIM_TYPE) INT_MAX; 1853 else if (value < (double) INT_MIN) 1854 return (RLIM_TYPE) INT_MIN; 1855 else 1856 return (RLIM_TYPE) value; 1857} 1858#else /* !convex */ 1859# define restrict_limit(x) ((RLIM_TYPE) (x)) 1860#endif /* convex */ 1861 1862 1863static struct limits * 1864findlim(cp) 1865 Char *cp; 1866{ 1867 register struct limits *lp, *res; 1868 1869 res = (struct limits *) NULL; 1870 for (lp = limits; lp->limconst >= 0; lp++) 1871 if (prefix(cp, str2short(lp->limname))) { 1872 if (res) 1873 stderror(ERR_NAME | ERR_AMBIG); 1874 res = lp; 1875 } 1876 if (res) 1877 return (res); 1878 stderror(ERR_NAME | ERR_LIMIT); 1879 /* NOTREACHED */ 1880 return (0); 1881} 1882 1883/*ARGSUSED*/ 1884void 1885dolimit(v, c) 1886 register Char **v; 1887 struct command *c; 1888{ 1889 register struct limits *lp; 1890 register RLIM_TYPE limit; 1891 int hard = 0; 1892 1893 USE(c); 1894 v++; 1895 if (*v && eq(*v, STRmh)) { 1896 hard = 1; 1897 v++; 1898 } 1899 if (*v == 0) { 1900 for (lp = limits; lp->limconst >= 0; lp++) 1901 plim(lp, hard); 1902 return; 1903 } 1904 lp = findlim(v[0]); 1905 if (v[1] == 0) { 1906 plim(lp, hard); 1907 return; 1908 } 1909 limit = getval(lp, v + 1); 1910 if (setlim(lp, hard, limit) < 0) 1911 stderror(ERR_SILENT); 1912} 1913 1914static RLIM_TYPE 1915getval(lp, v) 1916 register struct limits *lp; 1917 Char **v; 1918{ 1919 register float f; 1920#ifndef atof /* This can be a macro on linux */ 1921 extern double atof __P((const char *)); 1922#endif /* atof */ 1923 Char *cp = *v++; 1924 1925 f = atof(short2str(cp)); 1926 1927# ifdef convex 1928 /* 1929 * is f too large to cope with. limit f to minint, maxint - X-6768 by 1930 * strike 1931 */ 1932 if ((f < (double) INT_MIN) || (f > (double) INT_MAX)) { 1933 stderror(ERR_NAME | ERR_TOOLARGE); 1934 } 1935# endif /* convex */ 1936 1937 while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') 1938 cp++; 1939 if (*cp == 0) { 1940 if (*v == 0) 1941 return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f + 0.5) * lp->limdiv); 1942 cp = *v; 1943 } 1944 switch (*cp) { 1945# ifdef RLIMIT_CPU 1946 case ':': 1947 if (lp->limconst != RLIMIT_CPU) 1948 goto badscal; 1949 return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f * 60.0 + atof(short2str(cp + 1)))); 1950 case 'h': 1951 if (lp->limconst != RLIMIT_CPU) 1952 goto badscal; 1953 limtail(cp, "hours"); 1954 f *= 3600.0; 1955 break; 1956 case 'm': 1957 if (lp->limconst == RLIMIT_CPU) { 1958 limtail(cp, "minutes"); 1959 f *= 60.0; 1960 break; 1961 } 1962 *cp = 'm'; 1963 limtail(cp, "megabytes"); 1964 f *= 1024.0 * 1024.0; 1965 break; 1966 case 's': 1967 if (lp->limconst != RLIMIT_CPU) 1968 goto badscal; 1969 limtail(cp, "seconds"); 1970 break; 1971# endif /* RLIMIT_CPU */ 1972 case 'M': 1973# ifdef RLIMIT_CPU 1974 if (lp->limconst == RLIMIT_CPU) 1975 goto badscal; 1976# endif /* RLIMIT_CPU */ 1977 *cp = 'm'; 1978 limtail(cp, "megabytes"); 1979 f *= 1024.0 * 1024.0; 1980 break; 1981 case 'k': 1982# ifdef RLIMIT_CPU 1983 if (lp->limconst == RLIMIT_CPU) 1984 goto badscal; 1985# endif /* RLIMIT_CPU */ 1986 limtail(cp, "kbytes"); 1987 f *= 1024.0; 1988 break; 1989 case 'b': 1990# ifdef RLIMIT_CPU 1991 if (lp->limconst == RLIMIT_CPU) 1992 goto badscal; 1993# endif /* RLIMIT_CPU */ 1994 limtail(cp, "blocks"); 1995 f *= 512.0; 1996 break; 1997 case 'u': 1998 limtail(cp, "unlimited"); 1999 return ((RLIM_TYPE) RLIM_INFINITY); 2000 default: 2001# ifdef RLIMIT_CPU 2002badscal: 2003# endif /* RLIMIT_CPU */ 2004 stderror(ERR_NAME | ERR_SCALEF); 2005 } 2006# ifdef convex 2007 return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f + 0.5)); 2008# else 2009 f += 0.5; 2010 if (f > (float) RLIM_INFINITY) 2011 return ((RLIM_TYPE) RLIM_INFINITY); 2012 else 2013 return ((RLIM_TYPE) f); 2014# endif /* convex */ 2015} 2016 2017static void 2018limtail(cp, str) 2019 Char *cp; 2020 char *str; 2021{ 2022 while (*cp && *cp == *str) 2023 cp++, str++; 2024 if (*cp) 2025 stderror(ERR_BADSCALE, str); 2026} 2027 2028 2029/*ARGSUSED*/ 2030static void 2031plim(lp, hard) 2032 register struct limits *lp; 2033 int hard; 2034{ 2035# ifdef BSDLIMIT 2036 struct rlimit rlim; 2037# endif /* BSDLIMIT */ 2038 RLIM_TYPE limit; 2039 int div = lp->limdiv; 2040 2041 xprintf("%s \t", lp->limname); 2042 2043# ifndef BSDLIMIT 2044 limit = ulimit(lp->limconst, 0); 2045# ifdef aiws 2046 if (lp->limconst == RLIMIT_DATA) 2047 limit -= 0x20000000; 2048# endif /* aiws */ 2049# else /* BSDLIMIT */ 2050 (void) getrlimit(lp->limconst, &rlim); 2051 limit = hard ? rlim.rlim_max : rlim.rlim_cur; 2052# endif /* BSDLIMIT */ 2053 2054# if !defined(BSDLIMIT) || defined(FILESIZE512) 2055 /* 2056 * Christos: filesize comes in 512 blocks. we divide by 2 to get 1024 2057 * blocks. Note we cannot pre-multiply cause we might overflow (A/UX) 2058 */ 2059 if (lp->limconst == RLIMIT_FSIZE) { 2060 if (limit >= (RLIM_INFINITY / 512)) 2061 limit = RLIM_INFINITY; 2062 else 2063 div = (div == 1024 ? 2 : 1); 2064 } 2065# endif /* !BSDLIMIT || FILESIZE512 */ 2066 2067 if (limit == RLIM_INFINITY) 2068 xprintf("unlimited"); 2069 else 2070# ifdef RLIMIT_CPU 2071 if (lp->limconst == RLIMIT_CPU) 2072 psecs((long) limit); 2073 else 2074# endif /* RLIMIT_CPU */ 2075 xprintf("%ld %s", (long) (limit / div), lp->limscale); 2076 xputchar('\n'); 2077} 2078 2079/*ARGSUSED*/ 2080void 2081dounlimit(v, c) 2082 register Char **v; 2083 struct command *c; 2084{ 2085 register struct limits *lp; 2086 int lerr = 0; 2087 int hard = 0; 2088 int force = 0; 2089 2090 USE(c); 2091 while (*++v && **v == '-') { 2092 Char *vp = *v; 2093 while (*++vp) 2094 switch (*vp) { 2095 case 'f': 2096 force = 1; 2097 break; 2098 case 'h': 2099 hard = 1; 2100 break; 2101 default: 2102 stderror(ERR_ULIMUS); 2103 break; 2104 } 2105 } 2106 2107 if (*v == 0) { 2108 for (lp = limits; lp->limconst >= 0; lp++) 2109 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0) 2110 lerr++; 2111 if (!force && lerr) 2112 stderror(ERR_SILENT); 2113 return; 2114 } 2115 while (*v) { 2116 lp = findlim(*v++); 2117 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0 && !force) 2118 stderror(ERR_SILENT); 2119 } 2120} 2121 2122static int 2123setlim(lp, hard, limit) 2124 register struct limits *lp; 2125 int hard; 2126 RLIM_TYPE limit; 2127{ 2128# ifdef BSDLIMIT 2129 struct rlimit rlim; 2130 2131 (void) getrlimit(lp->limconst, &rlim); 2132 2133# ifdef FILESIZE512 2134 /* Even though hpux has setrlimit(), it expects fsize in 512 byte blocks */ 2135 if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 2136 limit /= 512; 2137# endif /* FILESIZE512 */ 2138 if (hard) 2139 rlim.rlim_max = limit; 2140 else if (limit == RLIM_INFINITY && euid != 0) 2141 rlim.rlim_cur = rlim.rlim_max; 2142 else 2143 rlim.rlim_cur = limit; 2144 2145 if (setrlimit(lp->limconst, &rlim) < 0) { 2146# else /* BSDLIMIT */ 2147 if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 2148 limit /= 512; 2149# ifdef aiws 2150 if (lp->limconst == RLIMIT_DATA) 2151 limit += 0x20000000; 2152# endif /* aiws */ 2153 if (ulimit(toset(lp->limconst), limit) < 0) { 2154# endif /* BSDLIMIT */ 2155 xprintf(CGETS(15, 1, "%s: %s: Can't %s%s limit\n"), bname, lp->limname, 2156 limit == RLIM_INFINITY ? CGETS(15, 2, "remove") : 2157 CGETS(15, 3, "set"), 2158 hard ? CGETS(14, 4, " hard") : ""); 2159 return (-1); 2160 } 2161 return (0); 2162} 2163 2164#endif /* !HAVENOLIMIT */ 2165 2166/*ARGSUSED*/ 2167void 2168dosuspend(v, c) 2169 Char **v; 2170 struct command *c; 2171{ 2172#ifdef BSDJOBS 2173 int ctpgrp; 2174 2175 signalfun_t old; 2176#endif /* BSDJOBS */ 2177 2178 USE(c); 2179 USE(v); 2180 2181 if (loginsh) 2182 stderror(ERR_SUSPLOG); 2183 untty(); 2184 2185#ifdef BSDJOBS 2186 old = signal(SIGTSTP, SIG_DFL); 2187 (void) kill(0, SIGTSTP); 2188 /* the shell stops here */ 2189 (void) signal(SIGTSTP, old); 2190#else /* !BSDJOBS */ 2191 stderror(ERR_JOBCONTROL); 2192#endif /* BSDJOBS */ 2193 2194#ifdef BSDJOBS 2195 if (tpgrp != -1) { 2196retry: 2197 ctpgrp = tcgetpgrp(FSHTTY); 2198 if (ctpgrp != opgrp) { 2199 old = signal(SIGTTIN, SIG_DFL); 2200 (void) kill(0, SIGTTIN); 2201 (void) signal(SIGTTIN, old); 2202 goto retry; 2203 } 2204 (void) setpgid(0, shpgrp); 2205 (void) tcsetpgrp(FSHTTY, shpgrp); 2206 } 2207#endif /* BSDJOBS */ 2208 (void) setdisc(FSHTTY); 2209} 2210 2211/* This is the dreaded EVAL built-in. 2212 * If you don't fiddle with file descriptors, and reset didfds, 2213 * this command will either ignore redirection inside or outside 2214 * its arguments, e.g. eval "date >x" vs. eval "date" >x 2215 * The stuff here seems to work, but I did it by trial and error rather 2216 * than really knowing what was going on. If tpgrp is zero, we are 2217 * probably a background eval, e.g. "eval date &", and we want to 2218 * make sure that any processes we start stay in our pgrp. 2219 * This is also the case for "time eval date" -- stay in same pgrp. 2220 * Otherwise, under stty tostop, processes will stop in the wrong 2221 * pgrp, with no way for the shell to get them going again. -IAN! 2222 */ 2223 2224static Char **gv = NULL, **gav = NULL; 2225 2226/*ARGSUSED*/ 2227void 2228doeval(v, c) 2229 Char **v; 2230 struct command *c; 2231{ 2232 Char **oevalvec; 2233 Char *oevalp; 2234 int odidfds; 2235#ifndef CLOSE_ON_EXEC 2236 int odidcch; 2237#endif /* CLOSE_ON_EXEC */ 2238 jmp_buf_t osetexit; 2239 int my_reenter; 2240 Char **savegv; 2241 int saveIN, saveOUT, saveDIAG; 2242 int oSHIN, oSHOUT, oSHDIAG; 2243 2244 USE(c); 2245 oevalvec = evalvec; 2246 oevalp = evalp; 2247 odidfds = didfds; 2248#ifndef CLOSE_ON_EXEC 2249 odidcch = didcch; 2250#endif /* CLOSE_ON_EXEC */ 2251 oSHIN = SHIN; 2252 oSHOUT = SHOUT; 2253 oSHDIAG = SHDIAG; 2254 2255 savegv = gv; 2256 gav = v; 2257 2258 gav++; 2259 if (*gav == 0) 2260 return; 2261 gflag = 0, tglob(gav); 2262 if (gflag) { 2263 gv = gav = globall(gav); 2264 gargv = 0; 2265 if (gav == 0) 2266 stderror(ERR_NOMATCH); 2267 gav = copyblk(gav); 2268 } 2269 else { 2270 gv = NULL; 2271 gav = copyblk(gav); 2272 trim(gav); 2273 } 2274 2275 saveIN = dcopy(SHIN, -1); 2276 saveOUT = dcopy(SHOUT, -1); 2277 saveDIAG = dcopy(SHDIAG, -1); 2278 2279 getexit(osetexit); 2280 2281 /* PWP: setjmp/longjmp bugfix for optimizing compilers */ 2282#ifdef cray 2283 my_reenter = 1; /* assume non-zero return val */ 2284 if (setexit() == 0) { 2285 my_reenter = 0; /* Oh well, we were wrong */ 2286#else /* !cray */ 2287 if ((my_reenter = setexit()) == 0) { 2288#endif /* cray */ 2289 evalvec = gav; 2290 evalp = 0; 2291 SHIN = dcopy(0, -1); 2292 SHOUT = dcopy(1, -1); 2293 SHDIAG = dcopy(2, -1); 2294#ifndef CLOSE_ON_EXEC 2295 didcch = 0; 2296#endif /* CLOSE_ON_EXEC */ 2297 didfds = 0; 2298 process(0); 2299 } 2300 2301 evalvec = oevalvec; 2302 evalp = oevalp; 2303 doneinp = 0; 2304#ifndef CLOSE_ON_EXEC 2305 didcch = odidcch; 2306#endif /* CLOSE_ON_EXEC */ 2307 didfds = odidfds; 2308 (void) close(SHIN); 2309 (void) close(SHOUT); 2310 (void) close(SHDIAG); 2311 SHIN = dmove(saveIN, oSHIN); 2312 SHOUT = dmove(saveOUT, oSHOUT); 2313 SHDIAG = dmove(saveDIAG, oSHDIAG); 2314 2315 if (gv) 2316 blkfree(gv); 2317 2318 gv = savegv; 2319 resexit(osetexit); 2320 if (my_reenter) 2321 stderror(ERR_SILENT); 2322} 2323 2324/*************************************************************************/ 2325/* print list of builtin commands */ 2326 2327/*ARGSUSED*/ 2328void 2329dobuiltins(v, c) 2330Char **v; 2331struct command *c; 2332{ 2333 /* would use print_by_column() in tw.parse.c but that assumes 2334 * we have an array of Char * to pass.. (sg) 2335 */ 2336 extern int Tty_raw_mode; 2337 extern int TermH; /* from the editor routines */ 2338 extern int lbuffed; /* from sh.print.c */ 2339 2340 register struct biltins *b; 2341 register int row, col, columns, rows; 2342 unsigned int w, maxwidth; 2343 2344 USE(c); 2345 USE(v); 2346 lbuffed = 0; /* turn off line buffering */ 2347 2348 /* find widest string */ 2349 for (maxwidth = 0, b = bfunc; b < &bfunc[nbfunc]; ++b) 2350 maxwidth = max(maxwidth, strlen(b->bname)); 2351 ++maxwidth; /* for space */ 2352 2353 columns = (TermH + 1) / maxwidth; /* PWP: terminal size change */ 2354 if (!columns) 2355 columns = 1; 2356 rows = (nbfunc + (columns - 1)) / columns; 2357 2358 for (b = bfunc, row = 0; row < rows; row++) { 2359 for (col = 0; col < columns; col++) { 2360 if (b < &bfunc[nbfunc]) { 2361 w = strlen(b->bname); 2362 xprintf("%s", b->bname); 2363 if (col < (columns - 1)) /* Not last column? */ 2364 for (; w < maxwidth; w++) 2365 xputchar(' '); 2366 ++b; 2367 } 2368 } 2369 if (row < (rows - 1)) { 2370 if (Tty_raw_mode) 2371 xputchar('\r'); 2372 xputchar('\n'); 2373 } 2374 } 2375#ifdef WINNT 2376 nt_print_builtins(maxwidth); 2377#else 2378 if (Tty_raw_mode) 2379 xputchar('\r'); 2380 xputchar('\n'); 2381#endif /* WINNT */ 2382 2383 lbuffed = 1; /* turn back on line buffering */ 2384 flush(); 2385} 2386 2387void 2388nlsinit() 2389{ 2390#ifdef NLS_CATALOGS 2391 catd = catopen("tcsh", MCLoadBySet); 2392#endif 2393#ifdef WINNT 2394 nls_dll_init(); 2395#endif /* WINNT */ 2396 errinit(); /* init the errorlist in correct locale */ 2397 mesginit(); /* init the messages for signals */ 2398 dateinit(); /* init the messages for dates */ 2399 editinit(); /* init the editor messages */ 2400 terminit(); /* init the termcap messages */ 2401} 2402