sh.func.c revision 232633
116715Ssherman/* $Header: /p/tcsh/cvsroot/tcsh/sh.func.c,v 3.162 2011/02/26 00:07:06 christos Exp $ */ 216715Ssherman/* 316715Ssherman * sh.func.c: csh builtin functions 416715Ssherman */ 516715Ssherman/*- 616715Ssherman * Copyright (c) 1980, 1991 The Regents of the University of California. 716715Ssherman * All rights reserved. 816715Ssherman * 916715Ssherman * Redistribution and use in source and binary forms, with or without 1016715Ssherman * modification, are permitted provided that the following conditions 1116715Ssherman * are met: 1216715Ssherman * 1. Redistributions of source code must retain the above copyright 1316715Ssherman * notice, this list of conditions and the following disclaimer. 1416715Ssherman * 2. Redistributions in binary form must reproduce the above copyright 1516715Ssherman * notice, this list of conditions and the following disclaimer in the 1616715Ssherman * documentation and/or other materials provided with the distribution. 1716715Ssherman * 3. Neither the name of the University nor the names of its contributors 1816715Ssherman * may be used to endorse or promote products derived from this software 1916715Ssherman * without specific prior written permission. 2016715Ssherman * 2116715Ssherman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2216715Ssherman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2316715Ssherman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2416715Ssherman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2516715Ssherman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2616715Ssherman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2716715Ssherman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2816715Ssherman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2916715Ssherman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3016715Ssherman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3116715Ssherman * SUCH DAMAGE. 3216715Ssherman */ 3316715Ssherman#include "sh.h" 3416715Ssherman 3516715SshermanRCSID("$tcsh: sh.func.c,v 3.162 2011/02/26 00:07:06 christos Exp $") 3616715Ssherman 3716715Ssherman#include "ed.h" 3816715Ssherman#include "tw.h" 3916715Ssherman#include "tc.h" 4016715Ssherman#ifdef WINNT_NATIVE 4116715Ssherman#include "nt.const.h" 4216715Ssherman#endif /* WINNT_NATIVE */ 4316715Ssherman 4416715Ssherman#if defined (NLS_CATALOGS) && defined(HAVE_ICONV) 4516715Sshermanstatic iconv_t catgets_iconv; /* Or (iconv_t)-1 */ 4616715Ssherman#endif 4716715Ssherman 4816715Ssherman/* 4916715Ssherman * C shell 5016715Ssherman */ 5116715Ssherman 5216715Sshermanextern int MapsAreInited; 5316715Sshermanextern int NLSMapsAreInited; 5416715Sshermanextern int GotTermCaps; 5516715Ssherman 5616715Sshermanstatic int zlast = -1; 5716715Ssherman 5816715Sshermanstatic void islogin (void); 5916715Sshermanstatic void preread (void); 6016715Sshermanstatic void doagain (void); 6116715Sshermanstatic const char *isrchx (int); 6216715Sshermanstatic void search (int, int, Char *); 6316715Sshermanstatic int getword (struct Strbuf *); 6416715Sshermanstatic struct wordent *histgetword (struct wordent *); 6516715Sshermanstatic void toend (void); 6616715Sshermanstatic void xecho (int, Char **); 6716715Sshermanstatic int islocale_var (Char *); 6816715Sshermanstatic void wpfree (struct whyle *); 6916715Ssherman 7016715Sshermanconst struct biltins * 7116715Sshermanisbfunc(struct command *t) 7216715Ssherman{ 7316715Ssherman Char *cp = t->t_dcom[0]; 7416715Ssherman const struct biltins *bp, *bp1, *bp2; 7516715Ssherman static struct biltins label = {"", dozip, 0, 0}; 7616715Ssherman static struct biltins foregnd = {"%job", dofg1, 0, 0}; 7716715Ssherman static struct biltins backgnd = {"%job &", dobg1, 0, 0}; 7816715Ssherman 7916715Ssherman /* 8016715Ssherman * We never match a builtin that has quoted the first 8116715Ssherman * character; this has been the traditional way to escape 8216715Ssherman * builtin commands. 8316715Ssherman */ 8416715Ssherman if (*cp & QUOTE) 8516715Ssherman return NULL; 8616715Ssherman 8716715Ssherman if (*cp != ':' && lastchr(cp) == ':') { 8816715Ssherman label.bname = short2str(cp); 8916715Ssherman return (&label); 9016715Ssherman } 9116715Ssherman if (*cp == '%') { 9216715Ssherman if (t->t_dflg & F_AMPERSAND) { 9316715Ssherman t->t_dflg &= ~F_AMPERSAND; 9416715Ssherman backgnd.bname = short2str(cp); 9516715Ssherman return (&backgnd); 9616715Ssherman } 9716715Ssherman foregnd.bname = short2str(cp); 9816715Ssherman return (&foregnd); 9916715Ssherman } 10016715Ssherman#ifdef WARP 10116715Ssherman /* 10216715Ssherman * This is a perhaps kludgy way to determine if the warp builtin is to be 10316715Ssherman * acknowledged or not. If checkwarp() fails, then we are to assume that 10416715Ssherman * the warp command is invalid, and carry on as we would handle any other 10516715Ssherman * non-builtin command. -- JDK 2/4/88 10616715Ssherman */ 10716715Ssherman if (eq(STRwarp, cp) && !checkwarp()) { 10816715Ssherman return (0); /* this builtin disabled */ 10916715Ssherman } 11016715Ssherman#endif /* WARP */ 11116715Ssherman /* 11216715Ssherman * Binary search Bp1 is the beginning of the current search range. Bp2 is 11316715Ssherman * one past the end. 11416715Ssherman */ 11516715Ssherman for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) { 11616715Ssherman int i; 11716715Ssherman 11816715Ssherman bp = bp1 + ((bp2 - bp1) >> 1); 11916715Ssherman if ((i = ((char) *cp) - *bp->bname) == 0 && 12016715Ssherman (i = StrQcmp(cp, str2short(bp->bname))) == 0) 12116715Ssherman return bp; 12216715Ssherman if (i < 0) 12316715Ssherman bp2 = bp; 12416715Ssherman else 12516715Ssherman bp1 = bp + 1; 12616715Ssherman } 12716715Ssherman#ifdef WINNT_NATIVE 12816715Ssherman return nt_check_additional_builtins(cp); 12916715Ssherman#endif /*WINNT_NATIVE*/ 13016715Ssherman return (0); 13116715Ssherman} 13216715Ssherman 13316715Sshermanvoid 13416715Sshermanfunc(struct command *t, const struct biltins *bp) 13516715Ssherman{ 13616715Ssherman int i; 13716715Ssherman 13816715Ssherman xechoit(t->t_dcom); 13916715Ssherman setname(bp->bname); 14016715Ssherman i = blklen(t->t_dcom) - 1; 14116715Ssherman if (i < bp->minargs) 14216715Ssherman stderror(ERR_NAME | ERR_TOOFEW); 14316715Ssherman if (i > bp->maxargs) 14416715Ssherman stderror(ERR_NAME | ERR_TOOMANY); 14516715Ssherman (*bp->bfunct) (t->t_dcom, t); 14616715Ssherman} 14716715Ssherman 14816715Ssherman/*ARGSUSED*/ 14916715Sshermanvoid 15016715Sshermandoonintr(Char **v, struct command *c) 15116715Ssherman{ 15216715Ssherman Char *cp; 15316715Ssherman Char *vv = v[1]; 15416715Ssherman 15516715Ssherman USE(c); 15616715Ssherman if (parintr.sa_handler == SIG_IGN) 15716715Ssherman return; 15816715Ssherman if (setintr && intty) 15916715Ssherman stderror(ERR_NAME | ERR_TERMINAL); 16016715Ssherman cp = gointr; 16116715Ssherman gointr = 0; 16216715Ssherman xfree(cp); 16316715Ssherman if (vv == 0) { 16416715Ssherman if (setintr) 16516715Ssherman sigset_interrupting(SIGINT, queue_pintr); 16616715Ssherman else 16716715Ssherman (void) signal(SIGINT, SIG_DFL); 16816715Ssherman gointr = 0; 16916715Ssherman } 17016715Ssherman else if (eq((vv = strip(vv)), STRminus)) { 17116715Ssherman (void) signal(SIGINT, SIG_IGN); 17216715Ssherman gointr = Strsave(STRminus); 17316715Ssherman } 17416715Ssherman else { 17516715Ssherman gointr = Strsave(vv); 17616715Ssherman sigset_interrupting(SIGINT, queue_pintr); 17716715Ssherman } 17816715Ssherman} 17916715Ssherman 18016715Ssherman/*ARGSUSED*/ 18116715Sshermanvoid 18216715Sshermandonohup(Char **v, struct command *c) 18316715Ssherman{ 18416715Ssherman USE(c); 18516715Ssherman USE(v); 18616715Ssherman if (intty) 18716715Ssherman stderror(ERR_NAME | ERR_TERMINAL); 18816715Ssherman if (setintr == 0) { 18916715Ssherman (void) signal(SIGHUP, SIG_IGN); 19016715Ssherman phup_disabled = 1; 19116715Ssherman#ifdef CC 19216715Ssherman submit(getpid()); 19316715Ssherman#endif /* CC */ 19416715Ssherman } 19516715Ssherman} 19616715Ssherman 19716715Ssherman/*ARGSUSED*/ 19816715Sshermanvoid 19916715Sshermandohup(Char **v, struct command *c) 20016715Ssherman{ 20116715Ssherman USE(c); 20216715Ssherman USE(v); 20316715Ssherman if (intty) 20416715Ssherman stderror(ERR_NAME | ERR_TERMINAL); 20516715Ssherman if (setintr == 0) 20616715Ssherman (void) signal(SIGHUP, SIG_DFL); 20716715Ssherman} 20816715Ssherman 20916715Ssherman 21016715Ssherman/*ARGSUSED*/ 21116715Sshermanvoid 21216715Sshermandozip(Char **v, struct command *c) 21316715Ssherman{ 21416715Ssherman USE(c); 21516715Ssherman USE(v); 21616715Ssherman} 21716715Ssherman 21816715Ssherman/*ARGSUSED*/ 21916715Sshermanvoid 22016715Sshermandofiletest(Char **v, struct command *c) 22116715Ssherman{ 22216715Ssherman Char **globbed, **fileptr, *ftest, *res; 22316715Ssherman 22416715Ssherman USE(c); 22516715Ssherman if (*(ftest = *++v) != '-') 22616715Ssherman stderror(ERR_NAME | ERR_FILEINQ); 22716715Ssherman ++v; 22816715Ssherman 22916715Ssherman v = glob_all_or_error(v); 23016715Ssherman globbed = v; 23116715Ssherman cleanup_push(globbed, blk_cleanup); 23216715Ssherman 23316715Ssherman while (*(fileptr = v++) != '\0') { 23416715Ssherman res = filetest(ftest, &fileptr, 0); 23516715Ssherman cleanup_push(res, xfree); 23616715Ssherman xprintf("%S", res); 23716715Ssherman cleanup_until(res); 23816715Ssherman if (*v) 23916715Ssherman xprintf(" "); 24016715Ssherman } 24116715Ssherman xprintf("\n"); 24216715Ssherman 24316715Ssherman cleanup_until(globbed); 24416715Ssherman} 24516715Ssherman 24616715Sshermanvoid 24716715Sshermanprvars(void) 24816715Ssherman{ 24916715Ssherman plist(&shvhed, VAR_ALL); 25016715Ssherman} 25116715Ssherman 25216715Ssherman/*ARGSUSED*/ 25316715Sshermanvoid 25416715Sshermandoalias(Char **v, struct command *c) 25516715Ssherman{ 25616715Ssherman struct varent *vp; 25716715Ssherman Char *p; 25816715Ssherman 25916715Ssherman USE(c); 26016715Ssherman v++; 26116715Ssherman p = *v++; 26216715Ssherman if (p == 0) 26316715Ssherman plist(&aliases, VAR_ALL); 26416715Ssherman else if (*v == 0) { 26516715Ssherman vp = adrof1(strip(p), &aliases); 26616715Ssherman if (vp && vp->vec) 26716715Ssherman blkpr(vp->vec), xputchar('\n'); 26816715Ssherman } 26916715Ssherman else { 27016715Ssherman if (eq(p, STRalias) || eq(p, STRunalias)) { 27116715Ssherman setname(short2str(p)); 27216715Ssherman stderror(ERR_NAME | ERR_DANGER); 27316715Ssherman } 27416715Ssherman set1(strip(p), saveblk(v), &aliases, VAR_READWRITE); 27516715Ssherman tw_cmd_free(); 27616715Ssherman } 27716715Ssherman} 27816715Ssherman 27916715Ssherman/*ARGSUSED*/ 28016715Sshermanvoid 28116715Sshermanunalias(Char **v, struct command *c) 28216715Ssherman{ 28316715Ssherman USE(c); 28416715Ssherman unset1(v, &aliases); 28516715Ssherman tw_cmd_free(); 28616715Ssherman} 28716715Ssherman 28816715Ssherman/*ARGSUSED*/ 28916715Sshermanvoid 29016715Sshermandologout(Char **v, struct command *c) 29116715Ssherman{ 29216715Ssherman USE(c); 29316715Ssherman USE(v); 29416715Ssherman islogin(); 29516715Ssherman goodbye(NULL, NULL); 29616715Ssherman} 29716715Ssherman 29816715Ssherman/*ARGSUSED*/ 29916715Sshermanvoid 30016715Sshermandologin(Char **v, struct command *c) 30116715Ssherman{ 30216715Ssherman#ifdef WINNT_NATIVE 30316715Ssherman USE(c); 30416715Ssherman USE(v); 30516715Ssherman#else /* !WINNT_NATIVE */ 30616715Ssherman char **p = short2blk(v); 30716715Ssherman 30816715Ssherman USE(c); 30916715Ssherman cleanup_push((Char **)p, blk_cleanup); 31016715Ssherman islogin(); 31116715Ssherman rechist(NULL, adrof(STRsavehist) != NULL); 31216715Ssherman sigaction(SIGTERM, &parterm, NULL); 31316715Ssherman (void) execv(_PATH_BIN_LOGIN, p); 31416715Ssherman (void) execv(_PATH_USRBIN_LOGIN, p); 31516715Ssherman cleanup_until((Char **)p); 31616715Ssherman untty(); 31716715Ssherman xexit(1); 31816715Ssherman#endif /* !WINNT_NATIVE */ 31916715Ssherman} 32016715Ssherman 32116715Ssherman 32216715Ssherman#ifdef NEWGRP 32316715Ssherman/*ARGSUSED*/ 32416715Sshermanvoid 32516715Sshermandonewgrp(Char **v, struct command *c) 32616715Ssherman{ 32716715Ssherman char **p; 32816715Ssherman if (chkstop == 0 && setintr) 32916715Ssherman panystop(0); 33016715Ssherman sigaction(SIGTERM, &parterm, NULL); 33116715Ssherman p = short2blk(v); 33216715Ssherman /* 33316715Ssherman * From Beto Appleton (beto@aixwiz.austin.ibm.com) 33416715Ssherman * Newgrp can take 2 arguments... 33516715Ssherman */ 33616715Ssherman (void) execv(_PATH_BIN_NEWGRP, p); 33716715Ssherman (void) execv(_PATH_USRBIN_NEWGRP, p); 33816715Ssherman blkfree((Char **) p); 33916715Ssherman untty(); 34016715Ssherman xexit(1); 34116715Ssherman} 34216715Ssherman#endif /* NEWGRP */ 34316715Ssherman 34416715Sshermanstatic void 34516715Sshermanislogin(void) 34616715Ssherman{ 34716715Ssherman if (chkstop == 0 && setintr) 34816715Ssherman panystop(0); 34916715Ssherman if (loginsh) 35016715Ssherman return; 35116715Ssherman stderror(ERR_NOTLOGIN); 35216715Ssherman} 35316715Ssherman 35416715Sshermanvoid 35516715Sshermandoif(Char **v, struct command *kp) 35616715Ssherman{ 35716715Ssherman int i; 35816715Ssherman Char **vv; 35916715Ssherman 36016715Ssherman v++; 36116715Ssherman i = noexec ? 1 : expr(&v); 36216715Ssherman vv = v; 36316715Ssherman if (*vv == NULL) 36416715Ssherman stderror(ERR_NAME | ERR_EMPTYIF); 36516715Ssherman if (eq(*vv, STRthen)) { 36616715Ssherman if (*++vv) 36716715Ssherman stderror(ERR_NAME | ERR_IMPRTHEN); 36816715Ssherman setname(short2str(STRthen)); 36916715Ssherman /* 37016715Ssherman * If expression was zero, then scan to else , otherwise just fall into 37116715Ssherman * following code. 37216715Ssherman */ 37316715Ssherman if (!i) 37416715Ssherman search(TC_IF, 0, NULL); 37516715Ssherman return; 37616715Ssherman } 37716715Ssherman /* 37816715Ssherman * Simple command attached to this if. Left shift the node in this tree, 37916715Ssherman * munging it so we can reexecute it. 38016715Ssherman */ 38116715Ssherman if (i) { 38216715Ssherman lshift(kp->t_dcom, vv - kp->t_dcom); 38316715Ssherman reexecute(kp); 38416715Ssherman donefds(); 38516715Ssherman } 38616715Ssherman} 38716715Ssherman 38816715Ssherman/* 38916715Ssherman * Reexecute a command, being careful not 39016715Ssherman * to redo i/o redirection, which is already set up. 39116715Ssherman */ 39216715Sshermanvoid 39316715Sshermanreexecute(struct command *kp) 39416715Ssherman{ 39516715Ssherman kp->t_dflg &= F_SAVE; 39616715Ssherman kp->t_dflg |= F_REPEAT; 39716715Ssherman /* 39816715Ssherman * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set 39916715Ssherman * pgrp's as the jobs would then have no way to get the tty (we can't give 40016715Ssherman * it to them, and our parent wouldn't know their pgrp, etc. 40116715Ssherman */ 40216715Ssherman execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL, TRUE); 40316715Ssherman} 40416715Ssherman 40516715Ssherman/*ARGSUSED*/ 40616715Sshermanvoid 40716715Sshermandoelse (Char **v, struct command *c) 40816715Ssherman{ 40916715Ssherman USE(c); 41016715Ssherman USE(v); 41116715Ssherman if (!noexec) 41216715Ssherman search(TC_ELSE, 0, NULL); 41316715Ssherman} 41416715Ssherman 41516715Ssherman/*ARGSUSED*/ 41616715Sshermanvoid 41716715Sshermandogoto(Char **v, struct command *c) 41816715Ssherman{ 41916715Ssherman Char *lp; 42016715Ssherman 42116715Ssherman USE(c); 42216715Ssherman lp = globone(v[1], G_ERROR); 42316715Ssherman cleanup_push(lp, xfree); 42416715Ssherman if (!noexec) 42516715Ssherman gotolab(lp); 42616715Ssherman cleanup_until(lp); 42716715Ssherman} 42816715Ssherman 42916715Sshermanvoid 43016715Sshermangotolab(Char *lab) 43116715Ssherman{ 43216715Ssherman struct whyle *wp; 43316715Ssherman /* 43416715Ssherman * While we still can, locate any unknown ends of existing loops. This 43516715Ssherman * obscure code is the WORST result of the fact that we don't really parse. 43616715Ssherman */ 43716715Ssherman zlast = TC_GOTO; 43816715Ssherman for (wp = whyles; wp; wp = wp->w_next) 43916715Ssherman if (wp->w_end.type == TCSH_F_SEEK && wp->w_end.f_seek == 0) { 44016715Ssherman search(TC_BREAK, 0, NULL); 44116715Ssherman btell(&wp->w_end); 44216715Ssherman } 44316715Ssherman else { 44416715Ssherman bseek(&wp->w_end); 44516715Ssherman } 44616715Ssherman search(TC_GOTO, 0, lab); 44716715Ssherman /* 44816715Ssherman * Eliminate loops which were exited. 44916715Ssherman */ 45016715Ssherman wfree(); 45116715Ssherman} 45216715Ssherman 45316715Ssherman/*ARGSUSED*/ 45416715Sshermanvoid 45516715Sshermandoswitch(Char **v, struct command *c) 45616715Ssherman{ 45716715Ssherman Char *cp, *lp; 45816715Ssherman 45916715Ssherman USE(c); 46016715Ssherman v++; 46116715Ssherman if (!*v || *(*v++) != '(') 46216715Ssherman stderror(ERR_SYNTAX); 46316715Ssherman cp = **v == ')' ? STRNULL : *v++; 46416715Ssherman if (*(*v++) != ')') 46516715Ssherman v--; 46616715Ssherman if (*v) 46716715Ssherman stderror(ERR_SYNTAX); 46816715Ssherman lp = globone(cp, G_ERROR); 46916715Ssherman cleanup_push(lp, xfree); 47016715Ssherman if (!noexec) 47116715Ssherman search(TC_SWITCH, 0, lp); 47216715Ssherman cleanup_until(lp); 47316715Ssherman} 47416715Ssherman 47516715Ssherman/*ARGSUSED*/ 47616715Sshermanvoid 47716715Sshermandobreak(Char **v, struct command *c) 47816715Ssherman{ 47916715Ssherman USE(v); 48016715Ssherman USE(c); 48116715Ssherman if (whyles == NULL) 48216715Ssherman stderror(ERR_NAME | ERR_NOTWHILE); 48316715Ssherman if (!noexec) 48416715Ssherman toend(); 48516715Ssherman} 48616715Ssherman 48716715Ssherman/*ARGSUSED*/ 48816715Sshermanvoid 48916715Sshermandoexit(Char **v, struct command *c) 49016715Ssherman{ 49116715Ssherman USE(c); 49216715Ssherman 49316715Ssherman if (chkstop == 0 && (intty || intact) && evalvec == 0) 49416715Ssherman panystop(0); 49516715Ssherman /* 49616715Ssherman * Don't DEMAND parentheses here either. 49716715Ssherman */ 49816715Ssherman v++; 49916715Ssherman if (*v) { 50016715Ssherman setv(STRstatus, putn(expr(&v)), VAR_READWRITE); 50116715Ssherman if (*v) 50216715Ssherman stderror(ERR_NAME | ERR_EXPRESSION); 50316715Ssherman } 50416715Ssherman btoeof(); 50516715Ssherman#if 0 50616715Ssherman if (intty) 50716715Ssherman#endif 50816715Ssherman /* Always close, why only on ttys? */ 50916715Ssherman xclose(SHIN); 51016715Ssherman} 51116715Ssherman 51216715Ssherman/*ARGSUSED*/ 51316715Sshermanvoid 51416715Sshermandoforeach(Char **v, struct command *c) 51516715Ssherman{ 51616715Ssherman Char *cp, *sp; 51716715Ssherman struct whyle *nwp; 51816715Ssherman int gflag; 51916715Ssherman 52016715Ssherman USE(c); 52116715Ssherman v++; 52216715Ssherman cp = sp = strip(*v); 52316715Ssherman if (!letter(*cp)) 52416715Ssherman stderror(ERR_NAME | ERR_VARBEGIN); 52516715Ssherman do { 52616715Ssherman cp++; 52716715Ssherman } while (alnum(*cp)); 52816715Ssherman if (*cp != '\0') 52916715Ssherman stderror(ERR_NAME | ERR_VARALNUM); 53016715Ssherman cp = *v++; 53116715Ssherman if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') 53216715Ssherman stderror(ERR_NAME | ERR_NOPAREN); 53316715Ssherman v++; 53416715Ssherman gflag = tglob(v); 53516715Ssherman if (gflag) { 53616715Ssherman v = globall(v, gflag); 53716715Ssherman if (v == 0 && !noexec) 53816715Ssherman stderror(ERR_NAME | ERR_NOMATCH); 53916715Ssherman } 54016715Ssherman else { 54116715Ssherman v = saveblk(v); 54216715Ssherman trim(v); 54316715Ssherman } 54416715Ssherman nwp = xcalloc(1, sizeof *nwp); 54516715Ssherman nwp->w_fe = nwp->w_fe0 = v; 54616715Ssherman btell(&nwp->w_start); 54716715Ssherman nwp->w_fename = Strsave(cp); 54816715Ssherman nwp->w_next = whyles; 54916715Ssherman nwp->w_end.type = TCSH_F_SEEK; 55016715Ssherman whyles = nwp; 55116715Ssherman /* 55216715Ssherman * Pre-read the loop so as to be more comprehensible to a terminal user. 55316715Ssherman */ 55416715Ssherman zlast = TC_FOREACH; 55516715Ssherman if (intty) 55616715Ssherman preread(); 55716715Ssherman if (!noexec) 55816715Ssherman doagain(); 55916715Ssherman} 56016715Ssherman 56116715Ssherman/*ARGSUSED*/ 56216715Sshermanvoid 56316715Sshermandowhile(Char **v, struct command *c) 56416715Ssherman{ 56516715Ssherman int status; 56616715Ssherman int again = whyles != 0 && 56716715Ssherman SEEKEQ(&whyles->w_start, &lineloc) && 56816715Ssherman whyles->w_fename == 0; 56916715Ssherman 57016715Ssherman USE(c); 57116715Ssherman v++; 57216715Ssherman /* 57316715Ssherman * Implement prereading here also, taking care not to evaluate the 57416715Ssherman * expression before the loop has been read up from a terminal. 57516715Ssherman */ 57616715Ssherman if (noexec) 57716715Ssherman status = 0; 57816715Ssherman else if (intty && !again) 57916715Ssherman status = !exp0(&v, 1); 58016715Ssherman else 58116715Ssherman status = !expr(&v); 58216715Ssherman if (*v && !noexec) 58316715Ssherman stderror(ERR_NAME | ERR_EXPRESSION); 58416715Ssherman if (!again) { 58516715Ssherman struct whyle *nwp = xcalloc(1, sizeof(*nwp)); 58616715Ssherman 58716715Ssherman nwp->w_start = lineloc; 58816715Ssherman nwp->w_end.type = TCSH_F_SEEK; 58916715Ssherman nwp->w_end.f_seek = 0; 59016715Ssherman nwp->w_end.a_seek = 0; 59116715Ssherman nwp->w_next = whyles; 59216715Ssherman whyles = nwp; 59316715Ssherman zlast = TC_WHILE; 59416715Ssherman if (intty) { 59516715Ssherman /* 59616715Ssherman * The tty preread 59716715Ssherman */ 59816715Ssherman preread(); 59916715Ssherman doagain(); 60016715Ssherman return; 60116715Ssherman } 60216715Ssherman } 60316715Ssherman if (status) 60416715Ssherman /* We ain't gonna loop no more, no more! */ 60516715Ssherman toend(); 60616715Ssherman} 60716715Ssherman 60816715Sshermanstatic void 60916715Sshermanpreread(void) 61016715Ssherman{ 61116715Ssherman int old_pintr_disabled; 61216715Ssherman 61316715Ssherman whyles->w_end.type = TCSH_I_SEEK; 61416715Ssherman if (setintr) 61516715Ssherman pintr_push_enable(&old_pintr_disabled); 61616715Ssherman search(TC_BREAK, 0, NULL); /* read the expression in */ 61716715Ssherman if (setintr) 61816715Ssherman cleanup_until(&old_pintr_disabled); 61916715Ssherman btell(&whyles->w_end); 62016715Ssherman} 62116715Ssherman 62216715Ssherman/*ARGSUSED*/ 62316715Sshermanvoid 62416715Sshermandoend(Char **v, struct command *c) 62516715Ssherman{ 62616715Ssherman USE(v); 62716715Ssherman USE(c); 62816715Ssherman if (!whyles) 62916715Ssherman stderror(ERR_NAME | ERR_NOTWHILE); 63016715Ssherman btell(&whyles->w_end); 63116715Ssherman if (!noexec) 63216715Ssherman doagain(); 63316715Ssherman} 63416715Ssherman 63516715Ssherman/*ARGSUSED*/ 63616715Sshermanvoid 63716715Sshermandocontin(Char **v, struct command *c) 63816715Ssherman{ 63916715Ssherman USE(v); 64016715Ssherman USE(c); 64116715Ssherman if (!whyles) 64216715Ssherman stderror(ERR_NAME | ERR_NOTWHILE); 64316715Ssherman if (!noexec) 64416715Ssherman doagain(); 64516715Ssherman} 64616715Ssherman 64716715Sshermanstatic void 64816715Sshermandoagain(void) 64916715Ssherman{ 65016715Ssherman /* Repeating a while is simple */ 65116715Ssherman if (whyles->w_fename == 0) { 65216715Ssherman bseek(&whyles->w_start); 65316715Ssherman return; 65416715Ssherman } 65516715Ssherman /* 65616715Ssherman * The foreach variable list actually has a spurious word ")" at the end of 65716715Ssherman * the w_fe list. Thus we are at the of the list if one word beyond this 65816715Ssherman * is 0. 65916715Ssherman */ 66016715Ssherman if (!whyles->w_fe[1]) { 66116715Ssherman dobreak(NULL, NULL); 66216715Ssherman return; 66316715Ssherman } 66416715Ssherman setv(whyles->w_fename, quote(Strsave(*whyles->w_fe++)), VAR_READWRITE); 66516715Ssherman bseek(&whyles->w_start); 66616715Ssherman} 66716715Ssherman 66816715Sshermanvoid 66916715Sshermandorepeat(Char **v, struct command *kp) 67016715Ssherman{ 67116715Ssherman int i = 1; 67216715Ssherman 67316715Ssherman do { 67416715Ssherman i *= getn(v[1]); 67516715Ssherman lshift(v, 2); 67616715Ssherman } while (v[0] != NULL && Strcmp(v[0], STRrepeat) == 0); 67716715Ssherman if (noexec) 67816715Ssherman i = 1; 67916715Ssherman 68016715Ssherman if (setintr) { 68116715Ssherman pintr_disabled++; 68216715Ssherman cleanup_push(&pintr_disabled, disabled_cleanup); 68316715Ssherman } 68416715Ssherman while (i > 0) { 68516715Ssherman if (setintr && pintr_disabled == 1) { 68616715Ssherman cleanup_until(&pintr_disabled); 68716715Ssherman pintr_disabled++; 68816715Ssherman cleanup_push(&pintr_disabled, disabled_cleanup); 68916715Ssherman } 69016715Ssherman reexecute(kp); 69116715Ssherman --i; 69216715Ssherman } 69316715Ssherman if (setintr && pintr_disabled == 1) 69416715Ssherman cleanup_until(&pintr_disabled); 69516715Ssherman donefds(); 69616715Ssherman} 69716715Ssherman 69816715Ssherman/*ARGSUSED*/ 69916715Sshermanvoid 70016715Sshermandoswbrk(Char **v, struct command *c) 70116715Ssherman{ 70216715Ssherman USE(v); 70316715Ssherman USE(c); 70416715Ssherman if (!noexec) 70516715Ssherman search(TC_BRKSW, 0, NULL); 70616715Ssherman} 70716715Ssherman 70816715Sshermanint 70916715Sshermansrchx(Char *cp) 71016715Ssherman{ 71116715Ssherman struct srch *sp, *sp1, *sp2; 71216715Ssherman int i; 71316715Ssherman 71416715Ssherman /* 71516715Ssherman * Ignore keywords inside heredocs 71616715Ssherman */ 71716715Ssherman if (inheredoc) 71816715Ssherman return -1; 71916715Ssherman 72016715Ssherman /* 72116715Ssherman * Binary search Sp1 is the beginning of the current search range. Sp2 is 72216715Ssherman * one past the end. 72316715Ssherman */ 72416715Ssherman for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) { 72516715Ssherman sp = sp1 + ((sp2 - sp1) >> 1); 72616715Ssherman if ((i = *cp - *sp->s_name) == 0 && 72716715Ssherman (i = Strcmp(cp, str2short(sp->s_name))) == 0) 72816715Ssherman return sp->s_value; 72916715Ssherman if (i < 0) 73016715Ssherman sp2 = sp; 73116715Ssherman else 73216715Ssherman sp1 = sp + 1; 73316715Ssherman } 73416715Ssherman return (-1); 73516715Ssherman} 73616715Ssherman 73716715Sshermanstatic const char * 73816715Sshermanisrchx(int n) 73916715Ssherman{ 74016715Ssherman struct srch *sp, *sp2; 74116715Ssherman 74216715Ssherman for (sp = srchn, sp2 = srchn + nsrchn; sp < sp2; sp++) 74316715Ssherman if (sp->s_value == n) 74416715Ssherman return (sp->s_name); 74516715Ssherman return (""); 74616715Ssherman} 74716715Ssherman 74816715Ssherman 74916715Sshermanstatic int Stype; 75016715Sshermanstatic Char *Sgoal; 75116715Ssherman 75216715Sshermanstatic void 75316715Sshermansearch(int type, int level, Char *goal) 75416715Ssherman{ 75516715Ssherman struct Strbuf word = Strbuf_INIT; 75616715Ssherman Char *cp; 75716715Ssherman struct whyle *wp; 75816715Ssherman int wlevel = 0; 75916715Ssherman struct wordent *histent = NULL, *ohistent = NULL; 76016715Ssherman 76116715Ssherman Stype = type; 76216715Ssherman Sgoal = goal; 76316715Ssherman if (type == TC_GOTO) { 76416715Ssherman struct Ain a; 76516715Ssherman a.type = TCSH_F_SEEK; 76616715Ssherman a.f_seek = 0; 76716715Ssherman a.a_seek = 0; 76816715Ssherman bseek(&a); 76916715Ssherman } 77016715Ssherman cleanup_push(&word, Strbuf_cleanup); 77116715Ssherman do { 77216715Ssherman 77316715Ssherman if (intty) { 77416715Ssherman histent = xmalloc(sizeof(*histent)); 77516715Ssherman ohistent = xmalloc(sizeof(*histent)); 77616715Ssherman ohistent->word = STRNULL; 77716715Ssherman ohistent->next = histent; 77816715Ssherman histent->prev = ohistent; 77916715Ssherman } 78016715Ssherman 78116715Ssherman if (intty && fseekp == feobp && aret == TCSH_F_SEEK) 78216715Ssherman printprompt(1, isrchx(type == TC_BREAK ? zlast : type)); 78316715Ssherman /* xprintf("? "), flush(); */ 78416715Ssherman (void) getword(&word); 78516715Ssherman Strbuf_terminate(&word); 78616715Ssherman 78716715Ssherman if (intty && Strlen(word.s) > 0) { 78816715Ssherman histent->word = Strsave(word.s); 78916715Ssherman histent->next = xmalloc(sizeof(*histent)); 79016715Ssherman histent->next->prev = histent; 79116715Ssherman histent = histent->next; 79216715Ssherman } 79316715Ssherman 79416715Ssherman switch (srchx(word.s)) { 79516715Ssherman 79616715Ssherman case TC_ELSE: 79716715Ssherman if (level == 0 && type == TC_IF) 79816715Ssherman goto end; 79916715Ssherman break; 80016715Ssherman 80116715Ssherman case TC_IF: 80216715Ssherman while (getword(&word)) 80316715Ssherman continue; 80416715Ssherman if ((type == TC_IF || type == TC_ELSE) && 80516715Ssherman eq(word.s, STRthen)) 80616715Ssherman level++; 80716715Ssherman break; 80816715Ssherman 80916715Ssherman case TC_ENDIF: 81016715Ssherman if (type == TC_IF || type == TC_ELSE) 81116715Ssherman level--; 81216715Ssherman break; 81316715Ssherman 81416715Ssherman case TC_FOREACH: 81516715Ssherman case TC_WHILE: 81616715Ssherman wlevel++; 81716715Ssherman if (type == TC_BREAK) 81816715Ssherman level++; 81916715Ssherman break; 82016715Ssherman 82116715Ssherman case TC_END: 82216715Ssherman if (type == TC_BRKSW) { 82316715Ssherman if (wlevel == 0) { 82416715Ssherman wp = whyles; 82516715Ssherman if (wp) { 82616715Ssherman whyles = wp->w_next; 82716715Ssherman wpfree(wp); 82816715Ssherman } 82916715Ssherman } 83016715Ssherman } 83116715Ssherman if (type == TC_BREAK) 83216715Ssherman level--; 83316715Ssherman wlevel--; 83416715Ssherman break; 83516715Ssherman 83616715Ssherman case TC_SWITCH: 83716715Ssherman if (type == TC_SWITCH || type == TC_BRKSW) 83816715Ssherman level++; 83916715Ssherman break; 84016715Ssherman 84116715Ssherman case TC_ENDSW: 84216715Ssherman if (type == TC_SWITCH || type == TC_BRKSW) 84316715Ssherman level--; 84416715Ssherman break; 84516715Ssherman 84616715Ssherman case TC_LABEL: 84716715Ssherman if (type == TC_GOTO && getword(&word) && eq(word.s, goal)) 84816715Ssherman level = -1; 84916715Ssherman break; 85016715Ssherman 85116715Ssherman default: 85216715Ssherman if (type != TC_GOTO && (type != TC_SWITCH || level != 0)) 85316715Ssherman break; 85416715Ssherman if (word.len == 0 || word.s[word.len - 1] != ':') 85516715Ssherman break; 85616715Ssherman word.s[--word.len] = 0; 85716715Ssherman if ((type == TC_GOTO && eq(word.s, goal)) || 85816715Ssherman (type == TC_SWITCH && eq(word.s, STRdefault))) 85916715Ssherman level = -1; 86016715Ssherman break; 86116715Ssherman 86216715Ssherman case TC_CASE: 86316715Ssherman if (type != TC_SWITCH || level != 0) 86416715Ssherman break; 86516715Ssherman (void) getword(&word); 86616715Ssherman if (word.len != 0 && word.s[word.len - 1] == ':') 86716715Ssherman word.s[--word.len] = 0; 86816715Ssherman cp = strip(Dfix1(word.s)); 86916715Ssherman cleanup_push(cp, xfree); 87016715Ssherman if (Gmatch(goal, cp)) 87116715Ssherman level = -1; 87216715Ssherman cleanup_until(cp); 87316715Ssherman break; 87416715Ssherman 87516715Ssherman case TC_DEFAULT: 87616715Ssherman if (type == TC_SWITCH && level == 0) 87716715Ssherman level = -1; 87816715Ssherman break; 87916715Ssherman } 88016715Ssherman if (intty) { 88116715Ssherman ohistent->prev = histgetword(histent); 88216715Ssherman ohistent->prev->next = ohistent; 88316715Ssherman savehist(ohistent, 0); 88416715Ssherman freelex(ohistent); 88516715Ssherman xfree(ohistent); 88616715Ssherman } else 88716715Ssherman (void) getword(NULL); 88816715Ssherman } while (level >= 0); 88916715Ssherman end: 89016715Ssherman cleanup_until(&word); 89116715Ssherman} 89216715Ssherman 89316715Sshermanstatic struct wordent * 89416715Sshermanhistgetword(struct wordent *histent) 89516715Ssherman{ 89616715Ssherman int found = 0, first; 89716715Ssherman eChar c, d; 89816715Ssherman int e; 89916715Ssherman struct Strbuf *tmp; 90016715Ssherman tmp = xmalloc(sizeof(*tmp)); 90116715Ssherman tmp->size = 0; 90216715Ssherman tmp->s = NULL; 90316715Ssherman c = readc(1); 90416715Ssherman d = 0; 90516715Ssherman e = 0; 90616715Ssherman for (;;) { 90716715Ssherman tmp->len = 0; 90816715Ssherman Strbuf_terminate (tmp); 90916715Ssherman while (c == ' ' || c == '\t') 91016715Ssherman c = readc(1); 91116715Ssherman if (c == '#') 91216715Ssherman do 91316715Ssherman c = readc(1); 91416715Ssherman while (c != CHAR_ERR && c != '\n'); 91516715Ssherman if (c == CHAR_ERR) 91616715Ssherman goto past; 91716715Ssherman if (c == '\n') 91816715Ssherman goto nl; 91916715Ssherman unreadc(c); 92016715Ssherman found = 1; 92116715Ssherman first = 1; 92216715Ssherman do { 92316715Ssherman e = (c == '\\'); 92416715Ssherman c = readc(1); 92516715Ssherman if (c == '\\' && !e) { 92616715Ssherman if ((c = readc(1)) == '\n') { 92716715Ssherman e = 1; 92816715Ssherman c = ' '; 92916715Ssherman } else { 93016715Ssherman unreadc(c); 93116715Ssherman c = '\\'; 93216715Ssherman } 93316715Ssherman } 93416715Ssherman if ((c == '\'' || c == '"') && !e) { 93516715Ssherman if (d == 0) 93616715Ssherman d = c; 93716715Ssherman else if (d == c) 93816715Ssherman d = 0; 93916715Ssherman } 94016715Ssherman if (c == CHAR_ERR) 94116715Ssherman goto past; 94216715Ssherman 94316715Ssherman Strbuf_append1(tmp, (Char) c); 94416715Ssherman 94516715Ssherman if (!first && !d && c == '(' && !e) { 94616715Ssherman break; 94716715Ssherman } 94816715Ssherman first = 0; 94916715Ssherman } while (d || e || (c != ' ' && c != '\t' && c != '\n')); 95016715Ssherman tmp->len--; 95116715Ssherman if (tmp->len) { 95216715Ssherman Strbuf_terminate(tmp); 95316715Ssherman histent->word = Strsave(tmp->s); 95416715Ssherman histent->next = xmalloc(sizeof (*histent)); 95516715Ssherman histent->next->prev = histent; 95616715Ssherman histent = histent->next; 95716715Ssherman } 95816715Ssherman if (c == '\n') { 95916715Ssherman nl: 96016715Ssherman tmp->len = 0; 96116715Ssherman Strbuf_append1(tmp, (Char) c); 96216715Ssherman Strbuf_terminate(tmp); 96316715Ssherman histent->word = Strsave(tmp->s); 96416715Ssherman return histent; 96516715Ssherman } 96616715Ssherman } 96716715Ssherman 96816715Sshermanpast: 96916715Ssherman switch (Stype) { 97016715Ssherman 97116715Ssherman case TC_IF: 97216715Ssherman stderror(ERR_NAME | ERR_NOTFOUND, "then/endif"); 97316715Ssherman break; 97416715Ssherman 97516715Ssherman case TC_ELSE: 97616715Ssherman stderror(ERR_NAME | ERR_NOTFOUND, "endif"); 97716715Ssherman break; 97816715Ssherman 97916715Ssherman case TC_BRKSW: 98016715Ssherman case TC_SWITCH: 98116715Ssherman stderror(ERR_NAME | ERR_NOTFOUND, "endsw"); 98216715Ssherman break; 98316715Ssherman 98416715Ssherman case TC_BREAK: 98516715Ssherman stderror(ERR_NAME | ERR_NOTFOUND, "end"); 98616715Ssherman break; 98716715Ssherman 98816715Ssherman case TC_GOTO: 98916715Ssherman setname(short2str(Sgoal)); 99016715Ssherman stderror(ERR_NAME | ERR_NOTFOUND, "label"); 99116715Ssherman break; 99216715Ssherman 99316715Ssherman default: 99416715Ssherman break; 99516715Ssherman } 99616715Ssherman /* NOTREACHED */ 99716715Ssherman return NULL; 99816715Ssherman} 99916715Ssherman 100016715Sshermanstatic int 100116715Sshermangetword(struct Strbuf *wp) 100216715Ssherman{ 100316715Ssherman int found = 0, first; 100416715Ssherman eChar c, d; 100516715Ssherman 100616715Ssherman if (wp) 100716715Ssherman wp->len = 0; 100816715Ssherman c = readc(1); 100916715Ssherman d = 0; 101016715Ssherman do { 101116715Ssherman while (c == ' ' || c == '\t') 101216715Ssherman c = readc(1); 101316715Ssherman if (c == '#') 101416715Ssherman do 101516715Ssherman c = readc(1); 101616715Ssherman while (c != CHAR_ERR && c != '\n'); 101716715Ssherman if (c == CHAR_ERR) 101816715Ssherman goto past; 101916715Ssherman if (c == '\n') { 102016715Ssherman if (wp) 102116715Ssherman break; 102216715Ssherman return (0); 102316715Ssherman } 102416715Ssherman unreadc(c); 102516715Ssherman found = 1; 102616715Ssherman first = 1; 102716715Ssherman do { 102816715Ssherman c = readc(1); 102916715Ssherman if (c == '\\' && (c = readc(1)) == '\n') 103016715Ssherman c = ' '; 103116715Ssherman if (c == '\'' || c == '"') { 103216715Ssherman if (d == 0) 103316715Ssherman d = c; 103416715Ssherman else if (d == c) 103516715Ssherman d = 0; 103616715Ssherman } 103716715Ssherman if (c == CHAR_ERR) 103816715Ssherman goto past; 103916715Ssherman if (wp) 104016715Ssherman Strbuf_append1(wp, (Char) c); 104116715Ssherman if (!first && !d && c == '(') { 104216715Ssherman if (wp) 104316715Ssherman goto past_word_end; 104416715Ssherman else 104516715Ssherman break; 104616715Ssherman } 104716715Ssherman first = 0; 104816715Ssherman } while ((d || (c != ' ' && c != '\t')) && c != '\n'); 104916715Ssherman } while (wp == 0); 105016715Ssherman 105116715Ssherman past_word_end: 105216715Ssherman unreadc(c); 105316715Ssherman if (found) { 105416715Ssherman wp->len--; 105516715Ssherman Strbuf_terminate(wp); 105616715Ssherman } 105716715Ssherman 105816715Ssherman return (found); 105916715Ssherman 106016715Sshermanpast: 106116715Ssherman switch (Stype) { 106216715Ssherman 106316715Ssherman case TC_IF: 106416715Ssherman stderror(ERR_NAME | ERR_NOTFOUND, "then/endif"); 106516715Ssherman break; 106616715Ssherman 106716715Ssherman case TC_ELSE: 106816715Ssherman stderror(ERR_NAME | ERR_NOTFOUND, "endif"); 106916715Ssherman break; 107016715Ssherman 107116715Ssherman case TC_BRKSW: 107216715Ssherman case TC_SWITCH: 107316715Ssherman stderror(ERR_NAME | ERR_NOTFOUND, "endsw"); 107416715Ssherman break; 107516715Ssherman 107616715Ssherman case TC_BREAK: 107716715Ssherman stderror(ERR_NAME | ERR_NOTFOUND, "end"); 107816715Ssherman break; 107916715Ssherman 108016715Ssherman case TC_GOTO: 108116715Ssherman setname(short2str(Sgoal)); 108216715Ssherman stderror(ERR_NAME | ERR_NOTFOUND, "label"); 108316715Ssherman break; 108416715Ssherman 108516715Ssherman default: 108616715Ssherman break; 108716715Ssherman } 108816715Ssherman /* NOTREACHED */ 108916715Ssherman return (0); 109016715Ssherman} 109116715Ssherman 109216715Sshermanstatic void 109316715Sshermantoend(void) 109416715Ssherman{ 109516715Ssherman if (whyles->w_end.type == TCSH_F_SEEK && whyles->w_end.f_seek == 0) { 109616715Ssherman search(TC_BREAK, 0, NULL); 109716715Ssherman btell(&whyles->w_end); 109816715Ssherman whyles->w_end.f_seek--; 109916715Ssherman } 110016715Ssherman else { 110116715Ssherman bseek(&whyles->w_end); 110216715Ssherman } 110316715Ssherman wfree(); 110416715Ssherman} 110516715Ssherman 110616715Sshermanstatic void 110716715Sshermanwpfree(struct whyle *wp) 110816715Ssherman{ 110916715Ssherman if (wp->w_fe0) 111016715Ssherman blkfree(wp->w_fe0); 111116715Ssherman xfree(wp->w_fename); 111216715Ssherman xfree(wp); 111316715Ssherman} 111416715Ssherman 111516715Sshermanvoid 111616715Sshermanwfree(void) 111716715Ssherman{ 111816715Ssherman struct Ain o; 111916715Ssherman struct whyle *nwp; 112016715Ssherman#ifdef lint 112116715Ssherman nwp = NULL; /* sun lint is dumb! */ 112216715Ssherman#endif 112316715Ssherman 112416715Ssherman#ifdef FDEBUG 112516715Ssherman static const char foo[] = "IAFE"; 112616715Ssherman#endif /* FDEBUG */ 112716715Ssherman 112816715Ssherman btell(&o); 112916715Ssherman 113016715Ssherman#ifdef FDEBUG 113116715Ssherman xprintf("o->type %c o->a_seek %d o->f_seek %d\n", 113216715Ssherman foo[o.type + 1], o.a_seek, o.f_seek); 113316715Ssherman#endif /* FDEBUG */ 113416715Ssherman 113516715Ssherman for (; whyles; whyles = nwp) { 113616715Ssherman struct whyle *wp = whyles; 113716715Ssherman nwp = wp->w_next; 113816715Ssherman 113916715Ssherman#ifdef FDEBUG 114016715Ssherman xprintf("start->type %c start->a_seek %d start->f_seek %d\n", 114116715Ssherman foo[wp->w_start.type+1], 114216715Ssherman wp->w_start.a_seek, wp->w_start.f_seek); 114316715Ssherman xprintf("end->type %c end->a_seek %d end->f_seek %d\n", 114416715Ssherman foo[wp->w_end.type + 1], wp->w_end.a_seek, wp->w_end.f_seek); 114516715Ssherman#endif /* FDEBUG */ 114616715Ssherman 114716715Ssherman /* 114816715Ssherman * XXX: We free loops that have different seek types. 114916715Ssherman */ 115016715Ssherman if (wp->w_end.type != TCSH_I_SEEK && wp->w_start.type == wp->w_end.type && 115116715Ssherman wp->w_start.type == o.type) { 115216715Ssherman if (wp->w_end.type == TCSH_F_SEEK) { 115316715Ssherman if (o.f_seek >= wp->w_start.f_seek && 115416715Ssherman (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek)) 115516715Ssherman break; 115616715Ssherman } 115716715Ssherman else { 115816715Ssherman if (o.a_seek >= wp->w_start.a_seek && 115916715Ssherman (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek)) 116016715Ssherman break; 116116715Ssherman } 116216715Ssherman } 116316715Ssherman 116416715Ssherman wpfree(wp); 116516715Ssherman } 116616715Ssherman} 116716715Ssherman 116816715Ssherman/*ARGSUSED*/ 116916715Sshermanvoid 117016715Sshermandoecho(Char **v, struct command *c) 117116715Ssherman{ 117216715Ssherman USE(c); 117316715Ssherman xecho(' ', v); 117416715Ssherman} 117516715Ssherman 117616715Ssherman/*ARGSUSED*/ 117716715Sshermanvoid 117816715Sshermandoglob(Char **v, struct command *c) 117916715Ssherman{ 118016715Ssherman USE(c); 118116715Ssherman xecho(0, v); 118216715Ssherman flush(); 118316715Ssherman} 118416715Ssherman 118516715Sshermanstatic void 118616715Sshermanxecho(int sep, Char **v) 118716715Ssherman{ 118816715Ssherman Char *cp, **globbed = NULL; 118916715Ssherman int nonl = 0; 119016715Ssherman int echo_style = ECHO_STYLE; 119116715Ssherman struct varent *vp; 119216715Ssherman 119316715Ssherman if ((vp = adrof(STRecho_style)) != NULL && vp->vec != NULL && 119416715Ssherman vp->vec[0] != NULL) { 119516715Ssherman if (Strcmp(vp->vec[0], STRbsd) == 0) 119616715Ssherman echo_style = BSD_ECHO; 119716715Ssherman else if (Strcmp(vp->vec[0], STRsysv) == 0) 119816715Ssherman echo_style = SYSV_ECHO; 119916715Ssherman else if (Strcmp(vp->vec[0], STRboth) == 0) 120016715Ssherman echo_style = BOTH_ECHO; 120116715Ssherman else if (Strcmp(vp->vec[0], STRnone) == 0) 120216715Ssherman echo_style = NONE_ECHO; 120316715Ssherman } 120416715Ssherman 120516715Ssherman v++; 120616715Ssherman if (*v == 0) 120716715Ssherman goto done; 120816715Ssherman if (setintr) { 120916715Ssherman int old_pintr_disabled; 121016715Ssherman pintr_push_enable(&old_pintr_disabled); 121116715Ssherman v = glob_all_or_error(v); 121216715Ssherman cleanup_until(&old_pintr_disabled); 121316715Ssherman } else { 121416715Ssherman v = glob_all_or_error(v); 121516715Ssherman } 121616715Ssherman globbed = v; 121716715Ssherman if (globbed != NULL) 121816715Ssherman cleanup_push(globbed, blk_cleanup); 121916715Ssherman 122016715Ssherman if ((echo_style & BSD_ECHO) != 0 && sep == ' ' && *v && eq(*v, STRmn)) 122116715Ssherman nonl++, v++; 122216715Ssherman 122316715Ssherman while ((cp = *v++) != 0) { 122416715Ssherman Char c; 122516715Ssherman 122616715Ssherman if (setintr) { 122716715Ssherman int old_pintr_disabled; 1228 1229 pintr_push_enable(&old_pintr_disabled); 1230 cleanup_until(&old_pintr_disabled); 1231 } 1232 while ((c = *cp++) != 0) { 1233 if ((echo_style & SYSV_ECHO) != 0 && c == '\\') { 1234 switch (c = *cp++) { 1235 case 'a': 1236 c = '\a'; 1237 break; 1238 case 'b': 1239 c = '\b'; 1240 break; 1241 case 'c': 1242 nonl = 1; 1243 goto done; 1244 case 'e': 1245#if 0 /* Windows does not understand \e */ 1246 c = '\e'; 1247#else 1248 c = CTL_ESC('\033'); 1249#endif 1250 break; 1251 case 'f': 1252 c = '\f'; 1253 break; 1254 case 'n': 1255 c = '\n'; 1256 break; 1257 case 'r': 1258 c = '\r'; 1259 break; 1260 case 't': 1261 c = '\t'; 1262 break; 1263 case 'v': 1264 c = '\v'; 1265 break; 1266 case '\\': 1267 c = '\\'; 1268 break; 1269 case '0': 1270 c = 0; 1271 if (*cp >= '0' && *cp < '8') 1272 c = c * 8 + *cp++ - '0'; 1273 if (*cp >= '0' && *cp < '8') 1274 c = c * 8 + *cp++ - '0'; 1275 if (*cp >= '0' && *cp < '8') 1276 c = c * 8 + *cp++ - '0'; 1277 break; 1278 case '\0': 1279 c = '\\'; 1280 cp--; 1281 break; 1282 default: 1283 xputchar('\\' | QUOTE); 1284 break; 1285 } 1286 } 1287 xputwchar(c | QUOTE); 1288 1289 } 1290 if (*v) 1291 xputchar(sep | QUOTE); 1292 } 1293done: 1294 if (sep && nonl == 0) 1295 xputchar('\n'); 1296 else 1297 flush(); 1298 if (globbed != NULL) 1299 cleanup_until(globbed); 1300} 1301 1302/* check whether an environment variable should invoke 'set_locale()' */ 1303static int 1304islocale_var(Char *var) 1305{ 1306 static Char *locale_vars[] = { 1307 STRLANG, STRLC_ALL, STRLC_CTYPE, STRLC_NUMERIC, 1308 STRLC_TIME, STRLC_COLLATE, STRLC_MESSAGES, STRLC_MONETARY, 0 1309 }; 1310 Char **v; 1311 1312 for (v = locale_vars; *v; ++v) 1313 if (eq(var, *v)) 1314 return 1; 1315 return 0; 1316} 1317 1318static void 1319xlate_cr_cleanup(void *dummy) 1320{ 1321 USE(dummy); 1322 xlate_cr = 0; 1323} 1324 1325/*ARGSUSED*/ 1326void 1327doprintenv(Char **v, struct command *c) 1328{ 1329 Char *e; 1330 1331 USE(c); 1332 v++; 1333 if (*v == 0) { 1334 Char **ep; 1335 1336 xlate_cr = 1; 1337 cleanup_push(&xlate_cr, xlate_cr_cleanup); 1338 for (ep = STR_environ; *ep; ep++) { 1339 if (setintr) { 1340 int old_pintr_disabled; 1341 1342 pintr_push_enable(&old_pintr_disabled); 1343 cleanup_until(&old_pintr_disabled); 1344 } 1345 xprintf("%S\n", *ep); 1346 } 1347 cleanup_until(&xlate_cr); 1348 } 1349 else if ((e = tgetenv(*v)) != NULL) { 1350 int old_output_raw; 1351 1352 old_output_raw = output_raw; 1353 output_raw = 1; 1354 cleanup_push(&old_output_raw, output_raw_restore); 1355 xprintf("%S\n", e); 1356 cleanup_until(&old_output_raw); 1357 } 1358 else 1359 setcopy(STRstatus, STR1, VAR_READWRITE); 1360} 1361 1362/* from "Karl Berry." <karl%mote.umb.edu@relay.cs.net> -- for NeXT things 1363 (and anything else with a modern compiler) */ 1364 1365/*ARGSUSED*/ 1366void 1367dosetenv(Char **v, struct command *c) 1368{ 1369 Char *vp, *lp; 1370 1371 USE(c); 1372 if (*++v == 0) { 1373 doprintenv(--v, 0); 1374 return; 1375 } 1376 1377 vp = *v++; 1378 lp = vp; 1379 1380 if (!letter(*lp)) 1381 stderror(ERR_NAME | ERR_VARBEGIN); 1382 do { 1383 lp++; 1384 } while (alnum(*lp)); 1385 if (*lp != '\0') 1386 stderror(ERR_NAME | ERR_VARALNUM); 1387 1388 if ((lp = *v++) == 0) 1389 lp = STRNULL; 1390 1391 lp = globone(lp, G_APPEND); 1392 cleanup_push(lp, xfree); 1393 tsetenv(vp, lp); 1394 if (eq(vp, STRKPATH)) { 1395 importpath(lp); 1396 dohash(NULL, NULL); 1397 cleanup_until(lp); 1398 return; 1399 } 1400 1401#ifdef apollo 1402 if (eq(vp, STRSYSTYPE)) { 1403 dohash(NULL, NULL); 1404 cleanup_until(lp); 1405 return; 1406 } 1407#endif /* apollo */ 1408 1409 /* dspkanji/dspmbyte autosetting */ 1410 /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */ 1411#if defined(DSPMBYTE) 1412 if(eq(vp, STRLANG) && !adrof(CHECK_MBYTEVAR)) { 1413 autoset_dspmbyte(lp); 1414 } 1415#endif 1416 1417 if (islocale_var(vp)) { 1418#ifdef NLS 1419 int k; 1420 1421# ifdef SETLOCALEBUG 1422 dont_free = 1; 1423# endif /* SETLOCALEBUG */ 1424 (void) setlocale(LC_ALL, ""); 1425# ifdef LC_COLLATE 1426 (void) setlocale(LC_COLLATE, ""); 1427# endif 1428# ifdef LC_CTYPE 1429 (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 1430# endif /* LC_CTYPE */ 1431# if defined(AUTOSET_KANJI) 1432 autoset_kanji(); 1433# endif /* AUTOSET_KANJI */ 1434# ifdef NLS_CATALOGS 1435# ifdef LC_MESSAGES 1436 (void) setlocale(LC_MESSAGES, ""); 1437# endif /* LC_MESSAGES */ 1438 nlsclose(); 1439 nlsinit(); 1440# endif /* NLS_CATALOGS */ 1441# ifdef SETLOCALEBUG 1442 dont_free = 0; 1443# endif /* SETLOCALEBUG */ 1444# ifdef STRCOLLBUG 1445 fix_strcoll_bug(); 1446# endif /* STRCOLLBUG */ 1447 tw_cmd_free(); /* since the collation sequence has changed */ 1448 for (k = 0200; k <= 0377 && !Isprint(CTL_ESC(k)); k++) 1449 continue; 1450 AsciiOnly = MB_CUR_MAX == 1 && k > 0377; 1451#else /* !NLS */ 1452 AsciiOnly = 0; 1453#endif /* NLS */ 1454 NLSMapsAreInited = 0; 1455 ed_Init(); 1456 if (MapsAreInited && !NLSMapsAreInited) 1457 ed_InitNLSMaps(); 1458 cleanup_until(lp); 1459 return; 1460 } 1461 1462#ifdef NLS_CATALOGS 1463 if (eq(vp, STRNLSPATH)) { 1464 nlsclose(); 1465 nlsinit(); 1466 } 1467#endif 1468 1469 if (eq(vp, STRNOREBIND)) { 1470 NoNLSRebind = 1; 1471 MapsAreInited = 0; 1472 NLSMapsAreInited = 0; 1473 ed_InitMaps(); 1474 cleanup_until(lp); 1475 return; 1476 } 1477#ifdef WINNT_NATIVE 1478 if (eq(vp, STRtcshlang)) { 1479 nlsinit(); 1480 cleanup_until(lp); 1481 return; 1482 } 1483#endif /* WINNT_NATIVE */ 1484 if (eq(vp, STRKTERM)) { 1485 char *t; 1486 1487 setv(STRterm, quote(lp), VAR_READWRITE); /* lp memory used here */ 1488 cleanup_ignore(lp); 1489 cleanup_until(lp); 1490 t = short2str(lp); 1491 if (noediting && strcmp(t, "unknown") != 0 && strcmp(t,"dumb") != 0) { 1492 editing = 1; 1493 noediting = 0; 1494 setNS(STRedit); 1495 } 1496 GotTermCaps = 0; 1497 ed_Init(); 1498 return; 1499 } 1500 1501 if (eq(vp, STRKHOME)) { 1502 Char *canon; 1503 /* 1504 * convert to canonical pathname (possibly resolving symlinks) 1505 */ 1506 canon = dcanon(lp, lp); 1507 cleanup_ignore(lp); 1508 cleanup_until(lp); 1509 cleanup_push(canon, xfree); 1510 setv(STRhome, quote(canon), VAR_READWRITE); /* lp memory used here */ 1511 cleanup_ignore(canon); 1512 cleanup_until(canon); 1513 1514 /* fix directory stack for new tilde home */ 1515 dtilde(); 1516 return; 1517 } 1518 1519 if (eq(vp, STRKSHLVL)) { 1520 setv(STRshlvl, quote(lp), VAR_READWRITE); /* lp memory used here */ 1521 cleanup_ignore(lp); 1522 cleanup_until(lp); 1523 return; 1524 } 1525 1526 if (eq(vp, STRKUSER)) { 1527 setv(STRuser, quote(lp), VAR_READWRITE); /* lp memory used here */ 1528 cleanup_ignore(lp); 1529 cleanup_until(lp); 1530 return; 1531 } 1532 1533 if (eq(vp, STRKGROUP)) { 1534 setv(STRgroup, quote(lp), VAR_READWRITE); /* lp memory used here */ 1535 cleanup_ignore(lp); 1536 cleanup_until(lp); 1537 return; 1538 } 1539 1540#ifdef COLOR_LS_F 1541 if (eq(vp, STRLS_COLORS)) { 1542 parseLS_COLORS(lp); 1543 cleanup_until(lp); 1544 return; 1545 } 1546#endif /* COLOR_LS_F */ 1547 1548#ifdef SIG_WINDOW 1549 /* 1550 * Load/Update $LINES $COLUMNS 1551 */ 1552 if ((eq(lp, STRNULL) && (eq(vp, STRLINES) || eq(vp, STRCOLUMNS))) || 1553 eq(vp, STRTERMCAP)) { 1554 cleanup_until(lp); 1555 check_window_size(1); 1556 return; 1557 } 1558 1559 /* 1560 * Change the size to the one directed by $LINES and $COLUMNS 1561 */ 1562 if (eq(vp, STRLINES) || eq(vp, STRCOLUMNS)) { 1563#if 0 1564 GotTermCaps = 0; 1565#endif 1566 cleanup_until(lp); 1567 ed_Init(); 1568 return; 1569 } 1570#endif /* SIG_WINDOW */ 1571 cleanup_until(lp); 1572} 1573 1574/*ARGSUSED*/ 1575void 1576dounsetenv(Char **v, struct command *c) 1577{ 1578 Char **ep, *p, *n, *name; 1579 int i, maxi; 1580 1581 USE(c); 1582 /* 1583 * Find the longest environment variable 1584 */ 1585 for (maxi = 0, ep = STR_environ; *ep; ep++) { 1586 for (i = 0, p = *ep; *p && *p != '='; p++, i++) 1587 continue; 1588 if (i > maxi) 1589 maxi = i; 1590 } 1591 1592 name = xmalloc((maxi + 1) * sizeof(Char)); 1593 cleanup_push(name, xfree); 1594 1595 while (++v && *v) 1596 for (maxi = 1; maxi;) 1597 for (maxi = 0, ep = STR_environ; *ep; ep++) { 1598 for (n = name, p = *ep; *p && *p != '='; *n++ = *p++) 1599 continue; 1600 *n = '\0'; 1601 if (!Gmatch(name, *v)) 1602 continue; 1603 maxi = 1; 1604 1605 /* Unset the name. This wasn't being done until 1606 * later but most of the stuff following won't 1607 * work (particularly the setlocale() and getenv() 1608 * stuff) as intended until the name is actually 1609 * removed. (sg) 1610 */ 1611 Unsetenv(name); 1612 1613 if (eq(name, STRNOREBIND)) { 1614 NoNLSRebind = 0; 1615 MapsAreInited = 0; 1616 NLSMapsAreInited = 0; 1617 ed_InitMaps(); 1618 } 1619#ifdef apollo 1620 else if (eq(name, STRSYSTYPE)) 1621 dohash(NULL, NULL); 1622#endif /* apollo */ 1623 else if (islocale_var(name)) { 1624#ifdef NLS 1625 int k; 1626 1627# ifdef SETLOCALEBUG 1628 dont_free = 1; 1629# endif /* SETLOCALEBUG */ 1630 (void) setlocale(LC_ALL, ""); 1631# ifdef LC_COLLATE 1632 (void) setlocale(LC_COLLATE, ""); 1633# endif 1634# ifdef LC_CTYPE 1635 (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 1636# endif /* LC_CTYPE */ 1637# ifdef NLS_CATALOGS 1638# ifdef LC_MESSAGES 1639 (void) setlocale(LC_MESSAGES, ""); 1640# endif /* LC_MESSAGES */ 1641 nlsclose(); 1642 nlsinit(); 1643# endif /* NLS_CATALOGS */ 1644# ifdef SETLOCALEBUG 1645 dont_free = 0; 1646# endif /* SETLOCALEBUG */ 1647# ifdef STRCOLLBUG 1648 fix_strcoll_bug(); 1649# endif /* STRCOLLBUG */ 1650 tw_cmd_free();/* since the collation sequence has changed */ 1651 for (k = 0200; k <= 0377 && !Isprint(CTL_ESC(k)); k++) 1652 continue; 1653 AsciiOnly = MB_CUR_MAX == 1 && k > 0377; 1654#else /* !NLS */ 1655 AsciiOnly = getenv("LANG") == NULL && 1656 getenv("LC_CTYPE") == NULL; 1657#endif /* NLS */ 1658 NLSMapsAreInited = 0; 1659 ed_Init(); 1660 if (MapsAreInited && !NLSMapsAreInited) 1661 ed_InitNLSMaps(); 1662 1663 } 1664#ifdef WINNT_NATIVE 1665 else if (eq(name,(STRtcshlang))) { 1666 nls_dll_unload(); 1667 nlsinit(); 1668 } 1669#endif /* WINNT_NATIVE */ 1670#ifdef COLOR_LS_F 1671 else if (eq(name, STRLS_COLORS)) 1672 parseLS_COLORS(n); 1673#endif /* COLOR_LS_F */ 1674#ifdef NLS_CATALOGS 1675 else if (eq(name, STRNLSPATH)) { 1676 nlsclose(); 1677 nlsinit(); 1678 } 1679#endif 1680 /* 1681 * start again cause the environment changes 1682 */ 1683 break; 1684 } 1685 cleanup_until(name); 1686} 1687 1688void 1689tsetenv(const Char *name, const Char *val) 1690{ 1691#ifdef SETENV_IN_LIB 1692/* 1693 * XXX: This does not work right, since tcsh cannot track changes to 1694 * the environment this way. (the builtin setenv without arguments does 1695 * not print the right stuff neither does unsetenv). This was for Mach, 1696 * it is not needed anymore. 1697 */ 1698#undef setenv 1699 char *cname; 1700 1701 if (name == NULL) 1702 return; 1703 cname = strsave(short2str(name)); 1704 setenv(cname, short2str(val), 1); 1705 xfree(cname); 1706#else /* !SETENV_IN_LIB */ 1707 Char **ep = STR_environ; 1708 const Char *ccp; 1709 Char *cp, *dp; 1710 Char *blk[2]; 1711 Char **oep = ep; 1712 1713#ifdef WINNT_NATIVE 1714 nt_set_env(name,val); 1715#endif /* WINNT_NATIVE */ 1716 for (; *ep; ep++) { 1717#ifdef WINNT_NATIVE 1718 for (ccp = name, dp = *ep; *ccp && Tolower(*ccp & TRIM) == Tolower(*dp); 1719 ccp++, dp++) 1720#else 1721 for (ccp = name, dp = *ep; *ccp && (*ccp & TRIM) == *dp; ccp++, dp++) 1722#endif /* WINNT_NATIVE */ 1723 continue; 1724 if (*ccp != 0 || *dp != '=') 1725 continue; 1726 cp = Strspl(STRequal, val); 1727 xfree(*ep); 1728 *ep = strip(Strspl(name, cp)); 1729 xfree(cp); 1730 blkfree((Char **) environ); 1731 environ = short2blk(STR_environ); 1732 return; 1733 } 1734 cp = Strspl(name, STRequal); 1735 blk[0] = strip(Strspl(cp, val)); 1736 xfree(cp); 1737 blk[1] = 0; 1738 STR_environ = blkspl(STR_environ, blk); 1739 blkfree((Char **) environ); 1740 environ = short2blk(STR_environ); 1741 xfree(oep); 1742#endif /* SETENV_IN_LIB */ 1743} 1744 1745void 1746Unsetenv(Char *name) 1747{ 1748 Char **ep = STR_environ; 1749 Char *cp, *dp; 1750 Char **oep = ep; 1751 1752#ifdef WINNT_NATIVE 1753 nt_set_env(name,NULL); 1754#endif /*WINNT_NATIVE */ 1755 for (; *ep; ep++) { 1756 for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) 1757 continue; 1758 if (*cp != 0 || *dp != '=') 1759 continue; 1760 cp = *ep; 1761 *ep = 0; 1762 STR_environ = blkspl(STR_environ, ep + 1); 1763 blkfree((Char **) environ); 1764 environ = short2blk(STR_environ); 1765 *ep = cp; 1766 xfree(cp); 1767 xfree(oep); 1768 return; 1769 } 1770} 1771 1772/*ARGSUSED*/ 1773void 1774doumask(Char **v, struct command *c) 1775{ 1776 Char *cp = v[1]; 1777 int i; 1778 1779 USE(c); 1780 if (cp == 0) { 1781 i = (int)umask(0); 1782 (void) umask(i); 1783 xprintf("%o\n", i); 1784 return; 1785 } 1786 i = 0; 1787 while (Isdigit(*cp) && *cp != '8' && *cp != '9') 1788 i = i * 8 + *cp++ - '0'; 1789 if (*cp || i < 0 || i > 0777) 1790 stderror(ERR_NAME | ERR_MASK); 1791 (void) umask(i); 1792} 1793 1794#ifndef HAVENOLIMIT 1795# ifndef BSDLIMIT 1796 typedef long RLIM_TYPE; 1797# ifdef _OSD_POSIX /* BS2000 */ 1798# include <ulimit.h> 1799# endif 1800# ifndef RLIM_INFINITY 1801# if !defined(_MINIX) && !defined(__clipper__) && !defined(_CRAY) 1802 extern RLIM_TYPE ulimit(); 1803# endif /* ! _MINIX && !__clipper__ */ 1804# define RLIM_INFINITY 0x003fffff 1805# define RLIMIT_FSIZE 1 1806# endif /* RLIM_INFINITY */ 1807# ifdef aiws 1808# define toset(a) (((a) == 3) ? 1004 : (a) + 1) 1809# define RLIMIT_DATA 3 1810# define RLIMIT_STACK 1005 1811# else /* aiws */ 1812# define toset(a) ((a) + 1) 1813# endif /* aiws */ 1814# else /* BSDLIMIT */ 1815# if (defined(BSD4_4) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) || (HPUXVERSION >= 1100)) && !defined(__386BSD__) 1816 typedef rlim_t RLIM_TYPE; 1817# else 1818# if defined(SOLARIS2) || (defined(sgi) && SYSVREL > 3) 1819 typedef rlim_t RLIM_TYPE; 1820# else 1821# if defined(_SX) 1822 typedef long long RLIM_TYPE; 1823# else /* !_SX */ 1824 typedef unsigned long RLIM_TYPE; 1825# endif /* _SX */ 1826# endif /* SOLARIS2 || (sgi && SYSVREL > 3) */ 1827# endif /* BSD4_4 && !__386BSD__ */ 1828# endif /* BSDLIMIT */ 1829 1830# if (HPUXVERSION > 700) && (HPUXVERSION < 1100) && defined(BSDLIMIT) 1831/* Yes hpux8.0 has limits but <sys/resource.h> does not make them public */ 1832/* Yes, we could have defined _KERNEL, and -I/etc/conf/h, but is that better? */ 1833# ifndef RLIMIT_CPU 1834# define RLIMIT_CPU 0 1835# define RLIMIT_FSIZE 1 1836# define RLIMIT_DATA 2 1837# define RLIMIT_STACK 3 1838# define RLIMIT_CORE 4 1839# define RLIMIT_RSS 5 1840# define RLIMIT_NOFILE 6 1841# endif /* RLIMIT_CPU */ 1842# ifndef RLIM_INFINITY 1843# define RLIM_INFINITY 0x7fffffff 1844# endif /* RLIM_INFINITY */ 1845 /* 1846 * old versions of HP/UX counted limits in 512 bytes 1847 */ 1848# ifndef SIGRTMIN 1849# define FILESIZE512 1850# endif /* SIGRTMIN */ 1851# endif /* (HPUXVERSION > 700) && (HPUXVERSION < 1100) && BSDLIMIT */ 1852 1853# if SYSVREL > 3 && defined(BSDLIMIT) && !defined(_SX) 1854/* In order to use rusage, we included "/usr/ucbinclude/sys/resource.h" in */ 1855/* sh.h. However, some SVR4 limits are defined in <sys/resource.h>. Rather */ 1856/* than include both and get warnings, we define the extra SVR4 limits here. */ 1857/* XXX: I don't understand if RLIMIT_AS is defined, why don't we define */ 1858/* RLIMIT_VMEM based on it? */ 1859# ifndef RLIMIT_VMEM 1860# define RLIMIT_VMEM 6 1861# endif 1862# ifndef RLIMIT_AS 1863# define RLIMIT_AS RLIMIT_VMEM 1864# endif 1865# endif /* SYSVREL > 3 && BSDLIMIT */ 1866 1867# if (defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) 1868# if defined(RLIMIT_AS) && !defined(RLIMIT_VMEM) 1869# define RLIMIT_VMEM RLIMIT_AS 1870# endif 1871/* 1872 * Oh well, <asm-generic/resource.h> has it, but <bits/resource.h> does not 1873 * Linux headers: When the left hand does not know what the right hand does. 1874 */ 1875# if defined(RLIMIT_RTPRIO) && !defined(RLIMIT_RTTIME) 1876# define RLIMIT_RTTIME (RLIMIT_RTPRIO + 1) 1877# endif 1878# endif 1879 1880struct limits limits[] = 1881{ 1882# ifdef RLIMIT_CPU 1883 { RLIMIT_CPU, "cputime", 1, "seconds" }, 1884# endif /* RLIMIT_CPU */ 1885 1886# ifdef RLIMIT_FSIZE 1887# ifndef aiws 1888 { RLIMIT_FSIZE, "filesize", 1024, "kbytes" }, 1889# else 1890 { RLIMIT_FSIZE, "filesize", 512, "blocks" }, 1891# endif /* aiws */ 1892# endif /* RLIMIT_FSIZE */ 1893 1894# ifdef RLIMIT_DATA 1895 { RLIMIT_DATA, "datasize", 1024, "kbytes" }, 1896# endif /* RLIMIT_DATA */ 1897 1898# ifdef RLIMIT_STACK 1899# ifndef aiws 1900 { RLIMIT_STACK, "stacksize", 1024, "kbytes" }, 1901# else 1902 { RLIMIT_STACK, "stacksize", 1024 * 1024, "kbytes"}, 1903# endif /* aiws */ 1904# endif /* RLIMIT_STACK */ 1905 1906# ifdef RLIMIT_CORE 1907 { RLIMIT_CORE, "coredumpsize", 1024, "kbytes" }, 1908# endif /* RLIMIT_CORE */ 1909 1910# ifdef RLIMIT_RSS 1911 { RLIMIT_RSS, "memoryuse", 1024, "kbytes" }, 1912# endif /* RLIMIT_RSS */ 1913 1914# ifdef RLIMIT_UMEM 1915 { RLIMIT_UMEM, "memoryuse", 1024, "kbytes" }, 1916# endif /* RLIMIT_UMEM */ 1917 1918# ifdef RLIMIT_VMEM 1919 { RLIMIT_VMEM, "vmemoryuse", 1024, "kbytes" }, 1920# endif /* RLIMIT_VMEM */ 1921 1922# if defined(RLIMIT_HEAP) /* found on BS2000/OSD systems */ 1923 { RLIMIT_HEAP, "heapsize", 1024, "kbytes" }, 1924# endif /* RLIMIT_HEAP */ 1925 1926# ifdef RLIMIT_NOFILE 1927 { RLIMIT_NOFILE, "descriptors", 1, "" }, 1928# endif /* RLIMIT_NOFILE */ 1929 1930# ifdef RLIMIT_CONCUR 1931 { RLIMIT_CONCUR, "concurrency", 1, "thread(s)" }, 1932# endif /* RLIMIT_CONCUR */ 1933 1934# ifdef RLIMIT_MEMLOCK 1935 { RLIMIT_MEMLOCK, "memorylocked", 1024, "kbytes" }, 1936# endif /* RLIMIT_MEMLOCK */ 1937 1938# ifdef RLIMIT_NPROC 1939 { RLIMIT_NPROC, "maxproc", 1, "" }, 1940# endif /* RLIMIT_NPROC */ 1941 1942# if defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE) 1943 { RLIMIT_OFILE, "openfiles", 1, "" }, 1944# endif /* RLIMIT_OFILE && !defined(RLIMIT_NOFILE) */ 1945 1946# ifdef RLIMIT_SBSIZE 1947 { RLIMIT_SBSIZE, "sbsize", 1, "" }, 1948# endif /* RLIMIT_SBSIZE */ 1949 1950# ifdef RLIMIT_SWAP 1951 { RLIMIT_SWAP, "swapsize", 1024, "kbytes" }, 1952# endif /* RLIMIT_SWAP */ 1953 1954# ifdef RLIMIT_LOCKS 1955 { RLIMIT_LOCKS, "maxlocks", 1, "" }, 1956# endif /* RLIMIT_LOCKS */ 1957 1958# ifdef RLIMIT_SIGPENDING 1959 { RLIMIT_SIGPENDING,"maxsignal", 1, "" }, 1960# endif /* RLIMIT_SIGPENDING */ 1961 1962# ifdef RLIMIT_MSGQUEUE 1963 { RLIMIT_MSGQUEUE, "maxmessage", 1, "" }, 1964# endif /* RLIMIT_MSGQUEUE */ 1965 1966# ifdef RLIMIT_NICE 1967 { RLIMIT_NICE, "maxnice", 1, "" }, 1968# endif /* RLIMIT_NICE */ 1969 1970# ifdef RLIMIT_RTPRIO 1971 { RLIMIT_RTPRIO, "maxrtprio", 1, "" }, 1972# endif /* RLIMIT_RTPRIO */ 1973 1974# ifdef RLIMIT_RTTIME 1975 { RLIMIT_RTTIME, "maxrttime", 1, "usec" }, 1976# endif /* RLIMIT_RTTIME */ 1977 1978 { -1, NULL, 0, NULL } 1979}; 1980 1981static struct limits *findlim (Char *); 1982static RLIM_TYPE getval (struct limits *, Char **); 1983static int strtail (Char *, const char *); 1984static void limtail (Char *, const char *); 1985static void limtail2 (Char *, const char *, const char *); 1986static void plim (struct limits *, int); 1987static int setlim (struct limits *, int, RLIM_TYPE); 1988 1989#ifdef convex 1990static RLIM_TYPE 1991restrict_limit(double value) 1992{ 1993 /* 1994 * is f too large to cope with? return the maximum or minimum int 1995 */ 1996 if (value > (double) INT_MAX) 1997 return (RLIM_TYPE) INT_MAX; 1998 else if (value < (double) INT_MIN) 1999 return (RLIM_TYPE) INT_MIN; 2000 else 2001 return (RLIM_TYPE) value; 2002} 2003#else /* !convex */ 2004# define restrict_limit(x) ((RLIM_TYPE) (x)) 2005#endif /* convex */ 2006 2007 2008static struct limits * 2009findlim(Char *cp) 2010{ 2011 struct limits *lp, *res; 2012 2013 res = NULL; 2014 for (lp = limits; lp->limconst >= 0; lp++) 2015 if (prefix(cp, str2short(lp->limname))) { 2016 if (res) 2017 stderror(ERR_NAME | ERR_AMBIG); 2018 res = lp; 2019 } 2020 if (res) 2021 return (res); 2022 stderror(ERR_NAME | ERR_LIMIT); 2023 /* NOTREACHED */ 2024 return (0); 2025} 2026 2027/*ARGSUSED*/ 2028void 2029dolimit(Char **v, struct command *c) 2030{ 2031 struct limits *lp; 2032 RLIM_TYPE limit; 2033 int hard = 0; 2034 2035 USE(c); 2036 v++; 2037 if (*v && eq(*v, STRmh)) { 2038 hard = 1; 2039 v++; 2040 } 2041 if (*v == 0) { 2042 for (lp = limits; lp->limconst >= 0; lp++) 2043 plim(lp, hard); 2044 return; 2045 } 2046 lp = findlim(v[0]); 2047 if (v[1] == 0) { 2048 plim(lp, hard); 2049 return; 2050 } 2051 limit = getval(lp, v + 1); 2052 if (setlim(lp, hard, limit) < 0) 2053 stderror(ERR_SILENT); 2054} 2055 2056static RLIM_TYPE 2057getval(struct limits *lp, Char **v) 2058{ 2059 float f; 2060 Char *cp = *v++; 2061 2062 f = atof(short2str(cp)); 2063 2064# ifdef convex 2065 /* 2066 * is f too large to cope with. limit f to minint, maxint - X-6768 by 2067 * strike 2068 */ 2069 if ((f < (double) INT_MIN) || (f > (double) INT_MAX)) { 2070 stderror(ERR_NAME | ERR_TOOLARGE); 2071 } 2072# endif /* convex */ 2073 2074 while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') 2075 cp++; 2076 if (*cp == 0) { 2077 if (*v == 0) 2078 return restrict_limit((f * lp->limdiv) + 0.5); 2079 cp = *v; 2080 } 2081 switch (*cp) { 2082# ifdef RLIMIT_CPU 2083 case ':': 2084 if (lp->limconst != RLIMIT_CPU) 2085 goto badscal; 2086 return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f * 60.0 + atof(short2str(cp + 1)))); 2087 case 'h': 2088 if (lp->limconst != RLIMIT_CPU) 2089 goto badscal; 2090 limtail(cp, "hours"); 2091 f *= 3600.0; 2092 break; 2093# endif /* RLIMIT_CPU */ 2094 case 'm': 2095# ifdef RLIMIT_CPU 2096 if (lp->limconst == RLIMIT_CPU) { 2097 limtail(cp, "minutes"); 2098 f *= 60.0; 2099 break; 2100 } 2101# endif /* RLIMIT_CPU */ 2102 limtail2(cp, "megabytes", "mbytes"); 2103 f *= 1024.0 * 1024.0; 2104 break; 2105# ifdef RLIMIT_CPU 2106 case 's': 2107 if (lp->limconst != RLIMIT_CPU) 2108 goto badscal; 2109 limtail(cp, "seconds"); 2110 break; 2111# endif /* RLIMIT_CPU */ 2112 case 'G': 2113 *cp = 'g'; 2114 /*FALLTHROUGH*/ 2115 case 'g': 2116# ifdef RLIMIT_CPU 2117 if (lp->limconst == RLIMIT_CPU) 2118 goto badscal; 2119# endif /* RLIMIT_CPU */ 2120 limtail2(cp, "gigabytes", "gbytes"); 2121 f *= 1024.0 * 1024.0 * 1024.0; 2122 break; 2123 case 'M': 2124# ifdef RLIMIT_CPU 2125 if (lp->limconst == RLIMIT_CPU) 2126 goto badscal; 2127# endif /* RLIMIT_CPU */ 2128 *cp = 'm'; 2129 limtail2(cp, "megabytes", "mbytes"); 2130 f *= 1024.0 * 1024.0; 2131 break; 2132 case 'k': 2133# ifdef RLIMIT_CPU 2134 if (lp->limconst == RLIMIT_CPU) 2135 goto badscal; 2136# endif /* RLIMIT_CPU */ 2137 limtail2(cp, "kilobytes", "kbytes"); 2138 f *= 1024.0; 2139 break; 2140 case 'b': 2141# ifdef RLIMIT_CPU 2142 if (lp->limconst == RLIMIT_CPU) 2143 goto badscal; 2144# endif /* RLIMIT_CPU */ 2145 limtail(cp, "blocks"); 2146 f *= 512.0; 2147 break; 2148 case 'u': 2149 limtail(cp, "unlimited"); 2150 return ((RLIM_TYPE) RLIM_INFINITY); 2151 default: 2152# ifdef RLIMIT_CPU 2153badscal: 2154# endif /* RLIMIT_CPU */ 2155 stderror(ERR_NAME | ERR_SCALEF); 2156 } 2157# ifdef convex 2158 return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f + 0.5)); 2159# else 2160 f += 0.5; 2161 if (f > (float) ((RLIM_TYPE) RLIM_INFINITY)) 2162 return ((RLIM_TYPE) RLIM_INFINITY); 2163 else 2164 return ((RLIM_TYPE) f); 2165# endif /* convex */ 2166} 2167 2168static int 2169strtail(Char *cp, const char *str) 2170{ 2171 while (*cp && *cp == (Char)*str) 2172 cp++, str++; 2173 return (*cp != '\0'); 2174} 2175 2176static void 2177limtail(Char *cp, const char *str) 2178{ 2179 if (strtail(cp, str)) 2180 stderror(ERR_BADSCALE, str); 2181} 2182 2183static void 2184limtail2(Char *cp, const char *str1, const char *str2) 2185{ 2186 if (strtail(cp, str1) && strtail(cp, str2)) 2187 stderror(ERR_BADSCALE, str1); 2188} 2189 2190/*ARGSUSED*/ 2191static void 2192plim(struct limits *lp, int hard) 2193{ 2194# ifdef BSDLIMIT 2195 struct rlimit rlim; 2196# endif /* BSDLIMIT */ 2197 RLIM_TYPE limit; 2198 int xdiv = lp->limdiv; 2199 2200 xprintf("%-13.13s", lp->limname); 2201 2202# ifndef BSDLIMIT 2203 limit = ulimit(lp->limconst, 0); 2204# ifdef aiws 2205 if (lp->limconst == RLIMIT_DATA) 2206 limit -= 0x20000000; 2207# endif /* aiws */ 2208# else /* BSDLIMIT */ 2209 (void) getrlimit(lp->limconst, &rlim); 2210 limit = hard ? rlim.rlim_max : rlim.rlim_cur; 2211# endif /* BSDLIMIT */ 2212 2213# if !defined(BSDLIMIT) || defined(FILESIZE512) 2214 /* 2215 * Christos: filesize comes in 512 blocks. we divide by 2 to get 1024 2216 * blocks. Note we cannot pre-multiply cause we might overflow (A/UX) 2217 */ 2218 if (lp->limconst == RLIMIT_FSIZE) { 2219 if (limit >= (RLIM_INFINITY / 512)) 2220 limit = RLIM_INFINITY; 2221 else 2222 xdiv = (xdiv == 1024 ? 2 : 1); 2223 } 2224# endif /* !BSDLIMIT || FILESIZE512 */ 2225 2226 if (limit == RLIM_INFINITY) 2227 xprintf("unlimited"); 2228 else 2229# if defined(RLIMIT_CPU) && defined(_OSD_POSIX) 2230 if (lp->limconst == RLIMIT_CPU && 2231 (unsigned long)limit >= 0x7ffffffdUL) 2232 xprintf("unlimited"); 2233 else 2234# endif 2235# ifdef RLIMIT_CPU 2236 if (lp->limconst == RLIMIT_CPU) 2237 psecs(limit); 2238 else 2239# endif /* RLIMIT_CPU */ 2240 xprintf("%ld %s", (long) (limit / xdiv), lp->limscale); 2241 xputchar('\n'); 2242} 2243 2244/*ARGSUSED*/ 2245void 2246dounlimit(Char **v, struct command *c) 2247{ 2248 struct limits *lp; 2249 int lerr = 0; 2250 int hard = 0; 2251 int force = 0; 2252 2253 USE(c); 2254 while (*++v && **v == '-') { 2255 Char *vp = *v; 2256 while (*++vp) 2257 switch (*vp) { 2258 case 'f': 2259 force = 1; 2260 break; 2261 case 'h': 2262 hard = 1; 2263 break; 2264 default: 2265 stderror(ERR_ULIMUS); 2266 break; 2267 } 2268 } 2269 2270 if (*v == 0) { 2271 for (lp = limits; lp->limconst >= 0; lp++) 2272 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0) 2273 lerr++; 2274 if (!force && lerr) 2275 stderror(ERR_SILENT); 2276 return; 2277 } 2278 while (*v) { 2279 lp = findlim(*v++); 2280 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0 && !force) 2281 stderror(ERR_SILENT); 2282 } 2283} 2284 2285static int 2286setlim(struct limits *lp, int hard, RLIM_TYPE limit) 2287{ 2288# ifdef BSDLIMIT 2289 struct rlimit rlim; 2290 2291 (void) getrlimit(lp->limconst, &rlim); 2292 2293# ifdef FILESIZE512 2294 /* Even though hpux has setrlimit(), it expects fsize in 512 byte blocks */ 2295 if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 2296 limit /= 512; 2297# endif /* FILESIZE512 */ 2298 if (hard) 2299 rlim.rlim_max = limit; 2300 else if (limit == RLIM_INFINITY && euid != 0) 2301 rlim.rlim_cur = rlim.rlim_max; 2302 else 2303 rlim.rlim_cur = limit; 2304 2305 if (rlim.rlim_cur > rlim.rlim_max) 2306 rlim.rlim_max = rlim.rlim_cur; 2307 2308 if (setrlimit(lp->limconst, &rlim) < 0) { 2309# else /* BSDLIMIT */ 2310 if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 2311 limit /= 512; 2312# ifdef aiws 2313 if (lp->limconst == RLIMIT_DATA) 2314 limit += 0x20000000; 2315# endif /* aiws */ 2316 if (ulimit(toset(lp->limconst), limit) < 0) { 2317# endif /* BSDLIMIT */ 2318 int err; 2319 char *op, *type; 2320 2321 err = errno; 2322 op = strsave(limit == RLIM_INFINITY ? CGETS(15, 2, "remove") : 2323 CGETS(15, 3, "set")); 2324 cleanup_push(op, xfree); 2325 type = strsave(hard ? CGETS(15, 4, " hard") : ""); 2326 cleanup_push(type, xfree); 2327 xprintf(CGETS(15, 1, "%s: %s: Can't %s%s limit (%s)\n"), bname, 2328 lp->limname, op, type, strerror(err)); 2329 cleanup_until(op); 2330 return (-1); 2331 } 2332 return (0); 2333} 2334 2335#endif /* !HAVENOLIMIT */ 2336 2337/*ARGSUSED*/ 2338void 2339dosuspend(Char **v, struct command *c) 2340{ 2341#ifdef BSDJOBS 2342 struct sigaction old; 2343#endif /* BSDJOBS */ 2344 2345 USE(c); 2346 USE(v); 2347 2348 if (loginsh) 2349 stderror(ERR_SUSPLOG); 2350 untty(); 2351 2352#ifdef BSDJOBS 2353 sigaction(SIGTSTP, NULL, &old); 2354 signal(SIGTSTP, SIG_DFL); 2355 (void) kill(0, SIGTSTP); 2356 /* the shell stops here */ 2357 sigaction(SIGTSTP, &old, NULL); 2358#else /* !BSDJOBS */ 2359 stderror(ERR_JOBCONTROL); 2360#endif /* BSDJOBS */ 2361 2362#ifdef BSDJOBS 2363 if (tpgrp != -1) { 2364 if (grabpgrp(FSHTTY, opgrp) == -1) 2365 stderror(ERR_SYSTEM, "tcgetpgrp", strerror(errno)); 2366 (void) setpgid(0, shpgrp); 2367 (void) tcsetpgrp(FSHTTY, shpgrp); 2368 } 2369#endif /* BSDJOBS */ 2370 (void) setdisc(FSHTTY); 2371} 2372 2373/* This is the dreaded EVAL built-in. 2374 * If you don't fiddle with file descriptors, and reset didfds, 2375 * this command will either ignore redirection inside or outside 2376 * its arguments, e.g. eval "date >x" vs. eval "date" >x 2377 * The stuff here seems to work, but I did it by trial and error rather 2378 * than really knowing what was going on. If tpgrp is zero, we are 2379 * probably a background eval, e.g. "eval date &", and we want to 2380 * make sure that any processes we start stay in our pgrp. 2381 * This is also the case for "time eval date" -- stay in same pgrp. 2382 * Otherwise, under stty tostop, processes will stop in the wrong 2383 * pgrp, with no way for the shell to get them going again. -IAN! 2384 */ 2385 2386struct doeval_state 2387{ 2388 Char **evalvec, *evalp; 2389 int didfds; 2390#ifndef CLOSE_ON_EXEC 2391 int didcch; 2392#endif 2393 int saveIN, saveOUT, saveDIAG; 2394 int SHIN, SHOUT, SHDIAG; 2395}; 2396 2397static void 2398doeval_cleanup(void *xstate) 2399{ 2400 struct doeval_state *state; 2401 2402 state = xstate; 2403 evalvec = state->evalvec; 2404 evalp = state->evalp; 2405 doneinp = 0; 2406#ifndef CLOSE_ON_EXEC 2407 didcch = state->didcch; 2408#endif /* CLOSE_ON_EXEC */ 2409 didfds = state->didfds; 2410 xclose(SHIN); 2411 xclose(SHOUT); 2412 xclose(SHDIAG); 2413 close_on_exec(SHIN = dmove(state->saveIN, state->SHIN), 1); 2414 close_on_exec(SHOUT = dmove(state->saveOUT, state->SHOUT), 1); 2415 close_on_exec(SHDIAG = dmove(state->saveDIAG, state->SHDIAG), 1); 2416} 2417 2418static Char **Ggv; 2419/*ARGSUSED*/ 2420void 2421doeval(Char **v, struct command *c) 2422{ 2423 struct doeval_state state; 2424 int gflag, my_reenter; 2425 Char **gv; 2426 jmp_buf_t osetexit; 2427 2428 USE(c); 2429 v++; 2430 if (*v == 0) 2431 return; 2432 gflag = tglob(v); 2433 if (gflag) { 2434 gv = v = globall(v, gflag); 2435 if (v == 0) 2436 stderror(ERR_NOMATCH); 2437 cleanup_push(gv, blk_cleanup); 2438 v = copyblk(v); 2439 } 2440 else { 2441 gv = NULL; 2442 v = copyblk(v); 2443 trim(v); 2444 } 2445 2446 Ggv = gv; 2447 state.evalvec = evalvec; 2448 state.evalp = evalp; 2449 state.didfds = didfds; 2450#ifndef CLOSE_ON_EXEC 2451 state.didcch = didcch; 2452#endif /* CLOSE_ON_EXEC */ 2453 state.SHIN = SHIN; 2454 state.SHOUT = SHOUT; 2455 state.SHDIAG = SHDIAG; 2456 2457 (void)close_on_exec(state.saveIN = dcopy(SHIN, -1), 1); 2458 (void)close_on_exec(state.saveOUT = dcopy(SHOUT, -1), 1); 2459 (void)close_on_exec(state.saveDIAG = dcopy(SHDIAG, -1), 1); 2460 2461 cleanup_push(&state, doeval_cleanup); 2462 2463 getexit(osetexit); 2464 2465 /* PWP: setjmp/longjmp bugfix for optimizing compilers */ 2466#ifdef cray 2467 my_reenter = 1; /* assume non-zero return val */ 2468 if (setexit() == 0) { 2469 my_reenter = 0; /* Oh well, we were wrong */ 2470#else /* !cray */ 2471 if ((my_reenter = setexit()) == 0) { 2472#endif /* cray */ 2473 evalvec = v; 2474 evalp = 0; 2475 (void)close_on_exec(SHIN = dcopy(0, -1), 1); 2476 (void)close_on_exec(SHOUT = dcopy(1, -1), 1); 2477 (void)close_on_exec(SHDIAG = dcopy(2, -1), 1); 2478#ifndef CLOSE_ON_EXEC 2479 didcch = 0; 2480#endif /* CLOSE_ON_EXEC */ 2481 didfds = 0; 2482 gv = Ggv; 2483 process(0); 2484 Ggv = gv; 2485 } 2486 2487 if (my_reenter == 0) { 2488 cleanup_until(&state); 2489 if (Ggv) 2490 cleanup_until(Ggv); 2491 } 2492 2493 resexit(osetexit); 2494 if (my_reenter) 2495 stderror(ERR_SILENT); 2496} 2497 2498/*************************************************************************/ 2499/* print list of builtin commands */ 2500 2501static void 2502lbuffed_cleanup (void *dummy) 2503{ 2504 USE(dummy); 2505 lbuffed = 1; 2506} 2507 2508/*ARGSUSED*/ 2509void 2510dobuiltins(Char **v, struct command *c) 2511{ 2512 /* would use print_by_column() in tw.parse.c but that assumes 2513 * we have an array of Char * to pass.. (sg) 2514 */ 2515 const struct biltins *b; 2516 int row, col, columns, rows; 2517 unsigned int w, maxwidth; 2518 2519 USE(c); 2520 USE(v); 2521 lbuffed = 0; /* turn off line buffering */ 2522 cleanup_push(&lbuffed, lbuffed_cleanup); 2523 2524 /* find widest string */ 2525 for (maxwidth = 0, b = bfunc; b < &bfunc[nbfunc]; ++b) 2526 maxwidth = max(maxwidth, strlen(b->bname)); 2527 ++maxwidth; /* for space */ 2528 2529 columns = (TermH + 1) / maxwidth; /* PWP: terminal size change */ 2530 if (!columns) 2531 columns = 1; 2532 rows = (nbfunc + (columns - 1)) / columns; 2533 2534 for (b = bfunc, row = 0; row < rows; row++) { 2535 for (col = 0; col < columns; col++) { 2536 if (b < &bfunc[nbfunc]) { 2537 w = strlen(b->bname); 2538 xprintf("%s", b->bname); 2539 if (col < (columns - 1)) /* Not last column? */ 2540 for (; w < maxwidth; w++) 2541 xputchar(' '); 2542 ++b; 2543 } 2544 } 2545 if (row < (rows - 1)) { 2546 if (Tty_raw_mode) 2547 xputchar('\r'); 2548 xputchar('\n'); 2549 } 2550 } 2551#ifdef WINNT_NATIVE 2552 nt_print_builtins(maxwidth); 2553#else 2554 if (Tty_raw_mode) 2555 xputchar('\r'); 2556 xputchar('\n'); 2557#endif /* WINNT_NATIVE */ 2558 2559 cleanup_until(&lbuffed); /* turn back on line buffering */ 2560 flush(); 2561} 2562 2563#ifdef NLS_CATALOGS 2564char * 2565xcatgets(nl_catd ctd, int set_id, int msg_id, const char *s) 2566{ 2567 char *res; 2568 2569 errno = 0; 2570 while ((res = catgets(ctd, set_id, msg_id, s)) == s && errno == EINTR) { 2571 handle_pending_signals(); 2572 errno = 0; 2573 } 2574 return res; 2575} 2576 2577 2578# if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2579char * 2580iconv_catgets(nl_catd ctd, int set_id, int msg_id, const char *s) 2581{ 2582 static char *buf = NULL; 2583 static size_t buf_size = 0; 2584 2585 char *orig, *dest, *p; 2586 ICONV_CONST char *src; 2587 size_t src_size, dest_size; 2588 2589 orig = xcatgets(ctd, set_id, msg_id, s); 2590 if (catgets_iconv == (iconv_t)-1 || orig == s) 2591 return orig; 2592 src = orig; 2593 src_size = strlen(src) + 1; 2594 if (buf == NULL && (buf = xmalloc(buf_size = src_size + 32)) == NULL) 2595 return orig; 2596 dest = buf; 2597 while (src_size != 0) { 2598 dest_size = buf + buf_size - dest; 2599 if (iconv(catgets_iconv, &src, &src_size, &dest, &dest_size) 2600 == (size_t)-1) { 2601 switch (errno) { 2602 case E2BIG: 2603 if ((p = xrealloc(buf, buf_size * 2)) == NULL) 2604 return orig; 2605 buf_size *= 2; 2606 dest = p + (dest - buf); 2607 buf = p; 2608 break; 2609 2610 case EILSEQ: case EINVAL: default: 2611 return orig; 2612 } 2613 } 2614 } 2615 return buf; 2616} 2617# endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2618#endif /* NLS_CATALOGS */ 2619 2620void 2621nlsinit(void) 2622{ 2623#ifdef NLS_CATALOGS 2624 static const char default_catalog[] = "tcsh"; 2625 2626 char *catalog = (char *)(intptr_t)default_catalog; 2627 2628 if (adrof(STRcatalog) != NULL) 2629 catalog = xasprintf("tcsh.%s", short2str(varval(STRcatalog))); 2630#ifdef NL_CAT_LOCALE /* POSIX-compliant. */ 2631 /* 2632 * Check if LC_MESSAGES is set in the environment and use it, if so. 2633 * If not, fall back to the setting of LANG. 2634 */ 2635 catd = catopen(catalog, tgetenv(STRLC_MESSAGES) ? NL_CAT_LOCALE : 0); 2636#else /* pre-POSIX */ 2637# ifndef MCLoadBySet 2638# define MCLoadBySet 0 2639# endif 2640 catd = catopen(catalog, MCLoadBySet); 2641#endif 2642 if (catalog != default_catalog) 2643 xfree(catalog); 2644#if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2645 /* xcatgets (), not CGETS, the charset name should be in ASCII anyway. */ 2646 catgets_iconv = iconv_open (nl_langinfo (CODESET), 2647 xcatgets(catd, 255, 1, "UTF-8")); 2648#endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2649#endif /* NLS_CATALOGS */ 2650#ifdef WINNT_NATIVE 2651 nls_dll_init(); 2652#endif /* WINNT_NATIVE */ 2653 errinit(); /* init the errorlist in correct locale */ 2654 mesginit(); /* init the messages for signals */ 2655 dateinit(); /* init the messages for dates */ 2656 editinit(); /* init the editor messages */ 2657 terminit(); /* init the termcap messages */ 2658} 2659 2660void 2661nlsclose(void) 2662{ 2663#ifdef NLS_CATALOGS 2664#if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) 2665 if (catgets_iconv != (iconv_t)-1) { 2666 iconv_close(catgets_iconv); 2667 catgets_iconv = (iconv_t)-1; 2668 } 2669#endif /* HAVE_ICONV && HAVE_NL_LANGINFO */ 2670 if (catd != (nl_catd)-1) { 2671 /* 2672 * catclose can call other functions which can call longjmp 2673 * making us re-enter this code. Prevent infinite recursion 2674 * by resetting catd. Problem reported and solved by: 2675 * Gerhard Niklasch 2676 */ 2677 nl_catd oldcatd = catd; 2678 catd = (nl_catd)-1; 2679 while (catclose(oldcatd) == -1 && errno == EINTR) 2680 handle_pending_signals(); 2681 } 2682#endif /* NLS_CATALOGS */ 2683} 2684