1232633Smp/* $Header: /p/tcsh/cvsroot/tcsh/sh.func.c,v 3.162 2011/02/26 00:07:06 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 35232633SmpRCSID("$tcsh: sh.func.c,v 3.162 2011/02/26 00:07:06 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 44232633Smp#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++; 522232633Smp cp = sp = strip(*v); 523232633Smp if (!letter(*cp)) 52459243Sobrien stderror(ERR_NAME | ERR_VARBEGIN); 525232633Smp do { 52659243Sobrien cp++; 527232633Smp } while (alnum(*cp)); 528232633Smp 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; 590232633Smp 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; 767232633Smp 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: 802167465Smp while (getword(&word)) 80359243Sobrien continue; 80459243Sobrien if ((type == TC_IF || type == TC_ELSE) && 805167465Smp eq(word.s, STRthen)) 80659243Sobrien level++; 80759243Sobrien break; 80859243Sobrien 80959243Sobrien case TC_ENDIF: 81059243Sobrien if (type == TC_IF || type == TC_ELSE) 81159243Sobrien level--; 81259243Sobrien break; 81359243Sobrien 81459243Sobrien case TC_FOREACH: 81559243Sobrien case TC_WHILE: 816131962Smp wlevel++; 81759243Sobrien if (type == TC_BREAK) 81859243Sobrien level++; 81959243Sobrien break; 82059243Sobrien 82159243Sobrien case TC_END: 822131962Smp if (type == TC_BRKSW) { 823131962Smp if (wlevel == 0) { 824131962Smp wp = whyles; 825131962Smp if (wp) { 826131962Smp whyles = wp->w_next; 827131962Smp wpfree(wp); 828131962Smp } 829131962Smp } 830131962Smp } 83159243Sobrien if (type == TC_BREAK) 83259243Sobrien level--; 833131962Smp wlevel--; 83459243Sobrien break; 83559243Sobrien 83659243Sobrien case TC_SWITCH: 83759243Sobrien if (type == TC_SWITCH || type == TC_BRKSW) 83859243Sobrien level++; 83959243Sobrien break; 84059243Sobrien 84159243Sobrien case TC_ENDSW: 84259243Sobrien if (type == TC_SWITCH || type == TC_BRKSW) 84359243Sobrien level--; 84459243Sobrien break; 84559243Sobrien 84659243Sobrien case TC_LABEL: 847167465Smp if (type == TC_GOTO && getword(&word) && eq(word.s, goal)) 84859243Sobrien level = -1; 84959243Sobrien break; 85059243Sobrien 85159243Sobrien default: 85259243Sobrien if (type != TC_GOTO && (type != TC_SWITCH || level != 0)) 85359243Sobrien break; 854167465Smp if (word.len == 0 || word.s[word.len - 1] != ':') 85559243Sobrien break; 856167465Smp word.s[--word.len] = 0; 857167465Smp if ((type == TC_GOTO && eq(word.s, goal)) || 858167465Smp (type == TC_SWITCH && eq(word.s, STRdefault))) 85959243Sobrien level = -1; 86059243Sobrien break; 86159243Sobrien 86259243Sobrien case TC_CASE: 86359243Sobrien if (type != TC_SWITCH || level != 0) 86459243Sobrien break; 865167465Smp (void) getword(&word); 866167465Smp if (word.len != 0 && word.s[word.len - 1] == ':') 867167465Smp word.s[--word.len] = 0; 868167465Smp cp = strip(Dfix1(word.s)); 869167465Smp cleanup_push(cp, xfree); 87059243Sobrien if (Gmatch(goal, cp)) 87159243Sobrien level = -1; 872167465Smp cleanup_until(cp); 87359243Sobrien break; 87459243Sobrien 87559243Sobrien case TC_DEFAULT: 87659243Sobrien if (type == TC_SWITCH && level == 0) 87759243Sobrien level = -1; 87859243Sobrien break; 87959243Sobrien } 880195609Smp if (intty) { 881195609Smp ohistent->prev = histgetword(histent); 882195609Smp ohistent->prev->next = ohistent; 883195609Smp savehist(ohistent, 0); 884195609Smp freelex(ohistent); 885195609Smp xfree(ohistent); 886195609Smp } else 887195609Smp (void) getword(NULL); 88859243Sobrien } while (level >= 0); 889167465Smp end: 890167465Smp cleanup_until(&word); 89159243Sobrien} 89259243Sobrien 893195609Smpstatic struct wordent * 894195609Smphistgetword(struct wordent *histent) 895195609Smp{ 896195609Smp int found = 0, first; 897195609Smp eChar c, d; 898195609Smp int e; 899195609Smp struct Strbuf *tmp; 900195609Smp tmp = xmalloc(sizeof(*tmp)); 901195609Smp tmp->size = 0; 902195609Smp tmp->s = NULL; 903195609Smp c = readc(1); 904195609Smp d = 0; 905195609Smp e = 0; 906195609Smp for (;;) { 907195609Smp tmp->len = 0; 908195609Smp Strbuf_terminate (tmp); 909195609Smp while (c == ' ' || c == '\t') 910195609Smp c = readc(1); 911195609Smp if (c == '#') 912195609Smp do 913195609Smp c = readc(1); 914195609Smp while (c != CHAR_ERR && c != '\n'); 915195609Smp if (c == CHAR_ERR) 916195609Smp goto past; 917195609Smp if (c == '\n') 918195609Smp goto nl; 919195609Smp unreadc(c); 920195609Smp found = 1; 921195609Smp first = 1; 922195609Smp do { 923195609Smp e = (c == '\\'); 924195609Smp c = readc(1); 925195609Smp if (c == '\\' && !e) { 926195609Smp if ((c = readc(1)) == '\n') { 927195609Smp e = 1; 928195609Smp c = ' '; 929195609Smp } else { 930195609Smp unreadc(c); 931195609Smp c = '\\'; 932195609Smp } 933195609Smp } 934195609Smp if ((c == '\'' || c == '"') && !e) { 935195609Smp if (d == 0) 936195609Smp d = c; 937195609Smp else if (d == c) 938195609Smp d = 0; 939195609Smp } 940195609Smp if (c == CHAR_ERR) 941195609Smp goto past; 942195609Smp 943195609Smp Strbuf_append1(tmp, (Char) c); 944195609Smp 945195609Smp if (!first && !d && c == '(' && !e) { 946195609Smp break; 947195609Smp } 948195609Smp first = 0; 949195609Smp } while (d || e || (c != ' ' && c != '\t' && c != '\n')); 950195609Smp tmp->len--; 951195609Smp if (tmp->len) { 952195609Smp Strbuf_terminate(tmp); 953195609Smp histent->word = Strsave(tmp->s); 954195609Smp histent->next = xmalloc(sizeof (*histent)); 955195609Smp histent->next->prev = histent; 956195609Smp histent = histent->next; 957195609Smp } 958195609Smp if (c == '\n') { 959195609Smp nl: 960195609Smp tmp->len = 0; 961195609Smp Strbuf_append1(tmp, (Char) c); 962195609Smp Strbuf_terminate(tmp); 963195609Smp histent->word = Strsave(tmp->s); 964195609Smp return histent; 965195609Smp } 966195609Smp } 967195609Smp 968195609Smppast: 969195609Smp switch (Stype) { 970195609Smp 971195609Smp case TC_IF: 972195609Smp stderror(ERR_NAME | ERR_NOTFOUND, "then/endif"); 973195609Smp break; 974195609Smp 975195609Smp case TC_ELSE: 976195609Smp stderror(ERR_NAME | ERR_NOTFOUND, "endif"); 977195609Smp break; 978195609Smp 979195609Smp case TC_BRKSW: 980195609Smp case TC_SWITCH: 981195609Smp stderror(ERR_NAME | ERR_NOTFOUND, "endsw"); 982195609Smp break; 983195609Smp 984195609Smp case TC_BREAK: 985195609Smp stderror(ERR_NAME | ERR_NOTFOUND, "end"); 986195609Smp break; 987195609Smp 988195609Smp case TC_GOTO: 989195609Smp setname(short2str(Sgoal)); 990195609Smp stderror(ERR_NAME | ERR_NOTFOUND, "label"); 991195609Smp break; 992195609Smp 993195609Smp default: 994195609Smp break; 995195609Smp } 996195609Smp /* NOTREACHED */ 997195609Smp return NULL; 998195609Smp} 999195609Smp 100059243Sobrienstatic int 1001167465Smpgetword(struct Strbuf *wp) 100259243Sobrien{ 100359243Sobrien int found = 0, first; 1004145479Smp eChar c, d; 100559243Sobrien 1006167465Smp if (wp) 1007167465Smp wp->len = 0; 100859243Sobrien c = readc(1); 100959243Sobrien d = 0; 101059243Sobrien do { 101159243Sobrien while (c == ' ' || c == '\t') 101259243Sobrien c = readc(1); 101359243Sobrien if (c == '#') 101459243Sobrien do 101559243Sobrien c = readc(1); 1016145479Smp while (c != CHAR_ERR && c != '\n'); 1017145479Smp if (c == CHAR_ERR) 101859243Sobrien goto past; 101959243Sobrien if (c == '\n') { 102059243Sobrien if (wp) 102159243Sobrien break; 102259243Sobrien return (0); 102359243Sobrien } 102459243Sobrien unreadc(c); 102559243Sobrien found = 1; 102659243Sobrien first = 1; 102759243Sobrien do { 102859243Sobrien c = readc(1); 102959243Sobrien if (c == '\\' && (c = readc(1)) == '\n') 103059243Sobrien c = ' '; 103159243Sobrien if (c == '\'' || c == '"') { 103259243Sobrien if (d == 0) 103359243Sobrien d = c; 103459243Sobrien else if (d == c) 103559243Sobrien d = 0; 103659243Sobrien } 1037145479Smp if (c == CHAR_ERR) 103859243Sobrien goto past; 1039167465Smp if (wp) 1040167465Smp Strbuf_append1(wp, (Char) c); 104159243Sobrien if (!first && !d && c == '(') { 1042167465Smp if (wp) 1043167465Smp goto past_word_end; 104459243Sobrien else 104559243Sobrien break; 104659243Sobrien } 104759243Sobrien first = 0; 104859243Sobrien } while ((d || (c != ' ' && c != '\t')) && c != '\n'); 104959243Sobrien } while (wp == 0); 105059243Sobrien 1051167465Smp past_word_end: 105259243Sobrien unreadc(c); 1053167465Smp if (found) { 1054167465Smp wp->len--; 1055167465Smp Strbuf_terminate(wp); 1056167465Smp } 105759243Sobrien 105859243Sobrien return (found); 105959243Sobrien 106059243Sobrienpast: 106159243Sobrien switch (Stype) { 106259243Sobrien 106359243Sobrien case TC_IF: 106459243Sobrien stderror(ERR_NAME | ERR_NOTFOUND, "then/endif"); 106559243Sobrien break; 106659243Sobrien 106759243Sobrien case TC_ELSE: 106859243Sobrien stderror(ERR_NAME | ERR_NOTFOUND, "endif"); 106959243Sobrien break; 107059243Sobrien 107159243Sobrien case TC_BRKSW: 107259243Sobrien case TC_SWITCH: 107359243Sobrien stderror(ERR_NAME | ERR_NOTFOUND, "endsw"); 107459243Sobrien break; 107559243Sobrien 107659243Sobrien case TC_BREAK: 107759243Sobrien stderror(ERR_NAME | ERR_NOTFOUND, "end"); 107859243Sobrien break; 107959243Sobrien 108059243Sobrien case TC_GOTO: 108159243Sobrien setname(short2str(Sgoal)); 108259243Sobrien stderror(ERR_NAME | ERR_NOTFOUND, "label"); 108359243Sobrien break; 108459243Sobrien 108559243Sobrien default: 108659243Sobrien break; 108759243Sobrien } 108859243Sobrien /* NOTREACHED */ 108959243Sobrien return (0); 109059243Sobrien} 109159243Sobrien 109259243Sobrienstatic void 1093167465Smptoend(void) 109459243Sobrien{ 109569408Sache if (whyles->w_end.type == TCSH_F_SEEK && whyles->w_end.f_seek == 0) { 109659243Sobrien search(TC_BREAK, 0, NULL); 109759243Sobrien btell(&whyles->w_end); 109859243Sobrien whyles->w_end.f_seek--; 109959243Sobrien } 110059243Sobrien else { 110159243Sobrien bseek(&whyles->w_end); 110259243Sobrien } 110359243Sobrien wfree(); 110459243Sobrien} 110559243Sobrien 1106131962Smpstatic void 1107167465Smpwpfree(struct whyle *wp) 1108131962Smp{ 1109131962Smp if (wp->w_fe0) 1110131962Smp blkfree(wp->w_fe0); 1111167465Smp xfree(wp->w_fename); 1112167465Smp xfree(wp); 1113131962Smp} 1114131962Smp 111559243Sobrienvoid 1116167465Smpwfree(void) 111759243Sobrien{ 111859243Sobrien struct Ain o; 111959243Sobrien struct whyle *nwp; 112059243Sobrien#ifdef lint 112159243Sobrien nwp = NULL; /* sun lint is dumb! */ 112259243Sobrien#endif 112359243Sobrien 112459243Sobrien#ifdef FDEBUG 1125167465Smp static const char foo[] = "IAFE"; 112659243Sobrien#endif /* FDEBUG */ 112759243Sobrien 112859243Sobrien btell(&o); 112959243Sobrien 113059243Sobrien#ifdef FDEBUG 1131167465Smp xprintf("o->type %c o->a_seek %d o->f_seek %d\n", 113259243Sobrien foo[o.type + 1], o.a_seek, o.f_seek); 113359243Sobrien#endif /* FDEBUG */ 113459243Sobrien 113559243Sobrien for (; whyles; whyles = nwp) { 1136145479Smp struct whyle *wp = whyles; 113759243Sobrien nwp = wp->w_next; 113859243Sobrien 113959243Sobrien#ifdef FDEBUG 1140167465Smp xprintf("start->type %c start->a_seek %d start->f_seek %d\n", 114159243Sobrien foo[wp->w_start.type+1], 114259243Sobrien wp->w_start.a_seek, wp->w_start.f_seek); 1143167465Smp xprintf("end->type %c end->a_seek %d end->f_seek %d\n", 114459243Sobrien foo[wp->w_end.type + 1], wp->w_end.a_seek, wp->w_end.f_seek); 114559243Sobrien#endif /* FDEBUG */ 114659243Sobrien 114759243Sobrien /* 114859243Sobrien * XXX: We free loops that have different seek types. 114959243Sobrien */ 115069408Sache if (wp->w_end.type != TCSH_I_SEEK && wp->w_start.type == wp->w_end.type && 115159243Sobrien wp->w_start.type == o.type) { 115269408Sache if (wp->w_end.type == TCSH_F_SEEK) { 115359243Sobrien if (o.f_seek >= wp->w_start.f_seek && 115459243Sobrien (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek)) 115559243Sobrien break; 115659243Sobrien } 115759243Sobrien else { 115859243Sobrien if (o.a_seek >= wp->w_start.a_seek && 115959243Sobrien (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek)) 116059243Sobrien break; 116159243Sobrien } 116259243Sobrien } 116359243Sobrien 1164131962Smp wpfree(wp); 116559243Sobrien } 116659243Sobrien} 116759243Sobrien 116859243Sobrien/*ARGSUSED*/ 116959243Sobrienvoid 1170167465Smpdoecho(Char **v, struct command *c) 117159243Sobrien{ 117259243Sobrien USE(c); 117359243Sobrien xecho(' ', v); 117459243Sobrien} 117559243Sobrien 117659243Sobrien/*ARGSUSED*/ 117759243Sobrienvoid 1178167465Smpdoglob(Char **v, struct command *c) 117959243Sobrien{ 118059243Sobrien USE(c); 118159243Sobrien xecho(0, v); 118259243Sobrien flush(); 118359243Sobrien} 118459243Sobrien 118559243Sobrienstatic void 1186167465Smpxecho(int sep, Char **v) 118759243Sobrien{ 1188167465Smp Char *cp, **globbed = NULL; 118959243Sobrien int nonl = 0; 119059243Sobrien int echo_style = ECHO_STYLE; 119159243Sobrien struct varent *vp; 119259243Sobrien 119359243Sobrien if ((vp = adrof(STRecho_style)) != NULL && vp->vec != NULL && 119459243Sobrien vp->vec[0] != NULL) { 119559243Sobrien if (Strcmp(vp->vec[0], STRbsd) == 0) 119659243Sobrien echo_style = BSD_ECHO; 119759243Sobrien else if (Strcmp(vp->vec[0], STRsysv) == 0) 119859243Sobrien echo_style = SYSV_ECHO; 119959243Sobrien else if (Strcmp(vp->vec[0], STRboth) == 0) 120059243Sobrien echo_style = BOTH_ECHO; 120159243Sobrien else if (Strcmp(vp->vec[0], STRnone) == 0) 120259243Sobrien echo_style = NONE_ECHO; 120359243Sobrien } 120459243Sobrien 120559243Sobrien v++; 120659243Sobrien if (*v == 0) 120783098Smp goto done; 1208167465Smp if (setintr) { 1209167465Smp int old_pintr_disabled; 1210167465Smp pintr_push_enable(&old_pintr_disabled); 1211167465Smp v = glob_all_or_error(v); 1212167465Smp cleanup_until(&old_pintr_disabled); 1213167465Smp } else { 1214167465Smp v = glob_all_or_error(v); 121559243Sobrien } 1216167465Smp globbed = v; 1217167465Smp if (globbed != NULL) 1218167465Smp cleanup_push(globbed, blk_cleanup); 121959243Sobrien 122059243Sobrien if ((echo_style & BSD_ECHO) != 0 && sep == ' ' && *v && eq(*v, STRmn)) 122159243Sobrien nonl++, v++; 122259243Sobrien 122359243Sobrien while ((cp = *v++) != 0) { 1224145479Smp Char c; 122559243Sobrien 1226167465Smp if (setintr) { 1227167465Smp int old_pintr_disabled; 1228167465Smp 1229167465Smp pintr_push_enable(&old_pintr_disabled); 1230167465Smp cleanup_until(&old_pintr_disabled); 1231167465Smp } 123259243Sobrien while ((c = *cp++) != 0) { 123359243Sobrien if ((echo_style & SYSV_ECHO) != 0 && c == '\\') { 123459243Sobrien switch (c = *cp++) { 123559243Sobrien case 'a': 123659243Sobrien c = '\a'; 123759243Sobrien break; 123859243Sobrien case 'b': 123959243Sobrien c = '\b'; 124059243Sobrien break; 124159243Sobrien case 'c': 124259243Sobrien nonl = 1; 124359243Sobrien goto done; 124459243Sobrien case 'e': 124559243Sobrien#if 0 /* Windows does not understand \e */ 124659243Sobrien c = '\e'; 124759243Sobrien#else 1248167465Smp c = CTL_ESC('\033'); 124959243Sobrien#endif 125059243Sobrien break; 125159243Sobrien case 'f': 125259243Sobrien c = '\f'; 125359243Sobrien break; 125459243Sobrien case 'n': 125559243Sobrien c = '\n'; 125659243Sobrien break; 125759243Sobrien case 'r': 125859243Sobrien c = '\r'; 125959243Sobrien break; 126059243Sobrien case 't': 126159243Sobrien c = '\t'; 126259243Sobrien break; 126359243Sobrien case 'v': 126459243Sobrien c = '\v'; 126559243Sobrien break; 126659243Sobrien case '\\': 126759243Sobrien c = '\\'; 126859243Sobrien break; 126959243Sobrien case '0': 127059243Sobrien c = 0; 127159243Sobrien if (*cp >= '0' && *cp < '8') 127259243Sobrien c = c * 8 + *cp++ - '0'; 127359243Sobrien if (*cp >= '0' && *cp < '8') 127459243Sobrien c = c * 8 + *cp++ - '0'; 127559243Sobrien if (*cp >= '0' && *cp < '8') 127659243Sobrien c = c * 8 + *cp++ - '0'; 127759243Sobrien break; 127859243Sobrien case '\0': 127959243Sobrien c = '\\'; 128059243Sobrien cp--; 128159243Sobrien break; 128259243Sobrien default: 128359243Sobrien xputchar('\\' | QUOTE); 128459243Sobrien break; 128559243Sobrien } 128659243Sobrien } 1287145479Smp xputwchar(c | QUOTE); 128859243Sobrien 128959243Sobrien } 129059243Sobrien if (*v) 129159243Sobrien xputchar(sep | QUOTE); 129259243Sobrien } 129359243Sobriendone: 129459243Sobrien if (sep && nonl == 0) 129559243Sobrien xputchar('\n'); 129659243Sobrien else 129759243Sobrien flush(); 1298167465Smp if (globbed != NULL) 1299167465Smp cleanup_until(globbed); 130059243Sobrien} 130159243Sobrien 130259243Sobrien/* check whether an environment variable should invoke 'set_locale()' */ 1303145479Smpstatic int 1304167465Smpislocale_var(Char *var) 130559243Sobrien{ 130659243Sobrien static Char *locale_vars[] = { 1307131962Smp STRLANG, STRLC_ALL, STRLC_CTYPE, STRLC_NUMERIC, 1308131962Smp STRLC_TIME, STRLC_COLLATE, STRLC_MESSAGES, STRLC_MONETARY, 0 130959243Sobrien }; 1310145479Smp Char **v; 131159243Sobrien 131259243Sobrien for (v = locale_vars; *v; ++v) 131359243Sobrien if (eq(var, *v)) 131459243Sobrien return 1; 131559243Sobrien return 0; 131659243Sobrien} 131759243Sobrien 1318167465Smpstatic void 1319167465Smpxlate_cr_cleanup(void *dummy) 1320167465Smp{ 1321167465Smp USE(dummy); 1322167465Smp xlate_cr = 0; 1323167465Smp} 1324167465Smp 132559243Sobrien/*ARGSUSED*/ 132659243Sobrienvoid 1327167465Smpdoprintenv(Char **v, struct command *c) 132859243Sobrien{ 132959243Sobrien Char *e; 133059243Sobrien 133159243Sobrien USE(c); 133259243Sobrien v++; 133359243Sobrien if (*v == 0) { 1334145479Smp Char **ep; 133559243Sobrien 133659243Sobrien xlate_cr = 1; 1337167465Smp cleanup_push(&xlate_cr, xlate_cr_cleanup); 1338167465Smp for (ep = STR_environ; *ep; ep++) { 1339167465Smp if (setintr) { 1340167465Smp int old_pintr_disabled; 1341167465Smp 1342167465Smp pintr_push_enable(&old_pintr_disabled); 1343167465Smp cleanup_until(&old_pintr_disabled); 1344167465Smp } 134559243Sobrien xprintf("%S\n", *ep); 1346167465Smp } 1347167465Smp cleanup_until(&xlate_cr); 134859243Sobrien } 134959243Sobrien else if ((e = tgetenv(*v)) != NULL) { 1350167465Smp int old_output_raw; 1351167465Smp 1352167465Smp old_output_raw = output_raw; 135359243Sobrien output_raw = 1; 1354167465Smp cleanup_push(&old_output_raw, output_raw_restore); 135559243Sobrien xprintf("%S\n", e); 1356167465Smp cleanup_until(&old_output_raw); 135759243Sobrien } 135859243Sobrien else 1359167465Smp setcopy(STRstatus, STR1, VAR_READWRITE); 136059243Sobrien} 136159243Sobrien 136259243Sobrien/* from "Karl Berry." <karl%mote.umb.edu@relay.cs.net> -- for NeXT things 136359243Sobrien (and anything else with a modern compiler) */ 136459243Sobrien 136559243Sobrien/*ARGSUSED*/ 136659243Sobrienvoid 1367167465Smpdosetenv(Char **v, struct command *c) 136859243Sobrien{ 136959243Sobrien Char *vp, *lp; 137059243Sobrien 137159243Sobrien USE(c); 137259243Sobrien if (*++v == 0) { 137359243Sobrien doprintenv(--v, 0); 137459243Sobrien return; 137559243Sobrien } 137659243Sobrien 137759243Sobrien vp = *v++; 1378232633Smp lp = vp; 137959243Sobrien 1380232633Smp if (!letter(*lp)) 1381232633Smp stderror(ERR_NAME | ERR_VARBEGIN); 1382232633Smp do { 1383232633Smp lp++; 1384232633Smp } while (alnum(*lp)); 1385232633Smp if (*lp != '\0') 1386232633Smp stderror(ERR_NAME | ERR_VARALNUM); 1387232633Smp 138859243Sobrien if ((lp = *v++) == 0) 138959243Sobrien lp = STRNULL; 139059243Sobrien 1391167465Smp lp = globone(lp, G_APPEND); 1392167465Smp cleanup_push(lp, xfree); 1393167465Smp tsetenv(vp, lp); 139459243Sobrien if (eq(vp, STRKPATH)) { 1395167465Smp importpath(lp); 139659243Sobrien dohash(NULL, NULL); 1397167465Smp cleanup_until(lp); 139859243Sobrien return; 139959243Sobrien } 140059243Sobrien 140159243Sobrien#ifdef apollo 140259243Sobrien if (eq(vp, STRSYSTYPE)) { 140359243Sobrien dohash(NULL, NULL); 1404167465Smp cleanup_until(lp); 140559243Sobrien return; 140659243Sobrien } 140759243Sobrien#endif /* apollo */ 140859243Sobrien 140959243Sobrien /* dspkanji/dspmbyte autosetting */ 141059243Sobrien /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */ 141159243Sobrien#if defined(DSPMBYTE) 141259243Sobrien if(eq(vp, STRLANG) && !adrof(CHECK_MBYTEVAR)) { 141359243Sobrien autoset_dspmbyte(lp); 141459243Sobrien } 141559243Sobrien#endif 141659243Sobrien 141759243Sobrien if (islocale_var(vp)) { 141859243Sobrien#ifdef NLS 141959243Sobrien int k; 142059243Sobrien 142159243Sobrien# ifdef SETLOCALEBUG 142259243Sobrien dont_free = 1; 142359243Sobrien# endif /* SETLOCALEBUG */ 142459243Sobrien (void) setlocale(LC_ALL, ""); 142559243Sobrien# ifdef LC_COLLATE 142659243Sobrien (void) setlocale(LC_COLLATE, ""); 142759243Sobrien# endif 1428145479Smp# ifdef LC_CTYPE 1429145479Smp (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 1430145479Smp# endif /* LC_CTYPE */ 1431232633Smp# if defined(AUTOSET_KANJI) 1432232633Smp autoset_kanji(); 1433232633Smp# endif /* AUTOSET_KANJI */ 143459243Sobrien# ifdef NLS_CATALOGS 143559243Sobrien# ifdef LC_MESSAGES 143659243Sobrien (void) setlocale(LC_MESSAGES, ""); 143759243Sobrien# endif /* LC_MESSAGES */ 1438145479Smp nlsclose(); 143959243Sobrien nlsinit(); 144059243Sobrien# endif /* NLS_CATALOGS */ 144159243Sobrien# ifdef SETLOCALEBUG 144259243Sobrien dont_free = 0; 144359243Sobrien# endif /* SETLOCALEBUG */ 144459243Sobrien# ifdef STRCOLLBUG 144559243Sobrien fix_strcoll_bug(); 144659243Sobrien# endif /* STRCOLLBUG */ 144759243Sobrien tw_cmd_free(); /* since the collation sequence has changed */ 1448167465Smp for (k = 0200; k <= 0377 && !Isprint(CTL_ESC(k)); k++) 144959243Sobrien continue; 1450145479Smp AsciiOnly = MB_CUR_MAX == 1 && k > 0377; 145159243Sobrien#else /* !NLS */ 145259243Sobrien AsciiOnly = 0; 145359243Sobrien#endif /* NLS */ 145459243Sobrien NLSMapsAreInited = 0; 145559243Sobrien ed_Init(); 145659243Sobrien if (MapsAreInited && !NLSMapsAreInited) 145759243Sobrien ed_InitNLSMaps(); 1458167465Smp cleanup_until(lp); 145959243Sobrien return; 146059243Sobrien } 146159243Sobrien 1462100616Smp#ifdef NLS_CATALOGS 1463100616Smp if (eq(vp, STRNLSPATH)) { 1464145479Smp nlsclose(); 1465100616Smp nlsinit(); 1466100616Smp } 1467100616Smp#endif 1468100616Smp 146959243Sobrien if (eq(vp, STRNOREBIND)) { 147059243Sobrien NoNLSRebind = 1; 147159243Sobrien MapsAreInited = 0; 147259243Sobrien NLSMapsAreInited = 0; 147359243Sobrien ed_InitMaps(); 1474167465Smp cleanup_until(lp); 147559243Sobrien return; 147659243Sobrien } 147769408Sache#ifdef WINNT_NATIVE 147859243Sobrien if (eq(vp, STRtcshlang)) { 147959243Sobrien nlsinit(); 1480167465Smp cleanup_until(lp); 148159243Sobrien return; 148259243Sobrien } 148369408Sache#endif /* WINNT_NATIVE */ 148459243Sobrien if (eq(vp, STRKTERM)) { 148559243Sobrien char *t; 1486167465Smp 1487167465Smp setv(STRterm, quote(lp), VAR_READWRITE); /* lp memory used here */ 1488167465Smp cleanup_ignore(lp); 1489167465Smp cleanup_until(lp); 149059243Sobrien t = short2str(lp); 149159243Sobrien if (noediting && strcmp(t, "unknown") != 0 && strcmp(t,"dumb") != 0) { 149259243Sobrien editing = 1; 149359243Sobrien noediting = 0; 1494167465Smp setNS(STRedit); 149559243Sobrien } 149659243Sobrien GotTermCaps = 0; 149759243Sobrien ed_Init(); 149859243Sobrien return; 149959243Sobrien } 150059243Sobrien 150159243Sobrien if (eq(vp, STRKHOME)) { 1502167465Smp Char *canon; 150359243Sobrien /* 150459243Sobrien * convert to canonical pathname (possibly resolving symlinks) 150559243Sobrien */ 1506167465Smp canon = dcanon(lp, lp); 1507167465Smp cleanup_ignore(lp); 1508167465Smp cleanup_until(lp); 1509167465Smp cleanup_push(canon, xfree); 1510167465Smp setv(STRhome, quote(canon), VAR_READWRITE); /* lp memory used here */ 1511167465Smp cleanup_ignore(canon); 1512167465Smp cleanup_until(canon); 151359243Sobrien 151459243Sobrien /* fix directory stack for new tilde home */ 151559243Sobrien dtilde(); 151659243Sobrien return; 151759243Sobrien } 151859243Sobrien 151959243Sobrien if (eq(vp, STRKSHLVL)) { 1520167465Smp setv(STRshlvl, quote(lp), VAR_READWRITE); /* lp memory used here */ 1521167465Smp cleanup_ignore(lp); 1522167465Smp cleanup_until(lp); 152359243Sobrien return; 152459243Sobrien } 152559243Sobrien 152659243Sobrien if (eq(vp, STRKUSER)) { 1527167465Smp setv(STRuser, quote(lp), VAR_READWRITE); /* lp memory used here */ 1528167465Smp cleanup_ignore(lp); 1529167465Smp cleanup_until(lp); 153059243Sobrien return; 153159243Sobrien } 153259243Sobrien 153359243Sobrien if (eq(vp, STRKGROUP)) { 1534167465Smp setv(STRgroup, quote(lp), VAR_READWRITE); /* lp memory used here */ 1535167465Smp cleanup_ignore(lp); 1536167465Smp cleanup_until(lp); 153759243Sobrien return; 153859243Sobrien } 153959243Sobrien 154059243Sobrien#ifdef COLOR_LS_F 154159243Sobrien if (eq(vp, STRLS_COLORS)) { 154259243Sobrien parseLS_COLORS(lp); 1543167465Smp cleanup_until(lp); 154459243Sobrien return; 154559243Sobrien } 154659243Sobrien#endif /* COLOR_LS_F */ 154759243Sobrien 154859243Sobrien#ifdef SIG_WINDOW 154959243Sobrien /* 155059243Sobrien * Load/Update $LINES $COLUMNS 155159243Sobrien */ 155259243Sobrien if ((eq(lp, STRNULL) && (eq(vp, STRLINES) || eq(vp, STRCOLUMNS))) || 155359243Sobrien eq(vp, STRTERMCAP)) { 1554167465Smp cleanup_until(lp); 155559243Sobrien check_window_size(1); 155659243Sobrien return; 155759243Sobrien } 155859243Sobrien 155959243Sobrien /* 156059243Sobrien * Change the size to the one directed by $LINES and $COLUMNS 156159243Sobrien */ 156259243Sobrien if (eq(vp, STRLINES) || eq(vp, STRCOLUMNS)) { 156359243Sobrien#if 0 156459243Sobrien GotTermCaps = 0; 156559243Sobrien#endif 1566167465Smp cleanup_until(lp); 156759243Sobrien ed_Init(); 156859243Sobrien return; 156959243Sobrien } 157059243Sobrien#endif /* SIG_WINDOW */ 1571167465Smp cleanup_until(lp); 157259243Sobrien} 157359243Sobrien 157459243Sobrien/*ARGSUSED*/ 157559243Sobrienvoid 1576167465Smpdounsetenv(Char **v, struct command *c) 157759243Sobrien{ 1578167465Smp Char **ep, *p, *n, *name; 157959243Sobrien int i, maxi; 158059243Sobrien 158159243Sobrien USE(c); 158259243Sobrien /* 158359243Sobrien * Find the longest environment variable 158459243Sobrien */ 158559243Sobrien for (maxi = 0, ep = STR_environ; *ep; ep++) { 158659243Sobrien for (i = 0, p = *ep; *p && *p != '='; p++, i++) 158759243Sobrien continue; 158859243Sobrien if (i > maxi) 158959243Sobrien maxi = i; 159059243Sobrien } 159159243Sobrien 1592167465Smp name = xmalloc((maxi + 1) * sizeof(Char)); 1593167465Smp cleanup_push(name, xfree); 159459243Sobrien 159559243Sobrien while (++v && *v) 159659243Sobrien for (maxi = 1; maxi;) 159759243Sobrien for (maxi = 0, ep = STR_environ; *ep; ep++) { 159859243Sobrien for (n = name, p = *ep; *p && *p != '='; *n++ = *p++) 159959243Sobrien continue; 160059243Sobrien *n = '\0'; 160159243Sobrien if (!Gmatch(name, *v)) 160259243Sobrien continue; 160359243Sobrien maxi = 1; 160459243Sobrien 160559243Sobrien /* Unset the name. This wasn't being done until 160659243Sobrien * later but most of the stuff following won't 160759243Sobrien * work (particularly the setlocale() and getenv() 160859243Sobrien * stuff) as intended until the name is actually 160959243Sobrien * removed. (sg) 161059243Sobrien */ 161159243Sobrien Unsetenv(name); 161259243Sobrien 161359243Sobrien if (eq(name, STRNOREBIND)) { 161459243Sobrien NoNLSRebind = 0; 161559243Sobrien MapsAreInited = 0; 161659243Sobrien NLSMapsAreInited = 0; 161759243Sobrien ed_InitMaps(); 161859243Sobrien } 161959243Sobrien#ifdef apollo 162059243Sobrien else if (eq(name, STRSYSTYPE)) 162159243Sobrien dohash(NULL, NULL); 162259243Sobrien#endif /* apollo */ 162359243Sobrien else if (islocale_var(name)) { 162459243Sobrien#ifdef NLS 162559243Sobrien int k; 162659243Sobrien 162759243Sobrien# ifdef SETLOCALEBUG 162859243Sobrien dont_free = 1; 162959243Sobrien# endif /* SETLOCALEBUG */ 163059243Sobrien (void) setlocale(LC_ALL, ""); 163159243Sobrien# ifdef LC_COLLATE 163259243Sobrien (void) setlocale(LC_COLLATE, ""); 163359243Sobrien# endif 1634145479Smp# ifdef LC_CTYPE 1635167465Smp (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 1636145479Smp# endif /* LC_CTYPE */ 163759243Sobrien# ifdef NLS_CATALOGS 163859243Sobrien# ifdef LC_MESSAGES 163959243Sobrien (void) setlocale(LC_MESSAGES, ""); 164059243Sobrien# endif /* LC_MESSAGES */ 1641145479Smp nlsclose(); 164259243Sobrien nlsinit(); 164359243Sobrien# endif /* NLS_CATALOGS */ 164459243Sobrien# ifdef SETLOCALEBUG 164559243Sobrien dont_free = 0; 164659243Sobrien# endif /* SETLOCALEBUG */ 164759243Sobrien# ifdef STRCOLLBUG 164859243Sobrien fix_strcoll_bug(); 164959243Sobrien# endif /* STRCOLLBUG */ 165059243Sobrien tw_cmd_free();/* since the collation sequence has changed */ 1651167465Smp for (k = 0200; k <= 0377 && !Isprint(CTL_ESC(k)); k++) 165259243Sobrien continue; 1653145479Smp AsciiOnly = MB_CUR_MAX == 1 && k > 0377; 165459243Sobrien#else /* !NLS */ 165559243Sobrien AsciiOnly = getenv("LANG") == NULL && 165659243Sobrien getenv("LC_CTYPE") == NULL; 165759243Sobrien#endif /* NLS */ 165859243Sobrien NLSMapsAreInited = 0; 165959243Sobrien ed_Init(); 166059243Sobrien if (MapsAreInited && !NLSMapsAreInited) 166159243Sobrien ed_InitNLSMaps(); 166259243Sobrien 166359243Sobrien } 166469408Sache#ifdef WINNT_NATIVE 166559243Sobrien else if (eq(name,(STRtcshlang))) { 166659243Sobrien nls_dll_unload(); 166759243Sobrien nlsinit(); 166859243Sobrien } 166969408Sache#endif /* WINNT_NATIVE */ 167059243Sobrien#ifdef COLOR_LS_F 167159243Sobrien else if (eq(name, STRLS_COLORS)) 167259243Sobrien parseLS_COLORS(n); 167359243Sobrien#endif /* COLOR_LS_F */ 1674100616Smp#ifdef NLS_CATALOGS 1675100616Smp else if (eq(name, STRNLSPATH)) { 1676145479Smp nlsclose(); 1677100616Smp nlsinit(); 1678100616Smp } 1679100616Smp#endif 168059243Sobrien /* 168159243Sobrien * start again cause the environment changes 168259243Sobrien */ 168359243Sobrien break; 168459243Sobrien } 1685167465Smp cleanup_until(name); 168659243Sobrien} 168759243Sobrien 168859243Sobrienvoid 1689167465Smptsetenv(const Char *name, const Char *val) 169059243Sobrien{ 169159243Sobrien#ifdef SETENV_IN_LIB 169259243Sobrien/* 169359243Sobrien * XXX: This does not work right, since tcsh cannot track changes to 169459243Sobrien * the environment this way. (the builtin setenv without arguments does 169559243Sobrien * not print the right stuff neither does unsetenv). This was for Mach, 169659243Sobrien * it is not needed anymore. 169759243Sobrien */ 169859243Sobrien#undef setenv 1699167465Smp char *cname; 170059243Sobrien 1701167465Smp if (name == NULL) 170259243Sobrien return; 1703167465Smp cname = strsave(short2str(name)); 1704167465Smp setenv(cname, short2str(val), 1); 1705167465Smp xfree(cname); 170659243Sobrien#else /* !SETENV_IN_LIB */ 1707145479Smp Char **ep = STR_environ; 1708145479Smp const Char *ccp; 1709145479Smp Char *cp, *dp; 171059243Sobrien Char *blk[2]; 171159243Sobrien Char **oep = ep; 171259243Sobrien 171369408Sache#ifdef WINNT_NATIVE 1714167465Smp nt_set_env(name,val); 171569408Sache#endif /* WINNT_NATIVE */ 171659243Sobrien for (; *ep; ep++) { 171769408Sache#ifdef WINNT_NATIVE 1718145479Smp for (ccp = name, dp = *ep; *ccp && Tolower(*ccp & TRIM) == Tolower(*dp); 1719145479Smp ccp++, dp++) 172059243Sobrien#else 1721145479Smp for (ccp = name, dp = *ep; *ccp && (*ccp & TRIM) == *dp; ccp++, dp++) 172269408Sache#endif /* WINNT_NATIVE */ 172359243Sobrien continue; 1724145479Smp if (*ccp != 0 || *dp != '=') 172559243Sobrien continue; 172659243Sobrien cp = Strspl(STRequal, val); 1727167465Smp xfree(*ep); 172859243Sobrien *ep = strip(Strspl(name, cp)); 1729167465Smp xfree(cp); 173059243Sobrien blkfree((Char **) environ); 173159243Sobrien environ = short2blk(STR_environ); 173259243Sobrien return; 173359243Sobrien } 173459243Sobrien cp = Strspl(name, STRequal); 173559243Sobrien blk[0] = strip(Strspl(cp, val)); 1736167465Smp xfree(cp); 173759243Sobrien blk[1] = 0; 173859243Sobrien STR_environ = blkspl(STR_environ, blk); 173959243Sobrien blkfree((Char **) environ); 174059243Sobrien environ = short2blk(STR_environ); 1741167465Smp xfree(oep); 174259243Sobrien#endif /* SETENV_IN_LIB */ 174359243Sobrien} 174459243Sobrien 174559243Sobrienvoid 1746167465SmpUnsetenv(Char *name) 174759243Sobrien{ 1748145479Smp Char **ep = STR_environ; 1749145479Smp Char *cp, *dp; 175059243Sobrien Char **oep = ep; 175159243Sobrien 175269408Sache#ifdef WINNT_NATIVE 175359243Sobrien nt_set_env(name,NULL); 175469408Sache#endif /*WINNT_NATIVE */ 175559243Sobrien for (; *ep; ep++) { 175659243Sobrien for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) 175759243Sobrien continue; 175859243Sobrien if (*cp != 0 || *dp != '=') 175959243Sobrien continue; 176059243Sobrien cp = *ep; 176159243Sobrien *ep = 0; 176259243Sobrien STR_environ = blkspl(STR_environ, ep + 1); 176359243Sobrien blkfree((Char **) environ); 176459243Sobrien environ = short2blk(STR_environ); 176559243Sobrien *ep = cp; 1766167465Smp xfree(cp); 1767167465Smp xfree(oep); 176859243Sobrien return; 176959243Sobrien } 177059243Sobrien} 177159243Sobrien 177259243Sobrien/*ARGSUSED*/ 177359243Sobrienvoid 1774167465Smpdoumask(Char **v, struct command *c) 177559243Sobrien{ 1776145479Smp Char *cp = v[1]; 1777145479Smp int i; 177859243Sobrien 177959243Sobrien USE(c); 178059243Sobrien if (cp == 0) { 178159415Sobrien i = (int)umask(0); 178259243Sobrien (void) umask(i); 178359243Sobrien xprintf("%o\n", i); 178459243Sobrien return; 178559243Sobrien } 178659243Sobrien i = 0; 178759243Sobrien while (Isdigit(*cp) && *cp != '8' && *cp != '9') 178859243Sobrien i = i * 8 + *cp++ - '0'; 178959243Sobrien if (*cp || i < 0 || i > 0777) 179059243Sobrien stderror(ERR_NAME | ERR_MASK); 179159243Sobrien (void) umask(i); 179259243Sobrien} 179359243Sobrien 179459243Sobrien#ifndef HAVENOLIMIT 179559243Sobrien# ifndef BSDLIMIT 179659243Sobrien typedef long RLIM_TYPE; 1797145479Smp# ifdef _OSD_POSIX /* BS2000 */ 1798145479Smp# include <ulimit.h> 1799145479Smp# endif 180059243Sobrien# ifndef RLIM_INFINITY 180159243Sobrien# if !defined(_MINIX) && !defined(__clipper__) && !defined(_CRAY) 180259243Sobrien extern RLIM_TYPE ulimit(); 180359243Sobrien# endif /* ! _MINIX && !__clipper__ */ 180459243Sobrien# define RLIM_INFINITY 0x003fffff 180559243Sobrien# define RLIMIT_FSIZE 1 180659243Sobrien# endif /* RLIM_INFINITY */ 180759243Sobrien# ifdef aiws 180859243Sobrien# define toset(a) (((a) == 3) ? 1004 : (a) + 1) 180959243Sobrien# define RLIMIT_DATA 3 181059243Sobrien# define RLIMIT_STACK 1005 181159243Sobrien# else /* aiws */ 181259243Sobrien# define toset(a) ((a) + 1) 181359243Sobrien# endif /* aiws */ 181459243Sobrien# else /* BSDLIMIT */ 1815145479Smp# if (defined(BSD4_4) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) || (HPUXVERSION >= 1100)) && !defined(__386BSD__) 1816100616Smp typedef rlim_t RLIM_TYPE; 181759243Sobrien# else 181859243Sobrien# if defined(SOLARIS2) || (defined(sgi) && SYSVREL > 3) 181959243Sobrien typedef rlim_t RLIM_TYPE; 182059243Sobrien# else 182159243Sobrien# if defined(_SX) 182259243Sobrien typedef long long RLIM_TYPE; 1823100616Smp# else /* !_SX */ 182459243Sobrien typedef unsigned long RLIM_TYPE; 182559243Sobrien# endif /* _SX */ 182659243Sobrien# endif /* SOLARIS2 || (sgi && SYSVREL > 3) */ 182759243Sobrien# endif /* BSD4_4 && !__386BSD__ */ 182859243Sobrien# endif /* BSDLIMIT */ 182959243Sobrien 1830131962Smp# if (HPUXVERSION > 700) && (HPUXVERSION < 1100) && defined(BSDLIMIT) 183159243Sobrien/* Yes hpux8.0 has limits but <sys/resource.h> does not make them public */ 183259243Sobrien/* Yes, we could have defined _KERNEL, and -I/etc/conf/h, but is that better? */ 183359243Sobrien# ifndef RLIMIT_CPU 183459243Sobrien# define RLIMIT_CPU 0 183559243Sobrien# define RLIMIT_FSIZE 1 183659243Sobrien# define RLIMIT_DATA 2 183759243Sobrien# define RLIMIT_STACK 3 183859243Sobrien# define RLIMIT_CORE 4 183959243Sobrien# define RLIMIT_RSS 5 184059243Sobrien# define RLIMIT_NOFILE 6 184159243Sobrien# endif /* RLIMIT_CPU */ 184259243Sobrien# ifndef RLIM_INFINITY 184359243Sobrien# define RLIM_INFINITY 0x7fffffff 184459243Sobrien# endif /* RLIM_INFINITY */ 184559243Sobrien /* 184659243Sobrien * old versions of HP/UX counted limits in 512 bytes 184759243Sobrien */ 184859243Sobrien# ifndef SIGRTMIN 184959243Sobrien# define FILESIZE512 185059243Sobrien# endif /* SIGRTMIN */ 1851131962Smp# endif /* (HPUXVERSION > 700) && (HPUXVERSION < 1100) && BSDLIMIT */ 185259243Sobrien 185359243Sobrien# if SYSVREL > 3 && defined(BSDLIMIT) && !defined(_SX) 185459243Sobrien/* In order to use rusage, we included "/usr/ucbinclude/sys/resource.h" in */ 185559243Sobrien/* sh.h. However, some SVR4 limits are defined in <sys/resource.h>. Rather */ 185659243Sobrien/* than include both and get warnings, we define the extra SVR4 limits here. */ 185783098Smp/* XXX: I don't understand if RLIMIT_AS is defined, why don't we define */ 185883098Smp/* RLIMIT_VMEM based on it? */ 185959243Sobrien# ifndef RLIMIT_VMEM 186059243Sobrien# define RLIMIT_VMEM 6 186159243Sobrien# endif 186259243Sobrien# ifndef RLIMIT_AS 186359243Sobrien# define RLIMIT_AS RLIMIT_VMEM 186459243Sobrien# endif 186559243Sobrien# endif /* SYSVREL > 3 && BSDLIMIT */ 186659243Sobrien 1867232633Smp# if (defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) 1868232633Smp# if defined(RLIMIT_AS) && !defined(RLIMIT_VMEM) 1869232633Smp# define RLIMIT_VMEM RLIMIT_AS 1870232633Smp# endif 1871232633Smp/* 1872232633Smp * Oh well, <asm-generic/resource.h> has it, but <bits/resource.h> does not 1873232633Smp * Linux headers: When the left hand does not know what the right hand does. 1874232633Smp */ 1875232633Smp# if defined(RLIMIT_RTPRIO) && !defined(RLIMIT_RTTIME) 1876232633Smp# define RLIMIT_RTTIME (RLIMIT_RTPRIO + 1) 1877232633Smp# endif 187883098Smp# endif 187983098Smp 188059243Sobrienstruct limits limits[] = 188159243Sobrien{ 188259243Sobrien# ifdef RLIMIT_CPU 188359243Sobrien { RLIMIT_CPU, "cputime", 1, "seconds" }, 188459243Sobrien# endif /* RLIMIT_CPU */ 188559243Sobrien 188659243Sobrien# ifdef RLIMIT_FSIZE 188759243Sobrien# ifndef aiws 188859243Sobrien { RLIMIT_FSIZE, "filesize", 1024, "kbytes" }, 188959243Sobrien# else 189059243Sobrien { RLIMIT_FSIZE, "filesize", 512, "blocks" }, 189159243Sobrien# endif /* aiws */ 189259243Sobrien# endif /* RLIMIT_FSIZE */ 189359243Sobrien 189459243Sobrien# ifdef RLIMIT_DATA 189559243Sobrien { RLIMIT_DATA, "datasize", 1024, "kbytes" }, 189659243Sobrien# endif /* RLIMIT_DATA */ 189759243Sobrien 189859243Sobrien# ifdef RLIMIT_STACK 189959243Sobrien# ifndef aiws 190059243Sobrien { RLIMIT_STACK, "stacksize", 1024, "kbytes" }, 190159243Sobrien# else 190259243Sobrien { RLIMIT_STACK, "stacksize", 1024 * 1024, "kbytes"}, 190359243Sobrien# endif /* aiws */ 190459243Sobrien# endif /* RLIMIT_STACK */ 190559243Sobrien 190659243Sobrien# ifdef RLIMIT_CORE 190759243Sobrien { RLIMIT_CORE, "coredumpsize", 1024, "kbytes" }, 190859243Sobrien# endif /* RLIMIT_CORE */ 190959243Sobrien 191059243Sobrien# ifdef RLIMIT_RSS 191159243Sobrien { RLIMIT_RSS, "memoryuse", 1024, "kbytes" }, 191259243Sobrien# endif /* RLIMIT_RSS */ 191359243Sobrien 191459243Sobrien# ifdef RLIMIT_UMEM 191559243Sobrien { RLIMIT_UMEM, "memoryuse", 1024, "kbytes" }, 191659243Sobrien# endif /* RLIMIT_UMEM */ 191759243Sobrien 191859243Sobrien# ifdef RLIMIT_VMEM 191959243Sobrien { RLIMIT_VMEM, "vmemoryuse", 1024, "kbytes" }, 192059243Sobrien# endif /* RLIMIT_VMEM */ 192159243Sobrien 1922145479Smp# if defined(RLIMIT_HEAP) /* found on BS2000/OSD systems */ 1923145479Smp { RLIMIT_HEAP, "heapsize", 1024, "kbytes" }, 1924145479Smp# endif /* RLIMIT_HEAP */ 1925145479Smp 192659243Sobrien# ifdef RLIMIT_NOFILE 192759243Sobrien { RLIMIT_NOFILE, "descriptors", 1, "" }, 192859243Sobrien# endif /* RLIMIT_NOFILE */ 192959243Sobrien 193059243Sobrien# ifdef RLIMIT_CONCUR 193159243Sobrien { RLIMIT_CONCUR, "concurrency", 1, "thread(s)" }, 193259243Sobrien# endif /* RLIMIT_CONCUR */ 193359243Sobrien 193459243Sobrien# ifdef RLIMIT_MEMLOCK 193559243Sobrien { RLIMIT_MEMLOCK, "memorylocked", 1024, "kbytes" }, 193659243Sobrien# endif /* RLIMIT_MEMLOCK */ 193759243Sobrien 193859243Sobrien# ifdef RLIMIT_NPROC 193959243Sobrien { RLIMIT_NPROC, "maxproc", 1, "" }, 194059243Sobrien# endif /* RLIMIT_NPROC */ 194159243Sobrien 1942100616Smp# if defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE) 194359243Sobrien { RLIMIT_OFILE, "openfiles", 1, "" }, 1944100616Smp# endif /* RLIMIT_OFILE && !defined(RLIMIT_NOFILE) */ 194559243Sobrien 1946100616Smp# ifdef RLIMIT_SBSIZE 1947100616Smp { RLIMIT_SBSIZE, "sbsize", 1, "" }, 1948100616Smp# endif /* RLIMIT_SBSIZE */ 1949100616Smp 1950195609Smp# ifdef RLIMIT_SWAP 1951195609Smp { RLIMIT_SWAP, "swapsize", 1024, "kbytes" }, 1952195609Smp# endif /* RLIMIT_SWAP */ 1953194767Skib 1954232633Smp# ifdef RLIMIT_LOCKS 1955232633Smp { RLIMIT_LOCKS, "maxlocks", 1, "" }, 1956232633Smp# endif /* RLIMIT_LOCKS */ 1957232633Smp 1958232633Smp# ifdef RLIMIT_SIGPENDING 1959232633Smp { RLIMIT_SIGPENDING,"maxsignal", 1, "" }, 1960232633Smp# endif /* RLIMIT_SIGPENDING */ 1961232633Smp 1962232633Smp# ifdef RLIMIT_MSGQUEUE 1963232633Smp { RLIMIT_MSGQUEUE, "maxmessage", 1, "" }, 1964232633Smp# endif /* RLIMIT_MSGQUEUE */ 1965232633Smp 1966232633Smp# ifdef RLIMIT_NICE 1967232633Smp { RLIMIT_NICE, "maxnice", 1, "" }, 1968232633Smp# endif /* RLIMIT_NICE */ 1969232633Smp 1970232633Smp# ifdef RLIMIT_RTPRIO 1971232633Smp { RLIMIT_RTPRIO, "maxrtprio", 1, "" }, 1972232633Smp# endif /* RLIMIT_RTPRIO */ 1973232633Smp 1974232633Smp# ifdef RLIMIT_RTTIME 1975232633Smp { RLIMIT_RTTIME, "maxrttime", 1, "usec" }, 1976232633Smp# endif /* RLIMIT_RTTIME */ 1977232633Smp 197859243Sobrien { -1, NULL, 0, NULL } 197959243Sobrien}; 198059243Sobrien 1981167465Smpstatic struct limits *findlim (Char *); 1982167465Smpstatic RLIM_TYPE getval (struct limits *, Char **); 1983232633Smpstatic int strtail (Char *, const char *); 1984167465Smpstatic void limtail (Char *, const char *); 1985232633Smpstatic void limtail2 (Char *, const char *, const char *); 1986167465Smpstatic void plim (struct limits *, int); 1987167465Smpstatic int setlim (struct limits *, int, RLIM_TYPE); 198859243Sobrien 198959243Sobrien#ifdef convex 199059243Sobrienstatic RLIM_TYPE 1991167465Smprestrict_limit(double value) 199259243Sobrien{ 199359243Sobrien /* 199459243Sobrien * is f too large to cope with? return the maximum or minimum int 199559243Sobrien */ 199659243Sobrien if (value > (double) INT_MAX) 199759243Sobrien return (RLIM_TYPE) INT_MAX; 199859243Sobrien else if (value < (double) INT_MIN) 199959243Sobrien return (RLIM_TYPE) INT_MIN; 200059243Sobrien else 200159243Sobrien return (RLIM_TYPE) value; 200259243Sobrien} 200359243Sobrien#else /* !convex */ 200459243Sobrien# define restrict_limit(x) ((RLIM_TYPE) (x)) 200559243Sobrien#endif /* convex */ 200659243Sobrien 200759243Sobrien 200859243Sobrienstatic struct limits * 2009167465Smpfindlim(Char *cp) 201059243Sobrien{ 2011145479Smp struct limits *lp, *res; 201259243Sobrien 2013167465Smp res = NULL; 201459243Sobrien for (lp = limits; lp->limconst >= 0; lp++) 201559243Sobrien if (prefix(cp, str2short(lp->limname))) { 201659243Sobrien if (res) 201759243Sobrien stderror(ERR_NAME | ERR_AMBIG); 201859243Sobrien res = lp; 201959243Sobrien } 202059243Sobrien if (res) 202159243Sobrien return (res); 202259243Sobrien stderror(ERR_NAME | ERR_LIMIT); 202359243Sobrien /* NOTREACHED */ 202459243Sobrien return (0); 202559243Sobrien} 202659243Sobrien 202759243Sobrien/*ARGSUSED*/ 202859243Sobrienvoid 2029167465Smpdolimit(Char **v, struct command *c) 203059243Sobrien{ 2031145479Smp struct limits *lp; 2032145479Smp RLIM_TYPE limit; 203359243Sobrien int hard = 0; 203459243Sobrien 203559243Sobrien USE(c); 203659243Sobrien v++; 203759243Sobrien if (*v && eq(*v, STRmh)) { 203859243Sobrien hard = 1; 203959243Sobrien v++; 204059243Sobrien } 204159243Sobrien if (*v == 0) { 204259243Sobrien for (lp = limits; lp->limconst >= 0; lp++) 204359243Sobrien plim(lp, hard); 204459243Sobrien return; 204559243Sobrien } 204659243Sobrien lp = findlim(v[0]); 204759243Sobrien if (v[1] == 0) { 204859243Sobrien plim(lp, hard); 204959243Sobrien return; 205059243Sobrien } 205159243Sobrien limit = getval(lp, v + 1); 205259243Sobrien if (setlim(lp, hard, limit) < 0) 205359243Sobrien stderror(ERR_SILENT); 205459243Sobrien} 205559243Sobrien 205659243Sobrienstatic RLIM_TYPE 2057167465Smpgetval(struct limits *lp, Char **v) 205859243Sobrien{ 2059145479Smp float f; 206059243Sobrien Char *cp = *v++; 206159243Sobrien 206259243Sobrien f = atof(short2str(cp)); 206359243Sobrien 206459243Sobrien# ifdef convex 206559243Sobrien /* 206659243Sobrien * is f too large to cope with. limit f to minint, maxint - X-6768 by 206759243Sobrien * strike 206859243Sobrien */ 206959243Sobrien if ((f < (double) INT_MIN) || (f > (double) INT_MAX)) { 207059243Sobrien stderror(ERR_NAME | ERR_TOOLARGE); 207159243Sobrien } 207259243Sobrien# endif /* convex */ 207359243Sobrien 207459243Sobrien while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') 207559243Sobrien cp++; 207659243Sobrien if (*cp == 0) { 207759243Sobrien if (*v == 0) 207869408Sache return restrict_limit((f * lp->limdiv) + 0.5); 207959243Sobrien cp = *v; 208059243Sobrien } 208159243Sobrien switch (*cp) { 208259243Sobrien# ifdef RLIMIT_CPU 208359243Sobrien case ':': 208459243Sobrien if (lp->limconst != RLIMIT_CPU) 208559243Sobrien goto badscal; 208659243Sobrien return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f * 60.0 + atof(short2str(cp + 1)))); 208759243Sobrien case 'h': 208859243Sobrien if (lp->limconst != RLIMIT_CPU) 208959243Sobrien goto badscal; 209059243Sobrien limtail(cp, "hours"); 209159243Sobrien f *= 3600.0; 209259243Sobrien break; 2093232633Smp# endif /* RLIMIT_CPU */ 209459243Sobrien case 'm': 2095232633Smp# ifdef RLIMIT_CPU 209659243Sobrien if (lp->limconst == RLIMIT_CPU) { 209759243Sobrien limtail(cp, "minutes"); 209859243Sobrien f *= 60.0; 209959243Sobrien break; 210059243Sobrien } 2101232633Smp# endif /* RLIMIT_CPU */ 2102232633Smp limtail2(cp, "megabytes", "mbytes"); 210359243Sobrien f *= 1024.0 * 1024.0; 210459243Sobrien break; 2105232633Smp# ifdef RLIMIT_CPU 210659243Sobrien case 's': 210759243Sobrien if (lp->limconst != RLIMIT_CPU) 210859243Sobrien goto badscal; 210959243Sobrien limtail(cp, "seconds"); 211059243Sobrien break; 211159243Sobrien# endif /* RLIMIT_CPU */ 2112232633Smp case 'G': 2113232633Smp *cp = 'g'; 2114232633Smp /*FALLTHROUGH*/ 2115232633Smp case 'g': 2116232633Smp# ifdef RLIMIT_CPU 2117232633Smp if (lp->limconst == RLIMIT_CPU) 2118232633Smp goto badscal; 2119232633Smp# endif /* RLIMIT_CPU */ 2120232633Smp limtail2(cp, "gigabytes", "gbytes"); 2121232633Smp f *= 1024.0 * 1024.0 * 1024.0; 2122232633Smp break; 212359243Sobrien case 'M': 212459243Sobrien# ifdef RLIMIT_CPU 212559243Sobrien if (lp->limconst == RLIMIT_CPU) 212659243Sobrien goto badscal; 212759243Sobrien# endif /* RLIMIT_CPU */ 212859243Sobrien *cp = 'm'; 2129232633Smp limtail2(cp, "megabytes", "mbytes"); 213059243Sobrien f *= 1024.0 * 1024.0; 213159243Sobrien break; 213259243Sobrien case 'k': 213359243Sobrien# ifdef RLIMIT_CPU 213459243Sobrien if (lp->limconst == RLIMIT_CPU) 213559243Sobrien goto badscal; 213659243Sobrien# endif /* RLIMIT_CPU */ 2137232633Smp limtail2(cp, "kilobytes", "kbytes"); 213859243Sobrien f *= 1024.0; 213959243Sobrien break; 214059243Sobrien case 'b': 214159243Sobrien# ifdef RLIMIT_CPU 214259243Sobrien if (lp->limconst == RLIMIT_CPU) 214359243Sobrien goto badscal; 214459243Sobrien# endif /* RLIMIT_CPU */ 214559243Sobrien limtail(cp, "blocks"); 214659243Sobrien f *= 512.0; 214759243Sobrien break; 214859243Sobrien case 'u': 214959243Sobrien limtail(cp, "unlimited"); 215059243Sobrien return ((RLIM_TYPE) RLIM_INFINITY); 215159243Sobrien default: 215259243Sobrien# ifdef RLIMIT_CPU 215359243Sobrienbadscal: 215459243Sobrien# endif /* RLIMIT_CPU */ 215559243Sobrien stderror(ERR_NAME | ERR_SCALEF); 215659243Sobrien } 215759243Sobrien# ifdef convex 215859243Sobrien return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f + 0.5)); 215959243Sobrien# else 216059243Sobrien f += 0.5; 2161232633Smp if (f > (float) ((RLIM_TYPE) RLIM_INFINITY)) 216259243Sobrien return ((RLIM_TYPE) RLIM_INFINITY); 216359243Sobrien else 216459243Sobrien return ((RLIM_TYPE) f); 216559243Sobrien# endif /* convex */ 216659243Sobrien} 216759243Sobrien 2168232633Smpstatic int 2169232633Smpstrtail(Char *cp, const char *str) 2170232633Smp{ 2171232633Smp while (*cp && *cp == (Char)*str) 2172232633Smp cp++, str++; 2173232633Smp return (*cp != '\0'); 2174232633Smp} 2175232633Smp 217659243Sobrienstatic void 2177167465Smplimtail(Char *cp, const char *str) 217859243Sobrien{ 2179232633Smp if (strtail(cp, str)) 2180232633Smp stderror(ERR_BADSCALE, str); 2181232633Smp} 218261515Sobrien 2183232633Smpstatic void 2184232633Smplimtail2(Char *cp, const char *str1, const char *str2) 2185232633Smp{ 2186232633Smp if (strtail(cp, str1) && strtail(cp, str2)) 2187232633Smp stderror(ERR_BADSCALE, str1); 218859243Sobrien} 218959243Sobrien 219059243Sobrien/*ARGSUSED*/ 219159243Sobrienstatic void 2192167465Smpplim(struct limits *lp, int hard) 219359243Sobrien{ 219459243Sobrien# ifdef BSDLIMIT 219559243Sobrien struct rlimit rlim; 219659243Sobrien# endif /* BSDLIMIT */ 219759243Sobrien RLIM_TYPE limit; 2198145479Smp int xdiv = lp->limdiv; 219959243Sobrien 2200131962Smp xprintf("%-13.13s", lp->limname); 220159243Sobrien 220259243Sobrien# ifndef BSDLIMIT 220359243Sobrien limit = ulimit(lp->limconst, 0); 220459243Sobrien# ifdef aiws 220559243Sobrien if (lp->limconst == RLIMIT_DATA) 220659243Sobrien limit -= 0x20000000; 220759243Sobrien# endif /* aiws */ 220859243Sobrien# else /* BSDLIMIT */ 220959243Sobrien (void) getrlimit(lp->limconst, &rlim); 221059243Sobrien limit = hard ? rlim.rlim_max : rlim.rlim_cur; 221159243Sobrien# endif /* BSDLIMIT */ 221259243Sobrien 221359243Sobrien# if !defined(BSDLIMIT) || defined(FILESIZE512) 221459243Sobrien /* 221559243Sobrien * Christos: filesize comes in 512 blocks. we divide by 2 to get 1024 221659243Sobrien * blocks. Note we cannot pre-multiply cause we might overflow (A/UX) 221759243Sobrien */ 221859243Sobrien if (lp->limconst == RLIMIT_FSIZE) { 221959243Sobrien if (limit >= (RLIM_INFINITY / 512)) 222059243Sobrien limit = RLIM_INFINITY; 222159243Sobrien else 2222145479Smp xdiv = (xdiv == 1024 ? 2 : 1); 222359243Sobrien } 222459243Sobrien# endif /* !BSDLIMIT || FILESIZE512 */ 222559243Sobrien 222659243Sobrien if (limit == RLIM_INFINITY) 222759243Sobrien xprintf("unlimited"); 222859243Sobrien else 2229145479Smp# if defined(RLIMIT_CPU) && defined(_OSD_POSIX) 2230145479Smp if (lp->limconst == RLIMIT_CPU && 2231145479Smp (unsigned long)limit >= 0x7ffffffdUL) 2232145479Smp xprintf("unlimited"); 2233145479Smp else 2234145479Smp# endif 223559243Sobrien# ifdef RLIMIT_CPU 223659243Sobrien if (lp->limconst == RLIMIT_CPU) 2237167465Smp psecs(limit); 223859243Sobrien else 223959243Sobrien# endif /* RLIMIT_CPU */ 2240145479Smp xprintf("%ld %s", (long) (limit / xdiv), lp->limscale); 224159243Sobrien xputchar('\n'); 224259243Sobrien} 224359243Sobrien 224459243Sobrien/*ARGSUSED*/ 224559243Sobrienvoid 2246167465Smpdounlimit(Char **v, struct command *c) 224759243Sobrien{ 2248145479Smp struct limits *lp; 224959243Sobrien int lerr = 0; 225059243Sobrien int hard = 0; 225159243Sobrien int force = 0; 225259243Sobrien 225359243Sobrien USE(c); 225459243Sobrien while (*++v && **v == '-') { 225559243Sobrien Char *vp = *v; 225659243Sobrien while (*++vp) 225759243Sobrien switch (*vp) { 225859243Sobrien case 'f': 225959243Sobrien force = 1; 226059243Sobrien break; 226159243Sobrien case 'h': 226259243Sobrien hard = 1; 226359243Sobrien break; 226459243Sobrien default: 226559243Sobrien stderror(ERR_ULIMUS); 226659243Sobrien break; 226759243Sobrien } 226859243Sobrien } 226959243Sobrien 227059243Sobrien if (*v == 0) { 227159243Sobrien for (lp = limits; lp->limconst >= 0; lp++) 227259243Sobrien if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0) 227359243Sobrien lerr++; 227459243Sobrien if (!force && lerr) 227559243Sobrien stderror(ERR_SILENT); 227659243Sobrien return; 227759243Sobrien } 227859243Sobrien while (*v) { 227959243Sobrien lp = findlim(*v++); 228059243Sobrien if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0 && !force) 228159243Sobrien stderror(ERR_SILENT); 228259243Sobrien } 228359243Sobrien} 228459243Sobrien 228559243Sobrienstatic int 2286167465Smpsetlim(struct limits *lp, int hard, RLIM_TYPE limit) 228759243Sobrien{ 228859243Sobrien# ifdef BSDLIMIT 228959243Sobrien struct rlimit rlim; 229059243Sobrien 229159243Sobrien (void) getrlimit(lp->limconst, &rlim); 229259243Sobrien 229359243Sobrien# ifdef FILESIZE512 229459243Sobrien /* Even though hpux has setrlimit(), it expects fsize in 512 byte blocks */ 229559243Sobrien if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 229659243Sobrien limit /= 512; 229759243Sobrien# endif /* FILESIZE512 */ 229859243Sobrien if (hard) 229959243Sobrien rlim.rlim_max = limit; 230059243Sobrien else if (limit == RLIM_INFINITY && euid != 0) 230159243Sobrien rlim.rlim_cur = rlim.rlim_max; 230259243Sobrien else 230359243Sobrien rlim.rlim_cur = limit; 230459243Sobrien 2305100616Smp if (rlim.rlim_cur > rlim.rlim_max) 2306100616Smp rlim.rlim_max = rlim.rlim_cur; 2307100616Smp 230859243Sobrien if (setrlimit(lp->limconst, &rlim) < 0) { 230959243Sobrien# else /* BSDLIMIT */ 231059243Sobrien if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 231159243Sobrien limit /= 512; 231259243Sobrien# ifdef aiws 231359243Sobrien if (lp->limconst == RLIMIT_DATA) 231459243Sobrien limit += 0x20000000; 231559243Sobrien# endif /* aiws */ 231659243Sobrien if (ulimit(toset(lp->limconst), limit) < 0) { 231759243Sobrien# endif /* BSDLIMIT */ 2318145479Smp int err; 2319145479Smp char *op, *type; 2320145479Smp 2321145479Smp err = errno; 2322145479Smp op = strsave(limit == RLIM_INFINITY ? CGETS(15, 2, "remove") : 2323145479Smp CGETS(15, 3, "set")); 2324167465Smp cleanup_push(op, xfree); 2325145479Smp type = strsave(hard ? CGETS(15, 4, " hard") : ""); 2326167465Smp cleanup_push(type, xfree); 2327100616Smp xprintf(CGETS(15, 1, "%s: %s: Can't %s%s limit (%s)\n"), bname, 2328145479Smp lp->limname, op, type, strerror(err)); 2329167465Smp cleanup_until(op); 233059243Sobrien return (-1); 233159243Sobrien } 233259243Sobrien return (0); 233359243Sobrien} 233459243Sobrien 233559243Sobrien#endif /* !HAVENOLIMIT */ 233659243Sobrien 233759243Sobrien/*ARGSUSED*/ 233859243Sobrienvoid 2339167465Smpdosuspend(Char **v, struct command *c) 234059243Sobrien{ 234159243Sobrien#ifdef BSDJOBS 2342167465Smp struct sigaction old; 234359243Sobrien#endif /* BSDJOBS */ 2344195609Smp 234559243Sobrien USE(c); 234659243Sobrien USE(v); 234759243Sobrien 234859243Sobrien if (loginsh) 234959243Sobrien stderror(ERR_SUSPLOG); 235059243Sobrien untty(); 235159243Sobrien 235259243Sobrien#ifdef BSDJOBS 2353167465Smp sigaction(SIGTSTP, NULL, &old); 2354167465Smp signal(SIGTSTP, SIG_DFL); 235559243Sobrien (void) kill(0, SIGTSTP); 235659243Sobrien /* the shell stops here */ 2357167465Smp sigaction(SIGTSTP, &old, NULL); 235859243Sobrien#else /* !BSDJOBS */ 235959243Sobrien stderror(ERR_JOBCONTROL); 236059243Sobrien#endif /* BSDJOBS */ 236159243Sobrien 236259243Sobrien#ifdef BSDJOBS 236359243Sobrien if (tpgrp != -1) { 2364195609Smp if (grabpgrp(FSHTTY, opgrp) == -1) 2365131962Smp stderror(ERR_SYSTEM, "tcgetpgrp", strerror(errno)); 236659243Sobrien (void) setpgid(0, shpgrp); 236759243Sobrien (void) tcsetpgrp(FSHTTY, shpgrp); 236859243Sobrien } 236959243Sobrien#endif /* BSDJOBS */ 237059243Sobrien (void) setdisc(FSHTTY); 237159243Sobrien} 237259243Sobrien 237359243Sobrien/* This is the dreaded EVAL built-in. 237459243Sobrien * If you don't fiddle with file descriptors, and reset didfds, 237559243Sobrien * this command will either ignore redirection inside or outside 237659243Sobrien * its arguments, e.g. eval "date >x" vs. eval "date" >x 237759243Sobrien * The stuff here seems to work, but I did it by trial and error rather 237859243Sobrien * than really knowing what was going on. If tpgrp is zero, we are 237959243Sobrien * probably a background eval, e.g. "eval date &", and we want to 238059243Sobrien * make sure that any processes we start stay in our pgrp. 238159243Sobrien * This is also the case for "time eval date" -- stay in same pgrp. 238259243Sobrien * Otherwise, under stty tostop, processes will stop in the wrong 238359243Sobrien * pgrp, with no way for the shell to get them going again. -IAN! 238459243Sobrien */ 238559243Sobrien 2386167465Smpstruct doeval_state 238759243Sobrien{ 2388167465Smp Char **evalvec, *evalp; 2389167465Smp int didfds; 239059243Sobrien#ifndef CLOSE_ON_EXEC 2391167465Smp int didcch; 2392167465Smp#endif 2393167465Smp int saveIN, saveOUT, saveDIAG; 2394167465Smp int SHIN, SHOUT, SHDIAG; 2395167465Smp}; 239659243Sobrien 2397167465Smpstatic void 2398167465Smpdoeval_cleanup(void *xstate) 2399167465Smp{ 2400167465Smp struct doeval_state *state; 2401167465Smp 2402167465Smp state = xstate; 2403167465Smp evalvec = state->evalvec; 2404167465Smp evalp = state->evalp; 2405167465Smp doneinp = 0; 240659243Sobrien#ifndef CLOSE_ON_EXEC 2407167465Smp didcch = state->didcch; 240859243Sobrien#endif /* CLOSE_ON_EXEC */ 2409167465Smp didfds = state->didfds; 2410167465Smp xclose(SHIN); 2411167465Smp xclose(SHOUT); 2412167465Smp xclose(SHDIAG); 2413167465Smp close_on_exec(SHIN = dmove(state->saveIN, state->SHIN), 1); 2414167465Smp close_on_exec(SHOUT = dmove(state->saveOUT, state->SHOUT), 1); 2415167465Smp close_on_exec(SHDIAG = dmove(state->saveDIAG, state->SHDIAG), 1); 2416167465Smp} 241759243Sobrien 2418195609Smpstatic Char **Ggv; 2419167465Smp/*ARGSUSED*/ 2420167465Smpvoid 2421167465Smpdoeval(Char **v, struct command *c) 2422167465Smp{ 2423167465Smp struct doeval_state state; 2424195609Smp int gflag, my_reenter; 2425167465Smp Char **gv; 2426195609Smp jmp_buf_t osetexit; 242759243Sobrien 2428167465Smp USE(c); 2429167465Smp v++; 2430167465Smp if (*v == 0) 243159243Sobrien return; 2432167465Smp gflag = tglob(v); 243359243Sobrien if (gflag) { 2434167465Smp gv = v = globall(v, gflag); 2435167465Smp if (v == 0) 243659243Sobrien stderror(ERR_NOMATCH); 2437167465Smp cleanup_push(gv, blk_cleanup); 2438167465Smp v = copyblk(v); 243959243Sobrien } 244059243Sobrien else { 244159243Sobrien gv = NULL; 2442167465Smp v = copyblk(v); 2443167465Smp trim(v); 244459243Sobrien } 244559243Sobrien 2446195609Smp Ggv = gv; 2447167465Smp state.evalvec = evalvec; 2448167465Smp state.evalp = evalp; 2449167465Smp state.didfds = didfds; 245059243Sobrien#ifndef CLOSE_ON_EXEC 2451167465Smp state.didcch = didcch; 245259243Sobrien#endif /* CLOSE_ON_EXEC */ 2453167465Smp state.SHIN = SHIN; 2454167465Smp state.SHOUT = SHOUT; 2455167465Smp state.SHDIAG = SHDIAG; 245659243Sobrien 2457167465Smp (void)close_on_exec(state.saveIN = dcopy(SHIN, -1), 1); 2458167465Smp (void)close_on_exec(state.saveOUT = dcopy(SHOUT, -1), 1); 2459167465Smp (void)close_on_exec(state.saveDIAG = dcopy(SHDIAG, -1), 1); 2460167465Smp 2461167465Smp cleanup_push(&state, doeval_cleanup); 2462167465Smp 2463195609Smp getexit(osetexit); 2464195609Smp 2465195609Smp /* PWP: setjmp/longjmp bugfix for optimizing compilers */ 2466195609Smp#ifdef cray 2467195609Smp my_reenter = 1; /* assume non-zero return val */ 2468195609Smp if (setexit() == 0) { 2469195609Smp my_reenter = 0; /* Oh well, we were wrong */ 2470195609Smp#else /* !cray */ 2471195609Smp if ((my_reenter = setexit()) == 0) { 2472195609Smp#endif /* cray */ 2473195609Smp evalvec = v; 2474195609Smp evalp = 0; 2475195609Smp (void)close_on_exec(SHIN = dcopy(0, -1), 1); 2476195609Smp (void)close_on_exec(SHOUT = dcopy(1, -1), 1); 2477195609Smp (void)close_on_exec(SHDIAG = dcopy(2, -1), 1); 247859243Sobrien#ifndef CLOSE_ON_EXEC 2479195609Smp didcch = 0; 248059243Sobrien#endif /* CLOSE_ON_EXEC */ 2481195609Smp didfds = 0; 2482195609Smp gv = Ggv; 2483195609Smp process(0); 2484195609Smp Ggv = gv; 2485195609Smp } 248659243Sobrien 2487195609Smp if (my_reenter == 0) { 2488195609Smp cleanup_until(&state); 2489195609Smp if (Ggv) 2490195609Smp cleanup_until(Ggv); 2491195609Smp } 2492167465Smp 2493195609Smp resexit(osetexit); 2494195609Smp if (my_reenter) 2495195609Smp stderror(ERR_SILENT); 249659243Sobrien} 249759243Sobrien 249859243Sobrien/*************************************************************************/ 249959243Sobrien/* print list of builtin commands */ 250059243Sobrien 2501167465Smpstatic void 2502167465Smplbuffed_cleanup (void *dummy) 2503167465Smp{ 2504167465Smp USE(dummy); 2505167465Smp lbuffed = 1; 2506167465Smp} 2507167465Smp 250859243Sobrien/*ARGSUSED*/ 250959243Sobrienvoid 2510167465Smpdobuiltins(Char **v, struct command *c) 251159243Sobrien{ 251259243Sobrien /* would use print_by_column() in tw.parse.c but that assumes 251359243Sobrien * we have an array of Char * to pass.. (sg) 251459243Sobrien */ 2515167465Smp const struct biltins *b; 2516145479Smp int row, col, columns, rows; 251759243Sobrien unsigned int w, maxwidth; 251859243Sobrien 251959243Sobrien USE(c); 252059243Sobrien USE(v); 252159243Sobrien lbuffed = 0; /* turn off line buffering */ 2522167465Smp cleanup_push(&lbuffed, lbuffed_cleanup); 252359243Sobrien 252459243Sobrien /* find widest string */ 252559243Sobrien for (maxwidth = 0, b = bfunc; b < &bfunc[nbfunc]; ++b) 252659243Sobrien maxwidth = max(maxwidth, strlen(b->bname)); 252759243Sobrien ++maxwidth; /* for space */ 252859243Sobrien 252959243Sobrien columns = (TermH + 1) / maxwidth; /* PWP: terminal size change */ 253059243Sobrien if (!columns) 253159243Sobrien columns = 1; 253259243Sobrien rows = (nbfunc + (columns - 1)) / columns; 253359243Sobrien 253459243Sobrien for (b = bfunc, row = 0; row < rows; row++) { 253559243Sobrien for (col = 0; col < columns; col++) { 253659243Sobrien if (b < &bfunc[nbfunc]) { 253759243Sobrien w = strlen(b->bname); 253859243Sobrien xprintf("%s", b->bname); 253959243Sobrien if (col < (columns - 1)) /* Not last column? */ 254059243Sobrien for (; w < maxwidth; w++) 254159243Sobrien xputchar(' '); 254259243Sobrien ++b; 254359243Sobrien } 254459243Sobrien } 254559243Sobrien if (row < (rows - 1)) { 254659243Sobrien if (Tty_raw_mode) 254759243Sobrien xputchar('\r'); 254859243Sobrien xputchar('\n'); 254959243Sobrien } 255059243Sobrien } 255169408Sache#ifdef WINNT_NATIVE 255259243Sobrien nt_print_builtins(maxwidth); 255359243Sobrien#else 255459243Sobrien if (Tty_raw_mode) 255559243Sobrien xputchar('\r'); 255659243Sobrien xputchar('\n'); 255769408Sache#endif /* WINNT_NATIVE */ 255859243Sobrien 2559167465Smp cleanup_until(&lbuffed); /* turn back on line buffering */ 256059243Sobrien flush(); 256159243Sobrien} 256259243Sobrien 2563145479Smp#ifdef NLS_CATALOGS 2564145479Smpchar * 2565167465Smpxcatgets(nl_catd ctd, int set_id, int msg_id, const char *s) 2566145479Smp{ 2567167465Smp char *res; 2568167465Smp 2569167465Smp errno = 0; 2570167465Smp while ((res = catgets(ctd, set_id, msg_id, s)) == s && errno == EINTR) { 2571167465Smp handle_pending_signals(); 2572167465Smp errno = 0; 2573167465Smp } 2574167465Smp return res; 2575167465Smp} 2576167465Smp 2577167465Smp 2578167465Smp# if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2579167465Smpchar * 2580167465Smpiconv_catgets(nl_catd ctd, int set_id, int msg_id, const char *s) 2581167465Smp{ 2582145479Smp static char *buf = NULL; 2583145479Smp static size_t buf_size = 0; 2584145479Smp 2585145479Smp char *orig, *dest, *p; 2586167465Smp ICONV_CONST char *src; 2587145479Smp size_t src_size, dest_size; 2588145479Smp 2589167465Smp orig = xcatgets(ctd, set_id, msg_id, s); 2590145479Smp if (catgets_iconv == (iconv_t)-1 || orig == s) 2591145479Smp return orig; 2592145479Smp src = orig; 2593145479Smp src_size = strlen(src) + 1; 2594145479Smp if (buf == NULL && (buf = xmalloc(buf_size = src_size + 32)) == NULL) 2595145479Smp return orig; 2596145479Smp dest = buf; 2597145479Smp while (src_size != 0) { 2598145479Smp dest_size = buf + buf_size - dest; 2599145479Smp if (iconv(catgets_iconv, &src, &src_size, &dest, &dest_size) 2600145479Smp == (size_t)-1) { 2601145479Smp switch (errno) { 2602145479Smp case E2BIG: 2603145479Smp if ((p = xrealloc(buf, buf_size * 2)) == NULL) 2604145479Smp return orig; 2605145479Smp buf_size *= 2; 2606145479Smp dest = p + (dest - buf); 2607145479Smp buf = p; 2608145479Smp break; 2609145479Smp 2610145479Smp case EILSEQ: case EINVAL: default: 2611145479Smp return orig; 2612145479Smp } 2613145479Smp } 2614145479Smp } 2615145479Smp return buf; 2616145479Smp} 2617167465Smp# endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2618167465Smp#endif /* NLS_CATALOGS */ 2619145479Smp 262059243Sobrienvoid 2621167465Smpnlsinit(void) 262259243Sobrien{ 262359243Sobrien#ifdef NLS_CATALOGS 2624167465Smp static const char default_catalog[] = "tcsh"; 262569408Sache 2626167465Smp char *catalog = (char *)(intptr_t)default_catalog; 2627167465Smp 262869408Sache if (adrof(STRcatalog) != NULL) 2629167465Smp catalog = xasprintf("tcsh.%s", short2str(varval(STRcatalog))); 2630232633Smp#ifdef NL_CAT_LOCALE /* POSIX-compliant. */ 2631232633Smp /* 2632232633Smp * Check if LC_MESSAGES is set in the environment and use it, if so. 2633232633Smp * If not, fall back to the setting of LANG. 2634232633Smp */ 2635232633Smp catd = catopen(catalog, tgetenv(STRLC_MESSAGES) ? NL_CAT_LOCALE : 0); 2636232633Smp#else /* pre-POSIX */ 2637232633Smp# ifndef MCLoadBySet 2638232633Smp# define MCLoadBySet 0 2639232633Smp# endif 264069408Sache catd = catopen(catalog, MCLoadBySet); 2641232633Smp#endif 2642167465Smp if (catalog != default_catalog) 2643167465Smp xfree(catalog); 2644167465Smp#if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2645167465Smp /* xcatgets (), not CGETS, the charset name should be in ASCII anyway. */ 2646145479Smp catgets_iconv = iconv_open (nl_langinfo (CODESET), 2647232633Smp xcatgets(catd, 255, 1, "UTF-8")); 2648167465Smp#endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 264969408Sache#endif /* NLS_CATALOGS */ 265069408Sache#ifdef WINNT_NATIVE 265159243Sobrien nls_dll_init(); 265269408Sache#endif /* WINNT_NATIVE */ 265359243Sobrien errinit(); /* init the errorlist in correct locale */ 265459243Sobrien mesginit(); /* init the messages for signals */ 265559243Sobrien dateinit(); /* init the messages for dates */ 265659243Sobrien editinit(); /* init the editor messages */ 265759243Sobrien terminit(); /* init the termcap messages */ 265859243Sobrien} 2659145479Smp 2660145479Smpvoid 2661167465Smpnlsclose(void) 2662145479Smp{ 2663145479Smp#ifdef NLS_CATALOGS 2664167465Smp#if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2665145479Smp if (catgets_iconv != (iconv_t)-1) { 2666145479Smp iconv_close(catgets_iconv); 2667145479Smp catgets_iconv = (iconv_t)-1; 2668145479Smp } 2669167465Smp#endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2670167465Smp if (catd != (nl_catd)-1) { 2671167465Smp /* 2672167465Smp * catclose can call other functions which can call longjmp 2673167465Smp * making us re-enter this code. Prevent infinite recursion 2674167465Smp * by resetting catd. Problem reported and solved by: 2675167465Smp * Gerhard Niklasch 2676167465Smp */ 2677167465Smp nl_catd oldcatd = catd; 2678167465Smp catd = (nl_catd)-1; 2679167465Smp while (catclose(oldcatd) == -1 && errno == EINTR) 2680167465Smp handle_pending_signals(); 2681167465Smp } 2682145479Smp#endif /* NLS_CATALOGS */ 2683145479Smp} 2684