sh.func.c revision 145479
1215976Sjmallett/* $Header: /src/pub/tcsh/sh.func.c,v 3.126 2005/03/20 06:35:48 christos Exp $ */ 2215976Sjmallett/* 3215976Sjmallett * sh.func.c: csh builtin functions 4215976Sjmallett */ 5215976Sjmallett/*- 6215976Sjmallett * Copyright (c) 1980, 1991 The Regents of the University of California. 7215976Sjmallett * All rights reserved. 8215976Sjmallett * 9215976Sjmallett * Redistribution and use in source and binary forms, with or without 10215976Sjmallett * modification, are permitted provided that the following conditions 11215976Sjmallett * are met: 12215976Sjmallett * 1. Redistributions of source code must retain the above copyright 13215976Sjmallett * notice, this list of conditions and the following disclaimer. 14215976Sjmallett * 2. Redistributions in binary form must reproduce the above copyright 15215976Sjmallett * notice, this list of conditions and the following disclaimer in the 16215976Sjmallett * documentation and/or other materials provided with the distribution. 17215976Sjmallett * 3. Neither the name of the University nor the names of its contributors 18215976Sjmallett * may be used to endorse or promote products derived from this software 19215976Sjmallett * without specific prior written permission. 20215976Sjmallett * 21215976Sjmallett * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22215976Sjmallett * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23215976Sjmallett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24215976Sjmallett * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25215976Sjmallett * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26215976Sjmallett * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27215976Sjmallett * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28215976Sjmallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29215976Sjmallett * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30215976Sjmallett * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31215976Sjmallett * SUCH DAMAGE. 32215976Sjmallett */ 33215976Sjmallett#include "sh.h" 34215976Sjmallett 35215976SjmallettRCSID("$Id: sh.func.c,v 3.126 2005/03/20 06:35:48 christos Exp $") 36215976Sjmallett 37215976Sjmallett#include "ed.h" 38215976Sjmallett#include "tw.h" 39215976Sjmallett#include "tc.h" 40215976Sjmallett#ifdef WINNT_NATIVE 41215976Sjmallett#include "nt.const.h" 42215976Sjmallett#endif /* WINNT_NATIVE */ 43215976Sjmallett 44215976Sjmallett#ifdef NLS_CATALOGS 45215976Sjmallett#ifdef HAVE_ICONV 46215976Sjmallett#include <langinfo.h> 47215976Sjmallettstatic iconv_t catgets_iconv; /* Or (iconv_t)-1 */ 48215976Sjmallett#endif 49215976Sjmallett#endif 50215976Sjmallett 51215976Sjmallett/* 52215976Sjmallett * C shell 53215976Sjmallett */ 54215976Sjmallettextern int just_signaled; 55215976Sjmallettextern char **environ; 56215976Sjmallett 57215976Sjmallettextern int MapsAreInited; 58215976Sjmallettextern int NLSMapsAreInited; 59215976Sjmallettextern int GotTermCaps; 60215976Sjmallett 61215976Sjmallettstatic int zlast = -1; 62215976Sjmallett 63215976Sjmallettstatic void islogin __P((void)); 64215976Sjmallettstatic void preread __P((void)); 65215976Sjmallettstatic void doagain __P((void)); 66215976Sjmallettstatic const char *isrchx __P((int)); 67215976Sjmallettstatic void search __P((int, int, Char *)); 68215976Sjmallettstatic int getword __P((Char *)); 69215976Sjmallettstatic void toend __P((void)); 70215976Sjmallettstatic void xecho __P((int, Char **)); 71215976Sjmallettstatic int islocale_var __P((Char *)); 72215976Sjmallettstatic void wpfree __P((struct whyle *)); 73215976Sjmallett 74215976Sjmallettstruct biltins * 75215976Sjmallettisbfunc(t) 76215976Sjmallett struct command *t; 77215976Sjmallett{ 78215976Sjmallett Char *cp = t->t_dcom[0]; 79215976Sjmallett struct biltins *bp, *bp1, *bp2; 80215976Sjmallett static struct biltins label = {"", dozip, 0, 0}; 81215976Sjmallett static struct biltins foregnd = {"%job", dofg1, 0, 0}; 82215976Sjmallett static struct biltins backgnd = {"%job &", dobg1, 0, 0}; 83215976Sjmallett 84215976Sjmallett /* 85215976Sjmallett * We never match a builtin that has quoted the first 86215976Sjmallett * character; this has been the traditional way to escape 87215976Sjmallett * builtin commands. 88215976Sjmallett */ 89215976Sjmallett if (*cp & QUOTE) 90215976Sjmallett return NULL; 91215976Sjmallett 92215976Sjmallett if (*cp != ':' && lastchr(cp) == ':') { 93215976Sjmallett label.bname = short2str(cp); 94215976Sjmallett return (&label); 95215976Sjmallett } 96215976Sjmallett if (*cp == '%') { 97215976Sjmallett if (t->t_dflg & F_AMPERSAND) { 98215976Sjmallett t->t_dflg &= ~F_AMPERSAND; 99215976Sjmallett backgnd.bname = short2str(cp); 100215976Sjmallett return (&backgnd); 101215976Sjmallett } 102215976Sjmallett foregnd.bname = short2str(cp); 103215976Sjmallett return (&foregnd); 104215976Sjmallett } 105215976Sjmallett#ifdef WARP 106215976Sjmallett /* 107215976Sjmallett * This is a perhaps kludgy way to determine if the warp builtin is to be 108215976Sjmallett * acknowledged or not. If checkwarp() fails, then we are to assume that 109215976Sjmallett * the warp command is invalid, and carry on as we would handle any other 110215976Sjmallett * non-builtin command. -- JDK 2/4/88 111215976Sjmallett */ 112215976Sjmallett if (eq(STRwarp, cp) && !checkwarp()) { 113215976Sjmallett return (0); /* this builtin disabled */ 114215976Sjmallett } 115215976Sjmallett#endif /* WARP */ 116215976Sjmallett /* 117215976Sjmallett * Binary search Bp1 is the beginning of the current search range. Bp2 is 118215976Sjmallett * one past the end. 119215976Sjmallett */ 120215976Sjmallett for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) { 121215976Sjmallett int i; 122215976Sjmallett 123215976Sjmallett bp = bp1 + ((bp2 - bp1) >> 1); 124215976Sjmallett if ((i = ((char) *cp) - *bp->bname) == 0 && 125215976Sjmallett (i = StrQcmp(cp, str2short(bp->bname))) == 0) 126215976Sjmallett return bp; 127215976Sjmallett if (i < 0) 128215976Sjmallett bp2 = bp; 129215976Sjmallett else 130215976Sjmallett bp1 = bp + 1; 131215976Sjmallett } 132215976Sjmallett#ifdef WINNT_NATIVE 133215976Sjmallett return nt_check_additional_builtins(cp); 134215976Sjmallett#endif /*WINNT_NATIVE*/ 135215976Sjmallett return (0); 136215976Sjmallett} 137215976Sjmallett 138215976Sjmallettvoid 139215976Sjmallettfunc(t, bp) 140215976Sjmallett struct command *t; 141215976Sjmallett struct biltins *bp; 142215976Sjmallett{ 143215976Sjmallett int i; 144215976Sjmallett 145215976Sjmallett xechoit(t->t_dcom); 146215976Sjmallett setname(bp->bname); 147215976Sjmallett i = blklen(t->t_dcom) - 1; 148215976Sjmallett if (i < bp->minargs) 149215976Sjmallett stderror(ERR_NAME | ERR_TOOFEW); 150215976Sjmallett if (i > bp->maxargs) 151215976Sjmallett stderror(ERR_NAME | ERR_TOOMANY); 152215976Sjmallett (*bp->bfunct) (t->t_dcom, t); 153215976Sjmallett} 154215976Sjmallett 155215976Sjmallett/*ARGSUSED*/ 156215976Sjmallettvoid 157215976Sjmallettdoonintr(v, c) 158215976Sjmallett Char **v; 159215976Sjmallett struct command *c; 160215976Sjmallett{ 161215976Sjmallett Char *cp; 162215976Sjmallett Char *vv = v[1]; 163215976Sjmallett 164215976Sjmallett USE(c); 165215976Sjmallett if (parintr == SIG_IGN) 166215976Sjmallett return; 167215976Sjmallett if (setintr && intty) 168215976Sjmallett stderror(ERR_NAME | ERR_TERMINAL); 169215976Sjmallett cp = gointr; 170215976Sjmallett gointr = 0; 171215976Sjmallett xfree((ptr_t) cp); 172215976Sjmallett if (vv == 0) { 173215976Sjmallett#ifdef BSDSIGS 174215976Sjmallett if (setintr) { 175215976Sjmallett (void) sigblock(sigmask(SIGINT)); 176215976Sjmallett (void) signal(SIGINT, pintr); 177215976Sjmallett } 178215976Sjmallett else 179215976Sjmallett (void) signal(SIGINT, SIG_DFL); 180215976Sjmallett#else /* !BSDSIGS */ 181215976Sjmallett if (setintr) { 182215976Sjmallett (void) sighold(SIGINT); 183215976Sjmallett (void) sigset(SIGINT, pintr); 184215976Sjmallett } 185215976Sjmallett else 186215976Sjmallett (void) sigset(SIGINT, SIG_DFL); 187215976Sjmallett#endif /* BSDSIGS */ 188215976Sjmallett gointr = 0; 189215976Sjmallett } 190215976Sjmallett else if (eq((vv = strip(vv)), STRminus)) { 191215976Sjmallett#ifdef BSDSIGS 192215976Sjmallett (void) signal(SIGINT, SIG_IGN); 193215976Sjmallett#else /* !BSDSIGS */ 194215976Sjmallett (void) sigset(SIGINT, SIG_IGN); 195215976Sjmallett#endif /* BSDSIGS */ 196215976Sjmallett gointr = Strsave(STRminus); 197215976Sjmallett } 198215976Sjmallett else { 199215976Sjmallett gointr = Strsave(vv); 200215976Sjmallett#ifdef BSDSIGS 201215976Sjmallett (void) signal(SIGINT, pintr); 202215976Sjmallett#else /* !BSDSIGS */ 203215976Sjmallett (void) sigset(SIGINT, pintr); 204215976Sjmallett#endif /* BSDSIGS */ 205215976Sjmallett } 206215976Sjmallett} 207215976Sjmallett 208215976Sjmallett/*ARGSUSED*/ 209215976Sjmallettvoid 210215976Sjmallettdonohup(v, c) 211215976Sjmallett Char **v; 212215976Sjmallett struct command *c; 213215976Sjmallett{ 214215976Sjmallett USE(c); 215215976Sjmallett USE(v); 216215976Sjmallett if (intty) 217215976Sjmallett stderror(ERR_NAME | ERR_TERMINAL); 218215976Sjmallett if (setintr == 0) { 219215976Sjmallett (void) signal(SIGHUP, SIG_IGN); 220215976Sjmallett#ifdef CC 221215976Sjmallett submit(getpid()); 222215976Sjmallett#endif /* CC */ 223215976Sjmallett } 224215976Sjmallett} 225215976Sjmallett 226215976Sjmallett/*ARGSUSED*/ 227215976Sjmallettvoid 228215976Sjmallettdohup(v, c) 229215976Sjmallett Char **v; 230215976Sjmallett struct command *c; 231215976Sjmallett{ 232215976Sjmallett USE(c); 233215976Sjmallett USE(v); 234215976Sjmallett if (intty) 235215976Sjmallett stderror(ERR_NAME | ERR_TERMINAL); 236215976Sjmallett if (setintr == 0) 237215976Sjmallett (void) signal(SIGHUP, SIG_DFL); 238215976Sjmallett} 239215976Sjmallett 240215976Sjmallett 241215976Sjmallett/*ARGSUSED*/ 242215976Sjmallettvoid 243215976Sjmallettdozip(v, c) 244215976Sjmallett Char **v; 245215976Sjmallett struct command *c; 246215976Sjmallett{ 247215976Sjmallett USE(c); 248215976Sjmallett USE(v); 249215976Sjmallett} 250215976Sjmallett 251215976Sjmallett/*ARGSUSED*/ 252215976Sjmallettvoid 253215976Sjmallettdofiletest(v, c) 254215976Sjmallett Char **v; 255215976Sjmallett struct command *c; 256215976Sjmallett{ 257215976Sjmallett Char **fileptr, *ftest, *res; 258215976Sjmallett 259215976Sjmallett USE(c); 260215976Sjmallett if (*(ftest = *++v) != '-') 261215976Sjmallett stderror(ERR_NAME | ERR_FILEINQ); 262215976Sjmallett ++v; 263215976Sjmallett 264215976Sjmallett gflag = 0; 265215976Sjmallett tglob(v); 266215976Sjmallett if (gflag) { 267215976Sjmallett v = globall(v); 268215976Sjmallett if (v == 0) 269215976Sjmallett stderror(ERR_NAME | ERR_NOMATCH); 270215976Sjmallett } 271215976Sjmallett else 272215976Sjmallett v = gargv = saveblk(v); 273215976Sjmallett trim(v); 274215976Sjmallett 275215976Sjmallett while (*(fileptr = v++) != '\0') { 276215976Sjmallett xprintf("%S", res = filetest(ftest, &fileptr, 0)); 277215976Sjmallett xfree((ptr_t) res); 278215976Sjmallett if (*v) 279215976Sjmallett xprintf(" "); 280215976Sjmallett } 281215976Sjmallett xprintf("\n"); 282215976Sjmallett 283215976Sjmallett if (gargv) { 284215976Sjmallett blkfree(gargv); 285215976Sjmallett gargv = 0; 286215976Sjmallett } 287215976Sjmallett} 288215976Sjmallett 289215976Sjmallettvoid 290215976Sjmallettprvars() 291215976Sjmallett{ 292215976Sjmallett plist(&shvhed, VAR_ALL); 293215976Sjmallett} 294215976Sjmallett 295215976Sjmallett/*ARGSUSED*/ 296215976Sjmallettvoid 297215976Sjmallettdoalias(v, c) 298215976Sjmallett Char **v; 299215976Sjmallett struct command *c; 300215976Sjmallett{ 301215976Sjmallett struct varent *vp; 302215976Sjmallett Char *p; 303215976Sjmallett 304215976Sjmallett USE(c); 305215976Sjmallett v++; 306215976Sjmallett p = *v++; 307215976Sjmallett if (p == 0) 308215976Sjmallett plist(&aliases, VAR_ALL); 309215976Sjmallett else if (*v == 0) { 310215976Sjmallett vp = adrof1(strip(p), &aliases); 311215976Sjmallett if (vp && vp->vec) 312215976Sjmallett blkpr(vp->vec), xputchar('\n'); 313215976Sjmallett } 314215976Sjmallett else { 315215976Sjmallett if (eq(p, STRalias) || eq(p, STRunalias)) { 316215976Sjmallett setname(short2str(p)); 317215976Sjmallett stderror(ERR_NAME | ERR_DANGER); 318215976Sjmallett } 319215976Sjmallett set1(strip(p), saveblk(v), &aliases, VAR_READWRITE); 320215976Sjmallett tw_cmd_free(); 321215976Sjmallett } 322215976Sjmallett} 323215976Sjmallett 324215976Sjmallett/*ARGSUSED*/ 325215976Sjmallettvoid 326215976Sjmallettunalias(v, c) 327215976Sjmallett Char **v; 328215976Sjmallett struct command *c; 329215976Sjmallett{ 330215976Sjmallett USE(c); 331215976Sjmallett unset1(v, &aliases); 332215976Sjmallett tw_cmd_free(); 333215976Sjmallett} 334215976Sjmallett 335215976Sjmallett/*ARGSUSED*/ 336215976Sjmallettvoid 337215976Sjmallettdologout(v, c) 338215976Sjmallett Char **v; 339215976Sjmallett struct command *c; 340215976Sjmallett{ 341215976Sjmallett USE(c); 342215976Sjmallett USE(v); 343215976Sjmallett islogin(); 344215976Sjmallett goodbye(NULL, NULL); 345215976Sjmallett} 346215976Sjmallett 347215976Sjmallett/*ARGSUSED*/ 348215976Sjmallettvoid 349215976Sjmallettdologin(v, c) 350215976Sjmallett Char **v; 351215976Sjmallett struct command *c; 352215976Sjmallett{ 353215976Sjmallett#ifdef WINNT_NATIVE 354215976Sjmallett USE(c); 355215976Sjmallett USE(v); 356215976Sjmallett#else /* !WINNT_NATIVE */ 357215976Sjmallett char **p = short2blk(v); 358215976Sjmallett USE(c); 359215976Sjmallett islogin(); 360215976Sjmallett rechist(NULL, adrof(STRsavehist) != NULL); 361215976Sjmallett (void) signal(SIGTERM, parterm); 362215976Sjmallett (void) execv(_PATH_BIN_LOGIN, p); 363215976Sjmallett (void) execv(_PATH_USRBIN_LOGIN, p); 364215976Sjmallett blkfree((Char **) p); 365215976Sjmallett untty(); 366215976Sjmallett xexit(1); 367215976Sjmallett#endif /* !WINNT_NATIVE */ 368215976Sjmallett} 369215976Sjmallett 370215976Sjmallett 371215976Sjmallett#ifdef NEWGRP 372215976Sjmallett/*ARGSUSED*/ 373215976Sjmallettvoid 374215976Sjmallettdonewgrp(v, c) 375215976Sjmallett Char **v; 376215976Sjmallett struct command *c; 377215976Sjmallett{ 378215976Sjmallett char **p; 379215976Sjmallett if (chkstop == 0 && setintr) 380215976Sjmallett panystop(0); 381215976Sjmallett (void) signal(SIGTERM, parterm); 382215976Sjmallett p = short2blk(v); 383215976Sjmallett /* 384215976Sjmallett * From Beto Appleton (beto@aixwiz.austin.ibm.com) 385215976Sjmallett * Newgrp can take 2 arguments... 386215976Sjmallett */ 387215976Sjmallett (void) execv(_PATH_BIN_NEWGRP, p); 388215976Sjmallett (void) execv(_PATH_USRBIN_NEWGRP, p); 389215976Sjmallett blkfree((Char **) p); 390215976Sjmallett untty(); 391215976Sjmallett xexit(1); 392215976Sjmallett} 393215976Sjmallett#endif /* NEWGRP */ 394215976Sjmallett 395215976Sjmallettstatic void 396215976Sjmallettislogin() 397215976Sjmallett{ 398215976Sjmallett if (chkstop == 0 && setintr) 399215976Sjmallett panystop(0); 400215976Sjmallett if (loginsh) 401215976Sjmallett return; 402215976Sjmallett stderror(ERR_NOTLOGIN); 403215976Sjmallett} 404215976Sjmallett 405215976Sjmallettvoid 406215976Sjmallettdoif(v, kp) 407215976Sjmallett Char **v; 408215976Sjmallett struct command *kp; 409215976Sjmallett{ 410215976Sjmallett int i; 411215976Sjmallett Char **vv; 412215976Sjmallett 413215976Sjmallett v++; 414215976Sjmallett i = expr(&v); 415215976Sjmallett vv = v; 416215976Sjmallett if (*vv == NULL) 417215976Sjmallett stderror(ERR_NAME | ERR_EMPTYIF); 418215976Sjmallett if (eq(*vv, STRthen)) { 419215976Sjmallett if (*++vv) 420215976Sjmallett stderror(ERR_NAME | ERR_IMPRTHEN); 421215976Sjmallett setname(short2str(STRthen)); 422215976Sjmallett /* 423215976Sjmallett * If expression was zero, then scan to else , otherwise just fall into 424215976Sjmallett * following code. 425215976Sjmallett */ 426215976Sjmallett if (!i) 427215976Sjmallett search(TC_IF, 0, NULL); 428215976Sjmallett return; 429215976Sjmallett } 430215976Sjmallett /* 431215976Sjmallett * Simple command attached to this if. Left shift the node in this tree, 432215976Sjmallett * munging it so we can reexecute it. 433215976Sjmallett */ 434215976Sjmallett if (i) { 435215976Sjmallett lshift(kp->t_dcom, vv - kp->t_dcom); 436215976Sjmallett reexecute(kp); 437215976Sjmallett donefds(); 438215976Sjmallett } 439215976Sjmallett} 440215976Sjmallett 441215976Sjmallett/* 442215976Sjmallett * Reexecute a command, being careful not 443215976Sjmallett * to redo i/o redirection, which is already set up. 444215976Sjmallett */ 445215976Sjmallettvoid 446215976Sjmallettreexecute(kp) 447215976Sjmallett struct command *kp; 448215976Sjmallett{ 449215976Sjmallett kp->t_dflg &= F_SAVE; 450215976Sjmallett kp->t_dflg |= F_REPEAT; 451215976Sjmallett /* 452215976Sjmallett * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set 453215976Sjmallett * pgrp's as the jobs would then have no way to get the tty (we can't give 454215976Sjmallett * it to them, and our parent wouldn't know their pgrp, etc. 455215976Sjmallett */ 456215976Sjmallett execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL, TRUE); 457215976Sjmallett} 458215976Sjmallett 459215976Sjmallett/*ARGSUSED*/ 460215976Sjmallettvoid 461215976Sjmallettdoelse (v, c) 462215976Sjmallett Char **v; 463215976Sjmallett struct command *c; 464215976Sjmallett{ 465215976Sjmallett USE(c); 466215976Sjmallett USE(v); 467215976Sjmallett search(TC_ELSE, 0, NULL); 468215976Sjmallett} 469215976Sjmallett 470215976Sjmallett/*ARGSUSED*/ 471215976Sjmallettvoid 472215976Sjmallettdogoto(v, c) 473215976Sjmallett Char **v; 474215976Sjmallett struct command *c; 475215976Sjmallett{ 476215976Sjmallett Char *lp; 477215976Sjmallett 478215976Sjmallett USE(c); 479215976Sjmallett gotolab(lp = globone(v[1], G_ERROR)); 480215976Sjmallett xfree((ptr_t) lp); 481215976Sjmallett} 482215976Sjmallett 483215976Sjmallettvoid 484215976Sjmallettgotolab(lab) 485215976Sjmallett Char *lab; 486215976Sjmallett{ 487215976Sjmallett struct whyle *wp; 488215976Sjmallett /* 489215976Sjmallett * While we still can, locate any unknown ends of existing loops. This 490215976Sjmallett * obscure code is the WORST result of the fact that we don't really parse. 491215976Sjmallett */ 492215976Sjmallett zlast = TC_GOTO; 493215976Sjmallett for (wp = whyles; wp; wp = wp->w_next) 494215976Sjmallett if (wp->w_end.type == TCSH_F_SEEK && wp->w_end.f_seek == 0) { 495215976Sjmallett search(TC_BREAK, 0, NULL); 496215976Sjmallett btell(&wp->w_end); 497215976Sjmallett } 498215976Sjmallett else { 499215976Sjmallett bseek(&wp->w_end); 500215976Sjmallett } 501215976Sjmallett search(TC_GOTO, 0, lab); 502215976Sjmallett /* 503215976Sjmallett * Eliminate loops which were exited. 504215976Sjmallett */ 505215976Sjmallett wfree(); 506215976Sjmallett} 507215976Sjmallett 508215976Sjmallett/*ARGSUSED*/ 509215976Sjmallettvoid 510215976Sjmallettdoswitch(v, c) 511215976Sjmallett Char **v; 512215976Sjmallett struct command *c; 513215976Sjmallett{ 514215976Sjmallett Char *cp, *lp; 515215976Sjmallett 516215976Sjmallett USE(c); 517215976Sjmallett v++; 518215976Sjmallett if (!*v || *(*v++) != '(') 519215976Sjmallett stderror(ERR_SYNTAX); 520215976Sjmallett cp = **v == ')' ? STRNULL : *v++; 521215976Sjmallett if (*(*v++) != ')') 522215976Sjmallett v--; 523215976Sjmallett if (*v) 524215976Sjmallett stderror(ERR_SYNTAX); 525215976Sjmallett search(TC_SWITCH, 0, lp = globone(cp, G_ERROR)); 526215976Sjmallett xfree((ptr_t) lp); 527215976Sjmallett} 528215976Sjmallett 529215976Sjmallett/*ARGSUSED*/ 530215976Sjmallettvoid 531215976Sjmallettdobreak(v, c) 532215976Sjmallett Char **v; 533215976Sjmallett struct command *c; 534215976Sjmallett{ 535215976Sjmallett USE(v); 536215976Sjmallett USE(c); 537215976Sjmallett if (whyles) 538215976Sjmallett toend(); 539215976Sjmallett else 540215976Sjmallett stderror(ERR_NAME | ERR_NOTWHILE); 541215976Sjmallett} 542215976Sjmallett 543215976Sjmallett/*ARGSUSED*/ 544215976Sjmallettvoid 545215976Sjmallettdoexit(v, c) 546215976Sjmallett Char **v; 547215976Sjmallett struct command *c; 548215976Sjmallett{ 549215976Sjmallett USE(c); 550215976Sjmallett 551215976Sjmallett if (chkstop == 0 && (intty || intact) && evalvec == 0) 552215976Sjmallett panystop(0); 553215976Sjmallett /* 554215976Sjmallett * Don't DEMAND parentheses here either. 555215976Sjmallett */ 556215976Sjmallett v++; 557215976Sjmallett if (*v) { 558215976Sjmallett set(STRstatus, putn(expr(&v)), VAR_READWRITE); 559215976Sjmallett if (*v) 560215976Sjmallett stderror(ERR_NAME | ERR_EXPRESSION); 561215976Sjmallett } 562215976Sjmallett btoeof(); 563215976Sjmallett#if 0 564215976Sjmallett if (intty) 565215976Sjmallett#endif 566215976Sjmallett /* Always close, why only on ttys? */ 567215976Sjmallett (void) close(SHIN); 568215976Sjmallett} 569215976Sjmallett 570215976Sjmallett/*ARGSUSED*/ 571215976Sjmallettvoid 572215976Sjmallettdoforeach(v, c) 573215976Sjmallett Char **v; 574215976Sjmallett struct command *c; 575215976Sjmallett{ 576215976Sjmallett Char *cp, *sp; 577215976Sjmallett struct whyle *nwp; 578215976Sjmallett 579215976Sjmallett USE(c); 580215976Sjmallett v++; 581215976Sjmallett sp = cp = strip(*v); 582215976Sjmallett if (!letter(*sp)) 583215976Sjmallett stderror(ERR_NAME | ERR_VARBEGIN); 584215976Sjmallett while (*cp && alnum(*cp)) 585215976Sjmallett cp++; 586215976Sjmallett if (*cp) 587215976Sjmallett stderror(ERR_NAME | ERR_VARALNUM); 588215976Sjmallett if ((cp - sp) > MAXVARLEN) 589215976Sjmallett stderror(ERR_NAME | ERR_VARTOOLONG); 590215976Sjmallett cp = *v++; 591215976Sjmallett if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') 592215976Sjmallett stderror(ERR_NAME | ERR_NOPAREN); 593215976Sjmallett v++; 594215976Sjmallett gflag = 0, tglob(v); 595215976Sjmallett if (gflag) { 596215976Sjmallett v = globall(v); 597215976Sjmallett if (v == 0) 598215976Sjmallett stderror(ERR_NAME | ERR_NOMATCH); 599215976Sjmallett } 600215976Sjmallett else { 601215976Sjmallett v = gargv = saveblk(v); 602215976Sjmallett trim(v); 603215976Sjmallett } 604215976Sjmallett nwp = (struct whyle *) xcalloc(1, sizeof *nwp); 605215976Sjmallett nwp->w_fe = nwp->w_fe0 = v; 606215976Sjmallett gargv = 0; 607215976Sjmallett btell(&nwp->w_start); 608215976Sjmallett nwp->w_fename = Strsave(cp); 609215976Sjmallett nwp->w_next = whyles; 610215976Sjmallett nwp->w_end.type = TCSH_F_SEEK; 611215976Sjmallett whyles = nwp; 612215976Sjmallett /* 613215976Sjmallett * Pre-read the loop so as to be more comprehensible to a terminal user. 614215976Sjmallett */ 615215976Sjmallett zlast = TC_FOREACH; 616215976Sjmallett if (intty) 617215976Sjmallett preread(); 618215976Sjmallett doagain(); 619215976Sjmallett} 620215976Sjmallett 621215976Sjmallett/*ARGSUSED*/ 622215976Sjmallettvoid 623215976Sjmallettdowhile(v, c) 624215976Sjmallett Char **v; 625215976Sjmallett struct command *c; 626215976Sjmallett{ 627215976Sjmallett int status; 628215976Sjmallett int again = whyles != 0 && 629215976Sjmallett SEEKEQ(&whyles->w_start, &lineloc) && 630215976Sjmallett whyles->w_fename == 0; 631215976Sjmallett 632215976Sjmallett USE(c); 633215976Sjmallett v++; 634215976Sjmallett /* 635215976Sjmallett * Implement prereading here also, taking care not to evaluate the 636215976Sjmallett * expression before the loop has been read up from a terminal. 637215976Sjmallett */ 638215976Sjmallett if (intty && !again) 639215976Sjmallett status = !exp0(&v, 1); 640215976Sjmallett else 641215976Sjmallett status = !expr(&v); 642215976Sjmallett if (*v) 643215976Sjmallett stderror(ERR_NAME | ERR_EXPRESSION); 644215976Sjmallett if (!again) { 645215976Sjmallett struct whyle *nwp = 646215976Sjmallett (struct whyle *) xcalloc(1, sizeof(*nwp)); 647215976Sjmallett 648215976Sjmallett nwp->w_start = lineloc; 649215976Sjmallett nwp->w_end.type = TCSH_F_SEEK; 650215976Sjmallett nwp->w_end.f_seek = 0; 651215976Sjmallett nwp->w_next = whyles; 652215976Sjmallett whyles = nwp; 653215976Sjmallett zlast = TC_WHILE; 654215976Sjmallett if (intty) { 655215976Sjmallett /* 656215976Sjmallett * The tty preread 657215976Sjmallett */ 658215976Sjmallett preread(); 659215976Sjmallett doagain(); 660215976Sjmallett return; 661215976Sjmallett } 662215976Sjmallett } 663215976Sjmallett if (status) 664215976Sjmallett /* We ain't gonna loop no more, no more! */ 665215976Sjmallett toend(); 666215976Sjmallett} 667215976Sjmallett 668215976Sjmallettstatic void 669215976Sjmallettpreread() 670215976Sjmallett{ 671215976Sjmallett whyles->w_end.type = TCSH_I_SEEK; 672215976Sjmallett if (setintr) 673215976Sjmallett#ifdef BSDSIGS 674215976Sjmallett (void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT)); 675215976Sjmallett#else /* !BSDSIGS */ 676215976Sjmallett (void) sigrelse (SIGINT); 677215976Sjmallett#endif /* BSDSIGS */ 678215976Sjmallett search(TC_BREAK, 0, NULL); /* read the expression in */ 679215976Sjmallett if (setintr) 680215976Sjmallett#ifdef BSDSIGS 681215976Sjmallett (void) sigblock(sigmask(SIGINT)); 682215976Sjmallett#else /* !BSDSIGS */ 683215976Sjmallett (void) sighold(SIGINT); 684215976Sjmallett#endif /* BSDSIGS */ 685215976Sjmallett btell(&whyles->w_end); 686215976Sjmallett} 687215976Sjmallett 688215976Sjmallett/*ARGSUSED*/ 689215976Sjmallettvoid 690215976Sjmallettdoend(v, c) 691215976Sjmallett Char **v; 692215976Sjmallett struct command *c; 693215976Sjmallett{ 694215976Sjmallett USE(v); 695215976Sjmallett USE(c); 696215976Sjmallett if (!whyles) 697215976Sjmallett stderror(ERR_NAME | ERR_NOTWHILE); 698215976Sjmallett btell(&whyles->w_end); 699215976Sjmallett doagain(); 700215976Sjmallett} 701215976Sjmallett 702215976Sjmallett/*ARGSUSED*/ 703215976Sjmallettvoid 704215976Sjmallettdocontin(v, c) 705215976Sjmallett Char **v; 706215976Sjmallett struct command *c; 707215976Sjmallett{ 708215976Sjmallett USE(v); 709215976Sjmallett USE(c); 710215976Sjmallett if (!whyles) 711215976Sjmallett stderror(ERR_NAME | ERR_NOTWHILE); 712215976Sjmallett doagain(); 713215976Sjmallett} 714215976Sjmallett 715215976Sjmallettstatic void 716215976Sjmallettdoagain() 717215976Sjmallett{ 718215976Sjmallett /* Repeating a while is simple */ 719215976Sjmallett if (whyles->w_fename == 0) { 720215976Sjmallett bseek(&whyles->w_start); 721215976Sjmallett return; 722215976Sjmallett } 723215976Sjmallett /* 724215976Sjmallett * The foreach variable list actually has a spurious word ")" at the end of 725215976Sjmallett * the w_fe list. Thus we are at the of the list if one word beyond this 726215976Sjmallett * is 0. 727215976Sjmallett */ 728215976Sjmallett if (!whyles->w_fe[1]) { 729215976Sjmallett dobreak(NULL, NULL); 730215976Sjmallett return; 731215976Sjmallett } 732215976Sjmallett set(whyles->w_fename, quote(Strsave(*whyles->w_fe++)), VAR_READWRITE); 733215976Sjmallett bseek(&whyles->w_start); 734215976Sjmallett} 735215976Sjmallett 736215976Sjmallettvoid 737215976Sjmallettdorepeat(v, kp) 738215976Sjmallett Char **v; 739215976Sjmallett struct command *kp; 740215976Sjmallett{ 741215976Sjmallett int i = 1; 742215976Sjmallett 743215976Sjmallett#ifdef BSDSIGS 744215976Sjmallett sigmask_t omask = 0; 745215976Sjmallett#endif /* BSDSIGS */ 746215976Sjmallett 747215976Sjmallett do { 748215976Sjmallett i *= getn(v[1]); 749215976Sjmallett lshift(v, 2); 750215976Sjmallett } while (v[0] != NULL && Strcmp(v[0], STRrepeat) == 0); 751215976Sjmallett 752215976Sjmallett if (setintr) 753215976Sjmallett#ifdef BSDSIGS 754215976Sjmallett omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT); 755215976Sjmallett#else /* !BSDSIGS */ 756215976Sjmallett (void) sighold(SIGINT); 757215976Sjmallett#endif /* BSDSIGS */ 758215976Sjmallett while (i > 0) { 759215976Sjmallett if (setintr) 760215976Sjmallett#ifdef BSDSIGS 761215976Sjmallett (void) sigsetmask(omask); 762215976Sjmallett#else /* !BSDSIGS */ 763215976Sjmallett (void) sigrelse (SIGINT); 764215976Sjmallett#endif /* BSDSIGS */ 765215976Sjmallett reexecute(kp); 766215976Sjmallett --i; 767215976Sjmallett } 768215976Sjmallett donefds(); 769215976Sjmallett if (setintr) 770215976Sjmallett#ifdef BSDSIGS 771215976Sjmallett (void) sigsetmask(omask); 772215976Sjmallett#else /* !BSDSIGS */ 773215976Sjmallett (void) sigrelse (SIGINT); 774215976Sjmallett#endif /* BSDSIGS */ 775215976Sjmallett} 776215976Sjmallett 777215976Sjmallett/*ARGSUSED*/ 778215976Sjmallettvoid 779215976Sjmallettdoswbrk(v, c) 780215976Sjmallett Char **v; 781215976Sjmallett struct command *c; 782215976Sjmallett{ 783215976Sjmallett USE(v); 784215976Sjmallett USE(c); 785215976Sjmallett search(TC_BRKSW, 0, NULL); 786215976Sjmallett} 787215976Sjmallett 788215976Sjmallettint 789215976Sjmallettsrchx(cp) 790215976Sjmallett Char *cp; 791215976Sjmallett{ 792215976Sjmallett struct srch *sp, *sp1, *sp2; 793215976Sjmallett int i; 794215976Sjmallett 795215976Sjmallett /* 796215976Sjmallett * Ignore keywords inside heredocs 797215976Sjmallett */ 798215976Sjmallett if (inheredoc) 799215976Sjmallett return -1; 800215976Sjmallett 801215976Sjmallett /* 802215976Sjmallett * Binary search Sp1 is the beginning of the current search range. Sp2 is 803215976Sjmallett * one past the end. 804215976Sjmallett */ 805215976Sjmallett for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) { 806215976Sjmallett sp = sp1 + ((sp2 - sp1) >> 1); 807215976Sjmallett if ((i = *cp - *sp->s_name) == 0 && 808215976Sjmallett (i = Strcmp(cp, str2short(sp->s_name))) == 0) 809215976Sjmallett return sp->s_value; 810215976Sjmallett if (i < 0) 811215976Sjmallett sp2 = sp; 812215976Sjmallett else 813215976Sjmallett sp1 = sp + 1; 814215976Sjmallett } 815215976Sjmallett return (-1); 816215976Sjmallett} 817215976Sjmallett 818215976Sjmallettstatic const char * 819215976Sjmallettisrchx(n) 820215976Sjmallett int n; 821215976Sjmallett{ 822215976Sjmallett struct srch *sp, *sp2; 823215976Sjmallett 824215976Sjmallett for (sp = srchn, sp2 = srchn + nsrchn; sp < sp2; sp++) 825215976Sjmallett if (sp->s_value == n) 826215976Sjmallett return (sp->s_name); 827215976Sjmallett return (""); 828215976Sjmallett} 829215976Sjmallett 830215976Sjmallett 831215976Sjmallettstatic Char Stype; 832215976Sjmallettstatic Char *Sgoal; 833215976Sjmallett 834215976Sjmallettstatic void 835215976Sjmallettsearch(type, level, goal) 836215976Sjmallett int type; 837215976Sjmallett int level; 838215976Sjmallett Char *goal; 839215976Sjmallett{ 840215976Sjmallett Char wordbuf[BUFSIZE]; 841215976Sjmallett Char *aword = wordbuf; 842215976Sjmallett Char *cp; 843215976Sjmallett struct whyle *wp; 844215976Sjmallett int wlevel = 0; 845215976Sjmallett 846215976Sjmallett Stype = (Char) type; 847215976Sjmallett Sgoal = goal; 848215976Sjmallett if (type == TC_GOTO) { 849215976Sjmallett struct Ain a; 850215976Sjmallett a.type = TCSH_F_SEEK; 851215976Sjmallett a.f_seek = 0; 852215976Sjmallett bseek(&a); 853215976Sjmallett } 854215976Sjmallett do { 855215976Sjmallett if (intty && fseekp == feobp && aret == TCSH_F_SEEK) 856215976Sjmallett printprompt(1, isrchx(type == TC_BREAK ? zlast : type)); 857215976Sjmallett /* xprintf("? "), flush(); */ 858215976Sjmallett aword[0] = 0; 859215976Sjmallett (void) getword(aword); 860215976Sjmallett switch (srchx(aword)) { 861215976Sjmallett 862215976Sjmallett case TC_ELSE: 863215976Sjmallett if (level == 0 && type == TC_IF) 864215976Sjmallett return; 865215976Sjmallett break; 866215976Sjmallett 867215976Sjmallett case TC_IF: 868215976Sjmallett while (getword(aword)) 869215976Sjmallett continue; 870215976Sjmallett if ((type == TC_IF || type == TC_ELSE) && 871215976Sjmallett eq(aword, STRthen)) 872215976Sjmallett level++; 873215976Sjmallett break; 874215976Sjmallett 875215976Sjmallett case TC_ENDIF: 876215976Sjmallett if (type == TC_IF || type == TC_ELSE) 877215976Sjmallett level--; 878215976Sjmallett break; 879215976Sjmallett 880215976Sjmallett case TC_FOREACH: 881215976Sjmallett case TC_WHILE: 882215976Sjmallett wlevel++; 883215976Sjmallett if (type == TC_BREAK) 884215976Sjmallett level++; 885215976Sjmallett break; 886215976Sjmallett 887215976Sjmallett case TC_END: 888215976Sjmallett if (type == TC_BRKSW) { 889215976Sjmallett if (wlevel == 0) { 890215976Sjmallett wp = whyles; 891215976Sjmallett if (wp) { 892215976Sjmallett whyles = wp->w_next; 893215976Sjmallett wpfree(wp); 894215976Sjmallett } 895215976Sjmallett } 896215976Sjmallett } 897215976Sjmallett if (type == TC_BREAK) 898215976Sjmallett level--; 899215976Sjmallett wlevel--; 900215976Sjmallett break; 901215976Sjmallett 902215976Sjmallett case TC_SWITCH: 903215976Sjmallett if (type == TC_SWITCH || type == TC_BRKSW) 904215976Sjmallett level++; 905215976Sjmallett break; 906215976Sjmallett 907215976Sjmallett case TC_ENDSW: 908215976Sjmallett if (type == TC_SWITCH || type == TC_BRKSW) 909215976Sjmallett level--; 910215976Sjmallett break; 911215976Sjmallett 912215976Sjmallett case TC_LABEL: 913215976Sjmallett if (type == TC_GOTO && getword(aword) && eq(aword, goal)) 914215976Sjmallett level = -1; 915215976Sjmallett break; 916215976Sjmallett 917215976Sjmallett default: 918215976Sjmallett if (type != TC_GOTO && (type != TC_SWITCH || level != 0)) 919215976Sjmallett break; 920215976Sjmallett if (lastchr(aword) != ':') 921215976Sjmallett break; 922215976Sjmallett aword[Strlen(aword) - 1] = 0; 923215976Sjmallett if ((type == TC_GOTO && eq(aword, goal)) || 924215976Sjmallett (type == TC_SWITCH && eq(aword, STRdefault))) 925215976Sjmallett level = -1; 926215976Sjmallett break; 927215976Sjmallett 928215976Sjmallett case TC_CASE: 929215976Sjmallett if (type != TC_SWITCH || level != 0) 930215976Sjmallett break; 931215976Sjmallett (void) getword(aword); 932215976Sjmallett if (lastchr(aword) == ':') 933215976Sjmallett aword[Strlen(aword) - 1] = 0; 934215976Sjmallett cp = strip(Dfix1(aword)); 935215976Sjmallett if (Gmatch(goal, cp)) 936215976Sjmallett level = -1; 937215976Sjmallett xfree((ptr_t) cp); 938215976Sjmallett break; 939215976Sjmallett 940215976Sjmallett case TC_DEFAULT: 941215976Sjmallett if (type == TC_SWITCH && level == 0) 942215976Sjmallett level = -1; 943215976Sjmallett break; 944215976Sjmallett } 945215976Sjmallett (void) getword(NULL); 946215976Sjmallett } while (level >= 0); 947215976Sjmallett} 948215976Sjmallett 949215976Sjmallettstatic int 950215976Sjmallettgetword(wp) 951215976Sjmallett Char *wp; 952215976Sjmallett{ 953215976Sjmallett int found = 0, first; 954215976Sjmallett eChar c, d; 955215976Sjmallett 956215976Sjmallett c = readc(1); 957215976Sjmallett d = 0; 958215976Sjmallett do { 959215976Sjmallett while (c == ' ' || c == '\t') 960215976Sjmallett c = readc(1); 961215976Sjmallett if (c == '#') 962215976Sjmallett do 963215976Sjmallett c = readc(1); 964215976Sjmallett while (c != CHAR_ERR && c != '\n'); 965215976Sjmallett if (c == CHAR_ERR) 966215976Sjmallett goto past; 967215976Sjmallett if (c == '\n') { 968215976Sjmallett if (wp) 969215976Sjmallett break; 970215976Sjmallett return (0); 971215976Sjmallett } 972215976Sjmallett unreadc(c); 973215976Sjmallett found = 1; 974215976Sjmallett first = 1; 975215976Sjmallett do { 976215976Sjmallett c = readc(1); 977215976Sjmallett if (c == '\\' && (c = readc(1)) == '\n') 978215976Sjmallett c = ' '; 979215976Sjmallett if (c == '\'' || c == '"') { 980215976Sjmallett if (d == 0) 981215976Sjmallett d = c; 982215976Sjmallett else if (d == c) 983215976Sjmallett d = 0; 984215976Sjmallett } 985215976Sjmallett if (c == CHAR_ERR) 986215976Sjmallett goto past; 987215976Sjmallett if (wp) { 988215976Sjmallett *wp++ = (Char) c; 989215976Sjmallett *wp = '\0'; 990215976Sjmallett } 991215976Sjmallett if (!first && !d && c == '(') { 992215976Sjmallett if (wp) { 993215976Sjmallett unreadc(c); 994215976Sjmallett *--wp = '\0'; 995215976Sjmallett return found; 996215976Sjmallett } 997215976Sjmallett else 998215976Sjmallett break; 999215976Sjmallett } 1000215976Sjmallett first = 0; 1001215976Sjmallett } while ((d || (c != ' ' && c != '\t')) && c != '\n'); 1002215976Sjmallett } while (wp == 0); 1003215976Sjmallett 1004215976Sjmallett unreadc(c); 1005215976Sjmallett if (found) 1006215976Sjmallett *--wp = '\0'; 1007215976Sjmallett 1008215976Sjmallett return (found); 1009215976Sjmallett 1010215976Sjmallettpast: 1011215976Sjmallett switch (Stype) { 1012215976Sjmallett 1013215976Sjmallett case TC_IF: 1014215976Sjmallett stderror(ERR_NAME | ERR_NOTFOUND, "then/endif"); 1015215976Sjmallett break; 1016215976Sjmallett 1017215976Sjmallett case TC_ELSE: 1018215976Sjmallett stderror(ERR_NAME | ERR_NOTFOUND, "endif"); 1019215976Sjmallett break; 1020215976Sjmallett 1021215976Sjmallett case TC_BRKSW: 1022215976Sjmallett case TC_SWITCH: 1023215976Sjmallett stderror(ERR_NAME | ERR_NOTFOUND, "endsw"); 1024215976Sjmallett break; 1025215976Sjmallett 1026215976Sjmallett case TC_BREAK: 1027215976Sjmallett stderror(ERR_NAME | ERR_NOTFOUND, "end"); 1028215976Sjmallett break; 1029215976Sjmallett 1030215976Sjmallett case TC_GOTO: 1031215976Sjmallett setname(short2str(Sgoal)); 1032215976Sjmallett stderror(ERR_NAME | ERR_NOTFOUND, "label"); 1033215976Sjmallett break; 1034215976Sjmallett 1035215976Sjmallett default: 1036215976Sjmallett break; 1037215976Sjmallett } 1038215976Sjmallett /* NOTREACHED */ 1039215976Sjmallett return (0); 1040215976Sjmallett} 1041215976Sjmallett 1042215976Sjmallettstatic void 1043215976Sjmalletttoend() 1044215976Sjmallett{ 1045215976Sjmallett if (whyles->w_end.type == TCSH_F_SEEK && whyles->w_end.f_seek == 0) { 1046215976Sjmallett search(TC_BREAK, 0, NULL); 1047215976Sjmallett btell(&whyles->w_end); 1048215976Sjmallett whyles->w_end.f_seek--; 1049215976Sjmallett } 1050215976Sjmallett else { 1051215976Sjmallett bseek(&whyles->w_end); 1052215976Sjmallett } 1053215976Sjmallett wfree(); 1054215976Sjmallett} 1055215976Sjmallett 1056215976Sjmallettstatic void 1057215976Sjmallettwpfree(wp) 1058215976Sjmallett struct whyle *wp; 1059215976Sjmallett{ 1060215976Sjmallett if (wp->w_fe0) 1061215976Sjmallett blkfree(wp->w_fe0); 1062215976Sjmallett if (wp->w_fename) 1063215976Sjmallett xfree((ptr_t) wp->w_fename); 1064215976Sjmallett xfree((ptr_t) wp); 1065215976Sjmallett} 1066215976Sjmallett 1067215976Sjmallettvoid 1068215976Sjmallettwfree() 1069215976Sjmallett{ 1070215976Sjmallett struct Ain o; 1071215976Sjmallett struct whyle *nwp; 1072215976Sjmallett#ifdef lint 1073215976Sjmallett nwp = NULL; /* sun lint is dumb! */ 1074215976Sjmallett#endif 1075215976Sjmallett 1076215976Sjmallett#ifdef FDEBUG 1077215976Sjmallett static char foo[] = "IAFE"; 1078215976Sjmallett#endif /* FDEBUG */ 1079215976Sjmallett 1080215976Sjmallett btell(&o); 1081215976Sjmallett 1082215976Sjmallett#ifdef FDEBUG 1083215976Sjmallett xprintf("o->type %c o->a_seek %d o->f_seek %d\n", 1084215976Sjmallett foo[o.type + 1], o.a_seek, o.f_seek); 1085215976Sjmallett#endif /* FDEBUG */ 1086215976Sjmallett 1087215976Sjmallett for (; whyles; whyles = nwp) { 1088215976Sjmallett struct whyle *wp = whyles; 1089215976Sjmallett nwp = wp->w_next; 1090215976Sjmallett 1091215976Sjmallett#ifdef FDEBUG 1092215976Sjmallett xprintf("start->type %c start->a_seek %d start->f_seek %d\n", 1093215976Sjmallett foo[wp->w_start.type+1], 1094215976Sjmallett wp->w_start.a_seek, wp->w_start.f_seek); 1095215976Sjmallett xprintf("end->type %c end->a_seek %d end->f_seek %d\n", 1096215976Sjmallett foo[wp->w_end.type + 1], wp->w_end.a_seek, wp->w_end.f_seek); 1097215976Sjmallett#endif /* FDEBUG */ 1098215976Sjmallett 1099215976Sjmallett /* 1100215976Sjmallett * XXX: We free loops that have different seek types. 1101215976Sjmallett */ 1102215976Sjmallett if (wp->w_end.type != TCSH_I_SEEK && wp->w_start.type == wp->w_end.type && 1103215976Sjmallett wp->w_start.type == o.type) { 1104215976Sjmallett if (wp->w_end.type == TCSH_F_SEEK) { 1105215976Sjmallett if (o.f_seek >= wp->w_start.f_seek && 1106215976Sjmallett (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek)) 1107215976Sjmallett break; 1108215976Sjmallett } 1109215976Sjmallett else { 1110215976Sjmallett if (o.a_seek >= wp->w_start.a_seek && 1111215976Sjmallett (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek)) 1112215976Sjmallett break; 1113215976Sjmallett } 1114215976Sjmallett } 1115215976Sjmallett 1116215976Sjmallett wpfree(wp); 1117215976Sjmallett } 1118215976Sjmallett} 1119215976Sjmallett 1120215976Sjmallett/*ARGSUSED*/ 1121215976Sjmallettvoid 1122215976Sjmallettdoecho(v, c) 1123215976Sjmallett Char **v; 1124215976Sjmallett struct command *c; 1125215976Sjmallett{ 1126215976Sjmallett USE(c); 1127215976Sjmallett xecho(' ', v); 1128215976Sjmallett} 1129215976Sjmallett 1130215976Sjmallett/*ARGSUSED*/ 1131215976Sjmallettvoid 1132215976Sjmallettdoglob(v, c) 1133215976Sjmallett Char **v; 1134215976Sjmallett struct command *c; 1135215976Sjmallett{ 1136215976Sjmallett USE(c); 1137215976Sjmallett xecho(0, v); 1138215976Sjmallett flush(); 1139215976Sjmallett} 1140215976Sjmallett 1141215976Sjmallettstatic void 1142215976Sjmallettxecho(sep, v) 1143215976Sjmallett int sep; 1144215976Sjmallett Char **v; 1145215976Sjmallett{ 1146215976Sjmallett Char *cp; 1147215976Sjmallett int nonl = 0; 1148215976Sjmallett#ifdef ECHO_STYLE 1149215976Sjmallett int echo_style = ECHO_STYLE; 1150215976Sjmallett#else /* !ECHO_STYLE */ 1151215976Sjmallett# if SYSVREL > 0 1152215976Sjmallett int echo_style = SYSV_ECHO; 1153215976Sjmallett# else /* SYSVREL == 0 */ 1154215976Sjmallett int echo_style = BSD_ECHO; 1155215976Sjmallett# endif /* SYSVREL */ 1156215976Sjmallett#endif /* ECHO_STYLE */ 1157215976Sjmallett struct varent *vp; 1158215976Sjmallett 1159215976Sjmallett if ((vp = adrof(STRecho_style)) != NULL && vp->vec != NULL && 1160215976Sjmallett vp->vec[0] != NULL) { 1161215976Sjmallett if (Strcmp(vp->vec[0], STRbsd) == 0) 1162215976Sjmallett echo_style = BSD_ECHO; 1163215976Sjmallett else if (Strcmp(vp->vec[0], STRsysv) == 0) 1164215976Sjmallett echo_style = SYSV_ECHO; 1165215976Sjmallett else if (Strcmp(vp->vec[0], STRboth) == 0) 1166215976Sjmallett echo_style = BOTH_ECHO; 1167215976Sjmallett else if (Strcmp(vp->vec[0], STRnone) == 0) 1168215976Sjmallett echo_style = NONE_ECHO; 1169215976Sjmallett } 1170215976Sjmallett 1171215976Sjmallett if (setintr) 1172215976Sjmallett#ifdef BSDSIGS 1173 (void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT)); 1174#else /* !BSDSIGS */ 1175 (void) sigrelse (SIGINT); 1176#endif /* BSDSIGS */ 1177 v++; 1178 if (*v == 0) 1179 goto done; 1180 gflag = 0, tglob(v); 1181 if (gflag) { 1182 v = globall(v); 1183 if (v == 0) 1184 stderror(ERR_NAME | ERR_NOMATCH); 1185 } 1186 else { 1187 v = gargv = saveblk(v); 1188 trim(v); 1189 } 1190 1191 if ((echo_style & BSD_ECHO) != 0 && sep == ' ' && *v && eq(*v, STRmn)) 1192 nonl++, v++; 1193 1194 while ((cp = *v++) != 0) { 1195 Char c; 1196 1197 while ((c = *cp++) != 0) { 1198 if ((echo_style & SYSV_ECHO) != 0 && c == '\\') { 1199 switch (c = *cp++) { 1200 case 'a': 1201 c = '\a'; 1202 break; 1203 case 'b': 1204 c = '\b'; 1205 break; 1206 case 'c': 1207 nonl = 1; 1208 goto done; 1209 case 'e': 1210#if 0 /* Windows does not understand \e */ 1211 c = '\e'; 1212#else 1213 c = '\033'; 1214#endif 1215 break; 1216 case 'f': 1217 c = '\f'; 1218 break; 1219 case 'n': 1220 c = '\n'; 1221 break; 1222 case 'r': 1223 c = '\r'; 1224 break; 1225 case 't': 1226 c = '\t'; 1227 break; 1228 case 'v': 1229 c = '\v'; 1230 break; 1231 case '\\': 1232 c = '\\'; 1233 break; 1234 case '0': 1235 c = 0; 1236 if (*cp >= '0' && *cp < '8') 1237 c = c * 8 + *cp++ - '0'; 1238 if (*cp >= '0' && *cp < '8') 1239 c = c * 8 + *cp++ - '0'; 1240 if (*cp >= '0' && *cp < '8') 1241 c = c * 8 + *cp++ - '0'; 1242 break; 1243 case '\0': 1244 c = '\\'; 1245 cp--; 1246 break; 1247 default: 1248 xputchar('\\' | QUOTE); 1249 break; 1250 } 1251 } 1252 xputwchar(c | QUOTE); 1253 1254 } 1255 if (*v) 1256 xputchar(sep | QUOTE); 1257 } 1258done: 1259 if (sep && nonl == 0) 1260 xputchar('\n'); 1261 else 1262 flush(); 1263 if (setintr) 1264#ifdef BSDSIGS 1265 (void) sigblock(sigmask(SIGINT)); 1266#else /* !BSDSIGS */ 1267 (void) sighold(SIGINT); 1268#endif /* BSDSIGS */ 1269 if (gargv) 1270 blkfree(gargv), gargv = 0; 1271} 1272 1273/* check whether an environment variable should invoke 'set_locale()' */ 1274static int 1275islocale_var(var) 1276 Char *var; 1277{ 1278 static Char *locale_vars[] = { 1279 STRLANG, STRLC_ALL, STRLC_CTYPE, STRLC_NUMERIC, 1280 STRLC_TIME, STRLC_COLLATE, STRLC_MESSAGES, STRLC_MONETARY, 0 1281 }; 1282 Char **v; 1283 1284 for (v = locale_vars; *v; ++v) 1285 if (eq(var, *v)) 1286 return 1; 1287 return 0; 1288} 1289 1290/*ARGSUSED*/ 1291void 1292doprintenv(v, c) 1293 Char **v; 1294 struct command *c; 1295{ 1296 Char *e; 1297 1298 USE(c); 1299 if (setintr) 1300#ifdef BSDSIGS 1301 (void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT)); 1302#else /* !BSDSIGS */ 1303 (void) sigrelse (SIGINT); 1304#endif /* BSDSIGS */ 1305 1306 v++; 1307 if (*v == 0) { 1308 Char **ep; 1309 1310 xlate_cr = 1; 1311 for (ep = STR_environ; *ep; ep++) 1312 xprintf("%S\n", *ep); 1313 xlate_cr = 0; 1314 } 1315 else if ((e = tgetenv(*v)) != NULL) { 1316 output_raw = 1; 1317 xprintf("%S\n", e); 1318 output_raw = 0; 1319 } 1320 else 1321 set(STRstatus, Strsave(STR1), VAR_READWRITE); 1322} 1323 1324/* from "Karl Berry." <karl%mote.umb.edu@relay.cs.net> -- for NeXT things 1325 (and anything else with a modern compiler) */ 1326 1327/*ARGSUSED*/ 1328void 1329dosetenv(v, c) 1330 Char **v; 1331 struct command *c; 1332{ 1333 Char *vp, *lp; 1334 1335 USE(c); 1336 if (*++v == 0) { 1337 doprintenv(--v, 0); 1338 return; 1339 } 1340 1341 vp = *v++; 1342 1343 lp = vp; 1344 1345 for (; *lp != '\0' ; lp++) { 1346 if (*lp == '=') 1347 stderror(ERR_NAME | ERR_SYNTAX); 1348 } 1349 if ((lp = *v++) == 0) 1350 lp = STRNULL; 1351 1352 tsetenv(vp, lp = globone(lp, G_APPEND)); 1353 if (eq(vp, STRKPATH)) { 1354 importpath(lp); 1355 dohash(NULL, NULL); 1356 xfree((ptr_t) lp); 1357 return; 1358 } 1359 1360#ifdef apollo 1361 if (eq(vp, STRSYSTYPE)) { 1362 dohash(NULL, NULL); 1363 xfree((ptr_t) lp); 1364 return; 1365 } 1366#endif /* apollo */ 1367 1368 /* dspkanji/dspmbyte autosetting */ 1369 /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */ 1370#if defined(DSPMBYTE) 1371 if(eq(vp, STRLANG) && !adrof(CHECK_MBYTEVAR)) { 1372 autoset_dspmbyte(lp); 1373 } 1374#endif 1375 1376 if (islocale_var(vp)) { 1377#ifdef NLS 1378 int k; 1379 1380# ifdef SETLOCALEBUG 1381 dont_free = 1; 1382# endif /* SETLOCALEBUG */ 1383 (void) setlocale(LC_ALL, ""); 1384# ifdef LC_COLLATE 1385 (void) setlocale(LC_COLLATE, ""); 1386# endif 1387# ifdef LC_CTYPE 1388 (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 1389# endif /* LC_CTYPE */ 1390# ifdef NLS_CATALOGS 1391# ifdef LC_MESSAGES 1392 (void) setlocale(LC_MESSAGES, ""); 1393# endif /* LC_MESSAGES */ 1394 nlsclose(); 1395 nlsinit(); 1396# endif /* NLS_CATALOGS */ 1397# ifdef SETLOCALEBUG 1398 dont_free = 0; 1399# endif /* SETLOCALEBUG */ 1400# ifdef STRCOLLBUG 1401 fix_strcoll_bug(); 1402# endif /* STRCOLLBUG */ 1403 tw_cmd_free(); /* since the collation sequence has changed */ 1404 for (k = 0200; k <= 0377 && !Isprint(k); k++) 1405 continue; 1406 AsciiOnly = MB_CUR_MAX == 1 && k > 0377; 1407#else /* !NLS */ 1408 AsciiOnly = 0; 1409#endif /* NLS */ 1410 NLSMapsAreInited = 0; 1411 ed_Init(); 1412 if (MapsAreInited && !NLSMapsAreInited) 1413 ed_InitNLSMaps(); 1414 xfree((ptr_t) lp); 1415 return; 1416 } 1417 1418#ifdef NLS_CATALOGS 1419 if (eq(vp, STRNLSPATH)) { 1420 nlsclose(); 1421 nlsinit(); 1422 } 1423#endif 1424 1425 if (eq(vp, STRNOREBIND)) { 1426 NoNLSRebind = 1; 1427 MapsAreInited = 0; 1428 NLSMapsAreInited = 0; 1429 ed_InitMaps(); 1430 xfree((ptr_t) lp); 1431 return; 1432 } 1433#ifdef WINNT_NATIVE 1434 if (eq(vp, STRtcshlang)) { 1435 nlsinit(); 1436 xfree((ptr_t) lp); 1437 return; 1438 } 1439#endif /* WINNT_NATIVE */ 1440 if (eq(vp, STRKTERM)) { 1441 char *t; 1442 set(STRterm, quote(lp), VAR_READWRITE); /* lp memory used here */ 1443 t = short2str(lp); 1444 if (noediting && strcmp(t, "unknown") != 0 && strcmp(t,"dumb") != 0) { 1445 editing = 1; 1446 noediting = 0; 1447 set(STRedit, Strsave(STRNULL), VAR_READWRITE); 1448 } 1449 GotTermCaps = 0; 1450 ed_Init(); 1451 return; 1452 } 1453 1454 if (eq(vp, STRKHOME)) { 1455 /* 1456 * convert to canonical pathname (possibly resolving symlinks) 1457 */ 1458 lp = dcanon(lp, lp); 1459 set(STRhome, quote(lp), VAR_READWRITE); /* cp memory used here */ 1460 1461 /* fix directory stack for new tilde home */ 1462 dtilde(); 1463 return; 1464 } 1465 1466 if (eq(vp, STRKSHLVL)) { 1467 /* lp memory used here */ 1468 set(STRshlvl, quote(lp), VAR_READWRITE); 1469 return; 1470 } 1471 1472 if (eq(vp, STRKUSER)) { 1473 set(STRuser, quote(lp), VAR_READWRITE); /* lp memory used here */ 1474 return; 1475 } 1476 1477 if (eq(vp, STRKGROUP)) { 1478 set(STRgroup, quote(lp), VAR_READWRITE); /* lp memory used here */ 1479 return; 1480 } 1481 1482#ifdef COLOR_LS_F 1483 if (eq(vp, STRLS_COLORS)) { 1484 parseLS_COLORS(lp); 1485 return; 1486 } 1487#endif /* COLOR_LS_F */ 1488 1489#ifdef SIG_WINDOW 1490 /* 1491 * Load/Update $LINES $COLUMNS 1492 */ 1493 if ((eq(lp, STRNULL) && (eq(vp, STRLINES) || eq(vp, STRCOLUMNS))) || 1494 eq(vp, STRTERMCAP)) { 1495 xfree((ptr_t) lp); 1496 check_window_size(1); 1497 return; 1498 } 1499 1500 /* 1501 * Change the size to the one directed by $LINES and $COLUMNS 1502 */ 1503 if (eq(vp, STRLINES) || eq(vp, STRCOLUMNS)) { 1504#if 0 1505 GotTermCaps = 0; 1506#endif 1507 xfree((ptr_t) lp); 1508 ed_Init(); 1509 return; 1510 } 1511#endif /* SIG_WINDOW */ 1512 xfree((ptr_t) lp); 1513} 1514 1515/*ARGSUSED*/ 1516void 1517dounsetenv(v, c) 1518 Char **v; 1519 struct command *c; 1520{ 1521 Char **ep, *p, *n; 1522 int i, maxi; 1523 static Char *name = NULL; 1524 1525 USE(c); 1526 if (name) 1527 xfree((ptr_t) name); 1528 /* 1529 * Find the longest environment variable 1530 */ 1531 for (maxi = 0, ep = STR_environ; *ep; ep++) { 1532 for (i = 0, p = *ep; *p && *p != '='; p++, i++) 1533 continue; 1534 if (i > maxi) 1535 maxi = i; 1536 } 1537 1538 name = (Char *) xmalloc((size_t) ((maxi + 1) * sizeof(Char))); 1539 1540 while (++v && *v) 1541 for (maxi = 1; maxi;) 1542 for (maxi = 0, ep = STR_environ; *ep; ep++) { 1543 for (n = name, p = *ep; *p && *p != '='; *n++ = *p++) 1544 continue; 1545 *n = '\0'; 1546 if (!Gmatch(name, *v)) 1547 continue; 1548 maxi = 1; 1549 1550 /* Unset the name. This wasn't being done until 1551 * later but most of the stuff following won't 1552 * work (particularly the setlocale() and getenv() 1553 * stuff) as intended until the name is actually 1554 * removed. (sg) 1555 */ 1556 Unsetenv(name); 1557 1558 if (eq(name, STRNOREBIND)) { 1559 NoNLSRebind = 0; 1560 MapsAreInited = 0; 1561 NLSMapsAreInited = 0; 1562 ed_InitMaps(); 1563 } 1564#ifdef apollo 1565 else if (eq(name, STRSYSTYPE)) 1566 dohash(NULL, NULL); 1567#endif /* apollo */ 1568 else if (islocale_var(name)) { 1569#ifdef NLS 1570 int k; 1571 1572# ifdef SETLOCALEBUG 1573 dont_free = 1; 1574# endif /* SETLOCALEBUG */ 1575 (void) setlocale(LC_ALL, ""); 1576# ifdef LC_COLLATE 1577 (void) setlocale(LC_COLLATE, ""); 1578# endif 1579# ifdef LC_CTYPE 1580 (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 1581# endif /* LC_CTYPE */ 1582# ifdef NLS_CATALOGS 1583# ifdef LC_MESSAGES 1584 (void) setlocale(LC_MESSAGES, ""); 1585# endif /* LC_MESSAGES */ 1586 nlsclose(); 1587 nlsinit(); 1588# endif /* NLS_CATALOGS */ 1589# ifdef SETLOCALEBUG 1590 dont_free = 0; 1591# endif /* SETLOCALEBUG */ 1592# ifdef STRCOLLBUG 1593 fix_strcoll_bug(); 1594# endif /* STRCOLLBUG */ 1595 tw_cmd_free();/* since the collation sequence has changed */ 1596 for (k = 0200; k <= 0377 && !Isprint(k); k++) 1597 continue; 1598 AsciiOnly = MB_CUR_MAX == 1 && k > 0377; 1599#else /* !NLS */ 1600 AsciiOnly = getenv("LANG") == NULL && 1601 getenv("LC_CTYPE") == NULL; 1602#endif /* NLS */ 1603 NLSMapsAreInited = 0; 1604 ed_Init(); 1605 if (MapsAreInited && !NLSMapsAreInited) 1606 ed_InitNLSMaps(); 1607 1608 } 1609#ifdef WINNT_NATIVE 1610 else if (eq(name,(STRtcshlang))) { 1611 nls_dll_unload(); 1612 nlsinit(); 1613 } 1614#endif /* WINNT_NATIVE */ 1615#ifdef COLOR_LS_F 1616 else if (eq(name, STRLS_COLORS)) 1617 parseLS_COLORS(n); 1618#endif /* COLOR_LS_F */ 1619#ifdef NLS_CATALOGS 1620 else if (eq(name, STRNLSPATH)) { 1621 nlsclose(); 1622 nlsinit(); 1623 } 1624#endif 1625 /* 1626 * start again cause the environment changes 1627 */ 1628 break; 1629 } 1630 xfree((ptr_t) name); name = NULL; 1631} 1632 1633void 1634tsetenv(name, val) 1635 const Char *name, *val; 1636{ 1637#ifdef SETENV_IN_LIB 1638/* 1639 * XXX: This does not work right, since tcsh cannot track changes to 1640 * the environment this way. (the builtin setenv without arguments does 1641 * not print the right stuff neither does unsetenv). This was for Mach, 1642 * it is not needed anymore. 1643 */ 1644#undef setenv 1645 char nameBuf[BUFSIZE]; 1646 char *cname = short2str(name); 1647 1648 if (cname == NULL) 1649 return; 1650 (void) strcpy(nameBuf, cname); 1651 setenv(nameBuf, short2str(val), 1); 1652#else /* !SETENV_IN_LIB */ 1653 Char **ep = STR_environ; 1654 const Char *ccp; 1655 Char *cp, *dp; 1656 Char *blk[2]; 1657 Char **oep = ep; 1658 1659#ifdef WINNT_NATIVE 1660 nt_set_env(name,val); 1661#endif /* WINNT_NATIVE */ 1662 for (; *ep; ep++) { 1663#ifdef WINNT_NATIVE 1664 for (ccp = name, dp = *ep; *ccp && Tolower(*ccp & TRIM) == Tolower(*dp); 1665 ccp++, dp++) 1666#else 1667 for (ccp = name, dp = *ep; *ccp && (*ccp & TRIM) == *dp; ccp++, dp++) 1668#endif /* WINNT_NATIVE */ 1669 continue; 1670 if (*ccp != 0 || *dp != '=') 1671 continue; 1672 cp = Strspl(STRequal, val); 1673 xfree((ptr_t) * ep); 1674 *ep = strip(Strspl(name, cp)); 1675 xfree((ptr_t) cp); 1676 blkfree((Char **) environ); 1677 environ = short2blk(STR_environ); 1678 return; 1679 } 1680 cp = Strspl(name, STRequal); 1681 blk[0] = strip(Strspl(cp, val)); 1682 xfree((ptr_t) cp); 1683 blk[1] = 0; 1684 STR_environ = blkspl(STR_environ, blk); 1685 blkfree((Char **) environ); 1686 environ = short2blk(STR_environ); 1687 xfree((ptr_t) oep); 1688#endif /* SETENV_IN_LIB */ 1689} 1690 1691void 1692Unsetenv(name) 1693 Char *name; 1694{ 1695 Char **ep = STR_environ; 1696 Char *cp, *dp; 1697 Char **oep = ep; 1698 1699#ifdef WINNT_NATIVE 1700 nt_set_env(name,NULL); 1701#endif /*WINNT_NATIVE */ 1702 for (; *ep; ep++) { 1703 for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) 1704 continue; 1705 if (*cp != 0 || *dp != '=') 1706 continue; 1707 cp = *ep; 1708 *ep = 0; 1709 STR_environ = blkspl(STR_environ, ep + 1); 1710 blkfree((Char **) environ); 1711 environ = short2blk(STR_environ); 1712 *ep = cp; 1713 xfree((ptr_t) cp); 1714 xfree((ptr_t) oep); 1715 return; 1716 } 1717} 1718 1719/*ARGSUSED*/ 1720void 1721doumask(v, c) 1722 Char **v; 1723 struct command *c; 1724{ 1725 Char *cp = v[1]; 1726 int i; 1727 1728 USE(c); 1729 if (cp == 0) { 1730 i = (int)umask(0); 1731 (void) umask(i); 1732 xprintf("%o\n", i); 1733 return; 1734 } 1735 i = 0; 1736 while (Isdigit(*cp) && *cp != '8' && *cp != '9') 1737 i = i * 8 + *cp++ - '0'; 1738 if (*cp || i < 0 || i > 0777) 1739 stderror(ERR_NAME | ERR_MASK); 1740 (void) umask(i); 1741} 1742 1743#ifndef HAVENOLIMIT 1744# ifndef BSDLIMIT 1745 typedef long RLIM_TYPE; 1746# ifdef _OSD_POSIX /* BS2000 */ 1747# include <ulimit.h> 1748# endif 1749# ifndef RLIM_INFINITY 1750# if !defined(_MINIX) && !defined(__clipper__) && !defined(_CRAY) 1751 extern RLIM_TYPE ulimit(); 1752# endif /* ! _MINIX && !__clipper__ */ 1753# define RLIM_INFINITY 0x003fffff 1754# define RLIMIT_FSIZE 1 1755# endif /* RLIM_INFINITY */ 1756# ifdef aiws 1757# define toset(a) (((a) == 3) ? 1004 : (a) + 1) 1758# define RLIMIT_DATA 3 1759# define RLIMIT_STACK 1005 1760# else /* aiws */ 1761# define toset(a) ((a) + 1) 1762# endif /* aiws */ 1763# else /* BSDLIMIT */ 1764# if (defined(BSD4_4) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) || (HPUXVERSION >= 1100)) && !defined(__386BSD__) 1765 typedef rlim_t RLIM_TYPE; 1766# else 1767# if defined(SOLARIS2) || (defined(sgi) && SYSVREL > 3) 1768 typedef rlim_t RLIM_TYPE; 1769# else 1770# if defined(_SX) 1771 typedef long long RLIM_TYPE; 1772# else /* !_SX */ 1773 typedef unsigned long RLIM_TYPE; 1774# endif /* _SX */ 1775# endif /* SOLARIS2 || (sgi && SYSVREL > 3) */ 1776# endif /* BSD4_4 && !__386BSD__ */ 1777# endif /* BSDLIMIT */ 1778 1779# if (HPUXVERSION > 700) && (HPUXVERSION < 1100) && defined(BSDLIMIT) 1780/* Yes hpux8.0 has limits but <sys/resource.h> does not make them public */ 1781/* Yes, we could have defined _KERNEL, and -I/etc/conf/h, but is that better? */ 1782# ifndef RLIMIT_CPU 1783# define RLIMIT_CPU 0 1784# define RLIMIT_FSIZE 1 1785# define RLIMIT_DATA 2 1786# define RLIMIT_STACK 3 1787# define RLIMIT_CORE 4 1788# define RLIMIT_RSS 5 1789# define RLIMIT_NOFILE 6 1790# endif /* RLIMIT_CPU */ 1791# ifndef RLIM_INFINITY 1792# define RLIM_INFINITY 0x7fffffff 1793# endif /* RLIM_INFINITY */ 1794 /* 1795 * old versions of HP/UX counted limits in 512 bytes 1796 */ 1797# ifndef SIGRTMIN 1798# define FILESIZE512 1799# endif /* SIGRTMIN */ 1800# endif /* (HPUXVERSION > 700) && (HPUXVERSION < 1100) && BSDLIMIT */ 1801 1802# if SYSVREL > 3 && defined(BSDLIMIT) && !defined(_SX) 1803/* In order to use rusage, we included "/usr/ucbinclude/sys/resource.h" in */ 1804/* sh.h. However, some SVR4 limits are defined in <sys/resource.h>. Rather */ 1805/* than include both and get warnings, we define the extra SVR4 limits here. */ 1806/* XXX: I don't understand if RLIMIT_AS is defined, why don't we define */ 1807/* RLIMIT_VMEM based on it? */ 1808# ifndef RLIMIT_VMEM 1809# define RLIMIT_VMEM 6 1810# endif 1811# ifndef RLIMIT_AS 1812# define RLIMIT_AS RLIMIT_VMEM 1813# endif 1814# endif /* SYSVREL > 3 && BSDLIMIT */ 1815 1816# if (defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) && defined(RLIMIT_AS) && !defined(RLIMIT_VMEM) 1817# define RLIMIT_VMEM RLIMIT_AS 1818# endif 1819 1820struct limits limits[] = 1821{ 1822# ifdef RLIMIT_CPU 1823 { RLIMIT_CPU, "cputime", 1, "seconds" }, 1824# endif /* RLIMIT_CPU */ 1825 1826# ifdef RLIMIT_FSIZE 1827# ifndef aiws 1828 { RLIMIT_FSIZE, "filesize", 1024, "kbytes" }, 1829# else 1830 { RLIMIT_FSIZE, "filesize", 512, "blocks" }, 1831# endif /* aiws */ 1832# endif /* RLIMIT_FSIZE */ 1833 1834# ifdef RLIMIT_DATA 1835 { RLIMIT_DATA, "datasize", 1024, "kbytes" }, 1836# endif /* RLIMIT_DATA */ 1837 1838# ifdef RLIMIT_STACK 1839# ifndef aiws 1840 { RLIMIT_STACK, "stacksize", 1024, "kbytes" }, 1841# else 1842 { RLIMIT_STACK, "stacksize", 1024 * 1024, "kbytes"}, 1843# endif /* aiws */ 1844# endif /* RLIMIT_STACK */ 1845 1846# ifdef RLIMIT_CORE 1847 { RLIMIT_CORE, "coredumpsize", 1024, "kbytes" }, 1848# endif /* RLIMIT_CORE */ 1849 1850# ifdef RLIMIT_RSS 1851 { RLIMIT_RSS, "memoryuse", 1024, "kbytes" }, 1852# endif /* RLIMIT_RSS */ 1853 1854# ifdef RLIMIT_UMEM 1855 { RLIMIT_UMEM, "memoryuse", 1024, "kbytes" }, 1856# endif /* RLIMIT_UMEM */ 1857 1858# ifdef RLIMIT_VMEM 1859 { RLIMIT_VMEM, "vmemoryuse", 1024, "kbytes" }, 1860# endif /* RLIMIT_VMEM */ 1861 1862# if defined(RLIMIT_HEAP) /* found on BS2000/OSD systems */ 1863 { RLIMIT_HEAP, "heapsize", 1024, "kbytes" }, 1864# endif /* RLIMIT_HEAP */ 1865 1866# ifdef RLIMIT_NOFILE 1867 { RLIMIT_NOFILE, "descriptors", 1, "" }, 1868# endif /* RLIMIT_NOFILE */ 1869 1870# ifdef RLIMIT_CONCUR 1871 { RLIMIT_CONCUR, "concurrency", 1, "thread(s)" }, 1872# endif /* RLIMIT_CONCUR */ 1873 1874# ifdef RLIMIT_MEMLOCK 1875 { RLIMIT_MEMLOCK, "memorylocked", 1024, "kbytes" }, 1876# endif /* RLIMIT_MEMLOCK */ 1877 1878# ifdef RLIMIT_NPROC 1879 { RLIMIT_NPROC, "maxproc", 1, "" }, 1880# endif /* RLIMIT_NPROC */ 1881 1882# if defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE) 1883 { RLIMIT_OFILE, "openfiles", 1, "" }, 1884# endif /* RLIMIT_OFILE && !defined(RLIMIT_NOFILE) */ 1885 1886# ifdef RLIMIT_SBSIZE 1887 { RLIMIT_SBSIZE, "sbsize", 1, "" }, 1888# endif /* RLIMIT_SBSIZE */ 1889 1890 { -1, NULL, 0, NULL } 1891}; 1892 1893static struct limits *findlim __P((Char *)); 1894static RLIM_TYPE getval __P((struct limits *, Char **)); 1895static void limtail __P((Char *, const char *)); 1896static void plim __P((struct limits *, int)); 1897static int setlim __P((struct limits *, int, RLIM_TYPE)); 1898 1899#ifdef convex 1900static RLIM_TYPE 1901restrict_limit(value) 1902 double value; 1903{ 1904 /* 1905 * is f too large to cope with? return the maximum or minimum int 1906 */ 1907 if (value > (double) INT_MAX) 1908 return (RLIM_TYPE) INT_MAX; 1909 else if (value < (double) INT_MIN) 1910 return (RLIM_TYPE) INT_MIN; 1911 else 1912 return (RLIM_TYPE) value; 1913} 1914#else /* !convex */ 1915# define restrict_limit(x) ((RLIM_TYPE) (x)) 1916#endif /* convex */ 1917 1918 1919static struct limits * 1920findlim(cp) 1921 Char *cp; 1922{ 1923 struct limits *lp, *res; 1924 1925 res = (struct limits *) NULL; 1926 for (lp = limits; lp->limconst >= 0; lp++) 1927 if (prefix(cp, str2short(lp->limname))) { 1928 if (res) 1929 stderror(ERR_NAME | ERR_AMBIG); 1930 res = lp; 1931 } 1932 if (res) 1933 return (res); 1934 stderror(ERR_NAME | ERR_LIMIT); 1935 /* NOTREACHED */ 1936 return (0); 1937} 1938 1939/*ARGSUSED*/ 1940void 1941dolimit(v, c) 1942 Char **v; 1943 struct command *c; 1944{ 1945 struct limits *lp; 1946 RLIM_TYPE limit; 1947 int hard = 0; 1948 1949 USE(c); 1950 v++; 1951 if (*v && eq(*v, STRmh)) { 1952 hard = 1; 1953 v++; 1954 } 1955 if (*v == 0) { 1956 for (lp = limits; lp->limconst >= 0; lp++) 1957 plim(lp, hard); 1958 return; 1959 } 1960 lp = findlim(v[0]); 1961 if (v[1] == 0) { 1962 plim(lp, hard); 1963 return; 1964 } 1965 limit = getval(lp, v + 1); 1966 if (setlim(lp, hard, limit) < 0) 1967 stderror(ERR_SILENT); 1968} 1969 1970static RLIM_TYPE 1971getval(lp, v) 1972 struct limits *lp; 1973 Char **v; 1974{ 1975 float f; 1976 Char *cp = *v++; 1977 1978 f = atof(short2str(cp)); 1979 1980# ifdef convex 1981 /* 1982 * is f too large to cope with. limit f to minint, maxint - X-6768 by 1983 * strike 1984 */ 1985 if ((f < (double) INT_MIN) || (f > (double) INT_MAX)) { 1986 stderror(ERR_NAME | ERR_TOOLARGE); 1987 } 1988# endif /* convex */ 1989 1990 while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') 1991 cp++; 1992 if (*cp == 0) { 1993 if (*v == 0) 1994 return restrict_limit((f * lp->limdiv) + 0.5); 1995 cp = *v; 1996 } 1997 switch (*cp) { 1998# ifdef RLIMIT_CPU 1999 case ':': 2000 if (lp->limconst != RLIMIT_CPU) 2001 goto badscal; 2002 return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f * 60.0 + atof(short2str(cp + 1)))); 2003 case 'h': 2004 if (lp->limconst != RLIMIT_CPU) 2005 goto badscal; 2006 limtail(cp, "hours"); 2007 f *= 3600.0; 2008 break; 2009 case 'm': 2010 if (lp->limconst == RLIMIT_CPU) { 2011 limtail(cp, "minutes"); 2012 f *= 60.0; 2013 break; 2014 } 2015 *cp = 'm'; 2016 limtail(cp, "megabytes"); 2017 f *= 1024.0 * 1024.0; 2018 break; 2019 case 's': 2020 if (lp->limconst != RLIMIT_CPU) 2021 goto badscal; 2022 limtail(cp, "seconds"); 2023 break; 2024# endif /* RLIMIT_CPU */ 2025 case 'M': 2026# ifdef RLIMIT_CPU 2027 if (lp->limconst == RLIMIT_CPU) 2028 goto badscal; 2029# endif /* RLIMIT_CPU */ 2030 *cp = 'm'; 2031 limtail(cp, "megabytes"); 2032 f *= 1024.0 * 1024.0; 2033 break; 2034 case 'k': 2035# ifdef RLIMIT_CPU 2036 if (lp->limconst == RLIMIT_CPU) 2037 goto badscal; 2038# endif /* RLIMIT_CPU */ 2039 limtail(cp, "kbytes"); 2040 f *= 1024.0; 2041 break; 2042 case 'b': 2043# ifdef RLIMIT_CPU 2044 if (lp->limconst == RLIMIT_CPU) 2045 goto badscal; 2046# endif /* RLIMIT_CPU */ 2047 limtail(cp, "blocks"); 2048 f *= 512.0; 2049 break; 2050 case 'u': 2051 limtail(cp, "unlimited"); 2052 return ((RLIM_TYPE) RLIM_INFINITY); 2053 default: 2054# ifdef RLIMIT_CPU 2055badscal: 2056# endif /* RLIMIT_CPU */ 2057 stderror(ERR_NAME | ERR_SCALEF); 2058 } 2059# ifdef convex 2060 return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f + 0.5)); 2061# else 2062 f += 0.5; 2063 if (f > (float) RLIM_INFINITY) 2064 return ((RLIM_TYPE) RLIM_INFINITY); 2065 else 2066 return ((RLIM_TYPE) f); 2067# endif /* convex */ 2068} 2069 2070static void 2071limtail(cp, str) 2072 Char *cp; 2073 const char *str; 2074{ 2075 const char *sp; 2076 2077 sp = str; 2078 while (*cp && *cp == (Char)*str) 2079 cp++, str++; 2080 if (*cp) 2081 stderror(ERR_BADSCALE, sp); 2082} 2083 2084 2085/*ARGSUSED*/ 2086static void 2087plim(lp, hard) 2088 struct limits *lp; 2089 int hard; 2090{ 2091# ifdef BSDLIMIT 2092 struct rlimit rlim; 2093# endif /* BSDLIMIT */ 2094 RLIM_TYPE limit; 2095 int xdiv = lp->limdiv; 2096 2097 xprintf("%-13.13s", lp->limname); 2098 2099# ifndef BSDLIMIT 2100 limit = ulimit(lp->limconst, 0); 2101# ifdef aiws 2102 if (lp->limconst == RLIMIT_DATA) 2103 limit -= 0x20000000; 2104# endif /* aiws */ 2105# else /* BSDLIMIT */ 2106 (void) getrlimit(lp->limconst, &rlim); 2107 limit = hard ? rlim.rlim_max : rlim.rlim_cur; 2108# endif /* BSDLIMIT */ 2109 2110# if !defined(BSDLIMIT) || defined(FILESIZE512) 2111 /* 2112 * Christos: filesize comes in 512 blocks. we divide by 2 to get 1024 2113 * blocks. Note we cannot pre-multiply cause we might overflow (A/UX) 2114 */ 2115 if (lp->limconst == RLIMIT_FSIZE) { 2116 if (limit >= (RLIM_INFINITY / 512)) 2117 limit = RLIM_INFINITY; 2118 else 2119 xdiv = (xdiv == 1024 ? 2 : 1); 2120 } 2121# endif /* !BSDLIMIT || FILESIZE512 */ 2122 2123 if (limit == RLIM_INFINITY) 2124 xprintf("unlimited"); 2125 else 2126# if defined(RLIMIT_CPU) && defined(_OSD_POSIX) 2127 if (lp->limconst == RLIMIT_CPU && 2128 (unsigned long)limit >= 0x7ffffffdUL) 2129 xprintf("unlimited"); 2130 else 2131# endif 2132# ifdef RLIMIT_CPU 2133 if (lp->limconst == RLIMIT_CPU) 2134 psecs((long) limit); 2135 else 2136# endif /* RLIMIT_CPU */ 2137 xprintf("%ld %s", (long) (limit / xdiv), lp->limscale); 2138 xputchar('\n'); 2139} 2140 2141/*ARGSUSED*/ 2142void 2143dounlimit(v, c) 2144 Char **v; 2145 struct command *c; 2146{ 2147 struct limits *lp; 2148 int lerr = 0; 2149 int hard = 0; 2150 int force = 0; 2151 2152 USE(c); 2153 while (*++v && **v == '-') { 2154 Char *vp = *v; 2155 while (*++vp) 2156 switch (*vp) { 2157 case 'f': 2158 force = 1; 2159 break; 2160 case 'h': 2161 hard = 1; 2162 break; 2163 default: 2164 stderror(ERR_ULIMUS); 2165 break; 2166 } 2167 } 2168 2169 if (*v == 0) { 2170 for (lp = limits; lp->limconst >= 0; lp++) 2171 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0) 2172 lerr++; 2173 if (!force && lerr) 2174 stderror(ERR_SILENT); 2175 return; 2176 } 2177 while (*v) { 2178 lp = findlim(*v++); 2179 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0 && !force) 2180 stderror(ERR_SILENT); 2181 } 2182} 2183 2184static int 2185setlim(lp, hard, limit) 2186 struct limits *lp; 2187 int hard; 2188 RLIM_TYPE limit; 2189{ 2190# ifdef BSDLIMIT 2191 struct rlimit rlim; 2192 2193 (void) getrlimit(lp->limconst, &rlim); 2194 2195# ifdef FILESIZE512 2196 /* Even though hpux has setrlimit(), it expects fsize in 512 byte blocks */ 2197 if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 2198 limit /= 512; 2199# endif /* FILESIZE512 */ 2200 if (hard) 2201 rlim.rlim_max = limit; 2202 else if (limit == RLIM_INFINITY && euid != 0) 2203 rlim.rlim_cur = rlim.rlim_max; 2204 else 2205 rlim.rlim_cur = limit; 2206 2207 if (rlim.rlim_cur > rlim.rlim_max) 2208 rlim.rlim_max = rlim.rlim_cur; 2209 2210 if (setrlimit(lp->limconst, &rlim) < 0) { 2211# else /* BSDLIMIT */ 2212 if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 2213 limit /= 512; 2214# ifdef aiws 2215 if (lp->limconst == RLIMIT_DATA) 2216 limit += 0x20000000; 2217# endif /* aiws */ 2218 if (ulimit(toset(lp->limconst), limit) < 0) { 2219# endif /* BSDLIMIT */ 2220 int err; 2221 char *op, *type; 2222 2223 err = errno; 2224 op = strsave(limit == RLIM_INFINITY ? CGETS(15, 2, "remove") : 2225 CGETS(15, 3, "set")); 2226 type = strsave(hard ? CGETS(15, 4, " hard") : ""); 2227 xprintf(CGETS(15, 1, "%s: %s: Can't %s%s limit (%s)\n"), bname, 2228 lp->limname, op, type, strerror(err)); 2229 xfree(type); 2230 xfree(op); 2231 return (-1); 2232 } 2233 return (0); 2234} 2235 2236#endif /* !HAVENOLIMIT */ 2237 2238/*ARGSUSED*/ 2239void 2240dosuspend(v, c) 2241 Char **v; 2242 struct command *c; 2243{ 2244#ifdef BSDJOBS 2245 int ctpgrp; 2246 2247 signalfun_t old; 2248#endif /* BSDJOBS */ 2249 2250 USE(c); 2251 USE(v); 2252 2253 if (loginsh) 2254 stderror(ERR_SUSPLOG); 2255 untty(); 2256 2257#ifdef BSDJOBS 2258 old = signal(SIGTSTP, SIG_DFL); 2259 (void) kill(0, SIGTSTP); 2260 /* the shell stops here */ 2261 (void) signal(SIGTSTP, old); 2262#else /* !BSDJOBS */ 2263 stderror(ERR_JOBCONTROL); 2264#endif /* BSDJOBS */ 2265 2266#ifdef BSDJOBS 2267 if (tpgrp != -1) { 2268retry: 2269 ctpgrp = tcgetpgrp(FSHTTY); 2270 if (ctpgrp == -1) 2271 stderror(ERR_SYSTEM, "tcgetpgrp", strerror(errno)); 2272 if (ctpgrp != opgrp) { 2273 old = signal(SIGTTIN, SIG_DFL); 2274 (void) kill(0, SIGTTIN); 2275 (void) signal(SIGTTIN, old); 2276 goto retry; 2277 } 2278 (void) setpgid(0, shpgrp); 2279 (void) tcsetpgrp(FSHTTY, shpgrp); 2280 } 2281#endif /* BSDJOBS */ 2282 (void) setdisc(FSHTTY); 2283} 2284 2285/* This is the dreaded EVAL built-in. 2286 * If you don't fiddle with file descriptors, and reset didfds, 2287 * this command will either ignore redirection inside or outside 2288 * its arguments, e.g. eval "date >x" vs. eval "date" >x 2289 * The stuff here seems to work, but I did it by trial and error rather 2290 * than really knowing what was going on. If tpgrp is zero, we are 2291 * probably a background eval, e.g. "eval date &", and we want to 2292 * make sure that any processes we start stay in our pgrp. 2293 * This is also the case for "time eval date" -- stay in same pgrp. 2294 * Otherwise, under stty tostop, processes will stop in the wrong 2295 * pgrp, with no way for the shell to get them going again. -IAN! 2296 */ 2297 2298static Char **gv = NULL, **gav = NULL; 2299 2300/*ARGSUSED*/ 2301void 2302doeval(v, c) 2303 Char **v; 2304 struct command *c; 2305{ 2306 Char **oevalvec; 2307 Char *oevalp; 2308 int odidfds; 2309#ifndef CLOSE_ON_EXEC 2310 int odidcch; 2311#endif /* CLOSE_ON_EXEC */ 2312 jmp_buf_t osetexit; 2313 int my_reenter; 2314 Char **savegv; 2315 int saveIN, saveOUT, saveDIAG; 2316 int oSHIN, oSHOUT, oSHDIAG; 2317 2318 USE(c); 2319 oevalvec = evalvec; 2320 oevalp = evalp; 2321 odidfds = didfds; 2322#ifndef CLOSE_ON_EXEC 2323 odidcch = didcch; 2324#endif /* CLOSE_ON_EXEC */ 2325 oSHIN = SHIN; 2326 oSHOUT = SHOUT; 2327 oSHDIAG = SHDIAG; 2328 2329 savegv = gv; 2330 gav = v; 2331 2332 gav++; 2333 if (*gav == 0) 2334 return; 2335 gflag = 0, tglob(gav); 2336 if (gflag) { 2337 gv = gav = globall(gav); 2338 gargv = 0; 2339 if (gav == 0) 2340 stderror(ERR_NOMATCH); 2341 gav = copyblk(gav); 2342 } 2343 else { 2344 gv = NULL; 2345 gav = copyblk(gav); 2346 trim(gav); 2347 } 2348 2349 (void)close_on_exec(saveIN = dcopy(SHIN, -1), 1); 2350 (void)close_on_exec(saveOUT = dcopy(SHOUT, -1), 1); 2351 (void)close_on_exec(saveDIAG = dcopy(SHDIAG, -1), 1); 2352 2353 getexit(osetexit); 2354 2355 /* PWP: setjmp/longjmp bugfix for optimizing compilers */ 2356#ifdef cray 2357 my_reenter = 1; /* assume non-zero return val */ 2358 if (setexit() == 0) { 2359 my_reenter = 0; /* Oh well, we were wrong */ 2360#else /* !cray */ 2361 if ((my_reenter = setexit()) == 0) { 2362#endif /* cray */ 2363 evalvec = gav; 2364 evalp = 0; 2365 (void)close_on_exec(SHIN = dcopy(0, -1), 1); 2366 (void)close_on_exec(SHOUT = dcopy(1, -1), 1); 2367 (void)close_on_exec(SHDIAG = dcopy(2, -1), 1); 2368#ifndef CLOSE_ON_EXEC 2369 didcch = 0; 2370#endif /* CLOSE_ON_EXEC */ 2371 didfds = 0; 2372 process(0); 2373 } 2374 2375 evalvec = oevalvec; 2376 evalp = oevalp; 2377 doneinp = 0; 2378#ifndef CLOSE_ON_EXEC 2379 didcch = odidcch; 2380#endif /* CLOSE_ON_EXEC */ 2381 didfds = odidfds; 2382 (void) close(SHIN); 2383 (void) close(SHOUT); 2384 (void) close(SHDIAG); 2385 (void)close_on_exec (SHIN = dmove(saveIN, oSHIN), 1); 2386 (void)close_on_exec (SHOUT = dmove(saveOUT, oSHOUT), 1); 2387 (void)close_on_exec (SHDIAG = dmove(saveDIAG, oSHDIAG), 1); 2388 2389 if (gv) 2390 blkfree(gv); 2391 2392 gv = savegv; 2393 resexit(osetexit); 2394 if (my_reenter) 2395 stderror(ERR_SILENT); 2396} 2397 2398/*************************************************************************/ 2399/* print list of builtin commands */ 2400 2401/*ARGSUSED*/ 2402void 2403dobuiltins(v, c) 2404Char **v; 2405struct command *c; 2406{ 2407 /* would use print_by_column() in tw.parse.c but that assumes 2408 * we have an array of Char * to pass.. (sg) 2409 */ 2410 struct biltins *b; 2411 int row, col, columns, rows; 2412 unsigned int w, maxwidth; 2413 2414 USE(c); 2415 USE(v); 2416 lbuffed = 0; /* turn off line buffering */ 2417 2418 /* find widest string */ 2419 for (maxwidth = 0, b = bfunc; b < &bfunc[nbfunc]; ++b) 2420 maxwidth = max(maxwidth, strlen(b->bname)); 2421 ++maxwidth; /* for space */ 2422 2423 columns = (TermH + 1) / maxwidth; /* PWP: terminal size change */ 2424 if (!columns) 2425 columns = 1; 2426 rows = (nbfunc + (columns - 1)) / columns; 2427 2428 for (b = bfunc, row = 0; row < rows; row++) { 2429 for (col = 0; col < columns; col++) { 2430 if (b < &bfunc[nbfunc]) { 2431 w = strlen(b->bname); 2432 xprintf("%s", b->bname); 2433 if (col < (columns - 1)) /* Not last column? */ 2434 for (; w < maxwidth; w++) 2435 xputchar(' '); 2436 ++b; 2437 } 2438 } 2439 if (row < (rows - 1)) { 2440 if (Tty_raw_mode) 2441 xputchar('\r'); 2442 xputchar('\n'); 2443 } 2444 } 2445#ifdef WINNT_NATIVE 2446 nt_print_builtins(maxwidth); 2447#else 2448 if (Tty_raw_mode) 2449 xputchar('\r'); 2450 xputchar('\n'); 2451#endif /* WINNT_NATIVE */ 2452 2453 lbuffed = 1; /* turn back on line buffering */ 2454 flush(); 2455} 2456 2457#ifdef NLS_CATALOGS 2458#ifdef HAVE_ICONV 2459char * 2460iconv_catgets(ctd, set_id, msg_id, s) 2461nl_catd ctd; 2462int set_id, msg_id; 2463const char *s; 2464{ 2465 static char *buf = NULL; 2466 static size_t buf_size = 0; 2467 2468 char *orig, *dest, *p; 2469#ifdef __NetBSD__ 2470 const char *src; 2471#else 2472 char *src; 2473#endif 2474 size_t src_size, dest_size; 2475 2476 orig = catgets(ctd, set_id, msg_id, s); 2477 if (catgets_iconv == (iconv_t)-1 || orig == s) 2478 return orig; 2479 src = orig; 2480 src_size = strlen(src) + 1; 2481 if (buf == NULL && (buf = xmalloc(buf_size = src_size + 32)) == NULL) 2482 return orig; 2483 dest = buf; 2484 while (src_size != 0) { 2485 dest_size = buf + buf_size - dest; 2486 if (iconv(catgets_iconv, &src, &src_size, &dest, &dest_size) 2487 == (size_t)-1) { 2488 switch (errno) { 2489 case E2BIG: 2490 if ((p = xrealloc(buf, buf_size * 2)) == NULL) 2491 return orig; 2492 buf_size *= 2; 2493 dest = p + (dest - buf); 2494 buf = p; 2495 break; 2496 2497 case EILSEQ: case EINVAL: default: 2498 return orig; 2499 } 2500 } 2501 } 2502 return buf; 2503} 2504#endif 2505#endif 2506 2507void 2508nlsinit() 2509{ 2510#ifdef NLS_CATALOGS 2511 char catalog[ 256 ] = { 't', 'c', 's', 'h', '\0' }; 2512 2513 if (adrof(STRcatalog) != NULL) 2514 xsnprintf((char *)catalog, sizeof(catalog), "tcsh.%s", 2515 short2str(varval(STRcatalog))); 2516 catd = catopen(catalog, MCLoadBySet); 2517#ifdef HAVE_ICONV 2518 /* catgets (), not CGETS, the charset name should be in ASCII anyway. */ 2519 catgets_iconv = iconv_open (nl_langinfo (CODESET), 2520 catgets(catd, 255, 1, "ASCII")); 2521#endif /* HAVE_ICONV */ 2522#endif /* NLS_CATALOGS */ 2523#ifdef WINNT_NATIVE 2524 nls_dll_init(); 2525#endif /* WINNT_NATIVE */ 2526 errinit(); /* init the errorlist in correct locale */ 2527 mesginit(); /* init the messages for signals */ 2528 dateinit(); /* init the messages for dates */ 2529 editinit(); /* init the editor messages */ 2530 terminit(); /* init the termcap messages */ 2531} 2532 2533void 2534nlsclose() 2535{ 2536#ifdef NLS_CATALOGS 2537#ifdef HAVE_ICONV 2538 if (catgets_iconv != (iconv_t)-1) { 2539 iconv_close(catgets_iconv); 2540 catgets_iconv = (iconv_t)-1; 2541 } 2542#endif /* HAVE_ICONV */ 2543 catclose(catd); 2544#endif /* NLS_CATALOGS */ 2545} 2546