159243Sobrien/* 259243Sobrien * sh.func.c: csh builtin functions 359243Sobrien */ 459243Sobrien/*- 559243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 659243Sobrien * All rights reserved. 759243Sobrien * 859243Sobrien * Redistribution and use in source and binary forms, with or without 959243Sobrien * modification, are permitted provided that the following conditions 1059243Sobrien * are met: 1159243Sobrien * 1. Redistributions of source code must retain the above copyright 1259243Sobrien * notice, this list of conditions and the following disclaimer. 1359243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1459243Sobrien * notice, this list of conditions and the following disclaimer in the 1559243Sobrien * documentation and/or other materials provided with the distribution. 16100616Smp * 3. Neither the name of the University nor the names of its contributors 1759243Sobrien * may be used to endorse or promote products derived from this software 1859243Sobrien * without specific prior written permission. 1959243Sobrien * 2059243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2159243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2259243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2359243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2459243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2559243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2659243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2759243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2859243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2959243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3059243Sobrien * SUCH DAMAGE. 3159243Sobrien */ 3259243Sobrien#include "sh.h" 3359243Sobrien#include "ed.h" 3459243Sobrien#include "tw.h" 3559243Sobrien#include "tc.h" 3669408Sache#ifdef WINNT_NATIVE 3759243Sobrien#include "nt.const.h" 3869408Sache#endif /* WINNT_NATIVE */ 3959243Sobrien 40231990Smp#if defined (NLS_CATALOGS) && defined(HAVE_ICONV) 41145479Smpstatic iconv_t catgets_iconv; /* Or (iconv_t)-1 */ 42145479Smp#endif 43145479Smp 4459243Sobrien/* 4559243Sobrien * C shell 4659243Sobrien */ 4759243Sobrien 48145479Smpextern int MapsAreInited; 49145479Smpextern int NLSMapsAreInited; 50145479Smpextern int GotTermCaps; 5159243Sobrien 5259243Sobrienstatic int zlast = -1; 5359243Sobrien 54167465Smpstatic void islogin (void); 55167465Smpstatic void preread (void); 56167465Smpstatic void doagain (void); 57167465Smpstatic const char *isrchx (int); 58167465Smpstatic void search (int, int, Char *); 59167465Smpstatic int getword (struct Strbuf *); 60195609Smpstatic struct wordent *histgetword (struct wordent *); 61167465Smpstatic void toend (void); 62167465Smpstatic void xecho (int, Char **); 63167465Smpstatic int islocale_var (Char *); 64167465Smpstatic void wpfree (struct whyle *); 6559243Sobrien 66167465Smpconst struct biltins * 67167465Smpisbfunc(struct command *t) 6859243Sobrien{ 69145479Smp Char *cp = t->t_dcom[0]; 70167465Smp const struct biltins *bp, *bp1, *bp2; 7159243Sobrien static struct biltins label = {"", dozip, 0, 0}; 7259243Sobrien static struct biltins foregnd = {"%job", dofg1, 0, 0}; 7359243Sobrien static struct biltins backgnd = {"%job &", dobg1, 0, 0}; 7459243Sobrien 7559243Sobrien /* 7659243Sobrien * We never match a builtin that has quoted the first 7759243Sobrien * character; this has been the traditional way to escape 7859243Sobrien * builtin commands. 7959243Sobrien */ 8059243Sobrien if (*cp & QUOTE) 8159243Sobrien return NULL; 8259243Sobrien 8359243Sobrien if (*cp != ':' && lastchr(cp) == ':') { 8459243Sobrien label.bname = short2str(cp); 8559243Sobrien return (&label); 8659243Sobrien } 8759243Sobrien if (*cp == '%') { 8859243Sobrien if (t->t_dflg & F_AMPERSAND) { 8959243Sobrien t->t_dflg &= ~F_AMPERSAND; 9059243Sobrien backgnd.bname = short2str(cp); 9159243Sobrien return (&backgnd); 9259243Sobrien } 9359243Sobrien foregnd.bname = short2str(cp); 9459243Sobrien return (&foregnd); 9559243Sobrien } 9659243Sobrien#ifdef WARP 9759243Sobrien /* 9859243Sobrien * This is a perhaps kludgy way to determine if the warp builtin is to be 9959243Sobrien * acknowledged or not. If checkwarp() fails, then we are to assume that 10059243Sobrien * the warp command is invalid, and carry on as we would handle any other 10159243Sobrien * non-builtin command. -- JDK 2/4/88 10259243Sobrien */ 10359243Sobrien if (eq(STRwarp, cp) && !checkwarp()) { 10459243Sobrien return (0); /* this builtin disabled */ 10559243Sobrien } 10659243Sobrien#endif /* WARP */ 10759243Sobrien /* 10859243Sobrien * Binary search Bp1 is the beginning of the current search range. Bp2 is 10959243Sobrien * one past the end. 11059243Sobrien */ 11159243Sobrien for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) { 11259243Sobrien int i; 11359243Sobrien 11459243Sobrien bp = bp1 + ((bp2 - bp1) >> 1); 11559243Sobrien if ((i = ((char) *cp) - *bp->bname) == 0 && 11659243Sobrien (i = StrQcmp(cp, str2short(bp->bname))) == 0) 11759243Sobrien return bp; 11859243Sobrien if (i < 0) 11959243Sobrien bp2 = bp; 12059243Sobrien else 12159243Sobrien bp1 = bp + 1; 12259243Sobrien } 12369408Sache#ifdef WINNT_NATIVE 12459243Sobrien return nt_check_additional_builtins(cp); 12569408Sache#endif /*WINNT_NATIVE*/ 12659243Sobrien return (0); 12759243Sobrien} 12859243Sobrien 12959243Sobrienvoid 130167465Smpfunc(struct command *t, const struct biltins *bp) 13159243Sobrien{ 13259243Sobrien int i; 13359243Sobrien 13459243Sobrien xechoit(t->t_dcom); 13559243Sobrien setname(bp->bname); 13659243Sobrien i = blklen(t->t_dcom) - 1; 13759243Sobrien if (i < bp->minargs) 13859243Sobrien stderror(ERR_NAME | ERR_TOOFEW); 13959243Sobrien if (i > bp->maxargs) 14059243Sobrien stderror(ERR_NAME | ERR_TOOMANY); 14159243Sobrien (*bp->bfunct) (t->t_dcom, t); 14259243Sobrien} 14359243Sobrien 14459243Sobrien/*ARGSUSED*/ 14559243Sobrienvoid 146167465Smpdoonintr(Char **v, struct command *c) 14759243Sobrien{ 148145479Smp Char *cp; 149145479Smp Char *vv = v[1]; 15059243Sobrien 15159243Sobrien USE(c); 152167465Smp if (parintr.sa_handler == SIG_IGN) 15359243Sobrien return; 15459243Sobrien if (setintr && intty) 15559243Sobrien stderror(ERR_NAME | ERR_TERMINAL); 15659243Sobrien cp = gointr; 15759243Sobrien gointr = 0; 158167465Smp xfree(cp); 15959243Sobrien if (vv == 0) { 160167465Smp if (setintr) 161167465Smp sigset_interrupting(SIGINT, queue_pintr); 162167465Smp else 16359243Sobrien (void) signal(SIGINT, SIG_DFL); 16459243Sobrien gointr = 0; 16559243Sobrien } 16659243Sobrien else if (eq((vv = strip(vv)), STRminus)) { 16759243Sobrien (void) signal(SIGINT, SIG_IGN); 16859243Sobrien gointr = Strsave(STRminus); 16959243Sobrien } 17059243Sobrien else { 17159243Sobrien gointr = Strsave(vv); 172167465Smp sigset_interrupting(SIGINT, queue_pintr); 17359243Sobrien } 17459243Sobrien} 17559243Sobrien 17659243Sobrien/*ARGSUSED*/ 17759243Sobrienvoid 178167465Smpdonohup(Char **v, struct command *c) 17959243Sobrien{ 18059243Sobrien USE(c); 18159243Sobrien USE(v); 18259243Sobrien if (intty) 18359243Sobrien stderror(ERR_NAME | ERR_TERMINAL); 18459243Sobrien if (setintr == 0) { 18559243Sobrien (void) signal(SIGHUP, SIG_IGN); 186167465Smp phup_disabled = 1; 18759243Sobrien#ifdef CC 18859243Sobrien submit(getpid()); 18959243Sobrien#endif /* CC */ 19059243Sobrien } 19159243Sobrien} 19259243Sobrien 19359243Sobrien/*ARGSUSED*/ 19459243Sobrienvoid 195167465Smpdohup(Char **v, struct command *c) 19659243Sobrien{ 19759243Sobrien USE(c); 19859243Sobrien USE(v); 19959243Sobrien if (intty) 20059243Sobrien stderror(ERR_NAME | ERR_TERMINAL); 20159243Sobrien if (setintr == 0) 202354195Sbrooks sigset_interrupting(SIGHUP, SIG_DFL); 20359243Sobrien} 20459243Sobrien 20559243Sobrien 20659243Sobrien/*ARGSUSED*/ 20759243Sobrienvoid 208167465Smpdozip(Char **v, struct command *c) 20959243Sobrien{ 21059243Sobrien USE(c); 21159243Sobrien USE(v); 21259243Sobrien} 21359243Sobrien 21459243Sobrien/*ARGSUSED*/ 21559243Sobrienvoid 216167465Smpdofiletest(Char **v, struct command *c) 21759243Sobrien{ 218167465Smp Char **globbed, **fileptr, *ftest, *res; 21959243Sobrien 220145479Smp USE(c); 22159243Sobrien if (*(ftest = *++v) != '-') 22259243Sobrien stderror(ERR_NAME | ERR_FILEINQ); 22359243Sobrien ++v; 22459243Sobrien 225167465Smp v = glob_all_or_error(v); 226167465Smp globbed = v; 227167465Smp cleanup_push(globbed, blk_cleanup); 22859243Sobrien 229354195Sbrooks while (*(fileptr = v++) != NULL) { 230167465Smp res = filetest(ftest, &fileptr, 0); 231167465Smp cleanup_push(res, xfree); 232167465Smp xprintf("%S", res); 233167465Smp cleanup_until(res); 23459243Sobrien if (*v) 23559243Sobrien xprintf(" "); 23659243Sobrien } 23759243Sobrien xprintf("\n"); 23859243Sobrien 239167465Smp cleanup_until(globbed); 24059243Sobrien} 24159243Sobrien 24259243Sobrienvoid 243167465Smpprvars(void) 24459243Sobrien{ 24559243Sobrien plist(&shvhed, VAR_ALL); 24659243Sobrien} 24759243Sobrien 24859243Sobrien/*ARGSUSED*/ 24959243Sobrienvoid 250167465Smpdoalias(Char **v, struct command *c) 25159243Sobrien{ 252145479Smp struct varent *vp; 253145479Smp Char *p; 25459243Sobrien 25559243Sobrien USE(c); 25659243Sobrien v++; 25759243Sobrien p = *v++; 25859243Sobrien if (p == 0) 25959243Sobrien plist(&aliases, VAR_ALL); 26059243Sobrien else if (*v == 0) { 26159243Sobrien vp = adrof1(strip(p), &aliases); 262100616Smp if (vp && vp->vec) 26359243Sobrien blkpr(vp->vec), xputchar('\n'); 26459243Sobrien } 26559243Sobrien else { 26659243Sobrien if (eq(p, STRalias) || eq(p, STRunalias)) { 26759243Sobrien setname(short2str(p)); 26859243Sobrien stderror(ERR_NAME | ERR_DANGER); 26959243Sobrien } 27059243Sobrien set1(strip(p), saveblk(v), &aliases, VAR_READWRITE); 27159243Sobrien tw_cmd_free(); 27259243Sobrien } 27359243Sobrien} 27459243Sobrien 27559243Sobrien/*ARGSUSED*/ 27659243Sobrienvoid 277167465Smpunalias(Char **v, struct command *c) 27859243Sobrien{ 27959243Sobrien USE(c); 28059243Sobrien unset1(v, &aliases); 28159243Sobrien tw_cmd_free(); 28259243Sobrien} 28359243Sobrien 28459243Sobrien/*ARGSUSED*/ 28559243Sobrienvoid 286167465Smpdologout(Char **v, struct command *c) 28759243Sobrien{ 28859243Sobrien USE(c); 28959243Sobrien USE(v); 29059243Sobrien islogin(); 29159243Sobrien goodbye(NULL, NULL); 29259243Sobrien} 29359243Sobrien 29459243Sobrien/*ARGSUSED*/ 29559243Sobrienvoid 296167465Smpdologin(Char **v, struct command *c) 29759243Sobrien{ 298131962Smp#ifdef WINNT_NATIVE 29959243Sobrien USE(c); 30059243Sobrien USE(v); 30169408Sache#else /* !WINNT_NATIVE */ 302131962Smp char **p = short2blk(v); 303167465Smp 304131962Smp USE(c); 305167465Smp cleanup_push((Char **)p, blk_cleanup); 30659243Sobrien islogin(); 30759243Sobrien rechist(NULL, adrof(STRsavehist) != NULL); 308167465Smp sigaction(SIGTERM, &parterm, NULL); 309131962Smp (void) execv(_PATH_BIN_LOGIN, p); 310131962Smp (void) execv(_PATH_USRBIN_LOGIN, p); 311167465Smp cleanup_until((Char **)p); 31259243Sobrien untty(); 31359243Sobrien xexit(1); 31469408Sache#endif /* !WINNT_NATIVE */ 31559243Sobrien} 31659243Sobrien 31759243Sobrien 31859243Sobrien#ifdef NEWGRP 31959243Sobrien/*ARGSUSED*/ 32059243Sobrienvoid 321167465Smpdonewgrp(Char **v, struct command *c) 32259243Sobrien{ 32359243Sobrien char **p; 32459243Sobrien if (chkstop == 0 && setintr) 32559243Sobrien panystop(0); 326167465Smp sigaction(SIGTERM, &parterm, NULL); 32759243Sobrien p = short2blk(v); 32859243Sobrien /* 32959243Sobrien * From Beto Appleton (beto@aixwiz.austin.ibm.com) 33059243Sobrien * Newgrp can take 2 arguments... 33159243Sobrien */ 33259243Sobrien (void) execv(_PATH_BIN_NEWGRP, p); 33359243Sobrien (void) execv(_PATH_USRBIN_NEWGRP, p); 33459243Sobrien blkfree((Char **) p); 33559243Sobrien untty(); 33659243Sobrien xexit(1); 33759243Sobrien} 33859243Sobrien#endif /* NEWGRP */ 33959243Sobrien 34059243Sobrienstatic void 341167465Smpislogin(void) 34259243Sobrien{ 34359243Sobrien if (chkstop == 0 && setintr) 34459243Sobrien panystop(0); 34559243Sobrien if (loginsh) 34659243Sobrien return; 34759243Sobrien stderror(ERR_NOTLOGIN); 34859243Sobrien} 34959243Sobrien 35059243Sobrienvoid 351167465Smpdoif(Char **v, struct command *kp) 35259243Sobrien{ 353145479Smp int i; 354145479Smp Char **vv; 35559243Sobrien 35659243Sobrien v++; 357167465Smp i = noexec ? 1 : expr(&v); 35859243Sobrien vv = v; 35959243Sobrien if (*vv == NULL) 36059243Sobrien stderror(ERR_NAME | ERR_EMPTYIF); 36159243Sobrien if (eq(*vv, STRthen)) { 36259243Sobrien if (*++vv) 36359243Sobrien stderror(ERR_NAME | ERR_IMPRTHEN); 36459243Sobrien setname(short2str(STRthen)); 36559243Sobrien /* 36659243Sobrien * If expression was zero, then scan to else , otherwise just fall into 36759243Sobrien * following code. 36859243Sobrien */ 36959243Sobrien if (!i) 37059243Sobrien search(TC_IF, 0, NULL); 37159243Sobrien return; 37259243Sobrien } 37359243Sobrien /* 37459243Sobrien * Simple command attached to this if. Left shift the node in this tree, 37559243Sobrien * munging it so we can reexecute it. 37659243Sobrien */ 37759243Sobrien if (i) { 37859243Sobrien lshift(kp->t_dcom, vv - kp->t_dcom); 37959243Sobrien reexecute(kp); 38059243Sobrien donefds(); 38159243Sobrien } 38259243Sobrien} 38359243Sobrien 38459243Sobrien/* 38559243Sobrien * Reexecute a command, being careful not 38659243Sobrien * to redo i/o redirection, which is already set up. 38759243Sobrien */ 38859243Sobrienvoid 389167465Smpreexecute(struct command *kp) 39059243Sobrien{ 39159243Sobrien kp->t_dflg &= F_SAVE; 39259243Sobrien kp->t_dflg |= F_REPEAT; 39359243Sobrien /* 39459243Sobrien * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set 39559243Sobrien * pgrp's as the jobs would then have no way to get the tty (we can't give 39659243Sobrien * it to them, and our parent wouldn't know their pgrp, etc. 39759243Sobrien */ 398100616Smp execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL, TRUE); 39959243Sobrien} 40059243Sobrien 40159243Sobrien/*ARGSUSED*/ 40259243Sobrienvoid 403167465Smpdoelse (Char **v, struct command *c) 40459243Sobrien{ 40559243Sobrien USE(c); 40659243Sobrien USE(v); 407167465Smp if (!noexec) 408167465Smp search(TC_ELSE, 0, NULL); 40959243Sobrien} 41059243Sobrien 41159243Sobrien/*ARGSUSED*/ 41259243Sobrienvoid 413167465Smpdogoto(Char **v, struct command *c) 41459243Sobrien{ 41559243Sobrien Char *lp; 41659243Sobrien 41759243Sobrien USE(c); 418167465Smp lp = globone(v[1], G_ERROR); 419167465Smp cleanup_push(lp, xfree); 420167465Smp if (!noexec) 421167465Smp gotolab(lp); 422167465Smp cleanup_until(lp); 42359243Sobrien} 42459243Sobrien 42559243Sobrienvoid 426167465Smpgotolab(Char *lab) 42759243Sobrien{ 428145479Smp struct whyle *wp; 42959243Sobrien /* 43059243Sobrien * While we still can, locate any unknown ends of existing loops. This 43159243Sobrien * obscure code is the WORST result of the fact that we don't really parse. 43259243Sobrien */ 43359243Sobrien zlast = TC_GOTO; 43459243Sobrien for (wp = whyles; wp; wp = wp->w_next) 43569408Sache if (wp->w_end.type == TCSH_F_SEEK && wp->w_end.f_seek == 0) { 43659243Sobrien search(TC_BREAK, 0, NULL); 43759243Sobrien btell(&wp->w_end); 43859243Sobrien } 43959243Sobrien else { 44059243Sobrien bseek(&wp->w_end); 44159243Sobrien } 44259243Sobrien search(TC_GOTO, 0, lab); 44359243Sobrien /* 44459243Sobrien * Eliminate loops which were exited. 44559243Sobrien */ 44659243Sobrien wfree(); 44759243Sobrien} 44859243Sobrien 44959243Sobrien/*ARGSUSED*/ 45059243Sobrienvoid 451167465Smpdoswitch(Char **v, struct command *c) 45259243Sobrien{ 453145479Smp Char *cp, *lp; 45459243Sobrien 45559243Sobrien USE(c); 45659243Sobrien v++; 45759243Sobrien if (!*v || *(*v++) != '(') 45859243Sobrien stderror(ERR_SYNTAX); 45959243Sobrien cp = **v == ')' ? STRNULL : *v++; 46059243Sobrien if (*(*v++) != ')') 46159243Sobrien v--; 46259243Sobrien if (*v) 46359243Sobrien stderror(ERR_SYNTAX); 464167465Smp lp = globone(cp, G_ERROR); 465167465Smp cleanup_push(lp, xfree); 466167465Smp if (!noexec) 467167465Smp search(TC_SWITCH, 0, lp); 468167465Smp cleanup_until(lp); 46959243Sobrien} 47059243Sobrien 47159243Sobrien/*ARGSUSED*/ 47259243Sobrienvoid 473167465Smpdobreak(Char **v, struct command *c) 47459243Sobrien{ 47559243Sobrien USE(v); 47659243Sobrien USE(c); 477167465Smp if (whyles == NULL) 478167465Smp stderror(ERR_NAME | ERR_NOTWHILE); 479167465Smp if (!noexec) 48059243Sobrien toend(); 48159243Sobrien} 48259243Sobrien 48359243Sobrien/*ARGSUSED*/ 48459243Sobrienvoid 485167465Smpdoexit(Char **v, struct command *c) 48659243Sobrien{ 48759243Sobrien USE(c); 48859243Sobrien 48959243Sobrien if (chkstop == 0 && (intty || intact) && evalvec == 0) 49059243Sobrien panystop(0); 49159243Sobrien /* 49259243Sobrien * Don't DEMAND parentheses here either. 49359243Sobrien */ 49459243Sobrien v++; 49559243Sobrien if (*v) { 496167465Smp setv(STRstatus, putn(expr(&v)), VAR_READWRITE); 49759243Sobrien if (*v) 49859243Sobrien stderror(ERR_NAME | ERR_EXPRESSION); 49959243Sobrien } 50059243Sobrien btoeof(); 50159243Sobrien#if 0 50259243Sobrien if (intty) 50359243Sobrien#endif 50459243Sobrien /* Always close, why only on ttys? */ 505167465Smp xclose(SHIN); 50659243Sobrien} 50759243Sobrien 50859243Sobrien/*ARGSUSED*/ 50959243Sobrienvoid 510167465Smpdoforeach(Char **v, struct command *c) 51159243Sobrien{ 512145479Smp Char *cp, *sp; 513145479Smp struct whyle *nwp; 514167465Smp int gflag; 51559243Sobrien 51659243Sobrien USE(c); 51759243Sobrien v++; 518231990Smp cp = sp = strip(*v); 519231990Smp if (!letter(*cp)) 52059243Sobrien stderror(ERR_NAME | ERR_VARBEGIN); 521231990Smp do { 52259243Sobrien cp++; 523231990Smp } while (alnum(*cp)); 524231990Smp if (*cp != '\0') 52559243Sobrien stderror(ERR_NAME | ERR_VARALNUM); 52659243Sobrien cp = *v++; 52759243Sobrien if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') 52859243Sobrien stderror(ERR_NAME | ERR_NOPAREN); 52959243Sobrien v++; 530167465Smp gflag = tglob(v); 53159243Sobrien if (gflag) { 532167465Smp v = globall(v, gflag); 533167465Smp if (v == 0 && !noexec) 53459243Sobrien stderror(ERR_NAME | ERR_NOMATCH); 53559243Sobrien } 53659243Sobrien else { 537167465Smp v = saveblk(v); 53859243Sobrien trim(v); 53959243Sobrien } 540167465Smp nwp = xcalloc(1, sizeof *nwp); 54159243Sobrien nwp->w_fe = nwp->w_fe0 = v; 54259243Sobrien btell(&nwp->w_start); 54359243Sobrien nwp->w_fename = Strsave(cp); 54459243Sobrien nwp->w_next = whyles; 54569408Sache nwp->w_end.type = TCSH_F_SEEK; 54659243Sobrien whyles = nwp; 54759243Sobrien /* 54859243Sobrien * Pre-read the loop so as to be more comprehensible to a terminal user. 54959243Sobrien */ 55059243Sobrien zlast = TC_FOREACH; 55159243Sobrien if (intty) 55259243Sobrien preread(); 553167465Smp if (!noexec) 554167465Smp doagain(); 55559243Sobrien} 55659243Sobrien 55759243Sobrien/*ARGSUSED*/ 55859243Sobrienvoid 559167465Smpdowhile(Char **v, struct command *c) 56059243Sobrien{ 561145479Smp int status; 562145479Smp int again = whyles != 0 && 56359243Sobrien SEEKEQ(&whyles->w_start, &lineloc) && 56459243Sobrien whyles->w_fename == 0; 56559243Sobrien 56659243Sobrien USE(c); 56759243Sobrien v++; 56859243Sobrien /* 56959243Sobrien * Implement prereading here also, taking care not to evaluate the 57059243Sobrien * expression before the loop has been read up from a terminal. 57159243Sobrien */ 572167465Smp if (noexec) 573167465Smp status = 0; 574167465Smp else if (intty && !again) 57559243Sobrien status = !exp0(&v, 1); 57659243Sobrien else 57759243Sobrien status = !expr(&v); 578167465Smp if (*v && !noexec) 57959243Sobrien stderror(ERR_NAME | ERR_EXPRESSION); 58059243Sobrien if (!again) { 581167465Smp struct whyle *nwp = xcalloc(1, sizeof(*nwp)); 58259243Sobrien 58359243Sobrien nwp->w_start = lineloc; 58469408Sache nwp->w_end.type = TCSH_F_SEEK; 58559243Sobrien nwp->w_end.f_seek = 0; 586231990Smp nwp->w_end.a_seek = 0; 58759243Sobrien nwp->w_next = whyles; 58859243Sobrien whyles = nwp; 58959243Sobrien zlast = TC_WHILE; 59059243Sobrien if (intty) { 59159243Sobrien /* 59259243Sobrien * The tty preread 59359243Sobrien */ 59459243Sobrien preread(); 59559243Sobrien doagain(); 59659243Sobrien return; 59759243Sobrien } 59859243Sobrien } 59959243Sobrien if (status) 60059243Sobrien /* We ain't gonna loop no more, no more! */ 60159243Sobrien toend(); 60259243Sobrien} 60359243Sobrien 60459243Sobrienstatic void 605167465Smppreread(void) 60659243Sobrien{ 607167465Smp int old_pintr_disabled; 608167465Smp 60969408Sache whyles->w_end.type = TCSH_I_SEEK; 61059243Sobrien if (setintr) 611167465Smp pintr_push_enable(&old_pintr_disabled); 61259243Sobrien search(TC_BREAK, 0, NULL); /* read the expression in */ 61359243Sobrien if (setintr) 614167465Smp cleanup_until(&old_pintr_disabled); 61559243Sobrien btell(&whyles->w_end); 61659243Sobrien} 61759243Sobrien 61859243Sobrien/*ARGSUSED*/ 61959243Sobrienvoid 620167465Smpdoend(Char **v, struct command *c) 62159243Sobrien{ 62259243Sobrien USE(v); 62359243Sobrien USE(c); 62459243Sobrien if (!whyles) 62559243Sobrien stderror(ERR_NAME | ERR_NOTWHILE); 62659243Sobrien btell(&whyles->w_end); 627167465Smp if (!noexec) 628167465Smp doagain(); 62959243Sobrien} 63059243Sobrien 63159243Sobrien/*ARGSUSED*/ 63259243Sobrienvoid 633167465Smpdocontin(Char **v, struct command *c) 63459243Sobrien{ 63559243Sobrien USE(v); 63659243Sobrien USE(c); 63759243Sobrien if (!whyles) 63859243Sobrien stderror(ERR_NAME | ERR_NOTWHILE); 639167465Smp if (!noexec) 640167465Smp doagain(); 64159243Sobrien} 64259243Sobrien 64359243Sobrienstatic void 644167465Smpdoagain(void) 64559243Sobrien{ 64659243Sobrien /* Repeating a while is simple */ 64759243Sobrien if (whyles->w_fename == 0) { 64859243Sobrien bseek(&whyles->w_start); 64959243Sobrien return; 65059243Sobrien } 65159243Sobrien /* 65259243Sobrien * The foreach variable list actually has a spurious word ")" at the end of 65359243Sobrien * the w_fe list. Thus we are at the of the list if one word beyond this 65459243Sobrien * is 0. 65559243Sobrien */ 65659243Sobrien if (!whyles->w_fe[1]) { 65759243Sobrien dobreak(NULL, NULL); 65859243Sobrien return; 65959243Sobrien } 660167465Smp setv(whyles->w_fename, quote(Strsave(*whyles->w_fe++)), VAR_READWRITE); 66159243Sobrien bseek(&whyles->w_start); 66259243Sobrien} 66359243Sobrien 66459243Sobrienvoid 665167465Smpdorepeat(Char **v, struct command *kp) 66659243Sobrien{ 667100616Smp int i = 1; 66859243Sobrien 669100616Smp do { 670100616Smp i *= getn(v[1]); 671100616Smp lshift(v, 2); 672100616Smp } while (v[0] != NULL && Strcmp(v[0], STRrepeat) == 0); 673167465Smp if (noexec) 674167465Smp i = 1; 675100616Smp 676167465Smp if (setintr) { 677167465Smp pintr_disabled++; 678167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 679167465Smp } 68059243Sobrien while (i > 0) { 681167465Smp if (setintr && pintr_disabled == 1) { 682167465Smp cleanup_until(&pintr_disabled); 683167465Smp pintr_disabled++; 684167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 685167465Smp } 68659243Sobrien reexecute(kp); 68759243Sobrien --i; 68859243Sobrien } 689195609Smp if (setintr && pintr_disabled == 1) 690195609Smp cleanup_until(&pintr_disabled); 69159243Sobrien donefds(); 69259243Sobrien} 69359243Sobrien 69459243Sobrien/*ARGSUSED*/ 69559243Sobrienvoid 696167465Smpdoswbrk(Char **v, struct command *c) 69759243Sobrien{ 69859243Sobrien USE(v); 69959243Sobrien USE(c); 700167465Smp if (!noexec) 701167465Smp search(TC_BRKSW, 0, NULL); 70259243Sobrien} 70359243Sobrien 70459243Sobrienint 705167465Smpsrchx(Char *cp) 70659243Sobrien{ 70759243Sobrien struct srch *sp, *sp1, *sp2; 70859243Sobrien int i; 70959243Sobrien 71059243Sobrien /* 71159243Sobrien * Ignore keywords inside heredocs 71259243Sobrien */ 71359243Sobrien if (inheredoc) 71459243Sobrien return -1; 71559243Sobrien 71659243Sobrien /* 71759243Sobrien * Binary search Sp1 is the beginning of the current search range. Sp2 is 71859243Sobrien * one past the end. 71959243Sobrien */ 72059243Sobrien for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) { 72159243Sobrien sp = sp1 + ((sp2 - sp1) >> 1); 72259243Sobrien if ((i = *cp - *sp->s_name) == 0 && 72359243Sobrien (i = Strcmp(cp, str2short(sp->s_name))) == 0) 72459243Sobrien return sp->s_value; 72559243Sobrien if (i < 0) 72659243Sobrien sp2 = sp; 72759243Sobrien else 72859243Sobrien sp1 = sp + 1; 72959243Sobrien } 73059243Sobrien return (-1); 73159243Sobrien} 73259243Sobrien 733145479Smpstatic const char * 734167465Smpisrchx(int n) 73559243Sobrien{ 736145479Smp struct srch *sp, *sp2; 73759243Sobrien 73859243Sobrien for (sp = srchn, sp2 = srchn + nsrchn; sp < sp2; sp++) 73959243Sobrien if (sp->s_value == n) 74059243Sobrien return (sp->s_name); 74159243Sobrien return (""); 74259243Sobrien} 74359243Sobrien 74459243Sobrien 745167465Smpstatic int Stype; 74659243Sobrienstatic Char *Sgoal; 74759243Sobrien 74859243Sobrienstatic void 749167465Smpsearch(int type, int level, Char *goal) 75059243Sobrien{ 751167465Smp struct Strbuf word = Strbuf_INIT; 752145479Smp Char *cp; 753131962Smp struct whyle *wp; 754131962Smp int wlevel = 0; 755195609Smp struct wordent *histent = NULL, *ohistent = NULL; 75659243Sobrien 757167465Smp Stype = type; 75859243Sobrien Sgoal = goal; 75959243Sobrien if (type == TC_GOTO) { 76059243Sobrien struct Ain a; 76169408Sache a.type = TCSH_F_SEEK; 76259243Sobrien a.f_seek = 0; 763231990Smp a.a_seek = 0; 76459243Sobrien bseek(&a); 76559243Sobrien } 766167465Smp cleanup_push(&word, Strbuf_cleanup); 76759243Sobrien do { 768195609Smp 769195609Smp if (intty) { 770195609Smp histent = xmalloc(sizeof(*histent)); 771195609Smp ohistent = xmalloc(sizeof(*histent)); 772195609Smp ohistent->word = STRNULL; 773195609Smp ohistent->next = histent; 774195609Smp histent->prev = ohistent; 775195609Smp } 776195609Smp 77769408Sache if (intty && fseekp == feobp && aret == TCSH_F_SEEK) 77859243Sobrien printprompt(1, isrchx(type == TC_BREAK ? zlast : type)); 77959243Sobrien /* xprintf("? "), flush(); */ 780167465Smp (void) getword(&word); 781167465Smp Strbuf_terminate(&word); 782195609Smp 783195609Smp if (intty && Strlen(word.s) > 0) { 784195609Smp histent->word = Strsave(word.s); 785195609Smp histent->next = xmalloc(sizeof(*histent)); 786195609Smp histent->next->prev = histent; 787195609Smp histent = histent->next; 788195609Smp } 789195609Smp 790167465Smp switch (srchx(word.s)) { 79159243Sobrien 79259243Sobrien case TC_ELSE: 79359243Sobrien if (level == 0 && type == TC_IF) 794167465Smp goto end; 79559243Sobrien break; 79659243Sobrien 79759243Sobrien case TC_IF: 798316957Sdchagin while (getword(&word)) { 799316957Sdchagin if (intty) { 800316957Sdchagin histent->word = Strsave(word.s); 801316957Sdchagin histent->next = xmalloc(sizeof(*histent)); 802316957Sdchagin histent->next->prev = histent; 803316957Sdchagin histent = histent->next; 804316957Sdchagin } 80559243Sobrien continue; 806316957Sdchagin } 807316957Sdchagin 80859243Sobrien if ((type == TC_IF || type == TC_ELSE) && 809167465Smp eq(word.s, STRthen)) 81059243Sobrien level++; 81159243Sobrien break; 81259243Sobrien 81359243Sobrien case TC_ENDIF: 81459243Sobrien if (type == TC_IF || type == TC_ELSE) 81559243Sobrien level--; 81659243Sobrien break; 81759243Sobrien 81859243Sobrien case TC_FOREACH: 81959243Sobrien case TC_WHILE: 820131962Smp wlevel++; 82159243Sobrien if (type == TC_BREAK) 82259243Sobrien level++; 82359243Sobrien break; 82459243Sobrien 82559243Sobrien case TC_END: 826131962Smp if (type == TC_BRKSW) { 827131962Smp if (wlevel == 0) { 828131962Smp wp = whyles; 829131962Smp if (wp) { 830131962Smp whyles = wp->w_next; 831131962Smp wpfree(wp); 832131962Smp } 833131962Smp } 834131962Smp } 83559243Sobrien if (type == TC_BREAK) 83659243Sobrien level--; 837131962Smp wlevel--; 83859243Sobrien break; 83959243Sobrien 84059243Sobrien case TC_SWITCH: 84159243Sobrien if (type == TC_SWITCH || type == TC_BRKSW) 84259243Sobrien level++; 84359243Sobrien break; 84459243Sobrien 84559243Sobrien case TC_ENDSW: 84659243Sobrien if (type == TC_SWITCH || type == TC_BRKSW) 84759243Sobrien level--; 84859243Sobrien break; 84959243Sobrien 85059243Sobrien case TC_LABEL: 851167465Smp if (type == TC_GOTO && getword(&word) && eq(word.s, goal)) 85259243Sobrien level = -1; 85359243Sobrien break; 85459243Sobrien 85559243Sobrien default: 85659243Sobrien if (type != TC_GOTO && (type != TC_SWITCH || level != 0)) 85759243Sobrien break; 858167465Smp if (word.len == 0 || word.s[word.len - 1] != ':') 85959243Sobrien break; 860167465Smp word.s[--word.len] = 0; 861167465Smp if ((type == TC_GOTO && eq(word.s, goal)) || 862167465Smp (type == TC_SWITCH && eq(word.s, STRdefault))) 86359243Sobrien level = -1; 86459243Sobrien break; 86559243Sobrien 86659243Sobrien case TC_CASE: 86759243Sobrien if (type != TC_SWITCH || level != 0) 86859243Sobrien break; 869167465Smp (void) getword(&word); 870167465Smp if (word.len != 0 && word.s[word.len - 1] == ':') 871167465Smp word.s[--word.len] = 0; 872167465Smp cp = strip(Dfix1(word.s)); 873167465Smp cleanup_push(cp, xfree); 87459243Sobrien if (Gmatch(goal, cp)) 87559243Sobrien level = -1; 876167465Smp cleanup_until(cp); 87759243Sobrien break; 87859243Sobrien 87959243Sobrien case TC_DEFAULT: 88059243Sobrien if (type == TC_SWITCH && level == 0) 88159243Sobrien level = -1; 88259243Sobrien break; 88359243Sobrien } 884195609Smp if (intty) { 885195609Smp ohistent->prev = histgetword(histent); 886195609Smp ohistent->prev->next = ohistent; 887195609Smp savehist(ohistent, 0); 888195609Smp freelex(ohistent); 889195609Smp xfree(ohistent); 890195609Smp } else 891195609Smp (void) getword(NULL); 89259243Sobrien } while (level >= 0); 893167465Smp end: 894167465Smp cleanup_until(&word); 89559243Sobrien} 89659243Sobrien 897195609Smpstatic struct wordent * 898195609Smphistgetword(struct wordent *histent) 899195609Smp{ 900316957Sdchagin int first; 901195609Smp eChar c, d; 902195609Smp int e; 903195609Smp struct Strbuf *tmp; 904195609Smp tmp = xmalloc(sizeof(*tmp)); 905195609Smp tmp->size = 0; 906195609Smp tmp->s = NULL; 907195609Smp c = readc(1); 908195609Smp d = 0; 909195609Smp e = 0; 910195609Smp for (;;) { 911195609Smp tmp->len = 0; 912195609Smp Strbuf_terminate (tmp); 913195609Smp while (c == ' ' || c == '\t') 914195609Smp c = readc(1); 915195609Smp if (c == '#') 916195609Smp do 917195609Smp c = readc(1); 918195609Smp while (c != CHAR_ERR && c != '\n'); 919195609Smp if (c == CHAR_ERR) 920195609Smp goto past; 921195609Smp if (c == '\n') 922195609Smp goto nl; 923195609Smp unreadc(c); 924195609Smp first = 1; 925195609Smp do { 926195609Smp e = (c == '\\'); 927195609Smp c = readc(1); 928195609Smp if (c == '\\' && !e) { 929195609Smp if ((c = readc(1)) == '\n') { 930195609Smp e = 1; 931195609Smp c = ' '; 932195609Smp } else { 933195609Smp unreadc(c); 934195609Smp c = '\\'; 935195609Smp } 936195609Smp } 937195609Smp if ((c == '\'' || c == '"') && !e) { 938195609Smp if (d == 0) 939195609Smp d = c; 940195609Smp else if (d == c) 941195609Smp d = 0; 942195609Smp } 943195609Smp if (c == CHAR_ERR) 944195609Smp goto past; 945195609Smp 946195609Smp Strbuf_append1(tmp, (Char) c); 947195609Smp 948195609Smp if (!first && !d && c == '(' && !e) { 949195609Smp break; 950195609Smp } 951195609Smp first = 0; 952195609Smp } while (d || e || (c != ' ' && c != '\t' && c != '\n')); 953195609Smp tmp->len--; 954195609Smp if (tmp->len) { 955195609Smp Strbuf_terminate(tmp); 956195609Smp histent->word = Strsave(tmp->s); 957195609Smp histent->next = xmalloc(sizeof (*histent)); 958195609Smp histent->next->prev = histent; 959195609Smp histent = histent->next; 960195609Smp } 961195609Smp if (c == '\n') { 962195609Smp nl: 963195609Smp tmp->len = 0; 964195609Smp Strbuf_append1(tmp, (Char) c); 965195609Smp Strbuf_terminate(tmp); 966195609Smp histent->word = Strsave(tmp->s); 967195609Smp return histent; 968195609Smp } 969195609Smp } 970195609Smp 971195609Smppast: 972195609Smp switch (Stype) { 973195609Smp 974195609Smp case TC_IF: 975195609Smp stderror(ERR_NAME | ERR_NOTFOUND, "then/endif"); 976195609Smp break; 977195609Smp 978195609Smp case TC_ELSE: 979195609Smp stderror(ERR_NAME | ERR_NOTFOUND, "endif"); 980195609Smp break; 981195609Smp 982195609Smp case TC_BRKSW: 983195609Smp case TC_SWITCH: 984195609Smp stderror(ERR_NAME | ERR_NOTFOUND, "endsw"); 985195609Smp break; 986195609Smp 987195609Smp case TC_BREAK: 988195609Smp stderror(ERR_NAME | ERR_NOTFOUND, "end"); 989195609Smp break; 990195609Smp 991195609Smp case TC_GOTO: 992195609Smp setname(short2str(Sgoal)); 993195609Smp stderror(ERR_NAME | ERR_NOTFOUND, "label"); 994195609Smp break; 995195609Smp 996195609Smp default: 997195609Smp break; 998195609Smp } 999195609Smp /* NOTREACHED */ 1000195609Smp return NULL; 1001195609Smp} 1002195609Smp 100359243Sobrienstatic int 1004167465Smpgetword(struct Strbuf *wp) 100559243Sobrien{ 100659243Sobrien int found = 0, first; 1007145479Smp eChar c, d; 100859243Sobrien 1009167465Smp if (wp) 1010167465Smp wp->len = 0; 101159243Sobrien c = readc(1); 101259243Sobrien d = 0; 101359243Sobrien do { 101459243Sobrien while (c == ' ' || c == '\t') 101559243Sobrien c = readc(1); 101659243Sobrien if (c == '#') 101759243Sobrien do 101859243Sobrien c = readc(1); 1019145479Smp while (c != CHAR_ERR && c != '\n'); 1020145479Smp if (c == CHAR_ERR) 102159243Sobrien goto past; 102259243Sobrien if (c == '\n') { 102359243Sobrien if (wp) 102459243Sobrien break; 102559243Sobrien return (0); 102659243Sobrien } 102759243Sobrien unreadc(c); 102859243Sobrien found = 1; 102959243Sobrien first = 1; 103059243Sobrien do { 103159243Sobrien c = readc(1); 103259243Sobrien if (c == '\\' && (c = readc(1)) == '\n') 103359243Sobrien c = ' '; 103459243Sobrien if (c == '\'' || c == '"') { 103559243Sobrien if (d == 0) 103659243Sobrien d = c; 103759243Sobrien else if (d == c) 103859243Sobrien d = 0; 103959243Sobrien } 1040145479Smp if (c == CHAR_ERR) 104159243Sobrien goto past; 1042167465Smp if (wp) 1043167465Smp Strbuf_append1(wp, (Char) c); 1044316957Sdchagin if (!d && c == ')') { 1045316957Sdchagin if (!first && wp) { 1046316957Sdchagin goto past_word_end; 1047316957Sdchagin } else { 1048316957Sdchagin if (wp) { 1049316957Sdchagin wp->len = 1; 1050316957Sdchagin Strbuf_terminate(wp); 1051316957Sdchagin } 1052316957Sdchagin return found; 1053316957Sdchagin } 1054316957Sdchagin } 105559243Sobrien if (!first && !d && c == '(') { 1056167465Smp if (wp) 1057167465Smp goto past_word_end; 105859243Sobrien else 105959243Sobrien break; 106059243Sobrien } 106159243Sobrien first = 0; 106259243Sobrien } while ((d || (c != ' ' && c != '\t')) && c != '\n'); 106359243Sobrien } while (wp == 0); 106459243Sobrien 1065167465Smp past_word_end: 106659243Sobrien unreadc(c); 1067167465Smp if (found) { 1068167465Smp wp->len--; 1069167465Smp Strbuf_terminate(wp); 1070167465Smp } 107159243Sobrien 107259243Sobrien return (found); 107359243Sobrien 107459243Sobrienpast: 107559243Sobrien switch (Stype) { 107659243Sobrien 107759243Sobrien case TC_IF: 107859243Sobrien stderror(ERR_NAME | ERR_NOTFOUND, "then/endif"); 107959243Sobrien break; 108059243Sobrien 108159243Sobrien case TC_ELSE: 108259243Sobrien stderror(ERR_NAME | ERR_NOTFOUND, "endif"); 108359243Sobrien break; 108459243Sobrien 108559243Sobrien case TC_BRKSW: 108659243Sobrien case TC_SWITCH: 108759243Sobrien stderror(ERR_NAME | ERR_NOTFOUND, "endsw"); 108859243Sobrien break; 108959243Sobrien 109059243Sobrien case TC_BREAK: 109159243Sobrien stderror(ERR_NAME | ERR_NOTFOUND, "end"); 109259243Sobrien break; 109359243Sobrien 109459243Sobrien case TC_GOTO: 109559243Sobrien setname(short2str(Sgoal)); 109659243Sobrien stderror(ERR_NAME | ERR_NOTFOUND, "label"); 109759243Sobrien break; 109859243Sobrien 109959243Sobrien default: 110059243Sobrien break; 110159243Sobrien } 110259243Sobrien /* NOTREACHED */ 110359243Sobrien return (0); 110459243Sobrien} 110559243Sobrien 110659243Sobrienstatic void 1107167465Smptoend(void) 110859243Sobrien{ 110969408Sache if (whyles->w_end.type == TCSH_F_SEEK && whyles->w_end.f_seek == 0) { 111059243Sobrien search(TC_BREAK, 0, NULL); 111159243Sobrien btell(&whyles->w_end); 111259243Sobrien whyles->w_end.f_seek--; 111359243Sobrien } 111459243Sobrien else { 111559243Sobrien bseek(&whyles->w_end); 111659243Sobrien } 111759243Sobrien wfree(); 111859243Sobrien} 111959243Sobrien 1120131962Smpstatic void 1121167465Smpwpfree(struct whyle *wp) 1122131962Smp{ 1123131962Smp if (wp->w_fe0) 1124131962Smp blkfree(wp->w_fe0); 1125167465Smp xfree(wp->w_fename); 1126167465Smp xfree(wp); 1127131962Smp} 1128131962Smp 112959243Sobrienvoid 1130167465Smpwfree(void) 113159243Sobrien{ 113259243Sobrien struct Ain o; 113359243Sobrien struct whyle *nwp; 113459243Sobrien#ifdef lint 113559243Sobrien nwp = NULL; /* sun lint is dumb! */ 113659243Sobrien#endif 113759243Sobrien 113859243Sobrien#ifdef FDEBUG 1139167465Smp static const char foo[] = "IAFE"; 114059243Sobrien#endif /* FDEBUG */ 114159243Sobrien 114259243Sobrien btell(&o); 114359243Sobrien 114459243Sobrien#ifdef FDEBUG 1145167465Smp xprintf("o->type %c o->a_seek %d o->f_seek %d\n", 114659243Sobrien foo[o.type + 1], o.a_seek, o.f_seek); 114759243Sobrien#endif /* FDEBUG */ 114859243Sobrien 114959243Sobrien for (; whyles; whyles = nwp) { 1150145479Smp struct whyle *wp = whyles; 115159243Sobrien nwp = wp->w_next; 115259243Sobrien 115359243Sobrien#ifdef FDEBUG 1154167465Smp xprintf("start->type %c start->a_seek %d start->f_seek %d\n", 115559243Sobrien foo[wp->w_start.type+1], 115659243Sobrien wp->w_start.a_seek, wp->w_start.f_seek); 1157167465Smp xprintf("end->type %c end->a_seek %d end->f_seek %d\n", 115859243Sobrien foo[wp->w_end.type + 1], wp->w_end.a_seek, wp->w_end.f_seek); 115959243Sobrien#endif /* FDEBUG */ 116059243Sobrien 116159243Sobrien /* 116259243Sobrien * XXX: We free loops that have different seek types. 116359243Sobrien */ 116469408Sache if (wp->w_end.type != TCSH_I_SEEK && wp->w_start.type == wp->w_end.type && 116559243Sobrien wp->w_start.type == o.type) { 116669408Sache if (wp->w_end.type == TCSH_F_SEEK) { 116759243Sobrien if (o.f_seek >= wp->w_start.f_seek && 116859243Sobrien (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek)) 116959243Sobrien break; 117059243Sobrien } 117159243Sobrien else { 117259243Sobrien if (o.a_seek >= wp->w_start.a_seek && 117359243Sobrien (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek)) 117459243Sobrien break; 117559243Sobrien } 117659243Sobrien } 117759243Sobrien 1178131962Smp wpfree(wp); 117959243Sobrien } 118059243Sobrien} 118159243Sobrien 118259243Sobrien/*ARGSUSED*/ 118359243Sobrienvoid 1184167465Smpdoecho(Char **v, struct command *c) 118559243Sobrien{ 118659243Sobrien USE(c); 118759243Sobrien xecho(' ', v); 118859243Sobrien} 118959243Sobrien 119059243Sobrien/*ARGSUSED*/ 119159243Sobrienvoid 1192167465Smpdoglob(Char **v, struct command *c) 119359243Sobrien{ 119459243Sobrien USE(c); 119559243Sobrien xecho(0, v); 119659243Sobrien flush(); 119759243Sobrien} 119859243Sobrien 119959243Sobrienstatic void 1200167465Smpxecho(int sep, Char **v) 120159243Sobrien{ 1202167465Smp Char *cp, **globbed = NULL; 120359243Sobrien int nonl = 0; 120459243Sobrien int echo_style = ECHO_STYLE; 120559243Sobrien struct varent *vp; 120659243Sobrien 120759243Sobrien if ((vp = adrof(STRecho_style)) != NULL && vp->vec != NULL && 120859243Sobrien vp->vec[0] != NULL) { 120959243Sobrien if (Strcmp(vp->vec[0], STRbsd) == 0) 121059243Sobrien echo_style = BSD_ECHO; 121159243Sobrien else if (Strcmp(vp->vec[0], STRsysv) == 0) 121259243Sobrien echo_style = SYSV_ECHO; 121359243Sobrien else if (Strcmp(vp->vec[0], STRboth) == 0) 121459243Sobrien echo_style = BOTH_ECHO; 121559243Sobrien else if (Strcmp(vp->vec[0], STRnone) == 0) 121659243Sobrien echo_style = NONE_ECHO; 121759243Sobrien } 121859243Sobrien 121959243Sobrien v++; 122059243Sobrien if (*v == 0) 122183098Smp goto done; 1222167465Smp if (setintr) { 1223167465Smp int old_pintr_disabled; 1224167465Smp pintr_push_enable(&old_pintr_disabled); 1225167465Smp v = glob_all_or_error(v); 1226167465Smp cleanup_until(&old_pintr_disabled); 1227167465Smp } else { 1228167465Smp v = glob_all_or_error(v); 122959243Sobrien } 1230167465Smp globbed = v; 1231167465Smp if (globbed != NULL) 1232167465Smp cleanup_push(globbed, blk_cleanup); 123359243Sobrien 123459243Sobrien if ((echo_style & BSD_ECHO) != 0 && sep == ' ' && *v && eq(*v, STRmn)) 123559243Sobrien nonl++, v++; 123659243Sobrien 123759243Sobrien while ((cp = *v++) != 0) { 1238145479Smp Char c; 123959243Sobrien 1240167465Smp if (setintr) { 1241167465Smp int old_pintr_disabled; 1242167465Smp 1243167465Smp pintr_push_enable(&old_pintr_disabled); 1244167465Smp cleanup_until(&old_pintr_disabled); 1245167465Smp } 124659243Sobrien while ((c = *cp++) != 0) { 124759243Sobrien if ((echo_style & SYSV_ECHO) != 0 && c == '\\') { 124859243Sobrien switch (c = *cp++) { 124959243Sobrien case 'a': 125059243Sobrien c = '\a'; 125159243Sobrien break; 125259243Sobrien case 'b': 125359243Sobrien c = '\b'; 125459243Sobrien break; 125559243Sobrien case 'c': 125659243Sobrien nonl = 1; 125759243Sobrien goto done; 125859243Sobrien case 'e': 125959243Sobrien#if 0 /* Windows does not understand \e */ 126059243Sobrien c = '\e'; 126159243Sobrien#else 1262167465Smp c = CTL_ESC('\033'); 126359243Sobrien#endif 126459243Sobrien break; 126559243Sobrien case 'f': 126659243Sobrien c = '\f'; 126759243Sobrien break; 126859243Sobrien case 'n': 126959243Sobrien c = '\n'; 127059243Sobrien break; 127159243Sobrien case 'r': 127259243Sobrien c = '\r'; 127359243Sobrien break; 127459243Sobrien case 't': 127559243Sobrien c = '\t'; 127659243Sobrien break; 127759243Sobrien case 'v': 127859243Sobrien c = '\v'; 127959243Sobrien break; 128059243Sobrien case '\\': 128159243Sobrien c = '\\'; 128259243Sobrien break; 128359243Sobrien case '0': 128459243Sobrien c = 0; 128559243Sobrien if (*cp >= '0' && *cp < '8') 128659243Sobrien c = c * 8 + *cp++ - '0'; 128759243Sobrien if (*cp >= '0' && *cp < '8') 128859243Sobrien c = c * 8 + *cp++ - '0'; 128959243Sobrien if (*cp >= '0' && *cp < '8') 129059243Sobrien c = c * 8 + *cp++ - '0'; 129159243Sobrien break; 129259243Sobrien case '\0': 129359243Sobrien c = '\\'; 129459243Sobrien cp--; 129559243Sobrien break; 129659243Sobrien default: 129759243Sobrien xputchar('\\' | QUOTE); 129859243Sobrien break; 129959243Sobrien } 130059243Sobrien } 1301145479Smp xputwchar(c | QUOTE); 130259243Sobrien 130359243Sobrien } 130459243Sobrien if (*v) 130559243Sobrien xputchar(sep | QUOTE); 130659243Sobrien } 130759243Sobriendone: 130859243Sobrien if (sep && nonl == 0) 130959243Sobrien xputchar('\n'); 131059243Sobrien else 131159243Sobrien flush(); 1312167465Smp if (globbed != NULL) 1313167465Smp cleanup_until(globbed); 131459243Sobrien} 131559243Sobrien 131659243Sobrien/* check whether an environment variable should invoke 'set_locale()' */ 1317145479Smpstatic int 1318167465Smpislocale_var(Char *var) 131959243Sobrien{ 132059243Sobrien static Char *locale_vars[] = { 1321131962Smp STRLANG, STRLC_ALL, STRLC_CTYPE, STRLC_NUMERIC, 1322131962Smp STRLC_TIME, STRLC_COLLATE, STRLC_MESSAGES, STRLC_MONETARY, 0 132359243Sobrien }; 1324145479Smp Char **v; 132559243Sobrien 132659243Sobrien for (v = locale_vars; *v; ++v) 132759243Sobrien if (eq(var, *v)) 132859243Sobrien return 1; 132959243Sobrien return 0; 133059243Sobrien} 133159243Sobrien 1332167465Smpstatic void 1333167465Smpxlate_cr_cleanup(void *dummy) 1334167465Smp{ 1335167465Smp USE(dummy); 1336167465Smp xlate_cr = 0; 1337167465Smp} 1338167465Smp 133959243Sobrien/*ARGSUSED*/ 134059243Sobrienvoid 1341167465Smpdoprintenv(Char **v, struct command *c) 134259243Sobrien{ 134359243Sobrien Char *e; 134459243Sobrien 134559243Sobrien USE(c); 134659243Sobrien v++; 134759243Sobrien if (*v == 0) { 1348145479Smp Char **ep; 134959243Sobrien 135059243Sobrien xlate_cr = 1; 1351167465Smp cleanup_push(&xlate_cr, xlate_cr_cleanup); 1352167465Smp for (ep = STR_environ; *ep; ep++) { 1353167465Smp if (setintr) { 1354167465Smp int old_pintr_disabled; 1355167465Smp 1356167465Smp pintr_push_enable(&old_pintr_disabled); 1357167465Smp cleanup_until(&old_pintr_disabled); 1358167465Smp } 135959243Sobrien xprintf("%S\n", *ep); 1360167465Smp } 1361167465Smp cleanup_until(&xlate_cr); 136259243Sobrien } 136359243Sobrien else if ((e = tgetenv(*v)) != NULL) { 1364167465Smp int old_output_raw; 1365167465Smp 1366167465Smp old_output_raw = output_raw; 136759243Sobrien output_raw = 1; 1368167465Smp cleanup_push(&old_output_raw, output_raw_restore); 136959243Sobrien xprintf("%S\n", e); 1370167465Smp cleanup_until(&old_output_raw); 137159243Sobrien } 137259243Sobrien else 1373167465Smp setcopy(STRstatus, STR1, VAR_READWRITE); 137459243Sobrien} 137559243Sobrien 137659243Sobrien/* from "Karl Berry." <karl%mote.umb.edu@relay.cs.net> -- for NeXT things 137759243Sobrien (and anything else with a modern compiler) */ 137859243Sobrien 137959243Sobrien/*ARGSUSED*/ 138059243Sobrienvoid 1381167465Smpdosetenv(Char **v, struct command *c) 138259243Sobrien{ 138359243Sobrien Char *vp, *lp; 138459243Sobrien 138559243Sobrien USE(c); 138659243Sobrien if (*++v == 0) { 138759243Sobrien doprintenv(--v, 0); 138859243Sobrien return; 138959243Sobrien } 139059243Sobrien 139159243Sobrien vp = *v++; 1392231990Smp lp = vp; 139359243Sobrien 1394231990Smp if (!letter(*lp)) 1395231990Smp stderror(ERR_NAME | ERR_VARBEGIN); 1396231990Smp do { 1397231990Smp lp++; 1398316957Sdchagin } while (alnum(*lp) || *lp == '.'); 1399231990Smp if (*lp != '\0') 1400231990Smp stderror(ERR_NAME | ERR_VARALNUM); 1401231990Smp 140259243Sobrien if ((lp = *v++) == 0) 140359243Sobrien lp = STRNULL; 140459243Sobrien 1405167465Smp lp = globone(lp, G_APPEND); 1406167465Smp cleanup_push(lp, xfree); 1407167465Smp tsetenv(vp, lp); 140859243Sobrien if (eq(vp, STRKPATH)) { 1409167465Smp importpath(lp); 141059243Sobrien dohash(NULL, NULL); 1411167465Smp cleanup_until(lp); 141259243Sobrien return; 141359243Sobrien } 141459243Sobrien 141559243Sobrien#ifdef apollo 141659243Sobrien if (eq(vp, STRSYSTYPE)) { 141759243Sobrien dohash(NULL, NULL); 1418167465Smp cleanup_until(lp); 141959243Sobrien return; 142059243Sobrien } 142159243Sobrien#endif /* apollo */ 142259243Sobrien 142359243Sobrien /* dspkanji/dspmbyte autosetting */ 142459243Sobrien /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */ 142559243Sobrien#if defined(DSPMBYTE) 142659243Sobrien if(eq(vp, STRLANG) && !adrof(CHECK_MBYTEVAR)) { 142759243Sobrien autoset_dspmbyte(lp); 142859243Sobrien } 142959243Sobrien#endif 143059243Sobrien 143159243Sobrien if (islocale_var(vp)) { 143259243Sobrien#ifdef NLS 143359243Sobrien int k; 143459243Sobrien 143559243Sobrien# ifdef SETLOCALEBUG 143659243Sobrien dont_free = 1; 143759243Sobrien# endif /* SETLOCALEBUG */ 143859243Sobrien (void) setlocale(LC_ALL, ""); 143959243Sobrien# ifdef LC_COLLATE 144059243Sobrien (void) setlocale(LC_COLLATE, ""); 144159243Sobrien# endif 1442145479Smp# ifdef LC_CTYPE 1443145479Smp (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 1444145479Smp# endif /* LC_CTYPE */ 1445231990Smp# if defined(AUTOSET_KANJI) 1446231990Smp autoset_kanji(); 1447231990Smp# endif /* AUTOSET_KANJI */ 144859243Sobrien# ifdef NLS_CATALOGS 144959243Sobrien# ifdef LC_MESSAGES 145059243Sobrien (void) setlocale(LC_MESSAGES, ""); 145159243Sobrien# endif /* LC_MESSAGES */ 1452145479Smp nlsclose(); 145359243Sobrien nlsinit(); 145459243Sobrien# endif /* NLS_CATALOGS */ 145559243Sobrien# ifdef SETLOCALEBUG 145659243Sobrien dont_free = 0; 145759243Sobrien# endif /* SETLOCALEBUG */ 145859243Sobrien# ifdef STRCOLLBUG 145959243Sobrien fix_strcoll_bug(); 146059243Sobrien# endif /* STRCOLLBUG */ 146159243Sobrien tw_cmd_free(); /* since the collation sequence has changed */ 1462167465Smp for (k = 0200; k <= 0377 && !Isprint(CTL_ESC(k)); k++) 146359243Sobrien continue; 1464145479Smp AsciiOnly = MB_CUR_MAX == 1 && k > 0377; 146559243Sobrien#else /* !NLS */ 146659243Sobrien AsciiOnly = 0; 146759243Sobrien#endif /* NLS */ 146859243Sobrien NLSMapsAreInited = 0; 146959243Sobrien ed_Init(); 147059243Sobrien if (MapsAreInited && !NLSMapsAreInited) 147159243Sobrien ed_InitNLSMaps(); 1472167465Smp cleanup_until(lp); 147359243Sobrien return; 147459243Sobrien } 147559243Sobrien 1476100616Smp#ifdef NLS_CATALOGS 1477100616Smp if (eq(vp, STRNLSPATH)) { 1478145479Smp nlsclose(); 1479100616Smp nlsinit(); 1480100616Smp } 1481100616Smp#endif 1482100616Smp 148359243Sobrien if (eq(vp, STRNOREBIND)) { 148459243Sobrien NoNLSRebind = 1; 148559243Sobrien MapsAreInited = 0; 148659243Sobrien NLSMapsAreInited = 0; 148759243Sobrien ed_InitMaps(); 1488167465Smp cleanup_until(lp); 148959243Sobrien return; 149059243Sobrien } 149169408Sache#ifdef WINNT_NATIVE 149259243Sobrien if (eq(vp, STRtcshlang)) { 149359243Sobrien nlsinit(); 1494167465Smp cleanup_until(lp); 149559243Sobrien return; 149659243Sobrien } 149769408Sache#endif /* WINNT_NATIVE */ 149859243Sobrien if (eq(vp, STRKTERM)) { 149959243Sobrien char *t; 1500167465Smp 1501167465Smp setv(STRterm, quote(lp), VAR_READWRITE); /* lp memory used here */ 1502167465Smp cleanup_ignore(lp); 1503167465Smp cleanup_until(lp); 150459243Sobrien t = short2str(lp); 150559243Sobrien if (noediting && strcmp(t, "unknown") != 0 && strcmp(t,"dumb") != 0) { 150659243Sobrien editing = 1; 150759243Sobrien noediting = 0; 1508167465Smp setNS(STRedit); 150959243Sobrien } 151059243Sobrien GotTermCaps = 0; 151159243Sobrien ed_Init(); 151259243Sobrien return; 151359243Sobrien } 151459243Sobrien 151559243Sobrien if (eq(vp, STRKHOME)) { 1516167465Smp Char *canon; 151759243Sobrien /* 151859243Sobrien * convert to canonical pathname (possibly resolving symlinks) 151959243Sobrien */ 1520167465Smp canon = dcanon(lp, lp); 1521167465Smp cleanup_ignore(lp); 1522167465Smp cleanup_until(lp); 1523167465Smp cleanup_push(canon, xfree); 1524167465Smp setv(STRhome, quote(canon), VAR_READWRITE); /* lp memory used here */ 1525167465Smp cleanup_ignore(canon); 1526167465Smp cleanup_until(canon); 152759243Sobrien 152859243Sobrien /* fix directory stack for new tilde home */ 152959243Sobrien dtilde(); 153059243Sobrien return; 153159243Sobrien } 153259243Sobrien 153359243Sobrien if (eq(vp, STRKSHLVL)) { 1534167465Smp setv(STRshlvl, quote(lp), VAR_READWRITE); /* lp memory used here */ 1535167465Smp cleanup_ignore(lp); 1536167465Smp cleanup_until(lp); 153759243Sobrien return; 153859243Sobrien } 153959243Sobrien 154059243Sobrien if (eq(vp, STRKUSER)) { 1541167465Smp setv(STRuser, quote(lp), VAR_READWRITE); /* lp memory used here */ 1542167465Smp cleanup_ignore(lp); 1543167465Smp cleanup_until(lp); 154459243Sobrien return; 154559243Sobrien } 154659243Sobrien 154759243Sobrien if (eq(vp, STRKGROUP)) { 1548167465Smp setv(STRgroup, quote(lp), VAR_READWRITE); /* lp memory used here */ 1549167465Smp cleanup_ignore(lp); 1550167465Smp cleanup_until(lp); 155159243Sobrien return; 155259243Sobrien } 155359243Sobrien 155459243Sobrien#ifdef COLOR_LS_F 155559243Sobrien if (eq(vp, STRLS_COLORS)) { 155659243Sobrien parseLS_COLORS(lp); 1557167465Smp cleanup_until(lp); 155859243Sobrien return; 155959243Sobrien } 1560316957Sdchagin if (eq(vp, STRLSCOLORS)) { 1561316957Sdchagin parseLSCOLORS(lp); 1562316957Sdchagin cleanup_until(lp); 1563316957Sdchagin return; 1564316957Sdchagin } 156559243Sobrien#endif /* COLOR_LS_F */ 156659243Sobrien 156759243Sobrien#ifdef SIG_WINDOW 156859243Sobrien /* 156959243Sobrien * Load/Update $LINES $COLUMNS 157059243Sobrien */ 157159243Sobrien if ((eq(lp, STRNULL) && (eq(vp, STRLINES) || eq(vp, STRCOLUMNS))) || 157259243Sobrien eq(vp, STRTERMCAP)) { 1573167465Smp cleanup_until(lp); 157459243Sobrien check_window_size(1); 157559243Sobrien return; 157659243Sobrien } 157759243Sobrien 157859243Sobrien /* 157959243Sobrien * Change the size to the one directed by $LINES and $COLUMNS 158059243Sobrien */ 158159243Sobrien if (eq(vp, STRLINES) || eq(vp, STRCOLUMNS)) { 158259243Sobrien#if 0 158359243Sobrien GotTermCaps = 0; 158459243Sobrien#endif 1585167465Smp cleanup_until(lp); 158659243Sobrien ed_Init(); 158759243Sobrien return; 158859243Sobrien } 158959243Sobrien#endif /* SIG_WINDOW */ 1590167465Smp cleanup_until(lp); 159159243Sobrien} 159259243Sobrien 159359243Sobrien/*ARGSUSED*/ 159459243Sobrienvoid 1595167465Smpdounsetenv(Char **v, struct command *c) 159659243Sobrien{ 1597167465Smp Char **ep, *p, *n, *name; 159859243Sobrien int i, maxi; 159959243Sobrien 160059243Sobrien USE(c); 160159243Sobrien /* 160259243Sobrien * Find the longest environment variable 160359243Sobrien */ 160459243Sobrien for (maxi = 0, ep = STR_environ; *ep; ep++) { 160559243Sobrien for (i = 0, p = *ep; *p && *p != '='; p++, i++) 160659243Sobrien continue; 160759243Sobrien if (i > maxi) 160859243Sobrien maxi = i; 160959243Sobrien } 161059243Sobrien 1611167465Smp name = xmalloc((maxi + 1) * sizeof(Char)); 1612167465Smp cleanup_push(name, xfree); 161359243Sobrien 161459243Sobrien while (++v && *v) 161559243Sobrien for (maxi = 1; maxi;) 161659243Sobrien for (maxi = 0, ep = STR_environ; *ep; ep++) { 161759243Sobrien for (n = name, p = *ep; *p && *p != '='; *n++ = *p++) 161859243Sobrien continue; 161959243Sobrien *n = '\0'; 162059243Sobrien if (!Gmatch(name, *v)) 162159243Sobrien continue; 162259243Sobrien maxi = 1; 162359243Sobrien 162459243Sobrien /* Unset the name. This wasn't being done until 162559243Sobrien * later but most of the stuff following won't 162659243Sobrien * work (particularly the setlocale() and getenv() 162759243Sobrien * stuff) as intended until the name is actually 162859243Sobrien * removed. (sg) 162959243Sobrien */ 163059243Sobrien Unsetenv(name); 163159243Sobrien 163259243Sobrien if (eq(name, STRNOREBIND)) { 163359243Sobrien NoNLSRebind = 0; 163459243Sobrien MapsAreInited = 0; 163559243Sobrien NLSMapsAreInited = 0; 163659243Sobrien ed_InitMaps(); 163759243Sobrien } 163859243Sobrien#ifdef apollo 163959243Sobrien else if (eq(name, STRSYSTYPE)) 164059243Sobrien dohash(NULL, NULL); 164159243Sobrien#endif /* apollo */ 164259243Sobrien else if (islocale_var(name)) { 164359243Sobrien#ifdef NLS 164459243Sobrien int k; 164559243Sobrien 164659243Sobrien# ifdef SETLOCALEBUG 164759243Sobrien dont_free = 1; 164859243Sobrien# endif /* SETLOCALEBUG */ 164959243Sobrien (void) setlocale(LC_ALL, ""); 165059243Sobrien# ifdef LC_COLLATE 165159243Sobrien (void) setlocale(LC_COLLATE, ""); 165259243Sobrien# endif 1653145479Smp# ifdef LC_CTYPE 1654167465Smp (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 1655145479Smp# endif /* LC_CTYPE */ 165659243Sobrien# ifdef NLS_CATALOGS 165759243Sobrien# ifdef LC_MESSAGES 165859243Sobrien (void) setlocale(LC_MESSAGES, ""); 165959243Sobrien# endif /* LC_MESSAGES */ 1660145479Smp nlsclose(); 166159243Sobrien nlsinit(); 166259243Sobrien# endif /* NLS_CATALOGS */ 166359243Sobrien# ifdef SETLOCALEBUG 166459243Sobrien dont_free = 0; 166559243Sobrien# endif /* SETLOCALEBUG */ 166659243Sobrien# ifdef STRCOLLBUG 166759243Sobrien fix_strcoll_bug(); 166859243Sobrien# endif /* STRCOLLBUG */ 166959243Sobrien tw_cmd_free();/* since the collation sequence has changed */ 1670167465Smp for (k = 0200; k <= 0377 && !Isprint(CTL_ESC(k)); k++) 167159243Sobrien continue; 1672145479Smp AsciiOnly = MB_CUR_MAX == 1 && k > 0377; 167359243Sobrien#else /* !NLS */ 167459243Sobrien AsciiOnly = getenv("LANG") == NULL && 167559243Sobrien getenv("LC_CTYPE") == NULL; 167659243Sobrien#endif /* NLS */ 167759243Sobrien NLSMapsAreInited = 0; 167859243Sobrien ed_Init(); 167959243Sobrien if (MapsAreInited && !NLSMapsAreInited) 168059243Sobrien ed_InitNLSMaps(); 168159243Sobrien 168259243Sobrien } 168369408Sache#ifdef WINNT_NATIVE 168459243Sobrien else if (eq(name,(STRtcshlang))) { 168559243Sobrien nls_dll_unload(); 168659243Sobrien nlsinit(); 168759243Sobrien } 168869408Sache#endif /* WINNT_NATIVE */ 168959243Sobrien#ifdef COLOR_LS_F 169059243Sobrien else if (eq(name, STRLS_COLORS)) 169159243Sobrien parseLS_COLORS(n); 1692316957Sdchagin else if (eq(name, STRLSCOLORS)) 1693316957Sdchagin parseLSCOLORS(n); 169459243Sobrien#endif /* COLOR_LS_F */ 1695100616Smp#ifdef NLS_CATALOGS 1696100616Smp else if (eq(name, STRNLSPATH)) { 1697145479Smp nlsclose(); 1698100616Smp nlsinit(); 1699100616Smp } 1700100616Smp#endif 170159243Sobrien /* 170259243Sobrien * start again cause the environment changes 170359243Sobrien */ 170459243Sobrien break; 170559243Sobrien } 1706167465Smp cleanup_until(name); 170759243Sobrien} 170859243Sobrien 170959243Sobrienvoid 1710167465Smptsetenv(const Char *name, const Char *val) 171159243Sobrien{ 171259243Sobrien#ifdef SETENV_IN_LIB 171359243Sobrien/* 171459243Sobrien * XXX: This does not work right, since tcsh cannot track changes to 171559243Sobrien * the environment this way. (the builtin setenv without arguments does 171659243Sobrien * not print the right stuff neither does unsetenv). This was for Mach, 171759243Sobrien * it is not needed anymore. 171859243Sobrien */ 171959243Sobrien#undef setenv 1720167465Smp char *cname; 172159243Sobrien 1722167465Smp if (name == NULL) 172359243Sobrien return; 1724167465Smp cname = strsave(short2str(name)); 1725167465Smp setenv(cname, short2str(val), 1); 1726167465Smp xfree(cname); 172759243Sobrien#else /* !SETENV_IN_LIB */ 1728145479Smp Char **ep = STR_environ; 1729145479Smp const Char *ccp; 1730145479Smp Char *cp, *dp; 173159243Sobrien Char *blk[2]; 173259243Sobrien Char **oep = ep; 173359243Sobrien 173469408Sache#ifdef WINNT_NATIVE 1735167465Smp nt_set_env(name,val); 173669408Sache#endif /* WINNT_NATIVE */ 173759243Sobrien for (; *ep; ep++) { 173869408Sache#ifdef WINNT_NATIVE 1739145479Smp for (ccp = name, dp = *ep; *ccp && Tolower(*ccp & TRIM) == Tolower(*dp); 1740145479Smp ccp++, dp++) 174159243Sobrien#else 1742145479Smp for (ccp = name, dp = *ep; *ccp && (*ccp & TRIM) == *dp; ccp++, dp++) 174369408Sache#endif /* WINNT_NATIVE */ 174459243Sobrien continue; 1745145479Smp if (*ccp != 0 || *dp != '=') 174659243Sobrien continue; 174759243Sobrien cp = Strspl(STRequal, val); 1748167465Smp xfree(*ep); 174959243Sobrien *ep = strip(Strspl(name, cp)); 1750167465Smp xfree(cp); 175159243Sobrien blkfree((Char **) environ); 175259243Sobrien environ = short2blk(STR_environ); 175359243Sobrien return; 175459243Sobrien } 175559243Sobrien cp = Strspl(name, STRequal); 175659243Sobrien blk[0] = strip(Strspl(cp, val)); 1757167465Smp xfree(cp); 175859243Sobrien blk[1] = 0; 175959243Sobrien STR_environ = blkspl(STR_environ, blk); 176059243Sobrien blkfree((Char **) environ); 176159243Sobrien environ = short2blk(STR_environ); 1762167465Smp xfree(oep); 176359243Sobrien#endif /* SETENV_IN_LIB */ 176459243Sobrien} 176559243Sobrien 176659243Sobrienvoid 1767167465SmpUnsetenv(Char *name) 176859243Sobrien{ 1769145479Smp Char **ep = STR_environ; 1770145479Smp Char *cp, *dp; 177159243Sobrien Char **oep = ep; 177259243Sobrien 177369408Sache#ifdef WINNT_NATIVE 177459243Sobrien nt_set_env(name,NULL); 177569408Sache#endif /*WINNT_NATIVE */ 177659243Sobrien for (; *ep; ep++) { 177759243Sobrien for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) 177859243Sobrien continue; 177959243Sobrien if (*cp != 0 || *dp != '=') 178059243Sobrien continue; 178159243Sobrien cp = *ep; 178259243Sobrien *ep = 0; 178359243Sobrien STR_environ = blkspl(STR_environ, ep + 1); 178459243Sobrien blkfree((Char **) environ); 178559243Sobrien environ = short2blk(STR_environ); 178659243Sobrien *ep = cp; 1787167465Smp xfree(cp); 1788167465Smp xfree(oep); 178959243Sobrien return; 179059243Sobrien } 179159243Sobrien} 179259243Sobrien 179359243Sobrien/*ARGSUSED*/ 179459243Sobrienvoid 1795167465Smpdoumask(Char **v, struct command *c) 179659243Sobrien{ 1797145479Smp Char *cp = v[1]; 1798145479Smp int i; 179959243Sobrien 180059243Sobrien USE(c); 180159243Sobrien if (cp == 0) { 180259415Sobrien i = (int)umask(0); 180359243Sobrien (void) umask(i); 180459243Sobrien xprintf("%o\n", i); 180559243Sobrien return; 180659243Sobrien } 180759243Sobrien i = 0; 180859243Sobrien while (Isdigit(*cp) && *cp != '8' && *cp != '9') 180959243Sobrien i = i * 8 + *cp++ - '0'; 181059243Sobrien if (*cp || i < 0 || i > 0777) 181159243Sobrien stderror(ERR_NAME | ERR_MASK); 181259243Sobrien (void) umask(i); 181359243Sobrien} 181459243Sobrien 181559243Sobrien#ifndef HAVENOLIMIT 181659243Sobrien# ifndef BSDLIMIT 181759243Sobrien typedef long RLIM_TYPE; 1818145479Smp# ifdef _OSD_POSIX /* BS2000 */ 1819145479Smp# include <ulimit.h> 1820145479Smp# endif 182159243Sobrien# ifndef RLIM_INFINITY 182259243Sobrien# if !defined(_MINIX) && !defined(__clipper__) && !defined(_CRAY) 182359243Sobrien extern RLIM_TYPE ulimit(); 182459243Sobrien# endif /* ! _MINIX && !__clipper__ */ 182559243Sobrien# define RLIM_INFINITY 0x003fffff 182659243Sobrien# define RLIMIT_FSIZE 1 182759243Sobrien# endif /* RLIM_INFINITY */ 182859243Sobrien# ifdef aiws 182959243Sobrien# define toset(a) (((a) == 3) ? 1004 : (a) + 1) 183059243Sobrien# define RLIMIT_DATA 3 183159243Sobrien# define RLIMIT_STACK 1005 183259243Sobrien# else /* aiws */ 183359243Sobrien# define toset(a) ((a) + 1) 183459243Sobrien# endif /* aiws */ 183559243Sobrien# else /* BSDLIMIT */ 1836145479Smp# if (defined(BSD4_4) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) || (HPUXVERSION >= 1100)) && !defined(__386BSD__) 1837100616Smp typedef rlim_t RLIM_TYPE; 183859243Sobrien# else 183959243Sobrien# if defined(SOLARIS2) || (defined(sgi) && SYSVREL > 3) 184059243Sobrien typedef rlim_t RLIM_TYPE; 184159243Sobrien# else 184259243Sobrien# if defined(_SX) 184359243Sobrien typedef long long RLIM_TYPE; 1844100616Smp# else /* !_SX */ 184559243Sobrien typedef unsigned long RLIM_TYPE; 184659243Sobrien# endif /* _SX */ 184759243Sobrien# endif /* SOLARIS2 || (sgi && SYSVREL > 3) */ 184859243Sobrien# endif /* BSD4_4 && !__386BSD__ */ 184959243Sobrien# endif /* BSDLIMIT */ 185059243Sobrien 1851131962Smp# if (HPUXVERSION > 700) && (HPUXVERSION < 1100) && defined(BSDLIMIT) 185259243Sobrien/* Yes hpux8.0 has limits but <sys/resource.h> does not make them public */ 185359243Sobrien/* Yes, we could have defined _KERNEL, and -I/etc/conf/h, but is that better? */ 185459243Sobrien# ifndef RLIMIT_CPU 185559243Sobrien# define RLIMIT_CPU 0 185659243Sobrien# define RLIMIT_FSIZE 1 185759243Sobrien# define RLIMIT_DATA 2 185859243Sobrien# define RLIMIT_STACK 3 185959243Sobrien# define RLIMIT_CORE 4 186059243Sobrien# define RLIMIT_RSS 5 186159243Sobrien# define RLIMIT_NOFILE 6 186259243Sobrien# endif /* RLIMIT_CPU */ 186359243Sobrien# ifndef RLIM_INFINITY 186459243Sobrien# define RLIM_INFINITY 0x7fffffff 186559243Sobrien# endif /* RLIM_INFINITY */ 186659243Sobrien /* 186759243Sobrien * old versions of HP/UX counted limits in 512 bytes 186859243Sobrien */ 186959243Sobrien# ifndef SIGRTMIN 187059243Sobrien# define FILESIZE512 187159243Sobrien# endif /* SIGRTMIN */ 1872131962Smp# endif /* (HPUXVERSION > 700) && (HPUXVERSION < 1100) && BSDLIMIT */ 187359243Sobrien 187459243Sobrien# if SYSVREL > 3 && defined(BSDLIMIT) && !defined(_SX) 187559243Sobrien/* In order to use rusage, we included "/usr/ucbinclude/sys/resource.h" in */ 187659243Sobrien/* sh.h. However, some SVR4 limits are defined in <sys/resource.h>. Rather */ 187759243Sobrien/* than include both and get warnings, we define the extra SVR4 limits here. */ 187883098Smp/* XXX: I don't understand if RLIMIT_AS is defined, why don't we define */ 187983098Smp/* RLIMIT_VMEM based on it? */ 188059243Sobrien# ifndef RLIMIT_VMEM 188159243Sobrien# define RLIMIT_VMEM 6 188259243Sobrien# endif 188359243Sobrien# ifndef RLIMIT_AS 188459243Sobrien# define RLIMIT_AS RLIMIT_VMEM 188559243Sobrien# endif 188659243Sobrien# endif /* SYSVREL > 3 && BSDLIMIT */ 188759243Sobrien 1888231990Smp# if (defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) 1889231990Smp# if defined(RLIMIT_AS) && !defined(RLIMIT_VMEM) 1890231990Smp# define RLIMIT_VMEM RLIMIT_AS 1891231990Smp# endif 1892231990Smp/* 1893231990Smp * Oh well, <asm-generic/resource.h> has it, but <bits/resource.h> does not 1894231990Smp * Linux headers: When the left hand does not know what the right hand does. 1895231990Smp */ 1896231990Smp# if defined(RLIMIT_RTPRIO) && !defined(RLIMIT_RTTIME) 1897231990Smp# define RLIMIT_RTTIME (RLIMIT_RTPRIO + 1) 1898231990Smp# endif 189983098Smp# endif 190083098Smp 190159243Sobrienstruct limits limits[] = 190259243Sobrien{ 190359243Sobrien# ifdef RLIMIT_CPU 190459243Sobrien { RLIMIT_CPU, "cputime", 1, "seconds" }, 190559243Sobrien# endif /* RLIMIT_CPU */ 190659243Sobrien 190759243Sobrien# ifdef RLIMIT_FSIZE 190859243Sobrien# ifndef aiws 190959243Sobrien { RLIMIT_FSIZE, "filesize", 1024, "kbytes" }, 191059243Sobrien# else 191159243Sobrien { RLIMIT_FSIZE, "filesize", 512, "blocks" }, 191259243Sobrien# endif /* aiws */ 191359243Sobrien# endif /* RLIMIT_FSIZE */ 191459243Sobrien 191559243Sobrien# ifdef RLIMIT_DATA 191659243Sobrien { RLIMIT_DATA, "datasize", 1024, "kbytes" }, 191759243Sobrien# endif /* RLIMIT_DATA */ 191859243Sobrien 191959243Sobrien# ifdef RLIMIT_STACK 192059243Sobrien# ifndef aiws 192159243Sobrien { RLIMIT_STACK, "stacksize", 1024, "kbytes" }, 192259243Sobrien# else 192359243Sobrien { RLIMIT_STACK, "stacksize", 1024 * 1024, "kbytes"}, 192459243Sobrien# endif /* aiws */ 192559243Sobrien# endif /* RLIMIT_STACK */ 192659243Sobrien 192759243Sobrien# ifdef RLIMIT_CORE 192859243Sobrien { RLIMIT_CORE, "coredumpsize", 1024, "kbytes" }, 192959243Sobrien# endif /* RLIMIT_CORE */ 193059243Sobrien 193159243Sobrien# ifdef RLIMIT_RSS 193259243Sobrien { RLIMIT_RSS, "memoryuse", 1024, "kbytes" }, 193359243Sobrien# endif /* RLIMIT_RSS */ 193459243Sobrien 193559243Sobrien# ifdef RLIMIT_UMEM 193659243Sobrien { RLIMIT_UMEM, "memoryuse", 1024, "kbytes" }, 193759243Sobrien# endif /* RLIMIT_UMEM */ 193859243Sobrien 193959243Sobrien# ifdef RLIMIT_VMEM 194059243Sobrien { RLIMIT_VMEM, "vmemoryuse", 1024, "kbytes" }, 194159243Sobrien# endif /* RLIMIT_VMEM */ 194259243Sobrien 1943145479Smp# if defined(RLIMIT_HEAP) /* found on BS2000/OSD systems */ 1944145479Smp { RLIMIT_HEAP, "heapsize", 1024, "kbytes" }, 1945145479Smp# endif /* RLIMIT_HEAP */ 1946145479Smp 194759243Sobrien# ifdef RLIMIT_NOFILE 194859243Sobrien { RLIMIT_NOFILE, "descriptors", 1, "" }, 194959243Sobrien# endif /* RLIMIT_NOFILE */ 195059243Sobrien 1951316957Sdchagin# ifdef RLIMIT_NPTS 1952316957Sdchagin { RLIMIT_NPTS, "pseudoterminals", 1, "" }, 1953316957Sdchagin# endif /* RLIMIT_NPTS */ 1954316957Sdchagin 1955316957Sdchagin# ifdef RLIMIT_KQUEUES 1956316957Sdchagin { RLIMIT_KQUEUES, "kqueues", 1, "" }, 1957316957Sdchagin# endif /* RLIMIT_KQUEUES */ 1958316957Sdchagin 195959243Sobrien# ifdef RLIMIT_CONCUR 196059243Sobrien { RLIMIT_CONCUR, "concurrency", 1, "thread(s)" }, 196159243Sobrien# endif /* RLIMIT_CONCUR */ 196259243Sobrien 196359243Sobrien# ifdef RLIMIT_MEMLOCK 196459243Sobrien { RLIMIT_MEMLOCK, "memorylocked", 1024, "kbytes" }, 196559243Sobrien# endif /* RLIMIT_MEMLOCK */ 196659243Sobrien 196759243Sobrien# ifdef RLIMIT_NPROC 196859243Sobrien { RLIMIT_NPROC, "maxproc", 1, "" }, 196959243Sobrien# endif /* RLIMIT_NPROC */ 197059243Sobrien 1971316957Sdchagin# ifdef RLIMIT_NTHR 1972316957Sdchagin { RLIMIT_NTHR, "maxthread", 1, "" }, 1973316957Sdchagin# endif /* RLIMIT_NTHR */ 1974316957Sdchagin 1975100616Smp# if defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE) 197659243Sobrien { RLIMIT_OFILE, "openfiles", 1, "" }, 1977100616Smp# endif /* RLIMIT_OFILE && !defined(RLIMIT_NOFILE) */ 197859243Sobrien 1979100616Smp# ifdef RLIMIT_SBSIZE 1980100616Smp { RLIMIT_SBSIZE, "sbsize", 1, "" }, 1981100616Smp# endif /* RLIMIT_SBSIZE */ 1982100616Smp 1983195609Smp# ifdef RLIMIT_SWAP 1984195609Smp { RLIMIT_SWAP, "swapsize", 1024, "kbytes" }, 1985195609Smp# endif /* RLIMIT_SWAP */ 1986194767Skib 1987231990Smp# ifdef RLIMIT_LOCKS 1988231990Smp { RLIMIT_LOCKS, "maxlocks", 1, "" }, 1989231990Smp# endif /* RLIMIT_LOCKS */ 1990231990Smp 1991316957Sdchagin# ifdef RLIMIT_POSIXLOCKS 1992316957Sdchagin { RLIMIT_POSIXLOCKS,"posixlocks", 1, "" }, 1993316957Sdchagin# endif /* RLIMIT_POSIXLOCKS */ 1994316957Sdchagin 1995231990Smp# ifdef RLIMIT_SIGPENDING 1996231990Smp { RLIMIT_SIGPENDING,"maxsignal", 1, "" }, 1997231990Smp# endif /* RLIMIT_SIGPENDING */ 1998231990Smp 1999231990Smp# ifdef RLIMIT_MSGQUEUE 2000231990Smp { RLIMIT_MSGQUEUE, "maxmessage", 1, "" }, 2001231990Smp# endif /* RLIMIT_MSGQUEUE */ 2002231990Smp 2003231990Smp# ifdef RLIMIT_NICE 2004231990Smp { RLIMIT_NICE, "maxnice", 1, "" }, 2005231990Smp# endif /* RLIMIT_NICE */ 2006231990Smp 2007231990Smp# ifdef RLIMIT_RTPRIO 2008231990Smp { RLIMIT_RTPRIO, "maxrtprio", 1, "" }, 2009231990Smp# endif /* RLIMIT_RTPRIO */ 2010231990Smp 2011231990Smp# ifdef RLIMIT_RTTIME 2012231990Smp { RLIMIT_RTTIME, "maxrttime", 1, "usec" }, 2013231990Smp# endif /* RLIMIT_RTTIME */ 2014231990Smp 201559243Sobrien { -1, NULL, 0, NULL } 201659243Sobrien}; 201759243Sobrien 2018167465Smpstatic struct limits *findlim (Char *); 2019167465Smpstatic RLIM_TYPE getval (struct limits *, Char **); 2020231990Smpstatic int strtail (Char *, const char *); 2021167465Smpstatic void limtail (Char *, const char *); 2022231990Smpstatic void limtail2 (Char *, const char *, const char *); 2023167465Smpstatic void plim (struct limits *, int); 2024167465Smpstatic int setlim (struct limits *, int, RLIM_TYPE); 202559243Sobrien 202659243Sobrien#ifdef convex 202759243Sobrienstatic RLIM_TYPE 2028167465Smprestrict_limit(double value) 202959243Sobrien{ 203059243Sobrien /* 203159243Sobrien * is f too large to cope with? return the maximum or minimum int 203259243Sobrien */ 203359243Sobrien if (value > (double) INT_MAX) 203459243Sobrien return (RLIM_TYPE) INT_MAX; 203559243Sobrien else if (value < (double) INT_MIN) 203659243Sobrien return (RLIM_TYPE) INT_MIN; 203759243Sobrien else 203859243Sobrien return (RLIM_TYPE) value; 203959243Sobrien} 204059243Sobrien#else /* !convex */ 204159243Sobrien# define restrict_limit(x) ((RLIM_TYPE) (x)) 204259243Sobrien#endif /* convex */ 204359243Sobrien 204459243Sobrien 204559243Sobrienstatic struct limits * 2046167465Smpfindlim(Char *cp) 204759243Sobrien{ 2048145479Smp struct limits *lp, *res; 204959243Sobrien 2050167465Smp res = NULL; 205159243Sobrien for (lp = limits; lp->limconst >= 0; lp++) 205259243Sobrien if (prefix(cp, str2short(lp->limname))) { 205359243Sobrien if (res) 205459243Sobrien stderror(ERR_NAME | ERR_AMBIG); 205559243Sobrien res = lp; 205659243Sobrien } 205759243Sobrien if (res) 205859243Sobrien return (res); 205959243Sobrien stderror(ERR_NAME | ERR_LIMIT); 206059243Sobrien /* NOTREACHED */ 206159243Sobrien return (0); 206259243Sobrien} 206359243Sobrien 206459243Sobrien/*ARGSUSED*/ 206559243Sobrienvoid 2066167465Smpdolimit(Char **v, struct command *c) 206759243Sobrien{ 2068145479Smp struct limits *lp; 2069145479Smp RLIM_TYPE limit; 207059243Sobrien int hard = 0; 207159243Sobrien 207259243Sobrien USE(c); 207359243Sobrien v++; 207459243Sobrien if (*v && eq(*v, STRmh)) { 207559243Sobrien hard = 1; 207659243Sobrien v++; 207759243Sobrien } 207859243Sobrien if (*v == 0) { 207959243Sobrien for (lp = limits; lp->limconst >= 0; lp++) 208059243Sobrien plim(lp, hard); 208159243Sobrien return; 208259243Sobrien } 208359243Sobrien lp = findlim(v[0]); 208459243Sobrien if (v[1] == 0) { 208559243Sobrien plim(lp, hard); 208659243Sobrien return; 208759243Sobrien } 208859243Sobrien limit = getval(lp, v + 1); 208959243Sobrien if (setlim(lp, hard, limit) < 0) 209059243Sobrien stderror(ERR_SILENT); 209159243Sobrien} 209259243Sobrien 209359243Sobrienstatic RLIM_TYPE 2094167465Smpgetval(struct limits *lp, Char **v) 209559243Sobrien{ 2096145479Smp float f; 209759243Sobrien Char *cp = *v++; 209859243Sobrien 209959243Sobrien f = atof(short2str(cp)); 210059243Sobrien 210159243Sobrien# ifdef convex 210259243Sobrien /* 210359243Sobrien * is f too large to cope with. limit f to minint, maxint - X-6768 by 210459243Sobrien * strike 210559243Sobrien */ 210659243Sobrien if ((f < (double) INT_MIN) || (f > (double) INT_MAX)) { 210759243Sobrien stderror(ERR_NAME | ERR_TOOLARGE); 210859243Sobrien } 210959243Sobrien# endif /* convex */ 211059243Sobrien 211159243Sobrien while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') 211259243Sobrien cp++; 211359243Sobrien if (*cp == 0) { 211459243Sobrien if (*v == 0) 211569408Sache return restrict_limit((f * lp->limdiv) + 0.5); 211659243Sobrien cp = *v; 211759243Sobrien } 211859243Sobrien switch (*cp) { 211959243Sobrien# ifdef RLIMIT_CPU 212059243Sobrien case ':': 212159243Sobrien if (lp->limconst != RLIMIT_CPU) 212259243Sobrien goto badscal; 212359243Sobrien return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f * 60.0 + atof(short2str(cp + 1)))); 212459243Sobrien case 'h': 212559243Sobrien if (lp->limconst != RLIMIT_CPU) 212659243Sobrien goto badscal; 212759243Sobrien limtail(cp, "hours"); 212859243Sobrien f *= 3600.0; 212959243Sobrien break; 2130231990Smp# endif /* RLIMIT_CPU */ 213159243Sobrien case 'm': 2132231990Smp# ifdef RLIMIT_CPU 213359243Sobrien if (lp->limconst == RLIMIT_CPU) { 213459243Sobrien limtail(cp, "minutes"); 213559243Sobrien f *= 60.0; 213659243Sobrien break; 213759243Sobrien } 2138231990Smp# endif /* RLIMIT_CPU */ 2139231990Smp limtail2(cp, "megabytes", "mbytes"); 214059243Sobrien f *= 1024.0 * 1024.0; 214159243Sobrien break; 2142231990Smp# ifdef RLIMIT_CPU 214359243Sobrien case 's': 214459243Sobrien if (lp->limconst != RLIMIT_CPU) 214559243Sobrien goto badscal; 214659243Sobrien limtail(cp, "seconds"); 214759243Sobrien break; 214859243Sobrien# endif /* RLIMIT_CPU */ 2149231990Smp case 'G': 2150231990Smp *cp = 'g'; 2151231990Smp /*FALLTHROUGH*/ 2152231990Smp case 'g': 2153231990Smp# ifdef RLIMIT_CPU 2154231990Smp if (lp->limconst == RLIMIT_CPU) 2155231990Smp goto badscal; 2156231990Smp# endif /* RLIMIT_CPU */ 2157231990Smp limtail2(cp, "gigabytes", "gbytes"); 2158231990Smp f *= 1024.0 * 1024.0 * 1024.0; 2159231990Smp break; 216059243Sobrien case 'M': 216159243Sobrien# ifdef RLIMIT_CPU 216259243Sobrien if (lp->limconst == RLIMIT_CPU) 216359243Sobrien goto badscal; 216459243Sobrien# endif /* RLIMIT_CPU */ 216559243Sobrien *cp = 'm'; 2166231990Smp limtail2(cp, "megabytes", "mbytes"); 216759243Sobrien f *= 1024.0 * 1024.0; 216859243Sobrien break; 216959243Sobrien case 'k': 217059243Sobrien# ifdef RLIMIT_CPU 217159243Sobrien if (lp->limconst == RLIMIT_CPU) 217259243Sobrien goto badscal; 217359243Sobrien# endif /* RLIMIT_CPU */ 2174231990Smp limtail2(cp, "kilobytes", "kbytes"); 217559243Sobrien f *= 1024.0; 217659243Sobrien break; 217759243Sobrien case 'b': 217859243Sobrien# ifdef RLIMIT_CPU 217959243Sobrien if (lp->limconst == RLIMIT_CPU) 218059243Sobrien goto badscal; 218159243Sobrien# endif /* RLIMIT_CPU */ 218259243Sobrien limtail(cp, "blocks"); 218359243Sobrien f *= 512.0; 218459243Sobrien break; 218559243Sobrien case 'u': 218659243Sobrien limtail(cp, "unlimited"); 218759243Sobrien return ((RLIM_TYPE) RLIM_INFINITY); 218859243Sobrien default: 218959243Sobrien# ifdef RLIMIT_CPU 219059243Sobrienbadscal: 219159243Sobrien# endif /* RLIMIT_CPU */ 219259243Sobrien stderror(ERR_NAME | ERR_SCALEF); 219359243Sobrien } 219459243Sobrien# ifdef convex 219559243Sobrien return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f + 0.5)); 219659243Sobrien# else 219759243Sobrien f += 0.5; 2198231990Smp if (f > (float) ((RLIM_TYPE) RLIM_INFINITY)) 219959243Sobrien return ((RLIM_TYPE) RLIM_INFINITY); 220059243Sobrien else 220159243Sobrien return ((RLIM_TYPE) f); 220259243Sobrien# endif /* convex */ 220359243Sobrien} 220459243Sobrien 2205231990Smpstatic int 2206231990Smpstrtail(Char *cp, const char *str) 2207231990Smp{ 2208231990Smp while (*cp && *cp == (Char)*str) 2209231990Smp cp++, str++; 2210231990Smp return (*cp != '\0'); 2211231990Smp} 2212231990Smp 221359243Sobrienstatic void 2214167465Smplimtail(Char *cp, const char *str) 221559243Sobrien{ 2216231990Smp if (strtail(cp, str)) 2217231990Smp stderror(ERR_BADSCALE, str); 2218231990Smp} 221961515Sobrien 2220231990Smpstatic void 2221231990Smplimtail2(Char *cp, const char *str1, const char *str2) 2222231990Smp{ 2223231990Smp if (strtail(cp, str1) && strtail(cp, str2)) 2224231990Smp stderror(ERR_BADSCALE, str1); 222559243Sobrien} 222659243Sobrien 222759243Sobrien/*ARGSUSED*/ 222859243Sobrienstatic void 2229167465Smpplim(struct limits *lp, int hard) 223059243Sobrien{ 223159243Sobrien# ifdef BSDLIMIT 223259243Sobrien struct rlimit rlim; 223359243Sobrien# endif /* BSDLIMIT */ 223459243Sobrien RLIM_TYPE limit; 2235145479Smp int xdiv = lp->limdiv; 223659243Sobrien 2237131962Smp xprintf("%-13.13s", lp->limname); 223859243Sobrien 223959243Sobrien# ifndef BSDLIMIT 224059243Sobrien limit = ulimit(lp->limconst, 0); 224159243Sobrien# ifdef aiws 224259243Sobrien if (lp->limconst == RLIMIT_DATA) 224359243Sobrien limit -= 0x20000000; 224459243Sobrien# endif /* aiws */ 224559243Sobrien# else /* BSDLIMIT */ 224659243Sobrien (void) getrlimit(lp->limconst, &rlim); 224759243Sobrien limit = hard ? rlim.rlim_max : rlim.rlim_cur; 224859243Sobrien# endif /* BSDLIMIT */ 224959243Sobrien 225059243Sobrien# if !defined(BSDLIMIT) || defined(FILESIZE512) 225159243Sobrien /* 225259243Sobrien * Christos: filesize comes in 512 blocks. we divide by 2 to get 1024 225359243Sobrien * blocks. Note we cannot pre-multiply cause we might overflow (A/UX) 225459243Sobrien */ 225559243Sobrien if (lp->limconst == RLIMIT_FSIZE) { 225659243Sobrien if (limit >= (RLIM_INFINITY / 512)) 225759243Sobrien limit = RLIM_INFINITY; 225859243Sobrien else 2259145479Smp xdiv = (xdiv == 1024 ? 2 : 1); 226059243Sobrien } 226159243Sobrien# endif /* !BSDLIMIT || FILESIZE512 */ 226259243Sobrien 226359243Sobrien if (limit == RLIM_INFINITY) 226459243Sobrien xprintf("unlimited"); 226559243Sobrien else 2266145479Smp# if defined(RLIMIT_CPU) && defined(_OSD_POSIX) 2267145479Smp if (lp->limconst == RLIMIT_CPU && 2268145479Smp (unsigned long)limit >= 0x7ffffffdUL) 2269145479Smp xprintf("unlimited"); 2270145479Smp else 2271145479Smp# endif 227259243Sobrien# ifdef RLIMIT_CPU 227359243Sobrien if (lp->limconst == RLIMIT_CPU) 2274167465Smp psecs(limit); 227559243Sobrien else 227659243Sobrien# endif /* RLIMIT_CPU */ 2277145479Smp xprintf("%ld %s", (long) (limit / xdiv), lp->limscale); 227859243Sobrien xputchar('\n'); 227959243Sobrien} 228059243Sobrien 228159243Sobrien/*ARGSUSED*/ 228259243Sobrienvoid 2283167465Smpdounlimit(Char **v, struct command *c) 228459243Sobrien{ 2285145479Smp struct limits *lp; 228659243Sobrien int lerr = 0; 228759243Sobrien int hard = 0; 228859243Sobrien int force = 0; 228959243Sobrien 229059243Sobrien USE(c); 229159243Sobrien while (*++v && **v == '-') { 229259243Sobrien Char *vp = *v; 229359243Sobrien while (*++vp) 229459243Sobrien switch (*vp) { 229559243Sobrien case 'f': 229659243Sobrien force = 1; 229759243Sobrien break; 229859243Sobrien case 'h': 229959243Sobrien hard = 1; 230059243Sobrien break; 230159243Sobrien default: 230259243Sobrien stderror(ERR_ULIMUS); 230359243Sobrien break; 230459243Sobrien } 230559243Sobrien } 230659243Sobrien 230759243Sobrien if (*v == 0) { 230859243Sobrien for (lp = limits; lp->limconst >= 0; lp++) 230959243Sobrien if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0) 231059243Sobrien lerr++; 231159243Sobrien if (!force && lerr) 231259243Sobrien stderror(ERR_SILENT); 231359243Sobrien return; 231459243Sobrien } 231559243Sobrien while (*v) { 231659243Sobrien lp = findlim(*v++); 231759243Sobrien if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0 && !force) 231859243Sobrien stderror(ERR_SILENT); 231959243Sobrien } 232059243Sobrien} 232159243Sobrien 232259243Sobrienstatic int 2323167465Smpsetlim(struct limits *lp, int hard, RLIM_TYPE limit) 232459243Sobrien{ 232559243Sobrien# ifdef BSDLIMIT 232659243Sobrien struct rlimit rlim; 232759243Sobrien 232859243Sobrien (void) getrlimit(lp->limconst, &rlim); 232959243Sobrien 233059243Sobrien# ifdef FILESIZE512 233159243Sobrien /* Even though hpux has setrlimit(), it expects fsize in 512 byte blocks */ 233259243Sobrien if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 233359243Sobrien limit /= 512; 233459243Sobrien# endif /* FILESIZE512 */ 233559243Sobrien if (hard) 233659243Sobrien rlim.rlim_max = limit; 233759243Sobrien else if (limit == RLIM_INFINITY && euid != 0) 233859243Sobrien rlim.rlim_cur = rlim.rlim_max; 233959243Sobrien else 234059243Sobrien rlim.rlim_cur = limit; 234159243Sobrien 2342100616Smp if (rlim.rlim_cur > rlim.rlim_max) 2343100616Smp rlim.rlim_max = rlim.rlim_cur; 2344100616Smp 234559243Sobrien if (setrlimit(lp->limconst, &rlim) < 0) { 234659243Sobrien# else /* BSDLIMIT */ 234759243Sobrien if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 234859243Sobrien limit /= 512; 234959243Sobrien# ifdef aiws 235059243Sobrien if (lp->limconst == RLIMIT_DATA) 235159243Sobrien limit += 0x20000000; 235259243Sobrien# endif /* aiws */ 235359243Sobrien if (ulimit(toset(lp->limconst), limit) < 0) { 235459243Sobrien# endif /* BSDLIMIT */ 2355145479Smp int err; 2356145479Smp char *op, *type; 2357145479Smp 2358145479Smp err = errno; 2359145479Smp op = strsave(limit == RLIM_INFINITY ? CGETS(15, 2, "remove") : 2360145479Smp CGETS(15, 3, "set")); 2361167465Smp cleanup_push(op, xfree); 2362145479Smp type = strsave(hard ? CGETS(15, 4, " hard") : ""); 2363167465Smp cleanup_push(type, xfree); 2364100616Smp xprintf(CGETS(15, 1, "%s: %s: Can't %s%s limit (%s)\n"), bname, 2365145479Smp lp->limname, op, type, strerror(err)); 2366167465Smp cleanup_until(op); 236759243Sobrien return (-1); 236859243Sobrien } 236959243Sobrien return (0); 237059243Sobrien} 237159243Sobrien 237259243Sobrien#endif /* !HAVENOLIMIT */ 237359243Sobrien 237459243Sobrien/*ARGSUSED*/ 237559243Sobrienvoid 2376167465Smpdosuspend(Char **v, struct command *c) 237759243Sobrien{ 237859243Sobrien#ifdef BSDJOBS 2379167465Smp struct sigaction old; 238059243Sobrien#endif /* BSDJOBS */ 2381195609Smp 238259243Sobrien USE(c); 238359243Sobrien USE(v); 238459243Sobrien 238559243Sobrien if (loginsh) 238659243Sobrien stderror(ERR_SUSPLOG); 238759243Sobrien untty(); 238859243Sobrien 238959243Sobrien#ifdef BSDJOBS 2390167465Smp sigaction(SIGTSTP, NULL, &old); 2391167465Smp signal(SIGTSTP, SIG_DFL); 239259243Sobrien (void) kill(0, SIGTSTP); 239359243Sobrien /* the shell stops here */ 2394167465Smp sigaction(SIGTSTP, &old, NULL); 239559243Sobrien#else /* !BSDJOBS */ 239659243Sobrien stderror(ERR_JOBCONTROL); 239759243Sobrien#endif /* BSDJOBS */ 239859243Sobrien 239959243Sobrien#ifdef BSDJOBS 240059243Sobrien if (tpgrp != -1) { 2401195609Smp if (grabpgrp(FSHTTY, opgrp) == -1) 2402131962Smp stderror(ERR_SYSTEM, "tcgetpgrp", strerror(errno)); 240359243Sobrien (void) setpgid(0, shpgrp); 240459243Sobrien (void) tcsetpgrp(FSHTTY, shpgrp); 240559243Sobrien } 240659243Sobrien#endif /* BSDJOBS */ 240759243Sobrien (void) setdisc(FSHTTY); 240859243Sobrien} 240959243Sobrien 241059243Sobrien/* This is the dreaded EVAL built-in. 241159243Sobrien * If you don't fiddle with file descriptors, and reset didfds, 241259243Sobrien * this command will either ignore redirection inside or outside 241359243Sobrien * its arguments, e.g. eval "date >x" vs. eval "date" >x 241459243Sobrien * The stuff here seems to work, but I did it by trial and error rather 241559243Sobrien * than really knowing what was going on. If tpgrp is zero, we are 241659243Sobrien * probably a background eval, e.g. "eval date &", and we want to 241759243Sobrien * make sure that any processes we start stay in our pgrp. 241859243Sobrien * This is also the case for "time eval date" -- stay in same pgrp. 241959243Sobrien * Otherwise, under stty tostop, processes will stop in the wrong 242059243Sobrien * pgrp, with no way for the shell to get them going again. -IAN! 242159243Sobrien */ 242259243Sobrien 2423167465Smpstruct doeval_state 242459243Sobrien{ 2425167465Smp Char **evalvec, *evalp; 2426167465Smp int didfds; 242759243Sobrien#ifndef CLOSE_ON_EXEC 2428167465Smp int didcch; 2429167465Smp#endif 2430167465Smp int saveIN, saveOUT, saveDIAG; 2431167465Smp int SHIN, SHOUT, SHDIAG; 2432167465Smp}; 243359243Sobrien 2434167465Smpstatic void 2435167465Smpdoeval_cleanup(void *xstate) 2436167465Smp{ 2437167465Smp struct doeval_state *state; 2438167465Smp 2439167465Smp state = xstate; 2440167465Smp evalvec = state->evalvec; 2441167465Smp evalp = state->evalp; 2442167465Smp doneinp = 0; 244359243Sobrien#ifndef CLOSE_ON_EXEC 2444167465Smp didcch = state->didcch; 244559243Sobrien#endif /* CLOSE_ON_EXEC */ 2446167465Smp didfds = state->didfds; 2447316957Sdchagin if (state->saveIN != SHIN) 2448316957Sdchagin xclose(SHIN); 2449316957Sdchagin if (state->saveOUT != SHOUT) 2450316957Sdchagin xclose(SHOUT); 2451316957Sdchagin if (state->saveDIAG != SHDIAG) 2452316957Sdchagin xclose(SHDIAG); 2453167465Smp close_on_exec(SHIN = dmove(state->saveIN, state->SHIN), 1); 2454167465Smp close_on_exec(SHOUT = dmove(state->saveOUT, state->SHOUT), 1); 2455167465Smp close_on_exec(SHDIAG = dmove(state->saveDIAG, state->SHDIAG), 1); 2456316957Sdchagin if (didfds) { 2457316957Sdchagin close_on_exec(dcopy(SHIN, 0), 1); 2458316957Sdchagin close_on_exec(dcopy(SHOUT, 1), 1); 2459316957Sdchagin close_on_exec(dcopy(SHDIAG, 2), 1); 2460316957Sdchagin } 2461167465Smp} 246259243Sobrien 2463195609Smpstatic Char **Ggv; 2464167465Smp/*ARGSUSED*/ 2465167465Smpvoid 2466167465Smpdoeval(Char **v, struct command *c) 2467167465Smp{ 2468167465Smp struct doeval_state state; 2469195609Smp int gflag, my_reenter; 2470167465Smp Char **gv; 2471195609Smp jmp_buf_t osetexit; 247259243Sobrien 2473167465Smp USE(c); 2474167465Smp v++; 2475167465Smp if (*v == 0) 247659243Sobrien return; 2477167465Smp gflag = tglob(v); 247859243Sobrien if (gflag) { 2479167465Smp gv = v = globall(v, gflag); 2480167465Smp if (v == 0) 248159243Sobrien stderror(ERR_NOMATCH); 2482167465Smp cleanup_push(gv, blk_cleanup); 2483167465Smp v = copyblk(v); 248459243Sobrien } 248559243Sobrien else { 248659243Sobrien gv = NULL; 2487167465Smp v = copyblk(v); 2488167465Smp trim(v); 248959243Sobrien } 249059243Sobrien 2491195609Smp Ggv = gv; 2492167465Smp state.evalvec = evalvec; 2493167465Smp state.evalp = evalp; 2494167465Smp state.didfds = didfds; 249559243Sobrien#ifndef CLOSE_ON_EXEC 2496167465Smp state.didcch = didcch; 249759243Sobrien#endif /* CLOSE_ON_EXEC */ 2498167465Smp state.SHIN = SHIN; 2499167465Smp state.SHOUT = SHOUT; 2500167465Smp state.SHDIAG = SHDIAG; 250159243Sobrien 2502167465Smp (void)close_on_exec(state.saveIN = dcopy(SHIN, -1), 1); 2503167465Smp (void)close_on_exec(state.saveOUT = dcopy(SHOUT, -1), 1); 2504167465Smp (void)close_on_exec(state.saveDIAG = dcopy(SHDIAG, -1), 1); 2505167465Smp 2506167465Smp cleanup_push(&state, doeval_cleanup); 2507167465Smp 2508195609Smp getexit(osetexit); 2509195609Smp 2510195609Smp /* PWP: setjmp/longjmp bugfix for optimizing compilers */ 2511195609Smp#ifdef cray 2512195609Smp my_reenter = 1; /* assume non-zero return val */ 2513195609Smp if (setexit() == 0) { 2514195609Smp my_reenter = 0; /* Oh well, we were wrong */ 2515195609Smp#else /* !cray */ 2516195609Smp if ((my_reenter = setexit()) == 0) { 2517195609Smp#endif /* cray */ 2518195609Smp evalvec = v; 2519195609Smp evalp = 0; 2520195609Smp (void)close_on_exec(SHIN = dcopy(0, -1), 1); 2521195609Smp (void)close_on_exec(SHOUT = dcopy(1, -1), 1); 2522195609Smp (void)close_on_exec(SHDIAG = dcopy(2, -1), 1); 252359243Sobrien#ifndef CLOSE_ON_EXEC 2524195609Smp didcch = 0; 252559243Sobrien#endif /* CLOSE_ON_EXEC */ 2526195609Smp didfds = 0; 2527195609Smp gv = Ggv; 2528195609Smp process(0); 2529195609Smp Ggv = gv; 2530195609Smp } 253159243Sobrien 2532195609Smp if (my_reenter == 0) { 2533195609Smp cleanup_until(&state); 2534195609Smp if (Ggv) 2535195609Smp cleanup_until(Ggv); 2536195609Smp } 2537167465Smp 2538195609Smp resexit(osetexit); 2539195609Smp if (my_reenter) 2540195609Smp stderror(ERR_SILENT); 254159243Sobrien} 254259243Sobrien 254359243Sobrien/*************************************************************************/ 254459243Sobrien/* print list of builtin commands */ 254559243Sobrien 2546167465Smpstatic void 2547167465Smplbuffed_cleanup (void *dummy) 2548167465Smp{ 2549167465Smp USE(dummy); 2550167465Smp lbuffed = 1; 2551167465Smp} 2552167465Smp 255359243Sobrien/*ARGSUSED*/ 255459243Sobrienvoid 2555167465Smpdobuiltins(Char **v, struct command *c) 255659243Sobrien{ 255759243Sobrien /* would use print_by_column() in tw.parse.c but that assumes 255859243Sobrien * we have an array of Char * to pass.. (sg) 255959243Sobrien */ 2560167465Smp const struct biltins *b; 2561145479Smp int row, col, columns, rows; 256259243Sobrien unsigned int w, maxwidth; 256359243Sobrien 256459243Sobrien USE(c); 256559243Sobrien USE(v); 256659243Sobrien lbuffed = 0; /* turn off line buffering */ 2567167465Smp cleanup_push(&lbuffed, lbuffed_cleanup); 256859243Sobrien 256959243Sobrien /* find widest string */ 257059243Sobrien for (maxwidth = 0, b = bfunc; b < &bfunc[nbfunc]; ++b) 257159243Sobrien maxwidth = max(maxwidth, strlen(b->bname)); 257259243Sobrien ++maxwidth; /* for space */ 257359243Sobrien 257459243Sobrien columns = (TermH + 1) / maxwidth; /* PWP: terminal size change */ 257559243Sobrien if (!columns) 257659243Sobrien columns = 1; 257759243Sobrien rows = (nbfunc + (columns - 1)) / columns; 257859243Sobrien 257959243Sobrien for (b = bfunc, row = 0; row < rows; row++) { 258059243Sobrien for (col = 0; col < columns; col++) { 258159243Sobrien if (b < &bfunc[nbfunc]) { 258259243Sobrien w = strlen(b->bname); 258359243Sobrien xprintf("%s", b->bname); 258459243Sobrien if (col < (columns - 1)) /* Not last column? */ 258559243Sobrien for (; w < maxwidth; w++) 258659243Sobrien xputchar(' '); 258759243Sobrien ++b; 258859243Sobrien } 258959243Sobrien } 259059243Sobrien if (row < (rows - 1)) { 259159243Sobrien if (Tty_raw_mode) 259259243Sobrien xputchar('\r'); 259359243Sobrien xputchar('\n'); 259459243Sobrien } 259559243Sobrien } 259669408Sache#ifdef WINNT_NATIVE 259759243Sobrien nt_print_builtins(maxwidth); 259859243Sobrien#else 259959243Sobrien if (Tty_raw_mode) 260059243Sobrien xputchar('\r'); 260159243Sobrien xputchar('\n'); 260269408Sache#endif /* WINNT_NATIVE */ 260359243Sobrien 2604167465Smp cleanup_until(&lbuffed); /* turn back on line buffering */ 260559243Sobrien flush(); 260659243Sobrien} 260759243Sobrien 2608145479Smp#ifdef NLS_CATALOGS 2609145479Smpchar * 2610167465Smpxcatgets(nl_catd ctd, int set_id, int msg_id, const char *s) 2611145479Smp{ 2612167465Smp char *res; 2613167465Smp 2614167465Smp errno = 0; 2615167465Smp while ((res = catgets(ctd, set_id, msg_id, s)) == s && errno == EINTR) { 2616167465Smp handle_pending_signals(); 2617167465Smp errno = 0; 2618167465Smp } 2619167465Smp return res; 2620167465Smp} 2621167465Smp 2622167465Smp 2623167465Smp# if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2624167465Smpchar * 2625167465Smpiconv_catgets(nl_catd ctd, int set_id, int msg_id, const char *s) 2626167465Smp{ 2627145479Smp static char *buf = NULL; 2628145479Smp static size_t buf_size = 0; 2629145479Smp 2630145479Smp char *orig, *dest, *p; 2631167465Smp ICONV_CONST char *src; 2632145479Smp size_t src_size, dest_size; 2633145479Smp 2634167465Smp orig = xcatgets(ctd, set_id, msg_id, s); 2635145479Smp if (catgets_iconv == (iconv_t)-1 || orig == s) 2636145479Smp return orig; 2637145479Smp src = orig; 2638145479Smp src_size = strlen(src) + 1; 2639145479Smp if (buf == NULL && (buf = xmalloc(buf_size = src_size + 32)) == NULL) 2640145479Smp return orig; 2641145479Smp dest = buf; 2642145479Smp while (src_size != 0) { 2643145479Smp dest_size = buf + buf_size - dest; 2644145479Smp if (iconv(catgets_iconv, &src, &src_size, &dest, &dest_size) 2645145479Smp == (size_t)-1) { 2646145479Smp switch (errno) { 2647145479Smp case E2BIG: 2648145479Smp if ((p = xrealloc(buf, buf_size * 2)) == NULL) 2649145479Smp return orig; 2650145479Smp buf_size *= 2; 2651145479Smp dest = p + (dest - buf); 2652145479Smp buf = p; 2653145479Smp break; 2654145479Smp 2655145479Smp case EILSEQ: case EINVAL: default: 2656145479Smp return orig; 2657145479Smp } 2658145479Smp } 2659145479Smp } 2660145479Smp return buf; 2661145479Smp} 2662167465Smp# endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2663167465Smp#endif /* NLS_CATALOGS */ 2664145479Smp 266559243Sobrienvoid 2666167465Smpnlsinit(void) 266759243Sobrien{ 266859243Sobrien#ifdef NLS_CATALOGS 2669167465Smp static const char default_catalog[] = "tcsh"; 267069408Sache 2671167465Smp char *catalog = (char *)(intptr_t)default_catalog; 2672167465Smp 267369408Sache if (adrof(STRcatalog) != NULL) 2674167465Smp catalog = xasprintf("tcsh.%s", short2str(varval(STRcatalog))); 2675231990Smp#ifdef NL_CAT_LOCALE /* POSIX-compliant. */ 2676231990Smp /* 2677231990Smp * Check if LC_MESSAGES is set in the environment and use it, if so. 2678231990Smp * If not, fall back to the setting of LANG. 2679231990Smp */ 2680231990Smp catd = catopen(catalog, tgetenv(STRLC_MESSAGES) ? NL_CAT_LOCALE : 0); 2681231990Smp#else /* pre-POSIX */ 2682231990Smp# ifndef MCLoadBySet 2683231990Smp# define MCLoadBySet 0 2684231990Smp# endif 268569408Sache catd = catopen(catalog, MCLoadBySet); 2686231990Smp#endif 2687167465Smp if (catalog != default_catalog) 2688167465Smp xfree(catalog); 2689167465Smp#if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2690167465Smp /* xcatgets (), not CGETS, the charset name should be in ASCII anyway. */ 2691145479Smp catgets_iconv = iconv_open (nl_langinfo (CODESET), 2692231990Smp xcatgets(catd, 255, 1, "UTF-8")); 2693167465Smp#endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 269469408Sache#endif /* NLS_CATALOGS */ 269569408Sache#ifdef WINNT_NATIVE 269659243Sobrien nls_dll_init(); 269769408Sache#endif /* WINNT_NATIVE */ 269859243Sobrien errinit(); /* init the errorlist in correct locale */ 269959243Sobrien mesginit(); /* init the messages for signals */ 270059243Sobrien dateinit(); /* init the messages for dates */ 270159243Sobrien editinit(); /* init the editor messages */ 270259243Sobrien terminit(); /* init the termcap messages */ 270359243Sobrien} 2704145479Smp 2705145479Smpvoid 2706167465Smpnlsclose(void) 2707145479Smp{ 2708145479Smp#ifdef NLS_CATALOGS 2709167465Smp#if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2710145479Smp if (catgets_iconv != (iconv_t)-1) { 2711145479Smp iconv_close(catgets_iconv); 2712145479Smp catgets_iconv = (iconv_t)-1; 2713145479Smp } 2714167465Smp#endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2715167465Smp if (catd != (nl_catd)-1) { 2716167465Smp /* 2717167465Smp * catclose can call other functions which can call longjmp 2718167465Smp * making us re-enter this code. Prevent infinite recursion 2719167465Smp * by resetting catd. Problem reported and solved by: 2720167465Smp * Gerhard Niklasch 2721167465Smp */ 2722167465Smp nl_catd oldcatd = catd; 2723167465Smp catd = (nl_catd)-1; 2724167465Smp while (catclose(oldcatd) == -1 && errno == EINTR) 2725167465Smp handle_pending_signals(); 2726167465Smp } 2727145479Smp#endif /* NLS_CATALOGS */ 2728145479Smp} 2729316957Sdchagin 2730316957Sdchaginint 2731316957SdchagingetYN(const char *prompt) 2732316957Sdchagin{ 2733316957Sdchagin int doit; 2734316957Sdchagin char c; 2735316957Sdchagin 2736316957Sdchagin xprintf("%s", prompt); 2737316957Sdchagin flush(); 2738316957Sdchagin (void) force_read(SHIN, &c, sizeof(c)); 2739316957Sdchagin /* 2740316957Sdchagin * Perhaps we should use the yesexpr from the 2741316957Sdchagin * actual locale 2742316957Sdchagin */ 2743316957Sdchagin doit = (strchr(CGETS(22, 14, "Yy"), c) != NULL); 2744316957Sdchagin while (c != '\n' && force_read(SHIN, &c, sizeof(c)) == sizeof(c)) 2745316957Sdchagin continue; 2746316957Sdchagin return doit; 2747316957Sdchagin} 2748