diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/Modules/parameter.c | 55 | ||||
-rw-r--r-- | Src/Modules/pcre.c | 2 | ||||
-rw-r--r-- | Src/Zle/compcore.c | 2 | ||||
-rw-r--r-- | Src/Zle/compctl.c | 2 | ||||
-rw-r--r-- | Src/Zle/zle_refresh.c | 3 | ||||
-rw-r--r-- | Src/builtin.c | 4 | ||||
-rw-r--r-- | Src/exec.c | 187 | ||||
-rw-r--r-- | Src/glob.c | 24 | ||||
-rw-r--r-- | Src/hashtable.c | 15 | ||||
-rw-r--r-- | Src/hist.c | 21 | ||||
-rw-r--r-- | Src/init.c | 37 | ||||
-rw-r--r-- | Src/jobs.c | 4 | ||||
-rw-r--r-- | Src/lex.c | 110 | ||||
-rw-r--r-- | Src/params.c | 39 | ||||
-rw-r--r-- | Src/parse.c | 290 | ||||
-rw-r--r-- | Src/pattern.c | 10 | ||||
-rw-r--r-- | Src/prompt.c | 38 | ||||
-rw-r--r-- | Src/signals.c | 15 | ||||
-rw-r--r-- | Src/subst.c | 15 | ||||
-rw-r--r-- | Src/utils.c | 44 | ||||
-rw-r--r-- | Src/zsh.h | 4 | ||||
-rw-r--r-- | Src/zsh.mdd | 3 | ||||
-rw-r--r-- | Src/ztype.h | 9 |
23 files changed, 689 insertions, 244 deletions
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c index 0385a709e..55157a90c 100644 --- a/Src/Modules/parameter.c +++ b/Src/Modules/parameter.c @@ -392,20 +392,36 @@ getfunction(UNUSED(HashTable ht), const char *name, int dis) ((shf->node.flags & PM_TAGGED) ? "t" : ""))); } else { char *t = getpermtext(shf->funcdef, NULL, 1), *n, *h; + char *start; + + if (shf->redir) + start = "{\n\t"; + else + start = "\t"; if (shf->funcdef->flags & EF_RUN) { n = nicedupstring(name); - h = (char *) zhalloc(strlen(t) + strlen(n) + 9); - h[0] = '\t'; - strcpy(h + 1, t); + h = (char *) zhalloc(strlen(start) + strlen(t) + strlen(n) + 8); + strcpy(h, start); + strcat(h, t); strcat(h, "\n\t"); strcat(h, n); strcat(h, " \"$@\""); } else - h = dyncat("\t", t); + h = dyncat(start, t); zsfree(t); + /* + * TBD: Is this unmetafy correct? Surely as this + * is a parameter value it stays metafied? + */ unmetafy(h, NULL); + if (shf->redir) { + t = getpermtext(shf->redir, NULL, 1); + h = zhtricat(h, "\n}", t); + zsfree(t); + } + pm->u.str = h; } } else { @@ -456,21 +472,38 @@ scanfunctions(UNUSED(HashTable ht), ScanFunc func, int flags, int dis) ((shf->node.flags & PM_TAGGED) ? "Ut" : "U") : ((shf->node.flags & PM_TAGGED) ? "t" : ""))); } else { - char *t = getpermtext(((Shfunc) hn)->funcdef, NULL, 1); - char *n; + Shfunc shf = (Shfunc)hn; + char *t = getpermtext(shf->funcdef, NULL, 1); + char *n, *start; - if (((Shfunc) hn)->funcdef->flags & EF_RUN) { + if (shf->redir) + start = "{\n\t"; + else + start = "\t"; + + if (shf->funcdef->flags & EF_RUN) { n = nicedupstring(hn->nam); - pm.u.str = (char *) zhalloc(strlen(t) + strlen(n) + 9); - pm.u.str[0] = '\t'; - strcpy(pm.u.str + 1, t); + pm.u.str = (char *) zhalloc( + strlen(start) + strlen(t) + strlen(n) + 8); + strcpy(pm.u.str, start); + strcat(pm.u.str, t); strcat(pm.u.str, "\n\t"); strcat(pm.u.str, n); strcat(pm.u.str, " \"$@\""); } else - pm.u.str = dyncat("\t", t); + pm.u.str = dyncat(start, t); + /* + * TBD: Is this unmetafy correct? Surely as this + * is a parameter value it stays metafied? + */ unmetafy(pm.u.str, NULL); zsfree(t); + + if (shf->redir) { + t = getpermtext(shf->redir, NULL, 1); + pm.u.str = zhtricat(pm.u.str, "\n}", t); + zsfree(t); + } } } func(&pm.node, flags); diff --git a/Src/Modules/pcre.c b/Src/Modules/pcre.c index 040a33f8e..2393cd1e7 100644 --- a/Src/Modules/pcre.c +++ b/Src/Modules/pcre.c @@ -289,7 +289,7 @@ bin_pcre_match(char *nam, char **args, Options ops, UNUSED(int func)) matched_portion = OPT_ARG(ops,c); } if(OPT_HASARG(ops,c='n')) { /* The offset position to start the search, in bytes. */ - if ((offset_start = getposint(OPT_ARG(ops,c), nam) < 0)) + if ((offset_start = getposint(OPT_ARG(ops,c), nam)) < 0) return 1; } /* For the entire match, 'Return' the offset byte positions instead of the matched string */ diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index ac7785ab7..35d410cc6 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -702,6 +702,7 @@ callcompfunc(char *s, char *fn) } zsfree(compprefix); zsfree(compsuffix); + makebangspecial(0); if (unset(COMPLETEINWORD)) { tmp = (linwhat == IN_MATH ? dupstring(s) : multiquote(s, 0)); untokenize(tmp); @@ -722,6 +723,7 @@ callcompfunc(char *s, char *fn) untokenize(ss); compsuffix = ztrdup(ss); } + makebangspecial(1); zsfree(complastprefix); zsfree(complastsuffix); complastprefix = ztrdup(compprefix); diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index 52b9e9c82..0b7a32445 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -3416,7 +3416,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) *npp++ = tp; pp++; } - *npp = '\0'; + *npp = NULL; } } if (!dirs) { diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index 80be27f03..684ac13a2 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -258,7 +258,6 @@ static const REFRESH_ELEMENT zr_cr = { ZWC('\r'), 0 }; static const REFRESH_ELEMENT zr_dt = { ZWC('.'), 0 }; static const REFRESH_ELEMENT zr_nl = { ZWC('\n'), 0 }; static const REFRESH_ELEMENT zr_sp = { ZWC(' '), 0 }; -static const REFRESH_ELEMENT zr_ht = { ZWC('\t'), 0 }; static const REFRESH_ELEMENT zr_zr = { ZWC('\0'), 0 }; /* @@ -429,7 +428,7 @@ get_region_highlight(UNUSED(Param pm)) digbuf1, digbuf2); (void)output_highlight(rhp->atr, *arrp + strlen(*arrp)); } - *arrp = '\0'; + *arrp = NULL; return retarr; } diff --git a/Src/builtin.c b/Src/builtin.c index a2a3ad748..4a10c7dd1 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -2759,7 +2759,7 @@ bin_functions(char *name, char **argv, Options ops, int func) tokenize(*argv); if ((pprog = patcompile(*argv, PAT_STATIC, 0))) { queue_signals(); - for (p = mathfuncs, q = NULL; p; q = p, p = p->next) { + for (p = mathfuncs, q = NULL; p; q = p) { MathFunc next; do { next = NULL; @@ -2774,6 +2774,8 @@ bin_functions(char *name, char **argv, Options ops, int func) } /* if we deleted one, retry with the new p */ } while (next); + if (p) + p = p->next; } unqueue_signals(); } else { diff --git a/Src/exec.c b/Src/exec.c index 5ad957f98..d0fadd69a 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -198,7 +198,8 @@ static char *blank_env[] = { NULL }; /* Execution functions. */ static int (*execfuncs[WC_COUNT-WC_CURSH]) _((Estate, int)) = { - execcursh, exectime, execfuncdef, execfor, execselect, + execcursh, exectime, NULL /* execfuncdef handled specially */, + execfor, execselect, execwhile, execrepeat, execcase, execif, execcond, execarith, execautofn, exectry }; @@ -1005,6 +1006,8 @@ entersubsh(int flags) signal_default(SIGTERM); if (!(sigtrapped[SIGINT] & ZSIG_IGNORED)) signal_default(SIGINT); + if (!(sigtrapped[SIGPIPE])) + signal_default(SIGPIPE); } if (!(sigtrapped[SIGQUIT] & ZSIG_IGNORED)) signal_default(SIGQUIT); @@ -1116,8 +1119,11 @@ execsimple(Estate state) fflush(xtrerr); } lv = (errflag ? errflag : cmdoutval); - } else + } else if (code == WC_FUNCDEF) { + lv = execfuncdef(state, NULL); + } else { lv = (execfuncs[code - WC_CURSH])(state, 0); + } thisjob = otj; @@ -2783,6 +2789,58 @@ execcmd(Estate state, int input, int output, int how, int last1) errflag = 1; } + if (type == WC_FUNCDEF) { + /* + * The first word of a function definition is a list of + * names. If this is empty, we're doing an anonymous function: + * in that case redirections are handled normally. + * If not, it's a function definition: then we don't do + * redirections here but pass in the list of redirections to + * be stored for recall with the function. + */ + if (*state->pc != 0) { + /* Nonymous, don't do redirections here */ + redir = NULL; + } + } else if (is_shfunc || type == WC_AUTOFN) { + Shfunc shf; + if (is_shfunc) + shf = (Shfunc)hn; + else { + shf = loadautofn(state->prog->shf, 1, 0); + if (shf) + state->prog->shf = shf; + else { + /* + * This doesn't set errflag, so just return now. + */ + lastval = 1; + if (oautocont >= 0) + opts[AUTOCONTINUE] = oautocont; + return; + } + } + /* + * A function definition may have a list of additional + * redirections to apply, so retrieve it. + */ + if (shf->redir) { + struct estate s; + LinkList redir2; + + s.prog = shf->redir; + s.pc = shf->redir->prog; + s.strs = shf->redir->strs; + redir2 = ecgetredirs(&s); + if (!redir) + redir = redir2; + else { + while (nonempty(redir2)) + addlinknode(redir, ugetnode(redir2)); + } + } + } + if (errflag) { lastval = 1; if (oautocont >= 0) @@ -3050,7 +3108,7 @@ execcmd(Estate state, int input, int output, int how, int last1) break; case REDIR_CLOSE: if (fn->varid) { - char *s = fn->varid; + char *s = fn->varid, *t; struct value vbuf; Value v; int bad = 0; @@ -3060,13 +3118,25 @@ execcmd(Estate state, int input, int output, int how, int last1) } else if (v->pm->node.flags & PM_READONLY) { bad = 2; } else { - fn->fd1 = (int)getintvalue(v); + s = getstrvalue(v); if (errflag) bad = 1; - else if (fn->fd1 <= max_zsh_fd) { - if (fn->fd1 >= 10 && - fdtable[fn->fd1] == FDT_INTERNAL) - bad = 3; + else { + fn->fd1 = zstrtol(s, &t, 0); + if (s == t) + bad = 1; + else if (*t) { + /* Check for base#number format */ + if (*t == '#' && *s != '0') + fn->fd1 = zstrtol(s = t+1, &t, fn->fd1); + if (s == t || *t) + bad = 1; + } + if (!bad && fn->fd1 <= max_zsh_fd) { + if (fn->fd1 >= 10 && + fdtable[fn->fd1] == FDT_INTERNAL) + bad = 3; + } } } if (bad) { @@ -3131,7 +3201,7 @@ execcmd(Estate state, int input, int output, int how, int last1) fil = movefd(dup(fd)); } if (fil == -1) { - char fdstr[4]; + char fdstr[DIGBUFSIZE]; closemnodes(mfds); fixfds(save); @@ -3226,10 +3296,44 @@ execcmd(Estate state, int input, int output, int how, int last1) flags |= ESUB_REVERTPGRP; entersubsh(flags); } - if (type >= WC_CURSH) { + if (type == WC_FUNCDEF) { + Eprog redir_prog; + if (!redir && wc_code(*beg) == WC_REDIR) { + /* + * We're not using a redirection from the currently + * parsed environment, which is what we'd do for an + * anonymous function, but there are redirections we + * should store with the new function. + */ + struct estate s; + + s.prog = state->prog; + s.pc = beg; + s.strs = state->prog->strs; + + /* + * The copy uses the wordcode parsing area, so save and + * restore state. + */ + lexsave(); + redir_prog = eccopyredirs(&s); + lexrestore(); + } else + redir_prog = NULL; + + lastval = execfuncdef(state, redir_prog); + } + else if (type >= WC_CURSH) { if (last1 == 1) do_exec = 1; - lastval = (execfuncs[type - WC_CURSH])(state, do_exec); + if (type == WC_AUTOFN) { + /* + * We pre-loaded this to get any redirs. + * So we execuate a simplified function here. + */ + lastval = execautofn_basic(state, do_exec); + } else + lastval = (execfuncs[type - WC_CURSH])(state, do_exec); } else if (is_builtin || is_shfunc) { LinkList restorelist = 0, removelist = 0; /* builtin or shell function */ @@ -3569,8 +3673,11 @@ closem(int how) for (i = 10; i <= max_zsh_fd; i++) if (fdtable[i] != FDT_UNUSED && - (how == FDT_UNUSED || fdtable[i] == how)) + (how == FDT_UNUSED || fdtable[i] == how)) { + if (i == SHTTY) + SHTTY = -1; zclose(i); + } } /* convert here document into a here string */ @@ -4220,11 +4327,12 @@ exectime(Estate state, UNUSED(int do_exec)) /**/ static int -execfuncdef(Estate state, UNUSED(int do_exec)) +execfuncdef(Estate state, Eprog redir_prog) { Shfunc shf; char *s = NULL; int signum, nprg, sbeg, nstrs, npats, len, plen, i, htok = 0, ret = 0; + int nfunc = 0; Wordcode beg = state->pc, end; Eprog prog; Patprog *pp; @@ -4249,6 +4357,8 @@ execfuncdef(Estate state, UNUSED(int do_exec)) } } + DPUTS(!names && redir_prog, + "Passing redirection to anon function definition."); while (!names || (s = (char *) ugetnode(names))) { if (!names) { prog = (Eprog) zhalloc(sizeof(*prog)); @@ -4290,6 +4400,15 @@ execfuncdef(Estate state, UNUSED(int do_exec)) shf->node.flags = 0; shf->filename = ztrdup(scriptfilename); shf->lineno = lineno; + /* + * redir_prog is permanently allocated --- but if + * this function has multiple names we need an additional + * one. + */ + if (nfunc++ && redir_prog) + shf->redir = dupeprog(redir_prog, 0); + else + shf->redir = redir_prog; shfunc_set_sticky(shf); if (!names) { @@ -4320,6 +4439,8 @@ execfuncdef(Estate state, UNUSED(int do_exec)) ret = lastval; freeeprog(shf->funcdef); + if (shf->redir) /* shouldn't be */ + freeeprog(shf->redir); zsfree(shf->filename); zfree(shf, sizeof(*shf)); break; @@ -4343,6 +4464,10 @@ execfuncdef(Estate state, UNUSED(int do_exec)) shfunctab->addnode(shfunctab, ztrdup(s), shf); } } + if (!nfunc && redir_prog) { + /* For completeness, shouldn't happen */ + freeeprog(redir_prog); + } state->pc = end; return ret; } @@ -4439,21 +4564,28 @@ execshfunc(Shfunc shf, LinkList args) deletefilelist(last_file_list, 0); } -/* Function to execute the special type of command that represents an * - * autoloaded shell function. The command structure tells us which * - * function it is. This function is actually called as part of the * - * execution of the autoloaded function itself, so when the function * - * has been autoloaded, its list is just run with no frills. */ +/* + * Function to execute the special type of command that represents an + * autoloaded shell function. The command structure tells us which + * function it is. This function is actually called as part of the + * execution of the autoloaded function itself, so when the function + * has been autoloaded, its list is just run with no frills. + * + * There are two cases because if we are doing all-singing, all-dancing + * non-simple code we load the shell function early in execcmd() (the + * action also present in the non-basic version) to check if + * there are redirections that need to be handled at that point. + * Then we call execautofn_basic() to do the rest. + */ /**/ static int -execautofn(Estate state, UNUSED(int do_exec)) +execautofn_basic(Estate state, UNUSED(int do_exec)) { Shfunc shf; char *oldscriptname, *oldscriptfilename; - if (!(shf = loadautofn(state->prog->shf, 1, 0))) - return 1; + shf = state->prog->shf; /* * Probably we didn't know the filename where this function was @@ -4473,6 +4605,19 @@ execautofn(Estate state, UNUSED(int do_exec)) } /**/ +static int +execautofn(Estate state, UNUSED(int do_exec)) +{ + Shfunc shf; + + if (!(shf = loadautofn(state->prog->shf, 1, 0))) + return 1; + + state->prog->shf = shf; + return execautofn_basic(state, 0); +} + +/**/ Shfunc loadautofn(Shfunc shf, int fksh, int autol) { diff --git a/Src/glob.c b/Src/glob.c index cb853870a..ca7bc4410 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -178,7 +178,7 @@ struct globdata { int gd_gf_numsort; int gd_gf_follow, gd_gf_sorts, gd_gf_nsorts; struct globsort gd_gf_sortlist[MAX_SORTS]; - LinkList gd_gf_pre_words; + LinkList gd_gf_pre_words, gd_gf_post_words; char *gd_glob_pre, *gd_glob_suf; }; @@ -210,6 +210,7 @@ static struct globdata curglobdata; #define gf_nsorts (curglobdata.gd_gf_nsorts) #define gf_sortlist (curglobdata.gd_gf_sortlist) #define gf_pre_words (curglobdata.gd_gf_pre_words) +#define gf_post_words (curglobdata.gd_gf_post_words) /* and macros for save/restore */ @@ -899,6 +900,9 @@ gmatchcmp(Gmatch a, Gmatch b) /* Count slashes. Trailing slashes don't count. */ while (*aptr && *aptr == *bptr) aptr++, bptr++; + /* Like I just said... */ + if ((!*aptr || !*bptr) && aptr > a->name && aptr[-1] == '/') + aptr--, bptr--; if (*aptr) for (; aptr[1]; aptr++) if (*aptr == '/') { @@ -1074,7 +1078,14 @@ insert_glob_match(LinkList list, LinkNode next, char *data) } } - insertlinknode(list, next, data); + next = insertlinknode(list, next, data); + + if (gf_post_words) { + LinkNode added; + for (added = firstnode(gf_post_words); added; incnode(added)) { + next = insertlinknode(list, next, dupstring(getdata(added))); + } + } } /* @@ -1190,7 +1201,7 @@ zglob(LinkList list, LinkNode np, int nountok) gf_noglobdots = unset(GLOBDOTS); gf_numsort = isset(NUMERICGLOBSORT); gf_sorts = gf_nsorts = 0; - gf_pre_words = NULL; + gf_pre_words = gf_post_words = NULL; /* Check for qualifiers */ while (!nobareglob || @@ -1679,9 +1690,10 @@ zglob(LinkList list, LinkNode np, int nountok) if (tt != NULL) { - if (!gf_pre_words) - gf_pre_words = newlinklist(); - addlinknode(gf_pre_words, tt); + LinkList *words = sense & 1 ? &gf_post_words : &gf_pre_words; + if (!*words) + *words = newlinklist(); + addlinknode(*words, tt); } break; } diff --git a/Src/hashtable.c b/Src/hashtable.c index ef187927b..7a430629d 100644 --- a/Src/hashtable.c +++ b/Src/hashtable.c @@ -887,6 +887,8 @@ freeshfuncnode(HashNode hn) zsfree(shf->node.nam); if (shf->funcdef) freeeprog(shf->funcdef); + if (shf->redir) + freeeprog(shf->redir); zsfree(shf->filename); if (shf->sticky) { if (shf->sticky->n_on_opts) @@ -954,10 +956,19 @@ printshfuncnode(HashNode hn, int printflags) printf(" \"$@\""); } } - printf("\n}\n"); + printf("\n}"); } else { - printf(" () { }\n"); + printf(" () { }"); } + if (f->redir) { + t = getpermtext(f->redir, NULL, 1); + if (t) { + zputs(t, stdout); + zsfree(t); + } + } + + putchar('\n'); } /**************************************/ diff --git a/Src/hist.c b/Src/hist.c index 770d559b1..4660fd073 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -2490,6 +2490,9 @@ flockhistfile(char *fn, int keep_trying) struct flock lck; int ctr = keep_trying ? 9 : 0; + if (flock_fd >= 0) + return 0; /* already locked */ + if ((flock_fd = open(unmeta(fn), O_RDWR | O_NOCTTY)) < 0) return errno == ENOENT ? 0 : 2; /* "successfully" locked missing file */ @@ -2590,7 +2593,12 @@ savehistfile(char *fn, int err, int writeflags) out = NULL; } else { int fd = open(tmpfile, O_CREAT | O_WRONLY | O_EXCL, 0600); - out = fd >= 0 ? fdopen(fd, "w") : NULL; + if (fd >=0) { + out = fdopen(fd, "w"); + if (!out) + close(fd); + } else + out = NULL; } #ifdef HAVE_FCHMOD @@ -2768,12 +2776,6 @@ lockhistfile(char *fn, int keep_trying) if (!fn && !(fn = getsparam("HISTFILE"))) return 1; -#ifdef HAVE_FCNTL_H - if (isset(HISTFCNTLLOCK) && flock_fd < 0) { - return flockhistfile(fn, keep_trying); - } -#endif - if (!lockhistct++) { struct stat sb; int fd; @@ -2786,6 +2788,11 @@ lockhistfile(char *fn, int keep_trying) # endif #endif +#ifdef HAVE_FCNTL_H + if (isset(HISTFCNTLLOCK)) + return flockhistfile(fn, keep_trying); +#endif + lockfile = bicat(unmeta(fn), ".LOCK"); /* NOTE: only use symlink locking on a link()-having host in order to * avoid a change from open()-based locking to symlink()-based. */ diff --git a/Src/init.c b/Src/init.c index 5e92f59df..6d005dce7 100644 --- a/Src/init.c +++ b/Src/init.c @@ -252,8 +252,9 @@ parseargs(char **argv, char **runscript) paramlist = znewlinklist(); if (*argv) { if (unset(SHINSTDIN)) { + posixzero = *argv; if (cmd) - argzero = posixzero = *argv; + argzero = *argv; else *runscript = *argv; opts[INTERACTIVE] &= 1; @@ -769,7 +770,8 @@ setupvals(void) struct timezone dummy_tz; char *ptr; int i, j; -#if defined(SITEFPATH_DIR) || defined(FPATH_DIR) || defined (ADDITIONAL_FPATH) +#if defined(SITEFPATH_DIR) || defined(FPATH_DIR) || defined (ADDITIONAL_FPATH) || defined(FIXED_FPATH_DIR) +#define FPATH_NEEDS_INIT 1 char **fpathptr; # if defined(FPATH_DIR) && defined(FPATH_SUBDIRS) char *fpath_subdirs[] = FPATH_SUBDIRS; @@ -778,11 +780,17 @@ setupvals(void) char *more_fndirs[] = ADDITIONAL_FPATH; int more_fndirs_len; # endif +# ifdef FIXED_FPATH_DIR +# define FIXED_FPATH_LEN 1 +# else +# define FIXED_FPATH_LEN 0 +# endif # ifdef SITEFPATH_DIR - int fpathlen = 1; +# define SITE_FPATH_LEN 1 # else - int fpathlen = 0; +# define SITE_FPATH_LEN 0 # endif + int fpathlen = FIXED_FPATH_LEN + SITE_FPATH_LEN; #endif int close_fds[10], tmppipe[2]; @@ -861,23 +869,27 @@ setupvals(void) manpath = mkarray(NULL); fignore = mkarray(NULL); -#if defined(SITEFPATH_DIR) || defined(FPATH_DIR) || defined(ADDITIONAL_FPATH) +#ifdef FPATH_NEEDS_INIT # ifdef FPATH_DIR # ifdef FPATH_SUBDIRS fpathlen += sizeof(fpath_subdirs)/sizeof(char *); -# else +# else /* FPATH_SUBDIRS */ fpathlen++; -# endif -# endif +# endif /* FPATH_SUBDIRS */ +# endif /* FPATH_DIR */ # if defined(ADDITIONAL_FPATH) more_fndirs_len = sizeof(more_fndirs)/sizeof(char *); fpathlen += more_fndirs_len; -# endif +# endif /* ADDITONAL_FPATH */ fpath = fpathptr = (char **)zalloc((fpathlen+1)*sizeof(char *)); +# ifdef FIXED_FPATH_DIR + *fpathptr++ = ztrdup(FIXED_FPATH_DIR); + fpathlen--; +# endif # ifdef SITEFPATH_DIR *fpathptr++ = ztrdup(SITEFPATH_DIR); fpathlen--; -# endif +# endif /* SITEFPATH_DIR */ # if defined(ADDITIONAL_FPATH) for (j = 0; j < more_fndirs_len; j++) *fpathptr++ = ztrdup(more_fndirs[j]); @@ -896,9 +908,9 @@ setupvals(void) # endif # endif *fpathptr = NULL; -#else +#else /* FPATH_NEEDS_INIT */ fpath = mkarray(NULL); -#endif +#endif /* FPATH_NEEDS_INIT */ mailpath = mkarray(NULL); watch = mkarray(NULL); @@ -1122,6 +1134,7 @@ init_signals(void) winch_block(); /* See utils.c:preprompt() */ #endif if (interact) { + install_handler(SIGPIPE); install_handler(SIGALRM); signal_ignore(SIGTERM); } diff --git a/Src/jobs.c b/Src/jobs.c index 83a4d96a4..bd95afb7a 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -1627,8 +1627,10 @@ spawnjob(void) } if (!hasprocs(thisjob)) deletejob(jobtab + thisjob, 0); - else + else { jobtab[thisjob].stat |= STAT_LOCKED; + pipecleanfilelist(jobtab[thisjob].filelist); + } thisjob = -1; } @@ -325,66 +325,70 @@ lexsave(void) mod_export void lexrestore(void) { - struct lexstack *ln; + struct lexstack *ln = lstack; DPUTS(!lstack, "BUG: lexrestore() without lexsave()"); - incmdpos = lstack->incmdpos; - incond = lstack->incond; - incasepat = lstack->incasepat; - dbparens = lstack->dbparens; - isfirstln = lstack->isfirstln; - isfirstch = lstack->isfirstch; - histactive = lstack->histactive; - histdone = lstack->histdone; - lexflags = lstack->lexflags; - stophist = lstack->stophist; - chline = lstack->hline; - hptr = lstack->hptr; + + queue_signals(); + lstack = lstack->next; + + if (!lstack) { + /* Back to top level: don't need special ZLE value */ + DPUTS(ln->hline != zle_chline, "BUG: Ouch, wrong chline for ZLE"); + zle_chline = NULL; + } + + incmdpos = ln->incmdpos; + incond = ln->incond; + incasepat = ln->incasepat; + dbparens = ln->dbparens; + isfirstln = ln->isfirstln; + isfirstch = ln->isfirstch; + histactive = ln->histactive; + histdone = ln->histdone; + lexflags = ln->lexflags; + stophist = ln->stophist; + chline = ln->hline; + hptr = ln->hptr; if (cmdstack) - free(cmdstack); - cmdstack = lstack->cstack; - cmdsp = lstack->csp; - tok = lstack->tok; - isnewlin = lstack->isnewlin; - tokstr = lstack->tokstr; - zshlextext = lstack->zshlextext; - bptr = lstack->bptr; - bsiz = lstack->bsiz; - len = lstack->len; - chwords = lstack->chwords; - chwordlen = lstack->chwordlen; - chwordpos = lstack->chwordpos; - hwgetword = lstack->hwgetword; - lexstop = lstack->lexstop; - hdocs = lstack->hdocs; - hgetc = lstack->hgetc; - hungetc = lstack->hungetc; - hwaddc = lstack->hwaddc; - hwbegin = lstack->hwbegin; - hwend = lstack->hwend; - addtoline = lstack->addtoline; + zfree(cmdstack, CMDSTACKSZ); + cmdstack = ln->cstack; + cmdsp = ln->csp; + tok = ln->tok; + isnewlin = ln->isnewlin; + tokstr = ln->tokstr; + zshlextext = ln->zshlextext; + bptr = ln->bptr; + bsiz = ln->bsiz; + len = ln->len; + chwords = ln->chwords; + chwordlen = ln->chwordlen; + chwordpos = ln->chwordpos; + hwgetword = ln->hwgetword; + lexstop = ln->lexstop; + hdocs = ln->hdocs; + hgetc = ln->hgetc; + hungetc = ln->hungetc; + hwaddc = ln->hwaddc; + hwbegin = ln->hwbegin; + hwend = ln->hwend; + addtoline = ln->addtoline; if (ecbuf) zfree(ecbuf, eclen); - eclen = lstack->eclen; - ecused = lstack->ecused; - ecnpats = lstack->ecnpats; - ecbuf = lstack->ecbuf; - ecstrs = lstack->ecstrs; - ecsoffs = lstack->ecsoffs; - ecssub = lstack->ecssub; - ecnfunc = lstack->ecnfunc; - hlinesz = lstack->hlinesz; - toklineno = lstack->toklineno; + eclen = ln->eclen; + ecused = ln->ecused; + ecnpats = ln->ecnpats; + ecbuf = ln->ecbuf; + ecstrs = ln->ecstrs; + ecsoffs = ln->ecsoffs; + ecssub = ln->ecssub; + ecnfunc = ln->ecnfunc; + hlinesz = ln->hlinesz; + toklineno = ln->toklineno; errflag = 0; + free(ln); - ln = lstack->next; - if (!ln) { - /* Back to top level: don't need special ZLE value */ - DPUTS(chline != zle_chline, "BUG: Ouch, wrong chline for ZLE"); - zle_chline = NULL; - } - free(lstack); - lstack = ln; + unqueue_signals(); } /**/ diff --git a/Src/params.c b/Src/params.c index 0699ead85..61edc5d08 100644 --- a/Src/params.c +++ b/Src/params.c @@ -46,7 +46,7 @@ /**/ mod_export int locallevel; - + /* Variables holding values of special parameters */ /**/ @@ -325,9 +325,12 @@ IPDEF4("ZSH_SUBSHELL", &zsh_subshell), IPDEF5("COLUMNS", &zterm_columns, zlevar_gsu), IPDEF5("LINES", &zterm_lines, zlevar_gsu), IPDEF5U("ZLE_RPROMPT_INDENT", &rprompt_indent, zlevar_gsu), -IPDEF5("OPTIND", &zoptind, varinteger_gsu), IPDEF5("SHLVL", &shlvl, varinteger_gsu), -IPDEF5("TRY_BLOCK_ERROR", &try_errflag, varinteger_gsu), + +/* Don't import internal integer status variables. */ +#define IPDEF6(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL|PM_DONTIMPORT},BR((void *)B),GSU(F),10,0,NULL,NULL,NULL,0} +IPDEF6("OPTIND", &zoptind, varinteger_gsu), +IPDEF6("TRY_BLOCK_ERROR", &try_errflag, varinteger_gsu), #define IPDEF7(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL},BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0} #define IPDEF7U(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL|PM_UNSET},BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0} @@ -742,7 +745,8 @@ createparamtable(void) if (!idigit(*iname) && isident(iname) && !strchr(iname, '[')) { if ((!(pm = (Param) paramtab->getnode(paramtab, iname)) || !(pm->node.flags & PM_DONTIMPORT || pm->node.flags & PM_EXPORTED)) && - (pm = setsparam(iname, metafy(ivalue, -1, META_DUP)))) { + (pm = assignsparam(iname, metafy(ivalue, -1, META_DUP), + ASSPM_ENV_IMPORT))) { pm->node.flags |= PM_EXPORTED; if (pm->node.flags & PM_SPECIAL) pm->env = mkenvstr (pm->node.nam, @@ -2271,6 +2275,13 @@ export_param(Param pm) mod_export void setstrvalue(Value v, char *val) { + assignstrvalue(v, val, 0); +} + +/**/ +mod_export void +assignstrvalue(Value v, char *val, int flags) +{ if (unset(EXECOPT)) return; if (v->pm->node.flags & PM_READONLY) { @@ -2347,7 +2358,13 @@ setstrvalue(Value v, char *val) break; case PM_INTEGER: if (val) { - v->pm->gsu.i->setfn(v->pm, mathevali(val)); + zlong ival; + if (flags & ASSPM_ENV_IMPORT) { + char *ptr; + ival = zstrtol_underscore(val, &ptr, 0, 1); + } else + ival = mathevali(val); + v->pm->gsu.i->setfn(v->pm, ival); if ((v->pm->node.flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) && !v->pm->width) v->pm->width = strlen(val); @@ -2359,7 +2376,13 @@ setstrvalue(Value v, char *val) case PM_EFLOAT: case PM_FFLOAT: if (val) { - mnumber mn = matheval(val); + mnumber mn; + if (flags & ASSPM_ENV_IMPORT) { + char *ptr; + mn.type = MN_FLOAT; + mn.u.d = strtod(val, &ptr); + } else + mn = matheval(val); v->pm->gsu.f->setfn(v->pm, (mn.type & MN_FLOAT) ? mn.u.d : (double)mn.u.l); if ((v->pm->node.flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) && @@ -2742,8 +2765,8 @@ assignsparam(char *s, char *val, int flags) } } } - - setstrvalue(v, val); + + assignstrvalue(v, val, flags); unqueue_signals(); return v->pm; } diff --git a/Src/parse.c b/Src/parse.c index 5f1303f1c..433efb94e 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -202,7 +202,7 @@ struct heredocs *hdocs; * sublists is that they can be executed faster, see exec.c. In the * parser, the test if a list can be simplified is done quite simply * by passing a int* around which gets set to non-zero if the thing - * just parsed is `complex', i.e. may need to be run by forking or + * just parsed is `cmplx', i.e. may need to be run by forking or * some such. * * In each of the above, strings are encoded as one word code. For empty @@ -375,6 +375,8 @@ init_parse(void) /* Build eprog. */ +/* careful: copy_ecstr is from arg1 to arg2, unlike memcpy */ + static void copy_ecstr(Eccstr s, char *p) { @@ -386,24 +388,25 @@ copy_ecstr(Eccstr s, char *p) } static Eprog -bld_eprog(void) +bld_eprog(int heap) { Eprog ret; int l; ecadd(WCB_END()); - ret = (Eprog) zhalloc(sizeof(*ret)); + ret = heap ? (Eprog) zhalloc(sizeof(*ret)) : (Eprog) zalloc(sizeof(*ret)); ret->len = ((ecnpats * sizeof(Patprog)) + (ecused * sizeof(wordcode)) + ecsoffs); ret->npats = ecnpats; - ret->nref = -1; /* Eprog is on the heap */ - ret->pats = (Patprog *) zhalloc(ret->len); + ret->nref = heap ? -1 : 1; + ret->pats = heap ? (Patprog *) zhalloc(ret->len) : + (Patprog *) zshcalloc(ret->len); ret->prog = (Wordcode) (ret->pats + ecnpats); ret->strs = (char *) (ret->prog + ecused); ret->shf = NULL; - ret->flags = EF_HEAP; + ret->flags = heap ? EF_HEAP : EF_REAL; ret->dump = NULL; for (l = 0; l < ecnpats; l++) ret->pats[l] = dummy_patprog1; @@ -455,7 +458,7 @@ parse_event(void) clear_hdocs(); return NULL; } - return bld_eprog(); + return bld_eprog(1); } /**/ @@ -534,7 +537,7 @@ parse_list(void) yyerror(0); return NULL; } - return bld_eprog(); + return bld_eprog(1); } /* @@ -553,7 +556,7 @@ parse_cond(void) clear_hdocs(); return NULL; } - return bld_eprog(); + return bld_eprog(1); } /* This adds a list wordcode. The important bit about this is that it also @@ -561,9 +564,9 @@ parse_cond(void) /**/ static void -set_list_code(int p, int type, int complex) +set_list_code(int p, int type, int cmplx) { - if (!complex && (type == Z_SYNC || type == (Z_SYNC | Z_END)) && + if (!cmplx && (type == Z_SYNC || type == (Z_SYNC | Z_END)) && WC_SUBLIST_TYPE(ecbuf[p + 1]) == WC_SUBLIST_END) { int ispipe = !(WC_SUBLIST_FLAGS(ecbuf[p + 1]) & WC_SUBLIST_SIMPLE); ecbuf[p] = WCB_LIST((type | Z_SIMPLE), ecused - 2 - p); @@ -578,9 +581,9 @@ set_list_code(int p, int type, int complex) /**/ static void -set_sublist_code(int p, int type, int flags, int skip, int complex) +set_sublist_code(int p, int type, int flags, int skip, int cmplx) { - if (complex) + if (cmplx) ecbuf[p] = WCB_SUBLIST(type, flags, skip); else { ecbuf[p] = WCB_SUBLIST(type, (flags | WC_SUBLIST_SIMPLE), skip); @@ -594,7 +597,7 @@ set_sublist_code(int p, int type, int flags, int skip, int complex) /**/ static int -par_list(int *complex) +par_list(int *cmplx) { int p, lp = -1, c; @@ -607,10 +610,10 @@ par_list(int *complex) c = 0; if (par_sublist(&c)) { - *complex |= c; + *cmplx |= c; if (tok == SEPER || tok == AMPER || tok == AMPERBANG) { if (tok != SEPER) - *complex = 1; + *cmplx = 1; set_list_code(p, ((tok == SEPER) ? Z_SYNC : (tok == AMPER) ? Z_ASYNC : (Z_ASYNC | Z_DISOWN)), c); @@ -635,13 +638,13 @@ par_list(int *complex) /**/ static int -par_list1(int *complex) +par_list1(int *cmplx) { int p = ecadd(0), c = 0; if (par_sublist(&c)) { set_list_code(p, (Z_SYNC | Z_END), c); - *complex |= c; + *cmplx |= c; return 1; } else { ecused--; @@ -655,7 +658,7 @@ par_list1(int *complex) /**/ static int -par_sublist(int *complex) +par_sublist(int *cmplx) { int f, p, c = 0; @@ -664,7 +667,7 @@ par_sublist(int *complex) if ((f = par_sublist2(&c)) != -1) { int e = ecused; - *complex |= c; + *cmplx |= c; if (tok == DBAR || tok == DAMPER) { enum lextok qtok = tok; int sl; @@ -673,7 +676,7 @@ par_sublist(int *complex) zshlex(); while (tok == SEPER) zshlex(); - sl = par_sublist(complex); + sl = par_sublist(cmplx); set_sublist_code(p, (sl ? (qtok == DBAR ? WC_SUBLIST_OR : WC_SUBLIST_AND) : WC_SUBLIST_END), @@ -694,20 +697,20 @@ par_sublist(int *complex) /**/ static int -par_sublist2(int *complex) +par_sublist2(int *cmplx) { int f = 0; if (tok == COPROC) { - *complex = 1; + *cmplx = 1; f |= WC_SUBLIST_COPROC; zshlex(); } else if (tok == BANG) { - *complex = 1; + *cmplx = 1; f |= WC_SUBLIST_NOT; zshlex(); } - if (!par_pline(complex) && !f) + if (!par_pline(cmplx) && !f) return -1; return f; @@ -719,19 +722,19 @@ par_sublist2(int *complex) /**/ static int -par_pline(int *complex) +par_pline(int *cmplx) { int p; zlong line = toklineno; p = ecadd(0); - if (!par_cmd(complex)) { + if (!par_cmd(cmplx, 0)) { ecused--; return 0; } if (tok == BAR) { - *complex = 1; + *cmplx = 1; cmdpush(CS_PIPE); zshlex(); while (tok == SEPER) @@ -739,7 +742,7 @@ par_pline(int *complex) ecbuf[p] = WCB_PIPE(WC_PIPE_MID, (line >= 0 ? line + 1 : 0)); ecispace(p + 1, 1); ecbuf[p + 1] = ecused - 1 - p; - if (!par_pline(complex)) { + if (!par_pline(cmplx)) { tok = LEXERR; } cmdpop(); @@ -755,7 +758,7 @@ par_pline(int *complex) ecbuf[r + 1] = 2; ecbuf[r + 2] = ecstrcode("1"); - *complex = 1; + *cmplx = 1; cmdpush(CS_ERRPIPE); zshlex(); while (tok == SEPER) @@ -763,7 +766,7 @@ par_pline(int *complex) ecbuf[p] = WCB_PIPE(WC_PIPE_MID, (line >= 0 ? line + 1 : 0)); ecispace(p + 1, 1); ecbuf[p + 1] = ecused - 1 - p; - if (!par_pline(complex)) { + if (!par_pline(cmplx)) { tok = LEXERR; } cmdpop(); @@ -777,18 +780,20 @@ par_pline(int *complex) /* * cmd : { redir } ( for | case | if | while | repeat | * subsh | funcdef | time | dinbrack | dinpar | simple ) { redir } + * + * zsh_construct is passed through to par_subsh(), q.v. */ /**/ static int -par_cmd(int *complex) +par_cmd(int *cmplx, int zsh_construct) { int r, nr = 0; r = ecused; if (IS_REDIROP(tok)) { - *complex = 1; + *cmplx = 1; while (IS_REDIROP(tok)) { nr += par_redir(&r, NULL); } @@ -796,57 +801,57 @@ par_cmd(int *complex) switch (tok) { case FOR: cmdpush(CS_FOR); - par_for(complex); + par_for(cmplx); cmdpop(); break; case FOREACH: cmdpush(CS_FOREACH); - par_for(complex); + par_for(cmplx); cmdpop(); break; case SELECT: - *complex = 1; + *cmplx = 1; cmdpush(CS_SELECT); - par_for(complex); + par_for(cmplx); cmdpop(); break; case CASE: cmdpush(CS_CASE); - par_case(complex); + par_case(cmplx); cmdpop(); break; case IF: - par_if(complex); + par_if(cmplx); break; case WHILE: cmdpush(CS_WHILE); - par_while(complex); + par_while(cmplx); cmdpop(); break; case UNTIL: cmdpush(CS_UNTIL); - par_while(complex); + par_while(cmplx); cmdpop(); break; case REPEAT: cmdpush(CS_REPEAT); - par_repeat(complex); + par_repeat(cmplx); cmdpop(); break; case INPAR: - *complex = 1; + *cmplx = 1; cmdpush(CS_SUBSH); - par_subsh(complex); + par_subsh(cmplx, zsh_construct); cmdpop(); break; case INBRACE: cmdpush(CS_CURSH); - par_subsh(complex); + par_subsh(cmplx, zsh_construct); cmdpop(); break; case FUNC: cmdpush(CS_FUNCDEF); - par_funcdef(complex); + par_funcdef(cmplx); cmdpop(); break; case DINBRACK: @@ -864,7 +869,7 @@ par_cmd(int *complex) static int inpartime = 0; if (!inpartime) { - *complex = 1; + *cmplx = 1; inpartime = 1; par_time(); inpartime = 0; @@ -877,13 +882,13 @@ par_cmd(int *complex) { int sr; - if (!(sr = par_simple(complex, nr))) { + if (!(sr = par_simple(cmplx, nr))) { if (!nr) return 0; } else { /* Take account of redirections */ if (sr > 1) { - *complex = 1; + *cmplx = 1; r += sr - 1; } } @@ -891,7 +896,7 @@ par_cmd(int *complex) break; } if (IS_REDIROP(tok)) { - *complex = 1; + *cmplx = 1; while (IS_REDIROP(tok)) (void)par_redir(&r, NULL); } @@ -909,7 +914,7 @@ par_cmd(int *complex) /**/ static void -par_for(int *complex) +par_for(int *cmplx) { int oecused = ecused, csh = (tok == FOREACH), p, sel = (tok == SELECT); int type; @@ -994,25 +999,28 @@ par_for(int *complex) zshlex(); if (tok == DOLOOP) { zshlex(); - par_save_list(complex); + par_save_list(cmplx); if (tok != DONE) YYERRORV(oecused); + incmdpos = 0; zshlex(); } else if (tok == INBRACE) { zshlex(); - par_save_list(complex); + par_save_list(cmplx); if (tok != OUTBRACE) YYERRORV(oecused); + incmdpos = 0; zshlex(); } else if (csh || isset(CSHJUNKIELOOPS)) { - par_save_list(complex); + par_save_list(cmplx); if (tok != ZEND) YYERRORV(oecused); + incmdpos = 0; zshlex(); } else if (unset(SHORTLOOPS)) { YYERRORV(oecused); } else - par_save_list1(complex); + par_save_list1(cmplx); ecbuf[p] = (sel ? WCB_SELECT(type, ecused - 1 - p) : @@ -1028,7 +1036,7 @@ par_for(int *complex) /**/ static void -par_case(int *complex) +par_case(int *cmplx) { int oecused = ecused, brflag, p, pp, n = 1, type; int ona, onc; @@ -1145,7 +1153,7 @@ par_case(int *complex) pp = ecadd(0); ecstr(str); ecadd(ecnpats++); - par_save_list(complex); + par_save_list(cmplx); n++; if (tok == SEMIAMP) type = WC_CASE_AND; @@ -1175,7 +1183,7 @@ par_case(int *complex) /**/ static void -par_if(int *complex) +par_if(int *cmplx) { int oecused = ecused, p, pp, type, usebrace = 0; enum lextok xtok; @@ -1186,9 +1194,12 @@ par_if(int *complex) for (;;) { xtok = tok; cmdpush(xtok == IF ? CS_IF : CS_ELIF); - zshlex(); - if (xtok == FI) + if (xtok == FI) { + incmdpos = 0; + zshlex(); break; + } + zshlex(); if (xtok == ELSE) break; while (tok == SEPER) @@ -1199,7 +1210,7 @@ par_if(int *complex) } pp = ecadd(0); type = (xtok == IF ? WC_IF_IF : WC_IF_ELIF); - par_save_list(complex); + par_save_list(cmplx); incmdpos = 1; if (tok == ENDINPUT) { cmdpop(); @@ -1214,7 +1225,7 @@ par_if(int *complex) cmdpop(); cmdpush(nc); zshlex(); - par_save_list(complex); + par_save_list(cmplx); ecbuf[pp] = WCB_IF(type, ecused - 1 - pp); incmdpos = 1; cmdpop(); @@ -1223,12 +1234,13 @@ par_if(int *complex) cmdpop(); cmdpush(nc); zshlex(); - par_save_list(complex); + par_save_list(cmplx); if (tok != OUTBRACE) { cmdpop(); YYERRORV(oecused); } ecbuf[pp] = WCB_IF(type, ecused - 1 - pp); + /* command word (else) allowed to follow immediately */ zshlex(); incmdpos = 1; if (tok == SEPER) @@ -1240,7 +1252,7 @@ par_if(int *complex) } else { cmdpop(); cmdpush(nc); - par_save_list1(complex); + par_save_list1(cmplx); ecbuf[pp] = WCB_IF(type, ecused - 1 - pp); incmdpos = 1; break; @@ -1254,18 +1266,19 @@ par_if(int *complex) zshlex(); if (tok == INBRACE && usebrace) { zshlex(); - par_save_list(complex); + par_save_list(cmplx); if (tok != OUTBRACE) { cmdpop(); YYERRORV(oecused); } } else { - par_save_list(complex); + par_save_list(cmplx); if (tok != FI) { cmdpop(); YYERRORV(oecused); } } + incmdpos = 0; ecbuf[pp] = WCB_IF(WC_IF_ELSE, ecused - 1 - pp); zshlex(); cmdpop(); @@ -1280,31 +1293,33 @@ par_if(int *complex) /**/ static void -par_while(int *complex) +par_while(int *cmplx) { int oecused = ecused, p; int type = (tok == UNTIL ? WC_WHILE_UNTIL : WC_WHILE_WHILE); p = ecadd(0); zshlex(); - par_save_list(complex); + par_save_list(cmplx); incmdpos = 1; while (tok == SEPER) zshlex(); if (tok == DOLOOP) { zshlex(); - par_save_list(complex); + par_save_list(cmplx); if (tok != DONE) YYERRORV(oecused); + incmdpos = 0; zshlex(); } else if (tok == INBRACE) { zshlex(); - par_save_list(complex); + par_save_list(cmplx); if (tok != OUTBRACE) YYERRORV(oecused); + incmdpos = 0; zshlex(); } else if (isset(CSHJUNKIELOOPS)) { - par_save_list(complex); + par_save_list(cmplx); if (tok != ZEND) YYERRORV(oecused); zshlex(); @@ -1320,7 +1335,7 @@ par_while(int *complex) /**/ static void -par_repeat(int *complex) +par_repeat(int *cmplx) { int oecused = ecused, p; @@ -1337,25 +1352,27 @@ par_repeat(int *complex) zshlex(); if (tok == DOLOOP) { zshlex(); - par_save_list(complex); + par_save_list(cmplx); if (tok != DONE) YYERRORV(oecused); + incmdpos = 0; zshlex(); } else if (tok == INBRACE) { zshlex(); - par_save_list(complex); + par_save_list(cmplx); if (tok != OUTBRACE) YYERRORV(oecused); + incmdpos = 0; zshlex(); } else if (isset(CSHJUNKIELOOPS)) { - par_save_list(complex); + par_save_list(cmplx); if (tok != ZEND) YYERRORV(oecused); zshlex(); } else if (unset(SHORTLOOPS)) { YYERRORV(oecused); } else - par_save_list1(complex); + par_save_list1(cmplx); ecbuf[p] = WCB_REPEAT(ecused - 1 - p); } @@ -1363,11 +1380,15 @@ par_repeat(int *complex) /* * subsh : INPAR list OUTPAR | * INBRACE list OUTBRACE [ "always" INBRACE list OUTBRACE ] + * + * With zsh_construct non-zero, we're doing a zsh special in which + * the following token is not considered in command position. This + * is used for arguments of anonymous functions. */ /**/ static void -par_subsh(int *complex) +par_subsh(int *cmplx, int zsh_construct) { enum lextok otok = tok; int oecused = ecused, p, pp; @@ -1376,11 +1397,11 @@ par_subsh(int *complex) /* Extra word only needed for always block */ pp = ecadd(0); zshlex(); - par_list(complex); + par_list(cmplx); ecadd(WCB_END()); if (tok != ((otok == INPAR) ? OUTPAR : OUTBRACE)) YYERRORV(oecused); - incmdpos = 1; + incmdpos = !zsh_construct; zshlex(); /* Optional always block. No intervening SEPERs allowed. */ @@ -1397,7 +1418,7 @@ par_subsh(int *complex) cmdpush(CS_ALWAYS); zshlex(); - par_save_list(complex); + par_save_list(cmplx); while (tok == SEPER) zshlex(); @@ -1420,7 +1441,7 @@ par_subsh(int *complex) /**/ static void -par_funcdef(int *complex) +par_funcdef(int *cmplx) { int oecused = ecused, num = 0, onp, p, c = 0; int so, oecssub = ecssub; @@ -1502,7 +1523,8 @@ par_funcdef(int *complex) num++; zshlex(); } - *complex = (num > 0); + if (num > 0) + *cmplx = 1; ecbuf[parg] = ecused - parg; /*?*/ ecbuf[parg+1] = num; } @@ -1564,15 +1586,15 @@ par_dinbrack(void) /**/ static int -par_simple(int *complex, int nr) +par_simple(int *cmplx, int nr) { int oecused = ecused, isnull = 1, r, argc = 0, p, isfunc = 0, sr = 0; - int c = *complex, nrediradd, assignments = 0; + int c = *cmplx, nrediradd, assignments = 0; r = ecused; for (;;) { if (tok == NOCORRECT) { - *complex = c = 1; + *cmplx = c = 1; nocorrect = 1; } else if (tok == ENVSTRING) { char *p, *name, *str; @@ -1600,7 +1622,7 @@ par_simple(int *complex, int nr) */ if (p[1] == Inpar && (*p == Equals || *p == Inang || *p == OutangProc)) { - *complex = 1; + *cmplx = 1; break; } } @@ -1612,10 +1634,10 @@ par_simple(int *complex, int nr) int oldcmdpos = incmdpos, n, type2; /* - * We consider array setting complex because it can + * We consider array setting cmplx because it can * contain process substitutions, which need a valid job. */ - *complex = c = 1; + *cmplx = c = 1; p = ecadd(0); incmdpos = 0; if ((type2 = strlen(tokstr) - 1) && tokstr[type2] == '+') { @@ -1647,7 +1669,7 @@ par_simple(int *complex, int nr) if (tok == STRING) { int redir_var = 0; - *complex = 1; + *cmplx = 1; incmdpos = 0; if (!isset(IGNOREBRACES) && *tokstr == Inbrace) @@ -1666,7 +1688,7 @@ par_simple(int *complex, int nr) if (IS_REDIROP(tok) && tokfd == -1) { - *complex = c = 1; + *cmplx = c = 1; nrediradd = par_redir(&r, idstring); p += nrediradd; sr += nrediradd; @@ -1687,7 +1709,7 @@ par_simple(int *complex, int nr) zshlex(); } } else if (IS_REDIROP(tok)) { - *complex = c = 1; + *cmplx = c = 1; nrediradd = par_redir(&r, NULL); p += nrediradd; sr += nrediradd; @@ -1702,7 +1724,7 @@ par_simple(int *complex, int nr) if (assignments) YYERROR(oecused); - *complex = c; + *cmplx = c; lineno = 0; incmdpos = 1; cmdpush(CS_FUNCDEF); @@ -1745,10 +1767,21 @@ par_simple(int *complex, int nr) sl = ecadd(0); (void)ecadd(WCB_PIPE(WC_PIPE_END, 0)); - if (!par_cmd(&c)) { + if (!par_cmd(&c, argc == 0)) { cmdpop(); YYERROR(oecused); } + if (argc == 0) { + /* + * Anonymous function, possibly with arguments. + * N.B. for cmplx structures in particular + * ( ... ) we rely on lower level code doing this + * to get the immediately following word (the + * first token after the ")" has already been + * read). + */ + incmdpos = 0; + } set_sublist_code(sl, WC_SUBLIST_END, 0, ecused - 1 - sl, c); set_list_code(ll, (Z_SYNC | Z_END), c); @@ -1775,7 +1808,8 @@ par_simple(int *complex, int nr) argc++; zshlex(); } - *complex = (argc > 0); + if (argc > 0) + *cmplx = 1; ecbuf[parg] = ecused - parg; /*?*/ ecbuf[parg+1] = argc; } @@ -2542,6 +2576,73 @@ ecgetredirs(Estate s) return ret; } +/* + * Copy the consecutive set of redirections in the state at s. + * Return NULL if none, else an Eprog consisting only of the + * redirections from permanently allocated memory. + * + * s is left in the state ready for whatever follows the redirections. + */ + +/**/ +Eprog +eccopyredirs(Estate s) +{ + Wordcode pc = s->pc; + wordcode code = *pc; + int ncode, ncodes = 0, r, type; + + if (wc_code(code) != WC_REDIR) + return NULL; + + init_parse(); + + while (wc_code(code) == WC_REDIR) { + type = WC_REDIR_TYPE(code); + + DPUTS(type == REDIR_HEREDOC || type == REDIR_HEREDOCDASH, + "unexpanded here document"); + + if (WC_REDIR_FROM_HEREDOC(code)) + ncode = 5; + else + ncode = 3; + if (WC_REDIR_VARID(code)) + ncode++; + pc += ncode; + ncodes += ncode; + code = *pc; + } + r = ecused; + ecispace(r, ncodes); + + code = *s->pc; + while (wc_code(code) == WC_REDIR) { + s->pc++; + + ecbuf[r++] = code; + /* fd1 */ + ecbuf[r++] = *s->pc++; + /* name or HERE string */ + /* No DUP needed as we'll copy into Eprog immediately below */ + ecbuf[r++] = ecstrcode(ecgetstr(s, EC_NODUP, NULL)); + if (WC_REDIR_FROM_HEREDOC(code)) + { + /* terminator, raw */ + ecbuf[r++] = ecstrcode(ecgetstr(s, EC_NODUP, NULL)); + /* terminator, munged */ + ecbuf[r++] = ecstrcode(ecgetstr(s, EC_NODUP, NULL)); + } + if (WC_REDIR_VARID(code)) + ecbuf[r++] = ecstrcode(ecgetstr(s, EC_NODUP, NULL)); + + code = *s->pc; + } + + /* bld_eprog() appends a useful WC_END marker */ + return bld_eprog(0); +} + /**/ mod_export struct eprog dummy_eprog; @@ -3534,4 +3635,3 @@ dump_autoload(char *nam, char *file, int on, Options ops, int func) } return ret; } - diff --git a/Src/pattern.c b/Src/pattern.c index 94a299ebb..df5e602ca 100644 --- a/Src/pattern.c +++ b/Src/pattern.c @@ -3012,6 +3012,16 @@ patmatch(Upat prog) break; case P_STAR: /* Handle specially for speed, although really P_ONEHASH+P_ANY */ + while (P_OP(next) == P_STAR) { + /* + * If there's another * following we can optimise it + * out. Chains of *'s can give pathologically bad + * performance. + */ + scan = next; + next = PATNEXT(scan); + } + /*FALLTHROUGH*/ case P_ONEHASH: case P_TWOHASH: /* diff --git a/Src/prompt.c b/Src/prompt.c index 328ae3c66..0cc9ef917 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -372,6 +372,17 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep) if (t0 >= arg) test = 1; break; + case 'e': + { + Funcstack fsptr = funcstack; + test = arg; + while (fsptr && test > 0) { + test--; + fsptr = fsptr->prev; + } + test = !test; + } + break; case 'L': if (shlvl >= arg) test = 1; @@ -786,6 +797,19 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep) if(bv->Rstring) stradd(bv->Rstring); break; + case 'e': + { + int depth = 0; + Funcstack fsptr = funcstack; + while (fsptr) { + depth++; + fsptr = fsptr->prev; + } + addbufspc(DIGBUFSIZE); + sprintf(bv->bp, "%d", depth); + bv->bp += strlen(bv->bp); + break; + } case 'I': if (funcstack && funcstack->tp != FS_SOURCE && !IN_EVAL_TRAP()) { @@ -1292,12 +1316,11 @@ prompttrunc(int arg, int truncchar, int doprint, int endchar, */ for (;;) { *ptr++ = *fulltextptr; - if (*fulltextptr == Outpar || - *fulltextptr == '\0') + if (*fulltextptr == '\0' || + *fulltextptr++ == Outpar) break; - if (*fulltextptr == Nularg) + if (fulltextptr[-1] == Nularg) remw--; - fulltextptr++; } } else { #ifdef MULTIBYTE_SUPPORT @@ -1373,12 +1396,11 @@ prompttrunc(int arg, int truncchar, int doprint, int endchar, if (*skiptext == Inpar) { /* see comment on left truncation above */ for (;;) { - if (*skiptext == Outpar || - *skiptext == '\0') + if (*skiptext == '\0' || + *skiptext++ == Outpar) break; - if (*skiptext == Nularg) + if (skiptext[-1] == Nularg) maxwidth--; - skiptext++; } } else { #ifdef MULTIBYTE_SUPPORT diff --git a/Src/signals.c b/Src/signals.c index cb2b58161..2df69f96e 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -594,6 +594,17 @@ zhandler(int sig) wait_for_processes(); break; + case SIGPIPE: + if (!handletrap(SIGPIPE)) { + if (!interact) + _exit(SIGPIPE); + else if (!isatty(SHTTY)) { + stopmsg = 1; + zexit(SIGPIPE, 1); + } + } + break; + case SIGHUP: if (!handletrap(SIGHUP)) { stopmsg = 1; @@ -752,7 +763,7 @@ dosavetrap(int sig, int level) Shfunc shf, newshf = NULL; if ((shf = (Shfunc)gettrapnode(sig, 1))) { /* Copy the node for saving */ - newshf = (Shfunc) zalloc(sizeof(*newshf)); + newshf = (Shfunc) zshcalloc(sizeof(*newshf)); newshf->node.nam = ztrdup(shf->node.nam); newshf->node.flags = shf->node.flags; newshf->funcdef = dupeprog(shf->funcdef, 0); @@ -897,6 +908,8 @@ removetrap(int sig) noholdintr(); } else if (sig == SIGHUP) install_handler(sig); + else if (sig == SIGPIPE && interact && !forklevel) + install_handler(sig); else if (sig && sig <= SIGCOUNT && #ifdef SIGWINCH sig != SIGWINCH && diff --git a/Src/subst.c b/Src/subst.c index 4a5fe3a3c..1aa9b982e 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -1522,6 +1522,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) * unset. I don't quite understand why (v == NULL) isn't * good enough, but there are places where we seem to need * to second guess whether a value is a real value or not. + * See in particular the (colf && !vunset) test below. */ int vunset = 0; /* @@ -2638,8 +2639,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) * - (array) contains no elements * - (scalar) contains an empty string */ - if (colf && !vunset) + if (colf && !vunset) { vunset = (isarr) ? !*aval : !*val || (*val == Nularg && !val[1]); + vunset *= -1; /* Record that vunset was originally false */ + } switch (s[-1]) { case '+': @@ -2862,7 +2865,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) getmatcharr(&aval, s, flags, flnum, replstr); } else { if (vunset) { - if (unset(UNSET)) { + if (vunset > 0 && unset(UNSET)) { *idend = '\0'; zerr("%s: parameter not set", idbeg); return NULL; @@ -2892,7 +2895,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) return NULL; } if (vunset) { - if (unset(UNSET)) { + if (vunset > 0 && unset(UNSET)) { *idend = '\0'; zerr("%s: parameter not set", idbeg); return NULL; @@ -2974,7 +2977,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) *ap = NULL; } else { if (vunset) { - if (unset(UNSET)) { + if (vunset > 0 && unset(UNSET)) { *idend = '\0'; zerr("%s: parameter not set", idbeg); deletehashtable(ht); @@ -3003,7 +3006,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) } } if (vunset) { - if (unset(UNSET)) { + if (vunset > 0 && unset(UNSET)) { *idend = '\0'; zerr("%s: parameter not set", idbeg); return NULL; @@ -3020,7 +3023,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) val = dupstring(vunset ? "0" : "1"); isarr = 0; } else if (vunset) { - if (unset(UNSET)) { + if (vunset > 0 && unset(UNSET)) { *idend = '\0'; zerr("%s: parameter not set", idbeg); return NULL; diff --git a/Src/utils.c b/Src/utils.c index 9109f66a7..e6eb8e6a7 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -3424,12 +3424,12 @@ equalsplit(char *s, char **t) return 0; } -static int specialcomma; /* the ztypes table */ /**/ mod_export short int typtab[256]; +static int typtab_flags = 0; /* initialize the ztypes table */ @@ -3440,8 +3440,15 @@ inittyptab(void) int t0; char *s; - for (t0 = 0; t0 != 256; t0++) - typtab[t0] = 0; + if (!(typtab_flags & ZTF_INIT)) { + typtab_flags = ZTF_INIT; + if (interact && isset(SHINSTDIN)) + typtab_flags |= ZTF_INTERACT; + } + + queue_signals(); + + memset(typtab, 0, sizeof(typtab)); for (t0 = 0; t0 != 32; t0++) typtab[t0] = typtab[t0 + 128] = ICNTRL; typtab[127] = ICNTRL; @@ -3514,20 +3521,43 @@ inittyptab(void) #endif for (s = SPECCHARS; *s; s++) typtab[STOUC(*s)] |= ISPECIAL; - if (specialcomma) + if (typtab_flags & ZTF_SP_COMMA) typtab[STOUC(',')] |= ISPECIAL; - if (isset(BANGHIST) && bangchar && interact && isset(SHINSTDIN)) + if (isset(BANGHIST) && bangchar && (typtab_flags & ZTF_INTERACT)) { + typtab_flags |= ZTF_BANGCHAR; typtab[bangchar] |= ISPECIAL; + } else + typtab_flags &= ~ZTF_BANGCHAR; + + unqueue_signals(); } /**/ mod_export void makecommaspecial(int yesno) { - if ((specialcomma = yesno) != 0) + if (yesno != 0) { + typtab_flags |= ZTF_SP_COMMA; typtab[STOUC(',')] |= ISPECIAL; - else + } else { + typtab_flags &= ~ZTF_SP_COMMA; typtab[STOUC(',')] &= ~ISPECIAL; + } +} + +/**/ +mod_export void +makebangspecial(int yesno) +{ + /* Name and call signature for congruence with makecommaspecial(), + * but in this case when yesno is nonzero we defer to the state + * saved by inittyptab(). + */ + if (yesno == 0) { + typtab[bangchar] &= ~ISPECIAL; + } else if (typtab_flags & ZTF_BANGCHAR) { + typtab[bangchar] |= ISPECIAL; + } } @@ -1139,6 +1139,7 @@ struct shfunc { char *filename; /* Name of file located in */ zlong lineno; /* line number in above file */ Eprog funcdef; /* function definition */ + Eprog redir; /* redirections to apply */ Emulation_options sticky; /* sticky emulation definitions, if any */ }; @@ -1820,7 +1821,8 @@ struct paramdef { */ enum { ASSPM_AUGMENT = 1 << 0, - ASSPM_WARN_CREATE = 1 << 1 + ASSPM_WARN_CREATE = 1 << 1, + ASSPM_ENV_IMPORT = 1 << 2 }; /* node for named directory hash table (nameddirtab) */ diff --git a/Src/zsh.mdd b/Src/zsh.mdd index cec3edab7..9a8c923f9 100644 --- a/Src/zsh.mdd +++ b/Src/zsh.mdd @@ -73,6 +73,9 @@ zshpaths.h: Makemod $(CONFIG_INCS) @if test x$(sitefndir) != xno; then \ echo '#define SITEFPATH_DIR "'$(sitefndir)'"' >> zshpaths.h.tmp; \ fi + @if test x$(fixed_sitefndir) != x; then \ + echo '#define FIXED_FPATH_DIR "'$(fixed_sitefndir)'"' >> zshpaths.h.tmp; \ + fi @if test x$(fndir) != xno; then \ echo '#define FPATH_DIR "'$(fndir)'"' >> zshpaths.h.tmp; \ if test x$(FUNCTIONS_SUBDIRS) != x && \ diff --git a/Src/ztype.h b/Src/ztype.h index 14f66101c..eef0f23db 100644 --- a/Src/ztype.h +++ b/Src/ztype.h @@ -59,6 +59,15 @@ #define iwsep(X) zistype(X,IWSEP) #define inull(X) zistype(X,INULL) +/* + * Bit flags for typtab_flags --- preserved after + * shell initialisation. + */ +#define ZTF_INIT (0x0001) /* One-off initialisation done */ +#define ZTF_INTERACT (0x0002) /* Shell interative and reading from stdin */ +#define ZTF_SP_COMMA (0x0004) /* Treat comma as a special characters */ +#define ZTF_BANGCHAR (0x0008) /* Treat bangchar as a special character */ + #ifdef MULTIBYTE_SUPPORT #define WC_ZISTYPE(X,Y) wcsitype((X),(Y)) #define WC_ISPRINT(X) iswprint(X) |