sh.func.c revision 194767
1167465Smp/* $Header: /p/tcsh/cvsroot/tcsh/sh.func.c,v 3.143 2006/08/24 20:56:31 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 35167465SmpRCSID("$tcsh: sh.func.c,v 3.143 2006/08/24 20:56:31 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 44167465Smp#if defined (NLS_CATALOGS) && defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 45145479Smp#include <langinfo.h> 46145479Smpstatic iconv_t catgets_iconv; /* Or (iconv_t)-1 */ 47145479Smp#endif 48145479Smp 4959243Sobrien/* 5059243Sobrien * C shell 5159243Sobrien */ 5259243Sobrien 53145479Smpextern int MapsAreInited; 54145479Smpextern int NLSMapsAreInited; 55145479Smpextern int GotTermCaps; 5659243Sobrien 5759243Sobrienstatic int zlast = -1; 5859243Sobrien 59167465Smpstatic void islogin (void); 60167465Smpstatic void preread (void); 61167465Smpstatic void doagain (void); 62167465Smpstatic const char *isrchx (int); 63167465Smpstatic void search (int, int, Char *); 64167465Smpstatic int getword (struct Strbuf *); 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++; 52259243Sobrien sp = cp = strip(*v); 52359243Sobrien if (!letter(*sp)) 52459243Sobrien stderror(ERR_NAME | ERR_VARBEGIN); 52559243Sobrien while (*cp && alnum(*cp)) 52659243Sobrien cp++; 52759243Sobrien if (*cp) 52859243Sobrien stderror(ERR_NAME | ERR_VARALNUM); 52959243Sobrien cp = *v++; 53059243Sobrien if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') 53159243Sobrien stderror(ERR_NAME | ERR_NOPAREN); 53259243Sobrien v++; 533167465Smp gflag = tglob(v); 53459243Sobrien if (gflag) { 535167465Smp v = globall(v, gflag); 536167465Smp if (v == 0 && !noexec) 53759243Sobrien stderror(ERR_NAME | ERR_NOMATCH); 53859243Sobrien } 53959243Sobrien else { 540167465Smp v = saveblk(v); 54159243Sobrien trim(v); 54259243Sobrien } 543167465Smp nwp = xcalloc(1, sizeof *nwp); 54459243Sobrien nwp->w_fe = nwp->w_fe0 = v; 54559243Sobrien btell(&nwp->w_start); 54659243Sobrien nwp->w_fename = Strsave(cp); 54759243Sobrien nwp->w_next = whyles; 54869408Sache nwp->w_end.type = TCSH_F_SEEK; 54959243Sobrien whyles = nwp; 55059243Sobrien /* 55159243Sobrien * Pre-read the loop so as to be more comprehensible to a terminal user. 55259243Sobrien */ 55359243Sobrien zlast = TC_FOREACH; 55459243Sobrien if (intty) 55559243Sobrien preread(); 556167465Smp if (!noexec) 557167465Smp doagain(); 55859243Sobrien} 55959243Sobrien 56059243Sobrien/*ARGSUSED*/ 56159243Sobrienvoid 562167465Smpdowhile(Char **v, struct command *c) 56359243Sobrien{ 564145479Smp int status; 565145479Smp int again = whyles != 0 && 56659243Sobrien SEEKEQ(&whyles->w_start, &lineloc) && 56759243Sobrien whyles->w_fename == 0; 56859243Sobrien 56959243Sobrien USE(c); 57059243Sobrien v++; 57159243Sobrien /* 57259243Sobrien * Implement prereading here also, taking care not to evaluate the 57359243Sobrien * expression before the loop has been read up from a terminal. 57459243Sobrien */ 575167465Smp if (noexec) 576167465Smp status = 0; 577167465Smp else if (intty && !again) 57859243Sobrien status = !exp0(&v, 1); 57959243Sobrien else 58059243Sobrien status = !expr(&v); 581167465Smp if (*v && !noexec) 58259243Sobrien stderror(ERR_NAME | ERR_EXPRESSION); 58359243Sobrien if (!again) { 584167465Smp struct whyle *nwp = xcalloc(1, sizeof(*nwp)); 58559243Sobrien 58659243Sobrien nwp->w_start = lineloc; 58769408Sache nwp->w_end.type = TCSH_F_SEEK; 58859243Sobrien nwp->w_end.f_seek = 0; 58959243Sobrien nwp->w_next = whyles; 59059243Sobrien whyles = nwp; 59159243Sobrien zlast = TC_WHILE; 59259243Sobrien if (intty) { 59359243Sobrien /* 59459243Sobrien * The tty preread 59559243Sobrien */ 59659243Sobrien preread(); 59759243Sobrien doagain(); 59859243Sobrien return; 59959243Sobrien } 60059243Sobrien } 60159243Sobrien if (status) 60259243Sobrien /* We ain't gonna loop no more, no more! */ 60359243Sobrien toend(); 60459243Sobrien} 60559243Sobrien 60659243Sobrienstatic void 607167465Smppreread(void) 60859243Sobrien{ 609167465Smp int old_pintr_disabled; 610167465Smp 61169408Sache whyles->w_end.type = TCSH_I_SEEK; 61259243Sobrien if (setintr) 613167465Smp pintr_push_enable(&old_pintr_disabled); 61459243Sobrien search(TC_BREAK, 0, NULL); /* read the expression in */ 61559243Sobrien if (setintr) 616167465Smp cleanup_until(&old_pintr_disabled); 61759243Sobrien btell(&whyles->w_end); 61859243Sobrien} 61959243Sobrien 62059243Sobrien/*ARGSUSED*/ 62159243Sobrienvoid 622167465Smpdoend(Char **v, struct command *c) 62359243Sobrien{ 62459243Sobrien USE(v); 62559243Sobrien USE(c); 62659243Sobrien if (!whyles) 62759243Sobrien stderror(ERR_NAME | ERR_NOTWHILE); 62859243Sobrien btell(&whyles->w_end); 629167465Smp if (!noexec) 630167465Smp doagain(); 63159243Sobrien} 63259243Sobrien 63359243Sobrien/*ARGSUSED*/ 63459243Sobrienvoid 635167465Smpdocontin(Char **v, struct command *c) 63659243Sobrien{ 63759243Sobrien USE(v); 63859243Sobrien USE(c); 63959243Sobrien if (!whyles) 64059243Sobrien stderror(ERR_NAME | ERR_NOTWHILE); 641167465Smp if (!noexec) 642167465Smp doagain(); 64359243Sobrien} 64459243Sobrien 64559243Sobrienstatic void 646167465Smpdoagain(void) 64759243Sobrien{ 64859243Sobrien /* Repeating a while is simple */ 64959243Sobrien if (whyles->w_fename == 0) { 65059243Sobrien bseek(&whyles->w_start); 65159243Sobrien return; 65259243Sobrien } 65359243Sobrien /* 65459243Sobrien * The foreach variable list actually has a spurious word ")" at the end of 65559243Sobrien * the w_fe list. Thus we are at the of the list if one word beyond this 65659243Sobrien * is 0. 65759243Sobrien */ 65859243Sobrien if (!whyles->w_fe[1]) { 65959243Sobrien dobreak(NULL, NULL); 66059243Sobrien return; 66159243Sobrien } 662167465Smp setv(whyles->w_fename, quote(Strsave(*whyles->w_fe++)), VAR_READWRITE); 66359243Sobrien bseek(&whyles->w_start); 66459243Sobrien} 66559243Sobrien 66659243Sobrienvoid 667167465Smpdorepeat(Char **v, struct command *kp) 66859243Sobrien{ 669100616Smp int i = 1; 67059243Sobrien 671100616Smp do { 672100616Smp i *= getn(v[1]); 673100616Smp lshift(v, 2); 674100616Smp } while (v[0] != NULL && Strcmp(v[0], STRrepeat) == 0); 675167465Smp if (noexec) 676167465Smp i = 1; 677100616Smp 678167465Smp if (setintr) { 679167465Smp pintr_disabled++; 680167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 681167465Smp } 68259243Sobrien while (i > 0) { 683167465Smp if (setintr && pintr_disabled == 1) { 684167465Smp cleanup_until(&pintr_disabled); 685167465Smp pintr_disabled++; 686167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 687167465Smp } 68859243Sobrien reexecute(kp); 68959243Sobrien --i; 69059243Sobrien } 691167465Smp cleanup_until(&pintr_disabled); 69259243Sobrien donefds(); 69359243Sobrien} 69459243Sobrien 69559243Sobrien/*ARGSUSED*/ 69659243Sobrienvoid 697167465Smpdoswbrk(Char **v, struct command *c) 69859243Sobrien{ 69959243Sobrien USE(v); 70059243Sobrien USE(c); 701167465Smp if (!noexec) 702167465Smp search(TC_BRKSW, 0, NULL); 70359243Sobrien} 70459243Sobrien 70559243Sobrienint 706167465Smpsrchx(Char *cp) 70759243Sobrien{ 70859243Sobrien struct srch *sp, *sp1, *sp2; 70959243Sobrien int i; 71059243Sobrien 71159243Sobrien /* 71259243Sobrien * Ignore keywords inside heredocs 71359243Sobrien */ 71459243Sobrien if (inheredoc) 71559243Sobrien return -1; 71659243Sobrien 71759243Sobrien /* 71859243Sobrien * Binary search Sp1 is the beginning of the current search range. Sp2 is 71959243Sobrien * one past the end. 72059243Sobrien */ 72159243Sobrien for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) { 72259243Sobrien sp = sp1 + ((sp2 - sp1) >> 1); 72359243Sobrien if ((i = *cp - *sp->s_name) == 0 && 72459243Sobrien (i = Strcmp(cp, str2short(sp->s_name))) == 0) 72559243Sobrien return sp->s_value; 72659243Sobrien if (i < 0) 72759243Sobrien sp2 = sp; 72859243Sobrien else 72959243Sobrien sp1 = sp + 1; 73059243Sobrien } 73159243Sobrien return (-1); 73259243Sobrien} 73359243Sobrien 734145479Smpstatic const char * 735167465Smpisrchx(int n) 73659243Sobrien{ 737145479Smp struct srch *sp, *sp2; 73859243Sobrien 73959243Sobrien for (sp = srchn, sp2 = srchn + nsrchn; sp < sp2; sp++) 74059243Sobrien if (sp->s_value == n) 74159243Sobrien return (sp->s_name); 74259243Sobrien return (""); 74359243Sobrien} 74459243Sobrien 74559243Sobrien 746167465Smpstatic int Stype; 74759243Sobrienstatic Char *Sgoal; 74859243Sobrien 74959243Sobrienstatic void 750167465Smpsearch(int type, int level, Char *goal) 75159243Sobrien{ 752167465Smp struct Strbuf word = Strbuf_INIT; 753145479Smp Char *cp; 754131962Smp struct whyle *wp; 755131962Smp int wlevel = 0; 75659243Sobrien 757167465Smp Stype = type; 75859243Sobrien Sgoal = goal; 75959243Sobrien if (type == TC_GOTO) { 76059243Sobrien struct Ain a; 76169408Sache a.type = TCSH_F_SEEK; 76259243Sobrien a.f_seek = 0; 76359243Sobrien bseek(&a); 76459243Sobrien } 765167465Smp cleanup_push(&word, Strbuf_cleanup); 76659243Sobrien do { 76769408Sache if (intty && fseekp == feobp && aret == TCSH_F_SEEK) 76859243Sobrien printprompt(1, isrchx(type == TC_BREAK ? zlast : type)); 76959243Sobrien /* xprintf("? "), flush(); */ 770167465Smp (void) getword(&word); 771167465Smp Strbuf_terminate(&word); 772167465Smp switch (srchx(word.s)) { 77359243Sobrien 77459243Sobrien case TC_ELSE: 77559243Sobrien if (level == 0 && type == TC_IF) 776167465Smp goto end; 77759243Sobrien break; 77859243Sobrien 77959243Sobrien case TC_IF: 780167465Smp while (getword(&word)) 78159243Sobrien continue; 78259243Sobrien if ((type == TC_IF || type == TC_ELSE) && 783167465Smp eq(word.s, STRthen)) 78459243Sobrien level++; 78559243Sobrien break; 78659243Sobrien 78759243Sobrien case TC_ENDIF: 78859243Sobrien if (type == TC_IF || type == TC_ELSE) 78959243Sobrien level--; 79059243Sobrien break; 79159243Sobrien 79259243Sobrien case TC_FOREACH: 79359243Sobrien case TC_WHILE: 794131962Smp wlevel++; 79559243Sobrien if (type == TC_BREAK) 79659243Sobrien level++; 79759243Sobrien break; 79859243Sobrien 79959243Sobrien case TC_END: 800131962Smp if (type == TC_BRKSW) { 801131962Smp if (wlevel == 0) { 802131962Smp wp = whyles; 803131962Smp if (wp) { 804131962Smp whyles = wp->w_next; 805131962Smp wpfree(wp); 806131962Smp } 807131962Smp } 808131962Smp } 80959243Sobrien if (type == TC_BREAK) 81059243Sobrien level--; 811131962Smp wlevel--; 81259243Sobrien break; 81359243Sobrien 81459243Sobrien case TC_SWITCH: 81559243Sobrien if (type == TC_SWITCH || type == TC_BRKSW) 81659243Sobrien level++; 81759243Sobrien break; 81859243Sobrien 81959243Sobrien case TC_ENDSW: 82059243Sobrien if (type == TC_SWITCH || type == TC_BRKSW) 82159243Sobrien level--; 82259243Sobrien break; 82359243Sobrien 82459243Sobrien case TC_LABEL: 825167465Smp if (type == TC_GOTO && getword(&word) && eq(word.s, goal)) 82659243Sobrien level = -1; 82759243Sobrien break; 82859243Sobrien 82959243Sobrien default: 83059243Sobrien if (type != TC_GOTO && (type != TC_SWITCH || level != 0)) 83159243Sobrien break; 832167465Smp if (word.len == 0 || word.s[word.len - 1] != ':') 83359243Sobrien break; 834167465Smp word.s[--word.len] = 0; 835167465Smp if ((type == TC_GOTO && eq(word.s, goal)) || 836167465Smp (type == TC_SWITCH && eq(word.s, STRdefault))) 83759243Sobrien level = -1; 83859243Sobrien break; 83959243Sobrien 84059243Sobrien case TC_CASE: 84159243Sobrien if (type != TC_SWITCH || level != 0) 84259243Sobrien break; 843167465Smp (void) getword(&word); 844167465Smp if (word.len != 0 && word.s[word.len - 1] == ':') 845167465Smp word.s[--word.len] = 0; 846167465Smp cp = strip(Dfix1(word.s)); 847167465Smp cleanup_push(cp, xfree); 84859243Sobrien if (Gmatch(goal, cp)) 84959243Sobrien level = -1; 850167465Smp cleanup_until(cp); 85159243Sobrien break; 85259243Sobrien 85359243Sobrien case TC_DEFAULT: 85459243Sobrien if (type == TC_SWITCH && level == 0) 85559243Sobrien level = -1; 85659243Sobrien break; 85759243Sobrien } 85859243Sobrien (void) getword(NULL); 85959243Sobrien } while (level >= 0); 860167465Smp end: 861167465Smp cleanup_until(&word); 86259243Sobrien} 86359243Sobrien 86459243Sobrienstatic int 865167465Smpgetword(struct Strbuf *wp) 86659243Sobrien{ 86759243Sobrien int found = 0, first; 868145479Smp eChar c, d; 86959243Sobrien 870167465Smp if (wp) 871167465Smp wp->len = 0; 87259243Sobrien c = readc(1); 87359243Sobrien d = 0; 87459243Sobrien do { 87559243Sobrien while (c == ' ' || c == '\t') 87659243Sobrien c = readc(1); 87759243Sobrien if (c == '#') 87859243Sobrien do 87959243Sobrien c = readc(1); 880145479Smp while (c != CHAR_ERR && c != '\n'); 881145479Smp if (c == CHAR_ERR) 88259243Sobrien goto past; 88359243Sobrien if (c == '\n') { 88459243Sobrien if (wp) 88559243Sobrien break; 88659243Sobrien return (0); 88759243Sobrien } 88859243Sobrien unreadc(c); 88959243Sobrien found = 1; 89059243Sobrien first = 1; 89159243Sobrien do { 89259243Sobrien c = readc(1); 89359243Sobrien if (c == '\\' && (c = readc(1)) == '\n') 89459243Sobrien c = ' '; 89559243Sobrien if (c == '\'' || c == '"') { 89659243Sobrien if (d == 0) 89759243Sobrien d = c; 89859243Sobrien else if (d == c) 89959243Sobrien d = 0; 90059243Sobrien } 901145479Smp if (c == CHAR_ERR) 90259243Sobrien goto past; 903167465Smp if (wp) 904167465Smp Strbuf_append1(wp, (Char) c); 90559243Sobrien if (!first && !d && c == '(') { 906167465Smp if (wp) 907167465Smp goto past_word_end; 90859243Sobrien else 90959243Sobrien break; 91059243Sobrien } 91159243Sobrien first = 0; 91259243Sobrien } while ((d || (c != ' ' && c != '\t')) && c != '\n'); 91359243Sobrien } while (wp == 0); 91459243Sobrien 915167465Smp past_word_end: 91659243Sobrien unreadc(c); 917167465Smp if (found) { 918167465Smp wp->len--; 919167465Smp Strbuf_terminate(wp); 920167465Smp } 92159243Sobrien 92259243Sobrien return (found); 92359243Sobrien 92459243Sobrienpast: 92559243Sobrien switch (Stype) { 92659243Sobrien 92759243Sobrien case TC_IF: 92859243Sobrien stderror(ERR_NAME | ERR_NOTFOUND, "then/endif"); 92959243Sobrien break; 93059243Sobrien 93159243Sobrien case TC_ELSE: 93259243Sobrien stderror(ERR_NAME | ERR_NOTFOUND, "endif"); 93359243Sobrien break; 93459243Sobrien 93559243Sobrien case TC_BRKSW: 93659243Sobrien case TC_SWITCH: 93759243Sobrien stderror(ERR_NAME | ERR_NOTFOUND, "endsw"); 93859243Sobrien break; 93959243Sobrien 94059243Sobrien case TC_BREAK: 94159243Sobrien stderror(ERR_NAME | ERR_NOTFOUND, "end"); 94259243Sobrien break; 94359243Sobrien 94459243Sobrien case TC_GOTO: 94559243Sobrien setname(short2str(Sgoal)); 94659243Sobrien stderror(ERR_NAME | ERR_NOTFOUND, "label"); 94759243Sobrien break; 94859243Sobrien 94959243Sobrien default: 95059243Sobrien break; 95159243Sobrien } 95259243Sobrien /* NOTREACHED */ 95359243Sobrien return (0); 95459243Sobrien} 95559243Sobrien 95659243Sobrienstatic void 957167465Smptoend(void) 95859243Sobrien{ 95969408Sache if (whyles->w_end.type == TCSH_F_SEEK && whyles->w_end.f_seek == 0) { 96059243Sobrien search(TC_BREAK, 0, NULL); 96159243Sobrien btell(&whyles->w_end); 96259243Sobrien whyles->w_end.f_seek--; 96359243Sobrien } 96459243Sobrien else { 96559243Sobrien bseek(&whyles->w_end); 96659243Sobrien } 96759243Sobrien wfree(); 96859243Sobrien} 96959243Sobrien 970131962Smpstatic void 971167465Smpwpfree(struct whyle *wp) 972131962Smp{ 973131962Smp if (wp->w_fe0) 974131962Smp blkfree(wp->w_fe0); 975167465Smp xfree(wp->w_fename); 976167465Smp xfree(wp); 977131962Smp} 978131962Smp 97959243Sobrienvoid 980167465Smpwfree(void) 98159243Sobrien{ 98259243Sobrien struct Ain o; 98359243Sobrien struct whyle *nwp; 98459243Sobrien#ifdef lint 98559243Sobrien nwp = NULL; /* sun lint is dumb! */ 98659243Sobrien#endif 98759243Sobrien 98859243Sobrien#ifdef FDEBUG 989167465Smp static const char foo[] = "IAFE"; 99059243Sobrien#endif /* FDEBUG */ 99159243Sobrien 99259243Sobrien btell(&o); 99359243Sobrien 99459243Sobrien#ifdef FDEBUG 995167465Smp xprintf("o->type %c o->a_seek %d o->f_seek %d\n", 99659243Sobrien foo[o.type + 1], o.a_seek, o.f_seek); 99759243Sobrien#endif /* FDEBUG */ 99859243Sobrien 99959243Sobrien for (; whyles; whyles = nwp) { 1000145479Smp struct whyle *wp = whyles; 100159243Sobrien nwp = wp->w_next; 100259243Sobrien 100359243Sobrien#ifdef FDEBUG 1004167465Smp xprintf("start->type %c start->a_seek %d start->f_seek %d\n", 100559243Sobrien foo[wp->w_start.type+1], 100659243Sobrien wp->w_start.a_seek, wp->w_start.f_seek); 1007167465Smp xprintf("end->type %c end->a_seek %d end->f_seek %d\n", 100859243Sobrien foo[wp->w_end.type + 1], wp->w_end.a_seek, wp->w_end.f_seek); 100959243Sobrien#endif /* FDEBUG */ 101059243Sobrien 101159243Sobrien /* 101259243Sobrien * XXX: We free loops that have different seek types. 101359243Sobrien */ 101469408Sache if (wp->w_end.type != TCSH_I_SEEK && wp->w_start.type == wp->w_end.type && 101559243Sobrien wp->w_start.type == o.type) { 101669408Sache if (wp->w_end.type == TCSH_F_SEEK) { 101759243Sobrien if (o.f_seek >= wp->w_start.f_seek && 101859243Sobrien (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek)) 101959243Sobrien break; 102059243Sobrien } 102159243Sobrien else { 102259243Sobrien if (o.a_seek >= wp->w_start.a_seek && 102359243Sobrien (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek)) 102459243Sobrien break; 102559243Sobrien } 102659243Sobrien } 102759243Sobrien 1028131962Smp wpfree(wp); 102959243Sobrien } 103059243Sobrien} 103159243Sobrien 103259243Sobrien/*ARGSUSED*/ 103359243Sobrienvoid 1034167465Smpdoecho(Char **v, struct command *c) 103559243Sobrien{ 103659243Sobrien USE(c); 103759243Sobrien xecho(' ', v); 103859243Sobrien} 103959243Sobrien 104059243Sobrien/*ARGSUSED*/ 104159243Sobrienvoid 1042167465Smpdoglob(Char **v, struct command *c) 104359243Sobrien{ 104459243Sobrien USE(c); 104559243Sobrien xecho(0, v); 104659243Sobrien flush(); 104759243Sobrien} 104859243Sobrien 104959243Sobrienstatic void 1050167465Smpxecho(int sep, Char **v) 105159243Sobrien{ 1052167465Smp Char *cp, **globbed = NULL; 105359243Sobrien int nonl = 0; 105459243Sobrien int echo_style = ECHO_STYLE; 105559243Sobrien struct varent *vp; 105659243Sobrien 105759243Sobrien if ((vp = adrof(STRecho_style)) != NULL && vp->vec != NULL && 105859243Sobrien vp->vec[0] != NULL) { 105959243Sobrien if (Strcmp(vp->vec[0], STRbsd) == 0) 106059243Sobrien echo_style = BSD_ECHO; 106159243Sobrien else if (Strcmp(vp->vec[0], STRsysv) == 0) 106259243Sobrien echo_style = SYSV_ECHO; 106359243Sobrien else if (Strcmp(vp->vec[0], STRboth) == 0) 106459243Sobrien echo_style = BOTH_ECHO; 106559243Sobrien else if (Strcmp(vp->vec[0], STRnone) == 0) 106659243Sobrien echo_style = NONE_ECHO; 106759243Sobrien } 106859243Sobrien 106959243Sobrien v++; 107059243Sobrien if (*v == 0) 107183098Smp goto done; 1072167465Smp if (setintr) { 1073167465Smp int old_pintr_disabled; 1074167465Smp pintr_push_enable(&old_pintr_disabled); 1075167465Smp v = glob_all_or_error(v); 1076167465Smp cleanup_until(&old_pintr_disabled); 1077167465Smp } else { 1078167465Smp v = glob_all_or_error(v); 107959243Sobrien } 1080167465Smp globbed = v; 1081167465Smp if (globbed != NULL) 1082167465Smp cleanup_push(globbed, blk_cleanup); 108359243Sobrien 108459243Sobrien if ((echo_style & BSD_ECHO) != 0 && sep == ' ' && *v && eq(*v, STRmn)) 108559243Sobrien nonl++, v++; 108659243Sobrien 108759243Sobrien while ((cp = *v++) != 0) { 1088145479Smp Char c; 108959243Sobrien 1090167465Smp if (setintr) { 1091167465Smp int old_pintr_disabled; 1092167465Smp 1093167465Smp pintr_push_enable(&old_pintr_disabled); 1094167465Smp cleanup_until(&old_pintr_disabled); 1095167465Smp } 109659243Sobrien while ((c = *cp++) != 0) { 109759243Sobrien if ((echo_style & SYSV_ECHO) != 0 && c == '\\') { 109859243Sobrien switch (c = *cp++) { 109959243Sobrien case 'a': 110059243Sobrien c = '\a'; 110159243Sobrien break; 110259243Sobrien case 'b': 110359243Sobrien c = '\b'; 110459243Sobrien break; 110559243Sobrien case 'c': 110659243Sobrien nonl = 1; 110759243Sobrien goto done; 110859243Sobrien case 'e': 110959243Sobrien#if 0 /* Windows does not understand \e */ 111059243Sobrien c = '\e'; 111159243Sobrien#else 1112167465Smp c = CTL_ESC('\033'); 111359243Sobrien#endif 111459243Sobrien break; 111559243Sobrien case 'f': 111659243Sobrien c = '\f'; 111759243Sobrien break; 111859243Sobrien case 'n': 111959243Sobrien c = '\n'; 112059243Sobrien break; 112159243Sobrien case 'r': 112259243Sobrien c = '\r'; 112359243Sobrien break; 112459243Sobrien case 't': 112559243Sobrien c = '\t'; 112659243Sobrien break; 112759243Sobrien case 'v': 112859243Sobrien c = '\v'; 112959243Sobrien break; 113059243Sobrien case '\\': 113159243Sobrien c = '\\'; 113259243Sobrien break; 113359243Sobrien case '0': 113459243Sobrien c = 0; 113559243Sobrien if (*cp >= '0' && *cp < '8') 113659243Sobrien c = c * 8 + *cp++ - '0'; 113759243Sobrien if (*cp >= '0' && *cp < '8') 113859243Sobrien c = c * 8 + *cp++ - '0'; 113959243Sobrien if (*cp >= '0' && *cp < '8') 114059243Sobrien c = c * 8 + *cp++ - '0'; 114159243Sobrien break; 114259243Sobrien case '\0': 114359243Sobrien c = '\\'; 114459243Sobrien cp--; 114559243Sobrien break; 114659243Sobrien default: 114759243Sobrien xputchar('\\' | QUOTE); 114859243Sobrien break; 114959243Sobrien } 115059243Sobrien } 1151145479Smp xputwchar(c | QUOTE); 115259243Sobrien 115359243Sobrien } 115459243Sobrien if (*v) 115559243Sobrien xputchar(sep | QUOTE); 115659243Sobrien } 115759243Sobriendone: 115859243Sobrien if (sep && nonl == 0) 115959243Sobrien xputchar('\n'); 116059243Sobrien else 116159243Sobrien flush(); 1162167465Smp if (globbed != NULL) 1163167465Smp cleanup_until(globbed); 116459243Sobrien} 116559243Sobrien 116659243Sobrien/* check whether an environment variable should invoke 'set_locale()' */ 1167145479Smpstatic int 1168167465Smpislocale_var(Char *var) 116959243Sobrien{ 117059243Sobrien static Char *locale_vars[] = { 1171131962Smp STRLANG, STRLC_ALL, STRLC_CTYPE, STRLC_NUMERIC, 1172131962Smp STRLC_TIME, STRLC_COLLATE, STRLC_MESSAGES, STRLC_MONETARY, 0 117359243Sobrien }; 1174145479Smp Char **v; 117559243Sobrien 117659243Sobrien for (v = locale_vars; *v; ++v) 117759243Sobrien if (eq(var, *v)) 117859243Sobrien return 1; 117959243Sobrien return 0; 118059243Sobrien} 118159243Sobrien 1182167465Smpstatic void 1183167465Smpxlate_cr_cleanup(void *dummy) 1184167465Smp{ 1185167465Smp USE(dummy); 1186167465Smp xlate_cr = 0; 1187167465Smp} 1188167465Smp 118959243Sobrien/*ARGSUSED*/ 119059243Sobrienvoid 1191167465Smpdoprintenv(Char **v, struct command *c) 119259243Sobrien{ 119359243Sobrien Char *e; 119459243Sobrien 119559243Sobrien USE(c); 119659243Sobrien v++; 119759243Sobrien if (*v == 0) { 1198145479Smp Char **ep; 119959243Sobrien 120059243Sobrien xlate_cr = 1; 1201167465Smp cleanup_push(&xlate_cr, xlate_cr_cleanup); 1202167465Smp for (ep = STR_environ; *ep; ep++) { 1203167465Smp if (setintr) { 1204167465Smp int old_pintr_disabled; 1205167465Smp 1206167465Smp pintr_push_enable(&old_pintr_disabled); 1207167465Smp cleanup_until(&old_pintr_disabled); 1208167465Smp } 120959243Sobrien xprintf("%S\n", *ep); 1210167465Smp } 1211167465Smp cleanup_until(&xlate_cr); 121259243Sobrien } 121359243Sobrien else if ((e = tgetenv(*v)) != NULL) { 1214167465Smp int old_output_raw; 1215167465Smp 1216167465Smp old_output_raw = output_raw; 121759243Sobrien output_raw = 1; 1218167465Smp cleanup_push(&old_output_raw, output_raw_restore); 121959243Sobrien xprintf("%S\n", e); 1220167465Smp cleanup_until(&old_output_raw); 122159243Sobrien } 122259243Sobrien else 1223167465Smp setcopy(STRstatus, STR1, VAR_READWRITE); 122459243Sobrien} 122559243Sobrien 122659243Sobrien/* from "Karl Berry." <karl%mote.umb.edu@relay.cs.net> -- for NeXT things 122759243Sobrien (and anything else with a modern compiler) */ 122859243Sobrien 122959243Sobrien/*ARGSUSED*/ 123059243Sobrienvoid 1231167465Smpdosetenv(Char **v, struct command *c) 123259243Sobrien{ 123359243Sobrien Char *vp, *lp; 123459243Sobrien 123559243Sobrien USE(c); 123659243Sobrien if (*++v == 0) { 123759243Sobrien doprintenv(--v, 0); 123859243Sobrien return; 123959243Sobrien } 124059243Sobrien 124159243Sobrien vp = *v++; 124259243Sobrien 1243100616Smp lp = vp; 1244100616Smp 1245131962Smp for (; *lp != '\0' ; lp++) { 1246131962Smp if (*lp == '=') 1247131962Smp stderror(ERR_NAME | ERR_SYNTAX); 1248131962Smp } 124959243Sobrien if ((lp = *v++) == 0) 125059243Sobrien lp = STRNULL; 125159243Sobrien 1252167465Smp lp = globone(lp, G_APPEND); 1253167465Smp cleanup_push(lp, xfree); 1254167465Smp tsetenv(vp, lp); 125559243Sobrien if (eq(vp, STRKPATH)) { 1256167465Smp importpath(lp); 125759243Sobrien dohash(NULL, NULL); 1258167465Smp cleanup_until(lp); 125959243Sobrien return; 126059243Sobrien } 126159243Sobrien 126259243Sobrien#ifdef apollo 126359243Sobrien if (eq(vp, STRSYSTYPE)) { 126459243Sobrien dohash(NULL, NULL); 1265167465Smp cleanup_until(lp); 126659243Sobrien return; 126759243Sobrien } 126859243Sobrien#endif /* apollo */ 126959243Sobrien 127059243Sobrien /* dspkanji/dspmbyte autosetting */ 127159243Sobrien /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */ 127259243Sobrien#if defined(DSPMBYTE) 127359243Sobrien if(eq(vp, STRLANG) && !adrof(CHECK_MBYTEVAR)) { 127459243Sobrien autoset_dspmbyte(lp); 127559243Sobrien } 127659243Sobrien#endif 127759243Sobrien 127859243Sobrien if (islocale_var(vp)) { 127959243Sobrien#ifdef NLS 128059243Sobrien int k; 128159243Sobrien 128259243Sobrien# ifdef SETLOCALEBUG 128359243Sobrien dont_free = 1; 128459243Sobrien# endif /* SETLOCALEBUG */ 128559243Sobrien (void) setlocale(LC_ALL, ""); 128659243Sobrien# ifdef LC_COLLATE 128759243Sobrien (void) setlocale(LC_COLLATE, ""); 128859243Sobrien# endif 1289145479Smp# ifdef LC_CTYPE 1290145479Smp (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 1291145479Smp# endif /* LC_CTYPE */ 129259243Sobrien# ifdef NLS_CATALOGS 129359243Sobrien# ifdef LC_MESSAGES 129459243Sobrien (void) setlocale(LC_MESSAGES, ""); 129559243Sobrien# endif /* LC_MESSAGES */ 1296145479Smp nlsclose(); 129759243Sobrien nlsinit(); 129859243Sobrien# endif /* NLS_CATALOGS */ 129959243Sobrien# ifdef SETLOCALEBUG 130059243Sobrien dont_free = 0; 130159243Sobrien# endif /* SETLOCALEBUG */ 130259243Sobrien# ifdef STRCOLLBUG 130359243Sobrien fix_strcoll_bug(); 130459243Sobrien# endif /* STRCOLLBUG */ 130559243Sobrien tw_cmd_free(); /* since the collation sequence has changed */ 1306167465Smp for (k = 0200; k <= 0377 && !Isprint(CTL_ESC(k)); k++) 130759243Sobrien continue; 1308145479Smp AsciiOnly = MB_CUR_MAX == 1 && k > 0377; 130959243Sobrien#else /* !NLS */ 131059243Sobrien AsciiOnly = 0; 131159243Sobrien#endif /* NLS */ 131259243Sobrien NLSMapsAreInited = 0; 131359243Sobrien ed_Init(); 131459243Sobrien if (MapsAreInited && !NLSMapsAreInited) 131559243Sobrien ed_InitNLSMaps(); 1316167465Smp cleanup_until(lp); 131759243Sobrien return; 131859243Sobrien } 131959243Sobrien 1320100616Smp#ifdef NLS_CATALOGS 1321100616Smp if (eq(vp, STRNLSPATH)) { 1322145479Smp nlsclose(); 1323100616Smp nlsinit(); 1324100616Smp } 1325100616Smp#endif 1326100616Smp 132759243Sobrien if (eq(vp, STRNOREBIND)) { 132859243Sobrien NoNLSRebind = 1; 132959243Sobrien MapsAreInited = 0; 133059243Sobrien NLSMapsAreInited = 0; 133159243Sobrien ed_InitMaps(); 1332167465Smp cleanup_until(lp); 133359243Sobrien return; 133459243Sobrien } 133569408Sache#ifdef WINNT_NATIVE 133659243Sobrien if (eq(vp, STRtcshlang)) { 133759243Sobrien nlsinit(); 1338167465Smp cleanup_until(lp); 133959243Sobrien return; 134059243Sobrien } 134169408Sache#endif /* WINNT_NATIVE */ 134259243Sobrien if (eq(vp, STRKTERM)) { 134359243Sobrien char *t; 1344167465Smp 1345167465Smp setv(STRterm, quote(lp), VAR_READWRITE); /* lp memory used here */ 1346167465Smp cleanup_ignore(lp); 1347167465Smp cleanup_until(lp); 134859243Sobrien t = short2str(lp); 134959243Sobrien if (noediting && strcmp(t, "unknown") != 0 && strcmp(t,"dumb") != 0) { 135059243Sobrien editing = 1; 135159243Sobrien noediting = 0; 1352167465Smp setNS(STRedit); 135359243Sobrien } 135459243Sobrien GotTermCaps = 0; 135559243Sobrien ed_Init(); 135659243Sobrien return; 135759243Sobrien } 135859243Sobrien 135959243Sobrien if (eq(vp, STRKHOME)) { 1360167465Smp Char *canon; 136159243Sobrien /* 136259243Sobrien * convert to canonical pathname (possibly resolving symlinks) 136359243Sobrien */ 1364167465Smp canon = dcanon(lp, lp); 1365167465Smp cleanup_ignore(lp); 1366167465Smp cleanup_until(lp); 1367167465Smp cleanup_push(canon, xfree); 1368167465Smp setv(STRhome, quote(canon), VAR_READWRITE); /* lp memory used here */ 1369167465Smp cleanup_ignore(canon); 1370167465Smp cleanup_until(canon); 137159243Sobrien 137259243Sobrien /* fix directory stack for new tilde home */ 137359243Sobrien dtilde(); 137459243Sobrien return; 137559243Sobrien } 137659243Sobrien 137759243Sobrien if (eq(vp, STRKSHLVL)) { 1378167465Smp setv(STRshlvl, quote(lp), VAR_READWRITE); /* lp memory used here */ 1379167465Smp cleanup_ignore(lp); 1380167465Smp cleanup_until(lp); 138159243Sobrien return; 138259243Sobrien } 138359243Sobrien 138459243Sobrien if (eq(vp, STRKUSER)) { 1385167465Smp setv(STRuser, quote(lp), VAR_READWRITE); /* lp memory used here */ 1386167465Smp cleanup_ignore(lp); 1387167465Smp cleanup_until(lp); 138859243Sobrien return; 138959243Sobrien } 139059243Sobrien 139159243Sobrien if (eq(vp, STRKGROUP)) { 1392167465Smp setv(STRgroup, quote(lp), VAR_READWRITE); /* lp memory used here */ 1393167465Smp cleanup_ignore(lp); 1394167465Smp cleanup_until(lp); 139559243Sobrien return; 139659243Sobrien } 139759243Sobrien 139859243Sobrien#ifdef COLOR_LS_F 139959243Sobrien if (eq(vp, STRLS_COLORS)) { 140059243Sobrien parseLS_COLORS(lp); 1401167465Smp cleanup_until(lp); 140259243Sobrien return; 140359243Sobrien } 140459243Sobrien#endif /* COLOR_LS_F */ 140559243Sobrien 140659243Sobrien#ifdef SIG_WINDOW 140759243Sobrien /* 140859243Sobrien * Load/Update $LINES $COLUMNS 140959243Sobrien */ 141059243Sobrien if ((eq(lp, STRNULL) && (eq(vp, STRLINES) || eq(vp, STRCOLUMNS))) || 141159243Sobrien eq(vp, STRTERMCAP)) { 1412167465Smp cleanup_until(lp); 141359243Sobrien check_window_size(1); 141459243Sobrien return; 141559243Sobrien } 141659243Sobrien 141759243Sobrien /* 141859243Sobrien * Change the size to the one directed by $LINES and $COLUMNS 141959243Sobrien */ 142059243Sobrien if (eq(vp, STRLINES) || eq(vp, STRCOLUMNS)) { 142159243Sobrien#if 0 142259243Sobrien GotTermCaps = 0; 142359243Sobrien#endif 1424167465Smp cleanup_until(lp); 142559243Sobrien ed_Init(); 142659243Sobrien return; 142759243Sobrien } 142859243Sobrien#endif /* SIG_WINDOW */ 1429167465Smp cleanup_until(lp); 143059243Sobrien} 143159243Sobrien 143259243Sobrien/*ARGSUSED*/ 143359243Sobrienvoid 1434167465Smpdounsetenv(Char **v, struct command *c) 143559243Sobrien{ 1436167465Smp Char **ep, *p, *n, *name; 143759243Sobrien int i, maxi; 143859243Sobrien 143959243Sobrien USE(c); 144059243Sobrien /* 144159243Sobrien * Find the longest environment variable 144259243Sobrien */ 144359243Sobrien for (maxi = 0, ep = STR_environ; *ep; ep++) { 144459243Sobrien for (i = 0, p = *ep; *p && *p != '='; p++, i++) 144559243Sobrien continue; 144659243Sobrien if (i > maxi) 144759243Sobrien maxi = i; 144859243Sobrien } 144959243Sobrien 1450167465Smp name = xmalloc((maxi + 1) * sizeof(Char)); 1451167465Smp cleanup_push(name, xfree); 145259243Sobrien 145359243Sobrien while (++v && *v) 145459243Sobrien for (maxi = 1; maxi;) 145559243Sobrien for (maxi = 0, ep = STR_environ; *ep; ep++) { 145659243Sobrien for (n = name, p = *ep; *p && *p != '='; *n++ = *p++) 145759243Sobrien continue; 145859243Sobrien *n = '\0'; 145959243Sobrien if (!Gmatch(name, *v)) 146059243Sobrien continue; 146159243Sobrien maxi = 1; 146259243Sobrien 146359243Sobrien /* Unset the name. This wasn't being done until 146459243Sobrien * later but most of the stuff following won't 146559243Sobrien * work (particularly the setlocale() and getenv() 146659243Sobrien * stuff) as intended until the name is actually 146759243Sobrien * removed. (sg) 146859243Sobrien */ 146959243Sobrien Unsetenv(name); 147059243Sobrien 147159243Sobrien if (eq(name, STRNOREBIND)) { 147259243Sobrien NoNLSRebind = 0; 147359243Sobrien MapsAreInited = 0; 147459243Sobrien NLSMapsAreInited = 0; 147559243Sobrien ed_InitMaps(); 147659243Sobrien } 147759243Sobrien#ifdef apollo 147859243Sobrien else if (eq(name, STRSYSTYPE)) 147959243Sobrien dohash(NULL, NULL); 148059243Sobrien#endif /* apollo */ 148159243Sobrien else if (islocale_var(name)) { 148259243Sobrien#ifdef NLS 148359243Sobrien int k; 148459243Sobrien 148559243Sobrien# ifdef SETLOCALEBUG 148659243Sobrien dont_free = 1; 148759243Sobrien# endif /* SETLOCALEBUG */ 148859243Sobrien (void) setlocale(LC_ALL, ""); 148959243Sobrien# ifdef LC_COLLATE 149059243Sobrien (void) setlocale(LC_COLLATE, ""); 149159243Sobrien# endif 1492145479Smp# ifdef LC_CTYPE 1493167465Smp (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 1494145479Smp# endif /* LC_CTYPE */ 149559243Sobrien# ifdef NLS_CATALOGS 149659243Sobrien# ifdef LC_MESSAGES 149759243Sobrien (void) setlocale(LC_MESSAGES, ""); 149859243Sobrien# endif /* LC_MESSAGES */ 1499145479Smp nlsclose(); 150059243Sobrien nlsinit(); 150159243Sobrien# endif /* NLS_CATALOGS */ 150259243Sobrien# ifdef SETLOCALEBUG 150359243Sobrien dont_free = 0; 150459243Sobrien# endif /* SETLOCALEBUG */ 150559243Sobrien# ifdef STRCOLLBUG 150659243Sobrien fix_strcoll_bug(); 150759243Sobrien# endif /* STRCOLLBUG */ 150859243Sobrien tw_cmd_free();/* since the collation sequence has changed */ 1509167465Smp for (k = 0200; k <= 0377 && !Isprint(CTL_ESC(k)); k++) 151059243Sobrien continue; 1511145479Smp AsciiOnly = MB_CUR_MAX == 1 && k > 0377; 151259243Sobrien#else /* !NLS */ 151359243Sobrien AsciiOnly = getenv("LANG") == NULL && 151459243Sobrien getenv("LC_CTYPE") == NULL; 151559243Sobrien#endif /* NLS */ 151659243Sobrien NLSMapsAreInited = 0; 151759243Sobrien ed_Init(); 151859243Sobrien if (MapsAreInited && !NLSMapsAreInited) 151959243Sobrien ed_InitNLSMaps(); 152059243Sobrien 152159243Sobrien } 152269408Sache#ifdef WINNT_NATIVE 152359243Sobrien else if (eq(name,(STRtcshlang))) { 152459243Sobrien nls_dll_unload(); 152559243Sobrien nlsinit(); 152659243Sobrien } 152769408Sache#endif /* WINNT_NATIVE */ 152859243Sobrien#ifdef COLOR_LS_F 152959243Sobrien else if (eq(name, STRLS_COLORS)) 153059243Sobrien parseLS_COLORS(n); 153159243Sobrien#endif /* COLOR_LS_F */ 1532100616Smp#ifdef NLS_CATALOGS 1533100616Smp else if (eq(name, STRNLSPATH)) { 1534145479Smp nlsclose(); 1535100616Smp nlsinit(); 1536100616Smp } 1537100616Smp#endif 153859243Sobrien /* 153959243Sobrien * start again cause the environment changes 154059243Sobrien */ 154159243Sobrien break; 154259243Sobrien } 1543167465Smp cleanup_until(name); 154459243Sobrien} 154559243Sobrien 154659243Sobrienvoid 1547167465Smptsetenv(const Char *name, const Char *val) 154859243Sobrien{ 154959243Sobrien#ifdef SETENV_IN_LIB 155059243Sobrien/* 155159243Sobrien * XXX: This does not work right, since tcsh cannot track changes to 155259243Sobrien * the environment this way. (the builtin setenv without arguments does 155359243Sobrien * not print the right stuff neither does unsetenv). This was for Mach, 155459243Sobrien * it is not needed anymore. 155559243Sobrien */ 155659243Sobrien#undef setenv 1557167465Smp char *cname; 155859243Sobrien 1559167465Smp if (name == NULL) 156059243Sobrien return; 1561167465Smp cname = strsave(short2str(name)); 1562167465Smp setenv(cname, short2str(val), 1); 1563167465Smp xfree(cname); 156459243Sobrien#else /* !SETENV_IN_LIB */ 1565145479Smp Char **ep = STR_environ; 1566145479Smp const Char *ccp; 1567145479Smp Char *cp, *dp; 156859243Sobrien Char *blk[2]; 156959243Sobrien Char **oep = ep; 157059243Sobrien 157169408Sache#ifdef WINNT_NATIVE 1572167465Smp nt_set_env(name,val); 157369408Sache#endif /* WINNT_NATIVE */ 157459243Sobrien for (; *ep; ep++) { 157569408Sache#ifdef WINNT_NATIVE 1576145479Smp for (ccp = name, dp = *ep; *ccp && Tolower(*ccp & TRIM) == Tolower(*dp); 1577145479Smp ccp++, dp++) 157859243Sobrien#else 1579145479Smp for (ccp = name, dp = *ep; *ccp && (*ccp & TRIM) == *dp; ccp++, dp++) 158069408Sache#endif /* WINNT_NATIVE */ 158159243Sobrien continue; 1582145479Smp if (*ccp != 0 || *dp != '=') 158359243Sobrien continue; 158459243Sobrien cp = Strspl(STRequal, val); 1585167465Smp xfree(*ep); 158659243Sobrien *ep = strip(Strspl(name, cp)); 1587167465Smp xfree(cp); 158859243Sobrien blkfree((Char **) environ); 158959243Sobrien environ = short2blk(STR_environ); 159059243Sobrien return; 159159243Sobrien } 159259243Sobrien cp = Strspl(name, STRequal); 159359243Sobrien blk[0] = strip(Strspl(cp, val)); 1594167465Smp xfree(cp); 159559243Sobrien blk[1] = 0; 159659243Sobrien STR_environ = blkspl(STR_environ, blk); 159759243Sobrien blkfree((Char **) environ); 159859243Sobrien environ = short2blk(STR_environ); 1599167465Smp xfree(oep); 160059243Sobrien#endif /* SETENV_IN_LIB */ 160159243Sobrien} 160259243Sobrien 160359243Sobrienvoid 1604167465SmpUnsetenv(Char *name) 160559243Sobrien{ 1606145479Smp Char **ep = STR_environ; 1607145479Smp Char *cp, *dp; 160859243Sobrien Char **oep = ep; 160959243Sobrien 161069408Sache#ifdef WINNT_NATIVE 161159243Sobrien nt_set_env(name,NULL); 161269408Sache#endif /*WINNT_NATIVE */ 161359243Sobrien for (; *ep; ep++) { 161459243Sobrien for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) 161559243Sobrien continue; 161659243Sobrien if (*cp != 0 || *dp != '=') 161759243Sobrien continue; 161859243Sobrien cp = *ep; 161959243Sobrien *ep = 0; 162059243Sobrien STR_environ = blkspl(STR_environ, ep + 1); 162159243Sobrien blkfree((Char **) environ); 162259243Sobrien environ = short2blk(STR_environ); 162359243Sobrien *ep = cp; 1624167465Smp xfree(cp); 1625167465Smp xfree(oep); 162659243Sobrien return; 162759243Sobrien } 162859243Sobrien} 162959243Sobrien 163059243Sobrien/*ARGSUSED*/ 163159243Sobrienvoid 1632167465Smpdoumask(Char **v, struct command *c) 163359243Sobrien{ 1634145479Smp Char *cp = v[1]; 1635145479Smp int i; 163659243Sobrien 163759243Sobrien USE(c); 163859243Sobrien if (cp == 0) { 163959415Sobrien i = (int)umask(0); 164059243Sobrien (void) umask(i); 164159243Sobrien xprintf("%o\n", i); 164259243Sobrien return; 164359243Sobrien } 164459243Sobrien i = 0; 164559243Sobrien while (Isdigit(*cp) && *cp != '8' && *cp != '9') 164659243Sobrien i = i * 8 + *cp++ - '0'; 164759243Sobrien if (*cp || i < 0 || i > 0777) 164859243Sobrien stderror(ERR_NAME | ERR_MASK); 164959243Sobrien (void) umask(i); 165059243Sobrien} 165159243Sobrien 165259243Sobrien#ifndef HAVENOLIMIT 165359243Sobrien# ifndef BSDLIMIT 165459243Sobrien typedef long RLIM_TYPE; 1655145479Smp# ifdef _OSD_POSIX /* BS2000 */ 1656145479Smp# include <ulimit.h> 1657145479Smp# endif 165859243Sobrien# ifndef RLIM_INFINITY 165959243Sobrien# if !defined(_MINIX) && !defined(__clipper__) && !defined(_CRAY) 166059243Sobrien extern RLIM_TYPE ulimit(); 166159243Sobrien# endif /* ! _MINIX && !__clipper__ */ 166259243Sobrien# define RLIM_INFINITY 0x003fffff 166359243Sobrien# define RLIMIT_FSIZE 1 166459243Sobrien# endif /* RLIM_INFINITY */ 166559243Sobrien# ifdef aiws 166659243Sobrien# define toset(a) (((a) == 3) ? 1004 : (a) + 1) 166759243Sobrien# define RLIMIT_DATA 3 166859243Sobrien# define RLIMIT_STACK 1005 166959243Sobrien# else /* aiws */ 167059243Sobrien# define toset(a) ((a) + 1) 167159243Sobrien# endif /* aiws */ 167259243Sobrien# else /* BSDLIMIT */ 1673145479Smp# if (defined(BSD4_4) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) || (HPUXVERSION >= 1100)) && !defined(__386BSD__) 1674100616Smp typedef rlim_t RLIM_TYPE; 167559243Sobrien# else 167659243Sobrien# if defined(SOLARIS2) || (defined(sgi) && SYSVREL > 3) 167759243Sobrien typedef rlim_t RLIM_TYPE; 167859243Sobrien# else 167959243Sobrien# if defined(_SX) 168059243Sobrien typedef long long RLIM_TYPE; 1681100616Smp# else /* !_SX */ 168259243Sobrien typedef unsigned long RLIM_TYPE; 168359243Sobrien# endif /* _SX */ 168459243Sobrien# endif /* SOLARIS2 || (sgi && SYSVREL > 3) */ 168559243Sobrien# endif /* BSD4_4 && !__386BSD__ */ 168659243Sobrien# endif /* BSDLIMIT */ 168759243Sobrien 1688131962Smp# if (HPUXVERSION > 700) && (HPUXVERSION < 1100) && defined(BSDLIMIT) 168959243Sobrien/* Yes hpux8.0 has limits but <sys/resource.h> does not make them public */ 169059243Sobrien/* Yes, we could have defined _KERNEL, and -I/etc/conf/h, but is that better? */ 169159243Sobrien# ifndef RLIMIT_CPU 169259243Sobrien# define RLIMIT_CPU 0 169359243Sobrien# define RLIMIT_FSIZE 1 169459243Sobrien# define RLIMIT_DATA 2 169559243Sobrien# define RLIMIT_STACK 3 169659243Sobrien# define RLIMIT_CORE 4 169759243Sobrien# define RLIMIT_RSS 5 169859243Sobrien# define RLIMIT_NOFILE 6 169959243Sobrien# endif /* RLIMIT_CPU */ 170059243Sobrien# ifndef RLIM_INFINITY 170159243Sobrien# define RLIM_INFINITY 0x7fffffff 170259243Sobrien# endif /* RLIM_INFINITY */ 170359243Sobrien /* 170459243Sobrien * old versions of HP/UX counted limits in 512 bytes 170559243Sobrien */ 170659243Sobrien# ifndef SIGRTMIN 170759243Sobrien# define FILESIZE512 170859243Sobrien# endif /* SIGRTMIN */ 1709131962Smp# endif /* (HPUXVERSION > 700) && (HPUXVERSION < 1100) && BSDLIMIT */ 171059243Sobrien 171159243Sobrien# if SYSVREL > 3 && defined(BSDLIMIT) && !defined(_SX) 171259243Sobrien/* In order to use rusage, we included "/usr/ucbinclude/sys/resource.h" in */ 171359243Sobrien/* sh.h. However, some SVR4 limits are defined in <sys/resource.h>. Rather */ 171459243Sobrien/* than include both and get warnings, we define the extra SVR4 limits here. */ 171583098Smp/* XXX: I don't understand if RLIMIT_AS is defined, why don't we define */ 171683098Smp/* RLIMIT_VMEM based on it? */ 171759243Sobrien# ifndef RLIMIT_VMEM 171859243Sobrien# define RLIMIT_VMEM 6 171959243Sobrien# endif 172059243Sobrien# ifndef RLIMIT_AS 172159243Sobrien# define RLIMIT_AS RLIMIT_VMEM 172259243Sobrien# endif 172359243Sobrien# endif /* SYSVREL > 3 && BSDLIMIT */ 172459243Sobrien 1725145479Smp# if (defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) && defined(RLIMIT_AS) && !defined(RLIMIT_VMEM) 172683098Smp# define RLIMIT_VMEM RLIMIT_AS 172783098Smp# endif 172883098Smp 172959243Sobrienstruct limits limits[] = 173059243Sobrien{ 173159243Sobrien# ifdef RLIMIT_CPU 173259243Sobrien { RLIMIT_CPU, "cputime", 1, "seconds" }, 173359243Sobrien# endif /* RLIMIT_CPU */ 173459243Sobrien 173559243Sobrien# ifdef RLIMIT_FSIZE 173659243Sobrien# ifndef aiws 173759243Sobrien { RLIMIT_FSIZE, "filesize", 1024, "kbytes" }, 173859243Sobrien# else 173959243Sobrien { RLIMIT_FSIZE, "filesize", 512, "blocks" }, 174059243Sobrien# endif /* aiws */ 174159243Sobrien# endif /* RLIMIT_FSIZE */ 174259243Sobrien 174359243Sobrien# ifdef RLIMIT_DATA 174459243Sobrien { RLIMIT_DATA, "datasize", 1024, "kbytes" }, 174559243Sobrien# endif /* RLIMIT_DATA */ 174659243Sobrien 174759243Sobrien# ifdef RLIMIT_STACK 174859243Sobrien# ifndef aiws 174959243Sobrien { RLIMIT_STACK, "stacksize", 1024, "kbytes" }, 175059243Sobrien# else 175159243Sobrien { RLIMIT_STACK, "stacksize", 1024 * 1024, "kbytes"}, 175259243Sobrien# endif /* aiws */ 175359243Sobrien# endif /* RLIMIT_STACK */ 175459243Sobrien 175559243Sobrien# ifdef RLIMIT_CORE 175659243Sobrien { RLIMIT_CORE, "coredumpsize", 1024, "kbytes" }, 175759243Sobrien# endif /* RLIMIT_CORE */ 175859243Sobrien 175959243Sobrien# ifdef RLIMIT_RSS 176059243Sobrien { RLIMIT_RSS, "memoryuse", 1024, "kbytes" }, 176159243Sobrien# endif /* RLIMIT_RSS */ 176259243Sobrien 176359243Sobrien# ifdef RLIMIT_UMEM 176459243Sobrien { RLIMIT_UMEM, "memoryuse", 1024, "kbytes" }, 176559243Sobrien# endif /* RLIMIT_UMEM */ 176659243Sobrien 176759243Sobrien# ifdef RLIMIT_VMEM 176859243Sobrien { RLIMIT_VMEM, "vmemoryuse", 1024, "kbytes" }, 176959243Sobrien# endif /* RLIMIT_VMEM */ 177059243Sobrien 1771145479Smp# if defined(RLIMIT_HEAP) /* found on BS2000/OSD systems */ 1772145479Smp { RLIMIT_HEAP, "heapsize", 1024, "kbytes" }, 1773145479Smp# endif /* RLIMIT_HEAP */ 1774145479Smp 177559243Sobrien# ifdef RLIMIT_NOFILE 177659243Sobrien { RLIMIT_NOFILE, "descriptors", 1, "" }, 177759243Sobrien# endif /* RLIMIT_NOFILE */ 177859243Sobrien 177959243Sobrien# ifdef RLIMIT_CONCUR 178059243Sobrien { RLIMIT_CONCUR, "concurrency", 1, "thread(s)" }, 178159243Sobrien# endif /* RLIMIT_CONCUR */ 178259243Sobrien 178359243Sobrien# ifdef RLIMIT_MEMLOCK 178459243Sobrien { RLIMIT_MEMLOCK, "memorylocked", 1024, "kbytes" }, 178559243Sobrien# endif /* RLIMIT_MEMLOCK */ 178659243Sobrien 178759243Sobrien# ifdef RLIMIT_NPROC 178859243Sobrien { RLIMIT_NPROC, "maxproc", 1, "" }, 178959243Sobrien# endif /* RLIMIT_NPROC */ 179059243Sobrien 1791100616Smp# if defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE) 179259243Sobrien { RLIMIT_OFILE, "openfiles", 1, "" }, 1793100616Smp# endif /* RLIMIT_OFILE && !defined(RLIMIT_NOFILE) */ 179459243Sobrien 1795100616Smp# ifdef RLIMIT_SBSIZE 1796100616Smp { RLIMIT_SBSIZE, "sbsize", 1, "" }, 1797100616Smp# endif /* RLIMIT_SBSIZE */ 1798100616Smp 1799194767Skib# ifdef RLIMIT_SWAP 1800194767Skib { RLIMIT_SWAP, "swaplimit", 1024, "kbytes" }, 1801194767Skib# endif /* RLIMIT_SWAP */ 1802194767Skib 180359243Sobrien { -1, NULL, 0, NULL } 180459243Sobrien}; 180559243Sobrien 1806167465Smpstatic struct limits *findlim (Char *); 1807167465Smpstatic RLIM_TYPE getval (struct limits *, Char **); 1808167465Smpstatic void limtail (Char *, const char *); 1809167465Smpstatic void plim (struct limits *, int); 1810167465Smpstatic int setlim (struct limits *, int, RLIM_TYPE); 181159243Sobrien 181259243Sobrien#ifdef convex 181359243Sobrienstatic RLIM_TYPE 1814167465Smprestrict_limit(double value) 181559243Sobrien{ 181659243Sobrien /* 181759243Sobrien * is f too large to cope with? return the maximum or minimum int 181859243Sobrien */ 181959243Sobrien if (value > (double) INT_MAX) 182059243Sobrien return (RLIM_TYPE) INT_MAX; 182159243Sobrien else if (value < (double) INT_MIN) 182259243Sobrien return (RLIM_TYPE) INT_MIN; 182359243Sobrien else 182459243Sobrien return (RLIM_TYPE) value; 182559243Sobrien} 182659243Sobrien#else /* !convex */ 182759243Sobrien# define restrict_limit(x) ((RLIM_TYPE) (x)) 182859243Sobrien#endif /* convex */ 182959243Sobrien 183059243Sobrien 183159243Sobrienstatic struct limits * 1832167465Smpfindlim(Char *cp) 183359243Sobrien{ 1834145479Smp struct limits *lp, *res; 183559243Sobrien 1836167465Smp res = NULL; 183759243Sobrien for (lp = limits; lp->limconst >= 0; lp++) 183859243Sobrien if (prefix(cp, str2short(lp->limname))) { 183959243Sobrien if (res) 184059243Sobrien stderror(ERR_NAME | ERR_AMBIG); 184159243Sobrien res = lp; 184259243Sobrien } 184359243Sobrien if (res) 184459243Sobrien return (res); 184559243Sobrien stderror(ERR_NAME | ERR_LIMIT); 184659243Sobrien /* NOTREACHED */ 184759243Sobrien return (0); 184859243Sobrien} 184959243Sobrien 185059243Sobrien/*ARGSUSED*/ 185159243Sobrienvoid 1852167465Smpdolimit(Char **v, struct command *c) 185359243Sobrien{ 1854145479Smp struct limits *lp; 1855145479Smp RLIM_TYPE limit; 185659243Sobrien int hard = 0; 185759243Sobrien 185859243Sobrien USE(c); 185959243Sobrien v++; 186059243Sobrien if (*v && eq(*v, STRmh)) { 186159243Sobrien hard = 1; 186259243Sobrien v++; 186359243Sobrien } 186459243Sobrien if (*v == 0) { 186559243Sobrien for (lp = limits; lp->limconst >= 0; lp++) 186659243Sobrien plim(lp, hard); 186759243Sobrien return; 186859243Sobrien } 186959243Sobrien lp = findlim(v[0]); 187059243Sobrien if (v[1] == 0) { 187159243Sobrien plim(lp, hard); 187259243Sobrien return; 187359243Sobrien } 187459243Sobrien limit = getval(lp, v + 1); 187559243Sobrien if (setlim(lp, hard, limit) < 0) 187659243Sobrien stderror(ERR_SILENT); 187759243Sobrien} 187859243Sobrien 187959243Sobrienstatic RLIM_TYPE 1880167465Smpgetval(struct limits *lp, Char **v) 188159243Sobrien{ 1882145479Smp float f; 188359243Sobrien Char *cp = *v++; 188459243Sobrien 188559243Sobrien f = atof(short2str(cp)); 188659243Sobrien 188759243Sobrien# ifdef convex 188859243Sobrien /* 188959243Sobrien * is f too large to cope with. limit f to minint, maxint - X-6768 by 189059243Sobrien * strike 189159243Sobrien */ 189259243Sobrien if ((f < (double) INT_MIN) || (f > (double) INT_MAX)) { 189359243Sobrien stderror(ERR_NAME | ERR_TOOLARGE); 189459243Sobrien } 189559243Sobrien# endif /* convex */ 189659243Sobrien 189759243Sobrien while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') 189859243Sobrien cp++; 189959243Sobrien if (*cp == 0) { 190059243Sobrien if (*v == 0) 190169408Sache return restrict_limit((f * lp->limdiv) + 0.5); 190259243Sobrien cp = *v; 190359243Sobrien } 190459243Sobrien switch (*cp) { 190559243Sobrien# ifdef RLIMIT_CPU 190659243Sobrien case ':': 190759243Sobrien if (lp->limconst != RLIMIT_CPU) 190859243Sobrien goto badscal; 190959243Sobrien return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f * 60.0 + atof(short2str(cp + 1)))); 191059243Sobrien case 'h': 191159243Sobrien if (lp->limconst != RLIMIT_CPU) 191259243Sobrien goto badscal; 191359243Sobrien limtail(cp, "hours"); 191459243Sobrien f *= 3600.0; 191559243Sobrien break; 191659243Sobrien case 'm': 191759243Sobrien if (lp->limconst == RLIMIT_CPU) { 191859243Sobrien limtail(cp, "minutes"); 191959243Sobrien f *= 60.0; 192059243Sobrien break; 192159243Sobrien } 192259243Sobrien *cp = 'm'; 192359243Sobrien limtail(cp, "megabytes"); 192459243Sobrien f *= 1024.0 * 1024.0; 192559243Sobrien break; 192659243Sobrien case 's': 192759243Sobrien if (lp->limconst != RLIMIT_CPU) 192859243Sobrien goto badscal; 192959243Sobrien limtail(cp, "seconds"); 193059243Sobrien break; 193159243Sobrien# endif /* RLIMIT_CPU */ 193259243Sobrien case 'M': 193359243Sobrien# ifdef RLIMIT_CPU 193459243Sobrien if (lp->limconst == RLIMIT_CPU) 193559243Sobrien goto badscal; 193659243Sobrien# endif /* RLIMIT_CPU */ 193759243Sobrien *cp = 'm'; 193859243Sobrien limtail(cp, "megabytes"); 193959243Sobrien f *= 1024.0 * 1024.0; 194059243Sobrien break; 194159243Sobrien case 'k': 194259243Sobrien# ifdef RLIMIT_CPU 194359243Sobrien if (lp->limconst == RLIMIT_CPU) 194459243Sobrien goto badscal; 194559243Sobrien# endif /* RLIMIT_CPU */ 194659243Sobrien limtail(cp, "kbytes"); 194759243Sobrien f *= 1024.0; 194859243Sobrien break; 194959243Sobrien case 'b': 195059243Sobrien# ifdef RLIMIT_CPU 195159243Sobrien if (lp->limconst == RLIMIT_CPU) 195259243Sobrien goto badscal; 195359243Sobrien# endif /* RLIMIT_CPU */ 195459243Sobrien limtail(cp, "blocks"); 195559243Sobrien f *= 512.0; 195659243Sobrien break; 195759243Sobrien case 'u': 195859243Sobrien limtail(cp, "unlimited"); 195959243Sobrien return ((RLIM_TYPE) RLIM_INFINITY); 196059243Sobrien default: 196159243Sobrien# ifdef RLIMIT_CPU 196259243Sobrienbadscal: 196359243Sobrien# endif /* RLIMIT_CPU */ 196459243Sobrien stderror(ERR_NAME | ERR_SCALEF); 196559243Sobrien } 196659243Sobrien# ifdef convex 196759243Sobrien return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f + 0.5)); 196859243Sobrien# else 196959243Sobrien f += 0.5; 197059243Sobrien if (f > (float) RLIM_INFINITY) 197159243Sobrien return ((RLIM_TYPE) RLIM_INFINITY); 197259243Sobrien else 197359243Sobrien return ((RLIM_TYPE) f); 197459243Sobrien# endif /* convex */ 197559243Sobrien} 197659243Sobrien 197759243Sobrienstatic void 1978167465Smplimtail(Char *cp, const char *str) 197959243Sobrien{ 1980145479Smp const char *sp; 198161515Sobrien 198261515Sobrien sp = str; 1983145479Smp while (*cp && *cp == (Char)*str) 198459243Sobrien cp++, str++; 198559243Sobrien if (*cp) 198661515Sobrien stderror(ERR_BADSCALE, sp); 198759243Sobrien} 198859243Sobrien 198959243Sobrien 199059243Sobrien/*ARGSUSED*/ 199159243Sobrienstatic void 1992167465Smpplim(struct limits *lp, int hard) 199359243Sobrien{ 199459243Sobrien# ifdef BSDLIMIT 199559243Sobrien struct rlimit rlim; 199659243Sobrien# endif /* BSDLIMIT */ 199759243Sobrien RLIM_TYPE limit; 1998145479Smp int xdiv = lp->limdiv; 199959243Sobrien 2000131962Smp xprintf("%-13.13s", lp->limname); 200159243Sobrien 200259243Sobrien# ifndef BSDLIMIT 200359243Sobrien limit = ulimit(lp->limconst, 0); 200459243Sobrien# ifdef aiws 200559243Sobrien if (lp->limconst == RLIMIT_DATA) 200659243Sobrien limit -= 0x20000000; 200759243Sobrien# endif /* aiws */ 200859243Sobrien# else /* BSDLIMIT */ 200959243Sobrien (void) getrlimit(lp->limconst, &rlim); 201059243Sobrien limit = hard ? rlim.rlim_max : rlim.rlim_cur; 201159243Sobrien# endif /* BSDLIMIT */ 201259243Sobrien 201359243Sobrien# if !defined(BSDLIMIT) || defined(FILESIZE512) 201459243Sobrien /* 201559243Sobrien * Christos: filesize comes in 512 blocks. we divide by 2 to get 1024 201659243Sobrien * blocks. Note we cannot pre-multiply cause we might overflow (A/UX) 201759243Sobrien */ 201859243Sobrien if (lp->limconst == RLIMIT_FSIZE) { 201959243Sobrien if (limit >= (RLIM_INFINITY / 512)) 202059243Sobrien limit = RLIM_INFINITY; 202159243Sobrien else 2022145479Smp xdiv = (xdiv == 1024 ? 2 : 1); 202359243Sobrien } 202459243Sobrien# endif /* !BSDLIMIT || FILESIZE512 */ 202559243Sobrien 202659243Sobrien if (limit == RLIM_INFINITY) 202759243Sobrien xprintf("unlimited"); 202859243Sobrien else 2029145479Smp# if defined(RLIMIT_CPU) && defined(_OSD_POSIX) 2030145479Smp if (lp->limconst == RLIMIT_CPU && 2031145479Smp (unsigned long)limit >= 0x7ffffffdUL) 2032145479Smp xprintf("unlimited"); 2033145479Smp else 2034145479Smp# endif 203559243Sobrien# ifdef RLIMIT_CPU 203659243Sobrien if (lp->limconst == RLIMIT_CPU) 2037167465Smp psecs(limit); 203859243Sobrien else 203959243Sobrien# endif /* RLIMIT_CPU */ 2040145479Smp xprintf("%ld %s", (long) (limit / xdiv), lp->limscale); 204159243Sobrien xputchar('\n'); 204259243Sobrien} 204359243Sobrien 204459243Sobrien/*ARGSUSED*/ 204559243Sobrienvoid 2046167465Smpdounlimit(Char **v, struct command *c) 204759243Sobrien{ 2048145479Smp struct limits *lp; 204959243Sobrien int lerr = 0; 205059243Sobrien int hard = 0; 205159243Sobrien int force = 0; 205259243Sobrien 205359243Sobrien USE(c); 205459243Sobrien while (*++v && **v == '-') { 205559243Sobrien Char *vp = *v; 205659243Sobrien while (*++vp) 205759243Sobrien switch (*vp) { 205859243Sobrien case 'f': 205959243Sobrien force = 1; 206059243Sobrien break; 206159243Sobrien case 'h': 206259243Sobrien hard = 1; 206359243Sobrien break; 206459243Sobrien default: 206559243Sobrien stderror(ERR_ULIMUS); 206659243Sobrien break; 206759243Sobrien } 206859243Sobrien } 206959243Sobrien 207059243Sobrien if (*v == 0) { 207159243Sobrien for (lp = limits; lp->limconst >= 0; lp++) 207259243Sobrien if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0) 207359243Sobrien lerr++; 207459243Sobrien if (!force && lerr) 207559243Sobrien stderror(ERR_SILENT); 207659243Sobrien return; 207759243Sobrien } 207859243Sobrien while (*v) { 207959243Sobrien lp = findlim(*v++); 208059243Sobrien if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0 && !force) 208159243Sobrien stderror(ERR_SILENT); 208259243Sobrien } 208359243Sobrien} 208459243Sobrien 208559243Sobrienstatic int 2086167465Smpsetlim(struct limits *lp, int hard, RLIM_TYPE limit) 208759243Sobrien{ 208859243Sobrien# ifdef BSDLIMIT 208959243Sobrien struct rlimit rlim; 209059243Sobrien 209159243Sobrien (void) getrlimit(lp->limconst, &rlim); 209259243Sobrien 209359243Sobrien# ifdef FILESIZE512 209459243Sobrien /* Even though hpux has setrlimit(), it expects fsize in 512 byte blocks */ 209559243Sobrien if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 209659243Sobrien limit /= 512; 209759243Sobrien# endif /* FILESIZE512 */ 209859243Sobrien if (hard) 209959243Sobrien rlim.rlim_max = limit; 210059243Sobrien else if (limit == RLIM_INFINITY && euid != 0) 210159243Sobrien rlim.rlim_cur = rlim.rlim_max; 210259243Sobrien else 210359243Sobrien rlim.rlim_cur = limit; 210459243Sobrien 2105100616Smp if (rlim.rlim_cur > rlim.rlim_max) 2106100616Smp rlim.rlim_max = rlim.rlim_cur; 2107100616Smp 210859243Sobrien if (setrlimit(lp->limconst, &rlim) < 0) { 210959243Sobrien# else /* BSDLIMIT */ 211059243Sobrien if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 211159243Sobrien limit /= 512; 211259243Sobrien# ifdef aiws 211359243Sobrien if (lp->limconst == RLIMIT_DATA) 211459243Sobrien limit += 0x20000000; 211559243Sobrien# endif /* aiws */ 211659243Sobrien if (ulimit(toset(lp->limconst), limit) < 0) { 211759243Sobrien# endif /* BSDLIMIT */ 2118145479Smp int err; 2119145479Smp char *op, *type; 2120145479Smp 2121145479Smp err = errno; 2122145479Smp op = strsave(limit == RLIM_INFINITY ? CGETS(15, 2, "remove") : 2123145479Smp CGETS(15, 3, "set")); 2124167465Smp cleanup_push(op, xfree); 2125145479Smp type = strsave(hard ? CGETS(15, 4, " hard") : ""); 2126167465Smp cleanup_push(type, xfree); 2127100616Smp xprintf(CGETS(15, 1, "%s: %s: Can't %s%s limit (%s)\n"), bname, 2128145479Smp lp->limname, op, type, strerror(err)); 2129167465Smp cleanup_until(op); 213059243Sobrien return (-1); 213159243Sobrien } 213259243Sobrien return (0); 213359243Sobrien} 213459243Sobrien 213559243Sobrien#endif /* !HAVENOLIMIT */ 213659243Sobrien 213759243Sobrien/*ARGSUSED*/ 213859243Sobrienvoid 2139167465Smpdosuspend(Char **v, struct command *c) 214059243Sobrien{ 214159243Sobrien#ifdef BSDJOBS 214259243Sobrien int ctpgrp; 2143167465Smp struct sigaction old; 214459243Sobrien#endif /* BSDJOBS */ 214559243Sobrien 214659243Sobrien USE(c); 214759243Sobrien USE(v); 214859243Sobrien 214959243Sobrien if (loginsh) 215059243Sobrien stderror(ERR_SUSPLOG); 215159243Sobrien untty(); 215259243Sobrien 215359243Sobrien#ifdef BSDJOBS 2154167465Smp sigaction(SIGTSTP, NULL, &old); 2155167465Smp signal(SIGTSTP, SIG_DFL); 215659243Sobrien (void) kill(0, SIGTSTP); 215759243Sobrien /* the shell stops here */ 2158167465Smp sigaction(SIGTSTP, &old, NULL); 215959243Sobrien#else /* !BSDJOBS */ 216059243Sobrien stderror(ERR_JOBCONTROL); 216159243Sobrien#endif /* BSDJOBS */ 216259243Sobrien 216359243Sobrien#ifdef BSDJOBS 216459243Sobrien if (tpgrp != -1) { 216559243Sobrienretry: 216659243Sobrien ctpgrp = tcgetpgrp(FSHTTY); 2167131962Smp if (ctpgrp == -1) 2168131962Smp stderror(ERR_SYSTEM, "tcgetpgrp", strerror(errno)); 216959243Sobrien if (ctpgrp != opgrp) { 2170167465Smp sigaction(SIGTTIN, NULL, &old); 2171167465Smp signal(SIGTTIN, SIG_DFL); 217259243Sobrien (void) kill(0, SIGTTIN); 2173167465Smp sigaction(SIGTTIN, &old, NULL); 217459243Sobrien goto retry; 217559243Sobrien } 217659243Sobrien (void) setpgid(0, shpgrp); 217759243Sobrien (void) tcsetpgrp(FSHTTY, shpgrp); 217859243Sobrien } 217959243Sobrien#endif /* BSDJOBS */ 218059243Sobrien (void) setdisc(FSHTTY); 218159243Sobrien} 218259243Sobrien 218359243Sobrien/* This is the dreaded EVAL built-in. 218459243Sobrien * If you don't fiddle with file descriptors, and reset didfds, 218559243Sobrien * this command will either ignore redirection inside or outside 218659243Sobrien * its arguments, e.g. eval "date >x" vs. eval "date" >x 218759243Sobrien * The stuff here seems to work, but I did it by trial and error rather 218859243Sobrien * than really knowing what was going on. If tpgrp is zero, we are 218959243Sobrien * probably a background eval, e.g. "eval date &", and we want to 219059243Sobrien * make sure that any processes we start stay in our pgrp. 219159243Sobrien * This is also the case for "time eval date" -- stay in same pgrp. 219259243Sobrien * Otherwise, under stty tostop, processes will stop in the wrong 219359243Sobrien * pgrp, with no way for the shell to get them going again. -IAN! 219459243Sobrien */ 219559243Sobrien 2196167465Smpstruct doeval_state 219759243Sobrien{ 2198167465Smp Char **evalvec, *evalp; 2199167465Smp int didfds; 220059243Sobrien#ifndef CLOSE_ON_EXEC 2201167465Smp int didcch; 2202167465Smp#endif 2203167465Smp int saveIN, saveOUT, saveDIAG; 2204167465Smp int SHIN, SHOUT, SHDIAG; 2205167465Smp}; 220659243Sobrien 2207167465Smpstatic void 2208167465Smpdoeval_cleanup(void *xstate) 2209167465Smp{ 2210167465Smp struct doeval_state *state; 2211167465Smp 2212167465Smp state = xstate; 2213167465Smp evalvec = state->evalvec; 2214167465Smp evalp = state->evalp; 2215167465Smp doneinp = 0; 221659243Sobrien#ifndef CLOSE_ON_EXEC 2217167465Smp didcch = state->didcch; 221859243Sobrien#endif /* CLOSE_ON_EXEC */ 2219167465Smp didfds = state->didfds; 2220167465Smp xclose(SHIN); 2221167465Smp xclose(SHOUT); 2222167465Smp xclose(SHDIAG); 2223167465Smp close_on_exec(SHIN = dmove(state->saveIN, state->SHIN), 1); 2224167465Smp close_on_exec(SHOUT = dmove(state->saveOUT, state->SHOUT), 1); 2225167465Smp close_on_exec(SHDIAG = dmove(state->saveDIAG, state->SHDIAG), 1); 2226167465Smp} 222759243Sobrien 2228167465Smp/*ARGSUSED*/ 2229167465Smpvoid 2230167465Smpdoeval(Char **v, struct command *c) 2231167465Smp{ 2232167465Smp struct doeval_state state; 2233167465Smp int gflag; 2234167465Smp Char **gv; 223559243Sobrien 2236167465Smp USE(c); 2237167465Smp v++; 2238167465Smp if (*v == 0) 223959243Sobrien return; 2240167465Smp gflag = tglob(v); 224159243Sobrien if (gflag) { 2242167465Smp gv = v = globall(v, gflag); 2243167465Smp if (v == 0) 224459243Sobrien stderror(ERR_NOMATCH); 2245167465Smp cleanup_push(gv, blk_cleanup); 2246167465Smp v = copyblk(v); 224759243Sobrien } 224859243Sobrien else { 224959243Sobrien gv = NULL; 2250167465Smp v = copyblk(v); 2251167465Smp trim(v); 225259243Sobrien } 225359243Sobrien 2254167465Smp state.evalvec = evalvec; 2255167465Smp state.evalp = evalp; 2256167465Smp state.didfds = didfds; 225759243Sobrien#ifndef CLOSE_ON_EXEC 2258167465Smp state.didcch = didcch; 225959243Sobrien#endif /* CLOSE_ON_EXEC */ 2260167465Smp state.SHIN = SHIN; 2261167465Smp state.SHOUT = SHOUT; 2262167465Smp state.SHDIAG = SHDIAG; 226359243Sobrien 2264167465Smp (void)close_on_exec(state.saveIN = dcopy(SHIN, -1), 1); 2265167465Smp (void)close_on_exec(state.saveOUT = dcopy(SHOUT, -1), 1); 2266167465Smp (void)close_on_exec(state.saveDIAG = dcopy(SHDIAG, -1), 1); 2267167465Smp 2268167465Smp cleanup_push(&state, doeval_cleanup); 2269167465Smp 2270167465Smp evalvec = v; 2271167465Smp evalp = 0; 2272167465Smp (void)close_on_exec(SHIN = dcopy(0, -1), 1); 2273167465Smp (void)close_on_exec(SHOUT = dcopy(1, -1), 1); 2274167465Smp (void)close_on_exec(SHDIAG = dcopy(2, -1), 1); 227559243Sobrien#ifndef CLOSE_ON_EXEC 2276167465Smp didcch = 0; 227759243Sobrien#endif /* CLOSE_ON_EXEC */ 2278167465Smp didfds = 0; 2279167465Smp process(0); 228059243Sobrien 2281167465Smp cleanup_until(&state); 2282167465Smp 228359243Sobrien if (gv) 2284167465Smp cleanup_until(gv); 228559243Sobrien} 228659243Sobrien 228759243Sobrien/*************************************************************************/ 228859243Sobrien/* print list of builtin commands */ 228959243Sobrien 2290167465Smpstatic void 2291167465Smplbuffed_cleanup (void *dummy) 2292167465Smp{ 2293167465Smp USE(dummy); 2294167465Smp lbuffed = 1; 2295167465Smp} 2296167465Smp 229759243Sobrien/*ARGSUSED*/ 229859243Sobrienvoid 2299167465Smpdobuiltins(Char **v, struct command *c) 230059243Sobrien{ 230159243Sobrien /* would use print_by_column() in tw.parse.c but that assumes 230259243Sobrien * we have an array of Char * to pass.. (sg) 230359243Sobrien */ 2304167465Smp const struct biltins *b; 2305145479Smp int row, col, columns, rows; 230659243Sobrien unsigned int w, maxwidth; 230759243Sobrien 230859243Sobrien USE(c); 230959243Sobrien USE(v); 231059243Sobrien lbuffed = 0; /* turn off line buffering */ 2311167465Smp cleanup_push(&lbuffed, lbuffed_cleanup); 231259243Sobrien 231359243Sobrien /* find widest string */ 231459243Sobrien for (maxwidth = 0, b = bfunc; b < &bfunc[nbfunc]; ++b) 231559243Sobrien maxwidth = max(maxwidth, strlen(b->bname)); 231659243Sobrien ++maxwidth; /* for space */ 231759243Sobrien 231859243Sobrien columns = (TermH + 1) / maxwidth; /* PWP: terminal size change */ 231959243Sobrien if (!columns) 232059243Sobrien columns = 1; 232159243Sobrien rows = (nbfunc + (columns - 1)) / columns; 232259243Sobrien 232359243Sobrien for (b = bfunc, row = 0; row < rows; row++) { 232459243Sobrien for (col = 0; col < columns; col++) { 232559243Sobrien if (b < &bfunc[nbfunc]) { 232659243Sobrien w = strlen(b->bname); 232759243Sobrien xprintf("%s", b->bname); 232859243Sobrien if (col < (columns - 1)) /* Not last column? */ 232959243Sobrien for (; w < maxwidth; w++) 233059243Sobrien xputchar(' '); 233159243Sobrien ++b; 233259243Sobrien } 233359243Sobrien } 233459243Sobrien if (row < (rows - 1)) { 233559243Sobrien if (Tty_raw_mode) 233659243Sobrien xputchar('\r'); 233759243Sobrien xputchar('\n'); 233859243Sobrien } 233959243Sobrien } 234069408Sache#ifdef WINNT_NATIVE 234159243Sobrien nt_print_builtins(maxwidth); 234259243Sobrien#else 234359243Sobrien if (Tty_raw_mode) 234459243Sobrien xputchar('\r'); 234559243Sobrien xputchar('\n'); 234669408Sache#endif /* WINNT_NATIVE */ 234759243Sobrien 2348167465Smp cleanup_until(&lbuffed); /* turn back on line buffering */ 234959243Sobrien flush(); 235059243Sobrien} 235159243Sobrien 2352145479Smp#ifdef NLS_CATALOGS 2353145479Smpchar * 2354167465Smpxcatgets(nl_catd ctd, int set_id, int msg_id, const char *s) 2355145479Smp{ 2356167465Smp char *res; 2357167465Smp 2358167465Smp errno = 0; 2359167465Smp while ((res = catgets(ctd, set_id, msg_id, s)) == s && errno == EINTR) { 2360167465Smp handle_pending_signals(); 2361167465Smp errno = 0; 2362167465Smp } 2363167465Smp return res; 2364167465Smp} 2365167465Smp 2366167465Smp 2367167465Smp# if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2368167465Smpchar * 2369167465Smpiconv_catgets(nl_catd ctd, int set_id, int msg_id, const char *s) 2370167465Smp{ 2371145479Smp static char *buf = NULL; 2372145479Smp static size_t buf_size = 0; 2373145479Smp 2374145479Smp char *orig, *dest, *p; 2375167465Smp ICONV_CONST char *src; 2376145479Smp size_t src_size, dest_size; 2377145479Smp 2378167465Smp orig = xcatgets(ctd, set_id, msg_id, s); 2379145479Smp if (catgets_iconv == (iconv_t)-1 || orig == s) 2380145479Smp return orig; 2381145479Smp src = orig; 2382145479Smp src_size = strlen(src) + 1; 2383145479Smp if (buf == NULL && (buf = xmalloc(buf_size = src_size + 32)) == NULL) 2384145479Smp return orig; 2385145479Smp dest = buf; 2386145479Smp while (src_size != 0) { 2387145479Smp dest_size = buf + buf_size - dest; 2388145479Smp if (iconv(catgets_iconv, &src, &src_size, &dest, &dest_size) 2389145479Smp == (size_t)-1) { 2390145479Smp switch (errno) { 2391145479Smp case E2BIG: 2392145479Smp if ((p = xrealloc(buf, buf_size * 2)) == NULL) 2393145479Smp return orig; 2394145479Smp buf_size *= 2; 2395145479Smp dest = p + (dest - buf); 2396145479Smp buf = p; 2397145479Smp break; 2398145479Smp 2399145479Smp case EILSEQ: case EINVAL: default: 2400145479Smp return orig; 2401145479Smp } 2402145479Smp } 2403145479Smp } 2404145479Smp return buf; 2405145479Smp} 2406167465Smp# endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2407167465Smp#endif /* NLS_CATALOGS */ 2408145479Smp 240959243Sobrienvoid 2410167465Smpnlsinit(void) 241159243Sobrien{ 241259243Sobrien#ifdef NLS_CATALOGS 2413167465Smp static const char default_catalog[] = "tcsh"; 241469408Sache 2415167465Smp char *catalog = (char *)(intptr_t)default_catalog; 2416167465Smp 241769408Sache if (adrof(STRcatalog) != NULL) 2418167465Smp catalog = xasprintf("tcsh.%s", short2str(varval(STRcatalog))); 241969408Sache catd = catopen(catalog, MCLoadBySet); 2420167465Smp if (catalog != default_catalog) 2421167465Smp xfree(catalog); 2422167465Smp#if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2423167465Smp /* xcatgets (), not CGETS, the charset name should be in ASCII anyway. */ 2424145479Smp catgets_iconv = iconv_open (nl_langinfo (CODESET), 2425167465Smp xcatgets(catd, 255, 1, "ASCII")); 2426167465Smp#endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 242769408Sache#endif /* NLS_CATALOGS */ 242869408Sache#ifdef WINNT_NATIVE 242959243Sobrien nls_dll_init(); 243069408Sache#endif /* WINNT_NATIVE */ 243159243Sobrien errinit(); /* init the errorlist in correct locale */ 243259243Sobrien mesginit(); /* init the messages for signals */ 243359243Sobrien dateinit(); /* init the messages for dates */ 243459243Sobrien editinit(); /* init the editor messages */ 243559243Sobrien terminit(); /* init the termcap messages */ 243659243Sobrien} 2437145479Smp 2438145479Smpvoid 2439167465Smpnlsclose(void) 2440145479Smp{ 2441145479Smp#ifdef NLS_CATALOGS 2442167465Smp#if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2443145479Smp if (catgets_iconv != (iconv_t)-1) { 2444145479Smp iconv_close(catgets_iconv); 2445145479Smp catgets_iconv = (iconv_t)-1; 2446145479Smp } 2447167465Smp#endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2448167465Smp if (catd != (nl_catd)-1) { 2449167465Smp /* 2450167465Smp * catclose can call other functions which can call longjmp 2451167465Smp * making us re-enter this code. Prevent infinite recursion 2452167465Smp * by resetting catd. Problem reported and solved by: 2453167465Smp * Gerhard Niklasch 2454167465Smp */ 2455167465Smp nl_catd oldcatd = catd; 2456167465Smp catd = (nl_catd)-1; 2457167465Smp while (catclose(oldcatd) == -1 && errno == EINTR) 2458167465Smp handle_pending_signals(); 2459167465Smp } 2460145479Smp#endif /* NLS_CATALOGS */ 2461145479Smp} 2462