1316958Sdchagin/* $Header: /p/tcsh/cvsroot/tcsh/sh.func.c,v 3.176 2016/10/18 17:26:42 christos Exp $ */ 259243Sobrien/* 359243Sobrien * sh.func.c: csh builtin functions 459243Sobrien */ 559243Sobrien/*- 659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 759243Sobrien * All rights reserved. 859243Sobrien * 959243Sobrien * Redistribution and use in source and binary forms, with or without 1059243Sobrien * modification, are permitted provided that the following conditions 1159243Sobrien * are met: 1259243Sobrien * 1. Redistributions of source code must retain the above copyright 1359243Sobrien * notice, this list of conditions and the following disclaimer. 1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1559243Sobrien * notice, this list of conditions and the following disclaimer in the 1659243Sobrien * documentation and/or other materials provided with the distribution. 17100616Smp * 3. Neither the name of the University nor the names of its contributors 1859243Sobrien * may be used to endorse or promote products derived from this software 1959243Sobrien * without specific prior written permission. 2059243Sobrien * 2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2459243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3159243Sobrien * SUCH DAMAGE. 3259243Sobrien */ 3359243Sobrien#include "sh.h" 3459243Sobrien 35316958SdchaginRCSID("$tcsh: sh.func.c,v 3.176 2016/10/18 17:26:42 christos Exp $") 3659243Sobrien 3759243Sobrien#include "ed.h" 3859243Sobrien#include "tw.h" 3959243Sobrien#include "tc.h" 4069408Sache#ifdef WINNT_NATIVE 4159243Sobrien#include "nt.const.h" 4269408Sache#endif /* WINNT_NATIVE */ 4359243Sobrien 44231990Smp#if defined (NLS_CATALOGS) && defined(HAVE_ICONV) 45145479Smpstatic iconv_t catgets_iconv; /* Or (iconv_t)-1 */ 46145479Smp#endif 47145479Smp 4859243Sobrien/* 4959243Sobrien * C shell 5059243Sobrien */ 5159243Sobrien 52145479Smpextern int MapsAreInited; 53145479Smpextern int NLSMapsAreInited; 54145479Smpextern int GotTermCaps; 5559243Sobrien 5659243Sobrienstatic int zlast = -1; 5759243Sobrien 58167465Smpstatic void islogin (void); 59167465Smpstatic void preread (void); 60167465Smpstatic void doagain (void); 61167465Smpstatic const char *isrchx (int); 62167465Smpstatic void search (int, int, Char *); 63167465Smpstatic int getword (struct Strbuf *); 64195609Smpstatic struct wordent *histgetword (struct wordent *); 65167465Smpstatic void toend (void); 66167465Smpstatic void xecho (int, Char **); 67167465Smpstatic int islocale_var (Char *); 68167465Smpstatic void wpfree (struct whyle *); 6959243Sobrien 70167465Smpconst struct biltins * 71167465Smpisbfunc(struct command *t) 7259243Sobrien{ 73145479Smp Char *cp = t->t_dcom[0]; 74167465Smp const struct biltins *bp, *bp1, *bp2; 7559243Sobrien static struct biltins label = {"", dozip, 0, 0}; 7659243Sobrien static struct biltins foregnd = {"%job", dofg1, 0, 0}; 7759243Sobrien static struct biltins backgnd = {"%job &", dobg1, 0, 0}; 7859243Sobrien 7959243Sobrien /* 8059243Sobrien * We never match a builtin that has quoted the first 8159243Sobrien * character; this has been the traditional way to escape 8259243Sobrien * builtin commands. 8359243Sobrien */ 8459243Sobrien if (*cp & QUOTE) 8559243Sobrien return NULL; 8659243Sobrien 8759243Sobrien if (*cp != ':' && lastchr(cp) == ':') { 8859243Sobrien label.bname = short2str(cp); 8959243Sobrien return (&label); 9059243Sobrien } 9159243Sobrien if (*cp == '%') { 9259243Sobrien if (t->t_dflg & F_AMPERSAND) { 9359243Sobrien t->t_dflg &= ~F_AMPERSAND; 9459243Sobrien backgnd.bname = short2str(cp); 9559243Sobrien return (&backgnd); 9659243Sobrien } 9759243Sobrien foregnd.bname = short2str(cp); 9859243Sobrien return (&foregnd); 9959243Sobrien } 10059243Sobrien#ifdef WARP 10159243Sobrien /* 10259243Sobrien * This is a perhaps kludgy way to determine if the warp builtin is to be 10359243Sobrien * acknowledged or not. If checkwarp() fails, then we are to assume that 10459243Sobrien * the warp command is invalid, and carry on as we would handle any other 10559243Sobrien * non-builtin command. -- JDK 2/4/88 10659243Sobrien */ 10759243Sobrien if (eq(STRwarp, cp) && !checkwarp()) { 10859243Sobrien return (0); /* this builtin disabled */ 10959243Sobrien } 11059243Sobrien#endif /* WARP */ 11159243Sobrien /* 11259243Sobrien * Binary search Bp1 is the beginning of the current search range. Bp2 is 11359243Sobrien * one past the end. 11459243Sobrien */ 11559243Sobrien for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) { 11659243Sobrien int i; 11759243Sobrien 11859243Sobrien bp = bp1 + ((bp2 - bp1) >> 1); 11959243Sobrien if ((i = ((char) *cp) - *bp->bname) == 0 && 12059243Sobrien (i = StrQcmp(cp, str2short(bp->bname))) == 0) 12159243Sobrien return bp; 12259243Sobrien if (i < 0) 12359243Sobrien bp2 = bp; 12459243Sobrien else 12559243Sobrien bp1 = bp + 1; 12659243Sobrien } 12769408Sache#ifdef WINNT_NATIVE 12859243Sobrien return nt_check_additional_builtins(cp); 12969408Sache#endif /*WINNT_NATIVE*/ 13059243Sobrien return (0); 13159243Sobrien} 13259243Sobrien 13359243Sobrienvoid 134167465Smpfunc(struct command *t, const struct biltins *bp) 13559243Sobrien{ 13659243Sobrien int i; 13759243Sobrien 13859243Sobrien xechoit(t->t_dcom); 13959243Sobrien setname(bp->bname); 14059243Sobrien i = blklen(t->t_dcom) - 1; 14159243Sobrien if (i < bp->minargs) 14259243Sobrien stderror(ERR_NAME | ERR_TOOFEW); 14359243Sobrien if (i > bp->maxargs) 14459243Sobrien stderror(ERR_NAME | ERR_TOOMANY); 14559243Sobrien (*bp->bfunct) (t->t_dcom, t); 14659243Sobrien} 14759243Sobrien 14859243Sobrien/*ARGSUSED*/ 14959243Sobrienvoid 150167465Smpdoonintr(Char **v, struct command *c) 15159243Sobrien{ 152145479Smp Char *cp; 153145479Smp Char *vv = v[1]; 15459243Sobrien 15559243Sobrien USE(c); 156167465Smp if (parintr.sa_handler == SIG_IGN) 15759243Sobrien return; 15859243Sobrien if (setintr && intty) 15959243Sobrien stderror(ERR_NAME | ERR_TERMINAL); 16059243Sobrien cp = gointr; 16159243Sobrien gointr = 0; 162167465Smp xfree(cp); 16359243Sobrien if (vv == 0) { 164167465Smp if (setintr) 165167465Smp sigset_interrupting(SIGINT, queue_pintr); 166167465Smp else 16759243Sobrien (void) signal(SIGINT, SIG_DFL); 16859243Sobrien gointr = 0; 16959243Sobrien } 17059243Sobrien else if (eq((vv = strip(vv)), STRminus)) { 17159243Sobrien (void) signal(SIGINT, SIG_IGN); 17259243Sobrien gointr = Strsave(STRminus); 17359243Sobrien } 17459243Sobrien else { 17559243Sobrien gointr = Strsave(vv); 176167465Smp sigset_interrupting(SIGINT, queue_pintr); 17759243Sobrien } 17859243Sobrien} 17959243Sobrien 18059243Sobrien/*ARGSUSED*/ 18159243Sobrienvoid 182167465Smpdonohup(Char **v, struct command *c) 18359243Sobrien{ 18459243Sobrien USE(c); 18559243Sobrien USE(v); 18659243Sobrien if (intty) 18759243Sobrien stderror(ERR_NAME | ERR_TERMINAL); 18859243Sobrien if (setintr == 0) { 18959243Sobrien (void) signal(SIGHUP, SIG_IGN); 190167465Smp phup_disabled = 1; 19159243Sobrien#ifdef CC 19259243Sobrien submit(getpid()); 19359243Sobrien#endif /* CC */ 19459243Sobrien } 19559243Sobrien} 19659243Sobrien 19759243Sobrien/*ARGSUSED*/ 19859243Sobrienvoid 199167465Smpdohup(Char **v, struct command *c) 20059243Sobrien{ 20159243Sobrien USE(c); 20259243Sobrien USE(v); 20359243Sobrien if (intty) 20459243Sobrien stderror(ERR_NAME | ERR_TERMINAL); 20559243Sobrien if (setintr == 0) 20659243Sobrien (void) signal(SIGHUP, SIG_DFL); 20759243Sobrien} 20859243Sobrien 20959243Sobrien 21059243Sobrien/*ARGSUSED*/ 21159243Sobrienvoid 212167465Smpdozip(Char **v, struct command *c) 21359243Sobrien{ 21459243Sobrien USE(c); 21559243Sobrien USE(v); 21659243Sobrien} 21759243Sobrien 21859243Sobrien/*ARGSUSED*/ 21959243Sobrienvoid 220167465Smpdofiletest(Char **v, struct command *c) 22159243Sobrien{ 222167465Smp Char **globbed, **fileptr, *ftest, *res; 22359243Sobrien 224145479Smp USE(c); 22559243Sobrien if (*(ftest = *++v) != '-') 22659243Sobrien stderror(ERR_NAME | ERR_FILEINQ); 22759243Sobrien ++v; 22859243Sobrien 229167465Smp v = glob_all_or_error(v); 230167465Smp globbed = v; 231167465Smp cleanup_push(globbed, blk_cleanup); 23259243Sobrien 23359243Sobrien while (*(fileptr = v++) != '\0') { 234167465Smp res = filetest(ftest, &fileptr, 0); 235167465Smp cleanup_push(res, xfree); 236167465Smp xprintf("%S", res); 237167465Smp cleanup_until(res); 23859243Sobrien if (*v) 23959243Sobrien xprintf(" "); 24059243Sobrien } 24159243Sobrien xprintf("\n"); 24259243Sobrien 243167465Smp cleanup_until(globbed); 24459243Sobrien} 24559243Sobrien 24659243Sobrienvoid 247167465Smpprvars(void) 24859243Sobrien{ 24959243Sobrien plist(&shvhed, VAR_ALL); 25059243Sobrien} 25159243Sobrien 25259243Sobrien/*ARGSUSED*/ 25359243Sobrienvoid 254167465Smpdoalias(Char **v, struct command *c) 25559243Sobrien{ 256145479Smp struct varent *vp; 257145479Smp Char *p; 25859243Sobrien 25959243Sobrien USE(c); 26059243Sobrien v++; 26159243Sobrien p = *v++; 26259243Sobrien if (p == 0) 26359243Sobrien plist(&aliases, VAR_ALL); 26459243Sobrien else if (*v == 0) { 26559243Sobrien vp = adrof1(strip(p), &aliases); 266100616Smp if (vp && vp->vec) 26759243Sobrien blkpr(vp->vec), xputchar('\n'); 26859243Sobrien } 26959243Sobrien else { 27059243Sobrien if (eq(p, STRalias) || eq(p, STRunalias)) { 27159243Sobrien setname(short2str(p)); 27259243Sobrien stderror(ERR_NAME | ERR_DANGER); 27359243Sobrien } 27459243Sobrien set1(strip(p), saveblk(v), &aliases, VAR_READWRITE); 27559243Sobrien tw_cmd_free(); 27659243Sobrien } 27759243Sobrien} 27859243Sobrien 27959243Sobrien/*ARGSUSED*/ 28059243Sobrienvoid 281167465Smpunalias(Char **v, struct command *c) 28259243Sobrien{ 28359243Sobrien USE(c); 28459243Sobrien unset1(v, &aliases); 28559243Sobrien tw_cmd_free(); 28659243Sobrien} 28759243Sobrien 28859243Sobrien/*ARGSUSED*/ 28959243Sobrienvoid 290167465Smpdologout(Char **v, struct command *c) 29159243Sobrien{ 29259243Sobrien USE(c); 29359243Sobrien USE(v); 29459243Sobrien islogin(); 29559243Sobrien goodbye(NULL, NULL); 29659243Sobrien} 29759243Sobrien 29859243Sobrien/*ARGSUSED*/ 29959243Sobrienvoid 300167465Smpdologin(Char **v, struct command *c) 30159243Sobrien{ 302131962Smp#ifdef WINNT_NATIVE 30359243Sobrien USE(c); 30459243Sobrien USE(v); 30569408Sache#else /* !WINNT_NATIVE */ 306131962Smp char **p = short2blk(v); 307167465Smp 308131962Smp USE(c); 309167465Smp cleanup_push((Char **)p, blk_cleanup); 31059243Sobrien islogin(); 31159243Sobrien rechist(NULL, adrof(STRsavehist) != NULL); 312167465Smp sigaction(SIGTERM, &parterm, NULL); 313131962Smp (void) execv(_PATH_BIN_LOGIN, p); 314131962Smp (void) execv(_PATH_USRBIN_LOGIN, p); 315167465Smp cleanup_until((Char **)p); 31659243Sobrien untty(); 31759243Sobrien xexit(1); 31869408Sache#endif /* !WINNT_NATIVE */ 31959243Sobrien} 32059243Sobrien 32159243Sobrien 32259243Sobrien#ifdef NEWGRP 32359243Sobrien/*ARGSUSED*/ 32459243Sobrienvoid 325167465Smpdonewgrp(Char **v, struct command *c) 32659243Sobrien{ 32759243Sobrien char **p; 32859243Sobrien if (chkstop == 0 && setintr) 32959243Sobrien panystop(0); 330167465Smp sigaction(SIGTERM, &parterm, NULL); 33159243Sobrien p = short2blk(v); 33259243Sobrien /* 33359243Sobrien * From Beto Appleton (beto@aixwiz.austin.ibm.com) 33459243Sobrien * Newgrp can take 2 arguments... 33559243Sobrien */ 33659243Sobrien (void) execv(_PATH_BIN_NEWGRP, p); 33759243Sobrien (void) execv(_PATH_USRBIN_NEWGRP, p); 33859243Sobrien blkfree((Char **) p); 33959243Sobrien untty(); 34059243Sobrien xexit(1); 34159243Sobrien} 34259243Sobrien#endif /* NEWGRP */ 34359243Sobrien 34459243Sobrienstatic void 345167465Smpislogin(void) 34659243Sobrien{ 34759243Sobrien if (chkstop == 0 && setintr) 34859243Sobrien panystop(0); 34959243Sobrien if (loginsh) 35059243Sobrien return; 35159243Sobrien stderror(ERR_NOTLOGIN); 35259243Sobrien} 35359243Sobrien 35459243Sobrienvoid 355167465Smpdoif(Char **v, struct command *kp) 35659243Sobrien{ 357145479Smp int i; 358145479Smp Char **vv; 35959243Sobrien 36059243Sobrien v++; 361167465Smp i = noexec ? 1 : expr(&v); 36259243Sobrien vv = v; 36359243Sobrien if (*vv == NULL) 36459243Sobrien stderror(ERR_NAME | ERR_EMPTYIF); 36559243Sobrien if (eq(*vv, STRthen)) { 36659243Sobrien if (*++vv) 36759243Sobrien stderror(ERR_NAME | ERR_IMPRTHEN); 36859243Sobrien setname(short2str(STRthen)); 36959243Sobrien /* 37059243Sobrien * If expression was zero, then scan to else , otherwise just fall into 37159243Sobrien * following code. 37259243Sobrien */ 37359243Sobrien if (!i) 37459243Sobrien search(TC_IF, 0, NULL); 37559243Sobrien return; 37659243Sobrien } 37759243Sobrien /* 37859243Sobrien * Simple command attached to this if. Left shift the node in this tree, 37959243Sobrien * munging it so we can reexecute it. 38059243Sobrien */ 38159243Sobrien if (i) { 38259243Sobrien lshift(kp->t_dcom, vv - kp->t_dcom); 38359243Sobrien reexecute(kp); 38459243Sobrien donefds(); 38559243Sobrien } 38659243Sobrien} 38759243Sobrien 38859243Sobrien/* 38959243Sobrien * Reexecute a command, being careful not 39059243Sobrien * to redo i/o redirection, which is already set up. 39159243Sobrien */ 39259243Sobrienvoid 393167465Smpreexecute(struct command *kp) 39459243Sobrien{ 39559243Sobrien kp->t_dflg &= F_SAVE; 39659243Sobrien kp->t_dflg |= F_REPEAT; 39759243Sobrien /* 39859243Sobrien * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set 39959243Sobrien * pgrp's as the jobs would then have no way to get the tty (we can't give 40059243Sobrien * it to them, and our parent wouldn't know their pgrp, etc. 40159243Sobrien */ 402100616Smp execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL, TRUE); 40359243Sobrien} 40459243Sobrien 40559243Sobrien/*ARGSUSED*/ 40659243Sobrienvoid 407167465Smpdoelse (Char **v, struct command *c) 40859243Sobrien{ 40959243Sobrien USE(c); 41059243Sobrien USE(v); 411167465Smp if (!noexec) 412167465Smp search(TC_ELSE, 0, NULL); 41359243Sobrien} 41459243Sobrien 41559243Sobrien/*ARGSUSED*/ 41659243Sobrienvoid 417167465Smpdogoto(Char **v, struct command *c) 41859243Sobrien{ 41959243Sobrien Char *lp; 42059243Sobrien 42159243Sobrien USE(c); 422167465Smp lp = globone(v[1], G_ERROR); 423167465Smp cleanup_push(lp, xfree); 424167465Smp if (!noexec) 425167465Smp gotolab(lp); 426167465Smp cleanup_until(lp); 42759243Sobrien} 42859243Sobrien 42959243Sobrienvoid 430167465Smpgotolab(Char *lab) 43159243Sobrien{ 432145479Smp struct whyle *wp; 43359243Sobrien /* 43459243Sobrien * While we still can, locate any unknown ends of existing loops. This 43559243Sobrien * obscure code is the WORST result of the fact that we don't really parse. 43659243Sobrien */ 43759243Sobrien zlast = TC_GOTO; 43859243Sobrien for (wp = whyles; wp; wp = wp->w_next) 43969408Sache if (wp->w_end.type == TCSH_F_SEEK && wp->w_end.f_seek == 0) { 44059243Sobrien search(TC_BREAK, 0, NULL); 44159243Sobrien btell(&wp->w_end); 44259243Sobrien } 44359243Sobrien else { 44459243Sobrien bseek(&wp->w_end); 44559243Sobrien } 44659243Sobrien search(TC_GOTO, 0, lab); 44759243Sobrien /* 44859243Sobrien * Eliminate loops which were exited. 44959243Sobrien */ 45059243Sobrien wfree(); 45159243Sobrien} 45259243Sobrien 45359243Sobrien/*ARGSUSED*/ 45459243Sobrienvoid 455167465Smpdoswitch(Char **v, struct command *c) 45659243Sobrien{ 457145479Smp Char *cp, *lp; 45859243Sobrien 45959243Sobrien USE(c); 46059243Sobrien v++; 46159243Sobrien if (!*v || *(*v++) != '(') 46259243Sobrien stderror(ERR_SYNTAX); 46359243Sobrien cp = **v == ')' ? STRNULL : *v++; 46459243Sobrien if (*(*v++) != ')') 46559243Sobrien v--; 46659243Sobrien if (*v) 46759243Sobrien stderror(ERR_SYNTAX); 468167465Smp lp = globone(cp, G_ERROR); 469167465Smp cleanup_push(lp, xfree); 470167465Smp if (!noexec) 471167465Smp search(TC_SWITCH, 0, lp); 472167465Smp cleanup_until(lp); 47359243Sobrien} 47459243Sobrien 47559243Sobrien/*ARGSUSED*/ 47659243Sobrienvoid 477167465Smpdobreak(Char **v, struct command *c) 47859243Sobrien{ 47959243Sobrien USE(v); 48059243Sobrien USE(c); 481167465Smp if (whyles == NULL) 482167465Smp stderror(ERR_NAME | ERR_NOTWHILE); 483167465Smp if (!noexec) 48459243Sobrien toend(); 48559243Sobrien} 48659243Sobrien 48759243Sobrien/*ARGSUSED*/ 48859243Sobrienvoid 489167465Smpdoexit(Char **v, struct command *c) 49059243Sobrien{ 49159243Sobrien USE(c); 49259243Sobrien 49359243Sobrien if (chkstop == 0 && (intty || intact) && evalvec == 0) 49459243Sobrien panystop(0); 49559243Sobrien /* 49659243Sobrien * Don't DEMAND parentheses here either. 49759243Sobrien */ 49859243Sobrien v++; 49959243Sobrien if (*v) { 500167465Smp setv(STRstatus, putn(expr(&v)), VAR_READWRITE); 50159243Sobrien if (*v) 50259243Sobrien stderror(ERR_NAME | ERR_EXPRESSION); 50359243Sobrien } 50459243Sobrien btoeof(); 50559243Sobrien#if 0 50659243Sobrien if (intty) 50759243Sobrien#endif 50859243Sobrien /* Always close, why only on ttys? */ 509167465Smp xclose(SHIN); 51059243Sobrien} 51159243Sobrien 51259243Sobrien/*ARGSUSED*/ 51359243Sobrienvoid 514167465Smpdoforeach(Char **v, struct command *c) 51559243Sobrien{ 516145479Smp Char *cp, *sp; 517145479Smp struct whyle *nwp; 518167465Smp int gflag; 51959243Sobrien 52059243Sobrien USE(c); 52159243Sobrien v++; 522231990Smp cp = sp = strip(*v); 523231990Smp if (!letter(*cp)) 52459243Sobrien stderror(ERR_NAME | ERR_VARBEGIN); 525231990Smp do { 52659243Sobrien cp++; 527231990Smp } while (alnum(*cp)); 528231990Smp if (*cp != '\0') 52959243Sobrien stderror(ERR_NAME | ERR_VARALNUM); 53059243Sobrien cp = *v++; 53159243Sobrien if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') 53259243Sobrien stderror(ERR_NAME | ERR_NOPAREN); 53359243Sobrien v++; 534167465Smp gflag = tglob(v); 53559243Sobrien if (gflag) { 536167465Smp v = globall(v, gflag); 537167465Smp if (v == 0 && !noexec) 53859243Sobrien stderror(ERR_NAME | ERR_NOMATCH); 53959243Sobrien } 54059243Sobrien else { 541167465Smp v = saveblk(v); 54259243Sobrien trim(v); 54359243Sobrien } 544167465Smp nwp = xcalloc(1, sizeof *nwp); 54559243Sobrien nwp->w_fe = nwp->w_fe0 = v; 54659243Sobrien btell(&nwp->w_start); 54759243Sobrien nwp->w_fename = Strsave(cp); 54859243Sobrien nwp->w_next = whyles; 54969408Sache nwp->w_end.type = TCSH_F_SEEK; 55059243Sobrien whyles = nwp; 55159243Sobrien /* 55259243Sobrien * Pre-read the loop so as to be more comprehensible to a terminal user. 55359243Sobrien */ 55459243Sobrien zlast = TC_FOREACH; 55559243Sobrien if (intty) 55659243Sobrien preread(); 557167465Smp if (!noexec) 558167465Smp doagain(); 55959243Sobrien} 56059243Sobrien 56159243Sobrien/*ARGSUSED*/ 56259243Sobrienvoid 563167465Smpdowhile(Char **v, struct command *c) 56459243Sobrien{ 565145479Smp int status; 566145479Smp int again = whyles != 0 && 56759243Sobrien SEEKEQ(&whyles->w_start, &lineloc) && 56859243Sobrien whyles->w_fename == 0; 56959243Sobrien 57059243Sobrien USE(c); 57159243Sobrien v++; 57259243Sobrien /* 57359243Sobrien * Implement prereading here also, taking care not to evaluate the 57459243Sobrien * expression before the loop has been read up from a terminal. 57559243Sobrien */ 576167465Smp if (noexec) 577167465Smp status = 0; 578167465Smp else if (intty && !again) 57959243Sobrien status = !exp0(&v, 1); 58059243Sobrien else 58159243Sobrien status = !expr(&v); 582167465Smp if (*v && !noexec) 58359243Sobrien stderror(ERR_NAME | ERR_EXPRESSION); 58459243Sobrien if (!again) { 585167465Smp struct whyle *nwp = xcalloc(1, sizeof(*nwp)); 58659243Sobrien 58759243Sobrien nwp->w_start = lineloc; 58869408Sache nwp->w_end.type = TCSH_F_SEEK; 58959243Sobrien nwp->w_end.f_seek = 0; 590231990Smp nwp->w_end.a_seek = 0; 59159243Sobrien nwp->w_next = whyles; 59259243Sobrien whyles = nwp; 59359243Sobrien zlast = TC_WHILE; 59459243Sobrien if (intty) { 59559243Sobrien /* 59659243Sobrien * The tty preread 59759243Sobrien */ 59859243Sobrien preread(); 59959243Sobrien doagain(); 60059243Sobrien return; 60159243Sobrien } 60259243Sobrien } 60359243Sobrien if (status) 60459243Sobrien /* We ain't gonna loop no more, no more! */ 60559243Sobrien toend(); 60659243Sobrien} 60759243Sobrien 60859243Sobrienstatic void 609167465Smppreread(void) 61059243Sobrien{ 611167465Smp int old_pintr_disabled; 612167465Smp 61369408Sache whyles->w_end.type = TCSH_I_SEEK; 61459243Sobrien if (setintr) 615167465Smp pintr_push_enable(&old_pintr_disabled); 61659243Sobrien search(TC_BREAK, 0, NULL); /* read the expression in */ 61759243Sobrien if (setintr) 618167465Smp cleanup_until(&old_pintr_disabled); 61959243Sobrien btell(&whyles->w_end); 62059243Sobrien} 62159243Sobrien 62259243Sobrien/*ARGSUSED*/ 62359243Sobrienvoid 624167465Smpdoend(Char **v, struct command *c) 62559243Sobrien{ 62659243Sobrien USE(v); 62759243Sobrien USE(c); 62859243Sobrien if (!whyles) 62959243Sobrien stderror(ERR_NAME | ERR_NOTWHILE); 63059243Sobrien btell(&whyles->w_end); 631167465Smp if (!noexec) 632167465Smp doagain(); 63359243Sobrien} 63459243Sobrien 63559243Sobrien/*ARGSUSED*/ 63659243Sobrienvoid 637167465Smpdocontin(Char **v, struct command *c) 63859243Sobrien{ 63959243Sobrien USE(v); 64059243Sobrien USE(c); 64159243Sobrien if (!whyles) 64259243Sobrien stderror(ERR_NAME | ERR_NOTWHILE); 643167465Smp if (!noexec) 644167465Smp doagain(); 64559243Sobrien} 64659243Sobrien 64759243Sobrienstatic void 648167465Smpdoagain(void) 64959243Sobrien{ 65059243Sobrien /* Repeating a while is simple */ 65159243Sobrien if (whyles->w_fename == 0) { 65259243Sobrien bseek(&whyles->w_start); 65359243Sobrien return; 65459243Sobrien } 65559243Sobrien /* 65659243Sobrien * The foreach variable list actually has a spurious word ")" at the end of 65759243Sobrien * the w_fe list. Thus we are at the of the list if one word beyond this 65859243Sobrien * is 0. 65959243Sobrien */ 66059243Sobrien if (!whyles->w_fe[1]) { 66159243Sobrien dobreak(NULL, NULL); 66259243Sobrien return; 66359243Sobrien } 664167465Smp setv(whyles->w_fename, quote(Strsave(*whyles->w_fe++)), VAR_READWRITE); 66559243Sobrien bseek(&whyles->w_start); 66659243Sobrien} 66759243Sobrien 66859243Sobrienvoid 669167465Smpdorepeat(Char **v, struct command *kp) 67059243Sobrien{ 671100616Smp int i = 1; 67259243Sobrien 673100616Smp do { 674100616Smp i *= getn(v[1]); 675100616Smp lshift(v, 2); 676100616Smp } while (v[0] != NULL && Strcmp(v[0], STRrepeat) == 0); 677167465Smp if (noexec) 678167465Smp i = 1; 679100616Smp 680167465Smp if (setintr) { 681167465Smp pintr_disabled++; 682167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 683167465Smp } 68459243Sobrien while (i > 0) { 685167465Smp if (setintr && pintr_disabled == 1) { 686167465Smp cleanup_until(&pintr_disabled); 687167465Smp pintr_disabled++; 688167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 689167465Smp } 69059243Sobrien reexecute(kp); 69159243Sobrien --i; 69259243Sobrien } 693195609Smp if (setintr && pintr_disabled == 1) 694195609Smp cleanup_until(&pintr_disabled); 69559243Sobrien donefds(); 69659243Sobrien} 69759243Sobrien 69859243Sobrien/*ARGSUSED*/ 69959243Sobrienvoid 700167465Smpdoswbrk(Char **v, struct command *c) 70159243Sobrien{ 70259243Sobrien USE(v); 70359243Sobrien USE(c); 704167465Smp if (!noexec) 705167465Smp search(TC_BRKSW, 0, NULL); 70659243Sobrien} 70759243Sobrien 70859243Sobrienint 709167465Smpsrchx(Char *cp) 71059243Sobrien{ 71159243Sobrien struct srch *sp, *sp1, *sp2; 71259243Sobrien int i; 71359243Sobrien 71459243Sobrien /* 71559243Sobrien * Ignore keywords inside heredocs 71659243Sobrien */ 71759243Sobrien if (inheredoc) 71859243Sobrien return -1; 71959243Sobrien 72059243Sobrien /* 72159243Sobrien * Binary search Sp1 is the beginning of the current search range. Sp2 is 72259243Sobrien * one past the end. 72359243Sobrien */ 72459243Sobrien for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) { 72559243Sobrien sp = sp1 + ((sp2 - sp1) >> 1); 72659243Sobrien if ((i = *cp - *sp->s_name) == 0 && 72759243Sobrien (i = Strcmp(cp, str2short(sp->s_name))) == 0) 72859243Sobrien return sp->s_value; 72959243Sobrien if (i < 0) 73059243Sobrien sp2 = sp; 73159243Sobrien else 73259243Sobrien sp1 = sp + 1; 73359243Sobrien } 73459243Sobrien return (-1); 73559243Sobrien} 73659243Sobrien 737145479Smpstatic const char * 738167465Smpisrchx(int n) 73959243Sobrien{ 740145479Smp struct srch *sp, *sp2; 74159243Sobrien 74259243Sobrien for (sp = srchn, sp2 = srchn + nsrchn; sp < sp2; sp++) 74359243Sobrien if (sp->s_value == n) 74459243Sobrien return (sp->s_name); 74559243Sobrien return (""); 74659243Sobrien} 74759243Sobrien 74859243Sobrien 749167465Smpstatic int Stype; 75059243Sobrienstatic Char *Sgoal; 75159243Sobrien 75259243Sobrienstatic void 753167465Smpsearch(int type, int level, Char *goal) 75459243Sobrien{ 755167465Smp struct Strbuf word = Strbuf_INIT; 756145479Smp Char *cp; 757131962Smp struct whyle *wp; 758131962Smp int wlevel = 0; 759195609Smp struct wordent *histent = NULL, *ohistent = NULL; 76059243Sobrien 761167465Smp Stype = type; 76259243Sobrien Sgoal = goal; 76359243Sobrien if (type == TC_GOTO) { 76459243Sobrien struct Ain a; 76569408Sache a.type = TCSH_F_SEEK; 76659243Sobrien a.f_seek = 0; 767231990Smp a.a_seek = 0; 76859243Sobrien bseek(&a); 76959243Sobrien } 770167465Smp cleanup_push(&word, Strbuf_cleanup); 77159243Sobrien do { 772195609Smp 773195609Smp if (intty) { 774195609Smp histent = xmalloc(sizeof(*histent)); 775195609Smp ohistent = xmalloc(sizeof(*histent)); 776195609Smp ohistent->word = STRNULL; 777195609Smp ohistent->next = histent; 778195609Smp histent->prev = ohistent; 779195609Smp } 780195609Smp 78169408Sache if (intty && fseekp == feobp && aret == TCSH_F_SEEK) 78259243Sobrien printprompt(1, isrchx(type == TC_BREAK ? zlast : type)); 78359243Sobrien /* xprintf("? "), flush(); */ 784167465Smp (void) getword(&word); 785167465Smp Strbuf_terminate(&word); 786195609Smp 787195609Smp if (intty && Strlen(word.s) > 0) { 788195609Smp histent->word = Strsave(word.s); 789195609Smp histent->next = xmalloc(sizeof(*histent)); 790195609Smp histent->next->prev = histent; 791195609Smp histent = histent->next; 792195609Smp } 793195609Smp 794167465Smp switch (srchx(word.s)) { 79559243Sobrien 79659243Sobrien case TC_ELSE: 79759243Sobrien if (level == 0 && type == TC_IF) 798167465Smp goto end; 79959243Sobrien break; 80059243Sobrien 80159243Sobrien case TC_IF: 802316958Sdchagin while (getword(&word)) { 803316958Sdchagin if (intty) { 804316958Sdchagin histent->word = Strsave(word.s); 805316958Sdchagin histent->next = xmalloc(sizeof(*histent)); 806316958Sdchagin histent->next->prev = histent; 807316958Sdchagin histent = histent->next; 808316958Sdchagin } 80959243Sobrien continue; 810316958Sdchagin } 811316958Sdchagin 81259243Sobrien if ((type == TC_IF || type == TC_ELSE) && 813167465Smp eq(word.s, STRthen)) 81459243Sobrien level++; 81559243Sobrien break; 81659243Sobrien 81759243Sobrien case TC_ENDIF: 81859243Sobrien if (type == TC_IF || type == TC_ELSE) 81959243Sobrien level--; 82059243Sobrien break; 82159243Sobrien 82259243Sobrien case TC_FOREACH: 82359243Sobrien case TC_WHILE: 824131962Smp wlevel++; 82559243Sobrien if (type == TC_BREAK) 82659243Sobrien level++; 82759243Sobrien break; 82859243Sobrien 82959243Sobrien case TC_END: 830131962Smp if (type == TC_BRKSW) { 831131962Smp if (wlevel == 0) { 832131962Smp wp = whyles; 833131962Smp if (wp) { 834131962Smp whyles = wp->w_next; 835131962Smp wpfree(wp); 836131962Smp } 837131962Smp } 838131962Smp } 83959243Sobrien if (type == TC_BREAK) 84059243Sobrien level--; 841131962Smp wlevel--; 84259243Sobrien break; 84359243Sobrien 84459243Sobrien case TC_SWITCH: 84559243Sobrien if (type == TC_SWITCH || type == TC_BRKSW) 84659243Sobrien level++; 84759243Sobrien break; 84859243Sobrien 84959243Sobrien case TC_ENDSW: 85059243Sobrien if (type == TC_SWITCH || type == TC_BRKSW) 85159243Sobrien level--; 85259243Sobrien break; 85359243Sobrien 85459243Sobrien case TC_LABEL: 855167465Smp if (type == TC_GOTO && getword(&word) && eq(word.s, goal)) 85659243Sobrien level = -1; 85759243Sobrien break; 85859243Sobrien 85959243Sobrien default: 86059243Sobrien if (type != TC_GOTO && (type != TC_SWITCH || level != 0)) 86159243Sobrien break; 862167465Smp if (word.len == 0 || word.s[word.len - 1] != ':') 86359243Sobrien break; 864167465Smp word.s[--word.len] = 0; 865167465Smp if ((type == TC_GOTO && eq(word.s, goal)) || 866167465Smp (type == TC_SWITCH && eq(word.s, STRdefault))) 86759243Sobrien level = -1; 86859243Sobrien break; 86959243Sobrien 87059243Sobrien case TC_CASE: 87159243Sobrien if (type != TC_SWITCH || level != 0) 87259243Sobrien break; 873167465Smp (void) getword(&word); 874167465Smp if (word.len != 0 && word.s[word.len - 1] == ':') 875167465Smp word.s[--word.len] = 0; 876167465Smp cp = strip(Dfix1(word.s)); 877167465Smp cleanup_push(cp, xfree); 87859243Sobrien if (Gmatch(goal, cp)) 87959243Sobrien level = -1; 880167465Smp cleanup_until(cp); 88159243Sobrien break; 88259243Sobrien 88359243Sobrien case TC_DEFAULT: 88459243Sobrien if (type == TC_SWITCH && level == 0) 88559243Sobrien level = -1; 88659243Sobrien break; 88759243Sobrien } 888195609Smp if (intty) { 889195609Smp ohistent->prev = histgetword(histent); 890195609Smp ohistent->prev->next = ohistent; 891195609Smp savehist(ohistent, 0); 892195609Smp freelex(ohistent); 893195609Smp xfree(ohistent); 894195609Smp } else 895195609Smp (void) getword(NULL); 89659243Sobrien } while (level >= 0); 897167465Smp end: 898167465Smp cleanup_until(&word); 89959243Sobrien} 90059243Sobrien 901195609Smpstatic struct wordent * 902195609Smphistgetword(struct wordent *histent) 903195609Smp{ 904316958Sdchagin int first; 905195609Smp eChar c, d; 906195609Smp int e; 907195609Smp struct Strbuf *tmp; 908195609Smp tmp = xmalloc(sizeof(*tmp)); 909195609Smp tmp->size = 0; 910195609Smp tmp->s = NULL; 911195609Smp c = readc(1); 912195609Smp d = 0; 913195609Smp e = 0; 914195609Smp for (;;) { 915195609Smp tmp->len = 0; 916195609Smp Strbuf_terminate (tmp); 917195609Smp while (c == ' ' || c == '\t') 918195609Smp c = readc(1); 919195609Smp if (c == '#') 920195609Smp do 921195609Smp c = readc(1); 922195609Smp while (c != CHAR_ERR && c != '\n'); 923195609Smp if (c == CHAR_ERR) 924195609Smp goto past; 925195609Smp if (c == '\n') 926195609Smp goto nl; 927195609Smp unreadc(c); 928195609Smp first = 1; 929195609Smp do { 930195609Smp e = (c == '\\'); 931195609Smp c = readc(1); 932195609Smp if (c == '\\' && !e) { 933195609Smp if ((c = readc(1)) == '\n') { 934195609Smp e = 1; 935195609Smp c = ' '; 936195609Smp } else { 937195609Smp unreadc(c); 938195609Smp c = '\\'; 939195609Smp } 940195609Smp } 941195609Smp if ((c == '\'' || c == '"') && !e) { 942195609Smp if (d == 0) 943195609Smp d = c; 944195609Smp else if (d == c) 945195609Smp d = 0; 946195609Smp } 947195609Smp if (c == CHAR_ERR) 948195609Smp goto past; 949195609Smp 950195609Smp Strbuf_append1(tmp, (Char) c); 951195609Smp 952195609Smp if (!first && !d && c == '(' && !e) { 953195609Smp break; 954195609Smp } 955195609Smp first = 0; 956195609Smp } while (d || e || (c != ' ' && c != '\t' && c != '\n')); 957195609Smp tmp->len--; 958195609Smp if (tmp->len) { 959195609Smp Strbuf_terminate(tmp); 960195609Smp histent->word = Strsave(tmp->s); 961195609Smp histent->next = xmalloc(sizeof (*histent)); 962195609Smp histent->next->prev = histent; 963195609Smp histent = histent->next; 964195609Smp } 965195609Smp if (c == '\n') { 966195609Smp nl: 967195609Smp tmp->len = 0; 968195609Smp Strbuf_append1(tmp, (Char) c); 969195609Smp Strbuf_terminate(tmp); 970195609Smp histent->word = Strsave(tmp->s); 971195609Smp return histent; 972195609Smp } 973195609Smp } 974195609Smp 975195609Smppast: 976195609Smp switch (Stype) { 977195609Smp 978195609Smp case TC_IF: 979195609Smp stderror(ERR_NAME | ERR_NOTFOUND, "then/endif"); 980195609Smp break; 981195609Smp 982195609Smp case TC_ELSE: 983195609Smp stderror(ERR_NAME | ERR_NOTFOUND, "endif"); 984195609Smp break; 985195609Smp 986195609Smp case TC_BRKSW: 987195609Smp case TC_SWITCH: 988195609Smp stderror(ERR_NAME | ERR_NOTFOUND, "endsw"); 989195609Smp break; 990195609Smp 991195609Smp case TC_BREAK: 992195609Smp stderror(ERR_NAME | ERR_NOTFOUND, "end"); 993195609Smp break; 994195609Smp 995195609Smp case TC_GOTO: 996195609Smp setname(short2str(Sgoal)); 997195609Smp stderror(ERR_NAME | ERR_NOTFOUND, "label"); 998195609Smp break; 999195609Smp 1000195609Smp default: 1001195609Smp break; 1002195609Smp } 1003195609Smp /* NOTREACHED */ 1004195609Smp return NULL; 1005195609Smp} 1006195609Smp 100759243Sobrienstatic int 1008167465Smpgetword(struct Strbuf *wp) 100959243Sobrien{ 101059243Sobrien int found = 0, first; 1011145479Smp eChar c, d; 101259243Sobrien 1013167465Smp if (wp) 1014167465Smp wp->len = 0; 101559243Sobrien c = readc(1); 101659243Sobrien d = 0; 101759243Sobrien do { 101859243Sobrien while (c == ' ' || c == '\t') 101959243Sobrien c = readc(1); 102059243Sobrien if (c == '#') 102159243Sobrien do 102259243Sobrien c = readc(1); 1023145479Smp while (c != CHAR_ERR && c != '\n'); 1024145479Smp if (c == CHAR_ERR) 102559243Sobrien goto past; 102659243Sobrien if (c == '\n') { 102759243Sobrien if (wp) 102859243Sobrien break; 102959243Sobrien return (0); 103059243Sobrien } 103159243Sobrien unreadc(c); 103259243Sobrien found = 1; 103359243Sobrien first = 1; 103459243Sobrien do { 103559243Sobrien c = readc(1); 103659243Sobrien if (c == '\\' && (c = readc(1)) == '\n') 103759243Sobrien c = ' '; 103859243Sobrien if (c == '\'' || c == '"') { 103959243Sobrien if (d == 0) 104059243Sobrien d = c; 104159243Sobrien else if (d == c) 104259243Sobrien d = 0; 104359243Sobrien } 1044145479Smp if (c == CHAR_ERR) 104559243Sobrien goto past; 1046167465Smp if (wp) 1047167465Smp Strbuf_append1(wp, (Char) c); 1048316958Sdchagin if (!d && c == ')') { 1049316958Sdchagin if (!first && wp) { 1050316958Sdchagin goto past_word_end; 1051316958Sdchagin } else { 1052316958Sdchagin if (wp) { 1053316958Sdchagin wp->len = 1; 1054316958Sdchagin Strbuf_terminate(wp); 1055316958Sdchagin } 1056316958Sdchagin return found; 1057316958Sdchagin } 1058316958Sdchagin } 105959243Sobrien if (!first && !d && c == '(') { 1060167465Smp if (wp) 1061167465Smp goto past_word_end; 106259243Sobrien else 106359243Sobrien break; 106459243Sobrien } 106559243Sobrien first = 0; 106659243Sobrien } while ((d || (c != ' ' && c != '\t')) && c != '\n'); 106759243Sobrien } while (wp == 0); 106859243Sobrien 1069167465Smp past_word_end: 107059243Sobrien unreadc(c); 1071167465Smp if (found) { 1072167465Smp wp->len--; 1073167465Smp Strbuf_terminate(wp); 1074167465Smp } 107559243Sobrien 107659243Sobrien return (found); 107759243Sobrien 107859243Sobrienpast: 107959243Sobrien switch (Stype) { 108059243Sobrien 108159243Sobrien case TC_IF: 108259243Sobrien stderror(ERR_NAME | ERR_NOTFOUND, "then/endif"); 108359243Sobrien break; 108459243Sobrien 108559243Sobrien case TC_ELSE: 108659243Sobrien stderror(ERR_NAME | ERR_NOTFOUND, "endif"); 108759243Sobrien break; 108859243Sobrien 108959243Sobrien case TC_BRKSW: 109059243Sobrien case TC_SWITCH: 109159243Sobrien stderror(ERR_NAME | ERR_NOTFOUND, "endsw"); 109259243Sobrien break; 109359243Sobrien 109459243Sobrien case TC_BREAK: 109559243Sobrien stderror(ERR_NAME | ERR_NOTFOUND, "end"); 109659243Sobrien break; 109759243Sobrien 109859243Sobrien case TC_GOTO: 109959243Sobrien setname(short2str(Sgoal)); 110059243Sobrien stderror(ERR_NAME | ERR_NOTFOUND, "label"); 110159243Sobrien break; 110259243Sobrien 110359243Sobrien default: 110459243Sobrien break; 110559243Sobrien } 110659243Sobrien /* NOTREACHED */ 110759243Sobrien return (0); 110859243Sobrien} 110959243Sobrien 111059243Sobrienstatic void 1111167465Smptoend(void) 111259243Sobrien{ 111369408Sache if (whyles->w_end.type == TCSH_F_SEEK && whyles->w_end.f_seek == 0) { 111459243Sobrien search(TC_BREAK, 0, NULL); 111559243Sobrien btell(&whyles->w_end); 111659243Sobrien whyles->w_end.f_seek--; 111759243Sobrien } 111859243Sobrien else { 111959243Sobrien bseek(&whyles->w_end); 112059243Sobrien } 112159243Sobrien wfree(); 112259243Sobrien} 112359243Sobrien 1124131962Smpstatic void 1125167465Smpwpfree(struct whyle *wp) 1126131962Smp{ 1127131962Smp if (wp->w_fe0) 1128131962Smp blkfree(wp->w_fe0); 1129167465Smp xfree(wp->w_fename); 1130167465Smp xfree(wp); 1131131962Smp} 1132131962Smp 113359243Sobrienvoid 1134167465Smpwfree(void) 113559243Sobrien{ 113659243Sobrien struct Ain o; 113759243Sobrien struct whyle *nwp; 113859243Sobrien#ifdef lint 113959243Sobrien nwp = NULL; /* sun lint is dumb! */ 114059243Sobrien#endif 114159243Sobrien 114259243Sobrien#ifdef FDEBUG 1143167465Smp static const char foo[] = "IAFE"; 114459243Sobrien#endif /* FDEBUG */ 114559243Sobrien 114659243Sobrien btell(&o); 114759243Sobrien 114859243Sobrien#ifdef FDEBUG 1149167465Smp xprintf("o->type %c o->a_seek %d o->f_seek %d\n", 115059243Sobrien foo[o.type + 1], o.a_seek, o.f_seek); 115159243Sobrien#endif /* FDEBUG */ 115259243Sobrien 115359243Sobrien for (; whyles; whyles = nwp) { 1154145479Smp struct whyle *wp = whyles; 115559243Sobrien nwp = wp->w_next; 115659243Sobrien 115759243Sobrien#ifdef FDEBUG 1158167465Smp xprintf("start->type %c start->a_seek %d start->f_seek %d\n", 115959243Sobrien foo[wp->w_start.type+1], 116059243Sobrien wp->w_start.a_seek, wp->w_start.f_seek); 1161167465Smp xprintf("end->type %c end->a_seek %d end->f_seek %d\n", 116259243Sobrien foo[wp->w_end.type + 1], wp->w_end.a_seek, wp->w_end.f_seek); 116359243Sobrien#endif /* FDEBUG */ 116459243Sobrien 116559243Sobrien /* 116659243Sobrien * XXX: We free loops that have different seek types. 116759243Sobrien */ 116869408Sache if (wp->w_end.type != TCSH_I_SEEK && wp->w_start.type == wp->w_end.type && 116959243Sobrien wp->w_start.type == o.type) { 117069408Sache if (wp->w_end.type == TCSH_F_SEEK) { 117159243Sobrien if (o.f_seek >= wp->w_start.f_seek && 117259243Sobrien (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek)) 117359243Sobrien break; 117459243Sobrien } 117559243Sobrien else { 117659243Sobrien if (o.a_seek >= wp->w_start.a_seek && 117759243Sobrien (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek)) 117859243Sobrien break; 117959243Sobrien } 118059243Sobrien } 118159243Sobrien 1182131962Smp wpfree(wp); 118359243Sobrien } 118459243Sobrien} 118559243Sobrien 118659243Sobrien/*ARGSUSED*/ 118759243Sobrienvoid 1188167465Smpdoecho(Char **v, struct command *c) 118959243Sobrien{ 119059243Sobrien USE(c); 119159243Sobrien xecho(' ', v); 119259243Sobrien} 119359243Sobrien 119459243Sobrien/*ARGSUSED*/ 119559243Sobrienvoid 1196167465Smpdoglob(Char **v, struct command *c) 119759243Sobrien{ 119859243Sobrien USE(c); 119959243Sobrien xecho(0, v); 120059243Sobrien flush(); 120159243Sobrien} 120259243Sobrien 120359243Sobrienstatic void 1204167465Smpxecho(int sep, Char **v) 120559243Sobrien{ 1206167465Smp Char *cp, **globbed = NULL; 120759243Sobrien int nonl = 0; 120859243Sobrien int echo_style = ECHO_STYLE; 120959243Sobrien struct varent *vp; 121059243Sobrien 121159243Sobrien if ((vp = adrof(STRecho_style)) != NULL && vp->vec != NULL && 121259243Sobrien vp->vec[0] != NULL) { 121359243Sobrien if (Strcmp(vp->vec[0], STRbsd) == 0) 121459243Sobrien echo_style = BSD_ECHO; 121559243Sobrien else if (Strcmp(vp->vec[0], STRsysv) == 0) 121659243Sobrien echo_style = SYSV_ECHO; 121759243Sobrien else if (Strcmp(vp->vec[0], STRboth) == 0) 121859243Sobrien echo_style = BOTH_ECHO; 121959243Sobrien else if (Strcmp(vp->vec[0], STRnone) == 0) 122059243Sobrien echo_style = NONE_ECHO; 122159243Sobrien } 122259243Sobrien 122359243Sobrien v++; 122459243Sobrien if (*v == 0) 122583098Smp goto done; 1226167465Smp if (setintr) { 1227167465Smp int old_pintr_disabled; 1228167465Smp pintr_push_enable(&old_pintr_disabled); 1229167465Smp v = glob_all_or_error(v); 1230167465Smp cleanup_until(&old_pintr_disabled); 1231167465Smp } else { 1232167465Smp v = glob_all_or_error(v); 123359243Sobrien } 1234167465Smp globbed = v; 1235167465Smp if (globbed != NULL) 1236167465Smp cleanup_push(globbed, blk_cleanup); 123759243Sobrien 123859243Sobrien if ((echo_style & BSD_ECHO) != 0 && sep == ' ' && *v && eq(*v, STRmn)) 123959243Sobrien nonl++, v++; 124059243Sobrien 124159243Sobrien while ((cp = *v++) != 0) { 1242145479Smp Char c; 124359243Sobrien 1244167465Smp if (setintr) { 1245167465Smp int old_pintr_disabled; 1246167465Smp 1247167465Smp pintr_push_enable(&old_pintr_disabled); 1248167465Smp cleanup_until(&old_pintr_disabled); 1249167465Smp } 125059243Sobrien while ((c = *cp++) != 0) { 125159243Sobrien if ((echo_style & SYSV_ECHO) != 0 && c == '\\') { 125259243Sobrien switch (c = *cp++) { 125359243Sobrien case 'a': 125459243Sobrien c = '\a'; 125559243Sobrien break; 125659243Sobrien case 'b': 125759243Sobrien c = '\b'; 125859243Sobrien break; 125959243Sobrien case 'c': 126059243Sobrien nonl = 1; 126159243Sobrien goto done; 126259243Sobrien case 'e': 126359243Sobrien#if 0 /* Windows does not understand \e */ 126459243Sobrien c = '\e'; 126559243Sobrien#else 1266167465Smp c = CTL_ESC('\033'); 126759243Sobrien#endif 126859243Sobrien break; 126959243Sobrien case 'f': 127059243Sobrien c = '\f'; 127159243Sobrien break; 127259243Sobrien case 'n': 127359243Sobrien c = '\n'; 127459243Sobrien break; 127559243Sobrien case 'r': 127659243Sobrien c = '\r'; 127759243Sobrien break; 127859243Sobrien case 't': 127959243Sobrien c = '\t'; 128059243Sobrien break; 128159243Sobrien case 'v': 128259243Sobrien c = '\v'; 128359243Sobrien break; 128459243Sobrien case '\\': 128559243Sobrien c = '\\'; 128659243Sobrien break; 128759243Sobrien case '0': 128859243Sobrien c = 0; 128959243Sobrien if (*cp >= '0' && *cp < '8') 129059243Sobrien c = c * 8 + *cp++ - '0'; 129159243Sobrien if (*cp >= '0' && *cp < '8') 129259243Sobrien c = c * 8 + *cp++ - '0'; 129359243Sobrien if (*cp >= '0' && *cp < '8') 129459243Sobrien c = c * 8 + *cp++ - '0'; 129559243Sobrien break; 129659243Sobrien case '\0': 129759243Sobrien c = '\\'; 129859243Sobrien cp--; 129959243Sobrien break; 130059243Sobrien default: 130159243Sobrien xputchar('\\' | QUOTE); 130259243Sobrien break; 130359243Sobrien } 130459243Sobrien } 1305145479Smp xputwchar(c | QUOTE); 130659243Sobrien 130759243Sobrien } 130859243Sobrien if (*v) 130959243Sobrien xputchar(sep | QUOTE); 131059243Sobrien } 131159243Sobriendone: 131259243Sobrien if (sep && nonl == 0) 131359243Sobrien xputchar('\n'); 131459243Sobrien else 131559243Sobrien flush(); 1316167465Smp if (globbed != NULL) 1317167465Smp cleanup_until(globbed); 131859243Sobrien} 131959243Sobrien 132059243Sobrien/* check whether an environment variable should invoke 'set_locale()' */ 1321145479Smpstatic int 1322167465Smpislocale_var(Char *var) 132359243Sobrien{ 132459243Sobrien static Char *locale_vars[] = { 1325131962Smp STRLANG, STRLC_ALL, STRLC_CTYPE, STRLC_NUMERIC, 1326131962Smp STRLC_TIME, STRLC_COLLATE, STRLC_MESSAGES, STRLC_MONETARY, 0 132759243Sobrien }; 1328145479Smp Char **v; 132959243Sobrien 133059243Sobrien for (v = locale_vars; *v; ++v) 133159243Sobrien if (eq(var, *v)) 133259243Sobrien return 1; 133359243Sobrien return 0; 133459243Sobrien} 133559243Sobrien 1336167465Smpstatic void 1337167465Smpxlate_cr_cleanup(void *dummy) 1338167465Smp{ 1339167465Smp USE(dummy); 1340167465Smp xlate_cr = 0; 1341167465Smp} 1342167465Smp 134359243Sobrien/*ARGSUSED*/ 134459243Sobrienvoid 1345167465Smpdoprintenv(Char **v, struct command *c) 134659243Sobrien{ 134759243Sobrien Char *e; 134859243Sobrien 134959243Sobrien USE(c); 135059243Sobrien v++; 135159243Sobrien if (*v == 0) { 1352145479Smp Char **ep; 135359243Sobrien 135459243Sobrien xlate_cr = 1; 1355167465Smp cleanup_push(&xlate_cr, xlate_cr_cleanup); 1356167465Smp for (ep = STR_environ; *ep; ep++) { 1357167465Smp if (setintr) { 1358167465Smp int old_pintr_disabled; 1359167465Smp 1360167465Smp pintr_push_enable(&old_pintr_disabled); 1361167465Smp cleanup_until(&old_pintr_disabled); 1362167465Smp } 136359243Sobrien xprintf("%S\n", *ep); 1364167465Smp } 1365167465Smp cleanup_until(&xlate_cr); 136659243Sobrien } 136759243Sobrien else if ((e = tgetenv(*v)) != NULL) { 1368167465Smp int old_output_raw; 1369167465Smp 1370167465Smp old_output_raw = output_raw; 137159243Sobrien output_raw = 1; 1372167465Smp cleanup_push(&old_output_raw, output_raw_restore); 137359243Sobrien xprintf("%S\n", e); 1374167465Smp cleanup_until(&old_output_raw); 137559243Sobrien } 137659243Sobrien else 1377167465Smp setcopy(STRstatus, STR1, VAR_READWRITE); 137859243Sobrien} 137959243Sobrien 138059243Sobrien/* from "Karl Berry." <karl%mote.umb.edu@relay.cs.net> -- for NeXT things 138159243Sobrien (and anything else with a modern compiler) */ 138259243Sobrien 138359243Sobrien/*ARGSUSED*/ 138459243Sobrienvoid 1385167465Smpdosetenv(Char **v, struct command *c) 138659243Sobrien{ 138759243Sobrien Char *vp, *lp; 138859243Sobrien 138959243Sobrien USE(c); 139059243Sobrien if (*++v == 0) { 139159243Sobrien doprintenv(--v, 0); 139259243Sobrien return; 139359243Sobrien } 139459243Sobrien 139559243Sobrien vp = *v++; 1396231990Smp lp = vp; 139759243Sobrien 1398231990Smp if (!letter(*lp)) 1399231990Smp stderror(ERR_NAME | ERR_VARBEGIN); 1400231990Smp do { 1401231990Smp lp++; 1402316958Sdchagin } while (alnum(*lp) || *lp == '.'); 1403231990Smp if (*lp != '\0') 1404231990Smp stderror(ERR_NAME | ERR_VARALNUM); 1405231990Smp 140659243Sobrien if ((lp = *v++) == 0) 140759243Sobrien lp = STRNULL; 140859243Sobrien 1409167465Smp lp = globone(lp, G_APPEND); 1410167465Smp cleanup_push(lp, xfree); 1411167465Smp tsetenv(vp, lp); 141259243Sobrien if (eq(vp, STRKPATH)) { 1413167465Smp importpath(lp); 141459243Sobrien dohash(NULL, NULL); 1415167465Smp cleanup_until(lp); 141659243Sobrien return; 141759243Sobrien } 141859243Sobrien 141959243Sobrien#ifdef apollo 142059243Sobrien if (eq(vp, STRSYSTYPE)) { 142159243Sobrien dohash(NULL, NULL); 1422167465Smp cleanup_until(lp); 142359243Sobrien return; 142459243Sobrien } 142559243Sobrien#endif /* apollo */ 142659243Sobrien 142759243Sobrien /* dspkanji/dspmbyte autosetting */ 142859243Sobrien /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */ 142959243Sobrien#if defined(DSPMBYTE) 143059243Sobrien if(eq(vp, STRLANG) && !adrof(CHECK_MBYTEVAR)) { 143159243Sobrien autoset_dspmbyte(lp); 143259243Sobrien } 143359243Sobrien#endif 143459243Sobrien 143559243Sobrien if (islocale_var(vp)) { 143659243Sobrien#ifdef NLS 143759243Sobrien int k; 143859243Sobrien 143959243Sobrien# ifdef SETLOCALEBUG 144059243Sobrien dont_free = 1; 144159243Sobrien# endif /* SETLOCALEBUG */ 144259243Sobrien (void) setlocale(LC_ALL, ""); 144359243Sobrien# ifdef LC_COLLATE 144459243Sobrien (void) setlocale(LC_COLLATE, ""); 144559243Sobrien# endif 1446145479Smp# ifdef LC_CTYPE 1447145479Smp (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 1448145479Smp# endif /* LC_CTYPE */ 1449231990Smp# if defined(AUTOSET_KANJI) 1450231990Smp autoset_kanji(); 1451231990Smp# endif /* AUTOSET_KANJI */ 145259243Sobrien# ifdef NLS_CATALOGS 145359243Sobrien# ifdef LC_MESSAGES 145459243Sobrien (void) setlocale(LC_MESSAGES, ""); 145559243Sobrien# endif /* LC_MESSAGES */ 1456145479Smp nlsclose(); 145759243Sobrien nlsinit(); 145859243Sobrien# endif /* NLS_CATALOGS */ 145959243Sobrien# ifdef SETLOCALEBUG 146059243Sobrien dont_free = 0; 146159243Sobrien# endif /* SETLOCALEBUG */ 146259243Sobrien# ifdef STRCOLLBUG 146359243Sobrien fix_strcoll_bug(); 146459243Sobrien# endif /* STRCOLLBUG */ 146559243Sobrien tw_cmd_free(); /* since the collation sequence has changed */ 1466167465Smp for (k = 0200; k <= 0377 && !Isprint(CTL_ESC(k)); k++) 146759243Sobrien continue; 1468145479Smp AsciiOnly = MB_CUR_MAX == 1 && k > 0377; 146959243Sobrien#else /* !NLS */ 147059243Sobrien AsciiOnly = 0; 147159243Sobrien#endif /* NLS */ 147259243Sobrien NLSMapsAreInited = 0; 147359243Sobrien ed_Init(); 147459243Sobrien if (MapsAreInited && !NLSMapsAreInited) 147559243Sobrien ed_InitNLSMaps(); 1476167465Smp cleanup_until(lp); 147759243Sobrien return; 147859243Sobrien } 147959243Sobrien 1480100616Smp#ifdef NLS_CATALOGS 1481100616Smp if (eq(vp, STRNLSPATH)) { 1482145479Smp nlsclose(); 1483100616Smp nlsinit(); 1484100616Smp } 1485100616Smp#endif 1486100616Smp 148759243Sobrien if (eq(vp, STRNOREBIND)) { 148859243Sobrien NoNLSRebind = 1; 148959243Sobrien MapsAreInited = 0; 149059243Sobrien NLSMapsAreInited = 0; 149159243Sobrien ed_InitMaps(); 1492167465Smp cleanup_until(lp); 149359243Sobrien return; 149459243Sobrien } 149569408Sache#ifdef WINNT_NATIVE 149659243Sobrien if (eq(vp, STRtcshlang)) { 149759243Sobrien nlsinit(); 1498167465Smp cleanup_until(lp); 149959243Sobrien return; 150059243Sobrien } 150169408Sache#endif /* WINNT_NATIVE */ 150259243Sobrien if (eq(vp, STRKTERM)) { 150359243Sobrien char *t; 1504167465Smp 1505167465Smp setv(STRterm, quote(lp), VAR_READWRITE); /* lp memory used here */ 1506167465Smp cleanup_ignore(lp); 1507167465Smp cleanup_until(lp); 150859243Sobrien t = short2str(lp); 150959243Sobrien if (noediting && strcmp(t, "unknown") != 0 && strcmp(t,"dumb") != 0) { 151059243Sobrien editing = 1; 151159243Sobrien noediting = 0; 1512167465Smp setNS(STRedit); 151359243Sobrien } 151459243Sobrien GotTermCaps = 0; 151559243Sobrien ed_Init(); 151659243Sobrien return; 151759243Sobrien } 151859243Sobrien 151959243Sobrien if (eq(vp, STRKHOME)) { 1520167465Smp Char *canon; 152159243Sobrien /* 152259243Sobrien * convert to canonical pathname (possibly resolving symlinks) 152359243Sobrien */ 1524167465Smp canon = dcanon(lp, lp); 1525167465Smp cleanup_ignore(lp); 1526167465Smp cleanup_until(lp); 1527167465Smp cleanup_push(canon, xfree); 1528167465Smp setv(STRhome, quote(canon), VAR_READWRITE); /* lp memory used here */ 1529167465Smp cleanup_ignore(canon); 1530167465Smp cleanup_until(canon); 153159243Sobrien 153259243Sobrien /* fix directory stack for new tilde home */ 153359243Sobrien dtilde(); 153459243Sobrien return; 153559243Sobrien } 153659243Sobrien 153759243Sobrien if (eq(vp, STRKSHLVL)) { 1538167465Smp setv(STRshlvl, quote(lp), VAR_READWRITE); /* lp memory used here */ 1539167465Smp cleanup_ignore(lp); 1540167465Smp cleanup_until(lp); 154159243Sobrien return; 154259243Sobrien } 154359243Sobrien 154459243Sobrien if (eq(vp, STRKUSER)) { 1545167465Smp setv(STRuser, quote(lp), VAR_READWRITE); /* lp memory used here */ 1546167465Smp cleanup_ignore(lp); 1547167465Smp cleanup_until(lp); 154859243Sobrien return; 154959243Sobrien } 155059243Sobrien 155159243Sobrien if (eq(vp, STRKGROUP)) { 1552167465Smp setv(STRgroup, quote(lp), VAR_READWRITE); /* lp memory used here */ 1553167465Smp cleanup_ignore(lp); 1554167465Smp cleanup_until(lp); 155559243Sobrien return; 155659243Sobrien } 155759243Sobrien 155859243Sobrien#ifdef COLOR_LS_F 155959243Sobrien if (eq(vp, STRLS_COLORS)) { 156059243Sobrien parseLS_COLORS(lp); 1561167465Smp cleanup_until(lp); 156259243Sobrien return; 156359243Sobrien } 1564316958Sdchagin if (eq(vp, STRLSCOLORS)) { 1565316958Sdchagin parseLSCOLORS(lp); 1566316958Sdchagin cleanup_until(lp); 1567316958Sdchagin return; 1568316958Sdchagin } 156959243Sobrien#endif /* COLOR_LS_F */ 157059243Sobrien 157159243Sobrien#ifdef SIG_WINDOW 157259243Sobrien /* 157359243Sobrien * Load/Update $LINES $COLUMNS 157459243Sobrien */ 157559243Sobrien if ((eq(lp, STRNULL) && (eq(vp, STRLINES) || eq(vp, STRCOLUMNS))) || 157659243Sobrien eq(vp, STRTERMCAP)) { 1577167465Smp cleanup_until(lp); 157859243Sobrien check_window_size(1); 157959243Sobrien return; 158059243Sobrien } 158159243Sobrien 158259243Sobrien /* 158359243Sobrien * Change the size to the one directed by $LINES and $COLUMNS 158459243Sobrien */ 158559243Sobrien if (eq(vp, STRLINES) || eq(vp, STRCOLUMNS)) { 158659243Sobrien#if 0 158759243Sobrien GotTermCaps = 0; 158859243Sobrien#endif 1589167465Smp cleanup_until(lp); 159059243Sobrien ed_Init(); 159159243Sobrien return; 159259243Sobrien } 159359243Sobrien#endif /* SIG_WINDOW */ 1594167465Smp cleanup_until(lp); 159559243Sobrien} 159659243Sobrien 159759243Sobrien/*ARGSUSED*/ 159859243Sobrienvoid 1599167465Smpdounsetenv(Char **v, struct command *c) 160059243Sobrien{ 1601167465Smp Char **ep, *p, *n, *name; 160259243Sobrien int i, maxi; 160359243Sobrien 160459243Sobrien USE(c); 160559243Sobrien /* 160659243Sobrien * Find the longest environment variable 160759243Sobrien */ 160859243Sobrien for (maxi = 0, ep = STR_environ; *ep; ep++) { 160959243Sobrien for (i = 0, p = *ep; *p && *p != '='; p++, i++) 161059243Sobrien continue; 161159243Sobrien if (i > maxi) 161259243Sobrien maxi = i; 161359243Sobrien } 161459243Sobrien 1615167465Smp name = xmalloc((maxi + 1) * sizeof(Char)); 1616167465Smp cleanup_push(name, xfree); 161759243Sobrien 161859243Sobrien while (++v && *v) 161959243Sobrien for (maxi = 1; maxi;) 162059243Sobrien for (maxi = 0, ep = STR_environ; *ep; ep++) { 162159243Sobrien for (n = name, p = *ep; *p && *p != '='; *n++ = *p++) 162259243Sobrien continue; 162359243Sobrien *n = '\0'; 162459243Sobrien if (!Gmatch(name, *v)) 162559243Sobrien continue; 162659243Sobrien maxi = 1; 162759243Sobrien 162859243Sobrien /* Unset the name. This wasn't being done until 162959243Sobrien * later but most of the stuff following won't 163059243Sobrien * work (particularly the setlocale() and getenv() 163159243Sobrien * stuff) as intended until the name is actually 163259243Sobrien * removed. (sg) 163359243Sobrien */ 163459243Sobrien Unsetenv(name); 163559243Sobrien 163659243Sobrien if (eq(name, STRNOREBIND)) { 163759243Sobrien NoNLSRebind = 0; 163859243Sobrien MapsAreInited = 0; 163959243Sobrien NLSMapsAreInited = 0; 164059243Sobrien ed_InitMaps(); 164159243Sobrien } 164259243Sobrien#ifdef apollo 164359243Sobrien else if (eq(name, STRSYSTYPE)) 164459243Sobrien dohash(NULL, NULL); 164559243Sobrien#endif /* apollo */ 164659243Sobrien else if (islocale_var(name)) { 164759243Sobrien#ifdef NLS 164859243Sobrien int k; 164959243Sobrien 165059243Sobrien# ifdef SETLOCALEBUG 165159243Sobrien dont_free = 1; 165259243Sobrien# endif /* SETLOCALEBUG */ 165359243Sobrien (void) setlocale(LC_ALL, ""); 165459243Sobrien# ifdef LC_COLLATE 165559243Sobrien (void) setlocale(LC_COLLATE, ""); 165659243Sobrien# endif 1657145479Smp# ifdef LC_CTYPE 1658167465Smp (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 1659145479Smp# endif /* LC_CTYPE */ 166059243Sobrien# ifdef NLS_CATALOGS 166159243Sobrien# ifdef LC_MESSAGES 166259243Sobrien (void) setlocale(LC_MESSAGES, ""); 166359243Sobrien# endif /* LC_MESSAGES */ 1664145479Smp nlsclose(); 166559243Sobrien nlsinit(); 166659243Sobrien# endif /* NLS_CATALOGS */ 166759243Sobrien# ifdef SETLOCALEBUG 166859243Sobrien dont_free = 0; 166959243Sobrien# endif /* SETLOCALEBUG */ 167059243Sobrien# ifdef STRCOLLBUG 167159243Sobrien fix_strcoll_bug(); 167259243Sobrien# endif /* STRCOLLBUG */ 167359243Sobrien tw_cmd_free();/* since the collation sequence has changed */ 1674167465Smp for (k = 0200; k <= 0377 && !Isprint(CTL_ESC(k)); k++) 167559243Sobrien continue; 1676145479Smp AsciiOnly = MB_CUR_MAX == 1 && k > 0377; 167759243Sobrien#else /* !NLS */ 167859243Sobrien AsciiOnly = getenv("LANG") == NULL && 167959243Sobrien getenv("LC_CTYPE") == NULL; 168059243Sobrien#endif /* NLS */ 168159243Sobrien NLSMapsAreInited = 0; 168259243Sobrien ed_Init(); 168359243Sobrien if (MapsAreInited && !NLSMapsAreInited) 168459243Sobrien ed_InitNLSMaps(); 168559243Sobrien 168659243Sobrien } 168769408Sache#ifdef WINNT_NATIVE 168859243Sobrien else if (eq(name,(STRtcshlang))) { 168959243Sobrien nls_dll_unload(); 169059243Sobrien nlsinit(); 169159243Sobrien } 169269408Sache#endif /* WINNT_NATIVE */ 169359243Sobrien#ifdef COLOR_LS_F 169459243Sobrien else if (eq(name, STRLS_COLORS)) 169559243Sobrien parseLS_COLORS(n); 1696316958Sdchagin else if (eq(name, STRLSCOLORS)) 1697316958Sdchagin parseLSCOLORS(n); 169859243Sobrien#endif /* COLOR_LS_F */ 1699100616Smp#ifdef NLS_CATALOGS 1700100616Smp else if (eq(name, STRNLSPATH)) { 1701145479Smp nlsclose(); 1702100616Smp nlsinit(); 1703100616Smp } 1704100616Smp#endif 170559243Sobrien /* 170659243Sobrien * start again cause the environment changes 170759243Sobrien */ 170859243Sobrien break; 170959243Sobrien } 1710167465Smp cleanup_until(name); 171159243Sobrien} 171259243Sobrien 171359243Sobrienvoid 1714167465Smptsetenv(const Char *name, const Char *val) 171559243Sobrien{ 171659243Sobrien#ifdef SETENV_IN_LIB 171759243Sobrien/* 171859243Sobrien * XXX: This does not work right, since tcsh cannot track changes to 171959243Sobrien * the environment this way. (the builtin setenv without arguments does 172059243Sobrien * not print the right stuff neither does unsetenv). This was for Mach, 172159243Sobrien * it is not needed anymore. 172259243Sobrien */ 172359243Sobrien#undef setenv 1724167465Smp char *cname; 172559243Sobrien 1726167465Smp if (name == NULL) 172759243Sobrien return; 1728167465Smp cname = strsave(short2str(name)); 1729167465Smp setenv(cname, short2str(val), 1); 1730167465Smp xfree(cname); 173159243Sobrien#else /* !SETENV_IN_LIB */ 1732145479Smp Char **ep = STR_environ; 1733145479Smp const Char *ccp; 1734145479Smp Char *cp, *dp; 173559243Sobrien Char *blk[2]; 173659243Sobrien Char **oep = ep; 173759243Sobrien 173869408Sache#ifdef WINNT_NATIVE 1739167465Smp nt_set_env(name,val); 174069408Sache#endif /* WINNT_NATIVE */ 174159243Sobrien for (; *ep; ep++) { 174269408Sache#ifdef WINNT_NATIVE 1743145479Smp for (ccp = name, dp = *ep; *ccp && Tolower(*ccp & TRIM) == Tolower(*dp); 1744145479Smp ccp++, dp++) 174559243Sobrien#else 1746145479Smp for (ccp = name, dp = *ep; *ccp && (*ccp & TRIM) == *dp; ccp++, dp++) 174769408Sache#endif /* WINNT_NATIVE */ 174859243Sobrien continue; 1749145479Smp if (*ccp != 0 || *dp != '=') 175059243Sobrien continue; 175159243Sobrien cp = Strspl(STRequal, val); 1752167465Smp xfree(*ep); 175359243Sobrien *ep = strip(Strspl(name, cp)); 1754167465Smp xfree(cp); 175559243Sobrien blkfree((Char **) environ); 175659243Sobrien environ = short2blk(STR_environ); 175759243Sobrien return; 175859243Sobrien } 175959243Sobrien cp = Strspl(name, STRequal); 176059243Sobrien blk[0] = strip(Strspl(cp, val)); 1761167465Smp xfree(cp); 176259243Sobrien blk[1] = 0; 176359243Sobrien STR_environ = blkspl(STR_environ, blk); 176459243Sobrien blkfree((Char **) environ); 176559243Sobrien environ = short2blk(STR_environ); 1766167465Smp xfree(oep); 176759243Sobrien#endif /* SETENV_IN_LIB */ 176859243Sobrien} 176959243Sobrien 177059243Sobrienvoid 1771167465SmpUnsetenv(Char *name) 177259243Sobrien{ 1773145479Smp Char **ep = STR_environ; 1774145479Smp Char *cp, *dp; 177559243Sobrien Char **oep = ep; 177659243Sobrien 177769408Sache#ifdef WINNT_NATIVE 177859243Sobrien nt_set_env(name,NULL); 177969408Sache#endif /*WINNT_NATIVE */ 178059243Sobrien for (; *ep; ep++) { 178159243Sobrien for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) 178259243Sobrien continue; 178359243Sobrien if (*cp != 0 || *dp != '=') 178459243Sobrien continue; 178559243Sobrien cp = *ep; 178659243Sobrien *ep = 0; 178759243Sobrien STR_environ = blkspl(STR_environ, ep + 1); 178859243Sobrien blkfree((Char **) environ); 178959243Sobrien environ = short2blk(STR_environ); 179059243Sobrien *ep = cp; 1791167465Smp xfree(cp); 1792167465Smp xfree(oep); 179359243Sobrien return; 179459243Sobrien } 179559243Sobrien} 179659243Sobrien 179759243Sobrien/*ARGSUSED*/ 179859243Sobrienvoid 1799167465Smpdoumask(Char **v, struct command *c) 180059243Sobrien{ 1801145479Smp Char *cp = v[1]; 1802145479Smp int i; 180359243Sobrien 180459243Sobrien USE(c); 180559243Sobrien if (cp == 0) { 180659415Sobrien i = (int)umask(0); 180759243Sobrien (void) umask(i); 180859243Sobrien xprintf("%o\n", i); 180959243Sobrien return; 181059243Sobrien } 181159243Sobrien i = 0; 181259243Sobrien while (Isdigit(*cp) && *cp != '8' && *cp != '9') 181359243Sobrien i = i * 8 + *cp++ - '0'; 181459243Sobrien if (*cp || i < 0 || i > 0777) 181559243Sobrien stderror(ERR_NAME | ERR_MASK); 181659243Sobrien (void) umask(i); 181759243Sobrien} 181859243Sobrien 181959243Sobrien#ifndef HAVENOLIMIT 182059243Sobrien# ifndef BSDLIMIT 182159243Sobrien typedef long RLIM_TYPE; 1822145479Smp# ifdef _OSD_POSIX /* BS2000 */ 1823145479Smp# include <ulimit.h> 1824145479Smp# endif 182559243Sobrien# ifndef RLIM_INFINITY 182659243Sobrien# if !defined(_MINIX) && !defined(__clipper__) && !defined(_CRAY) 182759243Sobrien extern RLIM_TYPE ulimit(); 182859243Sobrien# endif /* ! _MINIX && !__clipper__ */ 182959243Sobrien# define RLIM_INFINITY 0x003fffff 183059243Sobrien# define RLIMIT_FSIZE 1 183159243Sobrien# endif /* RLIM_INFINITY */ 183259243Sobrien# ifdef aiws 183359243Sobrien# define toset(a) (((a) == 3) ? 1004 : (a) + 1) 183459243Sobrien# define RLIMIT_DATA 3 183559243Sobrien# define RLIMIT_STACK 1005 183659243Sobrien# else /* aiws */ 183759243Sobrien# define toset(a) ((a) + 1) 183859243Sobrien# endif /* aiws */ 183959243Sobrien# else /* BSDLIMIT */ 1840145479Smp# if (defined(BSD4_4) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) || (HPUXVERSION >= 1100)) && !defined(__386BSD__) 1841100616Smp typedef rlim_t RLIM_TYPE; 184259243Sobrien# else 184359243Sobrien# if defined(SOLARIS2) || (defined(sgi) && SYSVREL > 3) 184459243Sobrien typedef rlim_t RLIM_TYPE; 184559243Sobrien# else 184659243Sobrien# if defined(_SX) 184759243Sobrien typedef long long RLIM_TYPE; 1848100616Smp# else /* !_SX */ 184959243Sobrien typedef unsigned long RLIM_TYPE; 185059243Sobrien# endif /* _SX */ 185159243Sobrien# endif /* SOLARIS2 || (sgi && SYSVREL > 3) */ 185259243Sobrien# endif /* BSD4_4 && !__386BSD__ */ 185359243Sobrien# endif /* BSDLIMIT */ 185459243Sobrien 1855131962Smp# if (HPUXVERSION > 700) && (HPUXVERSION < 1100) && defined(BSDLIMIT) 185659243Sobrien/* Yes hpux8.0 has limits but <sys/resource.h> does not make them public */ 185759243Sobrien/* Yes, we could have defined _KERNEL, and -I/etc/conf/h, but is that better? */ 185859243Sobrien# ifndef RLIMIT_CPU 185959243Sobrien# define RLIMIT_CPU 0 186059243Sobrien# define RLIMIT_FSIZE 1 186159243Sobrien# define RLIMIT_DATA 2 186259243Sobrien# define RLIMIT_STACK 3 186359243Sobrien# define RLIMIT_CORE 4 186459243Sobrien# define RLIMIT_RSS 5 186559243Sobrien# define RLIMIT_NOFILE 6 186659243Sobrien# endif /* RLIMIT_CPU */ 186759243Sobrien# ifndef RLIM_INFINITY 186859243Sobrien# define RLIM_INFINITY 0x7fffffff 186959243Sobrien# endif /* RLIM_INFINITY */ 187059243Sobrien /* 187159243Sobrien * old versions of HP/UX counted limits in 512 bytes 187259243Sobrien */ 187359243Sobrien# ifndef SIGRTMIN 187459243Sobrien# define FILESIZE512 187559243Sobrien# endif /* SIGRTMIN */ 1876131962Smp# endif /* (HPUXVERSION > 700) && (HPUXVERSION < 1100) && BSDLIMIT */ 187759243Sobrien 187859243Sobrien# if SYSVREL > 3 && defined(BSDLIMIT) && !defined(_SX) 187959243Sobrien/* In order to use rusage, we included "/usr/ucbinclude/sys/resource.h" in */ 188059243Sobrien/* sh.h. However, some SVR4 limits are defined in <sys/resource.h>. Rather */ 188159243Sobrien/* than include both and get warnings, we define the extra SVR4 limits here. */ 188283098Smp/* XXX: I don't understand if RLIMIT_AS is defined, why don't we define */ 188383098Smp/* RLIMIT_VMEM based on it? */ 188459243Sobrien# ifndef RLIMIT_VMEM 188559243Sobrien# define RLIMIT_VMEM 6 188659243Sobrien# endif 188759243Sobrien# ifndef RLIMIT_AS 188859243Sobrien# define RLIMIT_AS RLIMIT_VMEM 188959243Sobrien# endif 189059243Sobrien# endif /* SYSVREL > 3 && BSDLIMIT */ 189159243Sobrien 1892231990Smp# if (defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) 1893231990Smp# if defined(RLIMIT_AS) && !defined(RLIMIT_VMEM) 1894231990Smp# define RLIMIT_VMEM RLIMIT_AS 1895231990Smp# endif 1896231990Smp/* 1897231990Smp * Oh well, <asm-generic/resource.h> has it, but <bits/resource.h> does not 1898231990Smp * Linux headers: When the left hand does not know what the right hand does. 1899231990Smp */ 1900231990Smp# if defined(RLIMIT_RTPRIO) && !defined(RLIMIT_RTTIME) 1901231990Smp# define RLIMIT_RTTIME (RLIMIT_RTPRIO + 1) 1902231990Smp# endif 190383098Smp# endif 190483098Smp 190559243Sobrienstruct limits limits[] = 190659243Sobrien{ 190759243Sobrien# ifdef RLIMIT_CPU 190859243Sobrien { RLIMIT_CPU, "cputime", 1, "seconds" }, 190959243Sobrien# endif /* RLIMIT_CPU */ 191059243Sobrien 191159243Sobrien# ifdef RLIMIT_FSIZE 191259243Sobrien# ifndef aiws 191359243Sobrien { RLIMIT_FSIZE, "filesize", 1024, "kbytes" }, 191459243Sobrien# else 191559243Sobrien { RLIMIT_FSIZE, "filesize", 512, "blocks" }, 191659243Sobrien# endif /* aiws */ 191759243Sobrien# endif /* RLIMIT_FSIZE */ 191859243Sobrien 191959243Sobrien# ifdef RLIMIT_DATA 192059243Sobrien { RLIMIT_DATA, "datasize", 1024, "kbytes" }, 192159243Sobrien# endif /* RLIMIT_DATA */ 192259243Sobrien 192359243Sobrien# ifdef RLIMIT_STACK 192459243Sobrien# ifndef aiws 192559243Sobrien { RLIMIT_STACK, "stacksize", 1024, "kbytes" }, 192659243Sobrien# else 192759243Sobrien { RLIMIT_STACK, "stacksize", 1024 * 1024, "kbytes"}, 192859243Sobrien# endif /* aiws */ 192959243Sobrien# endif /* RLIMIT_STACK */ 193059243Sobrien 193159243Sobrien# ifdef RLIMIT_CORE 193259243Sobrien { RLIMIT_CORE, "coredumpsize", 1024, "kbytes" }, 193359243Sobrien# endif /* RLIMIT_CORE */ 193459243Sobrien 193559243Sobrien# ifdef RLIMIT_RSS 193659243Sobrien { RLIMIT_RSS, "memoryuse", 1024, "kbytes" }, 193759243Sobrien# endif /* RLIMIT_RSS */ 193859243Sobrien 193959243Sobrien# ifdef RLIMIT_UMEM 194059243Sobrien { RLIMIT_UMEM, "memoryuse", 1024, "kbytes" }, 194159243Sobrien# endif /* RLIMIT_UMEM */ 194259243Sobrien 194359243Sobrien# ifdef RLIMIT_VMEM 194459243Sobrien { RLIMIT_VMEM, "vmemoryuse", 1024, "kbytes" }, 194559243Sobrien# endif /* RLIMIT_VMEM */ 194659243Sobrien 1947145479Smp# if defined(RLIMIT_HEAP) /* found on BS2000/OSD systems */ 1948145479Smp { RLIMIT_HEAP, "heapsize", 1024, "kbytes" }, 1949145479Smp# endif /* RLIMIT_HEAP */ 1950145479Smp 195159243Sobrien# ifdef RLIMIT_NOFILE 195259243Sobrien { RLIMIT_NOFILE, "descriptors", 1, "" }, 195359243Sobrien# endif /* RLIMIT_NOFILE */ 195459243Sobrien 1955316958Sdchagin# ifdef RLIMIT_NPTS 1956316958Sdchagin { RLIMIT_NPTS, "pseudoterminals", 1, "" }, 1957316958Sdchagin# endif /* RLIMIT_NPTS */ 1958316958Sdchagin 1959316958Sdchagin# ifdef RLIMIT_KQUEUES 1960316958Sdchagin { RLIMIT_KQUEUES, "kqueues", 1, "" }, 1961316958Sdchagin# endif /* RLIMIT_KQUEUES */ 1962316958Sdchagin 196359243Sobrien# ifdef RLIMIT_CONCUR 196459243Sobrien { RLIMIT_CONCUR, "concurrency", 1, "thread(s)" }, 196559243Sobrien# endif /* RLIMIT_CONCUR */ 196659243Sobrien 196759243Sobrien# ifdef RLIMIT_MEMLOCK 196859243Sobrien { RLIMIT_MEMLOCK, "memorylocked", 1024, "kbytes" }, 196959243Sobrien# endif /* RLIMIT_MEMLOCK */ 197059243Sobrien 197159243Sobrien# ifdef RLIMIT_NPROC 197259243Sobrien { RLIMIT_NPROC, "maxproc", 1, "" }, 197359243Sobrien# endif /* RLIMIT_NPROC */ 197459243Sobrien 1975316958Sdchagin# ifdef RLIMIT_NTHR 1976316958Sdchagin { RLIMIT_NTHR, "maxthread", 1, "" }, 1977316958Sdchagin# endif /* RLIMIT_NTHR */ 1978316958Sdchagin 1979100616Smp# if defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE) 198059243Sobrien { RLIMIT_OFILE, "openfiles", 1, "" }, 1981100616Smp# endif /* RLIMIT_OFILE && !defined(RLIMIT_NOFILE) */ 198259243Sobrien 1983100616Smp# ifdef RLIMIT_SBSIZE 1984100616Smp { RLIMIT_SBSIZE, "sbsize", 1, "" }, 1985100616Smp# endif /* RLIMIT_SBSIZE */ 1986100616Smp 1987195609Smp# ifdef RLIMIT_SWAP 1988195609Smp { RLIMIT_SWAP, "swapsize", 1024, "kbytes" }, 1989195609Smp# endif /* RLIMIT_SWAP */ 1990194767Skib 1991231990Smp# ifdef RLIMIT_LOCKS 1992231990Smp { RLIMIT_LOCKS, "maxlocks", 1, "" }, 1993231990Smp# endif /* RLIMIT_LOCKS */ 1994231990Smp 1995316958Sdchagin# ifdef RLIMIT_POSIXLOCKS 1996316958Sdchagin { RLIMIT_POSIXLOCKS,"posixlocks", 1, "" }, 1997316958Sdchagin# endif /* RLIMIT_POSIXLOCKS */ 1998316958Sdchagin 1999231990Smp# ifdef RLIMIT_SIGPENDING 2000231990Smp { RLIMIT_SIGPENDING,"maxsignal", 1, "" }, 2001231990Smp# endif /* RLIMIT_SIGPENDING */ 2002231990Smp 2003231990Smp# ifdef RLIMIT_MSGQUEUE 2004231990Smp { RLIMIT_MSGQUEUE, "maxmessage", 1, "" }, 2005231990Smp# endif /* RLIMIT_MSGQUEUE */ 2006231990Smp 2007231990Smp# ifdef RLIMIT_NICE 2008231990Smp { RLIMIT_NICE, "maxnice", 1, "" }, 2009231990Smp# endif /* RLIMIT_NICE */ 2010231990Smp 2011231990Smp# ifdef RLIMIT_RTPRIO 2012231990Smp { RLIMIT_RTPRIO, "maxrtprio", 1, "" }, 2013231990Smp# endif /* RLIMIT_RTPRIO */ 2014231990Smp 2015231990Smp# ifdef RLIMIT_RTTIME 2016231990Smp { RLIMIT_RTTIME, "maxrttime", 1, "usec" }, 2017231990Smp# endif /* RLIMIT_RTTIME */ 2018231990Smp 201959243Sobrien { -1, NULL, 0, NULL } 202059243Sobrien}; 202159243Sobrien 2022167465Smpstatic struct limits *findlim (Char *); 2023167465Smpstatic RLIM_TYPE getval (struct limits *, Char **); 2024231990Smpstatic int strtail (Char *, const char *); 2025167465Smpstatic void limtail (Char *, const char *); 2026231990Smpstatic void limtail2 (Char *, const char *, const char *); 2027167465Smpstatic void plim (struct limits *, int); 2028167465Smpstatic int setlim (struct limits *, int, RLIM_TYPE); 202959243Sobrien 203059243Sobrien#ifdef convex 203159243Sobrienstatic RLIM_TYPE 2032167465Smprestrict_limit(double value) 203359243Sobrien{ 203459243Sobrien /* 203559243Sobrien * is f too large to cope with? return the maximum or minimum int 203659243Sobrien */ 203759243Sobrien if (value > (double) INT_MAX) 203859243Sobrien return (RLIM_TYPE) INT_MAX; 203959243Sobrien else if (value < (double) INT_MIN) 204059243Sobrien return (RLIM_TYPE) INT_MIN; 204159243Sobrien else 204259243Sobrien return (RLIM_TYPE) value; 204359243Sobrien} 204459243Sobrien#else /* !convex */ 204559243Sobrien# define restrict_limit(x) ((RLIM_TYPE) (x)) 204659243Sobrien#endif /* convex */ 204759243Sobrien 204859243Sobrien 204959243Sobrienstatic struct limits * 2050167465Smpfindlim(Char *cp) 205159243Sobrien{ 2052145479Smp struct limits *lp, *res; 205359243Sobrien 2054167465Smp res = NULL; 205559243Sobrien for (lp = limits; lp->limconst >= 0; lp++) 205659243Sobrien if (prefix(cp, str2short(lp->limname))) { 205759243Sobrien if (res) 205859243Sobrien stderror(ERR_NAME | ERR_AMBIG); 205959243Sobrien res = lp; 206059243Sobrien } 206159243Sobrien if (res) 206259243Sobrien return (res); 206359243Sobrien stderror(ERR_NAME | ERR_LIMIT); 206459243Sobrien /* NOTREACHED */ 206559243Sobrien return (0); 206659243Sobrien} 206759243Sobrien 206859243Sobrien/*ARGSUSED*/ 206959243Sobrienvoid 2070167465Smpdolimit(Char **v, struct command *c) 207159243Sobrien{ 2072145479Smp struct limits *lp; 2073145479Smp RLIM_TYPE limit; 207459243Sobrien int hard = 0; 207559243Sobrien 207659243Sobrien USE(c); 207759243Sobrien v++; 207859243Sobrien if (*v && eq(*v, STRmh)) { 207959243Sobrien hard = 1; 208059243Sobrien v++; 208159243Sobrien } 208259243Sobrien if (*v == 0) { 208359243Sobrien for (lp = limits; lp->limconst >= 0; lp++) 208459243Sobrien plim(lp, hard); 208559243Sobrien return; 208659243Sobrien } 208759243Sobrien lp = findlim(v[0]); 208859243Sobrien if (v[1] == 0) { 208959243Sobrien plim(lp, hard); 209059243Sobrien return; 209159243Sobrien } 209259243Sobrien limit = getval(lp, v + 1); 209359243Sobrien if (setlim(lp, hard, limit) < 0) 209459243Sobrien stderror(ERR_SILENT); 209559243Sobrien} 209659243Sobrien 209759243Sobrienstatic RLIM_TYPE 2098167465Smpgetval(struct limits *lp, Char **v) 209959243Sobrien{ 2100145479Smp float f; 210159243Sobrien Char *cp = *v++; 210259243Sobrien 210359243Sobrien f = atof(short2str(cp)); 210459243Sobrien 210559243Sobrien# ifdef convex 210659243Sobrien /* 210759243Sobrien * is f too large to cope with. limit f to minint, maxint - X-6768 by 210859243Sobrien * strike 210959243Sobrien */ 211059243Sobrien if ((f < (double) INT_MIN) || (f > (double) INT_MAX)) { 211159243Sobrien stderror(ERR_NAME | ERR_TOOLARGE); 211259243Sobrien } 211359243Sobrien# endif /* convex */ 211459243Sobrien 211559243Sobrien while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') 211659243Sobrien cp++; 211759243Sobrien if (*cp == 0) { 211859243Sobrien if (*v == 0) 211969408Sache return restrict_limit((f * lp->limdiv) + 0.5); 212059243Sobrien cp = *v; 212159243Sobrien } 212259243Sobrien switch (*cp) { 212359243Sobrien# ifdef RLIMIT_CPU 212459243Sobrien case ':': 212559243Sobrien if (lp->limconst != RLIMIT_CPU) 212659243Sobrien goto badscal; 212759243Sobrien return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f * 60.0 + atof(short2str(cp + 1)))); 212859243Sobrien case 'h': 212959243Sobrien if (lp->limconst != RLIMIT_CPU) 213059243Sobrien goto badscal; 213159243Sobrien limtail(cp, "hours"); 213259243Sobrien f *= 3600.0; 213359243Sobrien break; 2134231990Smp# endif /* RLIMIT_CPU */ 213559243Sobrien case 'm': 2136231990Smp# ifdef RLIMIT_CPU 213759243Sobrien if (lp->limconst == RLIMIT_CPU) { 213859243Sobrien limtail(cp, "minutes"); 213959243Sobrien f *= 60.0; 214059243Sobrien break; 214159243Sobrien } 2142231990Smp# endif /* RLIMIT_CPU */ 2143231990Smp limtail2(cp, "megabytes", "mbytes"); 214459243Sobrien f *= 1024.0 * 1024.0; 214559243Sobrien break; 2146231990Smp# ifdef RLIMIT_CPU 214759243Sobrien case 's': 214859243Sobrien if (lp->limconst != RLIMIT_CPU) 214959243Sobrien goto badscal; 215059243Sobrien limtail(cp, "seconds"); 215159243Sobrien break; 215259243Sobrien# endif /* RLIMIT_CPU */ 2153231990Smp case 'G': 2154231990Smp *cp = 'g'; 2155231990Smp /*FALLTHROUGH*/ 2156231990Smp case 'g': 2157231990Smp# ifdef RLIMIT_CPU 2158231990Smp if (lp->limconst == RLIMIT_CPU) 2159231990Smp goto badscal; 2160231990Smp# endif /* RLIMIT_CPU */ 2161231990Smp limtail2(cp, "gigabytes", "gbytes"); 2162231990Smp f *= 1024.0 * 1024.0 * 1024.0; 2163231990Smp break; 216459243Sobrien case 'M': 216559243Sobrien# ifdef RLIMIT_CPU 216659243Sobrien if (lp->limconst == RLIMIT_CPU) 216759243Sobrien goto badscal; 216859243Sobrien# endif /* RLIMIT_CPU */ 216959243Sobrien *cp = 'm'; 2170231990Smp limtail2(cp, "megabytes", "mbytes"); 217159243Sobrien f *= 1024.0 * 1024.0; 217259243Sobrien break; 217359243Sobrien case 'k': 217459243Sobrien# ifdef RLIMIT_CPU 217559243Sobrien if (lp->limconst == RLIMIT_CPU) 217659243Sobrien goto badscal; 217759243Sobrien# endif /* RLIMIT_CPU */ 2178231990Smp limtail2(cp, "kilobytes", "kbytes"); 217959243Sobrien f *= 1024.0; 218059243Sobrien break; 218159243Sobrien case 'b': 218259243Sobrien# ifdef RLIMIT_CPU 218359243Sobrien if (lp->limconst == RLIMIT_CPU) 218459243Sobrien goto badscal; 218559243Sobrien# endif /* RLIMIT_CPU */ 218659243Sobrien limtail(cp, "blocks"); 218759243Sobrien f *= 512.0; 218859243Sobrien break; 218959243Sobrien case 'u': 219059243Sobrien limtail(cp, "unlimited"); 219159243Sobrien return ((RLIM_TYPE) RLIM_INFINITY); 219259243Sobrien default: 219359243Sobrien# ifdef RLIMIT_CPU 219459243Sobrienbadscal: 219559243Sobrien# endif /* RLIMIT_CPU */ 219659243Sobrien stderror(ERR_NAME | ERR_SCALEF); 219759243Sobrien } 219859243Sobrien# ifdef convex 219959243Sobrien return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f + 0.5)); 220059243Sobrien# else 220159243Sobrien f += 0.5; 2202231990Smp if (f > (float) ((RLIM_TYPE) RLIM_INFINITY)) 220359243Sobrien return ((RLIM_TYPE) RLIM_INFINITY); 220459243Sobrien else 220559243Sobrien return ((RLIM_TYPE) f); 220659243Sobrien# endif /* convex */ 220759243Sobrien} 220859243Sobrien 2209231990Smpstatic int 2210231990Smpstrtail(Char *cp, const char *str) 2211231990Smp{ 2212231990Smp while (*cp && *cp == (Char)*str) 2213231990Smp cp++, str++; 2214231990Smp return (*cp != '\0'); 2215231990Smp} 2216231990Smp 221759243Sobrienstatic void 2218167465Smplimtail(Char *cp, const char *str) 221959243Sobrien{ 2220231990Smp if (strtail(cp, str)) 2221231990Smp stderror(ERR_BADSCALE, str); 2222231990Smp} 222361515Sobrien 2224231990Smpstatic void 2225231990Smplimtail2(Char *cp, const char *str1, const char *str2) 2226231990Smp{ 2227231990Smp if (strtail(cp, str1) && strtail(cp, str2)) 2228231990Smp stderror(ERR_BADSCALE, str1); 222959243Sobrien} 223059243Sobrien 223159243Sobrien/*ARGSUSED*/ 223259243Sobrienstatic void 2233167465Smpplim(struct limits *lp, int hard) 223459243Sobrien{ 223559243Sobrien# ifdef BSDLIMIT 223659243Sobrien struct rlimit rlim; 223759243Sobrien# endif /* BSDLIMIT */ 223859243Sobrien RLIM_TYPE limit; 2239145479Smp int xdiv = lp->limdiv; 224059243Sobrien 2241131962Smp xprintf("%-13.13s", lp->limname); 224259243Sobrien 224359243Sobrien# ifndef BSDLIMIT 224459243Sobrien limit = ulimit(lp->limconst, 0); 224559243Sobrien# ifdef aiws 224659243Sobrien if (lp->limconst == RLIMIT_DATA) 224759243Sobrien limit -= 0x20000000; 224859243Sobrien# endif /* aiws */ 224959243Sobrien# else /* BSDLIMIT */ 225059243Sobrien (void) getrlimit(lp->limconst, &rlim); 225159243Sobrien limit = hard ? rlim.rlim_max : rlim.rlim_cur; 225259243Sobrien# endif /* BSDLIMIT */ 225359243Sobrien 225459243Sobrien# if !defined(BSDLIMIT) || defined(FILESIZE512) 225559243Sobrien /* 225659243Sobrien * Christos: filesize comes in 512 blocks. we divide by 2 to get 1024 225759243Sobrien * blocks. Note we cannot pre-multiply cause we might overflow (A/UX) 225859243Sobrien */ 225959243Sobrien if (lp->limconst == RLIMIT_FSIZE) { 226059243Sobrien if (limit >= (RLIM_INFINITY / 512)) 226159243Sobrien limit = RLIM_INFINITY; 226259243Sobrien else 2263145479Smp xdiv = (xdiv == 1024 ? 2 : 1); 226459243Sobrien } 226559243Sobrien# endif /* !BSDLIMIT || FILESIZE512 */ 226659243Sobrien 226759243Sobrien if (limit == RLIM_INFINITY) 226859243Sobrien xprintf("unlimited"); 226959243Sobrien else 2270145479Smp# if defined(RLIMIT_CPU) && defined(_OSD_POSIX) 2271145479Smp if (lp->limconst == RLIMIT_CPU && 2272145479Smp (unsigned long)limit >= 0x7ffffffdUL) 2273145479Smp xprintf("unlimited"); 2274145479Smp else 2275145479Smp# endif 227659243Sobrien# ifdef RLIMIT_CPU 227759243Sobrien if (lp->limconst == RLIMIT_CPU) 2278167465Smp psecs(limit); 227959243Sobrien else 228059243Sobrien# endif /* RLIMIT_CPU */ 2281145479Smp xprintf("%ld %s", (long) (limit / xdiv), lp->limscale); 228259243Sobrien xputchar('\n'); 228359243Sobrien} 228459243Sobrien 228559243Sobrien/*ARGSUSED*/ 228659243Sobrienvoid 2287167465Smpdounlimit(Char **v, struct command *c) 228859243Sobrien{ 2289145479Smp struct limits *lp; 229059243Sobrien int lerr = 0; 229159243Sobrien int hard = 0; 229259243Sobrien int force = 0; 229359243Sobrien 229459243Sobrien USE(c); 229559243Sobrien while (*++v && **v == '-') { 229659243Sobrien Char *vp = *v; 229759243Sobrien while (*++vp) 229859243Sobrien switch (*vp) { 229959243Sobrien case 'f': 230059243Sobrien force = 1; 230159243Sobrien break; 230259243Sobrien case 'h': 230359243Sobrien hard = 1; 230459243Sobrien break; 230559243Sobrien default: 230659243Sobrien stderror(ERR_ULIMUS); 230759243Sobrien break; 230859243Sobrien } 230959243Sobrien } 231059243Sobrien 231159243Sobrien if (*v == 0) { 231259243Sobrien for (lp = limits; lp->limconst >= 0; lp++) 231359243Sobrien if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0) 231459243Sobrien lerr++; 231559243Sobrien if (!force && lerr) 231659243Sobrien stderror(ERR_SILENT); 231759243Sobrien return; 231859243Sobrien } 231959243Sobrien while (*v) { 232059243Sobrien lp = findlim(*v++); 232159243Sobrien if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0 && !force) 232259243Sobrien stderror(ERR_SILENT); 232359243Sobrien } 232459243Sobrien} 232559243Sobrien 232659243Sobrienstatic int 2327167465Smpsetlim(struct limits *lp, int hard, RLIM_TYPE limit) 232859243Sobrien{ 232959243Sobrien# ifdef BSDLIMIT 233059243Sobrien struct rlimit rlim; 233159243Sobrien 233259243Sobrien (void) getrlimit(lp->limconst, &rlim); 233359243Sobrien 233459243Sobrien# ifdef FILESIZE512 233559243Sobrien /* Even though hpux has setrlimit(), it expects fsize in 512 byte blocks */ 233659243Sobrien if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 233759243Sobrien limit /= 512; 233859243Sobrien# endif /* FILESIZE512 */ 233959243Sobrien if (hard) 234059243Sobrien rlim.rlim_max = limit; 234159243Sobrien else if (limit == RLIM_INFINITY && euid != 0) 234259243Sobrien rlim.rlim_cur = rlim.rlim_max; 234359243Sobrien else 234459243Sobrien rlim.rlim_cur = limit; 234559243Sobrien 2346100616Smp if (rlim.rlim_cur > rlim.rlim_max) 2347100616Smp rlim.rlim_max = rlim.rlim_cur; 2348100616Smp 234959243Sobrien if (setrlimit(lp->limconst, &rlim) < 0) { 235059243Sobrien# else /* BSDLIMIT */ 235159243Sobrien if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 235259243Sobrien limit /= 512; 235359243Sobrien# ifdef aiws 235459243Sobrien if (lp->limconst == RLIMIT_DATA) 235559243Sobrien limit += 0x20000000; 235659243Sobrien# endif /* aiws */ 235759243Sobrien if (ulimit(toset(lp->limconst), limit) < 0) { 235859243Sobrien# endif /* BSDLIMIT */ 2359145479Smp int err; 2360145479Smp char *op, *type; 2361145479Smp 2362145479Smp err = errno; 2363145479Smp op = strsave(limit == RLIM_INFINITY ? CGETS(15, 2, "remove") : 2364145479Smp CGETS(15, 3, "set")); 2365167465Smp cleanup_push(op, xfree); 2366145479Smp type = strsave(hard ? CGETS(15, 4, " hard") : ""); 2367167465Smp cleanup_push(type, xfree); 2368100616Smp xprintf(CGETS(15, 1, "%s: %s: Can't %s%s limit (%s)\n"), bname, 2369145479Smp lp->limname, op, type, strerror(err)); 2370167465Smp cleanup_until(op); 237159243Sobrien return (-1); 237259243Sobrien } 237359243Sobrien return (0); 237459243Sobrien} 237559243Sobrien 237659243Sobrien#endif /* !HAVENOLIMIT */ 237759243Sobrien 237859243Sobrien/*ARGSUSED*/ 237959243Sobrienvoid 2380167465Smpdosuspend(Char **v, struct command *c) 238159243Sobrien{ 238259243Sobrien#ifdef BSDJOBS 2383167465Smp struct sigaction old; 238459243Sobrien#endif /* BSDJOBS */ 2385195609Smp 238659243Sobrien USE(c); 238759243Sobrien USE(v); 238859243Sobrien 238959243Sobrien if (loginsh) 239059243Sobrien stderror(ERR_SUSPLOG); 239159243Sobrien untty(); 239259243Sobrien 239359243Sobrien#ifdef BSDJOBS 2394167465Smp sigaction(SIGTSTP, NULL, &old); 2395167465Smp signal(SIGTSTP, SIG_DFL); 239659243Sobrien (void) kill(0, SIGTSTP); 239759243Sobrien /* the shell stops here */ 2398167465Smp sigaction(SIGTSTP, &old, NULL); 239959243Sobrien#else /* !BSDJOBS */ 240059243Sobrien stderror(ERR_JOBCONTROL); 240159243Sobrien#endif /* BSDJOBS */ 240259243Sobrien 240359243Sobrien#ifdef BSDJOBS 240459243Sobrien if (tpgrp != -1) { 2405195609Smp if (grabpgrp(FSHTTY, opgrp) == -1) 2406131962Smp stderror(ERR_SYSTEM, "tcgetpgrp", strerror(errno)); 240759243Sobrien (void) setpgid(0, shpgrp); 240859243Sobrien (void) tcsetpgrp(FSHTTY, shpgrp); 240959243Sobrien } 241059243Sobrien#endif /* BSDJOBS */ 241159243Sobrien (void) setdisc(FSHTTY); 241259243Sobrien} 241359243Sobrien 241459243Sobrien/* This is the dreaded EVAL built-in. 241559243Sobrien * If you don't fiddle with file descriptors, and reset didfds, 241659243Sobrien * this command will either ignore redirection inside or outside 241759243Sobrien * its arguments, e.g. eval "date >x" vs. eval "date" >x 241859243Sobrien * The stuff here seems to work, but I did it by trial and error rather 241959243Sobrien * than really knowing what was going on. If tpgrp is zero, we are 242059243Sobrien * probably a background eval, e.g. "eval date &", and we want to 242159243Sobrien * make sure that any processes we start stay in our pgrp. 242259243Sobrien * This is also the case for "time eval date" -- stay in same pgrp. 242359243Sobrien * Otherwise, under stty tostop, processes will stop in the wrong 242459243Sobrien * pgrp, with no way for the shell to get them going again. -IAN! 242559243Sobrien */ 242659243Sobrien 2427167465Smpstruct doeval_state 242859243Sobrien{ 2429167465Smp Char **evalvec, *evalp; 2430167465Smp int didfds; 243159243Sobrien#ifndef CLOSE_ON_EXEC 2432167465Smp int didcch; 2433167465Smp#endif 2434167465Smp int saveIN, saveOUT, saveDIAG; 2435167465Smp int SHIN, SHOUT, SHDIAG; 2436167465Smp}; 243759243Sobrien 2438167465Smpstatic void 2439167465Smpdoeval_cleanup(void *xstate) 2440167465Smp{ 2441167465Smp struct doeval_state *state; 2442167465Smp 2443167465Smp state = xstate; 2444167465Smp evalvec = state->evalvec; 2445167465Smp evalp = state->evalp; 2446167465Smp doneinp = 0; 244759243Sobrien#ifndef CLOSE_ON_EXEC 2448167465Smp didcch = state->didcch; 244959243Sobrien#endif /* CLOSE_ON_EXEC */ 2450167465Smp didfds = state->didfds; 2451316958Sdchagin if (state->saveIN != SHIN) 2452316958Sdchagin xclose(SHIN); 2453316958Sdchagin if (state->saveOUT != SHOUT) 2454316958Sdchagin xclose(SHOUT); 2455316958Sdchagin if (state->saveDIAG != SHDIAG) 2456316958Sdchagin xclose(SHDIAG); 2457167465Smp close_on_exec(SHIN = dmove(state->saveIN, state->SHIN), 1); 2458167465Smp close_on_exec(SHOUT = dmove(state->saveOUT, state->SHOUT), 1); 2459167465Smp close_on_exec(SHDIAG = dmove(state->saveDIAG, state->SHDIAG), 1); 2460316958Sdchagin if (didfds) { 2461316958Sdchagin close_on_exec(dcopy(SHIN, 0), 1); 2462316958Sdchagin close_on_exec(dcopy(SHOUT, 1), 1); 2463316958Sdchagin close_on_exec(dcopy(SHDIAG, 2), 1); 2464316958Sdchagin } 2465167465Smp} 246659243Sobrien 2467195609Smpstatic Char **Ggv; 2468167465Smp/*ARGSUSED*/ 2469167465Smpvoid 2470167465Smpdoeval(Char **v, struct command *c) 2471167465Smp{ 2472167465Smp struct doeval_state state; 2473195609Smp int gflag, my_reenter; 2474167465Smp Char **gv; 2475195609Smp jmp_buf_t osetexit; 247659243Sobrien 2477167465Smp USE(c); 2478167465Smp v++; 2479167465Smp if (*v == 0) 248059243Sobrien return; 2481167465Smp gflag = tglob(v); 248259243Sobrien if (gflag) { 2483167465Smp gv = v = globall(v, gflag); 2484167465Smp if (v == 0) 248559243Sobrien stderror(ERR_NOMATCH); 2486167465Smp cleanup_push(gv, blk_cleanup); 2487167465Smp v = copyblk(v); 248859243Sobrien } 248959243Sobrien else { 249059243Sobrien gv = NULL; 2491167465Smp v = copyblk(v); 2492167465Smp trim(v); 249359243Sobrien } 249459243Sobrien 2495195609Smp Ggv = gv; 2496167465Smp state.evalvec = evalvec; 2497167465Smp state.evalp = evalp; 2498167465Smp state.didfds = didfds; 249959243Sobrien#ifndef CLOSE_ON_EXEC 2500167465Smp state.didcch = didcch; 250159243Sobrien#endif /* CLOSE_ON_EXEC */ 2502167465Smp state.SHIN = SHIN; 2503167465Smp state.SHOUT = SHOUT; 2504167465Smp state.SHDIAG = SHDIAG; 250559243Sobrien 2506167465Smp (void)close_on_exec(state.saveIN = dcopy(SHIN, -1), 1); 2507167465Smp (void)close_on_exec(state.saveOUT = dcopy(SHOUT, -1), 1); 2508167465Smp (void)close_on_exec(state.saveDIAG = dcopy(SHDIAG, -1), 1); 2509167465Smp 2510167465Smp cleanup_push(&state, doeval_cleanup); 2511167465Smp 2512195609Smp getexit(osetexit); 2513195609Smp 2514195609Smp /* PWP: setjmp/longjmp bugfix for optimizing compilers */ 2515195609Smp#ifdef cray 2516195609Smp my_reenter = 1; /* assume non-zero return val */ 2517195609Smp if (setexit() == 0) { 2518195609Smp my_reenter = 0; /* Oh well, we were wrong */ 2519195609Smp#else /* !cray */ 2520195609Smp if ((my_reenter = setexit()) == 0) { 2521195609Smp#endif /* cray */ 2522195609Smp evalvec = v; 2523195609Smp evalp = 0; 2524195609Smp (void)close_on_exec(SHIN = dcopy(0, -1), 1); 2525195609Smp (void)close_on_exec(SHOUT = dcopy(1, -1), 1); 2526195609Smp (void)close_on_exec(SHDIAG = dcopy(2, -1), 1); 252759243Sobrien#ifndef CLOSE_ON_EXEC 2528195609Smp didcch = 0; 252959243Sobrien#endif /* CLOSE_ON_EXEC */ 2530195609Smp didfds = 0; 2531195609Smp gv = Ggv; 2532195609Smp process(0); 2533195609Smp Ggv = gv; 2534195609Smp } 253559243Sobrien 2536195609Smp if (my_reenter == 0) { 2537195609Smp cleanup_until(&state); 2538195609Smp if (Ggv) 2539195609Smp cleanup_until(Ggv); 2540195609Smp } 2541167465Smp 2542195609Smp resexit(osetexit); 2543195609Smp if (my_reenter) 2544195609Smp stderror(ERR_SILENT); 254559243Sobrien} 254659243Sobrien 254759243Sobrien/*************************************************************************/ 254859243Sobrien/* print list of builtin commands */ 254959243Sobrien 2550167465Smpstatic void 2551167465Smplbuffed_cleanup (void *dummy) 2552167465Smp{ 2553167465Smp USE(dummy); 2554167465Smp lbuffed = 1; 2555167465Smp} 2556167465Smp 255759243Sobrien/*ARGSUSED*/ 255859243Sobrienvoid 2559167465Smpdobuiltins(Char **v, struct command *c) 256059243Sobrien{ 256159243Sobrien /* would use print_by_column() in tw.parse.c but that assumes 256259243Sobrien * we have an array of Char * to pass.. (sg) 256359243Sobrien */ 2564167465Smp const struct biltins *b; 2565145479Smp int row, col, columns, rows; 256659243Sobrien unsigned int w, maxwidth; 256759243Sobrien 256859243Sobrien USE(c); 256959243Sobrien USE(v); 257059243Sobrien lbuffed = 0; /* turn off line buffering */ 2571167465Smp cleanup_push(&lbuffed, lbuffed_cleanup); 257259243Sobrien 257359243Sobrien /* find widest string */ 257459243Sobrien for (maxwidth = 0, b = bfunc; b < &bfunc[nbfunc]; ++b) 257559243Sobrien maxwidth = max(maxwidth, strlen(b->bname)); 257659243Sobrien ++maxwidth; /* for space */ 257759243Sobrien 257859243Sobrien columns = (TermH + 1) / maxwidth; /* PWP: terminal size change */ 257959243Sobrien if (!columns) 258059243Sobrien columns = 1; 258159243Sobrien rows = (nbfunc + (columns - 1)) / columns; 258259243Sobrien 258359243Sobrien for (b = bfunc, row = 0; row < rows; row++) { 258459243Sobrien for (col = 0; col < columns; col++) { 258559243Sobrien if (b < &bfunc[nbfunc]) { 258659243Sobrien w = strlen(b->bname); 258759243Sobrien xprintf("%s", b->bname); 258859243Sobrien if (col < (columns - 1)) /* Not last column? */ 258959243Sobrien for (; w < maxwidth; w++) 259059243Sobrien xputchar(' '); 259159243Sobrien ++b; 259259243Sobrien } 259359243Sobrien } 259459243Sobrien if (row < (rows - 1)) { 259559243Sobrien if (Tty_raw_mode) 259659243Sobrien xputchar('\r'); 259759243Sobrien xputchar('\n'); 259859243Sobrien } 259959243Sobrien } 260069408Sache#ifdef WINNT_NATIVE 260159243Sobrien nt_print_builtins(maxwidth); 260259243Sobrien#else 260359243Sobrien if (Tty_raw_mode) 260459243Sobrien xputchar('\r'); 260559243Sobrien xputchar('\n'); 260669408Sache#endif /* WINNT_NATIVE */ 260759243Sobrien 2608167465Smp cleanup_until(&lbuffed); /* turn back on line buffering */ 260959243Sobrien flush(); 261059243Sobrien} 261159243Sobrien 2612145479Smp#ifdef NLS_CATALOGS 2613145479Smpchar * 2614167465Smpxcatgets(nl_catd ctd, int set_id, int msg_id, const char *s) 2615145479Smp{ 2616167465Smp char *res; 2617167465Smp 2618167465Smp errno = 0; 2619167465Smp while ((res = catgets(ctd, set_id, msg_id, s)) == s && errno == EINTR) { 2620167465Smp handle_pending_signals(); 2621167465Smp errno = 0; 2622167465Smp } 2623167465Smp return res; 2624167465Smp} 2625167465Smp 2626167465Smp 2627167465Smp# if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2628167465Smpchar * 2629167465Smpiconv_catgets(nl_catd ctd, int set_id, int msg_id, const char *s) 2630167465Smp{ 2631145479Smp static char *buf = NULL; 2632145479Smp static size_t buf_size = 0; 2633145479Smp 2634145479Smp char *orig, *dest, *p; 2635167465Smp ICONV_CONST char *src; 2636145479Smp size_t src_size, dest_size; 2637145479Smp 2638167465Smp orig = xcatgets(ctd, set_id, msg_id, s); 2639145479Smp if (catgets_iconv == (iconv_t)-1 || orig == s) 2640145479Smp return orig; 2641145479Smp src = orig; 2642145479Smp src_size = strlen(src) + 1; 2643145479Smp if (buf == NULL && (buf = xmalloc(buf_size = src_size + 32)) == NULL) 2644145479Smp return orig; 2645145479Smp dest = buf; 2646145479Smp while (src_size != 0) { 2647145479Smp dest_size = buf + buf_size - dest; 2648145479Smp if (iconv(catgets_iconv, &src, &src_size, &dest, &dest_size) 2649145479Smp == (size_t)-1) { 2650145479Smp switch (errno) { 2651145479Smp case E2BIG: 2652145479Smp if ((p = xrealloc(buf, buf_size * 2)) == NULL) 2653145479Smp return orig; 2654145479Smp buf_size *= 2; 2655145479Smp dest = p + (dest - buf); 2656145479Smp buf = p; 2657145479Smp break; 2658145479Smp 2659145479Smp case EILSEQ: case EINVAL: default: 2660145479Smp return orig; 2661145479Smp } 2662145479Smp } 2663145479Smp } 2664145479Smp return buf; 2665145479Smp} 2666167465Smp# endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2667167465Smp#endif /* NLS_CATALOGS */ 2668145479Smp 266959243Sobrienvoid 2670167465Smpnlsinit(void) 267159243Sobrien{ 267259243Sobrien#ifdef NLS_CATALOGS 2673167465Smp static const char default_catalog[] = "tcsh"; 267469408Sache 2675167465Smp char *catalog = (char *)(intptr_t)default_catalog; 2676167465Smp 267769408Sache if (adrof(STRcatalog) != NULL) 2678167465Smp catalog = xasprintf("tcsh.%s", short2str(varval(STRcatalog))); 2679231990Smp#ifdef NL_CAT_LOCALE /* POSIX-compliant. */ 2680231990Smp /* 2681231990Smp * Check if LC_MESSAGES is set in the environment and use it, if so. 2682231990Smp * If not, fall back to the setting of LANG. 2683231990Smp */ 2684231990Smp catd = catopen(catalog, tgetenv(STRLC_MESSAGES) ? NL_CAT_LOCALE : 0); 2685231990Smp#else /* pre-POSIX */ 2686231990Smp# ifndef MCLoadBySet 2687231990Smp# define MCLoadBySet 0 2688231990Smp# endif 268969408Sache catd = catopen(catalog, MCLoadBySet); 2690231990Smp#endif 2691167465Smp if (catalog != default_catalog) 2692167465Smp xfree(catalog); 2693167465Smp#if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2694167465Smp /* xcatgets (), not CGETS, the charset name should be in ASCII anyway. */ 2695145479Smp catgets_iconv = iconv_open (nl_langinfo (CODESET), 2696231990Smp xcatgets(catd, 255, 1, "UTF-8")); 2697167465Smp#endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 269869408Sache#endif /* NLS_CATALOGS */ 269969408Sache#ifdef WINNT_NATIVE 270059243Sobrien nls_dll_init(); 270169408Sache#endif /* WINNT_NATIVE */ 270259243Sobrien errinit(); /* init the errorlist in correct locale */ 270359243Sobrien mesginit(); /* init the messages for signals */ 270459243Sobrien dateinit(); /* init the messages for dates */ 270559243Sobrien editinit(); /* init the editor messages */ 270659243Sobrien terminit(); /* init the termcap messages */ 270759243Sobrien} 2708145479Smp 2709145479Smpvoid 2710167465Smpnlsclose(void) 2711145479Smp{ 2712145479Smp#ifdef NLS_CATALOGS 2713167465Smp#if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2714145479Smp if (catgets_iconv != (iconv_t)-1) { 2715145479Smp iconv_close(catgets_iconv); 2716145479Smp catgets_iconv = (iconv_t)-1; 2717145479Smp } 2718167465Smp#endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2719167465Smp if (catd != (nl_catd)-1) { 2720167465Smp /* 2721167465Smp * catclose can call other functions which can call longjmp 2722167465Smp * making us re-enter this code. Prevent infinite recursion 2723167465Smp * by resetting catd. Problem reported and solved by: 2724167465Smp * Gerhard Niklasch 2725167465Smp */ 2726167465Smp nl_catd oldcatd = catd; 2727167465Smp catd = (nl_catd)-1; 2728167465Smp while (catclose(oldcatd) == -1 && errno == EINTR) 2729167465Smp handle_pending_signals(); 2730167465Smp } 2731145479Smp#endif /* NLS_CATALOGS */ 2732145479Smp} 2733316958Sdchagin 2734316958Sdchaginint 2735316958SdchagingetYN(const char *prompt) 2736316958Sdchagin{ 2737316958Sdchagin int doit; 2738316958Sdchagin char c; 2739316958Sdchagin 2740316958Sdchagin xprintf("%s", prompt); 2741316958Sdchagin flush(); 2742316958Sdchagin (void) force_read(SHIN, &c, sizeof(c)); 2743316958Sdchagin /* 2744316958Sdchagin * Perhaps we should use the yesexpr from the 2745316958Sdchagin * actual locale 2746316958Sdchagin */ 2747316958Sdchagin doit = (strchr(CGETS(22, 14, "Yy"), c) != NULL); 2748316958Sdchagin while (c != '\n' && force_read(SHIN, &c, sizeof(c)) == sizeof(c)) 2749316958Sdchagin continue; 2750316958Sdchagin return doit; 2751316958Sdchagin} 2752