diff options
Diffstat (limited to 'Src')
47 files changed, 1391 insertions, 378 deletions
diff --git a/Src/Builtins/rlimits.c b/Src/Builtins/rlimits.c index fd4c94aaa..9da31831d 100644 --- a/Src/Builtins/rlimits.c +++ b/Src/Builtins/rlimits.c @@ -32,12 +32,17 @@ #if defined(HAVE_GETRLIMIT) && defined(RLIM_INFINITY) -#ifdef RLIMIT_POSIXLOCKS +#if defined(HAVE_RLIMIT_POSIXLOCKS) && !defined(HAVE_RLIMIT_LOCKS) # define RLIMIT_LOCKS RLIMIT_POSIXLOCKS +# define HAVE_RLIMIT_LOCKS 1 #endif -#ifdef RLIMIT_NTHR +#if defined(HAVE_RLIMIT_NTHR) && !defined(HAVE_RLIMIT_PTHREAD) # define RLIMIT_PTHREAD RLIMIT_NTHR +# define HAVE_RLIMIT_PTHREAD 1 +# define THREAD_FMT "-T: threads " +#else +# define THREAD_FMT "-T: threads per process " #endif enum { @@ -367,13 +372,13 @@ printulimit(char *nam, int lim, int hard, int head) # ifdef HAVE_RLIMIT_SBSIZE case RLIMIT_SBSIZE: if (head) - printf("-b: socket buffer size (bytes) ", RLIMIT_SBSIZE); + printf("-b: socket buffer size (bytes) "); break; # endif /* HAVE_RLIMIT_SBSIZE */ # ifdef HAVE_RLIMIT_PTHREAD case RLIMIT_PTHREAD: if (head) - printf("-T: threads per process "); + printf("%s", THREAD_FMT); break; # endif /* HAVE_RLIMIT_PTHREAD */ # ifdef HAVE_RLIMIT_NICE @@ -860,6 +865,13 @@ bin_ulimit(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) case 'r': res = RLIMIT_RTPRIO; break; +# else +# ifdef HAVE_RLIMIT_NTHR + /* For compatibility with sh on NetBSD */ + case 'r': + res = RLIMIT_NTHR; + break; +# endif /* HAVE_RLIMIT_NTHR */ # endif # ifdef HAVE_RLIMIT_NPTS case 'p': @@ -876,6 +888,11 @@ bin_ulimit(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) res = RLIMIT_KQUEUES; break; # endif +# ifdef HAVE_RLIMIT_PTHREAD + case 'T': + res = RLIMIT_PTHREAD; + break; +# endif default: /* unrecognised limit */ zwarnnam(name, "bad option: -%c", *options); diff --git a/Src/Builtins/sched.c b/Src/Builtins/sched.c index 1ec3269bd..c1cc98354 100644 --- a/Src/Builtins/sched.c +++ b/Src/Builtins/sched.c @@ -211,7 +211,7 @@ bin_sched(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func)) t = sch->time; tmp = localtime(&t); - ztrftime(tbuf, 40, "%a %b %e %k:%M:%S", tmp); + ztrftime(tbuf, 40, "%a %b %e %k:%M:%S", tmp, 0L); if (sch->flags & SCHEDFLAG_TRASH_ZLE) flagstr = "-o "; else diff --git a/Src/Modules/datetime.c b/Src/Modules/datetime.c index a4e7eca86..00ebd2b49 100644 --- a/Src/Modules/datetime.c +++ b/Src/Modules/datetime.c @@ -130,7 +130,7 @@ bin_strftime(char *nam, char **argv, Options ops, UNUSED(int func)) buffer = zalloc(bufsize); for (x=0; x < 4; x++) { - if (ztrftime(buffer, bufsize, argv[0], t) >= 0) + if (ztrftime(buffer, bufsize, argv[0], t, 0L) >= 0) break; buffer = zrealloc(buffer, bufsize *= 2); } diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c index 22148f991..0385a709e 100644 --- a/Src/Modules/parameter.c +++ b/Src/Modules/parameter.c @@ -106,7 +106,7 @@ getpmparameter(UNUSED(HashTable ht), const char *name) pm->u.str = paramtypestr(rpm); else { pm->u.str = dupstring(""); - pm->node.flags |= PM_UNSET; + pm->node.flags |= (PM_UNSET|PM_SPECIAL); } return &pm->node; } @@ -224,7 +224,7 @@ getpmcommand(UNUSED(HashTable ht), const char *name) } } else { pm->u.str = dupstring(""); - pm->node.flags |= PM_UNSET; + pm->node.flags |= (PM_UNSET|PM_SPECIAL); } return &pm->node; } @@ -410,7 +410,7 @@ getfunction(UNUSED(HashTable ht), const char *name, int dis) } } else { pm->u.str = dupstring(""); - pm->node.flags |= PM_UNSET; + pm->node.flags |= (PM_UNSET|PM_SPECIAL); } return &pm->node; } @@ -661,7 +661,7 @@ getbuiltin(UNUSED(HashTable ht), const char *name, int dis) pm->u.str = dupstring(t); } else { pm->u.str = dupstring(""); - pm->node.flags |= PM_UNSET; + pm->node.flags |= (PM_UNSET|PM_SPECIAL); } return &pm->node; } @@ -876,7 +876,7 @@ getpmoption(UNUSED(HashTable ht), const char *name) } else { pm->u.str = dupstring(""); - pm->node.flags |= PM_UNSET; + pm->node.flags |= (PM_UNSET|PM_SPECIAL); } return &pm->node; } @@ -934,7 +934,7 @@ getpmmodule(UNUSED(HashTable ht), const char *name) pm->u.str = dupstring(type); else { pm->u.str = dupstring(""); - pm->node.flags |= PM_UNSET; + pm->node.flags |= (PM_UNSET|PM_SPECIAL); } return &pm->node; } @@ -1048,7 +1048,7 @@ getpmhistory(UNUSED(HashTable ht), const char *name) pm->u.str = dupstring(he->node.nam); else { pm->u.str = dupstring(""); - pm->node.flags |= PM_UNSET; + pm->node.flags |= (PM_UNSET|PM_SPECIAL); } return &pm->node; } @@ -1158,7 +1158,7 @@ getpmjobtext(UNUSED(HashTable ht), const char *name) pm->u.str = pmjobtext(job); else { pm->u.str = dupstring(""); - pm->node.flags |= PM_UNSET; + pm->node.flags |= (PM_UNSET|PM_SPECIAL); } return &pm->node; } @@ -1259,7 +1259,7 @@ getpmjobstate(UNUSED(HashTable ht), const char *name) pm->u.str = pmjobstate(job); else { pm->u.str = dupstring(""); - pm->node.flags |= PM_UNSET; + pm->node.flags |= (PM_UNSET|PM_SPECIAL); } return &pm->node; } @@ -1325,7 +1325,7 @@ getpmjobdir(UNUSED(HashTable ht), const char *name) pm->u.str = pmjobdir(job); else { pm->u.str = dupstring(""); - pm->node.flags |= PM_UNSET; + pm->node.flags |= (PM_UNSET|PM_SPECIAL); } return &pm->node; } @@ -1451,7 +1451,7 @@ getpmnameddir(UNUSED(HashTable ht), const char *name) pm->u.str = dupstring(nd->dir); else { pm->u.str = dupstring(""); - pm->node.flags |= PM_UNSET; + pm->node.flags |= (PM_UNSET|PM_SPECIAL); } return &pm->node; } @@ -1502,7 +1502,7 @@ getpmuserdir(UNUSED(HashTable ht), const char *name) pm->u.str = dupstring(nd->dir); else { pm->u.str = dupstring(""); - pm->node.flags |= PM_UNSET; + pm->node.flags |= (PM_UNSET|PM_SPECIAL); } return &pm->node; } @@ -1754,7 +1754,7 @@ getalias(HashTable alht, UNUSED(HashTable ht), const char *name, int flags) pm->u.str = dupstring(al->text); else { pm->u.str = dupstring(""); - pm->node.flags |= PM_UNSET; + pm->node.flags |= (PM_UNSET|PM_SPECIAL); } return &pm->node; } @@ -1950,7 +1950,7 @@ getpmusergroups(UNUSED(HashTable ht), const char *name) if (!gs) { zerr("failed to retrieve groups for user: %e", errno); pm->u.str = dupstring(""); - pm->node.flags |= PM_UNSET; + pm->node.flags |= (PM_UNSET|PM_SPECIAL); return &pm->node; } @@ -1965,7 +1965,7 @@ getpmusergroups(UNUSED(HashTable ht), const char *name) } pm->u.str = dupstring(""); - pm->node.flags |= PM_UNSET; + pm->node.flags |= (PM_UNSET|PM_SPECIAL); return &pm->node; } diff --git a/Src/Modules/pcre.c b/Src/Modules/pcre.c index cb9f8ef57..040a33f8e 100644 --- a/Src/Modules/pcre.c +++ b/Src/Modules/pcre.c @@ -289,14 +289,11 @@ 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. */ - offset_start = getposint(OPT_ARG(ops,c), nam); + 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 */ if(OPT_ISSET(ops,'b')) want_offset_pair = 1; - - if(!*args) { - zwarnnam(nam, "not enough arguments"); - } if ((ret = pcre_fullinfo(pcre_pattern, pcre_hints, PCRE_INFO_CAPTURECOUNT, &capcount))) { @@ -311,7 +308,7 @@ bin_pcre_match(char *nam, char **args, Options ops, UNUSED(int func)) unmetafy(plaintext, NULL); subject_len = (int)strlen(plaintext); - if (offset_start < 0 || offset_start >= subject_len) + if (offset_start > 0 && offset_start >= subject_len) ret = PCRE_ERROR_NOMATCH; else ret = pcre_exec(pcre_pattern, pcre_hints, plaintext, subject_len, offset_start, 0, ovec, ovecsize); @@ -345,6 +342,8 @@ cond_pcre_match(char **a, int id) if (zpcre_utf8_enabled()) pcre_opts |= PCRE_UTF8; + if (isset(REMATCHPCRE) && !isset(CASEMATCH)) + pcre_opts |= PCRE_CASELESS; lhstr = cond_str(a,0,0); rhre = cond_str(a,1,0); diff --git a/Src/Modules/stat.c b/Src/Modules/stat.c index edae0841e..6fc53894c 100644 --- a/Src/Modules/stat.c +++ b/Src/Modules/stat.c @@ -198,7 +198,7 @@ stattimeprint(time_t tim, char *outbuf, int flags) if (flags & STF_STRING) { char *oend = outbuf + strlen(outbuf); ztrftime(oend, 40, timefmt, (flags & STF_GMT) ? gmtime(&tim) : - localtime(&tim)); + localtime(&tim), 0L); if (flags & STF_RAW) strcat(oend, ")"); } diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c index 399c45f46..1cca0c4b8 100644 --- a/Src/Modules/zutil.c +++ b/Src/Modules/zutil.c @@ -30,6 +30,55 @@ #include "zutil.mdh" #include "zutil.pro" +typedef struct { + char **match; + char **mbegin; + char **mend; +} MatchData; + +static void +savematch(MatchData *m) +{ + char **a; + + queue_signals(); + a = getaparam("match"); + m->match = a ? zarrdup(a) : NULL; + a = getaparam("mbegin"); + m->mbegin = a ? zarrdup(a) : NULL; + a = getaparam("mend"); + m->mend = a ? zarrdup(a) : NULL; + unqueue_signals(); +} + +static void +restorematch(MatchData *m) +{ + if (m->match) + setaparam("match", m->match); + else + unsetparam("match"); + if (m->mbegin) + setaparam("mbegin", m->mbegin); + else + unsetparam("mbegin"); + if (m->mend) + setaparam("mend", m->mend); + else + unsetparam("mend"); +} + +static void +freematch(MatchData *m) +{ + if (m->match) + freearray(m->match); + if (m->mbegin) + freearray(m->mbegin); + if (m->mend) + freearray(m->mend); +} + /* Style stuff. */ typedef struct stypat *Stypat; @@ -370,15 +419,21 @@ lookupstyle(char *ctxt, char *style) { Style s; Stypat p; + char **found = NULL; s = (Style)zstyletab->getnode2(zstyletab, style); - if (!s) - return NULL; - for (p = s->pats; p; p = p->next) - if (pattry(p->prog, ctxt)) - return (p->eval ? evalstyle(p) : p->vals); + if (s) { + MatchData match; + savematch(&match); + for (p = s->pats; p; p = p->next) + if (pattry(p->prog, ctxt)) { + found = (p->eval ? evalstyle(p) : p->vals); + break; + } + restorematch(&match); + } - return NULL; + return found; } static int @@ -915,55 +970,6 @@ bin_zformat(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) /* Zregexparse stuff. */ typedef struct { - char **match; - char **mbegin; - char **mend; -} MatchData; - -static void -savematch(MatchData *m) -{ - char **a; - - queue_signals(); - a = getaparam("match"); - m->match = a ? zarrdup(a) : NULL; - a = getaparam("mbegin"); - m->mbegin = a ? zarrdup(a) : NULL; - a = getaparam("mend"); - m->mend = a ? zarrdup(a) : NULL; - unqueue_signals(); -} - -static void -restorematch(MatchData *m) -{ - if (m->match) - setaparam("match", m->match); - else - unsetparam("match"); - if (m->mbegin) - setaparam("mbegin", m->mbegin); - else - unsetparam("mbegin"); - if (m->mend) - setaparam("mend", m->mend); - else - unsetparam("mend"); -} - -static void -freematch(MatchData *m) -{ - if (m->match) - freearray(m->match); - if (m->mbegin) - freearray(m->mbegin); - if (m->mend) - freearray(m->mend); -} - -typedef struct { int cutoff; char *pattern; Patprog patprog; @@ -1543,6 +1549,45 @@ add_opt_val(Zoptdesc d, char *arg) } } +/* + * For "zparseopts -K -A assoc ..." this function copies the keys and + * values from the default and allocates the extra space for any parsed + * values having the same keys. If there are no new values, creates an + * empty array. Returns a pointer to the NULL element marking the end. + * + * aval = pointer to the newly allocated array + * assoc = name of the default hash param to copy + * keep = whether we need to make the copy at all + * num = count of new values to add space for + */ +static char ** +zalloc_default_array(char ***aval, char *assoc, int keep, int num) +{ + char **ap = 0; + + *aval = 0; + if (keep && num) { + struct value vbuf; + Value v = fetchvalue(&vbuf, &assoc, 0, + SCANPM_WANTKEYS|SCANPM_WANTVALS|SCANPM_MATCHMANY); + if (v && v->isarr) { + char **dp, **dval = getarrvalue(v); + int dnum = (dval ? arrlen(dval) : 0) + 1; + *aval = (char **) zalloc(((num * 2) + dnum) * sizeof(char *)); + for (ap = *aval, dp = dval; dp && *dp; dp++) { + *ap = (char *) zalloc(strlen(*dp) + 1); + strcpy(*ap++, *dp); + } + *ap = NULL; + } + } + if (!ap) { + ap = *aval = (char **) zalloc(((num * 2) + 1) * sizeof(char *)); + *ap = NULL; + } + return ap; +} + static int bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) { @@ -1825,8 +1870,8 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) num++; if (!keep || num) { - aval = (char **) zalloc(((num * 2) + 1) * sizeof(char *)); - for (ap = aval, d = opt_descs; d; d = d->next) { + ap = zalloc_default_array(&aval, assoc, keep, num); + for (d = opt_descs; d; d = d->next) { if (d->vals) { *ap++ = n = (char *) zalloc(strlen(d->name) + 2); *n = '-'; diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index 5c5628a8d..ac7785ab7 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -1260,6 +1260,20 @@ check_param(char *s, int set, int test) ispar = (br >= 2 ? 2 : 1); b[we-wb] = '\0'; return b; + } else if (offs > e - s && *e == ':') { + /* + * Guess whether we are in modifiers. + * If the name is followed by a : and the stuff after + * that is either colons or alphanumerics we probably are. + * This is a very rough guess. + */ + char *offsptr = s + offs; + for (; e < offsptr; e++) { + if (*e != ':' && !ialnum(*e)) + break; + } + ispar = (br >= 2 ? 2 : 1); + return NULL; } } return NULL; diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index ab1857c0a..52b9e9c82 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -193,7 +193,7 @@ compctlread(char *name, char **args, Options ops, char *reply) /* only allowed to be called for completion */ if (!incompctlfunc) { - zwarnnam(name, "option valid only in functions called for completion"); + zwarnnam(name, "option valid only in functions called via compctl"); return 1; } @@ -3391,7 +3391,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) mflags |= CMF_FILE; for (n = firstnode(l); n; incnode(n)) addmatch(getdata(n), NULL); - mflags &= !CMF_FILE; + mflags &= ~CMF_FILE; } opts[NULLGLOB] = ng; } else { diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c index bcf356179..5e5ba9f20 100644 --- a/Src/Zle/complist.c +++ b/Src/Zle/complist.c @@ -383,12 +383,25 @@ getcoldef(char *s) } else if (*s == '=') { char *p = ++s, *t, *cols[MAX_POS]; int ncols = 0; + int nesting = 0; Patprog prog; /* This is for a pattern. */ - while (*s && *s != '=') - s++; + while (*s && (nesting || *s != '=')) { + switch (*s++) { + case '\\': + if (*s) + s++; + break; + case '(': + nesting++; + break; + case ')': + nesting--; + break; + } + } if (!*s) return s; *s++ = '\0'; @@ -2500,7 +2513,7 @@ domenuselect(Hookdef dummy, Chdata dat) mlbeg--; } } - if ((space = zterm_lines - pl - mhasstat)) + if ((space = zterm_lines - pl - mhasstat) > 0) while (mline >= mlbeg + space) if ((mlbeg += step) + space > mlines) mlbeg = mlines - space; diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c index c0e5ff3d8..fcceb670c 100644 --- a/Src/Zle/compresult.c +++ b/Src/Zle/compresult.c @@ -1131,7 +1131,7 @@ do_single(Cmatch m) /* If a suffix was added, and is removable, let * * `,' and `}' remove it. */ if (isset(AUTOPARAMKEYS)) - addsuffix(SUFTYP_POSSTR, 0, ZWS(",}"), 2, suffixnoinslen); + addsuffix(SUFTYP_POSSTR, 0, ZWS(",}"), 2, suffixlen); } else if (!menucmp) { /*{{*/ /* Otherwise, add a `,' suffix, and let `}' remove it. */ diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c index f5e6ba195..b11c39f25 100644 --- a/Src/Zle/computil.c +++ b/Src/Zle/computil.c @@ -1500,9 +1500,11 @@ parse_cadef(char *nam, char **args) nodopts++; /* If this is for single-letter option we also store a - * pointer for the definition in the array for fast lookup. */ + * pointer for the definition in the array for fast lookup. + * But don't treat '--' as a single option called '-' */ - if (single && name[1] && !name[2]) + + if (single && name[1] && !name[2] && name[1] != '-') ret->single[STOUC(name[1])] = opt; if (again == 1) { @@ -2034,7 +2036,9 @@ ca_parse_line(Cadef d, int multi, int first) state.optbeg = state.argbeg = state.inopt = cur; state.argend = argend; state.singles = (d->single && (!pe || !*pe) && - state.curopt->name[1] && !state.curopt->name[2]); + state.curopt->name[1] && !state.curopt->name[2] && + /* Don't treat '--' as a single option called '-' */ + state.curopt->name[1] != '-'); if (!state.oargs[state.curopt->num]) state.oargs[state.curopt->num] = znewlinklist(); diff --git a/Src/Zle/iwidgets.list b/Src/Zle/iwidgets.list index 4372fe36e..e3ffe3e8c 100644 --- a/Src/Zle/iwidgets.list +++ b/Src/Zle/iwidgets.list @@ -102,6 +102,7 @@ "self-insert-unmeta", selfinsertunmeta, ZLE_MENUCMP | ZLE_KEEPSUFFIX "send-break", sendbreak, 0 "set-mark-command", setmarkcommand, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL +"split-undo", splitundo, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_NOTCOMMAND "spell-word", spellword, 0 "set-local-history", setlocalhistory, 0 "transpose-chars", transposechars, 0 diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c index bd5bc36d5..44b39d186 100644 --- a/Src/Zle/zle_hist.c +++ b/Src/Zle/zle_hist.c @@ -890,6 +890,10 @@ zgetline(UNUSED(char **args)) free(s); free(lineadd); clearlist = 1; + if (stackhist != -1) { + histline = stackhist; + stackhist = -1; + } } return 0; } diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 040b7cb83..442c31995 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -157,10 +157,10 @@ mod_export char *statusline; /**/ int stackhist, stackcs; -/* != 0 if we are making undo records */ +/* position in undo stack from when the current vi change started */ /**/ -int undoing; +zlong vistartchange; /* current modifier status */ @@ -525,7 +525,8 @@ raw_getbyte(long do_keytmout, char *cptr) #endif #ifndef HAVE_POLL # ifdef HAVE_SELECT - fd_set foofd; + fd_set foofd, errfd; + FD_ZERO(&errfd); # endif #endif @@ -613,11 +614,14 @@ raw_getbyte(long do_keytmout, char *cptr) if (!errtry) { for (i = 0; i < nwatch; i++) { int fd = watch_fds[i].fd; + if (FD_ISSET(fd, &errfd)) + continue; FD_SET(fd, &foofd); if (fd > fdmax) fdmax = fd; } } + FD_ZERO(&errfd); if (tmout.tp != ZTM_NONE) { expire_tv.tv_sec = tmout.exp100ths / 100; @@ -732,9 +736,10 @@ raw_getbyte(long do_keytmout, char *cptr) Watch_fd lwatch_fd = lwatch_fds + i; if ( # ifdef HAVE_POLL - (fds[i+1].revents & POLLIN) + (fds[i+1].revents & (POLLIN|POLLERR|POLLHUP|POLLNVAL)) # else - FD_ISSET(lwatch_fd->fd, &foofd) + FD_ISSET(lwatch_fd->fd, &foofd) || + FD_ISSET(lwatch_fd->fd, &errfd) # endif ) { /* Handle the fd. */ @@ -765,6 +770,9 @@ raw_getbyte(long do_keytmout, char *cptr) if (fds[i+1].revents & POLLNVAL) zaddlinknode(funcargs, ztrdup("nval")); # endif +# else + if (FD_ISSET(lwatch_fd->fd, &errfd)) + zaddlinknode(funcargs, ztrdup("err")); # endif callhookfunc(lwatch_fd->func, funcargs, 0, NULL); freelinklist(funcargs, freestr); @@ -786,6 +794,31 @@ raw_getbyte(long do_keytmout, char *cptr) for (i = 0; i < lnwatch; i++) zsfree(lwatch_fds[i].func); zfree(lwatch_fds, lnwatch*sizeof(struct watch_fd)); + +# ifdef HAVE_POLL + /* Function may have added or removed handlers */ + nfds = 1 + nwatch; + if (nfds > 1) { + fds = zrealloc(fds, sizeof(struct pollfd) * nfds); + for (i = 0; i < nwatch; i++) { + /* + * This is imperfect because it assumes fds[] and + * watch_fds[] remain in sync, which may be false + * if handlers are shuffled. However, it should + * be harmless (e.g., produce one extra pass of + * the loop) in the event they fall out of sync. + */ + if (fds[i+1].fd == watch_fds[i].fd && + (fds[i+1].revents & (POLLERR|POLLHUP|POLLNVAL))) { + fds[i+1].events = 0; /* Don't poll this */ + } else { + fds[i+1].fd = watch_fds[i].fd; + fds[i+1].events = POLLIN; + } + fds[i+1].revents = 0; + } + } +# endif } } # ifdef HAVE_POLL @@ -1080,8 +1113,7 @@ zlecore(void) if (invicmdmode() && zlecs > findbol() && (zlecs == zlell || zleline[zlecs] == ZWC('\n'))) DECCS(); - if (undoing) - handleundo(); + handleundo(); } else { errflag = 1; break; @@ -1190,7 +1222,7 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) zlereadflags = flags; zlecontext = context; histline = curhist; - undoing = 1; + vistartchange = -1; zleline = (ZLE_STRING_T)zalloc(((linesz = 256) + 2) * ZLE_CHAR_SIZE); *zleline = ZWC('\0'); virangeflag = lastcmd = done = zlecs = zlell = mark = 0; @@ -1198,14 +1230,7 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) viinsbegin = 0; statusline = NULL; selectkeymap("main", 1); - /* - * If main is linked to the viins keymap, we need to register - * explicitly that we're now in vi insert mode as there's - * no user operation to indicate this. - */ - if (openkeymap("main") == openkeymap("viins")) - viinsert(NULL); - selectlocalmap(NULL); + initundo(); fixsuffix(); if ((s = getlinknode(bufstack))) { setline(s, ZSL_TOEND); @@ -1222,7 +1247,14 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) stackhist = -1; } } - initundo(); + /* + * If main is linked to the viins keymap, we need to register + * explicitly that we're now in vi insert mode as there's + * no user operation to indicate this. + */ + if (openkeymap("main") == openkeymap("viins")) + viinsert_init(); + selectlocalmap(NULL); if (isset(PROMPTCR)) putc('\r', shout); if (tmout) diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c index 7be0ebbd1..9bc1cf6f5 100644 --- a/Src/Zle/zle_misc.c +++ b/Src/Zle/zle_misc.c @@ -1249,10 +1249,14 @@ static char *suffixfunc; /* Length associated with the suffix function */ static int suffixfunclen; -/* Length associated with uninsertable characters */ +/* Whether to remove suffix on uninsertable characters */ +/**/ +int suffixnoinsrem; + +/* Length of the currently active, auto-removable suffix. */ /**/ mod_export int -suffixnoinslen; +suffixlen; /**/ mod_export void @@ -1309,7 +1313,8 @@ makesuffix(int n) if ((suffixchars = getsparam("ZLE_SPACE_SUFFIX_CHARS")) && *suffixchars) addsuffixstring(SUFTYP_POSSTR, SUFFLAGS_SPACE, suffixchars, n); - suffixnoinslen = n; + suffixlen = n; + suffixnoinsrem = 1; } /* Set up suffix for parameter names: the last n characters are a suffix * @@ -1358,15 +1363,10 @@ makesuffixstr(char *f, char *s, int n) s = metafy(s, i, META_USEHEAP); ws = stringaszleline(s, 0, &i, NULL, NULL); - if (z) - suffixnoinslen = inv ? 0 : n; - else if (inv) { - /* - * negative match, \- wasn't present, so it *should* - * have this suffix length - */ - suffixnoinslen = n; - } + /* Remove suffix on uninsertable characters if \- was given * + * and the character class wasn't negated -- or vice versa. */ + suffixnoinsrem = z ^ inv; + suffixlen = n; lasts = wptr = ws; while (i) { @@ -1444,7 +1444,7 @@ iremovesuffix(ZLE_INT_T c, int keep) struct suffixset *ss; if (c == NO_INSERT_CHAR) { - sl = suffixnoinslen; + sl = suffixnoinsrem ? suffixlen : 0; } else { ZLE_CHAR_T ch = c; /* @@ -1538,5 +1538,5 @@ fixsuffix(void) suffixlist = next; } - suffixfunclen = suffixnoinslen = 0; + suffixfunclen = suffixnoinsrem = suffixlen = 0; } diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c index a9bbf136a..5845207fa 100644 --- a/Src/Zle/zle_params.c +++ b/Src/Zle/zle_params.c @@ -363,7 +363,7 @@ get_prebuffer(UNUSED(Param pm)) static char * get_widget(UNUSED(Param pm)) { - return bindk->nam; + return bindk ? bindk->nam : ""; } /**/ diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index fd5485770..80be27f03 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -444,6 +444,7 @@ void set_region_highlight(UNUSED(Param pm), char **aval) { int len; + char **av = aval; struct region_highlight *rhp; len = aval ? arrlen(aval) : 0; @@ -490,6 +491,8 @@ set_region_highlight(UNUSED(Param pm), char **aval) match_highlight(strp, &rhp->atr); } + + freearray(av); } @@ -977,7 +980,7 @@ zrefresh(void) int tmpalloced; /* flag to free tmpline when finished */ int remetafy; /* flag that zle line is metafied */ int txtchange; /* attributes set after prompts */ - int rprompt_off; /* Offset of rprompt from right of screen */ + int rprompt_off = 1; /* Offset of rprompt from right of screen */ struct rparams rpms; #ifdef MULTIBYTE_SUPPORT int width; /* width of wide character */ @@ -1046,8 +1049,8 @@ zrefresh(void) region_highlights[1].start = region_highlights[1].end = -1; } /* check for an active completion suffix */ - if (suffixnoinslen) { - region_highlights[2].start = zlecs - suffixnoinslen; + if (suffixlen) { + region_highlights[2].start = zlecs - suffixlen; region_highlights[2].end = zlecs; } else { region_highlights[2].start = region_highlights[2].end = -1; diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index 9d163ad9e..499c4ae77 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -611,8 +611,6 @@ docomplete(int lst) active = 1; comprecursive = 0; makecommaspecial(0); - if (undoing) - setlastline(); /* From the C-code's point of view, we can only use compctl as a default * type of completion. Load it if it hasn't been loaded already and @@ -1164,7 +1162,7 @@ get_comp_string(void) * being separated by tokens | & &! |& || &&). The loop stops when * * the end of the command containing the cursor is reached. What * * makes this messy is checking for things like redirections, loops * - * and whatnot. */ + * and whatnot. */ do { qsub = noword = 0; @@ -2797,6 +2795,7 @@ doexpandhist(void) if (!err) { zlemetacs = excs; if (strcmp(zlemetaline, ol)) { + zle_free_positions(); unmetafy_line(); /* For vi mode -- reset the beginning-of-insertion pointer * * to the beginning of the line. This seems a little silly, * diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c index b82e54ce5..1089e274f 100644 --- a/Src/Zle/zle_utils.c +++ b/Src/Zle/zle_utils.c @@ -710,6 +710,27 @@ zle_restore_positions(void) } /* + * Discard positions previously saved, the line has been updated. + */ + +/**/ +mod_export void +zle_free_positions(void) +{ + struct zle_position *oldpos = zle_positions; + struct zle_region *oldrhp; + + zle_positions = oldpos->next; + oldrhp = oldpos->regions; + while (oldrhp) { + struct zle_region *nextrhp = oldrhp->next; + zfree(oldrhp, sizeof(*oldrhp)); + oldrhp = nextrhp; + } + zfree(oldpos, sizeof(*oldpos)); +} + +/* * Basic utility functions for adding to line or removing from line. * At this level the counts supplied are raw character counts, so * the calling code must be aware of combining characters where @@ -1354,7 +1375,10 @@ handlesuffix(UNUSED(char **args)) /* head of the undo list, and the current position */ -static struct change *changes, *curchange; +/**/ +struct change *curchange; + +static struct change *changes; /* list of pending changes, not yet in the undo system */ @@ -1629,6 +1653,32 @@ viundochange(char **args) return undo(args); } +/**/ +int +splitundo(char **args) +{ + if (vistartchange >= 0) { + mergeundo(); + vistartchange = (curchange && curchange->prev) ? + curchange->prev->changeno : 0; + } + handleundo(); + return 0; +} + +/**/ +void +mergeundo(void) +{ + struct change *current; + for (current = curchange->prev; + current && current->prev && current->changeno > vistartchange+1; + current = current->prev) { + current->flags |= CH_PREV; + current->prev->flags |= CH_NEXT; + } +} + /* * Call a ZLE hook: a user-defined widget called at a specific point * within the line editor. diff --git a/Src/Zle/zle_vi.c b/Src/Zle/zle_vi.c index 173a49ef9..9e39143d0 100644 --- a/Src/Zle/zle_vi.c +++ b/Src/Zle/zle_vi.c @@ -67,15 +67,23 @@ int viinsbegin; static struct modifier lastmod; static int inrepeat, vichgrepeat; +/** + * im: >= 0: is an insertmode + * -1: skip setting insert mode + * -2: entering viins at start of editing from clean --- don't use + * inrepeat or lastchar, synthesise an i to enter insert mode. + */ + /**/ static void startvichange(int im) { if (im != -1) { - insmode = im; vichgflag = 1; + if (im > -1) + insmode = im; } - if (inrepeat) { + if (inrepeat && im != -2) { zmod = lastmod; inrepeat = vichgflag = 0; vichgrepeat = 1; @@ -84,7 +92,12 @@ startvichange(int im) if (vichgbuf) free(vichgbuf); vichgbuf = (char *)zalloc(vichgbufsz = 16); - vichgbuf[0] = lastchar; + if (im == -2) { + vichgbuf[0] = + zlell ? (insmode ? (zlecs < zlell ? 'i' : 'a') : 'R') : 'o'; + } else { + vichgbuf[0] = lastchar; + } vichgbufptr = 1; vichgrepeat = 0; } @@ -96,7 +109,7 @@ startvitext(int im) { startvichange(im); selectkeymap("main", 1); - undoing = 0; + vistartchange = (curchange && curchange->prev) ? curchange->prev->changeno : 0; viinsbegin = zlecs; } @@ -303,6 +316,18 @@ viinsert(UNUSED(char **args)) return 0; } +/* + * Go to vi insert mode when we first start the line editor. + * Iniialises some other stuff. + */ + +/**/ +void +viinsert_init(void) +{ + startvitext(-2); +} + /**/ int viinsertbol(UNUSED(char **args)) @@ -376,7 +401,7 @@ vichange(UNUSED(char **args)) forekill(c2 - zlecs, CUT_RAW); selectkeymap("main", 1); viinsbegin = zlecs; - undoing = 0; + vistartchange = (curchange && curchange->prev) ? curchange->prev->changeno : 0; } return ret; } @@ -561,7 +586,7 @@ vicmdmode(UNUSED(char **args)) { if (invicmdmode() || selectkeymap("vicmd", 0)) return 1; - undoing = 1; + mergeundo(); vichgflag = 0; if (zlecs != findbol()) DECCS(); diff --git a/Src/builtin.c b/Src/builtin.c index c3f0169c7..a2a3ad748 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -111,7 +111,7 @@ static struct builtin builtins[] = BUILTIN("return", BINF_PSPECIAL, bin_break, 0, 1, BIN_RETURN, NULL, NULL), BUILTIN("set", BINF_PSPECIAL | BINF_HANDLES_OPTS, bin_set, 0, -1, 0, NULL, NULL), BUILTIN("setopt", 0, bin_setopt, 0, -1, BIN_SETOPT, NULL, NULL), - BUILTIN("shift", BINF_PSPECIAL, bin_shift, 0, -1, 0, NULL, NULL), + BUILTIN("shift", BINF_PSPECIAL, bin_shift, 0, -1, 0, "p", NULL), BUILTIN("source", BINF_PSPECIAL, bin_dot, 1, -1, 0, NULL, NULL), BUILTIN("suspend", 0, bin_suspend, 0, 0, 0, "f", NULL), BUILTIN("test", BINF_HANDLES_OPTS, bin_test, 0, -1, BIN_TEST, NULL, NULL), @@ -1422,6 +1422,10 @@ bin_fc(char *nam, char **argv, Options ops, int func) unqueue_signals(); return 0; } + if (OPT_ISSET(ops,'I')) { + zwarnnam(nam, "-I requires one of -R/-W/-A"); + return 1; + } if (zleactive) { zwarnnam(nam, "no interactive history within ZLE"); @@ -1727,7 +1731,7 @@ fclist(FILE *f, Options ops, zlong first, zlong last, if (tdfmt != NULL) { struct tm *ltm; ltm = localtime(&ent->stim); - if (ztrftime(timebuf, 256, tdfmt, ltm)) + if (ztrftime(timebuf, 256, tdfmt, ltm, 0L)) fprintf(f, "%s ", timebuf); } /* display the time taken by the command, if required */ @@ -4509,7 +4513,7 @@ bin_print(char *name, char **args, Options ops, int func) /**/ int -bin_shift(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) +bin_shift(char *name, char **argv, Options ops, UNUSED(int func)) { int num = 1, l, ret = 0; char **s; @@ -4533,7 +4537,19 @@ bin_shift(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) ret++; continue; } - s = zarrdup(s + num); + if (OPT_ISSET(ops,'p')) { + char **s2, **src, **dst; + int count; + l = arrlen(s); + src = s; + dst = s2 = (char **)zalloc((l - num + 1) * sizeof(char *)); + for (count = l - num; count; count--) + *dst++ = ztrdup(*src++); + *dst = NULL; + s = s2; + } else { + s = zarrdup(s + num); + } setaparam(*argv, s); } } else { @@ -4542,9 +4558,16 @@ bin_shift(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) ret = 1; } else { s = zalloc((l - num + 1) * sizeof(char *)); - memcpy(s, pparams + num, (l - num + 1) * sizeof(char *)); - while (num--) - zsfree(pparams[num]); + if (OPT_ISSET(ops,'p')) { + memcpy(s, pparams, (l - num) * sizeof(char *)); + s[l-num] = NULL; + while (num--) + zsfree(pparams[l-1-num]); + } else { + memcpy(s, pparams + num, (l - num + 1) * sizeof(char *)); + while (num--) + zsfree(pparams[num]); + } zfree(pparams, (l + 1) * sizeof(char *)); pparams = s; } @@ -4669,9 +4692,10 @@ exit_pending; int bin_break(char *name, char **argv, UNUSED(Options ops), int func) { - int num = lastval, nump = 0; + int num = lastval, nump = 0, implicit; /* handle one optional numeric argument */ + implicit = !*argv; if (*argv) { num = mathevali(*argv++); nump = 1; @@ -4702,7 +4726,13 @@ bin_break(char *name, char **argv, UNUSED(Options ops), int func) retflag = 1; breaks = loops; lastval = num; - if (trap_state == TRAP_STATE_PRIMED && trap_return == -2) { + if (trap_state == TRAP_STATE_PRIMED && trap_return == -2 + /* + * With POSIX, "return" on its own in a trap doesn't + * update $? --- we keep the status from before the + * trap. + */ + && !(isset(POSIXTRAPS) && implicit)) { trap_state = TRAP_STATE_FORCE_RETURN; trap_return = lastval; } @@ -6069,8 +6099,9 @@ bin_test(char *name, char **argv, UNUSED(Options ops), int func) } /* display a time, provided in units of 1/60s, as minutes and seconds */ -#define pttime(X) printf("%ldm%ld.%02lds",((long) (X))/3600,\ - ((long) (X))/60%60,((long) (X))*100/60%100) +#define pttime(X) printf("%ldm%ld.%02lds",((long) (X))/(60 * clktck),\ + ((long) (X))/clktck%clktck,\ + ((long) (X))*100/clktck%100) /* times: display, in a two-line format, the times provided by times(3) */ @@ -6079,6 +6110,7 @@ int bin_times(UNUSED(char *name), UNUSED(char **argv), UNUSED(Options ops), UNUSED(int func)) { struct tms buf; + long clktck = get_clktck(); /* get time accounting information */ if (times(&buf) == -1) diff --git a/Src/compat.c b/Src/compat.c index cc4e876da..b0bcb6265 100644 --- a/Src/compat.c +++ b/Src/compat.c @@ -37,7 +37,7 @@ char * strstr(const char *s, const char *t) { - char *p1, *p2; + const char *p1, *p2; for (; *s; s++) { for (p1 = s, p2 = t; *p2; p1++, p2++) diff --git a/Src/cond.c b/Src/cond.c index c67354297..df9065660 100644 --- a/Src/cond.c +++ b/Src/cond.c @@ -37,6 +37,21 @@ static char *condstr[COND_MOD] = { "-ne", "-lt", "-gt", "-le", "-ge", "=~" }; +static void cond_subst(char **strp, int glob_ok) +{ + if (glob_ok && + checkglobqual(*strp, strlen(*strp), 1, NULL)) { + LinkList args = newlinklist(); + addlinknode(args, *strp); + prefork(args, 0); + while (!errflag && args && nonempty(args) && + has_token((char *)peekfirst(args))) + zglob(args, firstnode(args), 0); + *strp = sepjoin(hlinklist2array(args, 0), NULL, 1); + } else + singsub(strp); +} + /* * Evaluate a conditional expression given the arguments. * If fromtest is set, the caller is the test or [ builtin; @@ -177,13 +192,13 @@ evalcond(Estate state, char *fromtest) } left = ecgetstr(state, EC_DUPTOK, &htok); if (htok) { - singsub(&left); + cond_subst(&left, !fromtest); untokenize(left); } if (ctype <= COND_GE && ctype != COND_STREQ && ctype != COND_STRNEQ) { right = ecgetstr(state, EC_DUPTOK, &htok); if (htok) { - singsub(&right); + cond_subst(&right, !fromtest); untokenize(right); } } @@ -194,7 +209,7 @@ evalcond(Estate state, char *fromtest) fprintf(xtrerr, " %s ", condstr[ctype]); if (ctype == COND_STREQ || ctype == COND_STRNEQ) { char *rt = dupstring(ecrawstr(state->prog, state->pc, NULL)); - singsub(&rt); + cond_subst(&rt, !fromtest); quote_tokenized_output(rt, xtrerr); } else @@ -282,8 +297,7 @@ evalcond(Estate state, char *fromtest) right = dupstring(opat = ecrawstr(state->prog, state->pc, &htok)); - if (htok) - singsub(&right); + singsub(&right); save = (!(state->prog->flags & EF_HEAP) && !strcmp(opat, right) && pprog != dummy_patprog2); diff --git a/Src/exec.c b/Src/exec.c index f16cfd391..5ad957f98 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -2346,7 +2346,7 @@ execsubst(LinkList strs) { if (strs) { prefork(strs, esprefork); - if (esglob) { + if (esglob && !errflag) { LinkList ostrs = strs; globlist(strs, 0); strs = ostrs; @@ -3867,8 +3867,10 @@ getoutputfile(char *cmd, char **eptr) int fd; char *s; - if (thisjob == -1) + if (thisjob == -1){ + zerr("process substitution %s cannot be used here", cmd); return NULL; + } if (!(prog = parsecmd(cmd, eptr))) return NULL; if (!(nam = gettempname(NULL, 0))) @@ -3939,11 +3941,13 @@ namedpipe(void) char *tnam = gettempname(NULL, 1); # ifdef HAVE_MKFIFO - if (mkfifo(tnam, 0600) < 0) + if (mkfifo(tnam, 0600) < 0){ # else - if (mknod(tnam, 0010600, 0) < 0) + if (mknod(tnam, 0010600, 0) < 0){ # endif + zerr("failed to create named pipe: %s, %e", tnam, errno); return NULL; + } return tnam; } #endif /* ! PATH_DEV_FD && HAVE_FIFOS */ @@ -3966,9 +3970,10 @@ getproc(char *cmd, char **eptr) #ifndef PATH_DEV_FD int fd; - - if (thisjob == -1) + if (thisjob == -1) { + zerr("process substitution %s cannot be used here", cmd); return NULL; + } if (!(pnam = namedpipe())) return NULL; if (!(prog = parsecmd(cmd, eptr))) @@ -3993,8 +3998,10 @@ getproc(char *cmd, char **eptr) #else /* PATH_DEV_FD */ int pipes[2], fd; - if (thisjob == -1) + if (thisjob == -1) { + zerr("process substitution %s cannot be used here", cmd); return NULL; + } pnam = hcalloc(strlen(PATH_DEV_FD) + 6); if (!(prog = parsecmd(cmd, eptr))) return NULL; @@ -4234,8 +4241,13 @@ execfuncdef(Estate state, UNUSED(int do_exec)) plen = nprg * sizeof(wordcode); len = plen + (npats * sizeof(Patprog)) + nstrs; - if (htok && names) + if (htok && names) { execsubst(names); + if (errflag) { + state->pc = end; + return 1; + } + } while (!names || (s = (char *) ugetnode(names))) { if (!names) { @@ -4291,8 +4303,13 @@ execfuncdef(Estate state, UNUSED(int do_exec)) end += *state->pc++; args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok); - if (htok && args) + if (htok && args) { execsubst(args); + if (errflag) { + state->pc = end; + return 1; + } + } if (!args) args = newlinklist(); @@ -4597,7 +4614,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) char *name = shfunc->node.nam; int flags = shfunc->node.flags, ooflags; char *fname = dupstring(name); - int obreaks, saveemulation, restore_sticky; + int obreaks, ocontflag, oloops, saveemulation, restore_sticky; Eprog prog; struct funcstack fstack; static int oflags; @@ -4609,7 +4626,9 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) pushheap(); oargv0 = NULL; - obreaks = breaks;; + obreaks = breaks; + ocontflag = contflag; + oloops = loops; if (trap_state == TRAP_STATE_PRIMED) trap_return--; oldlastval = lastval; @@ -4797,6 +4816,17 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) opts[XTRACE] = saveopts[XTRACE]; opts[PRINTEXITVALUE] = saveopts[PRINTEXITVALUE]; opts[LOCALOPTIONS] = saveopts[LOCALOPTIONS]; + opts[LOCALLOOPS] = saveopts[LOCALLOOPS]; + } + + if (opts[LOCALLOOPS]) { + if (contflag) + zwarn("`continue' active at end of function scope"); + if (breaks) + zwarn("`break' active at end of function scope"); + breaks = obreaks; + contflag = ocontflag; + loops = oloops; } endtrapscope(); diff --git a/Src/glob.c b/Src/glob.c index e0d0cf68e..627166c7a 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -120,6 +120,8 @@ typedef struct stat *Statptr; /* This makes the Ultrix compiler happy. Go figu #define TT_POSIX_BLOCKS 1 #define TT_KILOBYTES 2 #define TT_MEGABYTES 3 +#define TT_GIGABYTES 4 +#define TT_TERABYTES 5 typedef int (*TestMatchFunc) _((char *, struct stat *, off_t, char *)); @@ -443,6 +445,7 @@ insert(char *s, int checked) break; } unqueue_signals(); + return; } /* Do the globbing: scanner is called recursively * @@ -451,7 +454,7 @@ insert(char *s, int checked) /**/ static void -scanner(Complist q) +scanner(Complist q, int shortcircuit) { Patprog p; int closure; @@ -459,16 +462,19 @@ scanner(Complist q) int errssofar = errsfound; struct dirsav ds; - init_dirsav(&ds); if (!q) return; + init_dirsav(&ds); if ((closure = q->closure)) { /* (foo/)# - match zero or more dirs */ if (q->closure == 2) /* (foo/)## - match one or more dirs */ q->closure = 1; - else - scanner(q->next); + else { + scanner(q->next, shortcircuit); + if (shortcircuit && shortcircuit == matchct) + return; + } } p = q->pat; /* Now the actual matching for the current path section. */ @@ -513,8 +519,11 @@ scanner(Complist q) } if (add) { addpath(str, l); - if (!closure || !statfullpath("", NULL, 1)) - scanner((q->closure) ? q : q->next); + if (!closure || !statfullpath("", NULL, 1)) { + scanner((q->closure) ? q : q->next, shortcircuit); + if (shortcircuit && shortcircuit == matchct) + return; + } pathbuf[pathpos = oppos] = '\0'; } } @@ -522,6 +531,8 @@ scanner(Complist q) if (str[l]) str = dupstrpfx(str, l); insert(str, 0); + if (shortcircuit && shortcircuit == matchct) + return; } } else { /* Do pattern matching on current path section. */ @@ -609,9 +620,12 @@ scanner(Complist q) memcpy(subdirs + subdirlen, (char *)&errsfound, sizeof(int)); subdirlen += sizeof(int); - } else + } else { /* if the last filename component, just add it */ insert(fn, 1); + if (shortcircuit && shortcircuit == matchct) + return; + } } } closedir(lock); @@ -624,7 +638,10 @@ scanner(Complist q) fn += l + 1; memcpy((char *)&errsfound, fn, sizeof(int)); fn += sizeof(int); - scanner((q->closure) ? q : q->next); /* scan next level */ + /* scan next level */ + scanner((q->closure) ? q : q->next, shortcircuit); + if (shortcircuit && shortcircuit == matchct) + return; pathbuf[pathpos = oppos] = '\0'; } hrealloc(subdirs, subdirlen, 0); @@ -638,6 +655,7 @@ scanner(Complist q) close(ds.dirfd); pathbufcwd = pbcwdsav; } + return; } /* This function tokenizes a zsh glob pattern */ @@ -1059,6 +1077,67 @@ insert_glob_match(LinkList list, LinkNode next, char *data) insertlinknode(list, next, data); } +/* + * Return + * 1 if str ends in bare glob qualifiers + * 2 if str ends in non-bare glob qualifiers (#q) + * 0 otherwise. + * + * str is the string to check. + * sl is its length (to avoid recalculation). + * nobareglob is 1 if bare glob qualifiers are not allowed. + * *sp, if sp is not null, will be a pointer to the opening parenthesis. + */ + +/**/ +int +checkglobqual(char *str, int sl, int nobareglob, char **sp) +{ + char *s; + int paren, ret = 1; + + if (str[sl - 1] != Outpar) + return 0; + + /* Check these are really qualifiers, not a set of * + * alternatives or exclusions. We can be more * + * lenient with an explicit (#q) than with a bare * + * set of qualifiers. */ + paren = 0; + for (s = str + sl - 2; *s && (*s != Inpar || paren); s--) { + switch (*s) { + case Outpar: + paren++; /*FALLTHROUGH*/ + case Bar: + if (!zpc_disables[ZPC_BAR]) + nobareglob = 1; + break; + case Tilde: + if (isset(EXTENDEDGLOB) && !zpc_disables[ZPC_TILDE]) + nobareglob = 1; + break; + case Inpar: + paren--; + break; + } + if (s == str) + break; + } + if (*s != Inpar) + return 0; + if (isset(EXTENDEDGLOB) && !zpc_disables[ZPC_HASH] && s[1] == Pound) { + if (s[2] != 'q') + return 0; + ret = 2; + } else if (nobareglob) + return 0; + + if (sp) + *sp = s; + + return ret; +} + /* Main entry point to the globbing code for filename globbing. * * np points to a node in the list list which will be expanded * * into a series of nodes. */ @@ -1078,6 +1157,8 @@ zglob(LinkList list, LinkNode np, int nountok) /* and index+1 of the last match */ struct globdata saved; /* saved glob state */ int nobareglob = !isset(BAREGLOBQUAL); + int shortcircuit = 0; /* How many files to match; */ + /* 0 means no limit */ if (unset(GLOBOPT) || !haswilds(ostr) || unset(EXECOPT)) { if (!nountok) @@ -1116,7 +1197,7 @@ zglob(LinkList list, LinkNode np, int nountok) (isset(EXTENDEDGLOB) && !zpc_disables[ZPC_HASH])) { struct qual *newquals; char *s; - int sense, paren; + int sense, qualsfound; off_t data; char *sdata, *newcolonmod; int (*func) _((char *, Statptr, off_t, char *)); @@ -1146,40 +1227,7 @@ zglob(LinkList list, LinkNode np, int nountok) newquals = qo = qn = ql = NULL; sl = strlen(str); - if (str[sl - 1] != Outpar) - break; - - /* Check these are really qualifiers, not a set of * - * alternatives or exclusions. We can be more * - * lenient with an explicit (#q) than with a bare * - * set of qualifiers. */ - paren = 0; - for (s = str + sl - 2; *s && (*s != Inpar || paren); s--) { - switch (*s) { - case Outpar: - paren++; /*FALLTHROUGH*/ - case Bar: - if (!zpc_disables[ZPC_BAR]) - nobareglob = 1; - break; - case Tilde: - if (isset(EXTENDEDGLOB) && !zpc_disables[ZPC_TILDE]) - nobareglob = 1; - break; - case Inpar: - paren--; - break; - } - } - if (*s != Inpar) - break; - if (isset(EXTENDEDGLOB) && !zpc_disables[ZPC_HASH] && s[1] == Pound) { - if (s[2] == 'q') { - *s = 0; - s += 2; - } else - break; - } else if (nobareglob) + if (!(qualsfound = checkglobqual(str, sl, nobareglob, &s))) break; /* Real qualifiers found. */ @@ -1192,6 +1240,8 @@ zglob(LinkList list, LinkNode np, int nountok) str[sl-1] = 0; *s++ = 0; + if (qualsfound == 2) + s += 2; while (*s && !newcolonmod) { func = (int (*) _((char *, Statptr, off_t, char *)))0; if (idigit(*s)) { @@ -1362,7 +1412,7 @@ zglob(LinkList list, LinkNode np, int nountok) /* Find matching delimiters */ tt = get_strarg(s, &arglen); if (!*tt) { - zerr("missing end of name"); + zerr("missing delimiter for 'u' glob qualifier"); data = 0; } else { #ifdef USE_GETPWNAM @@ -1402,7 +1452,7 @@ zglob(LinkList list, LinkNode np, int nountok) tt = get_strarg(s, &arglen); if (!*tt) { - zerr("missing end of name"); + zerr("missing delimiter for 'g' glob qualifier"); data = 0; } else { #ifdef USE_GETGRNAM @@ -1459,6 +1509,23 @@ zglob(LinkList list, LinkNode np, int nountok) /* Numeric glob sort */ gf_numsort = !(sense & 1); break; + case 'Y': + { + /* Short circuit: limit number of matches */ + const char *s_saved = s; + shortcircuit = !(sense & 1); + if (shortcircuit) { + /* Parse the argument. */ + data = qgetnum(&s); + if ((shortcircuit = data) != data) { + /* Integer overflow */ + zerr("value too big: Y%s", s_saved); + restore_globstate(saved); + return; + } + } + break; + } case 'a': /* Access time in given range */ g_amc = 0; @@ -1486,6 +1553,12 @@ zglob(LinkList list, LinkNode np, int nountok) g_units = TT_KILOBYTES, ++s; else if (*s == 'm' || *s == 'M') g_units = TT_MEGABYTES, ++s; +#if defined(ZSH_64_BIT_TYPE) || defined(LONG_IS_64_BIT) + else if (*s == 'g' || *s == 'G') + g_units = TT_GIGABYTES, ++s; + else if (*s == 't' || *s == 'T') + g_units = TT_TERABYTES, ++s; +#endif getrange: /* Get time multiplier */ if (g_amc >= 0) { @@ -1549,9 +1622,10 @@ zglob(LinkList list, LinkNode np, int nountok) restore_globstate(saved); return; } + if ((sense & 2) && + (t & (GS_SIZE|GS_ATIME|GS_MTIME|GS_CTIME|GS_LINKS))) + t <<= GS_SHIFT; /* HERE: GS_EXEC? */ if (t != GS_EXEC) { - if ((sense & 2) && !(t & (GS_NAME|GS_DEPTH))) - t <<= GS_SHIFT; /* HERE: GS_EXEC? */ if (gf_sorts & t) { zerr("doubled sort specifier"); restore_globstate(saved); @@ -1709,7 +1783,7 @@ zglob(LinkList list, LinkNode np, int nountok) return; } if (!gf_nsorts) { - gf_sortlist[0].tp = gf_sorts = GS_NAME; + gf_sortlist[0].tp = gf_sorts = (shortcircuit ? GS_NONE : GS_NAME); gf_nsorts = 1; } /* Initialise receptacle for matched files, * @@ -1721,7 +1795,7 @@ zglob(LinkList list, LinkNode np, int nountok) /* The actual processing takes place here: matches go into * * matchbuf. This is the only top-level call to scanner(). */ - scanner(q); + scanner(q, shortcircuit); /* Deal with failures to match depending on options */ if (matchct) @@ -1832,6 +1906,8 @@ zglob(LinkList list, LinkNode np, int nountok) matchptr++; } } + } else if (!badcshglob && !isset(NOMATCH) && matchct == 1) { + insert_glob_match(list, node, (--matchptr)->name); } free(matchbuf); @@ -1895,6 +1971,8 @@ hasbraces(char *str) switch (*str++) { case Inbrace: if (!lbr) { + if (bracechardots(str-1, NULL, NULL)) + return 1; lbr = str - 1; if (*str == '-') str++; @@ -2027,6 +2105,68 @@ xpandredir(struct redir *fn, LinkList redirtab) return ret; } +/* + * Check for a brace expansion of the form {<char>..<char>}. + * On input str must be positioned at an Inbrace, but the sequence + * of characters beyond that has not necessarily been checked. + * Return 1 if found else 0. + * + * The other parameters are optionaland if the function returns 1 are + * used to return: + * - *c1p: the first character in the expansion. + * - *c2p: the final character in the expansion. + */ + +/**/ +static int +bracechardots(char *str, convchar_t *c1p, convchar_t *c2p) +{ + convchar_t cstart, cend; + char *pnext = str + 1, *pconv, convstr[2]; + if (itok(*pnext)) { + if (*pnext == Inbrace) + return 0; + convstr[0] = ztokens[*pnext - Pound]; + convstr[1] = '\0'; + pconv = convstr; + } else + pconv = pnext; + MB_METACHARINIT(); + pnext += MB_METACHARLENCONV(pconv, &cstart); + if ( +#ifdef MULTIBYTE_SUPPORT + cstart == WEOF || +#else + !cstart || +#endif + pnext[0] != '.' || pnext[1] != '.') + return 0; + pnext += 2; + if (itok(*pnext)) { + if (*pnext == Inbrace) + return 0; + convstr[0] = ztokens[*pnext - Pound]; + convstr[1] = '\0'; + pconv = convstr; + } else + pconv = pnext; + MB_METACHARINIT(); + pnext += MB_METACHARLENCONV(pconv, &cend); + if ( +#ifdef MULTIBYTE_SUPPORT + cend == WEOF || +#else + !cend || +#endif + *pnext != Outbrace) + return 0; + if (c1p) + *c1p = cstart; + if (c2p) + *c2p = cend; + return 1; +} + /* brace expansion */ /**/ @@ -2060,10 +2200,57 @@ xpandbraces(LinkList list, LinkNode *np) char *dots, *p, *dots2 = NULL; LinkNode olast = last; /* Get the first number of the range */ - zlong rstart = zstrtol(str+1,&dots,10), rend = 0; + zlong rstart, rend; int err = 0, rev = 0, rincr = 1; - int wid1 = (dots - str) - 1, wid2 = (str2 - dots) - 2, wid3 = 0; - int strp = str - str3; + int wid1, wid2, wid3, strp; + convchar_t cstart, cend; + + if (bracechardots(str, &cstart, &cend)) { + int lenalloc; + /* + * This is a character range. + */ + if (cend < cstart) { + convchar_t ctmp = cend; + cend = cstart; + cstart = ctmp; + rev = 1; + } + uremnode(list, node); + strp = str - str3; + lenalloc = strp + strlen(str2+1) + 1; + for (; cend >= cstart; cend--) { +#ifdef MULTIBYTE_SUPPORT + char *ncptr; + int nclen; + mb_metacharinit(); + ncptr = wcs_nicechar(cend, NULL, NULL); + nclen = strlen(ncptr); + p = zhalloc(lenalloc + nclen); + memcpy(p, str3, strp); + memcpy(p + strp, ncptr, nclen); + strcpy(p + strp + nclen, str2 + 1); +#else + p = zhalloc(lenalloc + 1); + memcpy(p, str3, strp); + sprintf(p + strp, "%c", cend); + strcat(p + strp, str2 + 1); +#endif + insertlinknode(list, last, p); + if (rev) /* decreasing: add in reverse order. */ + last = nextnode(last); + } + *np = nextnode(olast); + return; + } + + /* Get the first number of the range */ + rstart = zstrtol(str+1,&dots,10); + rend = 0; + wid1 = (dots - str) - 1; + wid2 = (str2 - dots) - 2; + wid3 = 0; + strp = str - str3; if (dots == str + 1 || *dots != '.' || dots[1] != '.') err++; @@ -3443,9 +3630,9 @@ qualiscom(UNUSED(char *name), struct stat *buf, UNUSED(off_t mod), UNUSED(char * static int qualsize(UNUSED(char *name), struct stat *buf, off_t size, UNUSED(char *dummy)) { -#if defined(LONG_IS_64_BIT) || defined(OFF_T_IS_64_BIT) +#if defined(ZSH_64_BIT_TYPE) || defined(LONG_IS_64_BIT) # define QS_CAST_SIZE() - off_t scaled = buf->st_size; + zlong scaled = buf->st_size; #else # define QS_CAST_SIZE() (unsigned long) unsigned long scaled = (unsigned long)buf->st_size; @@ -3464,6 +3651,16 @@ qualsize(UNUSED(char *name), struct stat *buf, off_t size, UNUSED(char *dummy)) scaled += 1048575l; scaled /= 1048576l; break; +#if defined(ZSH_64_BIT_TYPE) || defined(LONG_IS_64_BIT) + case TT_GIGABYTES: + scaled += ZLONG_CONST(1073741823); + scaled /= ZLONG_CONST(1073741824); + break; + case TT_TERABYTES: + scaled += ZLONG_CONST(1099511627775); + scaled /= ZLONG_CONST(1099511627776); + break; +#endif } return (g_range < 0 ? scaled < QS_CAST_SIZE() size : diff --git a/Src/hist.c b/Src/hist.c index 1845bd8ad..770d559b1 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -935,9 +935,11 @@ hbegin(int dohist) hf = getsparam("HISTFILE"); /* - * For INCAPPENDHISTORY, when interactive, save the history here + * For INCAPPENDHISTORYTIME, when interactive, save the history here * as it gives a better estimate of the times of commands. * + * If INCAPPENDHISTORY is also set we've already done it. + * * If SHAREHISTORY is also set continue to do so in the * standard place, because that's safer about reading and * rewriting history atomically. @@ -950,7 +952,8 @@ hbegin(int dohist) * so that (correctly) nothing happens here. But it shows * I thought about it. */ - if (isset(INCAPPENDHISTORY) && !isset(SHAREHISTORY) && + if (isset(INCAPPENDHISTORYTIME) && !isset(SHAREHISTORY) && + !isset(INCAPPENDHISTORY) && !(histactive & HA_NOINC) && !strin && histsave_stack_pos == 0) savehistfile(hf, 0, HFILE_USE_OPTIONS | HFILE_FAST); } @@ -1378,7 +1381,8 @@ hend(Eprog prog) * For normal INCAPPENDHISTORY case and reasoning, see hbegin(). */ if (isset(SHAREHISTORY) ? histfileIsLocked() : - (isset(INCAPPENDHISTORY) && histsave_stack_pos != 0)) + (isset(INCAPPENDHISTORY) || (isset(INCAPPENDHISTORYTIME) && + histsave_stack_pos != 0))) savehistfile(hf, 0, HFILE_USE_OPTIONS | HFILE_FAST); unlockhistfile(hf); /* It's OK to call this even if we aren't locked */ /* @@ -1764,7 +1768,8 @@ chrealpath(char **junkptr) str++; } - *junkptr = metafy(bicat(real, nonreal), -1, META_HEAPDUP); + *junkptr = metafy(str = bicat(real, nonreal), -1, META_HEAPDUP); + zsfree(str); #ifdef HAVE_CANONICALIZE_FILE_NAME free(real); #endif @@ -2303,8 +2308,7 @@ readhistline(int start, char **bufp, int *bufsiz, FILE *in) } else { buf[len - 1] = '\0'; - if (len > 1 && buf[len - 2] == '\\' && - (len < 3 || buf[len - 3] != '\\')) { + if (len > 1 && buf[len - 2] == '\\') { buf[--len - 1] = '\n'; if (!feof(in)) return readhistline(len, bufp, bufsiz, in); @@ -2541,7 +2545,7 @@ savehistfile(char *fn, int err, int writeflags) } if (writeflags & HFILE_USE_OPTIONS) { if (isset(APPENDHISTORY) || isset(INCAPPENDHISTORY) - || isset(SHAREHISTORY)) + || isset(INCAPPENDHISTORYTIME) || isset(SHAREHISTORY)) writeflags |= HFILE_APPEND | HFILE_SKIPOLD; else histfile_linect = 0; @@ -2577,7 +2581,7 @@ savehistfile(char *fn, int err, int writeflags) tmpfile = NULL; if (err) { if (isset(APPENDHISTORY) || isset(INCAPPENDHISTORY) - || isset(SHAREHISTORY)) + || isset(INCAPPENDHISTORYTIME) || isset(SHAREHISTORY)) zerr("rewriting %s would change its ownership -- skipped", fn); else zerr("rewriting %s would change its ownership -- history not saved", fn); @@ -2613,6 +2617,8 @@ savehistfile(char *fn, int err, int writeflags) ret = 0; for (; he && he->histnum <= xcurhist; he = down_histent(he)) { + int count_backslashes = 0; + if ((writeflags & HFILE_SKIPDUPS && he->node.flags & HIST_DUP) || (writeflags & HFILE_SKIPFOREIGN && he->node.flags & HIST_FOREIGN) || he->node.flags & HIST_TMPSTORE) @@ -2644,9 +2650,18 @@ savehistfile(char *fn, int err, int writeflags) if (*t == '\n') if ((ret = fputc('\\', out)) < 0) break; + if (*t == '\\') + count_backslashes++; + else + count_backslashes = 0; if ((ret = fputc(*t, out)) < 0) break; } + if (ret < 0) + break; + if (count_backslashes && (count_backslashes % 2 == 0)) + if ((ret = fputc(' ', out)) < 0) + break; if (ret < 0 || (ret = fputc('\n', out)) < 0) break; } @@ -2719,6 +2734,25 @@ savehistfile(char *fn, int err, int writeflags) static int lockhistct; +static int +checklocktime(char *lockfile, time_t then) +{ + time_t now = time(NULL); + + if (now + 10 < then) { + /* File is more than 10 seconds in the future? */ + errno = EEXIST; + return -1; + } + + if (now - then < 10) + sleep(1); + else + unlink(lockfile); + + return 0; +} + /* * Lock history file. Return 0 on success, 1 on failure to lock this * time, 2 on permanent failure (e.g. permission). @@ -2736,9 +2770,7 @@ lockhistfile(char *fn, int keep_trying) #ifdef HAVE_FCNTL_H if (isset(HISTFCNTLLOCK) && flock_fd < 0) { - ret = flockhistfile(fn, keep_trying); - if (ret) - return ret; + return flockhistfile(fn, keep_trying); } #endif @@ -2775,10 +2807,10 @@ lockhistfile(char *fn, int keep_trying) continue; break; } - if (time(NULL) - sb.st_mtime < 10) - sleep(1); - else - unlink(lockfile); + if (checklocktime(lockfile, sb.st_mtime) < 0) { + ret = 1; + break; + } } if (fd < 0) lockhistct--; @@ -2803,10 +2835,10 @@ lockhistfile(char *fn, int keep_trying) continue; ret = 2; } else { - if (time(NULL) - sb.st_mtime < 10) - sleep(1); - else - unlink(lockfile); + if (checklocktime(lockfile, sb.st_mtime) < 0) { + ret = 1; + break; + } continue; } lockhistct--; @@ -2831,10 +2863,10 @@ lockhistfile(char *fn, int keep_trying) ret = 2; break; } - if (time(NULL) - sb.st_mtime < 10) - sleep(1); - else - unlink(lockfile); + if (checklocktime(lockfile, sb.st_mtime) < 0) { + ret = 1; + break; + } } if (fd < 0) lockhistct--; diff --git a/Src/init.c b/Src/init.c index f5aae71f2..5e92f59df 100644 --- a/Src/init.c +++ b/Src/init.c @@ -77,7 +77,7 @@ mod_export int tclen[TC_COUNT]; /**/ int tclines, tccolumns; /**/ -mod_export int hasam, hasxn, hasye; +mod_export int hasam, hasbw, hasxn, hasye; /* Value of the Co (max_colors) entry: may not be set */ @@ -226,7 +226,7 @@ parseargs(char **argv, char **runscript) char **x; LinkList paramlist; - argzero = *argv++; + argzero = posixzero = *argv++; SHIN = 0; /* There's a bit of trickery with opts[INTERACTIVE] here. It starts * @@ -253,7 +253,7 @@ parseargs(char **argv, char **runscript) if (*argv) { if (unset(SHINSTDIN)) { if (cmd) - argzero = *argv; + argzero = posixzero = *argv; else *runscript = *argv; opts[INTERACTIVE] &= 1; @@ -275,6 +275,7 @@ parseargs(char **argv, char **runscript) while ((*x++ = (char *)getlinknode(paramlist))); free(paramlist); argzero = ztrdup(argzero); + posixzero = ztrdup(posixzero); } /* Insert into list in order of pointer value */ @@ -698,6 +699,7 @@ init_term(void) /* check whether terminal has automargin (wraparound) capability */ hasam = tgetflag("am"); + hasbw = tgetflag("bw"); hasxn = tgetflag("xn"); /* also check for newline wraparound glitch */ hasye = tgetflag("YE"); /* print in last column does carriage return */ @@ -749,9 +751,8 @@ init_term(void) tcstr[TCCLEARSCREEN] = ztrdup("\14"); tclen[TCCLEARSCREEN] = 1; } -#if 0 /* This might work, but there may be more to it */ - rprompt_indent = (hasye || !tccan(TCLEFT)) ? 1 : 0; -#endif + /* This might work, but there may be more to it */ + rprompt_indent = ((hasam && !hasbw) || hasye || !tccan(TCLEFT)); } return 1; } @@ -1003,15 +1004,6 @@ setupvals(void) setiparam("COLUMNS", zterm_columns); setiparam("LINES", zterm_lines); #endif - { - /* Import from environment, overrides init_term() */ - struct value vbuf; - char *name = "ZLE_RPROMPT_INDENT"; - if (getvalue(&vbuf, &name, 1) && !(vbuf.flags & PM_UNSET)) - rprompt_indent = getintvalue(&vbuf); - else - rprompt_indent = 1; - } #ifdef HAVE_GETRLIMIT for (i = 0; i != RLIM_NLIMITS; i++) { @@ -1535,7 +1527,7 @@ mod_export CompctlReadFn compctlreadptr = fallback_compctlread; mod_export int fallback_compctlread(char *name, UNUSED(char **args), UNUSED(Options ops), UNUSED(char *reply)) { - zwarnnam(name, "option valid only in functions called from completion"); + zwarnnam(name, "no loaded module provides read for completion context"); return 1; } diff --git a/Src/jobs.c b/Src/jobs.c index 871946598..c4a0707d4 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -618,13 +618,11 @@ setprevjob(void) } /**/ -#ifndef HAVE_GETRUSAGE -static long clktck = 0; - -/**/ -static void -set_clktck(void) +long +get_clktck(void) { + static long clktck; + #ifdef _SC_CLK_TCK if (!clktck) /* fetch clock ticks per second from * @@ -646,9 +644,9 @@ set_clktck(void) # endif # endif #endif + + return clktck; } -/**/ -#endif /**/ static void @@ -698,11 +696,13 @@ printtime(struct timeval *real, child_times_t *ti, char *desc) percent = 100.0 * total_time / (real->tv_sec + real->tv_usec / 1000000.0); #else - set_clktck(); - user_time = ti->ut / (double) clktck; - system_time = ti->st / (double) clktck; - percent = 100.0 * (ti->ut + ti->st) - / (clktck * real->tv_sec + clktck * real->tv_usec / 1000000.0); + { + long clktck = get_clktck(); + user_time = ti->ut / (double) clktck; + system_time = ti->st / (double) clktck; + percent = 100.0 * (ti->ut + ti->st) + / (clktck * real->tv_sec + clktck * real->tv_usec / 1000000.0); + } #endif queue_signals(); @@ -910,8 +910,10 @@ should_report_time(Job j) reporttime--; return reporttime <= 0; #else - set_clktck(); - return ((j->procs->ti.ut + j->procs->ti.st) / clktck >= reporttime); + { + clktck = get_clktck(); + return ((j->procs->ti.ut + j->procs->ti.st) / clktck >= reporttime); + } #endif } @@ -30,6 +30,8 @@ #include "zsh.mdh" #include "lex.pro" +#define LEX_HEAP_SIZE (32) + /* tokens */ /**/ @@ -721,7 +723,7 @@ gettok(void) /* word includes the last character read and possibly \ before ! */ if (dbparens) { len = 0; - bptr = tokstr = (char *) hcalloc(bsiz = 32); + bptr = tokstr = (char *) hcalloc(bsiz = LEX_HEAP_SIZE); hungetc(c); cmdpush(CS_MATH); c = dquote_parse(infor ? ';' : ')', 0); @@ -775,7 +777,7 @@ gettok(void) if (lexflags & LEXFLAGS_COMMENTS_KEEP) { len = 0; - bptr = tokstr = (char *)hcalloc(bsiz = 32); + bptr = tokstr = (char *)hcalloc(bsiz = LEX_HEAP_SIZE); add(c); } hwend(); @@ -877,7 +879,7 @@ gettok(void) } if (incmdpos || (isset(SHGLOB) && !isset(KSHGLOB))) { len = 0; - bptr = tokstr = (char *) hcalloc(bsiz = 32); + bptr = tokstr = (char *) hcalloc(bsiz = LEX_HEAP_SIZE); switch (cmd_or_math(CS_MATH)) { case 1: return DINPAR; @@ -1027,7 +1029,7 @@ gettokstr(int c, int sub) peek = STRING; if (!sub) { len = 0; - bptr = tokstr = (char *) hcalloc(bsiz = 32); + bptr = tokstr = (char *) hcalloc(bsiz = LEX_HEAP_SIZE); } for (;;) { int act; diff --git a/Src/loop.c b/Src/loop.c index 90a0761b3..2f639fd5a 100644 --- a/Src/loop.c +++ b/Src/loop.c @@ -73,7 +73,7 @@ execfor(Estate state, int do_exec) matheval(str); if (errflag) { state->pc = end; - return lastval = errflag; + return 1; } cond = ecgetstr(state, EC_NODUP, &ctok); advance = ecgetstr(state, EC_NODUP, &atok); @@ -87,8 +87,13 @@ execfor(Estate state, int do_exec) state->pc = end; return 0; } - if (htok) + if (htok) { execsubst(args); + if (errflag) { + state->pc = end; + return 1; + } + } } else { char **x; @@ -97,7 +102,7 @@ execfor(Estate state, int do_exec) addlinknode(args, dupstring(*x)); } } - lastval = 0; + /* lastval = 0; */ loops++; pushheap(); cmdpush(CS_FOR); @@ -223,15 +228,20 @@ execselect(Estate state, UNUSED(int do_exec)) state->pc = end; return 0; } - if (htok) + if (htok) { execsubst(args); + if (errflag) { + state->pc = end; + return 1; + } + } } if (!args || empty(args)) { state->pc = end; return 1; } loops++; - lastval = 0; + /* lastval = 0; */ pushheap(); cmdpush(CS_SELECT); usezle = interact && SHTTY != -1 && isset(USEZLE); diff --git a/Src/math.c b/Src/math.c index 42355f885..266569827 100644 --- a/Src/math.c +++ b/Src/math.c @@ -556,6 +556,9 @@ lexconstant(void) int outputradix; /**/ +int outputunderscore; + +/**/ static int zzlex(void) { @@ -713,7 +716,7 @@ zzlex(void) return EOI; case '[': { - int n; + int n, checkradix = 0; if (idigit(*ptr)) { n = zstrtol(ptr, &ptr, 10); @@ -730,9 +733,19 @@ zzlex(void) n = -1; ptr++; } - if (!idigit(*ptr)) + if (!idigit(*ptr) && *ptr != '_') goto bofs; - outputradix = n * zstrtol(ptr, &ptr, 10); + if (idigit(*ptr)) { + outputradix = n * zstrtol(ptr, &ptr, 10); + checkradix = 1; + } + if (*ptr == '_') { + ptr++; + if (idigit(*ptr)) + outputunderscore = zstrtol(ptr, &ptr, 10); + else + outputunderscore = 3; + } } else { bofs: zerr("bad output format specification"); @@ -740,11 +753,13 @@ zzlex(void) } if(*ptr != ']') goto bofs; - n = (outputradix < 0) ? -outputradix : outputradix; - if (n < 2 || n > 36) { - zerr("invalid base (must be 2 to 36 inclusive): %d", - outputradix); - return EOI; + if (checkradix) { + n = (outputradix < 0) ? -outputradix : outputradix; + if (n < 2 || n > 36) { + zerr("invalid base (must be 2 to 36 inclusive): %d", + outputradix); + return EOI; + } } ptr++; break; @@ -1337,9 +1352,9 @@ matheval(char *s) char *junk; mnumber x; int xmtok = mtok; - /* maintain outputradix across levels of evaluation */ + /* maintain outputradix and outputunderscore across levels of evaluation */ if (!mlevel) - outputradix = 0; + outputradix = outputunderscore = 0; if (!*s) { x.type = MN_INTEGER; @@ -226,6 +226,9 @@ old_heaps(Heap old) #else zfree(h, HEAPSIZE); #endif +#ifdef ZSH_VALGRIND + VALGRIND_DESTROY_MEMPOOL((char *)h); +#endif } heaps = old; #ifdef ZSH_HEAP_DEBUG @@ -319,23 +322,26 @@ freeheap(void) h_free++; #endif - /* At this point we used to do: - fheap = NULL; - * + /* * When pushheap() is called, it sweeps over the entire heaps list of * arenas and marks every one of them with the amount of free space in * that arena at that moment. zhalloc() is then allowed to grab bits * out of any of those arenas that have free space. * - * With the above reset of fheap, the loop below sweeps back over the + * Whenever fheap is NULL here, the loop below sweeps back over the * entire heap list again, resetting the free space in every arena to * the amount stashed by pushheap() and finding the first arena with * free space to optimize zhalloc()'s next search. When there's a lot * of stuff already on the heap, this is an enormous amount of work, * and performance goes to hell. * - * However, there doesn't seem to be any reason to reset fheap before - * beginning this loop. Either it's already correct, or it has never + * However, if the arena to which fheap points is unused, we want to + * free it, so we have no choice but to do the sweep for a new fheap. + */ + if (fheap && !fheap->sp) + fheap = NULL; /* We used to do this unconditionally */ + /* + * In other cases, either fheap is already correct, or it has never * been set and this loop will do it, or it'll be reset from scratch * on the next popheap(). So all that's needed here is to pick up * the scan wherever the last pass [or the last popheap()] left off. @@ -344,6 +350,10 @@ freeheap(void) hn = h->next; if (h->sp) { #ifdef ZSH_MEM_DEBUG +#ifdef ZSH_VALGRIND + VALGRIND_MAKE_MEM_UNDEFINED((char *)arena(h) + h->sp->used, + h->used - h->sp->used); +#endif memset(arena(h) + h->sp->used, 0xff, h->used - h->sp->used); #endif h->used = h->sp->used; @@ -366,12 +376,18 @@ freeheap(void) h->heap_id = new_id; } #endif +#ifdef ZSH_VALGRIND + VALGRIND_MEMPOOL_TRIM((char *)h, (char *)arena(h), h->used); +#endif } else { #ifdef USE_MMAP munmap((void *) h, h->size); #else zfree(h, HEAPSIZE); #endif +#ifdef ZSH_VALGRIND + VALGRIND_DESTROY_MEMPOOL((char *)h); +#endif } } if (hl) @@ -403,6 +419,10 @@ popheap(void) if ((hs = h->sp)) { h->sp = hs->next; #ifdef ZSH_MEM_DEBUG +#ifdef ZSH_VALGRIND + VALGRIND_MAKE_MEM_UNDEFINED((char *)arena(h) + hs->used, + h->used - hs->used); +#endif memset(arena(h) + hs->used, 0xff, h->used - hs->used); #endif h->used = hs->used; @@ -414,6 +434,9 @@ popheap(void) } h->heap_id = hs->heap_id; #endif +#ifdef ZSH_VALGRIND + VALGRIND_MEMPOOL_TRIM((char *)h, (char *)arena(h), h->used); +#endif if (!fheap && h->used < ARENA_SIZEOF(h)) fheap = h; zfree(hs, sizeof(*hs)); @@ -425,6 +448,9 @@ popheap(void) #else zfree(h, HEAPSIZE); #endif +#ifdef ZSH_VALGRIND + VALGRIND_DESTROY_MEMPOOL((char *)h); +#endif } } if (hl) @@ -496,6 +522,12 @@ zhalloc(size_t size) { Heap h; size_t n; +#ifdef ZSH_VALGRIND + size_t req_size = size; + + if (size == 0) + return NULL; +#endif size = (size + H_ISIZE - 1) & ~(H_ISIZE - 1); @@ -523,6 +555,9 @@ zhalloc(size_t size) HEAPID_FMT ".\n", h->heap_id); } #endif +#ifdef ZSH_VALGRIND + VALGRIND_MEMPOOL_ALLOC((char *)h, (char *)ret, req_size); +#endif return ret; } } @@ -561,6 +596,12 @@ zhalloc(size_t size) h->heap_id); } #endif +#ifdef ZSH_VALGRIND + VALGRIND_CREATE_MEMPOOL((char *)h, 0, 0); + VALGRIND_MAKE_MEM_NOACCESS((char *)arena(h), + n - ((char *)arena(h)-(char *)h)); + VALGRIND_MEMPOOL_ALLOC((char *)h, (char *)arena(h), req_size); +#endif if (hp) hp->next = h; @@ -586,13 +627,21 @@ hrealloc(char *p, size_t old, size_t new) { Heap h, ph; +#ifdef ZSH_VALGRIND + size_t new_req = new; +#endif + old = (old + H_ISIZE - 1) & ~(H_ISIZE - 1); new = (new + H_ISIZE - 1) & ~(H_ISIZE - 1); if (old == new) return p; if (!old && !p) +#ifdef ZSH_VALGRIND + return zhalloc(new_req); +#else return zhalloc(new); +#endif /* find the heap with p */ @@ -615,14 +664,33 @@ hrealloc(char *p, size_t old, size_t new) */ if (p + old < arena(h) + h->used) { if (new > old) { +#ifdef ZSH_VALGRIND + char *ptr = (char *) zhalloc(new_req); +#else char *ptr = (char *) zhalloc(new); +#endif memcpy(ptr, p, old); #ifdef ZSH_MEM_DEBUG memset(p, 0xff, old); #endif +#ifdef ZSH_VALGRIND + VALGRIND_MEMPOOL_FREE((char *)h, (char *)p); + /* + * zhalloc() marked h,ptr,new as an allocation so we don't + * need to do that here. + */ +#endif unqueue_signals(); return ptr; } else { +#ifdef ZSH_VALGRIND + VALGRIND_MEMPOOL_FREE((char *)h, (char *)p); + if (p) { + VALGRIND_MEMPOOL_ALLOC((char *)h, (char *)p, + new_req); + VALGRIND_MAKE_MEM_DEFINED((char *)h, (char *)p); + } +#endif unqueue_signals(); return new ? p : NULL; } @@ -657,10 +725,14 @@ hrealloc(char *p, size_t old, size_t new) #else zfree(h, HEAPSIZE); #endif +#ifdef ZSH_VALGRIND + VALGRIND_DESTROY_MEMPOOL((char *)h); +#endif unqueue_signals(); return NULL; } if (new > ARENA_SIZEOF(h)) { + Heap hnew; /* * Not enough memory in this heap. Allocate a new * one of sufficient size. @@ -682,17 +754,23 @@ hrealloc(char *p, size_t old, size_t new) * a mmap'd segment be extended, so simply allocate * a new one and copy. */ - Heap hnew; - hnew = mmap_heap_alloc(&n); /* Copy the entire heap, header (with next pointer) included */ memcpy(hnew, h, h->size); munmap((void *)h, h->size); - h = hnew; } #else - h = (Heap) realloc(h, n); + hnew = (Heap) realloc(h, n); #endif +#ifdef ZSH_VALGRIND + VALGRIND_MEMPOOL_FREE((char *)h, p); + VALGRIND_DESTROY_MEMPOOL((char *)h); + VALGRIND_CREATE_MEMPOOL((char *)hnew, 0, 0); + VALGRIND_MEMPOOL_ALLOC((char *)hnew, (char *)arena(hnew), + new_req); + VALGRIND_MAKE_MEM_DEFINED((char *)hnew, (char *)arena(hnew)); +#endif + h = hnew; h->size = n; if (ph) @@ -700,6 +778,13 @@ hrealloc(char *p, size_t old, size_t new) else heaps = h; } +#ifdef ZSH_VALGRIND + else { + VALGRIND_MEMPOOL_FREE((char *)h, (char *)p); + VALGRIND_MEMPOOL_ALLOC((char *)h, (char *)p, new_req); + VALGRIND_MAKE_MEM_DEFINED((char *)h, (char *)p); + } +#endif h->used = new; #ifdef ZSH_HEAP_DEBUG h->heap_id = heap_id; @@ -713,6 +798,11 @@ hrealloc(char *p, size_t old, size_t new) if (h->used + (new - old) <= ARENA_SIZEOF(h)) { h->used += new - old; unqueue_signals(); +#ifdef ZSH_VALGRIND + VALGRIND_MEMPOOL_FREE((char *)h, (char *)p); + VALGRIND_MEMPOOL_ALLOC((char *)h, (char *)p, new_req); + VALGRIND_MAKE_MEM_DEFINED((char *)h, (char *)p); +#endif return p; } else { char *t = zhalloc(new); @@ -721,6 +811,10 @@ hrealloc(char *p, size_t old, size_t new) #ifdef ZSH_MEM_DEBUG memset(p, 0xff, old); #endif +#ifdef ZSH_VALGRIND + VALGRIND_MEMPOOL_FREE((char *)h, (char *)p); + /* t already marked as allocated by zhalloc() */ +#endif unqueue_signals(); return t; } @@ -856,7 +950,10 @@ zrealloc(void *ptr, size_t size) ptr = NULL; } else { /* If ptr is NULL, then behave like malloc */ - ptr = malloc(size); + if (!(ptr = (void *) malloc(size))) { + zerr("fatal error: out of memory"); + exit(1); + } } unqueue_signals(); @@ -1505,7 +1602,7 @@ zsfree(char *p) MALLOC_RET_T realloc(MALLOC_RET_T p, MALLOC_ARG_T size) { - struct m_hdr *m = (struct m_hdr *)(((char *)p) - M_ISIZE), *mp, *mt; + struct m_hdr *m = (struct m_hdr *)(((char *)p) - M_ISIZE), *mt; char *r; int i, l = 0; @@ -1521,10 +1618,10 @@ realloc(MALLOC_RET_T p, MALLOC_ARG_T size) /* check if we are reallocating a small block, if we do, we have to compute the size of the block from the sort of block it is in */ for (i = 0; i < M_NSMALL; i++) { - for (mp = NULL, mt = m_small[i]; + for (mt = m_small[i]; mt && (((char *)mt) > ((char *)p) || (((char *)mt) + mt->len) < ((char *)p)); - mp = mt, mt = mt->next); + mt = mt->next); if (mt) { l = M_BSLEN(mt->len); diff --git a/Src/mkmakemod.sh b/Src/mkmakemod.sh index 2633c27d4..002160910 100644 --- a/Src/mkmakemod.sh +++ b/Src/mkmakemod.sh @@ -307,10 +307,10 @@ if $first_stage; then echo "\$(SYMS_${mddname}): \$(PROTODEPS)" echo echo "${mddname}.export: \$(SYMS_${mddname})" - echo " ( echo '#!'; cat \$(SYMS_${mddname}) | sed -n '/^X/{s/^X//;p;}' | sort -u ) > \$@" + echo " @( echo '#!'; cat \$(SYMS_${mddname}) | sed -n '/^X/{s/^X//;p;}' | sort -u ) > \$@" echo echo "modobjs.${mddname}: \$(MODOBJS_${mddname})" - echo " echo '' \$(MODOBJS_${mddname}) $modobjs_sed>> \$(dir_src)/stamp-modobjs.tmp" + echo " @echo '' \$(MODOBJS_${mddname}) $modobjs_sed>> \$(dir_src)/stamp-modobjs.tmp" echo if test -z "$alwayslink"; then case " $all_modules" in *" ${mddname}."*) diff --git a/Src/options.c b/Src/options.c index ce73d9901..6e4e7b911 100644 --- a/Src/options.c +++ b/Src/options.c @@ -165,6 +165,7 @@ static struct optname optns[] = { {{NULL, "ignoreclosebraces", OPT_EMULATE}, IGNORECLOSEBRACES}, {{NULL, "ignoreeof", 0}, IGNOREEOF}, {{NULL, "incappendhistory", 0}, INCAPPENDHISTORY}, +{{NULL, "incappendhistorytime", 0}, INCAPPENDHISTORYTIME}, {{NULL, "interactive", OPT_SPECIAL}, INTERACTIVE}, {{NULL, "interactivecomments",OPT_BOURNE}, INTERACTIVECOMMENTS}, {{NULL, "ksharrays", OPT_EMULATE|OPT_BOURNE}, KSHARRAYS}, @@ -179,6 +180,7 @@ static struct optname optns[] = { {{NULL, "listrowsfirst", 0}, LISTROWSFIRST}, {{NULL, "listtypes", OPT_ALL}, LISTTYPES}, {{NULL, "localoptions", OPT_EMULATE|OPT_KSH}, LOCALOPTIONS}, +{{NULL, "localloops", OPT_EMULATE}, LOCALLOOPS}, {{NULL, "localpatterns", OPT_EMULATE}, LOCALPATTERNS}, {{NULL, "localtraps", OPT_EMULATE|OPT_KSH}, LOCALTRAPS}, {{NULL, "login", OPT_SPECIAL}, LOGINSHELL}, @@ -207,6 +209,7 @@ static struct optname optns[] = { {{NULL, "pathscript", OPT_EMULATE|OPT_BOURNE}, PATHSCRIPT}, {{NULL, "pipefail", OPT_EMULATE}, PIPEFAIL}, {{NULL, "posixaliases", OPT_EMULATE|OPT_BOURNE}, POSIXALIASES}, +{{NULL, "posixargzero", OPT_EMULATE}, POSIXARGZERO}, {{NULL, "posixbuiltins", OPT_EMULATE|OPT_BOURNE}, POSIXBUILTINS}, {{NULL, "posixcd", OPT_EMULATE|OPT_BOURNE}, POSIXCD}, {{NULL, "posixidentifiers", OPT_EMULATE|OPT_BOURNE}, POSIXIDENTIFIERS}, diff --git a/Src/params.c b/Src/params.c index ad9e3470b..0699ead85 100644 --- a/Src/params.c +++ b/Src/params.c @@ -67,6 +67,7 @@ char **path, /* $path */ /**/ mod_export char *argzero, /* $0 */ + *posixzero, /* $0 */ *home, /* $HOME */ *nullcmd, /* $NULLCMD */ *oldpwd, /* $OLDPWD */ @@ -194,6 +195,8 @@ static const struct gsu_integer euid_gsu = static const struct gsu_integer ttyidle_gsu = { ttyidlegetfn, nullintsetfn, stdunsetfn }; +static const struct gsu_scalar argzero_gsu = +{ argzerogetfn, nullstrsetfn, nullunsetfn }; static const struct gsu_scalar username_gsu = { usernamegetfn, usernamesetfn, stdunsetfn }; static const struct gsu_scalar dash_gsu = @@ -263,7 +266,7 @@ static initparam special_params[] ={ #define NULL_GSU BR((GsuScalar)(void *)NULL) #define IPDEF1(A,B,C) {{NULL,A,PM_INTEGER|PM_SPECIAL|C},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0} IPDEF1("#", pound_gsu, PM_READONLY), -IPDEF1("ERRNO", errno_gsu, 0), +IPDEF1("ERRNO", errno_gsu, PM_UNSET), IPDEF1("GID", gid_gsu, PM_DONTIMPORT | PM_RESTRICTED), IPDEF1("EGID", egid_gsu, PM_DONTIMPORT | PM_RESTRICTED), IPDEF1("HISTSIZE", histsize_gsu, PM_RESTRICTED), @@ -279,12 +282,13 @@ IPDEF2("USERNAME", username_gsu, PM_DONTIMPORT|PM_RESTRICTED), IPDEF2("-", dash_gsu, PM_READONLY), IPDEF2("histchars", histchars_gsu, PM_DONTIMPORT), IPDEF2("HOME", home_gsu, PM_UNSET), -IPDEF2("TERM", term_gsu, 0), +IPDEF2("TERM", term_gsu, PM_UNSET), IPDEF2("TERMINFO", terminfo_gsu, PM_UNSET), IPDEF2("WORDCHARS", wordchars_gsu, 0), IPDEF2("IFS", ifs_gsu, PM_DONTIMPORT), -IPDEF2("_", underscore_gsu, PM_READONLY), +IPDEF2("_", underscore_gsu, PM_DONTIMPORT), IPDEF2("KEYBOARD_HACK", keyboard_hack_gsu, PM_DONTIMPORT), +IPDEF2("0", argzero_gsu, 0), #ifdef USE_LOCALE # define LCIPDEF(name) IPDEF2(name, lc_blah_gsu, PM_UNSET) @@ -326,20 +330,20 @@ IPDEF5("SHLVL", &shlvl, varinteger_gsu), IPDEF5("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} IPDEF7("OPTARG", &zoptarg), IPDEF7("NULLCMD", &nullcmd), -IPDEF7("POSTEDIT", &postedit), +IPDEF7U("POSTEDIT", &postedit), IPDEF7("READNULLCMD", &readnullcmd), IPDEF7("PS1", &prompt), -IPDEF7("RPS1", &rprompt), -IPDEF7("RPROMPT", &rprompt), +IPDEF7U("RPS1", &rprompt), +IPDEF7U("RPROMPT", &rprompt), IPDEF7("PS2", &prompt2), -IPDEF7("RPS2", &rprompt2), -IPDEF7("RPROMPT2", &rprompt2), +IPDEF7U("RPS2", &rprompt2), +IPDEF7U("RPROMPT2", &rprompt2), IPDEF7("PS3", &prompt3), IPDEF7("PS4", &prompt4), IPDEF7("SPROMPT", &sprompt), -IPDEF7("0", &argzero), #define IPDEF8(A,B,C,D) {{NULL,A,D|PM_SCALAR|PM_SPECIAL},BR((void *)B),GSU(colonarr_gsu),0,0,NULL,C,NULL,0} IPDEF8("CDPATH", &cdpath, "cdpath", 0), @@ -2416,9 +2420,10 @@ setnumvalue(Value v, mnumber val) if ((val.type & MN_INTEGER) || outputradix) { if (!(val.type & MN_INTEGER)) val.u.l = (zlong) val.u.d; - convbase(p = buf, val.u.l, outputradix); + p = convbase_underscore(buf, val.u.l, outputradix, + outputunderscore); } else - p = convfloat(val.u.d, 0, 0, NULL); + p = convfloat_underscore(val.u.d, outputunderscore); setstrvalue(v, ztrdup(p)); break; case PM_INTEGER: @@ -3979,6 +3984,17 @@ lcsetfn(Param pm, char *x) } #endif /* USE_LOCALE */ +/* Function to get value for special parameter `0' */ + +/**/ +static char * +argzerogetfn(UNUSED(Param pm)) +{ + if (isset(POSIXARGZERO)) + return posixzero; + return argzero; +} + /* Function to get value for special parameter `HISTSIZE' */ /**/ @@ -4245,7 +4261,7 @@ static char ** pipestatgetfn(UNUSED(Param pm)) { char **x = (char **) zhalloc((numpipestats + 1) * sizeof(char *)); - char buf[20], **p; + char buf[DIGBUFSIZE], **p; int *q, i; for (p = x, q = pipestats, i = numpipestats; i--; p++, q++) { @@ -4555,9 +4571,14 @@ delenv(Param pm) */ } +/* + * Guts of convbase: this version can return the number of digits + * sans any base discriminator. + */ + /**/ -mod_export void -convbase(char *s, zlong v, int base) +void +convbase_ptr(char *s, zlong v, int base, int *ndigits) { int digs = 0; zulong x; @@ -4583,6 +4604,8 @@ convbase(char *s, zlong v, int base) x /= base; if (!digs) digs = 1; + if (ndigits) + *ndigits = digs; s[digs--] = '\0'; x = v; while (digs >= 0) { @@ -4594,6 +4617,64 @@ convbase(char *s, zlong v, int base) } /* + * Basic conversion of integer to a string given a base. + * If 0 base is 10. + * If negative no base discriminator is output. + */ + +/**/ +mod_export void +convbase(char *s, zlong v, int base) +{ + convbase_ptr(s, v, base, NULL); +} + +/* + * Add underscores to converted integer for readability with given spacing. + * s is as for convbase: at least BDIGBUFSIZE. + * If underscores were added, returned value with underscores comes from + * heap, else the returned value is s. + */ + +/**/ +char * +convbase_underscore(char *s, zlong v, int base, int underscore) +{ + char *retptr, *sptr, *dptr; + int ndigits, nunderscore, mod, len; + + convbase_ptr(s, v, base, &ndigits); + + if (underscore <= 0) + return s; + + nunderscore = (ndigits - 1) / underscore; + if (!nunderscore) + return s; + len = strlen(s); + retptr = zhalloc(len + nunderscore + 1); + mod = 0; + memcpy(retptr, s, len - ndigits); + sptr = s + len; + dptr = retptr + len + nunderscore; + /* copy the null */ + *dptr-- = *sptr--; + for (;;) { + *dptr = *sptr; + if (!--ndigits) + break; + dptr--; + sptr--; + if (++mod == underscore) { + mod = 0; + *dptr-- = '_'; + } + } + + return retptr; +} + +/* * Convert a floating point value for output. * Unlike convbase(), this has its own internal storage and returns * a value from the heap. @@ -4659,6 +4740,83 @@ convfloat(double dval, int digits, int flags, FILE *fout) return ret; } +/* + * convert float to string with basic options but inserting underscores + * for readability. + */ + +/**/ +char *convfloat_underscore(double dval, int underscore) +{ + int ndigits_int = 0, ndigits_frac = 0, nunderscore, len; + char *s, *retptr, *sptr, *dptr; + + s = convfloat(dval, 0, 0, NULL); + if (underscore <= 0) + return s; + + /* + * Count the number of digits before and after the decimal point, if any. + */ + sptr = s; + if (*sptr == '-') + sptr++; + while (idigit(*sptr)) { + ndigits_int++; + sptr++; + } + if (*sptr == '.') { + sptr++; + while (idigit(*sptr)) { + ndigits_frac++; + sptr++; + } + } + + /* + * Work out how many underscores to insert --- remember we + * put them in integer and fractional parts separately. + */ + nunderscore = (ndigits_int-1) / underscore + (ndigits_frac-1) / underscore; + if (!nunderscore) + return s; + len = strlen(s); + dptr = retptr = zhalloc(len + nunderscore + 1); + + /* + * Insert underscores in integer part. + * Grouping starts from the point in both directions. + */ + sptr = s; + if (*sptr == '-') + *dptr++ = *sptr++; + while (ndigits_int) { + *dptr++ = *sptr++; + if (--ndigits_int && !(ndigits_int % underscore)) + *dptr++ = '_'; + } + if (ndigits_frac) { + /* + * Insert underscores in the fractional part. + */ + int mod = 0; + /* decimal point, we already checked */ + *dptr++ = *sptr++; + while (ndigits_frac) { + *dptr++ = *sptr++; + mod++; + if (--ndigits_frac && mod == underscore) { + *dptr++ = '_'; + mod = 0; + } + } + } + /* Copy exponent and anything else up to null */ + while ((*dptr++ = *sptr++)) + ; + return retptr; +} + /* Start a parameter scope */ /**/ diff --git a/Src/parse.c b/Src/parse.c index f0d0855d3..5f1303f1c 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -1471,7 +1471,6 @@ par_funcdef(int *complex) if (num == 0) { /* Anonymous function, possibly with arguments */ incmdpos = 0; - *complex = 1; } zshlex(); } else if (unset(SHORTLOOPS)) { @@ -1503,6 +1502,7 @@ par_funcdef(int *complex) num++; zshlex(); } + *complex = (num > 0); ecbuf[parg] = ecused - parg; /*?*/ ecbuf[parg+1] = num; } @@ -1736,7 +1736,6 @@ par_simple(int *complex, int nr) if (argc == 0) { /* Anonymous function, possibly with arguments */ incmdpos = 0; - *complex = 1; } zshlex(); } else { @@ -1776,6 +1775,7 @@ par_simple(int *complex, int nr) argc++; zshlex(); } + *complex = (argc > 0); ecbuf[parg] = ecused - parg; /*?*/ ecbuf[parg+1] = argc; } @@ -2068,6 +2068,9 @@ par_cond_2(void) /* one argument: [ foo ] is equivalent to [ -n foo ] */ s1 = tokstr; condlex(); + /* ksh behavior: [ -t ] means [ -t 1 ]; bash disagrees */ + if (unset(POSIXBUILTINS) && !strcmp(s1, "-t")) + return par_cond_double(s1, dupstring("1")); return par_cond_double(dupstring("-n"), s1); } if (testargs[1]) { @@ -2086,6 +2089,10 @@ par_cond_2(void) return par_cond_triple(s1, s2, s3); } } + /* + * We fall through here on any non-numeric infix operator + * or any other time there are at least two arguments. + */ } if (tok == BANG) { /* @@ -2114,18 +2121,20 @@ par_cond_2(void) condlex(); return r; } + s1 = tokstr; + dble = (s1 && *s1 == '-' + && (condlex != testlex + || strspn(s1+1, "abcdefghknoprstuwxzLONGS") == 1) + && !s1[2]); if (tok != STRING) { - if (tok && tok != LEXERR && condlex == testlex) { - s1 = tokstr; + /* Check first argument for [[ STRING ]] re-interpretation */ + if (s1 /* tok != DOUTBRACK && tok != DAMPER && tok != DBAR */ + && tok != LEXERR && (!dble || condlex == testlex)) { condlex(); - return par_cond_double("-n", s1); + return par_cond_double(dupstring("-n"), s1); } else YYERROR(ecused); } - s1 = tokstr; - if (condlex == testlex) - dble = (*s1 == '-' && strspn(s1+1, "abcdefghknoprstuwxzLONGS") == 1 - && !s1[2]); condlex(); if (tok == INANG || tok == OUTANG) { enum lextok xtok = tok; @@ -2140,15 +2149,21 @@ par_cond_2(void) return 1; } if (tok != STRING) { - if (tok != LEXERR && condlex == testlex) { - if (!dble) - return par_cond_double("-n", s1); - else if (!strcmp(s1, "-t")) - return par_cond_double(s1, "1"); + /* + * Check second argument in case semantics e.g. [ = -a = ] + * mean we have to go back and fix up the first one + */ + if (tok != LEXERR) { + if (!dble || condlex == testlex) + return par_cond_double(dupstring("-n"), s1); + else + return par_cond_multi(s1, newlinklist()); } else YYERROR(ecused); } - s2 = tokstr; + s2 = tokstr; + if (condlex != testlex) + dble = (s2 && *s2 == '-' && !s2[2]); incond++; /* parentheses do globbing */ condlex(); incond--; /* parentheses do grouping */ diff --git a/Src/pattern.c b/Src/pattern.c index b79c3b444..94a299ebb 100644 --- a/Src/pattern.c +++ b/Src/pattern.c @@ -2223,6 +2223,8 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen, return ret; } else { + int q = queue_signal_level(); + /* * Test for a `must match' string, unless we're scanning for a match * in which case we don't need to do this each time. @@ -2270,6 +2272,8 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen, patinput = patinstart; + dont_queue_signals(); + if (patmatch((Upat)progstr)) { /* * we were lazy and didn't save the globflags if an exclusion @@ -2406,6 +2410,8 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen, } else ret = 0; + restore_queue_signals(q); + if (tryalloced) zfree(tryalloced, unmetalen + unmetalenp); @@ -2485,7 +2491,7 @@ patmatch(Upat prog) zrange_t from, to, comp; patint_t nextch; - while (scan) { + while (scan && !errflag) { next = PATNEXT(scan); if (!globdots && P_NOTDOT(scan) && patinput == patinstart && diff --git a/Src/prompt.c b/Src/prompt.c index 95a7d4969..328ae3c66 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -270,6 +270,8 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep) char *ss, *hostnam; int t0, arg, test, sep, j, numjobs; struct tm *tm; + struct timezone dummy_tz; + struct timeval tv; time_t timet; Nameddir nd; @@ -365,6 +367,8 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep) case 'l': *bv->bp = '\0'; countprompt(bv->bufline, &t0, 0, 0); + if (minus) + t0 = zterm_columns - t0; if (t0 >= arg) test = 1; break; @@ -558,6 +562,14 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep) break; case '<': case '>': + /* Test (minus) here so -0 means "at the right margin" */ + if (minus) { + *bv->bp = '\0'; + countprompt(bv->bufline, &t0, 0, 0); + arg = zterm_columns - t0 + arg; + if (arg <= 0) + arg = 1; + } if (!prompttrunc(arg, *bv->fm, doprint, endchar, txtchangep)) return *bv->fm; break; @@ -636,8 +648,8 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep) tmfmt = "%l:%M%p"; break; } - timet = time(NULL); - tm = localtime(&timet); + gettimeofday(&tv, &dummy_tz); + tm = localtime(&tv.tv_sec); /* * Hack because strftime won't say how * much space it actually needs. Try to add it @@ -647,7 +659,7 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep) */ for(j = 0, t0 = strlen(tmfmt)*8; j < 3; j++, t0*=2) { addbufspc(t0); - if (ztrftime(bv->bp, t0, tmfmt, tm) >= 0) + if (ztrftime(bv->bp, t0, tmfmt, tm, tv.tv_usec) >= 0) break; } /* There is enough room for this because addbufspc(t0) @@ -1172,7 +1184,7 @@ prompttrunc(int arg, int truncchar, int doprint, int endchar, addbufspc(1); *bv->bp++ = '<'; } - ptr = bv->buf + w; /* addbv->bufspc() may have realloc()'d bv->buf */ + ptr = bv->buf + w; /* addbufspc() may have realloc()'d bv->buf */ /* * Now: * bv->buf is the start of the output prompt buffer @@ -1187,7 +1199,7 @@ prompttrunc(int arg, int truncchar, int doprint, int endchar, bv->trunccount = bv->dontcount; putpromptchar(doprint, endchar, txtchangep); bv->trunccount = 0; - ptr = bv->buf + w; /* putpromptchar() may have realloc()'d */ + ptr = bv->buf + w; /* putpromptchar() may have realloc()'d */ *bv->bp = '\0'; /* * Now: @@ -1473,7 +1485,7 @@ prompttrunc(int arg, int truncchar, int doprint, int endchar, /* Now we have to trick it into matching endchar again */ bv->fm--; } else { - if (*bv->fm != ']') + if (*bv->fm != endchar) bv->fm++; while(*bv->fm && *bv->fm != truncchar) { if (*bv->fm == '\\' && bv->fm[1]) diff --git a/Src/prototypes.h b/Src/prototypes.h index 00988ac4c..e3db4f5ee 100644 --- a/Src/prototypes.h +++ b/Src/prototypes.h @@ -130,5 +130,5 @@ extern char *strerror _((int errnum)); /***************************************************/ #ifndef HAVE_MEMMOVE -extern void bcopy _((const void *, void *, int)); +extern void bcopy _((const void *, void *, size_t)); #endif diff --git a/Src/signals.c b/Src/signals.c index c8f5fbcca..cb2b58161 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -369,7 +369,7 @@ signal_suspend(UNUSED(int sig), int wait_cmd) #ifdef POSIX_SIGNALS # ifdef BROKEN_POSIX_SIGSUSPEND sigprocmask(SIG_SETMASK, &set, &oset); - pause(); + ret = pause(); sigprocmask(SIG_SETMASK, &oset, NULL); # else /* not BROKEN_POSIX_SIGSUSPEND */ ret = sigsuspend(&set); @@ -1155,6 +1155,7 @@ dotrapargs(int sig, int *sigtr, void *sigfn) char *name, num[4]; int obreaks = breaks; int oretflag = retflag; + int olastval = lastval; int isfunc; int traperr, new_trap_state, new_trap_return; @@ -1261,6 +1262,13 @@ dotrapargs(int sig, int *sigtr, void *sigfn) } else { if (traperr && !EMULATION(EMULATE_SH)) lastval = 1; + else { + /* + * With no explicit forced return, we keep the + * lastval from before the trap ran. + */ + lastval = olastval; + } if (try_tryflag) errflag = traperr; breaks += obreaks; diff --git a/Src/subst.c b/Src/subst.c index 1059508ef..4a5fe3a3c 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -169,7 +169,7 @@ stringsubst(LinkList list, LinkNode node, int pf_flags, int asssub) if (errflag) return NULL; if (!subst) - subst = ""; + rest = subst = ""; sublen = strlen(subst); restlen = strlen(rest); @@ -2878,6 +2878,67 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) } break; } + } else if (inbrace && (*s == '^' || *s == Hat)) { + char **zip; + int shortest = 1; + ++s; + if (*s == '^' || *s == Hat) { + shortest = 0; + ++s; + } + if (*itype_end(s, IIDENT, 0)) { + untokenize(s); + zerr("not an identifier: %s", s); + return NULL; + } + if (vunset) { + if (unset(UNSET)) { + *idend = '\0'; + zerr("%s: parameter not set", idbeg); + return NULL; + } + val = dupstring(""); + } else { + char *sval; + zip = getaparam(s); + if (!zip) { + sval = getsparam(s); + if (sval) + zip = hmkarray(sval); + } + if (!isarr) aval = mkarray(val); + if (zip) { + char **out; + int alen, ziplen, outlen, i = 0; + alen = arrlen(aval); + ziplen = arrlen(zip); + outlen = shortest ^ (alen > ziplen) ? alen : ziplen; + if (!shortest && (alen == 0 || ziplen == 0)) { + if (ziplen) + aval = arrdup(zip); + } else { + out = zhalloc(sizeof(char *) * (2 * outlen + 1)); + while (i < outlen) { + if (copied) + out[i*2] = aval[i % alen]; + else + out[i*2] = dupstring(aval[i % alen]); + out[i*2+1] = dupstring(zip[i % ziplen]); + i++; + } + out[i*2] = NULL; + aval = out; + copied = 1; + isarr = 1; + } + } else { + if (unset(UNSET)) { + zerr("%s: parameter not set", s); + return NULL; + } + val = dupstring(""); + } + } } else if (inbrace && (*s == '|' || *s == Bar || *s == '*' || *s == Star)) { int intersect = (*s == '*' || *s == Star); @@ -2935,7 +2996,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) */ if (!vunset) { if (isarr) { - aval = mkarray(NULL); + aval = hmkarray(NULL); } else { val = dupstring(""); } @@ -3754,19 +3815,19 @@ static char * arithsubst(char *a, char **bptr, char *rest) { char *s = *bptr, *t; - char buf[BDIGBUFSIZE], *b = buf; + char buf[BDIGBUFSIZE], *b; mnumber v; singsub(&a); v = matheval(a); if ((v.type & MN_FLOAT) && !outputradix) - b = convfloat(v.u.d, 0, 0, NULL); + b = convfloat_underscore(v.u.d, outputunderscore); else { if (v.type & MN_FLOAT) v.u.l = (zlong) v.u.d; - convbase(buf, v.u.l, outputradix); + b = convbase_underscore(buf, v.u.l, outputradix, outputunderscore); } - t = *bptr = (char *) hcalloc(strlen(*bptr) + strlen(b) + + t = *bptr = (char *) hcalloc(strlen(*bptr) + strlen(b) + strlen(rest) + 1); t--; while ((*++t = *s++)); diff --git a/Src/utils.c b/Src/utils.c index c6d178ce2..998e46a36 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -725,32 +725,36 @@ xsymlinks(char *s) char **pp, **opp; char xbuf2[PATH_MAX*2], xbuf3[PATH_MAX*2]; int t0, ret = 0; + zulong xbuflen = strlen(xbuf); opp = pp = slashsplit(s); - for (; *pp; pp++) { - if (!strcmp(*pp, ".")) { - zsfree(*pp); + for (; xbuflen < sizeof(xbuf) && *pp; pp++) { + if (!strcmp(*pp, ".")) continue; - } if (!strcmp(*pp, "..")) { char *p; - zsfree(*pp); if (!strcmp(xbuf, "/")) continue; if (!*xbuf) continue; - p = xbuf + strlen(xbuf); - while (*--p != '/'); + p = xbuf + xbuflen; + while (*--p != '/') + xbuflen--; *p = '\0'; continue; } sprintf(xbuf2, "%s/%s", xbuf, *pp); t0 = readlink(unmeta(xbuf2), xbuf3, PATH_MAX); if (t0 == -1) { - strcat(xbuf, "/"); - strcat(xbuf, *pp); - zsfree(*pp); + zulong pplen = strlen(*pp) + 1; + if ((xbuflen += pplen) < sizeof(xbuf)) { + strcat(xbuf, "/"); + strcat(xbuf, *pp); + } else { + *xbuf = 0; + break; + } } else { ret = 1; metafy(xbuf3, t0, META_NOALLOC); @@ -759,10 +763,9 @@ xsymlinks(char *s) xsymlinks(xbuf3 + 1); } else xsymlinks(xbuf3); - zsfree(*pp); } } - free(opp); + freearray(opp); return ret; } @@ -779,8 +782,10 @@ xsymlink(char *s) return NULL; *xbuf = '\0'; xsymlinks(s + 1); - if (!*xbuf) + if (!*xbuf) { + zwarn("path expansion failed, using root directory"); return ztrdup("/"); + } return ztrdup(xbuf); } @@ -2486,7 +2491,7 @@ getquery(char *valid_chars, int purge) static int d; static char *guess, *best; -static Patprog spckpat; +static Patprog spckpat, spnamepat; /**/ static void @@ -2557,6 +2562,13 @@ spckword(char **s, int hist, int cmd, int ask) } else spckpat = NULL; + if ((correct_ignore = getsparam("CORRECT_IGNORE_FILE")) != NULL) { + tokenize(correct_ignore = dupstring(correct_ignore)); + remnulargs(correct_ignore); + spnamepat = patcompile(correct_ignore, 0, NULL); + } else + spnamepat = NULL; + if (**s == String && !*t) { guess = *s + 1; if (itype_end(guess, IIDENT, 1) == guess) @@ -2698,10 +2710,13 @@ ztrftimebuf(int *bufsizeptr, int decr) /**/ mod_export int -ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm) +ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long usec) { - int hr12, decr; -#ifndef HAVE_STRFTIME + int hr12; +#ifdef HAVE_STRFTIME + int decr; + char tmp[4]; +#else static char *astr[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; static char *estr[] = @@ -2709,12 +2724,12 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm) "Aug", "Sep", "Oct", "Nov", "Dec"}; #endif char *origbuf = buf; - char tmp[4]; while (*fmt) if (*fmt == '%') { int strip; + int digs = 3; fmt++; if (*fmt == '-') { @@ -2722,6 +2737,17 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm) fmt++; } else strip = 0; + if (idigit(*fmt)) { + /* Digit --- only useful with . */ + char *dstart = fmt; + char *dend = fmt+1; + while (idigit(*dend)) + dend++; + if (*dend == '.') { + fmt = dend; + digs = atoi(dstart); + } + } /* * Assume this format will take up at least two * characters. Not always true, but if that matters @@ -2731,6 +2757,20 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm) if (ztrftimebuf(&bufsize, 2)) return -1; switch (*fmt++) { + case '.': + if (ztrftimebuf(&bufsize, digs)) + return -1; + if (digs > 6) + digs = 6; + if (digs < 6) { + int trunc; + for (trunc = 5 - digs; trunc; trunc--) + usec /= 10; + usec = (usec + 5) / 10; + } + sprintf(buf, "%0*ld", digs, usec); + buf += digs; + break; case 'd': if (tm->tm_mday > 9 || !strip) *buf++ = '0' + tm->tm_mday / 10; @@ -3332,6 +3372,17 @@ mkarray(char *s) } /**/ +mod_export char ** +hmkarray(char *s) +{ + char **t = (char **) zhalloc((s) ? (2 * sizeof s) : (sizeof s)); + + if ((*t = s)) + t[1] = NULL; + return t; +} + +/**/ mod_export void zbeep(void) { @@ -3778,6 +3829,8 @@ mindist(char *dir, char *mindistguess, char *mindistbest) if (!(dd = opendir(unmeta(dir)))) return mindistd; while ((fn = zreaddir(dd, 0))) { + if (spnamepat && pattry(spnamepat, fn)) + continue; nd = spdist(fn, mindistguess, (int)strlen(mindistguess) / 4 + 1); if (nd <= mindistd) { @@ -4256,6 +4309,12 @@ mod_export char * zreaddir(DIR *dir, int ignoredots) { struct dirent *de; +#if defined(HAVE_ICONV) && defined(__APPLE__) + static iconv_t conv_ds = (iconv_t)0; + static char *conv_name = 0; + char *conv_name_ptr, *orig_name_ptr; + size_t conv_name_len, orig_name_len; +#endif do { de = readdir(dir); @@ -4264,6 +4323,30 @@ zreaddir(DIR *dir, int ignoredots) } while(ignoredots && de->d_name[0] == '.' && (!de->d_name[1] || (de->d_name[1] == '.' && !de->d_name[2]))); +#if defined(HAVE_ICONV) && defined(__APPLE__) + if (!conv_ds) + conv_ds = iconv_open("UTF-8", "UTF-8-MAC"); + if (conv_ds != (iconv_t)(-1)) { + /* Force initial state in case re-using conv_ds */ + (void) iconv(conv_ds, 0, &orig_name_len, 0, &conv_name_len); + + orig_name_ptr = de->d_name; + orig_name_len = strlen(de->d_name); + conv_name = zrealloc(conv_name, orig_name_len+1); + conv_name_ptr = conv_name; + conv_name_len = orig_name_len; + if (iconv(conv_ds, + &orig_name_ptr, &orig_name_len, + &conv_name_ptr, &conv_name_len) != (size_t)(-1) && + orig_name_len == 0) { + /* Completely converted, metafy and return */ + *conv_name_ptr = '\0'; + return metafy(conv_name, -1, META_STATIC); + } + /* Error, or conversion incomplete, keep the original name */ + } +#endif + return metafy(de->d_name, -1, META_STATIC); } diff --git a/Src/watch.c b/Src/watch.c index 5231579f8..8dea0b495 100644 --- a/Src/watch.c +++ b/Src/watch.c @@ -330,7 +330,7 @@ watchlog2(int inout, WATCH_STRUCT_UTMP *u, char *fmt, int prnt, int fini) } timet = getlogtime(u, inout); tm = localtime(&timet); - ztrftime(buf, 40, fm2, tm); + ztrftime(buf, 40, fm2, tm, 0L); printf("%s", (*buf == ' ') ? buf + 1 : buf); break; case '%': @@ -33,9 +33,6 @@ /* * Our longest integer type: will be a 64 bit either if long already is, * or if we found some alternative such as long long. - * Currently we only define this to be longer than a long if - * --enable-largefile * was given. That enables internal use of 64-bit - * types even if no actual large file support is present. */ #ifdef ZSH_64_BIT_TYPE typedef ZSH_64_BIT_TYPE zlong; @@ -50,6 +47,32 @@ typedef unsigned long zulong; #endif /* + * Work out how to define large integer constants that will fit + * in a zlong. + */ +#if defined(ZSH_64_BIT_TYPE) || defined(LONG_IS_64_BIT) +/* We have some 64-bit type */ +#ifdef LONG_IS_64_BIT +/* It's long */ +#define ZLONG_CONST(x) x ## l +#else +/* It's long long */ +#ifdef ZLONG_IS_LONG_LONG +#define ZLONG_CONST(x) x ## ll +#else +/* + * There's some 64-bit type, but we don't know what it is. + * We'll just cast it and hope the compiler does the right thing. + */ +#define ZLONG_CONST(x) ((zlong)x) +#endif +#endif +#else +/* We're stuck with long */ +#define ZLONG_CONST(x) (x ## l) +#endif + +/* * Double float support requires 64-bit alignment, so if longs and * pointers are less we need to pad out. */ @@ -2092,6 +2115,7 @@ enum { IGNORECLOSEBRACES, IGNOREEOF, INCAPPENDHISTORY, + INCAPPENDHISTORYTIME, INTERACTIVE, INTERACTIVECOMMENTS, KSHARRAYS, @@ -2105,6 +2129,7 @@ enum { LISTPACKED, LISTROWSFIRST, LISTTYPES, + LOCALLOOPS, LOCALOPTIONS, LOCALPATTERNS, LOCALTRAPS, @@ -2128,6 +2153,7 @@ enum { PATHSCRIPT, PIPEFAIL, POSIXALIASES, + POSIXARGZERO, POSIXBUILTINS, POSIXCD, POSIXIDENTIFIERS, diff --git a/Src/zsh.mdd b/Src/zsh.mdd index d77fc4336..cec3edab7 100644 --- a/Src/zsh.mdd +++ b/Src/zsh.mdd @@ -44,7 +44,7 @@ patchlevel.h: FORCE cp -f $(sdir)/$@.release $@; \ else \ echo '#define ZSH_PATCHLEVEL "'`cd $(sdir) && git describe --tags --long`'"' > $@.tmp; \ - cmp $@ $@.tmp 2>/dev/null && rm -f $@.tmp || mv $@.tmp $@; \ + cmp $@ $@.tmp >/dev/null 2>&1 && rm -f $@.tmp || mv $@.tmp $@; \ fi FORCE: diff --git a/Src/zsh_system.h b/Src/zsh_system.h index e68fd62f9..811340d42 100644 --- a/Src/zsh_system.h +++ b/Src/zsh_system.h @@ -286,11 +286,15 @@ struct timezone { # include <limits.h> #endif +#ifdef USE_STACK_ALLOCATION #ifdef HAVE_VARIABLE_LENGTH_ARRAYS # define VARARR(X,Y,Z) X (Y)[Z] #else # define VARARR(X,Y,Z) X *(Y) = (X *) alloca(sizeof(X) * (Z)) #endif +#else +# define VARARR(X,Y,Z) X *(Y) = (X *) zhalloc(sizeof(X) * (Z)) +#endif /* we should handle unlimited sizes from pathconf(_PC_PATH_MAX) */ /* but this is too much trouble */ @@ -708,7 +712,10 @@ struct timezone { #endif #ifndef HAVE_MEMMOVE -# define memmove(dest, src, len) bcopy((src), (dest), (len)) +# ifndef memmove +static char *zmmv; +# define memmove(dest, src, len) (bcopy((src), zmmv = (dest), (len)), zmmv) +# endif #endif #ifndef offsetof @@ -874,3 +881,8 @@ extern short ospeed; # endif # endif #endif + +#ifdef ZSH_VALGRIND +# include "valgrind/valgrind.h" +# include "valgrind/memcheck.h" +#endif |