sh.func.c revision 354195
11541Srgrimes/* 21541Srgrimes * sh.func.c: csh builtin functions 31541Srgrimes */ 41541Srgrimes/*- 51541Srgrimes * Copyright (c) 1980, 1991 The Regents of the University of California. 61541Srgrimes * All rights reserved. 71541Srgrimes * 81541Srgrimes * Redistribution and use in source and binary forms, with or without 91541Srgrimes * modification, are permitted provided that the following conditions 101541Srgrimes * are met: 111541Srgrimes * 1. Redistributions of source code must retain the above copyright 121541Srgrimes * notice, this list of conditions and the following disclaimer. 131541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141541Srgrimes * notice, this list of conditions and the following disclaimer in the 151541Srgrimes * documentation and/or other materials provided with the distribution. 161541Srgrimes * 3. Neither the name of the University nor the names of its contributors 171541Srgrimes * may be used to endorse or promote products derived from this software 181541Srgrimes * without specific prior written permission. 191541Srgrimes * 201541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301541Srgrimes * SUCH DAMAGE. 311541Srgrimes */ 321541Srgrimes#include "sh.h" 331541Srgrimes#include "ed.h" 3450477Speter#include "tw.h" 351541Srgrimes#include "tc.h" 361541Srgrimes#ifdef WINNT_NATIVE 3777572Sobrien#include "nt.const.h" 381541Srgrimes#endif /* WINNT_NATIVE */ 391541Srgrimes 4076166Smarkm#if defined (NLS_CATALOGS) && defined(HAVE_ICONV) 4176166Smarkmstatic iconv_t catgets_iconv; /* Or (iconv_t)-1 */ 4232036Sbde#endif 431541Srgrimes 4423081Swollman/* 451541Srgrimes * C shell 461541Srgrimes */ 4776166Smarkm 489759Sbdeextern int MapsAreInited; 499759Sbdeextern int NLSMapsAreInited; 509759Sbdeextern int GotTermCaps; 519759Sbde 521541Srgrimesstatic int zlast = -1; 5366475Sbmilekic 5466475Sbmilekicstatic void islogin (void); 5566475Sbmilekicstatic void preread (void); 5644078Sdfrstatic void doagain (void); 5723081Swollmanstatic const char *isrchx (int); 5823081Swollmanstatic void search (int, int, Char *); 5923081Swollmanstatic int getword (struct Strbuf *); 6023081Swollmanstatic struct wordent *histgetword (struct wordent *); 6123081Swollmanstatic void toend (void); 6223081Swollmanstatic void xecho (int, Char **); 6323081Swollmanstatic int islocale_var (Char *); 6475112Sbmilekicstatic void wpfree (struct whyle *); 6566475Sbmilekic 6672473Sbmilekicconst struct biltins * 6772473Sbmilekicisbfunc(struct command *t) 6872473Sbmilekic{ 6972473Sbmilekic Char *cp = t->t_dcom[0]; 7072473Sbmilekic const struct biltins *bp, *bp1, *bp2; 7172473Sbmilekic static struct biltins label = {"", dozip, 0, 0}; 7272473Sbmilekic static struct biltins foregnd = {"%job", dofg1, 0, 0}; 7372473Sbmilekic static struct biltins backgnd = {"%job &", dobg1, 0, 0}; 7472473Sbmilekic 7572473Sbmilekic /* 7672473Sbmilekic * We never match a builtin that has quoted the first 7772473Sbmilekic * character; this has been the traditional way to escape 7872473Sbmilekic * builtin commands. 7972473Sbmilekic */ 8072473Sbmilekic if (*cp & QUOTE) 8172473Sbmilekic return NULL; 8272473Sbmilekic 8372473Sbmilekic if (*cp != ':' && lastchr(cp) == ':') { 8472473Sbmilekic label.bname = short2str(cp); 8572473Sbmilekic return (&label); 8672789Sbp } 8772473Sbmilekic if (*cp == '%') { 8872473Sbmilekic if (t->t_dflg & F_AMPERSAND) { 8972473Sbmilekic t->t_dflg &= ~F_AMPERSAND; 9072473Sbmilekic backgnd.bname = short2str(cp); 9172473Sbmilekic return (&backgnd); 9272473Sbmilekic } 9372473Sbmilekic foregnd.bname = short2str(cp); 9472473Sbmilekic return (&foregnd); 9572473Sbmilekic } 9672473Sbmilekic#ifdef WARP 9772473Sbmilekic /* 9872473Sbmilekic * This is a perhaps kludgy way to determine if the warp builtin is to be 9972473Sbmilekic * acknowledged or not. If checkwarp() fails, then we are to assume that 10072473Sbmilekic * the warp command is invalid, and carry on as we would handle any other 10172473Sbmilekic * non-builtin command. -- JDK 2/4/88 10272473Sbmilekic */ 10372473Sbmilekic if (eq(STRwarp, cp) && !checkwarp()) { 10472473Sbmilekic return (0); /* this builtin disabled */ 10572473Sbmilekic } 10672789Sbp#endif /* WARP */ 10772473Sbmilekic /* 10872473Sbmilekic * Binary search Bp1 is the beginning of the current search range. Bp2 is 10972473Sbmilekic * one past the end. 11072473Sbmilekic */ 11172473Sbmilekic for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) { 11272473Sbmilekic int i; 11372473Sbmilekic 11472473Sbmilekic bp = bp1 + ((bp2 - bp1) >> 1); 11572473Sbmilekic if ((i = ((char) *cp) - *bp->bname) == 0 && 11672473Sbmilekic (i = StrQcmp(cp, str2short(bp->bname))) == 0) 11772473Sbmilekic return bp; 11872473Sbmilekic if (i < 0) 11972473Sbmilekic bp2 = bp; 12072473Sbmilekic else 12172473Sbmilekic bp1 = bp + 1; 12272473Sbmilekic } 12372473Sbmilekic#ifdef WINNT_NATIVE 12472473Sbmilekic return nt_check_additional_builtins(cp); 12572473Sbmilekic#endif /*WINNT_NATIVE*/ 12672473Sbmilekic return (0); 12772473Sbmilekic} 12872473Sbmilekic 12972473Sbmilekicvoid 13072473Sbmilekicfunc(struct command *t, const struct biltins *bp) 1311541Srgrimes{ 13272356Sbmilekic int i; 1331541Srgrimes 13472356Sbmilekic xechoit(t->t_dcom); 1351541Srgrimes setname(bp->bname); 1361541Srgrimes i = blklen(t->t_dcom) - 1; 1371541Srgrimes if (i < bp->minargs) 1381541Srgrimes stderror(ERR_NAME | ERR_TOOFEW); 1391541Srgrimes if (i > bp->maxargs) 1403308Sphk stderror(ERR_NAME | ERR_TOOMANY); 1413308Sphk (*bp->bfunct) (t->t_dcom, t); 1421541Srgrimes} 1431541Srgrimes 1441541Srgrimes/*ARGSUSED*/ 1451541Srgrimesvoid 1461541Srgrimesdoonintr(Char **v, struct command *c) 1471541Srgrimes{ 1481541Srgrimes Char *cp; 1491541Srgrimes Char *vv = v[1]; 15072356Sbmilekic 1511541Srgrimes USE(c); 1521541Srgrimes if (parintr.sa_handler == SIG_IGN) 1531541Srgrimes return; 1541541Srgrimes if (setintr && intty) 15572356Sbmilekic stderror(ERR_NAME | ERR_TERMINAL); 1561541Srgrimes cp = gointr; 15772356Sbmilekic gointr = 0; 1581541Srgrimes xfree(cp); 1591541Srgrimes if (vv == 0) { 1601541Srgrimes if (setintr) 1611541Srgrimes sigset_interrupting(SIGINT, queue_pintr); 1621541Srgrimes else 1631541Srgrimes (void) signal(SIGINT, SIG_DFL); 1641541Srgrimes gointr = 0; 1651541Srgrimes } 1661541Srgrimes else if (eq((vv = strip(vv)), STRminus)) { 1671541Srgrimes (void) signal(SIGINT, SIG_IGN); 1681541Srgrimes gointr = Strsave(STRminus); 1691541Srgrimes } 1701541Srgrimes else { 1711541Srgrimes gointr = Strsave(vv); 1721541Srgrimes sigset_interrupting(SIGINT, queue_pintr); 1731541Srgrimes } 17470254Sbmilekic} 17554002Sarchie 17654002Sarchie/*ARGSUSED*/ 1771541Srgrimesvoid 1781541Srgrimesdonohup(Char **v, struct command *c) 17972356Sbmilekic{ 1801541Srgrimes USE(c); 18172356Sbmilekic USE(v); 18272356Sbmilekic if (intty) 1831541Srgrimes stderror(ERR_NAME | ERR_TERMINAL); 1841541Srgrimes if (setintr == 0) { 1851541Srgrimes (void) signal(SIGHUP, SIG_IGN); 18652201Salfred phup_disabled = 1; 18752201Salfred#ifdef CC 1881541Srgrimes submit(getpid()); 1891541Srgrimes#endif /* CC */ 1901541Srgrimes } 19152201Salfred} 1921541Srgrimes 1931541Srgrimes/*ARGSUSED*/ 1941541Srgrimesvoid 1951541Srgrimesdohup(Char **v, struct command *c) 1961541Srgrimes{ 1971541Srgrimes USE(c); 1981541Srgrimes USE(v); 1991541Srgrimes if (intty) 20072356Sbmilekic stderror(ERR_NAME | ERR_TERMINAL); 20152201Salfred if (setintr == 0) 20252201Salfred sigset_interrupting(SIGHUP, SIG_DFL); 2031541Srgrimes} 2041541Srgrimes 2051541Srgrimes 2061541Srgrimes/*ARGSUSED*/ 20772356Sbmilekicvoid 2081541Srgrimesdozip(Char **v, struct command *c) 2091541Srgrimes{ 2101541Srgrimes USE(c); 2111541Srgrimes USE(v); 2121541Srgrimes} 2131541Srgrimes 2141541Srgrimes/*ARGSUSED*/ 2151541Srgrimesvoid 2161541Srgrimesdofiletest(Char **v, struct command *c) 2171541Srgrimes{ 2181541Srgrimes Char **globbed, **fileptr, *ftest, *res; 2191541Srgrimes 2201541Srgrimes USE(c); 2211541Srgrimes if (*(ftest = *++v) != '-') 22264837Sdwmalone stderror(ERR_NAME | ERR_FILEINQ); 2231541Srgrimes ++v; 2241541Srgrimes 2251541Srgrimes v = glob_all_or_error(v); 2261541Srgrimes globbed = v; 2271541Srgrimes cleanup_push(globbed, blk_cleanup); 2281541Srgrimes 2291541Srgrimes while (*(fileptr = v++) != NULL) { 2301541Srgrimes res = filetest(ftest, &fileptr, 0); 2311541Srgrimes cleanup_push(res, xfree); 23278592Sbmilekic xprintf("%S", res); 23378592Sbmilekic cleanup_until(res); 23478592Sbmilekic if (*v) 2351541Srgrimes xprintf(" "); 2361541Srgrimes } 2371541Srgrimes xprintf("\n"); 23878592Sbmilekic 23972356Sbmilekic cleanup_until(globbed); 2401541Srgrimes} 2411541Srgrimes 2421541Srgrimesvoid 24315689Swollmanprvars(void) 24415689Swollman{ 24554002Sarchie plist(&shvhed, VAR_ALL); 24654002Sarchie} 24772750Sluigi 24872750Sluigi/*ARGSUSED*/ 24972750Sluigivoid 25015689Swollmandoalias(Char **v, struct command *c) 25115689Swollman{ 25272356Sbmilekic struct varent *vp; 25315689Swollman Char *p; 25415689Swollman 25515689Swollman USE(c); 25615689Swollman v++; 25715689Swollman p = *v++; 25872356Sbmilekic if (p == 0) 25915689Swollman plist(&aliases, VAR_ALL); 26015689Swollman else if (*v == 0) { 26115689Swollman vp = adrof1(strip(p), &aliases); 26215689Swollman if (vp && vp->vec) 26315689Swollman blkpr(vp->vec), xputchar('\n'); 26415689Swollman } 26515689Swollman else { 26615689Swollman if (eq(p, STRalias) || eq(p, STRunalias)) { 26764837Sdwmalone setname(short2str(p)); 26815689Swollman stderror(ERR_NAME | ERR_DANGER); 26972750Sluigi } 27015689Swollman set1(strip(p), saveblk(v), &aliases, VAR_READWRITE); 27115689Swollman tw_cmd_free(); 27215689Swollman } 27315689Swollman} 27415689Swollman 27515689Swollman/*ARGSUSED*/ 27672356Sbmilekicvoid 27715689Swollmanunalias(Char **v, struct command *c) 27815689Swollman{ 27915689Swollman USE(c); 28015689Swollman unset1(v, &aliases); 28115689Swollman tw_cmd_free(); 28215689Swollman} 28315689Swollman 28415689Swollman/*ARGSUSED*/ 28515689Swollmanvoid 28615689Swollmandologout(Char **v, struct command *c) 28764837Sdwmalone{ 28815689Swollman USE(c); 28915689Swollman USE(v); 29015689Swollman islogin(); 29115689Swollman goodbye(NULL, NULL); 29215689Swollman} 29315689Swollman 29415689Swollman/*ARGSUSED*/ 29515689Swollmanvoid 29615689Swollmandologin(Char **v, struct command *c) 29778592Sbmilekic{ 29872356Sbmilekic#ifdef WINNT_NATIVE 29915689Swollman USE(c); 30015689Swollman USE(v); 30115689Swollman#else /* !WINNT_NATIVE */ 3021541Srgrimes char **p = short2blk(v); 3031541Srgrimes 3041541Srgrimes USE(c); 3051549Srgrimes cleanup_push((Char **)p, blk_cleanup); 30681907Sjulian islogin(); 3071541Srgrimes rechist(NULL, adrof(STRsavehist) != NULL); 30872356Sbmilekic sigaction(SIGTERM, &parterm, NULL); 3091541Srgrimes (void) execv(_PATH_BIN_LOGIN, p); 31052201Salfred (void) execv(_PATH_USRBIN_LOGIN, p); 31152201Salfred cleanup_until((Char **)p); 3121541Srgrimes untty(); 31352201Salfred xexit(1); 3141541Srgrimes#endif /* !WINNT_NATIVE */ 3151541Srgrimes} 3161541Srgrimes 3171541Srgrimes 3181541Srgrimes#ifdef NEWGRP 3191541Srgrimes/*ARGSUSED*/ 32052201Salfredvoid 3211541Srgrimesdonewgrp(Char **v, struct command *c) 3221541Srgrimes{ 3231541Srgrimes char **p; 3241541Srgrimes if (chkstop == 0 && setintr) 3251541Srgrimes panystop(0); 3261541Srgrimes sigaction(SIGTERM, &parterm, NULL); 3271541Srgrimes p = short2blk(v); 3281541Srgrimes /* 3291541Srgrimes * From Beto Appleton (beto@aixwiz.austin.ibm.com) 3301541Srgrimes * Newgrp can take 2 arguments... 33154002Sarchie */ 33254002Sarchie (void) execv(_PATH_BIN_NEWGRP, p); 33354002Sarchie (void) execv(_PATH_USRBIN_NEWGRP, p); 33454002Sarchie blkfree((Char **) p); 33554002Sarchie untty(); 33672356Sbmilekic xexit(1); 33754002Sarchie} 33854002Sarchie#endif /* NEWGRP */ 33954002Sarchie 34054002Sarchiestatic void 34154002Sarchieislogin(void) 34254002Sarchie{ 34372356Sbmilekic if (chkstop == 0 && setintr) 34454002Sarchie panystop(0); 34554002Sarchie if (loginsh) 34654002Sarchie return; 34754002Sarchie stderror(ERR_NOTLOGIN); 34854002Sarchie} 34954002Sarchie 35054002Sarchievoid 35154002Sarchiedoif(Char **v, struct command *kp) 35254002Sarchie{ 35354002Sarchie int i; 35454002Sarchie Char **vv; 35554002Sarchie 35654002Sarchie v++; 35754002Sarchie i = noexec ? 1 : expr(&v); 35854002Sarchie vv = v; 35954002Sarchie if (*vv == NULL) 36054002Sarchie stderror(ERR_NAME | ERR_EMPTYIF); 36154002Sarchie if (eq(*vv, STRthen)) { 36254002Sarchie if (*++vv) 36354002Sarchie stderror(ERR_NAME | ERR_IMPRTHEN); 36454002Sarchie setname(short2str(STRthen)); 36554002Sarchie /* 36654002Sarchie * If expression was zero, then scan to else , otherwise just fall into 36754002Sarchie * following code. 36854002Sarchie */ 36954002Sarchie if (!i) 37054002Sarchie search(TC_IF, 0, NULL); 37154002Sarchie return; 37254002Sarchie } 37354002Sarchie /* 37454002Sarchie * Simple command attached to this if. Left shift the node in this tree, 37554002Sarchie * munging it so we can reexecute it. 37654002Sarchie */ 37754002Sarchie if (i) { 37854002Sarchie lshift(kp->t_dcom, vv - kp->t_dcom); 37954002Sarchie reexecute(kp); 38054002Sarchie donefds(); 38154002Sarchie } 38254002Sarchie} 38354002Sarchie 38454002Sarchie/* 38554002Sarchie * Reexecute a command, being careful not 38654002Sarchie * to redo i/o redirection, which is already set up. 38754002Sarchie */ 38854002Sarchievoid 38954002Sarchiereexecute(struct command *kp) 39054002Sarchie{ 39154002Sarchie kp->t_dflg &= F_SAVE; 39254002Sarchie kp->t_dflg |= F_REPEAT; 39354002Sarchie /* 39454002Sarchie * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set 39554002Sarchie * pgrp's as the jobs would then have no way to get the tty (we can't give 39654002Sarchie * it to them, and our parent wouldn't know their pgrp, etc. 39754002Sarchie */ 39878592Sbmilekic execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL, TRUE); 39972356Sbmilekic} 40054002Sarchie 40154002Sarchie/*ARGSUSED*/ 40254002Sarchievoid 4031541Srgrimesdoelse (Char **v, struct command *c) 4041541Srgrimes{ 4051541Srgrimes USE(c); 4061541Srgrimes USE(v); 4071549Srgrimes if (!noexec) 40872356Sbmilekic search(TC_ELSE, 0, NULL); 4091541Srgrimes} 4101541Srgrimes 4111541Srgrimes/*ARGSUSED*/ 4121541Srgrimesvoid 4131541Srgrimesdogoto(Char **v, struct command *c) 4141541Srgrimes{ 4151541Srgrimes Char *lp; 4161541Srgrimes 4171541Srgrimes USE(c); 4181541Srgrimes lp = globone(v[1], G_ERROR); 4191541Srgrimes cleanup_push(lp, xfree); 4201541Srgrimes if (!noexec) 4211541Srgrimes gotolab(lp); 4221541Srgrimes cleanup_until(lp); 4231541Srgrimes} 4241541Srgrimes 4251541Srgrimesvoid 4261541Srgrimesgotolab(Char *lab) 4271549Srgrimes{ 42872356Sbmilekic struct whyle *wp; 4291541Srgrimes /* 43072356Sbmilekic * While we still can, locate any unknown ends of existing loops. This 43172356Sbmilekic * obscure code is the WORST result of the fact that we don't really parse. 43272356Sbmilekic */ 4331541Srgrimes zlast = TC_GOTO; 4341541Srgrimes for (wp = whyles; wp; wp = wp->w_next) 4351541Srgrimes if (wp->w_end.type == TCSH_F_SEEK && wp->w_end.f_seek == 0) { 4361541Srgrimes search(TC_BREAK, 0, NULL); 4371541Srgrimes btell(&wp->w_end); 4381541Srgrimes } 4391541Srgrimes else { 4401541Srgrimes bseek(&wp->w_end); 4411541Srgrimes } 4421541Srgrimes search(TC_GOTO, 0, lab); 4431541Srgrimes /* 4441541Srgrimes * Eliminate loops which were exited. 4451541Srgrimes */ 4461541Srgrimes wfree(); 4471541Srgrimes} 4481541Srgrimes 4491541Srgrimes/*ARGSUSED*/ 4501541Srgrimesvoid 4511541Srgrimesdoswitch(Char **v, struct command *c) 4521541Srgrimes{ 4531541Srgrimes Char *cp, *lp; 4541541Srgrimes 4551541Srgrimes USE(c); 4561541Srgrimes v++; 4571541Srgrimes if (!*v || *(*v++) != '(') 4581541Srgrimes stderror(ERR_SYNTAX); 4591541Srgrimes cp = **v == ')' ? STRNULL : *v++; 4601541Srgrimes if (*(*v++) != ')') 4611541Srgrimes v--; 4621541Srgrimes if (*v) 4631541Srgrimes stderror(ERR_SYNTAX); 4641541Srgrimes lp = globone(cp, G_ERROR); 4651541Srgrimes cleanup_push(lp, xfree); 4661541Srgrimes if (!noexec) 4671541Srgrimes search(TC_SWITCH, 0, lp); 4681541Srgrimes cleanup_until(lp); 4691541Srgrimes} 4701541Srgrimes 4711541Srgrimes/*ARGSUSED*/ 4721541Srgrimesvoid 4731541Srgrimesdobreak(Char **v, struct command *c) 4741541Srgrimes{ 4751541Srgrimes USE(v); 4761541Srgrimes USE(c); 4771541Srgrimes if (whyles == NULL) 4781541Srgrimes stderror(ERR_NAME | ERR_NOTWHILE); 4791541Srgrimes if (!noexec) 4801541Srgrimes toend(); 4811541Srgrimes} 4821541Srgrimes 4831541Srgrimes/*ARGSUSED*/ 4841541Srgrimesvoid 4851541Srgrimesdoexit(Char **v, struct command *c) 4861541Srgrimes{ 4871541Srgrimes USE(c); 4881541Srgrimes 4891541Srgrimes if (chkstop == 0 && (intty || intact) && evalvec == 0) 4901541Srgrimes panystop(0); 4911541Srgrimes /* 4921541Srgrimes * Don't DEMAND parentheses here either. 4931541Srgrimes */ 4943308Sphk v++; 4953308Sphk if (*v) { 4961541Srgrimes setv(STRstatus, putn(expr(&v)), VAR_READWRITE); 4971541Srgrimes if (*v) 4981541Srgrimes stderror(ERR_NAME | ERR_EXPRESSION); 4991541Srgrimes } 5001541Srgrimes btoeof(); 5011541Srgrimes#if 0 5021541Srgrimes if (intty) 5031541Srgrimes#endif 5041541Srgrimes /* Always close, why only on ttys? */ 5051541Srgrimes xclose(SHIN); 5061541Srgrimes} 5071541Srgrimes 50872356Sbmilekic/*ARGSUSED*/ 5091541Srgrimesvoid 51072356Sbmilekicdoforeach(Char **v, struct command *c) 51172356Sbmilekic{ 5121541Srgrimes Char *cp, *sp; 5131541Srgrimes struct whyle *nwp; 5141541Srgrimes int gflag; 5151541Srgrimes 5161541Srgrimes USE(c); 5171541Srgrimes v++; 5181541Srgrimes cp = sp = strip(*v); 5191541Srgrimes if (!letter(*cp)) 5201541Srgrimes stderror(ERR_NAME | ERR_VARBEGIN); 5211541Srgrimes do { 5221541Srgrimes cp++; 5231541Srgrimes } while (alnum(*cp)); 5241541Srgrimes if (*cp != '\0') 5251541Srgrimes stderror(ERR_NAME | ERR_VARALNUM); 5261541Srgrimes cp = *v++; 5271541Srgrimes if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') 5281541Srgrimes stderror(ERR_NAME | ERR_NOPAREN); 5291541Srgrimes v++; 53072356Sbmilekic gflag = tglob(v); 5311541Srgrimes if (gflag) { 5321541Srgrimes v = globall(v, gflag); 5331541Srgrimes if (v == 0 && !noexec) 5341541Srgrimes stderror(ERR_NAME | ERR_NOMATCH); 5351541Srgrimes } 5361541Srgrimes else { 5371541Srgrimes v = saveblk(v); 5381541Srgrimes trim(v); 5391541Srgrimes } 5401541Srgrimes nwp = xcalloc(1, sizeof *nwp); 5411541Srgrimes nwp->w_fe = nwp->w_fe0 = v; 5421541Srgrimes btell(&nwp->w_start); 5431541Srgrimes nwp->w_fename = Strsave(cp); 5441541Srgrimes nwp->w_next = whyles; 5451541Srgrimes nwp->w_end.type = TCSH_F_SEEK; 5461541Srgrimes whyles = nwp; 5471541Srgrimes /* 5481541Srgrimes * Pre-read the loop so as to be more comprehensible to a terminal user. 5491541Srgrimes */ 5501541Srgrimes zlast = TC_FOREACH; 5511541Srgrimes if (intty) 5521541Srgrimes preread(); 5531541Srgrimes if (!noexec) 5541541Srgrimes doagain(); 5551541Srgrimes} 5561541Srgrimes 5571541Srgrimes/*ARGSUSED*/ 5581541Srgrimesvoid 5591541Srgrimesdowhile(Char **v, struct command *c) 56078592Sbmilekic{ 56172356Sbmilekic int status; 5621541Srgrimes int again = whyles != 0 && 5631541Srgrimes SEEKEQ(&whyles->w_start, &lineloc) && 5641541Srgrimes whyles->w_fename == 0; 5651541Srgrimes 5661541Srgrimes USE(c); 5671541Srgrimes v++; 5681541Srgrimes /* 5691541Srgrimes * Implement prereading here also, taking care not to evaluate the 57072356Sbmilekic * expression before the loop has been read up from a terminal. 5711541Srgrimes */ 57272356Sbmilekic if (noexec) 5731541Srgrimes status = 0; 5741541Srgrimes else if (intty && !again) 5751541Srgrimes status = !exp0(&v, 1); 5761541Srgrimes else 57772356Sbmilekic status = !expr(&v); 57872356Sbmilekic if (*v && !noexec) 5791541Srgrimes stderror(ERR_NAME | ERR_EXPRESSION); 5801541Srgrimes if (!again) { 5811541Srgrimes struct whyle *nwp = xcalloc(1, sizeof(*nwp)); 58272356Sbmilekic 58372356Sbmilekic nwp->w_start = lineloc; 5841541Srgrimes nwp->w_end.type = TCSH_F_SEEK; 5851541Srgrimes nwp->w_end.f_seek = 0; 5861541Srgrimes nwp->w_end.a_seek = 0; 5871541Srgrimes nwp->w_next = whyles; 5881541Srgrimes whyles = nwp; 5891541Srgrimes zlast = TC_WHILE; 5901541Srgrimes if (intty) { 5911541Srgrimes /* 5921541Srgrimes * The tty preread 59372356Sbmilekic */ 5941541Srgrimes preread(); 59572356Sbmilekic doagain(); 5961541Srgrimes return; 5971541Srgrimes } 5981541Srgrimes } 5991541Srgrimes if (status) 6001541Srgrimes /* We ain't gonna loop no more, no more! */ 6011541Srgrimes toend(); 60272356Sbmilekic} 6031541Srgrimes 6041541Srgrimesstatic void 6051541Srgrimespreread(void) 60672356Sbmilekic{ 60772356Sbmilekic int old_pintr_disabled; 6081541Srgrimes 6091541Srgrimes whyles->w_end.type = TCSH_I_SEEK; 6101541Srgrimes if (setintr) 6111541Srgrimes pintr_push_enable(&old_pintr_disabled); 6121541Srgrimes search(TC_BREAK, 0, NULL); /* read the expression in */ 6131541Srgrimes if (setintr) 61464837Sdwmalone cleanup_until(&old_pintr_disabled); 6151541Srgrimes btell(&whyles->w_end); 6161541Srgrimes} 6171541Srgrimes 6181541Srgrimes/*ARGSUSED*/ 6191541Srgrimesvoid 6201541Srgrimesdoend(Char **v, struct command *c) 6211541Srgrimes{ 6221541Srgrimes USE(v); 62372356Sbmilekic USE(c); 6241541Srgrimes if (!whyles) 6251541Srgrimes stderror(ERR_NAME | ERR_NOTWHILE); 6261541Srgrimes btell(&whyles->w_end); 6271541Srgrimes if (!noexec) 62878508Sbmilekic doagain(); 62978508Sbmilekic} 6301541Srgrimes 6311541Srgrimes/*ARGSUSED*/ 63278508Sbmilekicvoid 63372356Sbmilekicdocontin(Char **v, struct command *c) 6341541Srgrimes{ 63572356Sbmilekic USE(v); 6361541Srgrimes USE(c); 63778508Sbmilekic if (!whyles) 6381541Srgrimes stderror(ERR_NAME | ERR_NOTWHILE); 63978508Sbmilekic if (!noexec) 64078508Sbmilekic doagain(); 64178508Sbmilekic} 6421541Srgrimes 64372356Sbmilekicstatic void 64472356Sbmilekicdoagain(void) 6451541Srgrimes{ 6461541Srgrimes /* Repeating a while is simple */ 64778508Sbmilekic if (whyles->w_fename == 0) { 6481541Srgrimes bseek(&whyles->w_start); 6491541Srgrimes return; 6501541Srgrimes } 6511541Srgrimes /* 65272356Sbmilekic * The foreach variable list actually has a spurious word ")" at the end of 6531541Srgrimes * the w_fe list. Thus we are at the of the list if one word beyond this 65472356Sbmilekic * is 0. 6551541Srgrimes */ 65678508Sbmilekic if (!whyles->w_fe[1]) { 6571541Srgrimes dobreak(NULL, NULL); 65878508Sbmilekic return; 6591541Srgrimes } 6601541Srgrimes setv(whyles->w_fename, quote(Strsave(*whyles->w_fe++)), VAR_READWRITE); 66178508Sbmilekic bseek(&whyles->w_start); 6621541Srgrimes} 6631541Srgrimes 6641541Srgrimesvoid 6651541Srgrimesdorepeat(Char **v, struct command *kp) 66678508Sbmilekic{ 66778508Sbmilekic int i = 1; 66878508Sbmilekic 66978508Sbmilekic do { 6701541Srgrimes i *= getn(v[1]); 67178508Sbmilekic lshift(v, 2); 67278508Sbmilekic } while (v[0] != NULL && Strcmp(v[0], STRrepeat) == 0); 67378508Sbmilekic if (noexec) 67478508Sbmilekic i = 1; 67578508Sbmilekic 67678508Sbmilekic if (setintr) { 6771541Srgrimes pintr_disabled++; 67878508Sbmilekic cleanup_push(&pintr_disabled, disabled_cleanup); 6791541Srgrimes } 68078508Sbmilekic while (i > 0) { 68178508Sbmilekic if (setintr && pintr_disabled == 1) { 6821541Srgrimes cleanup_until(&pintr_disabled); 6831541Srgrimes pintr_disabled++; 6841541Srgrimes cleanup_push(&pintr_disabled, disabled_cleanup); 6851541Srgrimes } 6861541Srgrimes reexecute(kp); 6871541Srgrimes --i; 6883352Sphk } 6893352Sphk if (setintr && pintr_disabled == 1) 6903352Sphk cleanup_until(&pintr_disabled); 6913352Sphk donefds(); 6923352Sphk} 6933352Sphk 6943352Sphk/*ARGSUSED*/ 69572356Sbmilekicvoid 6963352Sphkdoswbrk(Char **v, struct command *c) 69772356Sbmilekic{ 69872356Sbmilekic USE(v); 6993352Sphk USE(c); 7003352Sphk if (!noexec) 70172356Sbmilekic search(TC_BRKSW, 0, NULL); 7023352Sphk} 7033352Sphk 7043352Sphkint 7053352Sphksrchx(Char *cp) 70672356Sbmilekic{ 70778592Sbmilekic struct srch *sp, *sp1, *sp2; 70872356Sbmilekic int i; 7093352Sphk 7103352Sphk /* 7113352Sphk * Ignore keywords inside heredocs 7123352Sphk */ 7133352Sphk if (inheredoc) 7143352Sphk return -1; 7153352Sphk 7163352Sphk /* 7173352Sphk * Binary search Sp1 is the beginning of the current search range. Sp2 is 7183352Sphk * one past the end. 7193352Sphk */ 7203352Sphk for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) { 7213352Sphk sp = sp1 + ((sp2 - sp1) >> 1); 7223352Sphk if ((i = *cp - *sp->s_name) == 0 && 7233352Sphk (i = Strcmp(cp, str2short(sp->s_name))) == 0) 7243352Sphk return sp->s_value; 72572356Sbmilekic if (i < 0) 7263352Sphk sp2 = sp; 72772356Sbmilekic else 7283352Sphk sp1 = sp + 1; 7293352Sphk } 7303352Sphk return (-1); 7313352Sphk} 7323352Sphk 7333352Sphkstatic const char * 7343352Sphkisrchx(int n) 7353352Sphk{ 7363352Sphk struct srch *sp, *sp2; 73752756Sphk 73852756Sphk for (sp = srchn, sp2 = srchn + nsrchn; sp < sp2; sp++) 73952756Sphk if (sp->s_value == n) 74052756Sphk return (sp->s_name); 74152756Sphk return (""); 74254906Seivind} 74352756Sphk 74452756Sphk 74552756Sphkstatic int Stype; 74652756Sphkstatic Char *Sgoal; 74752756Sphk 74852756Sphkstatic void 74952756Sphksearch(int type, int level, Char *goal) 75052756Sphk{ 75152756Sphk struct Strbuf word = Strbuf_INIT; 75252756Sphk Char *cp; 753 struct whyle *wp; 754 int wlevel = 0; 755 struct wordent *histent = NULL, *ohistent = NULL; 756 757 Stype = type; 758 Sgoal = goal; 759 if (type == TC_GOTO) { 760 struct Ain a; 761 a.type = TCSH_F_SEEK; 762 a.f_seek = 0; 763 a.a_seek = 0; 764 bseek(&a); 765 } 766 cleanup_push(&word, Strbuf_cleanup); 767 do { 768 769 if (intty) { 770 histent = xmalloc(sizeof(*histent)); 771 ohistent = xmalloc(sizeof(*histent)); 772 ohistent->word = STRNULL; 773 ohistent->next = histent; 774 histent->prev = ohistent; 775 } 776 777 if (intty && fseekp == feobp && aret == TCSH_F_SEEK) 778 printprompt(1, isrchx(type == TC_BREAK ? zlast : type)); 779 /* xprintf("? "), flush(); */ 780 (void) getword(&word); 781 Strbuf_terminate(&word); 782 783 if (intty && Strlen(word.s) > 0) { 784 histent->word = Strsave(word.s); 785 histent->next = xmalloc(sizeof(*histent)); 786 histent->next->prev = histent; 787 histent = histent->next; 788 } 789 790 switch (srchx(word.s)) { 791 792 case TC_ELSE: 793 if (level == 0 && type == TC_IF) 794 goto end; 795 break; 796 797 case TC_IF: 798 while (getword(&word)) { 799 if (intty) { 800 histent->word = Strsave(word.s); 801 histent->next = xmalloc(sizeof(*histent)); 802 histent->next->prev = histent; 803 histent = histent->next; 804 } 805 continue; 806 } 807 808 if ((type == TC_IF || type == TC_ELSE) && 809 eq(word.s, STRthen)) 810 level++; 811 break; 812 813 case TC_ENDIF: 814 if (type == TC_IF || type == TC_ELSE) 815 level--; 816 break; 817 818 case TC_FOREACH: 819 case TC_WHILE: 820 wlevel++; 821 if (type == TC_BREAK) 822 level++; 823 break; 824 825 case TC_END: 826 if (type == TC_BRKSW) { 827 if (wlevel == 0) { 828 wp = whyles; 829 if (wp) { 830 whyles = wp->w_next; 831 wpfree(wp); 832 } 833 } 834 } 835 if (type == TC_BREAK) 836 level--; 837 wlevel--; 838 break; 839 840 case TC_SWITCH: 841 if (type == TC_SWITCH || type == TC_BRKSW) 842 level++; 843 break; 844 845 case TC_ENDSW: 846 if (type == TC_SWITCH || type == TC_BRKSW) 847 level--; 848 break; 849 850 case TC_LABEL: 851 if (type == TC_GOTO && getword(&word) && eq(word.s, goal)) 852 level = -1; 853 break; 854 855 default: 856 if (type != TC_GOTO && (type != TC_SWITCH || level != 0)) 857 break; 858 if (word.len == 0 || word.s[word.len - 1] != ':') 859 break; 860 word.s[--word.len] = 0; 861 if ((type == TC_GOTO && eq(word.s, goal)) || 862 (type == TC_SWITCH && eq(word.s, STRdefault))) 863 level = -1; 864 break; 865 866 case TC_CASE: 867 if (type != TC_SWITCH || level != 0) 868 break; 869 (void) getword(&word); 870 if (word.len != 0 && word.s[word.len - 1] == ':') 871 word.s[--word.len] = 0; 872 cp = strip(Dfix1(word.s)); 873 cleanup_push(cp, xfree); 874 if (Gmatch(goal, cp)) 875 level = -1; 876 cleanup_until(cp); 877 break; 878 879 case TC_DEFAULT: 880 if (type == TC_SWITCH && level == 0) 881 level = -1; 882 break; 883 } 884 if (intty) { 885 ohistent->prev = histgetword(histent); 886 ohistent->prev->next = ohistent; 887 savehist(ohistent, 0); 888 freelex(ohistent); 889 xfree(ohistent); 890 } else 891 (void) getword(NULL); 892 } while (level >= 0); 893 end: 894 cleanup_until(&word); 895} 896 897static struct wordent * 898histgetword(struct wordent *histent) 899{ 900 int first; 901 eChar c, d; 902 int e; 903 struct Strbuf *tmp; 904 tmp = xmalloc(sizeof(*tmp)); 905 tmp->size = 0; 906 tmp->s = NULL; 907 c = readc(1); 908 d = 0; 909 e = 0; 910 for (;;) { 911 tmp->len = 0; 912 Strbuf_terminate (tmp); 913 while (c == ' ' || c == '\t') 914 c = readc(1); 915 if (c == '#') 916 do 917 c = readc(1); 918 while (c != CHAR_ERR && c != '\n'); 919 if (c == CHAR_ERR) 920 goto past; 921 if (c == '\n') 922 goto nl; 923 unreadc(c); 924 first = 1; 925 do { 926 e = (c == '\\'); 927 c = readc(1); 928 if (c == '\\' && !e) { 929 if ((c = readc(1)) == '\n') { 930 e = 1; 931 c = ' '; 932 } else { 933 unreadc(c); 934 c = '\\'; 935 } 936 } 937 if ((c == '\'' || c == '"') && !e) { 938 if (d == 0) 939 d = c; 940 else if (d == c) 941 d = 0; 942 } 943 if (c == CHAR_ERR) 944 goto past; 945 946 Strbuf_append1(tmp, (Char) c); 947 948 if (!first && !d && c == '(' && !e) { 949 break; 950 } 951 first = 0; 952 } while (d || e || (c != ' ' && c != '\t' && c != '\n')); 953 tmp->len--; 954 if (tmp->len) { 955 Strbuf_terminate(tmp); 956 histent->word = Strsave(tmp->s); 957 histent->next = xmalloc(sizeof (*histent)); 958 histent->next->prev = histent; 959 histent = histent->next; 960 } 961 if (c == '\n') { 962 nl: 963 tmp->len = 0; 964 Strbuf_append1(tmp, (Char) c); 965 Strbuf_terminate(tmp); 966 histent->word = Strsave(tmp->s); 967 return histent; 968 } 969 } 970 971past: 972 switch (Stype) { 973 974 case TC_IF: 975 stderror(ERR_NAME | ERR_NOTFOUND, "then/endif"); 976 break; 977 978 case TC_ELSE: 979 stderror(ERR_NAME | ERR_NOTFOUND, "endif"); 980 break; 981 982 case TC_BRKSW: 983 case TC_SWITCH: 984 stderror(ERR_NAME | ERR_NOTFOUND, "endsw"); 985 break; 986 987 case TC_BREAK: 988 stderror(ERR_NAME | ERR_NOTFOUND, "end"); 989 break; 990 991 case TC_GOTO: 992 setname(short2str(Sgoal)); 993 stderror(ERR_NAME | ERR_NOTFOUND, "label"); 994 break; 995 996 default: 997 break; 998 } 999 /* NOTREACHED */ 1000 return NULL; 1001} 1002 1003static int 1004getword(struct Strbuf *wp) 1005{ 1006 int found = 0, first; 1007 eChar c, d; 1008 1009 if (wp) 1010 wp->len = 0; 1011 c = readc(1); 1012 d = 0; 1013 do { 1014 while (c == ' ' || c == '\t') 1015 c = readc(1); 1016 if (c == '#') 1017 do 1018 c = readc(1); 1019 while (c != CHAR_ERR && c != '\n'); 1020 if (c == CHAR_ERR) 1021 goto past; 1022 if (c == '\n') { 1023 if (wp) 1024 break; 1025 return (0); 1026 } 1027 unreadc(c); 1028 found = 1; 1029 first = 1; 1030 do { 1031 c = readc(1); 1032 if (c == '\\' && (c = readc(1)) == '\n') 1033 c = ' '; 1034 if (c == '\'' || c == '"') { 1035 if (d == 0) 1036 d = c; 1037 else if (d == c) 1038 d = 0; 1039 } 1040 if (c == CHAR_ERR) 1041 goto past; 1042 if (wp) 1043 Strbuf_append1(wp, (Char) c); 1044 if (!d && c == ')') { 1045 if (!first && wp) { 1046 goto past_word_end; 1047 } else { 1048 if (wp) { 1049 wp->len = 1; 1050 Strbuf_terminate(wp); 1051 } 1052 return found; 1053 } 1054 } 1055 if (!first && !d && c == '(') { 1056 if (wp) 1057 goto past_word_end; 1058 else 1059 break; 1060 } 1061 first = 0; 1062 } while ((d || (c != ' ' && c != '\t')) && c != '\n'); 1063 } while (wp == 0); 1064 1065 past_word_end: 1066 unreadc(c); 1067 if (found) { 1068 wp->len--; 1069 Strbuf_terminate(wp); 1070 } 1071 1072 return (found); 1073 1074past: 1075 switch (Stype) { 1076 1077 case TC_IF: 1078 stderror(ERR_NAME | ERR_NOTFOUND, "then/endif"); 1079 break; 1080 1081 case TC_ELSE: 1082 stderror(ERR_NAME | ERR_NOTFOUND, "endif"); 1083 break; 1084 1085 case TC_BRKSW: 1086 case TC_SWITCH: 1087 stderror(ERR_NAME | ERR_NOTFOUND, "endsw"); 1088 break; 1089 1090 case TC_BREAK: 1091 stderror(ERR_NAME | ERR_NOTFOUND, "end"); 1092 break; 1093 1094 case TC_GOTO: 1095 setname(short2str(Sgoal)); 1096 stderror(ERR_NAME | ERR_NOTFOUND, "label"); 1097 break; 1098 1099 default: 1100 break; 1101 } 1102 /* NOTREACHED */ 1103 return (0); 1104} 1105 1106static void 1107toend(void) 1108{ 1109 if (whyles->w_end.type == TCSH_F_SEEK && whyles->w_end.f_seek == 0) { 1110 search(TC_BREAK, 0, NULL); 1111 btell(&whyles->w_end); 1112 whyles->w_end.f_seek--; 1113 } 1114 else { 1115 bseek(&whyles->w_end); 1116 } 1117 wfree(); 1118} 1119 1120static void 1121wpfree(struct whyle *wp) 1122{ 1123 if (wp->w_fe0) 1124 blkfree(wp->w_fe0); 1125 xfree(wp->w_fename); 1126 xfree(wp); 1127} 1128 1129void 1130wfree(void) 1131{ 1132 struct Ain o; 1133 struct whyle *nwp; 1134#ifdef lint 1135 nwp = NULL; /* sun lint is dumb! */ 1136#endif 1137 1138#ifdef FDEBUG 1139 static const char foo[] = "IAFE"; 1140#endif /* FDEBUG */ 1141 1142 btell(&o); 1143 1144#ifdef FDEBUG 1145 xprintf("o->type %c o->a_seek %d o->f_seek %d\n", 1146 foo[o.type + 1], o.a_seek, o.f_seek); 1147#endif /* FDEBUG */ 1148 1149 for (; whyles; whyles = nwp) { 1150 struct whyle *wp = whyles; 1151 nwp = wp->w_next; 1152 1153#ifdef FDEBUG 1154 xprintf("start->type %c start->a_seek %d start->f_seek %d\n", 1155 foo[wp->w_start.type+1], 1156 wp->w_start.a_seek, wp->w_start.f_seek); 1157 xprintf("end->type %c end->a_seek %d end->f_seek %d\n", 1158 foo[wp->w_end.type + 1], wp->w_end.a_seek, wp->w_end.f_seek); 1159#endif /* FDEBUG */ 1160 1161 /* 1162 * XXX: We free loops that have different seek types. 1163 */ 1164 if (wp->w_end.type != TCSH_I_SEEK && wp->w_start.type == wp->w_end.type && 1165 wp->w_start.type == o.type) { 1166 if (wp->w_end.type == TCSH_F_SEEK) { 1167 if (o.f_seek >= wp->w_start.f_seek && 1168 (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek)) 1169 break; 1170 } 1171 else { 1172 if (o.a_seek >= wp->w_start.a_seek && 1173 (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek)) 1174 break; 1175 } 1176 } 1177 1178 wpfree(wp); 1179 } 1180} 1181 1182/*ARGSUSED*/ 1183void 1184doecho(Char **v, struct command *c) 1185{ 1186 USE(c); 1187 xecho(' ', v); 1188} 1189 1190/*ARGSUSED*/ 1191void 1192doglob(Char **v, struct command *c) 1193{ 1194 USE(c); 1195 xecho(0, v); 1196 flush(); 1197} 1198 1199static void 1200xecho(int sep, Char **v) 1201{ 1202 Char *cp, **globbed = NULL; 1203 int nonl = 0; 1204 int echo_style = ECHO_STYLE; 1205 struct varent *vp; 1206 1207 if ((vp = adrof(STRecho_style)) != NULL && vp->vec != NULL && 1208 vp->vec[0] != NULL) { 1209 if (Strcmp(vp->vec[0], STRbsd) == 0) 1210 echo_style = BSD_ECHO; 1211 else if (Strcmp(vp->vec[0], STRsysv) == 0) 1212 echo_style = SYSV_ECHO; 1213 else if (Strcmp(vp->vec[0], STRboth) == 0) 1214 echo_style = BOTH_ECHO; 1215 else if (Strcmp(vp->vec[0], STRnone) == 0) 1216 echo_style = NONE_ECHO; 1217 } 1218 1219 v++; 1220 if (*v == 0) 1221 goto done; 1222 if (setintr) { 1223 int old_pintr_disabled; 1224 pintr_push_enable(&old_pintr_disabled); 1225 v = glob_all_or_error(v); 1226 cleanup_until(&old_pintr_disabled); 1227 } else { 1228 v = glob_all_or_error(v); 1229 } 1230 globbed = v; 1231 if (globbed != NULL) 1232 cleanup_push(globbed, blk_cleanup); 1233 1234 if ((echo_style & BSD_ECHO) != 0 && sep == ' ' && *v && eq(*v, STRmn)) 1235 nonl++, v++; 1236 1237 while ((cp = *v++) != 0) { 1238 Char c; 1239 1240 if (setintr) { 1241 int old_pintr_disabled; 1242 1243 pintr_push_enable(&old_pintr_disabled); 1244 cleanup_until(&old_pintr_disabled); 1245 } 1246 while ((c = *cp++) != 0) { 1247 if ((echo_style & SYSV_ECHO) != 0 && c == '\\') { 1248 switch (c = *cp++) { 1249 case 'a': 1250 c = '\a'; 1251 break; 1252 case 'b': 1253 c = '\b'; 1254 break; 1255 case 'c': 1256 nonl = 1; 1257 goto done; 1258 case 'e': 1259#if 0 /* Windows does not understand \e */ 1260 c = '\e'; 1261#else 1262 c = CTL_ESC('\033'); 1263#endif 1264 break; 1265 case 'f': 1266 c = '\f'; 1267 break; 1268 case 'n': 1269 c = '\n'; 1270 break; 1271 case 'r': 1272 c = '\r'; 1273 break; 1274 case 't': 1275 c = '\t'; 1276 break; 1277 case 'v': 1278 c = '\v'; 1279 break; 1280 case '\\': 1281 c = '\\'; 1282 break; 1283 case '0': 1284 c = 0; 1285 if (*cp >= '0' && *cp < '8') 1286 c = c * 8 + *cp++ - '0'; 1287 if (*cp >= '0' && *cp < '8') 1288 c = c * 8 + *cp++ - '0'; 1289 if (*cp >= '0' && *cp < '8') 1290 c = c * 8 + *cp++ - '0'; 1291 break; 1292 case '\0': 1293 c = '\\'; 1294 cp--; 1295 break; 1296 default: 1297 xputchar('\\' | QUOTE); 1298 break; 1299 } 1300 } 1301 xputwchar(c | QUOTE); 1302 1303 } 1304 if (*v) 1305 xputchar(sep | QUOTE); 1306 } 1307done: 1308 if (sep && nonl == 0) 1309 xputchar('\n'); 1310 else 1311 flush(); 1312 if (globbed != NULL) 1313 cleanup_until(globbed); 1314} 1315 1316/* check whether an environment variable should invoke 'set_locale()' */ 1317static int 1318islocale_var(Char *var) 1319{ 1320 static Char *locale_vars[] = { 1321 STRLANG, STRLC_ALL, STRLC_CTYPE, STRLC_NUMERIC, 1322 STRLC_TIME, STRLC_COLLATE, STRLC_MESSAGES, STRLC_MONETARY, 0 1323 }; 1324 Char **v; 1325 1326 for (v = locale_vars; *v; ++v) 1327 if (eq(var, *v)) 1328 return 1; 1329 return 0; 1330} 1331 1332static void 1333xlate_cr_cleanup(void *dummy) 1334{ 1335 USE(dummy); 1336 xlate_cr = 0; 1337} 1338 1339/*ARGSUSED*/ 1340void 1341doprintenv(Char **v, struct command *c) 1342{ 1343 Char *e; 1344 1345 USE(c); 1346 v++; 1347 if (*v == 0) { 1348 Char **ep; 1349 1350 xlate_cr = 1; 1351 cleanup_push(&xlate_cr, xlate_cr_cleanup); 1352 for (ep = STR_environ; *ep; ep++) { 1353 if (setintr) { 1354 int old_pintr_disabled; 1355 1356 pintr_push_enable(&old_pintr_disabled); 1357 cleanup_until(&old_pintr_disabled); 1358 } 1359 xprintf("%S\n", *ep); 1360 } 1361 cleanup_until(&xlate_cr); 1362 } 1363 else if ((e = tgetenv(*v)) != NULL) { 1364 int old_output_raw; 1365 1366 old_output_raw = output_raw; 1367 output_raw = 1; 1368 cleanup_push(&old_output_raw, output_raw_restore); 1369 xprintf("%S\n", e); 1370 cleanup_until(&old_output_raw); 1371 } 1372 else 1373 setcopy(STRstatus, STR1, VAR_READWRITE); 1374} 1375 1376/* from "Karl Berry." <karl%mote.umb.edu@relay.cs.net> -- for NeXT things 1377 (and anything else with a modern compiler) */ 1378 1379/*ARGSUSED*/ 1380void 1381dosetenv(Char **v, struct command *c) 1382{ 1383 Char *vp, *lp; 1384 1385 USE(c); 1386 if (*++v == 0) { 1387 doprintenv(--v, 0); 1388 return; 1389 } 1390 1391 vp = *v++; 1392 lp = vp; 1393 1394 if (!letter(*lp)) 1395 stderror(ERR_NAME | ERR_VARBEGIN); 1396 do { 1397 lp++; 1398 } while (alnum(*lp) || *lp == '.'); 1399 if (*lp != '\0') 1400 stderror(ERR_NAME | ERR_VARALNUM); 1401 1402 if ((lp = *v++) == 0) 1403 lp = STRNULL; 1404 1405 lp = globone(lp, G_APPEND); 1406 cleanup_push(lp, xfree); 1407 tsetenv(vp, lp); 1408 if (eq(vp, STRKPATH)) { 1409 importpath(lp); 1410 dohash(NULL, NULL); 1411 cleanup_until(lp); 1412 return; 1413 } 1414 1415#ifdef apollo 1416 if (eq(vp, STRSYSTYPE)) { 1417 dohash(NULL, NULL); 1418 cleanup_until(lp); 1419 return; 1420 } 1421#endif /* apollo */ 1422 1423 /* dspkanji/dspmbyte autosetting */ 1424 /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */ 1425#if defined(DSPMBYTE) 1426 if(eq(vp, STRLANG) && !adrof(CHECK_MBYTEVAR)) { 1427 autoset_dspmbyte(lp); 1428 } 1429#endif 1430 1431 if (islocale_var(vp)) { 1432#ifdef NLS 1433 int k; 1434 1435# ifdef SETLOCALEBUG 1436 dont_free = 1; 1437# endif /* SETLOCALEBUG */ 1438 (void) setlocale(LC_ALL, ""); 1439# ifdef LC_COLLATE 1440 (void) setlocale(LC_COLLATE, ""); 1441# endif 1442# ifdef LC_CTYPE 1443 (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 1444# endif /* LC_CTYPE */ 1445# if defined(AUTOSET_KANJI) 1446 autoset_kanji(); 1447# endif /* AUTOSET_KANJI */ 1448# ifdef NLS_CATALOGS 1449# ifdef LC_MESSAGES 1450 (void) setlocale(LC_MESSAGES, ""); 1451# endif /* LC_MESSAGES */ 1452 nlsclose(); 1453 nlsinit(); 1454# endif /* NLS_CATALOGS */ 1455# ifdef SETLOCALEBUG 1456 dont_free = 0; 1457# endif /* SETLOCALEBUG */ 1458# ifdef STRCOLLBUG 1459 fix_strcoll_bug(); 1460# endif /* STRCOLLBUG */ 1461 tw_cmd_free(); /* since the collation sequence has changed */ 1462 for (k = 0200; k <= 0377 && !Isprint(CTL_ESC(k)); k++) 1463 continue; 1464 AsciiOnly = MB_CUR_MAX == 1 && k > 0377; 1465#else /* !NLS */ 1466 AsciiOnly = 0; 1467#endif /* NLS */ 1468 NLSMapsAreInited = 0; 1469 ed_Init(); 1470 if (MapsAreInited && !NLSMapsAreInited) 1471 ed_InitNLSMaps(); 1472 cleanup_until(lp); 1473 return; 1474 } 1475 1476#ifdef NLS_CATALOGS 1477 if (eq(vp, STRNLSPATH)) { 1478 nlsclose(); 1479 nlsinit(); 1480 } 1481#endif 1482 1483 if (eq(vp, STRNOREBIND)) { 1484 NoNLSRebind = 1; 1485 MapsAreInited = 0; 1486 NLSMapsAreInited = 0; 1487 ed_InitMaps(); 1488 cleanup_until(lp); 1489 return; 1490 } 1491#ifdef WINNT_NATIVE 1492 if (eq(vp, STRtcshlang)) { 1493 nlsinit(); 1494 cleanup_until(lp); 1495 return; 1496 } 1497#endif /* WINNT_NATIVE */ 1498 if (eq(vp, STRKTERM)) { 1499 char *t; 1500 1501 setv(STRterm, quote(lp), VAR_READWRITE); /* lp memory used here */ 1502 cleanup_ignore(lp); 1503 cleanup_until(lp); 1504 t = short2str(lp); 1505 if (noediting && strcmp(t, "unknown") != 0 && strcmp(t,"dumb") != 0) { 1506 editing = 1; 1507 noediting = 0; 1508 setNS(STRedit); 1509 } 1510 GotTermCaps = 0; 1511 ed_Init(); 1512 return; 1513 } 1514 1515 if (eq(vp, STRKHOME)) { 1516 Char *canon; 1517 /* 1518 * convert to canonical pathname (possibly resolving symlinks) 1519 */ 1520 canon = dcanon(lp, lp); 1521 cleanup_ignore(lp); 1522 cleanup_until(lp); 1523 cleanup_push(canon, xfree); 1524 setv(STRhome, quote(canon), VAR_READWRITE); /* lp memory used here */ 1525 cleanup_ignore(canon); 1526 cleanup_until(canon); 1527 1528 /* fix directory stack for new tilde home */ 1529 dtilde(); 1530 return; 1531 } 1532 1533 if (eq(vp, STRKSHLVL)) { 1534 setv(STRshlvl, quote(lp), VAR_READWRITE); /* lp memory used here */ 1535 cleanup_ignore(lp); 1536 cleanup_until(lp); 1537 return; 1538 } 1539 1540 if (eq(vp, STRKUSER)) { 1541 setv(STRuser, quote(lp), VAR_READWRITE); /* lp memory used here */ 1542 cleanup_ignore(lp); 1543 cleanup_until(lp); 1544 return; 1545 } 1546 1547 if (eq(vp, STRKGROUP)) { 1548 setv(STRgroup, quote(lp), VAR_READWRITE); /* lp memory used here */ 1549 cleanup_ignore(lp); 1550 cleanup_until(lp); 1551 return; 1552 } 1553 1554#ifdef COLOR_LS_F 1555 if (eq(vp, STRLS_COLORS)) { 1556 parseLS_COLORS(lp); 1557 cleanup_until(lp); 1558 return; 1559 } 1560 if (eq(vp, STRLSCOLORS)) { 1561 parseLSCOLORS(lp); 1562 cleanup_until(lp); 1563 return; 1564 } 1565#endif /* COLOR_LS_F */ 1566 1567#ifdef SIG_WINDOW 1568 /* 1569 * Load/Update $LINES $COLUMNS 1570 */ 1571 if ((eq(lp, STRNULL) && (eq(vp, STRLINES) || eq(vp, STRCOLUMNS))) || 1572 eq(vp, STRTERMCAP)) { 1573 cleanup_until(lp); 1574 check_window_size(1); 1575 return; 1576 } 1577 1578 /* 1579 * Change the size to the one directed by $LINES and $COLUMNS 1580 */ 1581 if (eq(vp, STRLINES) || eq(vp, STRCOLUMNS)) { 1582#if 0 1583 GotTermCaps = 0; 1584#endif 1585 cleanup_until(lp); 1586 ed_Init(); 1587 return; 1588 } 1589#endif /* SIG_WINDOW */ 1590 cleanup_until(lp); 1591} 1592 1593/*ARGSUSED*/ 1594void 1595dounsetenv(Char **v, struct command *c) 1596{ 1597 Char **ep, *p, *n, *name; 1598 int i, maxi; 1599 1600 USE(c); 1601 /* 1602 * Find the longest environment variable 1603 */ 1604 for (maxi = 0, ep = STR_environ; *ep; ep++) { 1605 for (i = 0, p = *ep; *p && *p != '='; p++, i++) 1606 continue; 1607 if (i > maxi) 1608 maxi = i; 1609 } 1610 1611 name = xmalloc((maxi + 1) * sizeof(Char)); 1612 cleanup_push(name, xfree); 1613 1614 while (++v && *v) 1615 for (maxi = 1; maxi;) 1616 for (maxi = 0, ep = STR_environ; *ep; ep++) { 1617 for (n = name, p = *ep; *p && *p != '='; *n++ = *p++) 1618 continue; 1619 *n = '\0'; 1620 if (!Gmatch(name, *v)) 1621 continue; 1622 maxi = 1; 1623 1624 /* Unset the name. This wasn't being done until 1625 * later but most of the stuff following won't 1626 * work (particularly the setlocale() and getenv() 1627 * stuff) as intended until the name is actually 1628 * removed. (sg) 1629 */ 1630 Unsetenv(name); 1631 1632 if (eq(name, STRNOREBIND)) { 1633 NoNLSRebind = 0; 1634 MapsAreInited = 0; 1635 NLSMapsAreInited = 0; 1636 ed_InitMaps(); 1637 } 1638#ifdef apollo 1639 else if (eq(name, STRSYSTYPE)) 1640 dohash(NULL, NULL); 1641#endif /* apollo */ 1642 else if (islocale_var(name)) { 1643#ifdef NLS 1644 int k; 1645 1646# ifdef SETLOCALEBUG 1647 dont_free = 1; 1648# endif /* SETLOCALEBUG */ 1649 (void) setlocale(LC_ALL, ""); 1650# ifdef LC_COLLATE 1651 (void) setlocale(LC_COLLATE, ""); 1652# endif 1653# ifdef LC_CTYPE 1654 (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 1655# endif /* LC_CTYPE */ 1656# ifdef NLS_CATALOGS 1657# ifdef LC_MESSAGES 1658 (void) setlocale(LC_MESSAGES, ""); 1659# endif /* LC_MESSAGES */ 1660 nlsclose(); 1661 nlsinit(); 1662# endif /* NLS_CATALOGS */ 1663# ifdef SETLOCALEBUG 1664 dont_free = 0; 1665# endif /* SETLOCALEBUG */ 1666# ifdef STRCOLLBUG 1667 fix_strcoll_bug(); 1668# endif /* STRCOLLBUG */ 1669 tw_cmd_free();/* since the collation sequence has changed */ 1670 for (k = 0200; k <= 0377 && !Isprint(CTL_ESC(k)); k++) 1671 continue; 1672 AsciiOnly = MB_CUR_MAX == 1 && k > 0377; 1673#else /* !NLS */ 1674 AsciiOnly = getenv("LANG") == NULL && 1675 getenv("LC_CTYPE") == NULL; 1676#endif /* NLS */ 1677 NLSMapsAreInited = 0; 1678 ed_Init(); 1679 if (MapsAreInited && !NLSMapsAreInited) 1680 ed_InitNLSMaps(); 1681 1682 } 1683#ifdef WINNT_NATIVE 1684 else if (eq(name,(STRtcshlang))) { 1685 nls_dll_unload(); 1686 nlsinit(); 1687 } 1688#endif /* WINNT_NATIVE */ 1689#ifdef COLOR_LS_F 1690 else if (eq(name, STRLS_COLORS)) 1691 parseLS_COLORS(n); 1692 else if (eq(name, STRLSCOLORS)) 1693 parseLSCOLORS(n); 1694#endif /* COLOR_LS_F */ 1695#ifdef NLS_CATALOGS 1696 else if (eq(name, STRNLSPATH)) { 1697 nlsclose(); 1698 nlsinit(); 1699 } 1700#endif 1701 /* 1702 * start again cause the environment changes 1703 */ 1704 break; 1705 } 1706 cleanup_until(name); 1707} 1708 1709void 1710tsetenv(const Char *name, const Char *val) 1711{ 1712#ifdef SETENV_IN_LIB 1713/* 1714 * XXX: This does not work right, since tcsh cannot track changes to 1715 * the environment this way. (the builtin setenv without arguments does 1716 * not print the right stuff neither does unsetenv). This was for Mach, 1717 * it is not needed anymore. 1718 */ 1719#undef setenv 1720 char *cname; 1721 1722 if (name == NULL) 1723 return; 1724 cname = strsave(short2str(name)); 1725 setenv(cname, short2str(val), 1); 1726 xfree(cname); 1727#else /* !SETENV_IN_LIB */ 1728 Char **ep = STR_environ; 1729 const Char *ccp; 1730 Char *cp, *dp; 1731 Char *blk[2]; 1732 Char **oep = ep; 1733 1734#ifdef WINNT_NATIVE 1735 nt_set_env(name,val); 1736#endif /* WINNT_NATIVE */ 1737 for (; *ep; ep++) { 1738#ifdef WINNT_NATIVE 1739 for (ccp = name, dp = *ep; *ccp && Tolower(*ccp & TRIM) == Tolower(*dp); 1740 ccp++, dp++) 1741#else 1742 for (ccp = name, dp = *ep; *ccp && (*ccp & TRIM) == *dp; ccp++, dp++) 1743#endif /* WINNT_NATIVE */ 1744 continue; 1745 if (*ccp != 0 || *dp != '=') 1746 continue; 1747 cp = Strspl(STRequal, val); 1748 xfree(*ep); 1749 *ep = strip(Strspl(name, cp)); 1750 xfree(cp); 1751 blkfree((Char **) environ); 1752 environ = short2blk(STR_environ); 1753 return; 1754 } 1755 cp = Strspl(name, STRequal); 1756 blk[0] = strip(Strspl(cp, val)); 1757 xfree(cp); 1758 blk[1] = 0; 1759 STR_environ = blkspl(STR_environ, blk); 1760 blkfree((Char **) environ); 1761 environ = short2blk(STR_environ); 1762 xfree(oep); 1763#endif /* SETENV_IN_LIB */ 1764} 1765 1766void 1767Unsetenv(Char *name) 1768{ 1769 Char **ep = STR_environ; 1770 Char *cp, *dp; 1771 Char **oep = ep; 1772 1773#ifdef WINNT_NATIVE 1774 nt_set_env(name,NULL); 1775#endif /*WINNT_NATIVE */ 1776 for (; *ep; ep++) { 1777 for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) 1778 continue; 1779 if (*cp != 0 || *dp != '=') 1780 continue; 1781 cp = *ep; 1782 *ep = 0; 1783 STR_environ = blkspl(STR_environ, ep + 1); 1784 blkfree((Char **) environ); 1785 environ = short2blk(STR_environ); 1786 *ep = cp; 1787 xfree(cp); 1788 xfree(oep); 1789 return; 1790 } 1791} 1792 1793/*ARGSUSED*/ 1794void 1795doumask(Char **v, struct command *c) 1796{ 1797 Char *cp = v[1]; 1798 int i; 1799 1800 USE(c); 1801 if (cp == 0) { 1802 i = (int)umask(0); 1803 (void) umask(i); 1804 xprintf("%o\n", i); 1805 return; 1806 } 1807 i = 0; 1808 while (Isdigit(*cp) && *cp != '8' && *cp != '9') 1809 i = i * 8 + *cp++ - '0'; 1810 if (*cp || i < 0 || i > 0777) 1811 stderror(ERR_NAME | ERR_MASK); 1812 (void) umask(i); 1813} 1814 1815#ifndef HAVENOLIMIT 1816# ifndef BSDLIMIT 1817 typedef long RLIM_TYPE; 1818# ifdef _OSD_POSIX /* BS2000 */ 1819# include <ulimit.h> 1820# endif 1821# ifndef RLIM_INFINITY 1822# if !defined(_MINIX) && !defined(__clipper__) && !defined(_CRAY) 1823 extern RLIM_TYPE ulimit(); 1824# endif /* ! _MINIX && !__clipper__ */ 1825# define RLIM_INFINITY 0x003fffff 1826# define RLIMIT_FSIZE 1 1827# endif /* RLIM_INFINITY */ 1828# ifdef aiws 1829# define toset(a) (((a) == 3) ? 1004 : (a) + 1) 1830# define RLIMIT_DATA 3 1831# define RLIMIT_STACK 1005 1832# else /* aiws */ 1833# define toset(a) ((a) + 1) 1834# endif /* aiws */ 1835# else /* BSDLIMIT */ 1836# if (defined(BSD4_4) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) || (HPUXVERSION >= 1100)) && !defined(__386BSD__) 1837 typedef rlim_t RLIM_TYPE; 1838# else 1839# if defined(SOLARIS2) || (defined(sgi) && SYSVREL > 3) 1840 typedef rlim_t RLIM_TYPE; 1841# else 1842# if defined(_SX) 1843 typedef long long RLIM_TYPE; 1844# else /* !_SX */ 1845 typedef unsigned long RLIM_TYPE; 1846# endif /* _SX */ 1847# endif /* SOLARIS2 || (sgi && SYSVREL > 3) */ 1848# endif /* BSD4_4 && !__386BSD__ */ 1849# endif /* BSDLIMIT */ 1850 1851# if (HPUXVERSION > 700) && (HPUXVERSION < 1100) && defined(BSDLIMIT) 1852/* Yes hpux8.0 has limits but <sys/resource.h> does not make them public */ 1853/* Yes, we could have defined _KERNEL, and -I/etc/conf/h, but is that better? */ 1854# ifndef RLIMIT_CPU 1855# define RLIMIT_CPU 0 1856# define RLIMIT_FSIZE 1 1857# define RLIMIT_DATA 2 1858# define RLIMIT_STACK 3 1859# define RLIMIT_CORE 4 1860# define RLIMIT_RSS 5 1861# define RLIMIT_NOFILE 6 1862# endif /* RLIMIT_CPU */ 1863# ifndef RLIM_INFINITY 1864# define RLIM_INFINITY 0x7fffffff 1865# endif /* RLIM_INFINITY */ 1866 /* 1867 * old versions of HP/UX counted limits in 512 bytes 1868 */ 1869# ifndef SIGRTMIN 1870# define FILESIZE512 1871# endif /* SIGRTMIN */ 1872# endif /* (HPUXVERSION > 700) && (HPUXVERSION < 1100) && BSDLIMIT */ 1873 1874# if SYSVREL > 3 && defined(BSDLIMIT) && !defined(_SX) 1875/* In order to use rusage, we included "/usr/ucbinclude/sys/resource.h" in */ 1876/* sh.h. However, some SVR4 limits are defined in <sys/resource.h>. Rather */ 1877/* than include both and get warnings, we define the extra SVR4 limits here. */ 1878/* XXX: I don't understand if RLIMIT_AS is defined, why don't we define */ 1879/* RLIMIT_VMEM based on it? */ 1880# ifndef RLIMIT_VMEM 1881# define RLIMIT_VMEM 6 1882# endif 1883# ifndef RLIMIT_AS 1884# define RLIMIT_AS RLIMIT_VMEM 1885# endif 1886# endif /* SYSVREL > 3 && BSDLIMIT */ 1887 1888# if (defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) 1889# if defined(RLIMIT_AS) && !defined(RLIMIT_VMEM) 1890# define RLIMIT_VMEM RLIMIT_AS 1891# endif 1892/* 1893 * Oh well, <asm-generic/resource.h> has it, but <bits/resource.h> does not 1894 * Linux headers: When the left hand does not know what the right hand does. 1895 */ 1896# if defined(RLIMIT_RTPRIO) && !defined(RLIMIT_RTTIME) 1897# define RLIMIT_RTTIME (RLIMIT_RTPRIO + 1) 1898# endif 1899# endif 1900 1901struct limits limits[] = 1902{ 1903# ifdef RLIMIT_CPU 1904 { RLIMIT_CPU, "cputime", 1, "seconds" }, 1905# endif /* RLIMIT_CPU */ 1906 1907# ifdef RLIMIT_FSIZE 1908# ifndef aiws 1909 { RLIMIT_FSIZE, "filesize", 1024, "kbytes" }, 1910# else 1911 { RLIMIT_FSIZE, "filesize", 512, "blocks" }, 1912# endif /* aiws */ 1913# endif /* RLIMIT_FSIZE */ 1914 1915# ifdef RLIMIT_DATA 1916 { RLIMIT_DATA, "datasize", 1024, "kbytes" }, 1917# endif /* RLIMIT_DATA */ 1918 1919# ifdef RLIMIT_STACK 1920# ifndef aiws 1921 { RLIMIT_STACK, "stacksize", 1024, "kbytes" }, 1922# else 1923 { RLIMIT_STACK, "stacksize", 1024 * 1024, "kbytes"}, 1924# endif /* aiws */ 1925# endif /* RLIMIT_STACK */ 1926 1927# ifdef RLIMIT_CORE 1928 { RLIMIT_CORE, "coredumpsize", 1024, "kbytes" }, 1929# endif /* RLIMIT_CORE */ 1930 1931# ifdef RLIMIT_RSS 1932 { RLIMIT_RSS, "memoryuse", 1024, "kbytes" }, 1933# endif /* RLIMIT_RSS */ 1934 1935# ifdef RLIMIT_UMEM 1936 { RLIMIT_UMEM, "memoryuse", 1024, "kbytes" }, 1937# endif /* RLIMIT_UMEM */ 1938 1939# ifdef RLIMIT_VMEM 1940 { RLIMIT_VMEM, "vmemoryuse", 1024, "kbytes" }, 1941# endif /* RLIMIT_VMEM */ 1942 1943# if defined(RLIMIT_HEAP) /* found on BS2000/OSD systems */ 1944 { RLIMIT_HEAP, "heapsize", 1024, "kbytes" }, 1945# endif /* RLIMIT_HEAP */ 1946 1947# ifdef RLIMIT_NOFILE 1948 { RLIMIT_NOFILE, "descriptors", 1, "" }, 1949# endif /* RLIMIT_NOFILE */ 1950 1951# ifdef RLIMIT_NPTS 1952 { RLIMIT_NPTS, "pseudoterminals", 1, "" }, 1953# endif /* RLIMIT_NPTS */ 1954 1955# ifdef RLIMIT_KQUEUES 1956 { RLIMIT_KQUEUES, "kqueues", 1, "" }, 1957# endif /* RLIMIT_KQUEUES */ 1958 1959# ifdef RLIMIT_CONCUR 1960 { RLIMIT_CONCUR, "concurrency", 1, "thread(s)" }, 1961# endif /* RLIMIT_CONCUR */ 1962 1963# ifdef RLIMIT_MEMLOCK 1964 { RLIMIT_MEMLOCK, "memorylocked", 1024, "kbytes" }, 1965# endif /* RLIMIT_MEMLOCK */ 1966 1967# ifdef RLIMIT_NPROC 1968 { RLIMIT_NPROC, "maxproc", 1, "" }, 1969# endif /* RLIMIT_NPROC */ 1970 1971# ifdef RLIMIT_NTHR 1972 { RLIMIT_NTHR, "maxthread", 1, "" }, 1973# endif /* RLIMIT_NTHR */ 1974 1975# if defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE) 1976 { RLIMIT_OFILE, "openfiles", 1, "" }, 1977# endif /* RLIMIT_OFILE && !defined(RLIMIT_NOFILE) */ 1978 1979# ifdef RLIMIT_SBSIZE 1980 { RLIMIT_SBSIZE, "sbsize", 1, "" }, 1981# endif /* RLIMIT_SBSIZE */ 1982 1983# ifdef RLIMIT_SWAP 1984 { RLIMIT_SWAP, "swapsize", 1024, "kbytes" }, 1985# endif /* RLIMIT_SWAP */ 1986 1987# ifdef RLIMIT_LOCKS 1988 { RLIMIT_LOCKS, "maxlocks", 1, "" }, 1989# endif /* RLIMIT_LOCKS */ 1990 1991# ifdef RLIMIT_POSIXLOCKS 1992 { RLIMIT_POSIXLOCKS,"posixlocks", 1, "" }, 1993# endif /* RLIMIT_POSIXLOCKS */ 1994 1995# ifdef RLIMIT_SIGPENDING 1996 { RLIMIT_SIGPENDING,"maxsignal", 1, "" }, 1997# endif /* RLIMIT_SIGPENDING */ 1998 1999# ifdef RLIMIT_MSGQUEUE 2000 { RLIMIT_MSGQUEUE, "maxmessage", 1, "" }, 2001# endif /* RLIMIT_MSGQUEUE */ 2002 2003# ifdef RLIMIT_NICE 2004 { RLIMIT_NICE, "maxnice", 1, "" }, 2005# endif /* RLIMIT_NICE */ 2006 2007# ifdef RLIMIT_RTPRIO 2008 { RLIMIT_RTPRIO, "maxrtprio", 1, "" }, 2009# endif /* RLIMIT_RTPRIO */ 2010 2011# ifdef RLIMIT_RTTIME 2012 { RLIMIT_RTTIME, "maxrttime", 1, "usec" }, 2013# endif /* RLIMIT_RTTIME */ 2014 2015 { -1, NULL, 0, NULL } 2016}; 2017 2018static struct limits *findlim (Char *); 2019static RLIM_TYPE getval (struct limits *, Char **); 2020static int strtail (Char *, const char *); 2021static void limtail (Char *, const char *); 2022static void limtail2 (Char *, const char *, const char *); 2023static void plim (struct limits *, int); 2024static int setlim (struct limits *, int, RLIM_TYPE); 2025 2026#ifdef convex 2027static RLIM_TYPE 2028restrict_limit(double value) 2029{ 2030 /* 2031 * is f too large to cope with? return the maximum or minimum int 2032 */ 2033 if (value > (double) INT_MAX) 2034 return (RLIM_TYPE) INT_MAX; 2035 else if (value < (double) INT_MIN) 2036 return (RLIM_TYPE) INT_MIN; 2037 else 2038 return (RLIM_TYPE) value; 2039} 2040#else /* !convex */ 2041# define restrict_limit(x) ((RLIM_TYPE) (x)) 2042#endif /* convex */ 2043 2044 2045static struct limits * 2046findlim(Char *cp) 2047{ 2048 struct limits *lp, *res; 2049 2050 res = NULL; 2051 for (lp = limits; lp->limconst >= 0; lp++) 2052 if (prefix(cp, str2short(lp->limname))) { 2053 if (res) 2054 stderror(ERR_NAME | ERR_AMBIG); 2055 res = lp; 2056 } 2057 if (res) 2058 return (res); 2059 stderror(ERR_NAME | ERR_LIMIT); 2060 /* NOTREACHED */ 2061 return (0); 2062} 2063 2064/*ARGSUSED*/ 2065void 2066dolimit(Char **v, struct command *c) 2067{ 2068 struct limits *lp; 2069 RLIM_TYPE limit; 2070 int hard = 0; 2071 2072 USE(c); 2073 v++; 2074 if (*v && eq(*v, STRmh)) { 2075 hard = 1; 2076 v++; 2077 } 2078 if (*v == 0) { 2079 for (lp = limits; lp->limconst >= 0; lp++) 2080 plim(lp, hard); 2081 return; 2082 } 2083 lp = findlim(v[0]); 2084 if (v[1] == 0) { 2085 plim(lp, hard); 2086 return; 2087 } 2088 limit = getval(lp, v + 1); 2089 if (setlim(lp, hard, limit) < 0) 2090 stderror(ERR_SILENT); 2091} 2092 2093static RLIM_TYPE 2094getval(struct limits *lp, Char **v) 2095{ 2096 float f; 2097 Char *cp = *v++; 2098 2099 f = atof(short2str(cp)); 2100 2101# ifdef convex 2102 /* 2103 * is f too large to cope with. limit f to minint, maxint - X-6768 by 2104 * strike 2105 */ 2106 if ((f < (double) INT_MIN) || (f > (double) INT_MAX)) { 2107 stderror(ERR_NAME | ERR_TOOLARGE); 2108 } 2109# endif /* convex */ 2110 2111 while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') 2112 cp++; 2113 if (*cp == 0) { 2114 if (*v == 0) 2115 return restrict_limit((f * lp->limdiv) + 0.5); 2116 cp = *v; 2117 } 2118 switch (*cp) { 2119# ifdef RLIMIT_CPU 2120 case ':': 2121 if (lp->limconst != RLIMIT_CPU) 2122 goto badscal; 2123 return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f * 60.0 + atof(short2str(cp + 1)))); 2124 case 'h': 2125 if (lp->limconst != RLIMIT_CPU) 2126 goto badscal; 2127 limtail(cp, "hours"); 2128 f *= 3600.0; 2129 break; 2130# endif /* RLIMIT_CPU */ 2131 case 'm': 2132# ifdef RLIMIT_CPU 2133 if (lp->limconst == RLIMIT_CPU) { 2134 limtail(cp, "minutes"); 2135 f *= 60.0; 2136 break; 2137 } 2138# endif /* RLIMIT_CPU */ 2139 limtail2(cp, "megabytes", "mbytes"); 2140 f *= 1024.0 * 1024.0; 2141 break; 2142# ifdef RLIMIT_CPU 2143 case 's': 2144 if (lp->limconst != RLIMIT_CPU) 2145 goto badscal; 2146 limtail(cp, "seconds"); 2147 break; 2148# endif /* RLIMIT_CPU */ 2149 case 'G': 2150 *cp = 'g'; 2151 /*FALLTHROUGH*/ 2152 case 'g': 2153# ifdef RLIMIT_CPU 2154 if (lp->limconst == RLIMIT_CPU) 2155 goto badscal; 2156# endif /* RLIMIT_CPU */ 2157 limtail2(cp, "gigabytes", "gbytes"); 2158 f *= 1024.0 * 1024.0 * 1024.0; 2159 break; 2160 case 'M': 2161# ifdef RLIMIT_CPU 2162 if (lp->limconst == RLIMIT_CPU) 2163 goto badscal; 2164# endif /* RLIMIT_CPU */ 2165 *cp = 'm'; 2166 limtail2(cp, "megabytes", "mbytes"); 2167 f *= 1024.0 * 1024.0; 2168 break; 2169 case 'k': 2170# ifdef RLIMIT_CPU 2171 if (lp->limconst == RLIMIT_CPU) 2172 goto badscal; 2173# endif /* RLIMIT_CPU */ 2174 limtail2(cp, "kilobytes", "kbytes"); 2175 f *= 1024.0; 2176 break; 2177 case 'b': 2178# ifdef RLIMIT_CPU 2179 if (lp->limconst == RLIMIT_CPU) 2180 goto badscal; 2181# endif /* RLIMIT_CPU */ 2182 limtail(cp, "blocks"); 2183 f *= 512.0; 2184 break; 2185 case 'u': 2186 limtail(cp, "unlimited"); 2187 return ((RLIM_TYPE) RLIM_INFINITY); 2188 default: 2189# ifdef RLIMIT_CPU 2190badscal: 2191# endif /* RLIMIT_CPU */ 2192 stderror(ERR_NAME | ERR_SCALEF); 2193 } 2194# ifdef convex 2195 return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f + 0.5)); 2196# else 2197 f += 0.5; 2198 if (f > (float) ((RLIM_TYPE) RLIM_INFINITY)) 2199 return ((RLIM_TYPE) RLIM_INFINITY); 2200 else 2201 return ((RLIM_TYPE) f); 2202# endif /* convex */ 2203} 2204 2205static int 2206strtail(Char *cp, const char *str) 2207{ 2208 while (*cp && *cp == (Char)*str) 2209 cp++, str++; 2210 return (*cp != '\0'); 2211} 2212 2213static void 2214limtail(Char *cp, const char *str) 2215{ 2216 if (strtail(cp, str)) 2217 stderror(ERR_BADSCALE, str); 2218} 2219 2220static void 2221limtail2(Char *cp, const char *str1, const char *str2) 2222{ 2223 if (strtail(cp, str1) && strtail(cp, str2)) 2224 stderror(ERR_BADSCALE, str1); 2225} 2226 2227/*ARGSUSED*/ 2228static void 2229plim(struct limits *lp, int hard) 2230{ 2231# ifdef BSDLIMIT 2232 struct rlimit rlim; 2233# endif /* BSDLIMIT */ 2234 RLIM_TYPE limit; 2235 int xdiv = lp->limdiv; 2236 2237 xprintf("%-13.13s", lp->limname); 2238 2239# ifndef BSDLIMIT 2240 limit = ulimit(lp->limconst, 0); 2241# ifdef aiws 2242 if (lp->limconst == RLIMIT_DATA) 2243 limit -= 0x20000000; 2244# endif /* aiws */ 2245# else /* BSDLIMIT */ 2246 (void) getrlimit(lp->limconst, &rlim); 2247 limit = hard ? rlim.rlim_max : rlim.rlim_cur; 2248# endif /* BSDLIMIT */ 2249 2250# if !defined(BSDLIMIT) || defined(FILESIZE512) 2251 /* 2252 * Christos: filesize comes in 512 blocks. we divide by 2 to get 1024 2253 * blocks. Note we cannot pre-multiply cause we might overflow (A/UX) 2254 */ 2255 if (lp->limconst == RLIMIT_FSIZE) { 2256 if (limit >= (RLIM_INFINITY / 512)) 2257 limit = RLIM_INFINITY; 2258 else 2259 xdiv = (xdiv == 1024 ? 2 : 1); 2260 } 2261# endif /* !BSDLIMIT || FILESIZE512 */ 2262 2263 if (limit == RLIM_INFINITY) 2264 xprintf("unlimited"); 2265 else 2266# if defined(RLIMIT_CPU) && defined(_OSD_POSIX) 2267 if (lp->limconst == RLIMIT_CPU && 2268 (unsigned long)limit >= 0x7ffffffdUL) 2269 xprintf("unlimited"); 2270 else 2271# endif 2272# ifdef RLIMIT_CPU 2273 if (lp->limconst == RLIMIT_CPU) 2274 psecs(limit); 2275 else 2276# endif /* RLIMIT_CPU */ 2277 xprintf("%ld %s", (long) (limit / xdiv), lp->limscale); 2278 xputchar('\n'); 2279} 2280 2281/*ARGSUSED*/ 2282void 2283dounlimit(Char **v, struct command *c) 2284{ 2285 struct limits *lp; 2286 int lerr = 0; 2287 int hard = 0; 2288 int force = 0; 2289 2290 USE(c); 2291 while (*++v && **v == '-') { 2292 Char *vp = *v; 2293 while (*++vp) 2294 switch (*vp) { 2295 case 'f': 2296 force = 1; 2297 break; 2298 case 'h': 2299 hard = 1; 2300 break; 2301 default: 2302 stderror(ERR_ULIMUS); 2303 break; 2304 } 2305 } 2306 2307 if (*v == 0) { 2308 for (lp = limits; lp->limconst >= 0; lp++) 2309 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0) 2310 lerr++; 2311 if (!force && lerr) 2312 stderror(ERR_SILENT); 2313 return; 2314 } 2315 while (*v) { 2316 lp = findlim(*v++); 2317 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0 && !force) 2318 stderror(ERR_SILENT); 2319 } 2320} 2321 2322static int 2323setlim(struct limits *lp, int hard, RLIM_TYPE limit) 2324{ 2325# ifdef BSDLIMIT 2326 struct rlimit rlim; 2327 2328 (void) getrlimit(lp->limconst, &rlim); 2329 2330# ifdef FILESIZE512 2331 /* Even though hpux has setrlimit(), it expects fsize in 512 byte blocks */ 2332 if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 2333 limit /= 512; 2334# endif /* FILESIZE512 */ 2335 if (hard) 2336 rlim.rlim_max = limit; 2337 else if (limit == RLIM_INFINITY && euid != 0) 2338 rlim.rlim_cur = rlim.rlim_max; 2339 else 2340 rlim.rlim_cur = limit; 2341 2342 if (rlim.rlim_cur > rlim.rlim_max) 2343 rlim.rlim_max = rlim.rlim_cur; 2344 2345 if (setrlimit(lp->limconst, &rlim) < 0) { 2346# else /* BSDLIMIT */ 2347 if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 2348 limit /= 512; 2349# ifdef aiws 2350 if (lp->limconst == RLIMIT_DATA) 2351 limit += 0x20000000; 2352# endif /* aiws */ 2353 if (ulimit(toset(lp->limconst), limit) < 0) { 2354# endif /* BSDLIMIT */ 2355 int err; 2356 char *op, *type; 2357 2358 err = errno; 2359 op = strsave(limit == RLIM_INFINITY ? CGETS(15, 2, "remove") : 2360 CGETS(15, 3, "set")); 2361 cleanup_push(op, xfree); 2362 type = strsave(hard ? CGETS(15, 4, " hard") : ""); 2363 cleanup_push(type, xfree); 2364 xprintf(CGETS(15, 1, "%s: %s: Can't %s%s limit (%s)\n"), bname, 2365 lp->limname, op, type, strerror(err)); 2366 cleanup_until(op); 2367 return (-1); 2368 } 2369 return (0); 2370} 2371 2372#endif /* !HAVENOLIMIT */ 2373 2374/*ARGSUSED*/ 2375void 2376dosuspend(Char **v, struct command *c) 2377{ 2378#ifdef BSDJOBS 2379 struct sigaction old; 2380#endif /* BSDJOBS */ 2381 2382 USE(c); 2383 USE(v); 2384 2385 if (loginsh) 2386 stderror(ERR_SUSPLOG); 2387 untty(); 2388 2389#ifdef BSDJOBS 2390 sigaction(SIGTSTP, NULL, &old); 2391 signal(SIGTSTP, SIG_DFL); 2392 (void) kill(0, SIGTSTP); 2393 /* the shell stops here */ 2394 sigaction(SIGTSTP, &old, NULL); 2395#else /* !BSDJOBS */ 2396 stderror(ERR_JOBCONTROL); 2397#endif /* BSDJOBS */ 2398 2399#ifdef BSDJOBS 2400 if (tpgrp != -1) { 2401 if (grabpgrp(FSHTTY, opgrp) == -1) 2402 stderror(ERR_SYSTEM, "tcgetpgrp", strerror(errno)); 2403 (void) setpgid(0, shpgrp); 2404 (void) tcsetpgrp(FSHTTY, shpgrp); 2405 } 2406#endif /* BSDJOBS */ 2407 (void) setdisc(FSHTTY); 2408} 2409 2410/* This is the dreaded EVAL built-in. 2411 * If you don't fiddle with file descriptors, and reset didfds, 2412 * this command will either ignore redirection inside or outside 2413 * its arguments, e.g. eval "date >x" vs. eval "date" >x 2414 * The stuff here seems to work, but I did it by trial and error rather 2415 * than really knowing what was going on. If tpgrp is zero, we are 2416 * probably a background eval, e.g. "eval date &", and we want to 2417 * make sure that any processes we start stay in our pgrp. 2418 * This is also the case for "time eval date" -- stay in same pgrp. 2419 * Otherwise, under stty tostop, processes will stop in the wrong 2420 * pgrp, with no way for the shell to get them going again. -IAN! 2421 */ 2422 2423struct doeval_state 2424{ 2425 Char **evalvec, *evalp; 2426 int didfds; 2427#ifndef CLOSE_ON_EXEC 2428 int didcch; 2429#endif 2430 int saveIN, saveOUT, saveDIAG; 2431 int SHIN, SHOUT, SHDIAG; 2432}; 2433 2434static void 2435doeval_cleanup(void *xstate) 2436{ 2437 struct doeval_state *state; 2438 2439 state = xstate; 2440 evalvec = state->evalvec; 2441 evalp = state->evalp; 2442 doneinp = 0; 2443#ifndef CLOSE_ON_EXEC 2444 didcch = state->didcch; 2445#endif /* CLOSE_ON_EXEC */ 2446 didfds = state->didfds; 2447 if (state->saveIN != SHIN) 2448 xclose(SHIN); 2449 if (state->saveOUT != SHOUT) 2450 xclose(SHOUT); 2451 if (state->saveDIAG != SHDIAG) 2452 xclose(SHDIAG); 2453 close_on_exec(SHIN = dmove(state->saveIN, state->SHIN), 1); 2454 close_on_exec(SHOUT = dmove(state->saveOUT, state->SHOUT), 1); 2455 close_on_exec(SHDIAG = dmove(state->saveDIAG, state->SHDIAG), 1); 2456 if (didfds) { 2457 close_on_exec(dcopy(SHIN, 0), 1); 2458 close_on_exec(dcopy(SHOUT, 1), 1); 2459 close_on_exec(dcopy(SHDIAG, 2), 1); 2460 } 2461} 2462 2463static Char **Ggv; 2464/*ARGSUSED*/ 2465void 2466doeval(Char **v, struct command *c) 2467{ 2468 struct doeval_state state; 2469 int gflag, my_reenter; 2470 Char **gv; 2471 jmp_buf_t osetexit; 2472 2473 USE(c); 2474 v++; 2475 if (*v == 0) 2476 return; 2477 gflag = tglob(v); 2478 if (gflag) { 2479 gv = v = globall(v, gflag); 2480 if (v == 0) 2481 stderror(ERR_NOMATCH); 2482 cleanup_push(gv, blk_cleanup); 2483 v = copyblk(v); 2484 } 2485 else { 2486 gv = NULL; 2487 v = copyblk(v); 2488 trim(v); 2489 } 2490 2491 Ggv = gv; 2492 state.evalvec = evalvec; 2493 state.evalp = evalp; 2494 state.didfds = didfds; 2495#ifndef CLOSE_ON_EXEC 2496 state.didcch = didcch; 2497#endif /* CLOSE_ON_EXEC */ 2498 state.SHIN = SHIN; 2499 state.SHOUT = SHOUT; 2500 state.SHDIAG = SHDIAG; 2501 2502 (void)close_on_exec(state.saveIN = dcopy(SHIN, -1), 1); 2503 (void)close_on_exec(state.saveOUT = dcopy(SHOUT, -1), 1); 2504 (void)close_on_exec(state.saveDIAG = dcopy(SHDIAG, -1), 1); 2505 2506 cleanup_push(&state, doeval_cleanup); 2507 2508 getexit(osetexit); 2509 2510 /* PWP: setjmp/longjmp bugfix for optimizing compilers */ 2511#ifdef cray 2512 my_reenter = 1; /* assume non-zero return val */ 2513 if (setexit() == 0) { 2514 my_reenter = 0; /* Oh well, we were wrong */ 2515#else /* !cray */ 2516 if ((my_reenter = setexit()) == 0) { 2517#endif /* cray */ 2518 evalvec = v; 2519 evalp = 0; 2520 (void)close_on_exec(SHIN = dcopy(0, -1), 1); 2521 (void)close_on_exec(SHOUT = dcopy(1, -1), 1); 2522 (void)close_on_exec(SHDIAG = dcopy(2, -1), 1); 2523#ifndef CLOSE_ON_EXEC 2524 didcch = 0; 2525#endif /* CLOSE_ON_EXEC */ 2526 didfds = 0; 2527 gv = Ggv; 2528 process(0); 2529 Ggv = gv; 2530 } 2531 2532 if (my_reenter == 0) { 2533 cleanup_until(&state); 2534 if (Ggv) 2535 cleanup_until(Ggv); 2536 } 2537 2538 resexit(osetexit); 2539 if (my_reenter) 2540 stderror(ERR_SILENT); 2541} 2542 2543/*************************************************************************/ 2544/* print list of builtin commands */ 2545 2546static void 2547lbuffed_cleanup (void *dummy) 2548{ 2549 USE(dummy); 2550 lbuffed = 1; 2551} 2552 2553/*ARGSUSED*/ 2554void 2555dobuiltins(Char **v, struct command *c) 2556{ 2557 /* would use print_by_column() in tw.parse.c but that assumes 2558 * we have an array of Char * to pass.. (sg) 2559 */ 2560 const struct biltins *b; 2561 int row, col, columns, rows; 2562 unsigned int w, maxwidth; 2563 2564 USE(c); 2565 USE(v); 2566 lbuffed = 0; /* turn off line buffering */ 2567 cleanup_push(&lbuffed, lbuffed_cleanup); 2568 2569 /* find widest string */ 2570 for (maxwidth = 0, b = bfunc; b < &bfunc[nbfunc]; ++b) 2571 maxwidth = max(maxwidth, strlen(b->bname)); 2572 ++maxwidth; /* for space */ 2573 2574 columns = (TermH + 1) / maxwidth; /* PWP: terminal size change */ 2575 if (!columns) 2576 columns = 1; 2577 rows = (nbfunc + (columns - 1)) / columns; 2578 2579 for (b = bfunc, row = 0; row < rows; row++) { 2580 for (col = 0; col < columns; col++) { 2581 if (b < &bfunc[nbfunc]) { 2582 w = strlen(b->bname); 2583 xprintf("%s", b->bname); 2584 if (col < (columns - 1)) /* Not last column? */ 2585 for (; w < maxwidth; w++) 2586 xputchar(' '); 2587 ++b; 2588 } 2589 } 2590 if (row < (rows - 1)) { 2591 if (Tty_raw_mode) 2592 xputchar('\r'); 2593 xputchar('\n'); 2594 } 2595 } 2596#ifdef WINNT_NATIVE 2597 nt_print_builtins(maxwidth); 2598#else 2599 if (Tty_raw_mode) 2600 xputchar('\r'); 2601 xputchar('\n'); 2602#endif /* WINNT_NATIVE */ 2603 2604 cleanup_until(&lbuffed); /* turn back on line buffering */ 2605 flush(); 2606} 2607 2608#ifdef NLS_CATALOGS 2609char * 2610xcatgets(nl_catd ctd, int set_id, int msg_id, const char *s) 2611{ 2612 char *res; 2613 2614 errno = 0; 2615 while ((res = catgets(ctd, set_id, msg_id, s)) == s && errno == EINTR) { 2616 handle_pending_signals(); 2617 errno = 0; 2618 } 2619 return res; 2620} 2621 2622 2623# if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2624char * 2625iconv_catgets(nl_catd ctd, int set_id, int msg_id, const char *s) 2626{ 2627 static char *buf = NULL; 2628 static size_t buf_size = 0; 2629 2630 char *orig, *dest, *p; 2631 ICONV_CONST char *src; 2632 size_t src_size, dest_size; 2633 2634 orig = xcatgets(ctd, set_id, msg_id, s); 2635 if (catgets_iconv == (iconv_t)-1 || orig == s) 2636 return orig; 2637 src = orig; 2638 src_size = strlen(src) + 1; 2639 if (buf == NULL && (buf = xmalloc(buf_size = src_size + 32)) == NULL) 2640 return orig; 2641 dest = buf; 2642 while (src_size != 0) { 2643 dest_size = buf + buf_size - dest; 2644 if (iconv(catgets_iconv, &src, &src_size, &dest, &dest_size) 2645 == (size_t)-1) { 2646 switch (errno) { 2647 case E2BIG: 2648 if ((p = xrealloc(buf, buf_size * 2)) == NULL) 2649 return orig; 2650 buf_size *= 2; 2651 dest = p + (dest - buf); 2652 buf = p; 2653 break; 2654 2655 case EILSEQ: case EINVAL: default: 2656 return orig; 2657 } 2658 } 2659 } 2660 return buf; 2661} 2662# endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2663#endif /* NLS_CATALOGS */ 2664 2665void 2666nlsinit(void) 2667{ 2668#ifdef NLS_CATALOGS 2669 static const char default_catalog[] = "tcsh"; 2670 2671 char *catalog = (char *)(intptr_t)default_catalog; 2672 2673 if (adrof(STRcatalog) != NULL) 2674 catalog = xasprintf("tcsh.%s", short2str(varval(STRcatalog))); 2675#ifdef NL_CAT_LOCALE /* POSIX-compliant. */ 2676 /* 2677 * Check if LC_MESSAGES is set in the environment and use it, if so. 2678 * If not, fall back to the setting of LANG. 2679 */ 2680 catd = catopen(catalog, tgetenv(STRLC_MESSAGES) ? NL_CAT_LOCALE : 0); 2681#else /* pre-POSIX */ 2682# ifndef MCLoadBySet 2683# define MCLoadBySet 0 2684# endif 2685 catd = catopen(catalog, MCLoadBySet); 2686#endif 2687 if (catalog != default_catalog) 2688 xfree(catalog); 2689#if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2690 /* xcatgets (), not CGETS, the charset name should be in ASCII anyway. */ 2691 catgets_iconv = iconv_open (nl_langinfo (CODESET), 2692 xcatgets(catd, 255, 1, "UTF-8")); 2693#endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2694#endif /* NLS_CATALOGS */ 2695#ifdef WINNT_NATIVE 2696 nls_dll_init(); 2697#endif /* WINNT_NATIVE */ 2698 errinit(); /* init the errorlist in correct locale */ 2699 mesginit(); /* init the messages for signals */ 2700 dateinit(); /* init the messages for dates */ 2701 editinit(); /* init the editor messages */ 2702 terminit(); /* init the termcap messages */ 2703} 2704 2705void 2706nlsclose(void) 2707{ 2708#ifdef NLS_CATALOGS 2709#if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2710 if (catgets_iconv != (iconv_t)-1) { 2711 iconv_close(catgets_iconv); 2712 catgets_iconv = (iconv_t)-1; 2713 } 2714#endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2715 if (catd != (nl_catd)-1) { 2716 /* 2717 * catclose can call other functions which can call longjmp 2718 * making us re-enter this code. Prevent infinite recursion 2719 * by resetting catd. Problem reported and solved by: 2720 * Gerhard Niklasch 2721 */ 2722 nl_catd oldcatd = catd; 2723 catd = (nl_catd)-1; 2724 while (catclose(oldcatd) == -1 && errno == EINTR) 2725 handle_pending_signals(); 2726 } 2727#endif /* NLS_CATALOGS */ 2728} 2729 2730int 2731getYN(const char *prompt) 2732{ 2733 int doit; 2734 char c; 2735 2736 xprintf("%s", prompt); 2737 flush(); 2738 (void) force_read(SHIN, &c, sizeof(c)); 2739 /* 2740 * Perhaps we should use the yesexpr from the 2741 * actual locale 2742 */ 2743 doit = (strchr(CGETS(22, 14, "Yy"), c) != NULL); 2744 while (c != '\n' && force_read(SHIN, &c, sizeof(c)) == sizeof(c)) 2745 continue; 2746 return doit; 2747} 2748