diff options
author | mp <mp@FreeBSD.org> | 2007-03-11 22:33:41 +0000 |
---|---|---|
committer | mp <mp@FreeBSD.org> | 2007-03-11 22:33:41 +0000 |
commit | a40980339b13e3b506c2317b5b4864127039eb2c (patch) | |
tree | 34aefea92d30b614247ef1f2671f2362f4761785 /contrib/tcsh/sh.c | |
parent | 32837fb336d4709f0a121130a3a78f29be0db5ed (diff) | |
download | FreeBSD-src-a40980339b13e3b506c2317b5b4864127039eb2c.zip FreeBSD-src-a40980339b13e3b506c2317b5b4864127039eb2c.tar.gz |
Import of tcsh-6.15.00
Diffstat (limited to 'contrib/tcsh/sh.c')
-rw-r--r-- | contrib/tcsh/sh.c | 759 |
1 files changed, 293 insertions, 466 deletions
diff --git a/contrib/tcsh/sh.c b/contrib/tcsh/sh.c index 178b972..57b1bef 100644 --- a/contrib/tcsh/sh.c +++ b/contrib/tcsh/sh.c @@ -1,4 +1,4 @@ -/* $Header: /src/pub/tcsh/sh.c,v 3.123 2005/03/21 21:26:36 kim Exp $ */ +/* $Header: /p/tcsh/cvsroot/tcsh/sh.c,v 3.136 2007/02/22 21:57:37 christos Exp $ */ /* * sh.c: Main shell routines */ @@ -39,7 +39,7 @@ char copyright[] = All rights reserved.\n"; #endif /* not lint */ -RCSID("$Id: sh.c,v 3.123 2005/03/21 21:26:36 kim Exp $") +RCSID("$tcsh: sh.c,v 3.136 2007/02/22 21:57:37 christos Exp $") #include "tc.h" #include "ed.h" @@ -81,12 +81,9 @@ extern int NLSMapsAreInited; jmp_buf_t reslab INIT_ZERO_STRUCT; static const char tcshstr[] = "tcsh"; -#ifdef WINNT_NATIVE -static const char tcshstr_nt[] = "tcsh.exe"; -#endif /* WINNT_NATIVE */ -signalfun_t parintr = 0; /* Parents interrupt catch */ -signalfun_t parterm = 0; /* Parents terminate catch */ +struct sigaction parintr; /* Parents interrupt catch */ +struct sigaction parterm; /* Parents terminate catch */ #ifdef TESLA int do_logout = 0; @@ -103,14 +100,7 @@ static Char INVCHAR; Char *INVPTR = &INVCHAR; Char **INVPPTR = &INVPTR; -static int nofile = 0; -static int reenter = 0; -static int nverbose = 0; -static int nexececho = 0; -static int quitit = 0; -static int rdirs = 0; -int fast = 0; -static int batch = 0; +static int fast = 0; static int mflag = 0; static int prompt = 1; int enterhist = 0; @@ -123,7 +113,6 @@ int exitset = 0; static time_t chktim; /* Time mail last checked */ char *progname; int tcsh; -extern char **environ; /* * This preserves the input state of the shell. It is used by @@ -146,54 +135,48 @@ struct saved_state { int onelflg; int enterhist; Char **argv; + Char **av; Char HIST; int cantell; struct Bin B; - /* These keep signal state and setjump state */ -#ifdef BSDSIGS - sigmask_t mask; -#endif - jmp_buf_t oldexit; - int reenter; }; -static int srccat __P((Char *, Char *)); +static int srccat (Char *, Char *); #ifndef WINNT_NATIVE -static int srcfile __P((const char *, int, int, Char **)); +static int srcfile (const char *, int, int, Char **); #else -int srcfile __P((const char *, int, int, Char **)); +int srcfile (const char *, int, int, Char **); #endif /*WINNT_NATIVE*/ -static RETSIGTYPE phup __P((int)); -static void srcunit __P((int, int, int, Char **)); -static void mailchk __P((void)); +static void srcunit (int, int, int, Char **); +static void mailchk (void); #ifndef _PATH_DEFPATH -static Char **defaultpath __P((void)); +static Char **defaultpath (void); #endif -static void record __P((void)); -static void st_save __P((struct saved_state *, int, int, - Char **, Char **)); -static void st_restore __P((struct saved_state *, Char **)); +static void record (void); +static void st_save (struct saved_state *, int, int, + Char **, Char **); +static void st_restore (void *); - int main __P((int, char **)); + int main (int, char **); int -main(argc, argv) - int argc; - char **argv; +main(int argc, char **argv) { + int batch = 0; + volatile int nexececho = 0; + int nofile = 0; + volatile int nverbose = 0; + volatile int rdirs = 0; + int quitit = 0; Char *cp; #ifdef AUTOLOGOUT Char *cp2; #endif char *tcp, *ttyn; - int f; + int f, reenter; char **tempv; int osetintr; - signalfun_t oparintr; - -#ifdef BSDSIGS - sigvec_t osv; -#endif /* BSDSIGS */ + struct sigaction oparintr; #ifdef WINNT_NATIVE nt_init(); @@ -211,7 +194,7 @@ main(argc, argv) nlsinit(); #ifdef MALLOC_TRACE - mal_setstatsfile(fdopen(dmove(open("/tmp/tcsh.trace", + mal_setstatsfile(fdopen(dmove(xopen("/tmp/tcsh.trace", O_WRONLY|O_CREAT|O_LARGEFILE, 0666), 25), "w")); mal_trace(1); #endif /* MALLOC_TRACE */ @@ -239,11 +222,11 @@ main(argc, argv) */ { do - if ((f = open(_PATH_DEVNULL, O_RDONLY|O_LARGEFILE)) == -1 && - (f = open("/", O_RDONLY|O_LARGEFILE)) == -1) + if ((f = xopen(_PATH_DEVNULL, O_RDONLY|O_LARGEFILE)) == -1 && + (f = xopen("/", O_RDONLY|O_LARGEFILE)) == -1) exit(1); while (f < 3); - (void) close(f); + xclose(f); } #ifdef O_TEXT @@ -295,7 +278,7 @@ main(argc, argv) bslash_quote = 0; /* PWP: do tcsh-style backslash quoting? */ /* Default history size to 100 */ - set(STRhistory, SAVE("100"), VAR_READWRITE); + setcopy(STRhistory, str2short("100"), VAR_READWRITE); tempv = argv; ffile = SAVE(tempv[0]); @@ -322,22 +305,21 @@ main(argc, argv) #endif /* _VMS_POSIX */ if (loginsh && **tempv != '-') { + char *argv0; + /* * Mangle the argv space */ tempv[1][0] = '\0'; tempv[1][1] = '\0'; tempv[1] = NULL; - for (tcp = *tempv; *tcp++;) - continue; - for (tcp--; tcp >= *tempv; tcp--) - tcp[1] = tcp[0]; - *++tcp = '-'; + argv0 = strspl("-", *tempv); + *tempv = argv0; argc--; } if (loginsh) { (void) time(&chktim); - set(STRloginsh, Strsave(STRNULL), VAR_READWRITE); + setNS(STRloginsh); } AsciiOnly = 1; @@ -360,7 +342,7 @@ main(argc, argv) { int k; - for (k = 0200; k <= 0377 && !Isprint(k); k++) + for (k = 0200; k <= 0377 && !Isprint(CTL_ESC(k)); k++) continue; AsciiOnly = MB_CUR_MAX == 1 && k > 0377; } @@ -398,9 +380,9 @@ main(argc, argv) * 2. reenable the control terminal */ if (loginsh && isatty(SHIN)) { - ttyn = (char *) ttyname(SHIN); - (void) close(SHIN); - SHIN = open(ttyn, O_RDWR|O_LARGEFILE); + ttyn = ttyname(SHIN); + xclose(SHIN); + SHIN = xopen(ttyn, O_RDWR|O_LARGEFILE); shpgrp = getpid(); (void) ioctl (SHIN, TIOCSPGRP, (ioctl_t) &shpgrp); (void) setpgid(0, shpgrp); @@ -424,12 +406,12 @@ main(argc, argv) * utmp, so we keep it too. */ if (strncmp(ttyn, "/dev/", 5) == 0) - set(STRtty, cp = SAVE(ttyn + 5), VAR_READWRITE); + setv(STRtty, cp = SAVE(ttyn + 5), VAR_READWRITE); else - set(STRtty, cp = SAVE(ttyn), VAR_READWRITE); + setv(STRtty, cp = SAVE(ttyn), VAR_READWRITE); } else - set(STRtty, cp = SAVE(""), VAR_READWRITE); + setv(STRtty, cp = SAVE(""), VAR_READWRITE); /* * Initialize the shell variables. ARGV and PROMPT are initialized later. * STATUS is also munged in several places. CHILD is munged when @@ -463,14 +445,13 @@ main(argc, argv) */ #ifdef AUTOLOGOUT # ifdef convex - if (uid == 0) { + if (uid == 0) /* root always has a 15 minute autologout */ - set(STRautologout, Strsave(STRrootdefautologout), VAR_READWRITE); - } + setcopy(STRautologout, STRrootdefautologout, VAR_READWRITE); else if (loginsh) /* users get autologout set to 0 */ - set(STRautologout, Strsave(STR0), VAR_READWRITE); + setcopy(STRautologout, STR0, VAR_READWRITE); # else /* convex */ if (loginsh || (uid == 0)) { if (*cp) { @@ -484,8 +465,7 @@ main(argc, argv) ((Strncmp(cp, STRpts, 3) == 0) && cp[3] == '/'))) { if (getenv("DISPLAY") == NULL) { /* NOT on X window shells */ - set(STRautologout, Strsave(STRdefautologout), - VAR_READWRITE); + setcopy(STRautologout, STRdefautologout, VAR_READWRITE); } } } @@ -493,9 +473,9 @@ main(argc, argv) # endif /* convex */ #endif /* AUTOLOGOUT */ - (void) sigset(SIGALRM, alrmcatch); + sigset_interrupting(SIGALRM, queue_alrmcatch); - set(STRstatus, Strsave(STR0), VAR_READWRITE); + setcopy(STRstatus, STR0, VAR_READWRITE); /* * get and set machine specific environment variables @@ -509,42 +489,32 @@ main(argc, argv) #if ECHO_STYLE != BSD_ECHO if (tcsh) { # if ECHO_STYLE == NONE_ECHO - set(STRecho_style, Strsave(STRnone), VAR_READWRITE); + setcopy(STRecho_style, STRnone, VAR_READWRITE); # endif /* ECHO_STYLE == NONE_ECHO */ # if ECHO_STYLE == SYSV_ECHO - set(STRecho_style, Strsave(STRsysv), VAR_READWRITE); + setcopy(STRecho_style, STRsysv, VAR_READWRITE); # endif /* ECHO_STYLE == SYSV_ECHO */ # if ECHO_STYLE == BOTH_ECHO - set(STRecho_style, Strsave(STRboth), VAR_READWRITE); + setcopy(STRecho_style, STRboth, VAR_READWRITE); # endif /* ECHO_STYLE == BOTH_ECHO */ } else #endif /* ECHO_STYLE != BSD_ECHO */ - set(STRecho_style, Strsave(STRbsd), VAR_READWRITE); + setcopy(STRecho_style, STRbsd, VAR_READWRITE); /* * increment the shell level. */ shlvl(1); - if ((tcp = getenv("HOME")) != NULL) { - if (strlen(tcp) >= MAXPATHLEN) { - struct passwd *pw; - if ((pw = getpwuid(getuid())) != NULL) - cp = quote(SAVE(pw->pw_dir)); - else { - tcp[MAXPATHLEN-1] = '\0'; - cp = quote(SAVE(tcp)); - } - } else { - cp = quote(SAVE(tcp)); - } - } else + if ((tcp = getenv("HOME")) != NULL) + cp = quote(SAVE(tcp)); + else cp = NULL; if (cp == NULL) fast = 1; /* No home -> can't read scripts */ else - set(STRhome, cp, VAR_READWRITE); + setv(STRhome, cp, VAR_READWRITE); dinit(cp); /* dinit thinks that HOME == cwd in a login * shell */ @@ -554,7 +524,6 @@ main(argc, argv) */ { char *cln, *cus, *cgr; - Char buff[BUFSIZE]; struct passwd *pw; struct group *gr; @@ -562,26 +531,23 @@ main(argc, argv) #ifdef apollo int oid = getoid(); - (void) Itoa(oid, buff, 0, 0); - set(STRoid, Strsave(buff), VAR_READWRITE); + setv(STRoid, Itoa(oid, 0, 0), VAR_READWRITE); #endif /* apollo */ - (void) Itoa(uid, buff, 0, 0); - set(STRuid, Strsave(buff), VAR_READWRITE); + setv(STRuid, Itoa(uid, 0, 0), VAR_READWRITE); - (void) Itoa(gid, buff, 0, 0); - set(STRgid, Strsave(buff), VAR_READWRITE); + setv(STRgid, Itoa(gid, 0, 0), VAR_READWRITE); cln = getenv("LOGNAME"); cus = getenv("USER"); if (cus != NULL) - set(STRuser, quote(SAVE(cus)), VAR_READWRITE); + setv(STRuser, quote(SAVE(cus)), VAR_READWRITE); else if (cln != NULL) - set(STRuser, quote(SAVE(cln)), VAR_READWRITE); - else if ((pw = getpwuid(uid)) == NULL) - set(STRuser, SAVE("unknown"), VAR_READWRITE); + setv(STRuser, quote(SAVE(cln)), VAR_READWRITE); + else if ((pw = xgetpwuid(uid)) == NULL) + setcopy(STRuser, str2short("unknown"), VAR_READWRITE); else - set(STRuser, SAVE(pw->pw_name), VAR_READWRITE); + setcopy(STRuser, str2short(pw->pw_name), VAR_READWRITE); if (cln == NULL) tsetenv(STRLOGNAME, varval(STRuser)); if (cus == NULL) @@ -589,11 +555,11 @@ main(argc, argv) cgr = getenv("GROUP"); if (cgr != NULL) - set(STRgroup, quote(SAVE(cgr)), VAR_READWRITE); - else if ((gr = getgrgid(gid)) == NULL) - set(STRgroup, SAVE("unknown"), VAR_READWRITE); + setv(STRgroup, quote(SAVE(cgr)), VAR_READWRITE); + else if ((gr = xgetgrgid(gid)) == NULL) + setcopy(STRgroup, str2short("unknown"), VAR_READWRITE); else - set(STRgroup, SAVE(gr->gr_name), VAR_READWRITE); + setcopy(STRgroup, str2short(gr->gr_name), VAR_READWRITE); if (cgr == NULL) tsetenv(STRKGROUP, varval(STRgroup)); } @@ -648,7 +614,7 @@ main(argc, argv) * if noediting is set, we switch on editing if $TERM is changed. */ if ((tcp = getenv("TERM")) != NULL) { - set(STRterm, quote(SAVE(tcp)), VAR_READWRITE); + setv(STRterm, quote(SAVE(tcp)), VAR_READWRITE); noediting = strcmp(tcp, "unknown") == 0 || strcmp(tcp, "dumb") == 0 || strcmp(tcp, "network") == 0; editing = strcmp(tcp, "emacs") != 0 && strcmp(tcp, "wm") != 0 && @@ -664,24 +630,24 @@ main(argc, argv) * need a value. Making it 'emacs' might be confusing. */ if (editing) - set(STRedit, Strsave(STRNULL), VAR_READWRITE); + setNS(STRedit); /* * still more mutability: make the complete routine automatically add the * suffix of file names... */ - set(STRaddsuffix, Strsave(STRNULL), VAR_READWRITE); + setNS(STRaddsuffix); /* * Compatibility with tcsh >= 6.12 by default */ - set(STRcsubstnonl, Strsave(STRNULL), VAR_READWRITE); + setNS(STRcsubstnonl); /* * Random default kill ring size */ - set(STRkillring, SAVE("30"), VAR_READWRITE); + setcopy(STRkillring, str2short("30"), VAR_READWRITE); /* * Re-initialize path if set in environment @@ -709,20 +675,26 @@ main(argc, argv) * default isn't appropriate (sg). */ - int sh_len = 0; + size_t sh_len = 0; if ((tcp = getenv("SHELL")) != NULL) { sh_len = strlen(tcp); if ((sh_len >= 5 && strcmp(tcp + (sh_len - 5), "/tcsh") == 0) || (!tcsh && sh_len >= 4 && strcmp(tcp + (sh_len - 4), "/csh") == 0)) - set(STRshell, quote(SAVE(tcp)), VAR_READWRITE); + setv(STRshell, quote(SAVE(tcp)), VAR_READWRITE); else sh_len = 0; } if (sh_len == 0) - set(STRshell, Strsave(STR_SHELLPATH), VAR_READWRITE); + setcopy(STRshell, STR_SHELLPATH, VAR_READWRITE); } +#ifdef _OSD_POSIX /* BS2000 needs this variable set to "SHELL" */ + if ((tcp = getenv("PROGRAM_ENVIRONMENT")) == NULL) + tcp = "SHELL"; + tsetenv(STRPROGRAM_ENVIRONMENT, quote(str2short(tcp))); +#endif /* _OSD_POSIX */ + #ifdef COLOR_LS_F if ((tcp = getenv("LS_COLORS")) != NULL) parseLS_COLORS(str2short(tcp)); @@ -731,10 +703,18 @@ main(argc, argv) doldol = putn((int) getpid()); /* For $$ */ #ifdef WINNT_NATIVE { - char *strtmp1, strtmp2[MAXPATHLEN]; - if ((strtmp1 = getenv("TMP")) != NULL) - wsprintf(strtmp2, "%s/%s", strtmp1, "sh"); - shtemp = Strspl(SAVE(strtmp2), doldol); /* For << */ + char *tmp; + Char *tmp2; + if ((tmp = getenv("TMP")) != NULL) { + tmp = xasprintf("%s/%s", tmp, "sh"); + tmp2 = SAVE(tmp); + xfree(tmp); + } + else { + tmp2 = SAVE(""); + } + shtemp = Strspl(tmp2, doldol); /* For << */ + xfree(tmp2); } #else /* !WINNT_NATIVE */ shtemp = Strspl(STRtmpsh, doldol); /* For << */ @@ -746,33 +726,8 @@ main(argc, argv) * be either. Our children inherit termination from our parent. We catch it * only if we are the login shell. */ -#ifdef BSDSIGS - /* - * PURIFY-2 claims that osv does not get - * initialized after the sigvec call - */ - setzero((char*) &osv, sizeof(osv)); - /* parents interruptibility */ - (void) mysigvec(SIGINT, NULL, &osv); - parintr = (signalfun_t) osv.sv_handler; - (void) mysigvec(SIGTERM, NULL, &osv); - parterm = (signalfun_t) osv.sv_handler; -#else /* BSDSIGS */ - parintr = signal(SIGINT, SIG_IGN); /* parents interruptibility */ - (void) sigset(SIGINT, parintr); /* ... restore */ - -# ifdef COHERENT - if (loginsh) /* it seems that SIGTERM is always set to SIG_IGN by */ - /* init/getty so it should be set to SIG_DFL - there may be */ - /* a better fix for this. */ - parterm = SIG_DFL; - else -# else /* !COHERENT */ - parterm = signal(SIGTERM, SIG_IGN); /* parents terminability */ -# endif /* COHERENT */ - (void) sigset(SIGTERM, parterm); /* ... restore */ - -#endif /* BSDSIGS */ + sigaction(SIGINT, NULL, &parintr); + sigaction(SIGTERM, NULL, &parterm); #ifdef TCF @@ -857,7 +812,7 @@ main(argc, argv) * we put the command into a variable */ if (arginp != NULL) - set(STRcommand, quote(Strsave(arginp)), VAR_READWRITE); + setv(STRcommand, quote(Strsave(arginp)), VAR_READWRITE); /* * * Give an error on -c arguments that end in * backslash to @@ -866,7 +821,7 @@ main(argc, argv) { int count; - cp = arginp + Strlen(arginp); + cp = Strend(arginp); count = 0; while (cp > arginp && *--cp == '\\') ++count; @@ -950,7 +905,7 @@ main(argc, argv) setNS(STRecho); /* NOW! */ break; - case 'F': /* Undocumented flag */ + case 'F': /* * This will cause children to be created using fork instead of * vfork. @@ -984,7 +939,7 @@ main(argc, argv) * read commands. */ if (nofile == 0 && argc > 0) { - nofile = open(tempv[0], O_RDONLY|O_LARGEFILE); + nofile = xopen(tempv[0], O_RDONLY|O_LARGEFILE); if (nofile < 0) { child = 1; /* So this ... */ /* ... doesn't return */ @@ -993,8 +948,7 @@ main(argc, argv) #ifdef O_TEXT setmode(nofile, O_TEXT); #endif - if (ffile != NULL) - xfree((ptr_t) ffile); + xfree(ffile); dolzero = 1; ffile = SAVE(tempv[0]); /* @@ -1072,12 +1026,12 @@ main(argc, argv) */ if (prompt) { if (tcsh) - set(STRprompt, Strsave(STRdeftcshprompt), VAR_READWRITE); + setcopy(STRprompt, STRdeftcshprompt, VAR_READWRITE); else - set(STRprompt, Strsave(STRdefcshprompt), VAR_READWRITE); + setcopy(STRprompt, STRdefcshprompt, VAR_READWRITE); /* that's a meta-questionmark */ - set(STRprompt2, Strsave(STRmquestion), VAR_READWRITE); - set(STRprompt3, Strsave(STRKCORRECT), VAR_READWRITE); + setcopy(STRprompt2, STRmquestion, VAR_READWRITE); + setcopy(STRprompt3, STRKCORRECT, VAR_READWRITE); } /* @@ -1087,12 +1041,13 @@ main(argc, argv) shpgrp = mygetpgrp(); opgrp = tpgrp = -1; if (setintr) { - signalfun_t osig; + struct sigaction osig; + **argv = '-'; if (!quitit) /* Wary! */ (void) signal(SIGQUIT, SIG_IGN); - (void) sigset(SIGINT, pintr); - (void) sighold(SIGINT); + pintr_disabled = 1; + sigset_interrupting(SIGINT, queue_pintr); (void) signal(SIGTERM, SIG_IGN); /* @@ -1106,18 +1061,21 @@ main(argc, argv) * We also only setup the handlers for shells that are trully * interactive. */ - osig = signal(SIGHUP, phup); /* exit processing on HUP */ - if (!loginsh && osig == SIG_IGN) - (void) signal(SIGHUP, osig); + sigaction(SIGHUP, NULL, &osig); + if (loginsh || osig.sa_handler != SIG_IGN) + /* exit processing on HUP */ + sigset_interrupting(SIGHUP, queue_phup); #ifdef SIGXCPU - osig = signal(SIGXCPU, phup); /* exit processing on XCPU */ - if (!loginsh && osig == SIG_IGN) - (void) signal(SIGXCPU, osig); + sigaction(SIGXCPU, NULL, &osig); + if (loginsh || osig.sa_handler != SIG_IGN) + /* exit processing on XCPU */ + sigset_interrupting(SIGXCPU, queue_phup); #endif #ifdef SIGXFSZ - osig = signal(SIGXFSZ, phup); /* exit processing on XFSZ */ - if (!loginsh && osig == SIG_IGN) - (void) signal(SIGXFSZ, osig); + sigaction(SIGXFSZ, NULL, &osig); + if (loginsh || osig.sa_handler != SIG_IGN) + /* exit processing on XFSZ */ + sigset_interrupting(SIGXFSZ, queue_phup); #endif if (quitit == 0 && arginp == 0) { @@ -1155,9 +1113,12 @@ main(argc, argv) retry: if ((tpgrp = tcgetpgrp(f)) != -1) { if (tpgrp != shpgrp) { - signalfun_t old = signal(SIGTTIN, SIG_DFL); + struct sigaction old; + + sigaction(SIGTTIN, NULL, &old); + signal(SIGTTIN, SIG_DFL); (void) kill(0, SIGTTIN); - (void) signal(SIGTTIN, old); + sigaction(SIGTTIN, &old, NULL); goto retry; } /* @@ -1216,7 +1177,7 @@ main(argc, argv) } if (tpgrp == -1) { notty: - xprintf(CGETS(11, 1, "Warning: no access to tty (%s).\n"), + xprintf(CGETS(11, 1, "Warning: no access to tty (%s).\n"), strerror(errno)); xprintf(CGETS(11, 2, "Thus no job control in this shell.\n")); /* @@ -1232,7 +1193,7 @@ main(argc, argv) #endif /* BSDJOBS */ } } - if ((setintr == 0) && (parintr == SIG_DFL)) + if (setintr == 0 && parintr.sa_handler == SIG_DFL) setintr = 1; /* @@ -1242,25 +1203,7 @@ main(argc, argv) * * David Dawes (dawes@physics.su.oz.au) Sept 1991 */ - -#if SYSVREL > 3 - { - struct sigaction act; - act.sa_handler=pchild; - (void) sigemptyset(&(act.sa_mask)); /* Don't block any extra sigs - * when the handler is called - */ - act.sa_flags=0; /* want behaviour of sigset() without - * SA_NOCLDSTOP - */ - - if ((sigaction(SIGCHLD,&act,(struct sigaction *)NULL)) == -1) - stderror(ERR_SYSTEM, "sigaction", strerror(errno)); - } -#else /* SYSVREL <= 3 */ - (void) sigset(SIGCHLD, pchild); /* while signals not ready */ -#endif /* SYSVREL <= 3 */ - + sigset_interrupting(SIGCHLD, queue_pchild); if (intty && !arginp) (void) ed_Setup(editing);/* Get the tty state, and set defaults */ @@ -1272,23 +1215,25 @@ main(argc, argv) */ osetintr = setintr; oparintr = parintr; - reenter = setexit(); /* PWP */ + (void)cleanup_push_mark(); /* There is no outer handler */ + if (setexit() != 0) /* PWP */ + reenter = 1; + else + reenter = 0; exitset++; haderr = 0; /* In case second time through */ if (!fast && reenter == 0) { /* Will have varval(STRhome) here because set fast if don't */ { -#ifdef BSDSIGS - sigmask_t omask = sigblock(sigmask(SIGINT)); -#else - (void) sighold(SIGINT); -#endif - setintr = 0; - parintr = SIG_IGN; /* onintr in /etc/ files has no effect */ + pintr_disabled++; + cleanup_push(&pintr_disabled, disabled_cleanup); + setintr = 0;/*FIXRESET:cleanup*/ + /* onintr in /etc/ files has no effect */ + parintr.sa_handler = SIG_IGN;/*FIXRESET: cleanup*/ #ifdef LOGINFIRST #ifdef _PATH_DOTLOGIN if (loginsh) - (void) srcfile(_PATH_DOTLOGIN, 0, 0, NULL); + (void) srcfile(_PATH_DOTLOGIN, 0, 0, NULL); #endif #endif @@ -1303,11 +1248,7 @@ main(argc, argv) (void) srcfile(_PATH_DOTLOGIN, 0, 0, NULL); #endif #endif -#ifdef BSDSIGS - (void) sigsetmask(omask); -#else - (void) sigrelse(SIGINT); -#endif + cleanup_until(&pintr_disabled); setintr = osetintr; parintr = oparintr; } @@ -1319,7 +1260,7 @@ main(argc, argv) if (!srccat(varval(STRhome), STRsldottcshrc)) (void) srccat(varval(STRhome), STRsldotcshrc); - if (!fast && !arginp && !onelflg && !havhash) + if (!arginp && !onelflg && !havhash) dohash(NULL,NULL); /* @@ -1330,12 +1271,13 @@ main(argc, argv) if (loginsh) (void) srccat(varval(STRhome), STRsldotlogin); #endif - if (!fast && (loginsh || rdirs)) + if (loginsh || rdirs) loaddirs(NULL); } /* Reset interrupt flag */ setintr = osetintr; parintr = oparintr; + exitset--; /* Initing AFTER .cshrc is the Right Way */ if (intty && !arginp) { /* PWP setup stuff */ @@ -1367,7 +1309,7 @@ main(argc, argv) if (intty) { if (loginsh) { xprintf("logout\n"); - (void) close(SHIN); + xclose(SHIN); child = 1; #ifdef TESLA do_logout = 1; @@ -1384,7 +1326,7 @@ main(argc, argv) } void -untty() +untty(void) { #ifdef BSDJOBS if (tpgrp > 0 && opgrp != shpgrp) { @@ -1396,10 +1338,9 @@ untty() } void -importpath(cp) - Char *cp; +importpath(Char *cp) { - int i = 0; + size_t i = 0; Char *dp; Char **pv; int c; @@ -1411,7 +1352,7 @@ importpath(cp) * i+2 where i is the number of colons in the path. There are i+1 * directories in the path plus we need room for a zero terminator. */ - pv = (Char **) xcalloc((size_t) (i + 2), sizeof(Char *)); + pv = xcalloc(i + 2, sizeof(Char *)); dp = cp; i = 0; if (*dp) @@ -1433,15 +1374,17 @@ importpath(cp) dp++; } pv[i] = 0; + cleanup_push(pv, blk_cleanup); setq(STRpath, pv, &shvhed, VAR_READWRITE); + cleanup_ignore(pv); + cleanup_until(pv); } /* * Source to the file which is the catenation of the argument names. */ static int -srccat(cp, dp) - Char *cp, *dp; +srccat(Char *cp, Char *dp) { if (cp[0] == '/' && cp[1] == '\0') return srcfile(short2str(dp), (mflag ? 0 : 1), 0, NULL); @@ -1451,18 +1394,17 @@ srccat(cp, dp) int rv; #ifdef WINNT_NATIVE - ep = cp; - while(*ep) - ep++; - if (ep[-1] == '/' && dp[0] == '/') /* silly win95 */ + ep = Strend(cp); + if (ep != cp && ep[-1] == '/' && dp[0] == '/') /* silly win95 */ dp++; #endif /* WINNT_NATIVE */ ep = Strspl(cp, dp); + cleanup_push(ep, xfree); ptr = short2str(ep); rv = srcfile(ptr, (mflag ? 0 : 1), 0, NULL); - xfree((ptr_t) ep); + cleanup_until(ep); return rv; } } @@ -1475,20 +1417,19 @@ static int #else int #endif /*WINNT_NATIVE*/ -srcfile(f, onlyown, flag, av) - const char *f; - int onlyown; - int flag; - Char **av; +srcfile(const char *f, int onlyown, int flag, Char **av) { int unit; - if ((unit = open(f, O_RDONLY|O_LARGEFILE)) == -1) + if ((unit = xopen(f, O_RDONLY|O_LARGEFILE)) == -1) return 0; #ifdef O_TEXT setmode(unit, O_TEXT); #endif + cleanup_push(&unit, open_cleanup); unit = dmove(unit, -1); + cleanup_ignore(&unit); + cleanup_until(&unit); (void) close_on_exec(unit, 1); srcunit(unit, onlyown, flag, av); @@ -1501,10 +1442,7 @@ srcfile(f, onlyown, flag, av) * fd. */ static void -st_save(st, unit, hflg, al, av) - struct saved_state *st; - int unit, hflg; - Char **al, **av; +st_save(struct saved_state *st, int unit, int hflg, Char **al, Char **av) { st->insource = insource; st->SHIN = SHIN; @@ -1574,6 +1512,7 @@ st_save(st, unit, hflg, al, av) } else st->argv = NULL; + st->av = av; SHIN = unit; /* Do this first */ @@ -1604,10 +1543,11 @@ st_save(st, unit, hflg, al, av) * Restore the shell to a saved state */ static void -st_restore(st, av) - struct saved_state *st; - Char **av; +st_restore(void *xst) { + struct saved_state *st; + + st = xst; if (st->SHIN == -1) return; @@ -1620,21 +1560,21 @@ st_restore(st, av) fblocks = 0; fbuf = NULL; for (i = 0; i < nfblocks; i++) - xfree((ptr_t) nfbuf[i]); - xfree((ptr_t) nfbuf); + xfree(nfbuf[i]); + xfree(nfbuf); } cpybin(B, st->B); - (void) close(SHIN); + xclose(SHIN); insource = st->insource; SHIN = st->SHIN; if (st->OLDSTD != -1) - (void)close(OLDSTD), OLDSTD = st->OLDSTD; + xclose(OLDSTD), OLDSTD = st->OLDSTD; if (st->SHOUT != -1) - (void)close(SHOUT), SHOUT = st->SHOUT; + xclose(SHOUT), SHOUT = st->SHOUT; if (st->SHDIAG != -1) - (void)close(SHDIAG), SHDIAG = st->SHDIAG; + xclose(SHDIAG), SHDIAG = st->SHDIAG; arginp = st->arginp; onelflg = st->onelflg; evalp = st->evalp; @@ -1651,7 +1591,7 @@ st_restore(st, av) if (st->argv != NULL) setq(STRargv, st->argv, &shvhed, VAR_READWRITE); - else if (av != NULL && *av != NULL && adrof(STRargv) != NULL) + else if (st->av != NULL && *st->av != NULL && adrof(STRargv) != NULL) unsetv(STRargv); } @@ -1660,13 +1600,10 @@ st_restore(st, av) * we don't chance it. This occurs on ".cshrc"s and the like. */ static void -srcunit(unit, onlyown, hflg, av) - int unit; - int onlyown; - int hflg; - Char **av; +srcunit(int unit, int onlyown, int hflg, Char **av) { struct saved_state st; + st.SHIN = -1; /* st_restore checks this */ if (unit < 0) @@ -1676,19 +1613,17 @@ srcunit(unit, onlyown, hflg, av) struct stat stb; if (fstat(unit, &stb) < 0) { - (void) close(unit); + xclose(unit); return; } } - getexit(st.oldexit); - - if (setintr) -#ifdef BSDSIGS - st.mask = sigblock(sigmask(SIGINT)); -#else - (void) sighold(SIGINT); -#endif + /* Does nothing before st_save() because st.SHIN == -1 */ + cleanup_push(&st, st_restore); + if (setintr) { + pintr_disabled++; + cleanup_push(&pintr_disabled, disabled_cleanup); + } /* Save the current state and move us to a new state */ st_save(&st, unit, hflg, NULL, av); @@ -1697,87 +1632,64 @@ srcunit(unit, onlyown, hflg, av) * Now if we are allowing commands to be interrupted, we let ourselves be * interrupted. */ - if (setintr) -#ifdef BSDSIGS - (void) sigsetmask(st.mask); -#else - (void) sigrelse(SIGINT); -#endif - - /* - * Bugfix for running out of memory by: Jak Kirman - * <jak%cs.brown.edu@RELAY.CS.NET>. Solution: pay attention to what - * setexit() is returning because reenter _may_ be in a register, and - * thus restored to 0 on a longjump(). (PWP: insert flames about - * compiler-dependant code here) PWP: THANKS LOTS !!! - * - * PWP: think of this as like a LISP (unwind-protect ...) - * thanks to Diana Smetters for pointing out how this _should_ be written - */ -#ifdef cray - st.reenter = 1; /* assume non-zero return val */ - if (setexit() == 0) { - st.reenter = 0; /* Oh well, we were wrong */ -#else - if ((st.reenter = setexit()) == 0) { -#endif - process(0); /* 0 -> blow away on errors */ + if (setintr) { + cleanup_until(&pintr_disabled); + pintr_disabled++; + cleanup_push(&pintr_disabled, disabled_cleanup); } - if (setintr) -#ifdef BSDSIGS - (void) sigsetmask(st.mask); -#else - (void) sigrelse(SIGINT); -#endif + process(0); /* 0 -> blow away on errors */ /* Restore the old state */ - st_restore(&st, av); - resexit(st.oldexit); - /* - * If process reset() (effectively an unwind) then we must also unwind. - */ - if (st.reenter) - stderror(ERR_SILENT); + cleanup_until(&st); } /*ARGSUSED*/ void -goodbye(v, c) - Char **v; - struct command *c; +goodbye(Char **v, struct command *c) { USE(v); USE(c); record(); if (loginsh) { - (void) sigset(SIGQUIT, SIG_IGN); - (void) sigset(SIGINT, SIG_IGN); - (void) sigset(SIGTERM, SIG_IGN); - (void) sigset(SIGHUP, SIG_IGN); + size_t omark; + sigset_t set; + + signal(SIGQUIT, SIG_IGN); + sigaddset(&set, SIGQUIT); + sigprocmask(SIG_UNBLOCK, &set, NULL); + signal(SIGINT, SIG_IGN); + sigaddset(&set, SIGINT); + signal(SIGTERM, SIG_IGN); + sigaddset(&set, SIGTERM); + signal(SIGHUP, SIG_IGN); + sigaddset(&set, SIGHUP); + sigprocmask(SIG_UNBLOCK, &set, NULL); + phup_disabled = 1; setintr = 0; /* No interrupts after "logout" */ /* Trap errors inside .logout */ - reenter = setexit(); - if (reenter != 0) - exitstat(); - if (!(adrof(STRlogout))) - set(STRlogout, Strsave(STRnormal), VAR_READWRITE); + omark = cleanup_push_mark(); + if (setexit() == 0) { + if (!(adrof(STRlogout))) + setcopy(STRlogout, STRnormal, VAR_READWRITE); #ifdef _PATH_DOTLOGOUT - (void) srcfile(_PATH_DOTLOGOUT, 0, 0, NULL); + (void) srcfile(_PATH_DOTLOGOUT, 0, 0, NULL); #endif - if (adrof(STRhome)) - (void) srccat(varval(STRhome), STRsldtlogout); + if (adrof(STRhome)) + (void) srccat(varval(STRhome), STRsldtlogout); #ifdef TESLA - do_logout = 1; + do_logout = 1; #endif /* TESLA */ + } + cleanup_pop_mark(omark); } exitstat(); } void -exitstat() +exitstat(void) { #ifdef PROF monitor(0); @@ -1795,28 +1707,11 @@ exitstat() /* * in the event of a HUP we want to save the history */ -static RETSIGTYPE -phup(snum) -int snum; +void +phup(void) { - /* - * There is no return from here, - * so we are not going to release SIGHUP - * anymore - */ -#ifdef UNRELSIGS - if (snum) - (void) sigset(snum, SIG_IGN); -#else -# ifdef BSDSIGS - (void) sigblock(sigmask(SIGHUP)); -# else - (void) sighold(SIGHUP); -# endif /* BSDSIGS */ -#endif /* UNRELSIGS */ - if (loginsh) { - set(STRlogout, Strsave(STRhangup), VAR_READWRITE); + setcopy(STRlogout, STRhangup, VAR_READWRITE); #ifdef _PATH_DOTLOGOUT (void) srcfile(_PATH_DOTLOGOUT, 0, 0, NULL); #endif @@ -1863,7 +1758,7 @@ int snum; } #endif /* POSIXJOBS */ - xexit(snum); + xexit(SIGHUP); } static Char *jobargv[2] = {STRjobs, 0}; @@ -1875,39 +1770,19 @@ static Char *jobargv[2] = {STRjobs, 0}; * and finally go through the normal error mechanism, which * gets a chance to make the shell go away. */ -int just_signaled; /* bugfix by Michael Bloom (mg@ttidca.TTI.COM) */ +int just_signaled; /* bugfix by Michael Bloom (mg@ttidca.TTI.COM) */ -RETSIGTYPE -pintr(snum) -int snum; +void +pintr(void) { - USE(snum); -#ifdef UNRELSIGS - if (snum) - (void) sigset(snum, pintr); -#endif /* UNRELSIGS */ just_signaled = 1; pintr1(1); } void -pintr1(wantnl) - int wantnl; +pintr1(int wantnl) { - Char **v; -#ifdef BSDSIGS - sigmask_t omask; -#endif - -#ifdef BSDSIGS - omask = sigblock((sigmask_t) 0); -#endif if (setintr) { -#ifdef BSDSIGS - (void) sigsetmask(omask & ~sigmask(SIGINT)); -#else - (void) sigrelse(SIGINT); -#endif if (pjobs) { pjobs = 0; xputchar('\n'); @@ -1925,13 +1800,6 @@ pintr1(wantnl) (void) Cookedmode(); GettingInput = 0; } -#ifdef BSDSIGS - (void) sigsetmask(omask & ~sigmask(SIGCHLD)); -#else - if (setintr) - (void) sighold(SIGINT); - (void) sigrelse(SIGCHLD); -#endif drainoline(); #ifdef HAVE_GETPWENT (void) endpwent(); @@ -1944,11 +1812,6 @@ pintr1(wantnl) */ if (gointr) { gotolab(gointr); - timflg = 0; - if ((v = pargv) != 0) - pargv = 0, blkfree(v); - if ((v = gargv) != 0) - gargv = 0, blkfree(v); reset(); } else if (intty && wantnl) { @@ -1985,60 +1848,30 @@ pintr1(wantnl) * Note that if catch is not set then we will unwind on any error. * If an end-of-file occurs, we return. */ -static struct command *savet = NULL; void -process(catch) - int catch; +process(int catch) { jmp_buf_t osetexit; /* PWP: This might get nuked my longjmp so don't make it a register var */ - struct command *t = savet; + size_t omark; - savet = NULL; getexit(osetexit); + omark = cleanup_push_mark(); + exitset++; for (;;) { + struct command *t; + int hadhist, old_pintr_disabled; + (void) setexit(); pendjob(); - /* This was leaking memory badly, particularly when sourcing - * files, etc.. For whatever reason we were arriving here with - * allocated pointers still active, and the code was simply - * overwriting them. I can't say I fully understand the - * control flow here, but according to Purify this particular - * leak has been plugged, and I haven't noticed any ill - * effects.. (sg) - */ - if (paraml.next && paraml.next != ¶ml) - freelex(¶ml); - - paraml.next = paraml.prev = ¶ml; - paraml.word = STRNULL; - (void) setexit(); justpr = enterhist; /* execute if not entering history */ - /* - * Interruptible during interactive reads - */ - if (setintr) -#ifdef BSDSIGS - (void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT)); -#else - (void) sigrelse(SIGINT); -#endif - - - /* - * For the sake of reset() - */ - freelex(¶ml); - if (savet) - freesyn(savet), savet = NULL; - if (haderr) { if (!catch) { /* unwind */ doneinp = 0; - savet = t; + cleanup_pop_mark(omark); resexit(osetexit); reset(); } @@ -2072,7 +1905,7 @@ process(catch) #ifndef HAVENOUTMP watch_login(0); #endif /* !HAVENOUTMP */ - sched_run(0); + sched_run(); period_cmd(); precmd(); /* @@ -2086,16 +1919,26 @@ process(catch) setalarm(1); } if (seterr) { - xfree((ptr_t) seterr); + xfree(seterr); seterr = NULL; } /* + * Interruptible during interactive reads + */ + if (setintr) + pintr_push_enable(&old_pintr_disabled); + hadhist = lex(¶ml); + if (setintr) + cleanup_until(&old_pintr_disabled); + cleanup_push(¶ml, lex_cleanup); + + /* * Echo not only on VERBOSE, but also with history expansion. If there * is a lexical error then we forego history echo. */ - if ((lex(¶ml) && !seterr && intty && !tellwhat && !Expand && - !whyles) || adrof(STRverbose)) { + if ((hadhist && !seterr && intty && !tellwhat && !Expand && !whyles) || + adrof(STRverbose)) { int odidfds = didfds; haderr = 1; didfds = 0; @@ -2105,16 +1948,7 @@ process(catch) didfds = odidfds; } (void) alarm(0); /* Autologout OFF */ - - /* - * The parser may lose space if interrupted. - */ - if (setintr) -#ifdef BSDSIGS - (void) sigblock(sigmask(SIGINT)); -#else - (void) sighold(SIGINT); -#endif + alrmcatch_disabled = 1; /* * Save input text on the history list if reading in old history, or it @@ -2140,14 +1974,14 @@ process(catch) * should go */ if (justpr) - reset(); + goto cmd_done; /* * If had a tellwhat from twenex() then do */ if (tellwhat) { (void) tellmewhat(¶ml, NULL); - reset(); + goto cmd_done; } alias(¶ml); @@ -2168,7 +2002,8 @@ process(catch) /* * Parse the words of the input into a parse tree. */ - savet = syntax(paraml.next, ¶ml, 0); + t = syntax(paraml.next, ¶ml, 0); + cleanup_push(t, syntax_cleanup); if (seterr) stderror(ERR_OLD); @@ -2177,33 +2012,32 @@ process(catch) * Execute the parse tree From: Michael Schroeder * <mlschroe@immd4.informatik.uni-erlangen.de> was execute(t, tpgrp); */ - execute(savet, (tpgrp > 0 ? tpgrp : -1), NULL, NULL, TRUE); + execute(t, (tpgrp > 0 ? tpgrp : -1), NULL, NULL, TRUE); /* * Made it! */ - freelex(¶ml); - freesyn(savet), savet = NULL; #ifdef SIG_WINDOW if (windowchg || (catch && intty && !whyles && !tellwhat)) { (void) check_window_size(0); /* for window systems */ } #endif /* SIG_WINDOW */ - set(STR_, Strsave(InputBuf), VAR_READWRITE | VAR_NOGLOB); + setcopy(STR_, InputBuf, VAR_READWRITE | VAR_NOGLOB); + cmd_done: + cleanup_until(¶ml); } - savet = t; + exitset--; + cleanup_pop_mark(omark); resexit(osetexit); } /*ARGSUSED*/ void -dosource(t, c) - Char **t; - struct command *c; +dosource(Char **t, struct command *c) { Char *f; int hflg = 0; - char buf[BUFSIZE]; + char *file; USE(c); t++; @@ -2219,19 +2053,13 @@ dosource(t, c) } f = globone(*t++, G_ERROR); - (void) strcpy(buf, short2str(f)); - xfree((ptr_t) f); - gflag = 0, tglob(t); - if (gflag) { - t = globall(t); - if (t == 0) - stderror(ERR_NAME | ERR_NOMATCH); - } else { - t = saveblk(t); - trim(t); - } - if ((!srcfile(buf, 0, hflg, t)) && (!hflg) && (!bequiet)) - stderror(ERR_SYSTEM, buf, strerror(errno)); + file = strsave(short2str(f)); + cleanup_push(file, xfree); + xfree(f); + t = glob_all_or_error(t); + if ((!srcfile(file, 0, hflg, t)) && (!hflg) && (!bequiet)) + stderror(ERR_SYSTEM, file, strerror(errno)); + cleanup_until(file); } /* @@ -2254,7 +2082,7 @@ dosource(t, c) */ static void -mailchk() +mailchk(void) { struct varent *v; Char **vp; @@ -2288,10 +2116,10 @@ mailchk() if (S_ISDIR(stb.st_mode)) { DIR *mailbox; int mailcount = 0; - char tempfilename[MAXPATHLEN]; + char *tempfilename; struct stat stc; - xsnprintf(tempfilename, MAXPATHLEN, "%s/new", filename); + tempfilename = xasprintf("%s/new", filename); if (stat(tempfilename, &stc) != -1 && S_ISDIR(stc.st_mode)) { /* @@ -2307,10 +2135,14 @@ mailchk() mboxdir = tempfilename; } - if (stb.st_mtime <= chktim + 1 || (loginsh && !new)) + if (stb.st_mtime <= chktim + 1 || (loginsh && !new)) { + xfree(tempfilename); continue; + } - if ((mailbox = opendir(mboxdir)) == NULL) + mailbox = opendir(mboxdir); + xfree(tempfilename); + if (mailbox == NULL) continue; /* skip . and .. */ @@ -2338,11 +2170,12 @@ mailchk() (loginsh && !new)) continue; type = strsave(new ? CGETS(11, 6, "new ") : ""); + cleanup_push(type, xfree); if (cnt == 1) xprintf(CGETS(11, 5, "You have %smail.\n"), type); else xprintf(CGETS(11, 7, "You have %smail in %s.\n"), type, filename); - xfree(type); + cleanup_until(type); } } chktim = t; @@ -2352,11 +2185,10 @@ mailchk() * Extract a home directory from the password file * The argument points to a buffer where the name of the * user whose home directory is sought is currently. - * We write the home directory of the user back there. + * We return home directory of the user, or NULL. */ -int -gethdir(home) - Char *home; +Char * +gethdir(const Char *home) { Char *h; @@ -2364,23 +2196,19 @@ gethdir(home) * Is it us? */ if (*home == '\0') { - if ((h = varval(STRhome)) != STRNULL) { - (void) Strcpy(home, h); - return 0; - } + if ((h = varval(STRhome)) != STRNULL) + return Strsave(h); else - return 1; + return NULL; } /* * Look in the cache */ if ((h = gettilde(home)) == NULL) - return 1; - else { - (void) Strcpy(home, h); - return 0; - } + return NULL; + else + return Strsave(h); } /* @@ -2388,7 +2216,7 @@ gethdir(home) * resting places, closing all other units. */ void -initdesc() +initdesc(void) { #ifdef NLS_BUGS #ifdef NLS_CATALOGS @@ -2417,11 +2245,10 @@ initdesc() void #ifdef PROF -done(i) +done(int i) #else -xexit(i) +xexit(int i) #endif - int i; { #ifdef TESLA if (loginsh && do_logout) { @@ -2477,13 +2304,13 @@ xexit(i) #ifndef _PATH_DEFPATH static Char ** -defaultpath() +defaultpath(void) { char *ptr; Char **blk, **blkp; struct stat stb; - blkp = blk = (Char **) xmalloc((size_t) sizeof(Char *) * 10); + blkp = blk = xmalloc(sizeof(Char *) * 10); #ifndef NODOT # ifndef DOTLAST @@ -2528,7 +2355,7 @@ defaultpath() #endif static void -record() +record(void) { if (!fast) { recdirs(NULL, adrof(STRsavedirs) != NULL); |