From ea0ddb0fc6073be3d7d289e59b083f564dbd761f Mon Sep 17 00:00:00 2001 From: Tanaka Akira Date: Wed, 12 May 1999 04:49:46 +0000 Subject: pws-18 --- Src/Builtins/rlimits.c | 4 +- Src/Zle/comp1.c | 3 +- Src/Zle/iwidgets.list | 1 + Src/Zle/zle_hist.c | 318 ++++++++++----------- Src/Zle/zle_keymap.c | 2 + Src/Zle/zle_main.c | 42 ++- Src/Zle/zle_move.c | 15 +- Src/Zle/zle_thingy.c | 17 +- Src/Zle/zle_tricky.c | 63 ++++- Src/Zle/zle_utils.c | 12 +- Src/builtin.c | 71 ++--- Src/exec.c | 6 +- Src/hashtable.c | 176 +++++++++++- Src/hist.c | 747 +++++++++++++++++++++++++++++++++---------------- Src/init.c | 17 +- Src/jobs.c | 34 ++- Src/module.c | 39 ++- Src/options.c | 13 +- Src/params.c | 25 +- Src/signals.c | 5 +- Src/subst.c | 25 +- Src/text.c | 3 +- Src/utils.c | 61 +++- Src/zsh.export | 6 + Src/zsh.h | 36 ++- 25 files changed, 1164 insertions(+), 577 deletions(-) (limited to 'Src') diff --git a/Src/Builtins/rlimits.c b/Src/Builtins/rlimits.c index 7825a900d..34344f5c1 100644 --- a/Src/Builtins/rlimits.c +++ b/Src/Builtins/rlimits.c @@ -43,14 +43,14 @@ zstrtorlimt(const char *s, char **t, int base) { rlim_t ret = 0; - if (!base) + if (!base) { if (*s != '0') base = 10; else if (*++s == 'x' || *s == 'X') base = 16, s++; else base = 8; - + } if (base <= 10) for (; *s >= '0' && *s < ('0' + base); s++) ret = ret * base + *s - '0'; diff --git a/Src/Zle/comp1.c b/Src/Zle/comp1.c index c51aad297..f32e5f5c0 100644 --- a/Src/Zle/comp1.c +++ b/Src/Zle/comp1.c @@ -47,7 +47,7 @@ Cmlist cmatcher; void (*makecompparamsptr) _((void)); /**/ -void (*comp_setunsetptr) _((int, int)); +void (*comp_setunsetptr) _((unsigned int, unsigned int)); /* pointers to functions required by compctl and defined by zle */ @@ -147,6 +147,7 @@ createcompctltable(void) compctltab->hash = hasher; compctltab->emptytable = emptyhashtable; compctltab->filltable = NULL; + compctltab->cmpnodes = strcmp; compctltab->addnode = addhashnode; compctltab->getnode = gethashnode2; compctltab->getnode2 = gethashnode2; diff --git a/Src/Zle/iwidgets.list b/Src/Zle/iwidgets.list index 61ad0e24a..e0c93bd03 100644 --- a/Src/Zle/iwidgets.list +++ b/Src/Zle/iwidgets.list @@ -91,6 +91,7 @@ "send-break", sendbreak, 0 "set-mark-command", setmarkcommand, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL "spell-word", spellword, 0 +"set-local-history", setlocalhistory, 0 "transpose-chars", transposechars, 0 "transpose-words", transposewords, 0 "undefined-key", undefinedkey, 0 diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c index 0064d4ef0..d2b9a3233 100644 --- a/Src/Zle/zle_hist.c +++ b/Src/Zle/zle_hist.c @@ -47,27 +47,16 @@ int lastcol; /**/ int histline; -/* the last line in the history (the current one), metafied */ - -/**/ -char *curhistline; +#define ZLETEXT(X) ((X)->zle_text ? (X)->zle_text : (X)->text) /**/ void remember_edits(void) { - if (histline == curhist) { - zsfree(curhistline); - curhistline = metafy((char *) line, ll, META_DUP); - } - else { - Histent ent = gethistent(histline); - - if (metadiffer(ent->zle_text ? ent->zle_text : ent->text, - (char *) line, ll)) { - zsfree(ent->zle_text); - ent->zle_text = metafy((char *) line, ll, META_DUP); - } + Histent ent = quietgethist(histline); + if (metadiffer(ZLETEXT(ent), (char *) line, ll)) { + zsfree(ent->zle_text); + ent->zle_text = metafy((char *) line, ll, META_DUP); } } @@ -75,11 +64,11 @@ remember_edits(void) void forget_edits(void) { - int i; + Histent he; - for (i = 0; i < histentct; i++) { - zsfree(histentarr[i].zle_text); - histentarr[i].zle_text = NULL; + for (he = hist_ring; he; he = up_histent(he)) { + zsfree(he->zle_text); + he->zle_text = NULL; } } @@ -87,16 +76,12 @@ forget_edits(void) void uphistory(void) { - if (zmult < 0) { - zmult = -zmult; - downhistory(); - zmult = -zmult; - } else if(!zle_goto_hist(histline - zmult) && isset(HISTBEEP)) + if (!zle_goto_hist(histline, -zmult) && isset(HISTBEEP)) feep(); } /**/ -int +static int upline(void) { int n = zmult; @@ -159,7 +144,6 @@ viuplineorhistory(void) vifirstnonblank(); } - /**/ void uplineorsearch(void) @@ -181,7 +165,7 @@ uplineorsearch(void) } /**/ -int +static int downline(void) { int n = zmult; @@ -268,26 +252,22 @@ downlineorsearch(void) void acceptlineanddownhistory(void) { - char *s; + Histent he; - if (!(s = zle_get_event(histline + 1))) { + if (!(he = movehistent(quietgethist(histline), 1, HIST_FOREIGN))) { feep(); return; } - pushnode(bufstack, ztrdup(s)); + pushnode(bufstack, ztrdup(ZLETEXT(he))); done = 1; - stackhist = histline + 1; + stackhist = he->histnum; } /**/ void downhistory(void) { - if (zmult < 0) { - zmult = -zmult; - uphistory(); - zmult = -zmult; - } else if(!zle_goto_hist(histline + zmult) && isset(HISTBEEP)) + if (!zle_goto_hist(histline, zmult) && isset(HISTBEEP)) feep(); } @@ -298,7 +278,7 @@ static char *srch_str; void historysearchbackward(void) { - int hl = histline; + Histent he; int n = zmult; char *s; @@ -308,7 +288,7 @@ historysearchbackward(void) zmult = n; return; } - if (hl == curhist || hl != srch_hl || cs != srch_cs || mark != 0 + if (histline == curhist || histline != srch_hl || cs != srch_cs || mark != 0 || memcmp(srch_str, line, histpos) != 0) { zfree(srch_str, histpos); for (histpos = 0; histpos < ll && !iblank(line[histpos]); histpos++) ; @@ -317,28 +297,29 @@ historysearchbackward(void) srch_str = zalloc(histpos); memcpy(srch_str, line, histpos); } - for (;;) { - hl--; - if (!(s = zle_get_event(hl))) { - feep(); - return; - } + he = quietgethist(histline); + while ((he = movehistent(he, -1, hist_skip_flags))) { + if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP) + continue; + s = ZLETEXT(he); if (metadiffer(s, srch_str, histpos) < 0 && metadiffer(s, srch_str, ll)) { - if (--n <= 0) - break; + if (--n <= 0) { + zle_setline(he); + srch_hl = histline; + srch_cs = cs; + return; + } } } - zle_goto_hist(hl); - srch_hl = hl; - srch_cs = cs; + feep(); } /**/ void historysearchforward(void) { - int hl = histline; + Histent he; int n = zmult; char *s; @@ -348,7 +329,7 @@ historysearchforward(void) zmult = n; return; } - if (hl == curhist || hl != srch_hl || cs != srch_cs || mark != 0 + if (histline == curhist || histline != srch_hl || cs != srch_cs || mark != 0 || memcmp(srch_str, line, histpos) != 0) { zfree(srch_str, histpos); for (histpos = 0; histpos < ll && !iblank(line[histpos]); histpos++) ; @@ -357,20 +338,22 @@ historysearchforward(void) srch_str = zalloc(histpos); memcpy(srch_str, line, histpos); } - for (;;) { - hl++; - if (!(s = zle_get_event(hl))) { - feep(); - return; + he = quietgethist(histline); + while ((he = movehistent(he, 1, hist_skip_flags))) { + if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP) + continue; + s = ZLETEXT(he); + if (metadiffer(s, srch_str, histpos) < (he->histnum == curhist) && + metadiffer(s, srch_str, ll)) { + if (--n <= 0) { + zle_setline(he); + srch_hl = histline; + srch_cs = cs; + return; + } } - if (metadiffer(s, srch_str, histpos) < (hl == curhist) && - metadiffer(s, srch_str, ll)) - if (--n <= 0) - break; } - zle_goto_hist(hl); - srch_hl = hl; - srch_cs = cs; + feep(); } /**/ @@ -387,7 +370,7 @@ beginningofbufferorhistory(void) void beginningofhistory(void) { - if (!zle_goto_hist(firsthist()) && isset(HISTBEEP)) + if (!zle_goto_hist(firsthist(), 0) && isset(HISTBEEP)) feep(); } @@ -405,7 +388,7 @@ endofbufferorhistory(void) void endofhistory(void) { - zle_goto_hist(curhist); + zle_goto_hist(curhist, 0); } /**/ @@ -419,7 +402,7 @@ insertlastword(void) /* multiple calls will now search back through the history, pem */ static char *lastinsert; static int lasthist, lastpos; - int evhist = curhist - 1, save; + int evhist = addhistnum(curhist, -1, HIST_FOREIGN), save; if (lastinsert) { int lastlen = ztrlen(lastinsert); @@ -428,7 +411,7 @@ insertlastword(void) if (lastpos <= pos && lastlen == pos - lastpos && memcmp(lastinsert, (char *)&line[lastpos], lastlen) == 0) { - evhist = --lasthist; + evhist = addhistnum(lasthist, -1, HIST_FOREIGN); cs = lastpos; foredel(pos - cs); } @@ -464,41 +447,37 @@ insertlastword(void) } /**/ -char * -qgetevent(int ev) +void +zle_setline(Histent he) { - return ((ev == curhist) ? curhistline : quietgetevent(ev)); + remember_edits(); + mkundoent(); + histline = he->histnum; + setline(ZLETEXT(he)); + setlastline(); + clearlist = 1; } /**/ -char * -zle_get_event(int ev) +void +setlocalhistory(void) { - Histent ent; - - if (ev == curhist) - return curhistline; - if (! (ent = quietgethist(ev))) - return NULL; - if (ent->zle_text) - return ent->zle_text; - return ent->text; + if (zmod.flags & MOD_MULT) { + hist_skip_flags = zmult? HIST_FOREIGN : 0; + } + else { + hist_skip_flags ^= HIST_FOREIGN; + } } /**/ -static int -zle_goto_hist(int ev) +int +zle_goto_hist(int ev, int n) { - char *t; - - remember_edits(); - if(!(t = zle_get_event(ev))) + Histent he = movehistent(quietgethist(ev), n, hist_skip_flags); + if (!he) return 0; - mkundoent(); - histline = ev; - setline(t); - setlastline(); - clearlist = 1; + zle_setline(he); return 1; } @@ -603,6 +582,7 @@ static struct isrch_spot { static int max_spot = 0; +/**/ #ifdef MODULE /**/ @@ -612,6 +592,7 @@ free_isrch_spots(void) zfree(isrch_spots, max_spot * sizeof(*isrch_spots)); } +/**/ #endif /* MODULE */ /**/ @@ -665,13 +646,15 @@ doisearch(int dir) char *okeymap = curkeymapname; static char *previous_search = NULL; static int previous_search_len = 0; + Histent he; clearlist = 1; strcpy(ibuf, ISEARCH_PROMPT); memcpy(ibuf + NORM_PROMPT_POS, (dir == 1) ? "fwd" : "bck", 3); remember_edits(); - s = zle_get_event(hl); + he = quietgethist(hl); + s = ZLETEXT(he); selectkeymap("main", 1); pos = metalen(s, cs); for (;;) { @@ -705,15 +688,14 @@ doisearch(int dir) if (!skip_line && ((sbuf[0] == '^') ? (t = metadiffer(s, sbuf + 1, sbptr - 1) < sens ? s : NULL) : (t = hstrnstr(s, pos, sbuf, sbptr, dir, sens)))) { - zle_goto_hist(hl); + zle_setline(he); pos = t - s; cs = ztrsub(t, s) + (dir == 1? sbptr - (sbuf[0]=='^') : 0); nomatch = 0; statusline = ibuf + NORM_PROMPT_POS; break; } - hl += dir; - if (!(s = zle_get_event(hl))) { + if (!(he = movehistent(he, dir, hist_skip_flags))) { if (sbptr == (int)isrch_spots[top_spot-1].len && (isrch_spots[top_spot-1].flags & ISS_FAILING)) top_spot--; @@ -723,13 +705,17 @@ doisearch(int dir) feep(); nomatch = 1; } - s = last_line; + he = quietgethist(hl); + s = ZLETEXT(he); skip_line = 0; statusline = ibuf; break; } + hl = he->histnum; + s = ZLETEXT(he); pos = dir == 1? 0 : strlen(s); - skip_line = !strcmp(last_line, s); + skip_line = isset(HISTFINDNODUPS)? !!(he->flags & HIST_DUP) + : !strcmp(last_line, s); } } else { top_spot = 0; @@ -743,8 +729,9 @@ doisearch(int dir) if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak)) { int i; get_isrch_spot(0, &hl, &pos, &i, &sbptr, &dir, &nomatch); - s = zle_get_event(hl); - zle_goto_hist(hl); + he = quietgethist(hl); + zle_setline(he); + s = ZLETEXT(he); cs = i; break; } @@ -769,10 +756,11 @@ doisearch(int dir) statusline = ibuf; skip_pos = 1; } - s = zle_get_event(hl); + he = quietgethist(hl); + s = ZLETEXT(he); if (nomatch || !sbptr || (sbptr == 1 && sbuf[0] == '^')) { int i = cs; - zle_goto_hist(hl); + zle_setline(he); cs = i; } memcpy(ibuf + NORM_PROMPT_POS, (dir == 1) ? "fwd" : "bck", 3); @@ -874,42 +862,35 @@ doisearch(int dir) void acceptandinfernexthistory(void) { - int t0; - char *s; + Histent he; done = 1; - for (t0 = histline - 2;; t0--) { - if (!(s = qgetevent(t0))) + for (he = movehistent(quietgethist(histline), -2, HIST_FOREIGN); + he; he = movehistent(he, -1, HIST_FOREIGN)) { + if (!metadiffer(ZLETEXT(he), (char *) line, ll)) { + he = movehistent(he, 1, HIST_FOREIGN); + pushnode(bufstack, ztrdup(ZLETEXT(he))); + stackhist = he->histnum; return; - if (!metadiffer(s, (char *) line, ll)) - break; + } } - if (!(s = qgetevent(t0 + 1))) - return; - pushnode(bufstack, ztrdup(s)); - stackhist = t0 + 1; } /**/ void infernexthistory(void) { - int t0; - char *s; + Histent he; - for (t0 = histline - 2;; t0--) { - if (!(s = qgetevent(t0))) { - feep(); + for (he = movehistent(quietgethist(histline), -2, HIST_FOREIGN); + he; he = movehistent(he, -1, HIST_FOREIGN)) { + if (!metadiffer(ZLETEXT(he), (char *) line, ll)) { + he = movehistent(he, 1, HIST_FOREIGN); + zle_setline(he); return; } - if (! metadiffer(s, (char *) line, ll)) - break; } - if (!(s = qgetevent(t0 + 1))) { - feep(); - return; - } - zle_goto_hist(t0 + 1); + feep(); } /**/ @@ -925,7 +906,7 @@ vifetchhistory(void) return; } } - if (!zle_goto_hist((zmod.flags & MOD_MULT) ? zmult : curhist) && + if (!zle_goto_hist((zmod.flags & MOD_MULT) ? zmult : curhist, 0) && isset(HISTBEEP)) feep(); } @@ -1041,7 +1022,8 @@ vihistorysearchbackward(void) void virepeatsearch(void) { - int hl = histline, t0; + Histent he; + int t0; int n = zmult; char *s; @@ -1054,23 +1036,21 @@ virepeatsearch(void) visrchsense = -visrchsense; } t0 = strlen(visrchstr); - for (;;) { - hl += visrchsense; - if (!(s = zle_get_event(hl))) { - feep(); - return; - } - if (!metadiffer(s, (char *) line, ll)) - continue; - if (*visrchstr == '^') { - if (strncmp(s, visrchstr + 1, t0 - 1) != 0) - continue; - } else if (!hstrnstr(s, 0, visrchstr, t0, 1, 1)) + he = quietgethist(histline); + while ((he = movehistent(he, visrchsense, hist_skip_flags))) { + if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP) continue; - if (--n <= 0) - break; + s = ZLETEXT(he); + if (metadiffer(s, (char *) line, ll) + && (*visrchstr == '^'? strncmp(s, visrchstr + 1, t0 - 1) == 0 + : hstrnstr(s, 0, visrchstr, t0, 1, 1) != 0)) { + if (--n <= 0) { + zle_setline(he); + return; + } + } } - zle_goto_hist(hl); + feep(); } /**/ @@ -1090,8 +1070,8 @@ virevrepeatsearch(void) void historybeginningsearchbackward(void) { + Histent he; int cpos = cs; /* save cursor position */ - int hl = histline; int n = zmult; char *s; @@ -1101,20 +1081,21 @@ historybeginningsearchbackward(void) zmult = n; return; } - for (;;) { - hl--; - if (!(s = zle_get_event(hl))) { - feep(); - return; - } + he = quietgethist(histline); + while ((he = movehistent(he, -1, hist_skip_flags))) { + if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP) + continue; + s = ZLETEXT(he); if (metadiffer(s, (char *)line, cs) < 0 && - metadiffer(s, (char *)line, ll)) - if (--n <= 0) - break; + metadiffer(s, (char *)line, ll)) { + if (--n <= 0) { + zle_setline(he); + cs = cpos; + return; + } + } } - - zle_goto_hist(hl); - cs = cpos; + feep(); } /* Extra function added by A.R. Iano-Fletcher. */ @@ -1124,8 +1105,8 @@ historybeginningsearchbackward(void) void historybeginningsearchforward(void) { + Histent he; int cpos = cs; /* save cursor position */ - int hl = histline; int n = zmult; char *s; @@ -1135,18 +1116,19 @@ historybeginningsearchforward(void) zmult = n; return; } - for (;;) { - hl++; - if (!(s = zle_get_event(hl))) { - feep(); - return; + he = quietgethist(histline); + while ((he = movehistent(he, 1, hist_skip_flags))) { + if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP) + continue; + s = ZLETEXT(he); + if (metadiffer(s, (char *)line, cs) < (he->histnum == curhist) && + metadiffer(s, (char *)line, ll)) { + if (--n <= 0) { + zle_setline(he); + cs = cpos; + return; + } } - if (metadiffer(s, (char *)line, cs) < (hl == curhist) && - metadiffer(s, (char *)line, ll)) - if (--n <= 0) - break; } - - zle_goto_hist(hl); - cs = cpos; + feep(); } diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index 1baa3a845..7504ed809 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -130,6 +130,7 @@ createkeymapnamtab(void) keymapnamtab->hash = hasher; keymapnamtab->emptytable = emptyhashtable; keymapnamtab->filltable = NULL; + keymapnamtab->cmpnodes = strcmp; keymapnamtab->addnode = addhashnode; keymapnamtab->getnode = gethashnode2; keymapnamtab->getnode2 = gethashnode2; @@ -172,6 +173,7 @@ newkeytab(char *kmname) ht->hash = hasher; ht->emptytable = emptyhashtable; ht->filltable = NULL; + ht->cmpnodes = strcmp; ht->addnode = addhashnode; ht->getnode = gethashnode2; ht->getnode2 = gethashnode2; diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index a5da84b66..dfb437308 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -111,6 +111,10 @@ int prefixflag; /**/ int feepflag; +#ifdef FIONREAD +static int delayzsetterm; +#endif + /* set up terminal */ /**/ @@ -119,12 +123,30 @@ zsetterm(void) { struct ttyinfo ti; -#if defined(CLOBBERS_TYPEAHEAD) && defined(FIONREAD) +#if defined(FIONREAD) int val; ioctl(SHTTY, FIONREAD, (char *)&val); - if (val) + if (val) { + /* + * Problems can occur on some systems when switching from + * canonical to non-canonical input. The former is usually + * set while running programmes, but the latter is necessary + * for zle. If there is input in canonical mode, then we + * need to read it without setting up the terminal. Furthermore, + * while that input gets processed there may be more input + * being typed (i.e. further typeahead). This means that + * we can't set up the terminal for zle *at all* until + * we are sure there is no more typeahead to come. So + * if there is typeahead, we set the flag delayzsetterm. + * Then getkey() performs another FIONREAD call; if that is + * 0, we have finally used up all the typeahead, and it is + * safe to alter the terminal, which we do at that point. + */ + delayzsetterm = 1; return; + } else + delayzsetterm = 0; #endif /* sanitize the tty */ @@ -298,7 +320,19 @@ getkey(int keytmout) if (kungetct) ret = STOUC(kungetbuf[--kungetct]); else { - if (keytmout) { +#ifdef FIONREAD + if (delayzsetterm) { + int val; + ioctl(SHTTY, FIONREAD, (char *)&val); + if (!val) + zsetterm(); + } +#endif + if (keytmout +#ifdef FIONREAD + && ! delayzsetterm +#endif + ) { if (keytimeout > 500) exp100ths = 500; else if (keytimeout > 0) @@ -461,7 +495,6 @@ zleread(char *lp, char *rp, int flags) undoing = 1; line = (unsigned char *)zalloc((linesz = 256) + 2); virangeflag = lastcmd = done = cs = ll = mark = 0; - curhistline = NULL; vichgflag = 0; viinsbegin = 0; statusline = NULL; @@ -542,7 +575,6 @@ zleread(char *lp, char *rp, int flags) zleactive = no_restore_tty = 0; alarm(0); } LASTALLOC; - zsfree(curhistline); freeundo(); if (eofsent) { free(line); diff --git a/Src/Zle/zle_move.c b/Src/Zle/zle_move.c index d6e9c4b7d..7169f5700 100644 --- a/Src/Zle/zle_move.c +++ b/Src/Zle/zle_move.c @@ -476,17 +476,10 @@ vigotomark(void) feep(); return; } - if (curhist != vimarkline[ch]) { - char *s; - - remember_edits(); - if (!(s = qgetevent(vimarkline[ch]))) { - vimarkline[ch] = 0; - feep(); - return; - } - histline = vimarkline[ch]; - setline(s); + if (curhist != vimarkline[ch] && !zle_goto_hist(vimarkline[ch], 0)) { + vimarkline[ch] = 0; + feep(); + return; } cs = vimarkcs[ch]; if (cs > ll) diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c index b879669ac..dbf982899 100644 --- a/Src/Zle/zle_thingy.c +++ b/Src/Zle/zle_thingy.c @@ -64,6 +64,7 @@ createthingytab(void) thingytab->hash = hasher; thingytab->emptytable = emptythingytab; thingytab->filltable = NULL; + thingytab->cmpnodes = strcmp; thingytab->addnode = addhashnode; thingytab->getnode = gethashnode; thingytab->getnode2 = gethashnode2; @@ -356,7 +357,7 @@ bin_zle(char *name, char **args, char *ops, int func) /* check number of arguments */ for(n = 0; args[n]; n++) ; - if(!op->o && n != 1) { + if(!op->o && n != 1 && n != 2) { zerrnam(name, "wrong number of arguments", NULL, 0); return 1; } @@ -515,17 +516,31 @@ static int bin_zle_call(char *name, char **args, char *ops, char func) { Thingy t; + struct modifier modsave; if(!zleactive || incompctlfunc || incompfunc) { zerrnam(name, "widgets can only be called when ZLE is active", NULL, 0); return 1; } + if (args[1]) { + modsave = zmod; + if (isdigit(*args[1])) { + zmod.mult = atoi(args[1]); + zmod.flags |= MOD_MULT; + } + else { + zmod.mult = 1; + zmod.flags &= ~MOD_MULT; + } + } t = rthingy(args[0]); PERMALLOC { execzlefunc(t); } LASTALLOC; unrefthingy(t); + if (args[1]) + zmod = modsave; return 0; } diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index 8db571d0b..bc6cff8b6 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -578,6 +578,10 @@ static char *varname; static int insubscr; +/* Parameter pointer for completing keys of an assoc array. */ + +static Param keypm; + /* 1 if we are completing in a quoted string (or inside `...`) */ /**/ @@ -1364,9 +1368,15 @@ get_comp_string(void) zsfree(varname); varname = ztrdup(tt); *s = sav; - if (skipparens(Inbrack, Outbrack, &s) > 0 || s > tt + cs - wb) - s = NULL, inwhat = IN_MATH, insubscr = 1; - else if (*s == '=' && cs > wb + (s - tt)) { + if (skipparens(Inbrack, Outbrack, &s) > 0 || s > tt + cs - wb) { + s = NULL; + inwhat = IN_MATH; + if ((keypm = (Param) paramtab->getnode(paramtab, varname)) && + (keypm->flags & PM_HASHED)) + insubscr = 2; + else + insubscr = 1; + } else if (*s == '=' && cs > wb + (s - tt)) { s++; wb += s - tt; t0 = STRING; @@ -1424,11 +1434,15 @@ get_comp_string(void) zsfree(varname); varname = ztrdup(nb); *ne = sav; + if ((keypm = (Param) paramtab->getnode(paramtab, + varname)) && + (keypm->flags & PM_HASHED)) + insubscr = 2; } } } if (inwhat == IN_MATH) { - if (compfunc) { + if (compfunc || insubscr == 2) { int lev; char *p; @@ -1472,7 +1486,11 @@ get_comp_string(void) zsfree(varname); varname = ztrdup((char *) line + i + 1); line[wb - 1] = sav; - insubscr = 1; + if ((keypm = (Param) paramtab->getnode(paramtab, varname)) && + (keypm->flags & PM_HASHED)) + insubscr = 2; + else + insubscr = 1; } } /* This variable will hold the current word in quoted form. */ @@ -3524,7 +3542,7 @@ int addmatches(Cadata dat, char **argv) { char *s, *ms, *lipre = NULL, *lisuf = NULL, *lpre = NULL, *lsuf = NULL; - char **aign = NULL, **dparr; + char **aign = NULL, **dparr = NULL; int lpl, lsl, pl, sl, bpl, bsl, llpl = 0, llsl = 0, nm = mnum; int oisalt = 0, isalt, isexact, doadd; Cline lc = NULL; @@ -4360,7 +4378,7 @@ callcompfunc(char *s, char *fn) PERMALLOC { q = compwords = (char **) - zalloc((clwnum - aadd + 1) * sizeof(char *)); + zalloc((clwnum + 1) * sizeof(char *)); for (p = clwords + aadd; *p; p++, q++) { tmp = dupstring(*p); untokenize(tmp); @@ -4829,13 +4847,22 @@ makecomplistglobal(char *os, int incmd, int lst, int flags) char *s; ccont = CC_CCCONT; + cc_dummy.suffix = NULL; if (linwhat == IN_ENV) { /* Default completion for parameter values. */ cc = &cc_default; + keypm = NULL; } else if (linwhat == IN_MATH) { - /* Parameter names inside mathematical expression. */ - cc_dummy.mask = CC_PARAMS; + if (insubscr == 2) { + /* Inside subscript of assoc array, complete keys. */ + cc_dummy.mask = 0; + cc_dummy.suffix = "]"; + } else { + /* Other math environment, complete paramete names. */ + keypm = NULL; + cc_dummy.mask = CC_PARAMS; + } cc = &cc_dummy; cc_dummy.refc = 10000; } else if (linwhat == IN_COND) { @@ -4851,13 +4878,16 @@ makecomplistglobal(char *os, int incmd, int lst, int flags) (CC_FILES | CC_PARAMS); cc = &cc_dummy; cc_dummy.refc = 10000; - } else if (linredir) + keypm = NULL; + } else if (linredir) { /* In redirections use default completion. */ cc = &cc_default; - else + keypm = NULL; + } else { /* Otherwise get the matches for the command. */ + keypm = NULL; return makecomplistcmd(os, incmd, flags); - + } if (cc) { /* First, use the -T compctl. */ if (!(flags & CFN_FIRST)) { @@ -5917,7 +5947,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) Comp compc = NULL; char *e, *h, hpatsav; Histent he; - int i = curhist - 1, n = cc->hnum; + int i = addhistnum(curhist,-1,HIST_FOREIGN), n = cc->hnum; /* Parse the pattern, if it isn't the null string. */ if (*(cc->hpat)) { @@ -5971,7 +6001,12 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) if ((t = cc->mask & (CC_ALREG | CC_ALGLOB))) /* Add the two types of aliases. */ dumphashtable(aliastab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS))); - + if (keypm && cc == &cc_dummy) { + /* Add the keys of the parameter in keypm. */ + scanhashtable(keypm->gets.hfn(keypm), 0, 0, PM_UNSET, addhnmatch, 0); + keypm = NULL; + cc_dummy.suffix = NULL; + } if (!errflag && cc->ylist) { /* generate the user-defined display list: if anything fails, * * we silently allow the normal completion list to be used. */ diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c index 4cdb3c52d..8524fd21e 100644 --- a/Src/Zle/zle_utils.c +++ b/Src/Zle/zle_utils.c @@ -572,10 +572,8 @@ undo(void) static void unapplychange(struct change *ch) { - if(ch->hist != histline) { - remember_edits(); - setline(zle_get_event(histline = ch->hist)); - } + if(ch->hist != histline) + zle_setline(quietgethist(ch->hist)); cs = ch->off; if(ch->ins) foredel(ztrlen(ch->ins)); @@ -613,10 +611,8 @@ redo(void) static void applychange(struct change *ch) { - if(ch->hist != histline) { - remember_edits(); - setline(zle_get_event(histline = ch->hist)); - } + if(ch->hist != histline) + zle_setline(quietgethist(ch->hist)); cs = ch->off; if(ch->del) foredel(ztrlen(ch->del)); diff --git a/Src/builtin.c b/Src/builtin.c index 9ffcad1b3..8436cde33 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -120,7 +120,7 @@ static struct builtin builtins[] = BUILTIN("which", 0, bin_whence, 0, -1, 0, "ampsw", "c"), #ifdef DYNAMIC - BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "LaudicIp", NULL), + BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "ILabcdipu", NULL), #endif }; @@ -142,6 +142,7 @@ createbuiltintable(void) builtintab->hash = hasher; builtintab->emptytable = NULL; builtintab->filltable = NULL; + builtintab->cmpnodes = strcmp; builtintab->addnode = addhashnode; builtintab->getnode = gethashnode; builtintab->getnode2 = gethashnode2; @@ -1146,19 +1147,17 @@ bin_fc(char *nam, char **argv, char *ops, int func) } if (ops['R']) { /* read history from a file */ - readhistfile(*argv ? *argv : getsparam("HISTFILE"), 1); + readhistfile(*argv, 1, ops['I'] ? HFILE_SKIPOLD : 0); return 0; } if (ops['W']) { /* write history to a file */ - savehistfile(*argv ? *argv : getsparam("HISTFILE"), 1, - (ops['I'] ? 2 : 0)); + savehistfile(*argv, 1, ops['I'] ? HFILE_SKIPOLD : 0); return 0; } if (ops['A']) { /* append history to a file */ - savehistfile(*argv ? *argv : getsparam("HISTFILE"), 1, - (ops['I'] ? 3 : 1)); + savehistfile(*argv, 1, HFILE_APPEND | (ops['I'] ? HFILE_SKIPOLD : 0)); return 0; } if (!(ops['l'] && unset(HISTNOSTORE))) @@ -1200,9 +1199,9 @@ bin_fc(char *nam, char **argv, char *ops, int func) } /* default values of first and last, and range checking */ if (first == -1) - first = (ops['l']) ? curhist - 16 : curhist - 1; + first = ops['l']? addhistnum(curhist,-16,0) : addhistnum(curhist,-1,0); if (last == -1) - last = (ops['l']) ? curhist - 1 : first; + last = ops['l']? addhistnum(curhist,-1,0) : first; if (first < firsthist()) first = firsthist(); if (last == -1) @@ -1267,7 +1266,7 @@ fcgetcomm(char *s) * numbers indicate reversed numbering. */ if ((cmd = atoi(s))) { if (cmd < 0) - cmd = curhist + cmd; + cmd = addhistnum(curhist,cmd,HIST_FOREIGN); if (cmd >= curhist) { zwarnnam("fc", "bad history number: %d", 0, cmd); return -1; @@ -1331,7 +1330,7 @@ static int fclist(FILE *f, int n, int r, int D, int d, int first, int last, struct asgment *subs, Comp com) { int fclistdone = 0; - char *s, *hs; + char *s; Histent ent; /* reverse range if required */ @@ -1344,28 +1343,31 @@ fclist(FILE *f, int n, int r, int D, int d, int first, int last, struct asgment if (!subs) fclistdone = 1; - for (;;) { - hs = quietgetevent(first); - if (!hs) { + ent = gethistent(first, first < last? GETHIST_DOWNWARD : GETHIST_UPWARD); + if (!ent || ent->histnum < first || ent->histnum > last) { + if (first == last) zwarnnam("fc", "no such event: %d", NULL, first); - return 1; - } - s = dupstring(hs); + else + zwarnnam("fc", "no events in that range", NULL, 0); + return 1; + } + + for (;;) { + s = dupstring(ent->text); /* this if does the pattern matching, if required */ if (!com || domatch(s, com, 0)) { /* perform substitution */ fclistdone |= fcsubs(&s, subs); /* do numbering */ - if (n) - fprintf(f, "%5d ", first); - ent = NULL; + if (n) { + fprintf(f, "%5d%c ", ent->histnum, + ent->flags & HIST_FOREIGN? '*' : ' '); + } /* output actual time (and possibly date) of execution of the command, if required */ if (d) { struct tm *ltm; - if (!ent) - ent = gethistent(first); ltm = localtime(&ent->stim); if (d >= 2) { if (d >= 8) { @@ -1387,8 +1389,6 @@ fclist(FILE *f, int n, int r, int D, int d, int first, int last, struct asgment /* display the time taken by the command, if required */ if (D) { long diff; - if (!ent) - ent = gethistent(first); diff = (ent->ftim) ? ent->ftim - ent->stim : 0; fprintf(f, "%ld:%02ld ", diff / 60, diff % 60); } @@ -1401,12 +1401,14 @@ fclist(FILE *f, int n, int r, int D, int d, int first, int last, struct asgment fprintf(f, "%s\n", s); } /* move on to the next history line, or quit the loop */ - if (first == last) - break; - else if (first > last) - first--; - else - first++; + if (first < last) { + if (!(ent = down_histent(ent)) || ent->histnum > last) + break; + } + else { + if (!(ent = up_histent(ent)) || ent->histnum < last) + break; + } } /* final processing */ @@ -1768,7 +1770,8 @@ bin_typeset(char *name, char **argv, char *ops, int func) for (i = 0; i < paramtab->hsize; i++) { for (pm = (Param) paramtab->nodes[i]; pm; pm = (Param) pm->next) { - if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) + if (((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) || + (pm->flags & PM_UNSET)) continue; if (domatch(pm->nam, com, 0)) addlinknode(pmlist, pm); @@ -2523,10 +2526,7 @@ bin_print(char *name, char **args, char *ops, int func) char **pargs = args; PERMALLOC { - ent = gethistent(++curhist); - zsfree(ent->text); - if (ent->nwords) - zfree(ent->words, ent->nwords*2*sizeof(short)); + ent = prepnexthistent(++curhist); while (*pargs++) nwords++; if ((ent->nwords = nwords)) { @@ -2543,6 +2543,7 @@ bin_print(char *name, char **args, char *ops, int func) ent->text = zjoin(args, ' '); ent->stim = ent->ftim = time(NULL); ent->flags = 0; + addhistnode(histtab, ent->text, ent); } LASTALLOC; return 0; } @@ -2952,7 +2953,7 @@ zexit(int val, int from_signal) killrunjobs(from_signal); if (isset(RCS) && interact) { if (!nohistsave) - savehistfile(getsparam("HISTFILE"), 1, isset(APPENDHISTORY) ? 3 : 0); + savehistfile(NULL, 1, HFILE_USE_OPTIONS); if (islogin && !subsh) { sourcehome(".zlogout"); #ifdef GLOBAL_ZLOGOUT diff --git a/Src/exec.c b/Src/exec.c index 764b7140c..da2bf9fe2 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1862,7 +1862,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1) /* If we are exec'ing a command, and we are not in a subshell, * * then check if we should save the history file. */ if (isset(RCS) && interact && !nohistsave) - savehistfile(getsparam("HISTFILE"), 1, isset(APPENDHISTORY) ? 3 : 0); + savehistfile(NULL, 1, HFILE_USE_OPTIONS); exit(lastval); } @@ -1874,7 +1874,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1) /* If we are exec'ing a command, and we are not * * in a subshell, then save the history file. */ if (!subsh && isset(RCS) && interact && !nohistsave) - savehistfile(getsparam("HISTFILE"), 1, isset(APPENDHISTORY) ? 3 : 0); + savehistfile(NULL, 1, HFILE_USE_OPTIONS); } if (type == SIMPLE) { if (cmd->vars) { @@ -2232,7 +2232,7 @@ getoutput(char *cmd, int qt) zclose(pipes[1]); retval = readoutput(pipes[0], qt); fdtable[pipes[0]] = 0; - child_suspend(0); /* unblocks */ + waitforpid(pid); /* unblocks */ lastval = cmdoutval; return retval; } diff --git a/Src/hashtable.c b/Src/hashtable.c index 72e4db21b..0a640349b 100644 --- a/Src/hashtable.c +++ b/Src/hashtable.c @@ -83,7 +83,7 @@ hasher(char *str) unsigned hashval = 0; while (*str) - hashval += (hashval << 5) + ((unsigned) *str++); + hashval += (hashval << 5) + *(unsigned char *)str++; return hashval; } @@ -138,7 +138,7 @@ deletehashtable(HashTable ht) } /* Add a node to a hash table. * - * nam is the key to use in hashing. dat is a pointer * + * nam is the key to use in hashing. nodeptr points * * to the node to add. If there is already a node in * * the table with the same key, it is first freed, and * * then the new node is added. If the number of nodes * @@ -148,6 +148,17 @@ deletehashtable(HashTable ht) /**/ void addhashnode(HashTable ht, char *nam, void *nodeptr) +{ + HashNode oldnode = addhashnode2(ht, nam, nodeptr); + if (oldnode) + ht->freenode(oldnode); +} + +/* Add a node to a hash table, returning the old node on replacment. */ + +/**/ +HashNode +addhashnode2(HashTable ht, char *nam, void *nodeptr) { unsigned hashval; HashNode hn, hp, hq; @@ -164,11 +175,11 @@ addhashnode(HashTable ht, char *nam, void *nodeptr) ht->nodes[hashval] = hn; if (++ht->ct >= ht->hsize * 2 && !ht->scan) expandhashtable(ht); - return; + return NULL; } /* else check if the first node contains the same key */ - if (!strcmp(hp->nam, hn->nam)) { + if (ht->cmpnodes(hp->nam, hn->nam) == 0) { ht->nodes[hashval] = hn; replacing: hn->next = hp->next; @@ -182,15 +193,14 @@ addhashnode(HashTable ht, char *nam, void *nodeptr) } else if(ht->scan->u.u == hp) ht->scan->u.u = hn; } - ht->freenode(hp); - return; + return hp; } /* else run through the list and check all the keys */ hq = hp; hp = hp->next; for (; hp; hq = hp, hp = hp->next) { - if (!strcmp(hp->nam, hn->nam)) { + if (ht->cmpnodes(hp->nam, hn->nam) == 0) { hq->next = hn; goto replacing; } @@ -201,6 +211,7 @@ addhashnode(HashTable ht, char *nam, void *nodeptr) ht->nodes[hashval] = hn; if (++ht->ct >= ht->hsize * 2 && !ht->scan) expandhashtable(ht); + return NULL; } /* Get an enabled entry in a hash table. * @@ -217,7 +228,7 @@ gethashnode(HashTable ht, char *nam) hashval = ht->hash(nam) % ht->hsize; for (hp = ht->nodes[hashval]; hp; hp = hp->next) { - if (!strcmp(hp->nam, nam)) { + if (ht->cmpnodes(hp->nam, nam) == 0) { if (hp->flags & DISABLED) return NULL; else @@ -241,7 +252,7 @@ gethashnode2(HashTable ht, char *nam) hashval = ht->hash(nam) % ht->hsize; for (hp = ht->nodes[hashval]; hp; hp = hp->next) { - if (!strcmp(hp->nam, nam)) + if (ht->cmpnodes(hp->nam, nam) == 0) return hp; } return NULL; @@ -267,7 +278,7 @@ removehashnode(HashTable ht, char *nam) return NULL; /* else check if the key in the first one matches */ - if (!strcmp(hp->nam, nam)) { + if (ht->cmpnodes(hp->nam, nam) == 0) { ht->nodes[hashval] = hp->next; gotit: ht->ct--; @@ -288,7 +299,7 @@ removehashnode(HashTable ht, char *nam) hq = hp; hp = hp->next; for (; hp; hq = hp, hp = hp->next) { - if (!strcmp(hp->nam, nam)) { + if (ht->cmpnodes(hp->nam, nam) == 0) { hq->next = hp->next; goto gotit; } @@ -316,7 +327,7 @@ enablehashnode(HashNode hn, int flags) hn->flags &= ~DISABLED; } -/* Compare two hash table entries */ +/* Compare two hash table entries by name */ /**/ static int @@ -498,6 +509,7 @@ emptyhashtable(HashTable ht) resizehashtable(ht, ht->hsize); } +/**/ #ifdef ZSH_HASH_DEBUG /* Print info about hash table */ @@ -550,6 +562,7 @@ bin_hashinfo(char *nam, char **args, char *ops, int func) return 0; } +/**/ #endif /* ZSH_HASH_DEBUG */ /********************************/ @@ -577,6 +590,7 @@ createcmdnamtable(void) cmdnamtab->hash = hasher; cmdnamtab->emptytable = emptycmdnamtable; cmdnamtab->filltable = fillcmdnamtable; + cmdnamtab->cmpnodes = strcmp; cmdnamtab->addnode = addhashnode; cmdnamtab->getnode = gethashnode2; cmdnamtab->getnode2 = gethashnode2; @@ -747,6 +761,7 @@ createshfunctable(void) shfunctab->hash = hasher; shfunctab->emptytable = NULL; shfunctab->filltable = NULL; + shfunctab->cmpnodes = strcmp; shfunctab->addnode = addhashnode; shfunctab->getnode = gethashnode; shfunctab->getnode2 = gethashnode2; @@ -920,6 +935,7 @@ createreswdtable(void) reswdtab->hash = hasher; reswdtab->emptytable = NULL; reswdtab->filltable = NULL; + reswdtab->cmpnodes = strcmp; reswdtab->addnode = addhashnode; reswdtab->getnode = gethashnode; reswdtab->getnode2 = gethashnode2; @@ -980,6 +996,7 @@ createaliastable(void) aliastab->hash = hasher; aliastab->emptytable = NULL; aliastab->filltable = NULL; + aliastab->cmpnodes = strcmp; aliastab->addnode = addhashnode; aliastab->getnode = gethashnode; aliastab->getnode2 = gethashnode2; @@ -1109,6 +1126,7 @@ createnameddirtable(void) nameddirtab->hash = hasher; nameddirtab->emptytable = emptynameddirtable; nameddirtab->filltable = fillnameddirtable; + nameddirtab->cmpnodes = strcmp; nameddirtab->addnode = addnameddirnode; nameddirtab->getnode = gethashnode; nameddirtab->getnode2 = gethashnode2; @@ -1219,3 +1237,137 @@ printnameddirnode(HashNode hn, int printflags) quotedzputs(nd->dir, stdout); putchar('\n'); } + +/*************************************/ +/* History Line Hash Table Functions */ +/*************************************/ + +/**/ +void +createhisttable(void) +{ + histtab = newhashtable(599, "histtab", NULL); + + histtab->hash = histhasher; + histtab->emptytable = emptyhisttable; + histtab->filltable = NULL; + histtab->cmpnodes = histstrcmp; + histtab->addnode = addhistnode; + histtab->getnode = gethashnode2; + histtab->getnode2 = gethashnode2; + histtab->removenode = removehashnode; + histtab->disablenode = NULL; + histtab->enablenode = NULL; + histtab->freenode = freehistnode; + histtab->printnode = NULL; +} + +/**/ +unsigned +histhasher(char *str) +{ + unsigned hashval = 0; + + while (inblank(*str)) str++; + + while (*str) { + if (inblank(*str)) { + do str++; while (inblank(*str)); + if (*str) + hashval += (hashval << 5) + ' '; + } + else + hashval += (hashval << 5) + *(unsigned char *)str++; + } + return hashval; +} + +/**/ +void +emptyhisttable(HashTable ht) +{ + emptyhashtable(ht); + if (hist_ring) + histremovedups(); +} + +/* Compare two strings with normalized white-space */ + +/**/ +int +histstrcmp(const char *str1, const char *str2) +{ + while (inblank(*str1)) str1++; + while (inblank(*str2)) str2++; + while (*str1 && *str2) { + if (inblank(*str1)) { + if (!inblank(*str2)) + break; + do str1++; while (inblank(*str1)); + do str2++; while (inblank(*str2)); + } + else { + if (*str1 != *str2) + break; + str1++; + str2++; + } + } + return *str1 - *str2; +} + +/**/ +void +addhistnode(HashTable ht, char *nam, void *nodeptr) +{ + HashNode oldnode = addhashnode2(ht, nam, nodeptr); + Histent he = (Histent)nodeptr; + if (oldnode && oldnode != nodeptr) { + if (he->flags & HIST_MAKEUNIQUE + || (he->flags & HIST_FOREIGN && (Histent)oldnode == he->up)) { + he->flags |= HIST_DUP; + addhashnode(ht, oldnode->nam, oldnode); /* Remove the new dup */ + } + else { + oldnode->flags |= HIST_DUP; + if (hist_ignore_all_dups) + freehistnode(oldnode); /* Remove the old dup */ + } + } + else + he->flags &= ~HIST_MAKEUNIQUE; +} + +/**/ +void +freehistnode(HashNode nodeptr) +{ + freehistdata((Histent)nodeptr, 1); + zfree(nodeptr, sizeof (struct histent)); +} + +/**/ +void +freehistdata(Histent he, int unlink) +{ + if (!he) + return; + + if (!(he->flags & HIST_DUP)) + removehashnode(histtab, he->text); + + zsfree(he->text); + if (he->nwords) + zfree(he->words, he->nwords*2*sizeof(short)); + + if (unlink) { + if (!--histlinect) + hist_ring = NULL; + else { + if (he == hist_ring) + hist_ring = hist_ring->up; + he->up->down = he->down; + he->down->up = he->up; + } + } +} diff --git a/Src/hist.c b/Src/hist.c index e104e1f3e..55209a1c0 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -56,23 +56,29 @@ int excs, exlast; * Note on curhist: with history inactive, this points to the * last line actually added to the history list. With history active, * the line does not get added to the list until hend(), if at all. - * However, curhist is incremented to reflect the current line anyway. - * Thus if the line is not added to the list, curhist must be + * However, curhist is incremented to reflect the current line anyway + * and a temporary history entry is inserted while the user is editing. + * If the resulting line was not added to the list, curhist is * decremented in hend(). */ /**/ int curhist; -/* number of history entries */ - /**/ -int histentct; - -/* array of history entries */ - +struct histent curline; + +/* current line count of allocated history entries */ + +/**/ +int histlinect; + +/* The history lines are kept in a hash, and also doubly-linked in a ring */ + +/**/ +HashTable histtab; /**/ -Histent histentarr; +Histent hist_ring; /* capacity of history lists */ @@ -90,6 +96,17 @@ int histdone; /**/ int histactive; +/* Current setting of the associated option, but sometimes also includes + * the setting of the HIST_SAVE_NO_DUPS option. */ + +/**/ +int hist_ignore_all_dups; + +/* What flags (if any) we should skip when moving through the history */ + +/**/ +int hist_skip_flags; + /* Bits of histactive variable */ #define HA_ACTIVE (1<<0) /* History mechanism is active */ #define HA_NOSTORE (1<<1) /* Don't store the line when finished */ @@ -395,7 +412,7 @@ histsubchar(int c) if (!*buf) { if (c != '%') { if (isset(CSHJUNKIEHISTORY)) - ev = curhist - 1; + ev = addhistnum(curhist,-1,HIST_FOREIGN); else ev = defev; if (c == ':' && evset == -1) @@ -410,10 +427,10 @@ histsubchar(int c) evset = 0; } } else if ((t0 = atoi(buf))) { - ev = (t0 < 0) ? curhist + t0 : t0; + ev = (t0 < 0) ? addhistnum(curhist,t0,HIST_FOREIGN) : t0; evset = 1; } else if ((unsigned)*buf == bangchar) { - ev = curhist - 1; + ev = addhistnum(curhist,-1,HIST_FOREIGN); evset = 1; } else if (*buf == '#') { ev = curhist; @@ -650,8 +667,6 @@ strinend(void) void hbegin(void) { - Histent curhistent; - isfirstln = isfirstch = 1; errflag = histdone = spaceflag = 0; stophist = (!interact || unset(BANGHIST) || unset(SHINSTDIN)) << 1; @@ -661,43 +676,23 @@ hbegin(void) if (histactive & HA_JUNKED) curhist--; - curhistent = gethistent(curhist); - if (!curhistent->ftim) - curhistent->ftim = time(NULL); - histactive = HA_ACTIVE; + if (hist_ring && !hist_ring->ftim) + hist_ring->ftim = time(NULL); if (interact && isset(SHINSTDIN) && !strin) { + histactive = HA_ACTIVE; attachtty(mypgrp); - defev = curhist; - curhist++; + if (!hist_ring) + hist_ring = curline.up = curline.down = &curline; + else { + curline.up = hist_ring; + curline.down = hist_ring->down; + hist_ring->down = hist_ring->down->up = &curline; + hist_ring = &curline; + } + curline.histnum = ++curhist; + defev = addhistnum(curhist, -1, HIST_FOREIGN); } else - histactive |= HA_NOINC; -} - -/* compare current line with history entry using only text in words */ - -/**/ -static int -histcmp(Histent he) -{ - int kword, lword; - int nwords = chwordpos/2; - - /* If the history entry came from a file, the words were not - * divided by the lexer so we have to resort to strcmp. - */ - if (he->flags & HIST_READ) - return strcmp(he->text, chline); - - if (nwords != he->nwords) - return 1; - - for (kword = 0; kword < 2*nwords; kword += 2) - if ((lword = chwords[kword+1]-chwords[kword]) - != he->words[kword+1]-he->words[kword] || - memcmp(he->text+he->words[kword], chline+chwords[kword], lword)) - return 1; - - return 0; + histactive = HA_ACTIVE | HA_NOINC; } /**/ @@ -726,6 +721,140 @@ histreduceblanks(void) chline[pos] = '\0'; } +/**/ +void +histremovedups(void) +{ + Histent he, next; + for (he = hist_ring; he; he = next) { + next = up_histent(he); + if (he->flags & HIST_DUP) + freehistnode((HashNode)he); + } +} + +/**/ +int +addhistnum(int hl, int n, int xflags) +{ + int dir = n < 0? -1 : n > 0? 1 : 0; + Histent he = gethistent(hl, dir); + + if (!he) + return 0; + if (he->histnum != hl) + n -= dir; + if (n) + he = movehistent(he, n, xflags); + if (!he) + return dir < 0? firsthist() : curhist; + return he->histnum; +} + +/**/ +Histent +movehistent(Histent he, int n, int xflags) +{ + while (n < 0) { + if (!(he = up_histent(he))) + return NULL; + if (!(he->flags & xflags)) + n++; + } + while (n > 0) { + if (!(he = down_histent(he))) + return NULL; + if (!(he->flags & xflags)) + n--; + } + return he; +} + +/**/ +Histent +up_histent(Histent he) +{ + return he->up == hist_ring? NULL : he->up; +} + +/**/ +Histent +down_histent(Histent he) +{ + return he == hist_ring? NULL : he->down; +} + +/**/ +Histent +gethistent(int ev, int nearmatch) +{ + Histent he; + + if (!hist_ring) + return NULL; + + if (ev - hist_ring->down->histnum < hist_ring->histnum - ev) { + for (he = hist_ring->down; he->histnum <= ev; he = he->down) { + if (he->histnum == ev) + return he; + } + if (nearmatch < 0) + return up_histent(he); + if (nearmatch > 0) + return he; + } + else { + for (he = hist_ring; he->histnum >= ev; he = he->up) { + if (he->histnum == ev) + return he; + } + if (nearmatch < 0) + return he; + if (nearmatch > 0) + return down_histent(he); + } + + return NULL; +} + +/**/ +Histent +prepnexthistent(int histnum) +{ + Histent he; + + if (histlinect < histsiz) { + he = (Histent)zcalloc(sizeof *he); + if (!hist_ring) + hist_ring = he->up = he->down = he; + else { + he->up = hist_ring; + he->down = hist_ring->down; + hist_ring->down = he->down->up = he; + hist_ring = he; + } + histlinect++; + } + else { + he = hist_ring->down; + if (isset(HISTEXPIREDUPSFIRST) && !(he->flags & HIST_DUP)) { + do { + he = he->down; + } while (he != hist_ring->down && !(he->flags & HIST_DUP)) ; + if (he != hist_ring->down) { + he->up->down = he->down; + he->down->up = he->up; + he->up = hist_ring; + he->down = hist_ring->down; + hist_ring->down = he->down->up = he; + } + } + freehistdata(hist_ring = he, 0); + } + hist_ring->histnum = histnum; + return hist_ring; +} + /* say we're done using the history mechanism */ /**/ @@ -733,19 +862,35 @@ int hend(void) { int flag, save = 1; + char *hf = getsparam("HISTFILE"); DPUTS(!chline, "BUG: chline is NULL in hend()"); if (histdone & HISTFLAG_SETTY) settyinfo(&shttyinfo); + if (!(histactive & HA_NOINC)) { + curline.up->down = curline.down; + curline.down->up = curline.up; + if (hist_ring == &curline) { + if (!histlinect) + hist_ring = NULL; + else + hist_ring = curline.up; + } + curhist--; + } if (histactive & (HA_NOSTORE|HA_NOINC)) { zfree(chline, hlinesz); zfree(chwords, chwordlen*sizeof(short)); chline = NULL; - if (!(histactive & HA_NOINC)) - curhist--; histactive = 0; return 1; } + if (hist_ignore_all_dups != isset(HISTIGNOREALLDUPS) + && (hist_ignore_all_dups = isset(HISTIGNOREALLDUPS)) != 0) + histremovedups(); + /* For history sharing, lock history file once for both read and write */ + if (isset(SHAREHISTORY) && lockhistfile(hf, 0)) + readhistfile(hf, 0, HFILE_USE_OPTIONS | HFILE_FAST); flag = histdone; histdone = 0; if (hptr < chline + 1) @@ -781,8 +926,10 @@ hend(void) } if (save) { Histent he; - int keepflags = 0; + int keepflags; + for (he = hist_ring; he && he->flags & hist_skip_flags; + he = up_histent(he)) ; #ifdef DEBUG /* debugging only */ if (chwordpos%2) { @@ -796,23 +943,21 @@ hend(void) /* strip superfluous blanks, if desired */ if (isset(HISTREDUCEBLANKS)) histreduceblanks(); - - if (isset(HISTIGNOREDUPS) && (he = gethistent(curhist - 1)) - && he->text && !histcmp(he)) { + if ((isset(HISTIGNOREDUPS) || isset(HISTIGNOREALLDUPS)) && he + && histstrcmp(chline, he->text) == 0) { /* This history entry compares the same as the previous. * In case minor changes were made, we overwrite the - * previous one with the current one. This also gets - * the timestamp right. However, keep the old flags. + * previous one with the current one. This also gets the + * timestamp right. Perhaps, preserve the HIST_OLD flag. */ - keepflags = he->flags; - curhist--; + keepflags = he->flags & HIST_OLD; /* Avoid re-saving */ + freehistdata(he, 0); + } else { + keepflags = 0; + he = prepnexthistent(++curhist); } - he = gethistent(curhist); - zsfree(he->text); he->text = ztrdup(chline); - if (he->nwords) - zfree(he->words, he->nwords*2*sizeof(short)); he->stim = time(NULL); he->ftim = 0L; he->flags = keepflags; @@ -821,12 +966,15 @@ hend(void) he->words = (short *)zalloc(chwordpos * sizeof(short)); memcpy(he->words, chwords, chwordpos * sizeof(short)); } - } else - curhist--; + addhistnode(histtab, he->text, he); + } zfree(chline, hlinesz); zfree(chwords, chwordlen*sizeof(short)); chline = NULL; histactive = 0; + if (isset(SHAREHISTORY) || isset(INCREMENTALAPPENDHISTORY)) + savehistfile(hf, 1, HFILE_USE_OPTIONS | HFILE_FAST); + unlockhistfile(hf); /* It's OK to call this even if we aren't locked */ return !(flag & HISTFLAG_NOEXEC || errflag); } @@ -838,10 +986,7 @@ remhist(void) { if (!(histactive & HA_ACTIVE)) { if (!(histactive & HA_JUNKED)) { - /* make sure this doesn't show up when we do firsthist() */ - Histent he = gethistent(curhist); - zsfree(he->text); - he->text = NULL; + freehistnode((HashNode)hist_ring); histactive |= HA_JUNKED; /* curhist-- is delayed until the next hbegin() */ } @@ -1026,18 +1171,21 @@ getargspec(int argc, int marg, int evset) static int hconsearch(char *str, int *marg) { - int t0, t1 = 0; + int t1 = 0; char *s; Histent he; - for (t0 = curhist - 1; (he = quietgethist(t0)); t0--) + for (he = up_histent(hist_ring); he; he = up_histent(he)) { + if (he->flags & HIST_FOREIGN) + continue; if ((s = strstr(he->text, str))) { int pos = s - he->text; while (t1 < he->nwords && he->words[2*t1] <= pos) t1++; *marg = t1 - 1; - return t0; + return he->histnum; } + } return -1; } @@ -1047,12 +1195,15 @@ hconsearch(char *str, int *marg) int hcomsearch(char *str) { - int t0; - char *hs; + Histent he; + int len = strlen(str); - for (t0 = curhist - 1; (hs = quietgetevent(t0)); t0--) - if (!strncmp(hs, str, strlen(str))) - return t0; + for (he = up_histent(hist_ring); he; he = up_histent(he)) { + if (he->flags & HIST_FOREIGN) + continue; + if (strncmp(he->text, str, len) == 0) + return he->histnum; + } return -1; } @@ -1206,33 +1357,15 @@ convamps(char *out, char *in, int inlen) } /**/ -struct histent * +Histent quietgethist(int ev) { - static struct histent storehist; - - if (ev < firsthist() || ev > curhist) - return NULL; if (ev == curhist && (histactive & HA_ACTIVE)) { - /* The current history line has not been stored. Build it up - * from other variables. - */ - storehist.text = chline; - storehist.nwords = chwordpos/2; - storehist.words = chwords; - - return &storehist; - } else - return gethistent(ev); -} - -/**/ -char * -quietgetevent(int ev) -{ - Histent ent = quietgethist(ev); - - return ent ? ent->text : NULL; + curline.text = chline; + curline.nwords = chwordpos/2; + curline.words = chwords; + } + return gethistent(ev, GETHIST_EXACT); } /**/ @@ -1362,10 +1495,9 @@ quotebreak(char **tr) return 0; } -#if 0 /* read an arbitrary amount of data into a buffer until stop is found */ -/**/ +#if 0 /**/ char * hdynread(int stop) { @@ -1424,61 +1556,80 @@ hdynread2(int stop) void inithist(void) { - histentct = histsiz; - histentarr = (Histent) zcalloc(histentct * sizeof *histentarr); + createhisttable(); } /**/ void resizehistents(void) { - int newentct, t0, t1, firstlex; - Histent newarr; - - newentct = histsiz; - newarr = (Histent) zcalloc(newentct * sizeof *newarr); - firstlex = curhist - histsiz + 1; - t0 = firsthist(); - if (t0 < curhist - newentct) - t0 = curhist - newentct; - t1 = t0 % newentct; - for (; t0 <= curhist; t0++) { - newarr[t1] = *gethistent(t0); - if (t0 < firstlex) { - zsfree(newarr[t1].text); - newarr[t1].text = NULL; - } - t1++; - if (t1 == newentct) - t1 = 0; - } - free(histentarr); - histentarr = newarr; - histentct = newentct; + while (histlinect > histsiz) + freehistnode((HashNode)hist_ring->down); } +/* Remember the last line in the history file so we can find it again. */ +static struct { + char *text; + time_t stim, mtim; + off_t fpos, fsiz; + int next_write_ev; +} lasthist; + +static int histfile_linect; + /**/ void -readhistfile(char *s, int err) +readhistfile(char *fn, int err, int readflags) { - char *buf; + char *buf, *start = NULL; FILE *in; - Histent ent; - time_t tim = time(NULL); + Histent he; + time_t stim, ftim, tim = time(NULL); + off_t fpos; short *wordlist; + struct stat sb; int nwordpos, nwordlist, bufsiz; + int searching, newflags; - if (!s) + if (!fn && !(fn = getsparam("HISTFILE"))) + return; + if (readflags & HFILE_FAST) { + if (stat(fn, &sb) < 0 + || (lasthist.fsiz == sb.st_size && lasthist.mtim == sb.st_mtime) + || !lockhistfile(fn, 0)) + return; + lasthist.fsiz = sb.st_size; + lasthist.mtim = sb.st_mtime; + } + else if (!lockhistfile(fn, 1)) return; - if ((in = fopen(unmeta(s), "r"))) { + if ((in = fopen(unmeta(fn), "r"))) { nwordlist = 16; wordlist = (short *)zalloc(nwordlist*sizeof(short)); bufsiz = 1024; buf = zalloc(bufsiz); - while (fgets(buf, bufsiz, in)) { + if (readflags & HFILE_FAST && lasthist.text) { + if (lasthist.fpos < lasthist.fsiz) { + fseek(in, lasthist.fpos, 0); + searching = 1; + } + else { + histfile_linect = 0; + searching = -1; + } + } else + searching = 0; + + newflags = HIST_OLD | HIST_READ; + if (readflags & HFILE_FAST) + newflags |= HIST_FOREIGN; + if (readflags & HFILE_SKIPOLD + || (hist_ignore_all_dups && newflags & hist_skip_flags)) + newflags |= HIST_MAKEUNIQUE; + while (fpos = ftell(in), fgets(buf, bufsiz, in)) { int l = strlen(buf); - char *pt, *start; + char *pt; while (l) { while (buf[l - 1] != '\n') { @@ -1488,114 +1639,184 @@ readhistfile(char *s, int err) l++; break; } - l = strlen(buf); + l += strlen(buf+l); } buf[l - 1] = '\0'; if (l > 1 && buf[l - 2] == '\\') { - buf[l - 2] = '\n'; - fgets(buf + l - 1, bufsiz - (l - 1), in); - l = strlen(buf); + buf[--l - 1] = '\n'; + fgets(buf + l, bufsiz - l, in); + l += strlen(buf+l); } else break; } - ent = gethistent(++curhist); pt = buf; if (*pt == ':') { pt++; - ent->stim = zstrtol(pt, NULL, 0); + stim = zstrtol(pt, NULL, 0); for (; *pt != ':' && *pt; pt++); if (*pt) { pt++; - ent->ftim = zstrtol(pt, NULL, 0); + ftim = zstrtol(pt, NULL, 0); for (; *pt != ';' && *pt; pt++); if (*pt) pt++; - } else { - ent->ftim = tim; - } - if (ent->stim == 0) - ent->stim = tim; - if (ent->ftim == 0) - ent->ftim = tim; + } else + ftim = stim; } else { - ent->ftim = ent->stim = tim; + if (*pt == '\\' && pt[1] == ':') + pt++; + stim = ftim = 0; + } + + if (searching) { + if (searching > 0) { + if (stim == lasthist.stim + && histstrcmp(pt, lasthist.text) == 0) + searching = 0; + else { + fseek(in, 0, 0); + histfile_linect = 0; + searching = -1; + } + continue; + } + else if (stim < lasthist.stim) { + histfile_linect++; + continue; + } + searching = 0; } - zsfree(ent->text); - ent->text = ztrdup(pt); - ent->flags = HIST_OLD|HIST_READ; - if (ent->nwords) - zfree(ent->words, ent->nwords*2*sizeof(short)); + if (readflags & HFILE_USE_OPTIONS) { + histfile_linect++; + lasthist.fpos = fpos; + lasthist.stim = stim; + } + + he = prepnexthistent(++curhist); + he->text = ztrdup(pt); + he->flags = newflags; + if ((he->stim = stim) == 0) + he->stim = he->ftim = tim; + else if (ftim < stim) + he->ftim = stim + ftim; + else + he->ftim = ftim; /* Divide up the words. We don't know how it lexes, - so just look for spaces. + so just look for white-space. */ nwordpos = 0; start = pt; do { - while (*pt == ' ') + while (inblank(*pt)) pt++; if (*pt) { if (nwordpos >= nwordlist) wordlist = (short *) realloc(wordlist, (nwordlist += 16)*sizeof(short)); wordlist[nwordpos++] = pt - start; - while (*pt && *pt != ' ') + while (*pt && !inblank(*pt)) pt++; wordlist[nwordpos++] = pt - start; } } while (*pt); - ent->nwords = nwordpos/2; - if (ent->nwords) { - ent->words = (short *)zalloc(nwordpos*sizeof(short)); - memcpy(ent->words, wordlist, nwordpos*sizeof(short)); + he->nwords = nwordpos/2; + if (he->nwords) { + he->words = (short *)zalloc(nwordpos*sizeof(short)); + memcpy(he->words, wordlist, nwordpos*sizeof(short)); } else - ent->words = (short *)NULL; + he->words = (short *)NULL; + addhistnode(histtab, he->text, he); + if (hist_ring != he) + curhist--; /* We discarded a foreign duplicate */ + } + if (start && readflags & HFILE_USE_OPTIONS) { + zsfree(lasthist.text); + lasthist.text = ztrdup(start); } - fclose(in); - zfree(wordlist, nwordlist*sizeof(short)); zfree(buf, bufsiz); + + fclose(in); } else if (err) - zerr("can't read history file", s, 0); + zerr("can't read history file", fn, 0); + + unlockhistfile(fn); } /**/ void -savehistfile(char *s, int err, int app) +savehistfile(char *fn, int err, int writeflags) { - char *t; + char *t, *start = NULL; FILE *out; - int ev; - Histent ent; + Histent he; + int xcurhist = curhist - !!(histactive & HA_ACTIVE); int savehist = getiparam("SAVEHIST"); + int extended_history = isset(EXTENDEDHISTORY); - if (!s || !interact || savehist <= 0) + if (!interact || savehist <= 0 || !hist_ring + || (!fn && !(fn = getsparam("HISTFILE")))) return; - ev = curhist - savehist + 1; - if (ev < firsthist()) - ev = firsthist(); - if (app & 1) - out = fdopen(open(unmeta(s), - O_CREAT | O_WRONLY | O_APPEND | O_NOCTTY, 0600), "a"); - else - out = fdopen(open(unmeta(s), - O_CREAT | O_WRONLY | O_TRUNC | O_NOCTTY, 0600), "w"); + if (writeflags & HFILE_FAST) { + he = gethistent(lasthist.next_write_ev, GETHIST_DOWNWARD); + while (he && he->flags & HIST_OLD) { + lasthist.next_write_ev = he->histnum + 1; + he = down_histent(he); + } + if (!he || !lockhistfile(fn, 0)) + return; + if (histfile_linect > savehist + savehist / 5) + writeflags &= ~HFILE_FAST; + } + else { + if (!lockhistfile(fn, 1)) + return; + he = hist_ring->down; + } + if (writeflags & HFILE_USE_OPTIONS) { + if (isset(APPENDHISTORY) || isset(INCREMENTALAPPENDHISTORY) + || isset(SHAREHISTORY)) + writeflags |= HFILE_APPEND | HFILE_SKIPOLD; + else + histfile_linect = 0; + if (isset(HISTSAVENODUPS)) + writeflags |= HFILE_SKIPDUPS; + if (isset(SHAREHISTORY)) + extended_history = 1; + } + if (writeflags & HFILE_APPEND) { + out = fdopen(open(unmeta(fn), + O_CREAT | O_WRONLY | O_APPEND | O_NOCTTY, 0600), "a"); + } + else { + out = fdopen(open(unmeta(fn), + O_CREAT | O_WRONLY | O_TRUNC | O_NOCTTY, 0600), "w"); + } if (out) { - for (; ev <= curhist - !!(histactive & HA_ACTIVE); ev++) { - ent = gethistent(ev); - if (app & 2) { - if (ent->flags & HIST_OLD) + for (; he && he->histnum <= xcurhist; he = down_histent(he)) { + if ((writeflags & HFILE_SKIPDUPS && he->flags & HIST_DUP) + || (writeflags & HFILE_SKIPFOREIGN && he->flags & HIST_FOREIGN)) + continue; + if (writeflags & HFILE_SKIPOLD) { + if (he->flags & HIST_OLD) continue; - ent->flags |= HIST_OLD; + he->flags |= HIST_OLD; + if (writeflags & HFILE_USE_OPTIONS) + lasthist.next_write_ev = he->histnum + 1; } - t = ent->text; - if (isset(EXTENDEDHISTORY)) { - fprintf(out, ": %ld:%ld;", - (long)ent->stim, - (long)ent->ftim); + if (writeflags & HFILE_USE_OPTIONS) { + lasthist.fpos = ftell(out); + lasthist.stim = he->stim; + histfile_linect++; + } + t = start = he->text; + if (extended_history) { + fprintf(out, ": %ld:%ld;", (long)he->stim, + he->ftim? (long)(he->ftim - he->stim) : 0L); } else if (*t == ':') fputc('\\', out); @@ -1606,69 +1827,109 @@ savehistfile(char *s, int err, int app) } fputc('\n', out); } + if (start && writeflags & HFILE_USE_OPTIONS) { + struct stat sb; + fflush(out); + if (fstat(fileno(out), &sb) == 0) { + lasthist.fsiz = sb.st_size; + lasthist.mtim = sb.st_mtime; + } + zsfree(lasthist.text); + lasthist.text = ztrdup(start); + } fclose(out); - if (app & 2 && (out = fopen(unmeta(s), "r"))) { - char **store, buf[1024], **ptr; - int i, l, histnum = 0; - - store = (char **)zcalloc((savehist + 1) * sizeof *store); - while (fgets(buf, sizeof(buf), out)) { - char *t; - - if (store[i = histnum % savehist]) - free(store[i]); - store[i] = ztrdup(buf); - l = strlen(buf); - if (l > 1) { - t = store[i] + l; - while ((t[-1] != '\n' || - (t[-1] == '\n' && t[-2] == '\\')) && - fgets(buf, sizeof(buf), out)) { - l += strlen(buf); - store[i] = zrealloc(store[i], l + 1); - t = store[i] + l; - strcat(store[i], buf); - } - } - histnum++; - } - fclose(out); - if ((out = fdopen(open(unmeta(s), - O_WRONLY | O_TRUNC | O_NOCTTY, 0600), "w"))) { - if (histnum < savehist) - for (i = 0; i < histnum; i++) - fprintf(out, "%s", store[i]); - else - for (i = histnum; i < histnum + savehist; i++) - fprintf(out, "%s", store[i % savehist]); - fclose(out); - } - for (ptr = store; *ptr; ptr++) - zsfree(*ptr); - free(store); + if ((writeflags & (HFILE_SKIPOLD | HFILE_FAST)) == HFILE_SKIPOLD) { + HashTable remember_histtab = histtab; + Histent remember_hist_ring = hist_ring; + int remember_histlinect = histlinect; + int remember_curhist = curhist; + + hist_ring = NULL; + curhist = histlinect = 0; + histsiz = savehist; + createhisttable(); /* sets histtab */ + + hist_ignore_all_dups |= isset(HISTSAVENODUPS); + readhistfile(fn, err, 0); + hist_ignore_all_dups = isset(HISTIGNOREALLDUPS); + savehistfile(fn, err, 0); + deletehashtable(histtab); + + curhist = remember_curhist; + histlinect = remember_histlinect; + hist_ring = remember_hist_ring; + histtab = remember_histtab; } } else if (err) - zerr("can't write history file %s", s, 0); + zerr("can't write history file %s", fn, 0); + + unlockhistfile(fn); } +static int lockhistct; + /**/ int -firsthist(void) +lockhistfile(char *fn, int keep_trying) { - int ev; - Histent ent; + int ct = lockhistct; - ev = curhist - histentct + 1; - if (ev < 1) - ev = 1; - do { - ent = gethistent(ev); - if (ent->text) - break; - ev++; + if (!fn && !(fn = getsparam("HISTFILE"))) + return 0; + if (!lockhistct++) { + struct stat sb; + int fd, len = strlen(fn); + char *tmpfile, *lockfile; + + tmpfile = zalloc(len + 10 + 1); + sprintf(tmpfile, "%s.%ld", fn, mypid); + if ((fd = open(tmpfile, O_RDWR|O_CREAT|O_EXCL, 0644)) >= 0) { + write(fd, "0\n", 2); + close(fd); + lockfile = zalloc(len + 5 + 1); + sprintf(lockfile, "%s.LOCK", fn); + while (link(tmpfile, lockfile) < 0) { + if (stat(lockfile, &sb) < 0) { + if (errno == ENOENT) + continue; + } + else if (keep_trying) { + if (time(NULL) - sb.st_mtime < 10) + sleep(1); + else + unlink(lockfile); + continue; + } + lockhistct--; + break; + } + free(lockfile); + } + unlink(tmpfile); + free(tmpfile); } - while (ev < curhist); - return ev; + return ct != lockhistct; } +/* Unlock the history file if this corresponds to the last nested lock + * request. If we don't have the file locked, just return. + */ + +/**/ +void +unlockhistfile(char *fn) +{ + if (!fn && !(fn = getsparam("HISTFILE"))) + return; + if (--lockhistct) { + if (lockhistct < 0) + lockhistct = 0; + } + else { + char *lockfile = zalloc(strlen(fn) + 5 + 1); + sprintf(lockfile, "%s.LOCK", fn); + unlink(lockfile); + free(lockfile); + } +} diff --git a/Src/init.c b/Src/init.c index 6ad1e5100..e92a5000f 100644 --- a/Src/init.c +++ b/Src/init.c @@ -110,15 +110,14 @@ loop(int toplevel, int justonce) List prelist; if (toplevel && (prelist = getshfunc("preexec")) != &dummy_list) { - Histent he = gethistent(curhist); LinkList args; int osc = sfcontext; PERMALLOC { args = newlinklist(); addlinknode(args, "preexec"); - if (he && he->text) - addlinknode(args, he->text); + if (hist_ring) + addlinknode(args, hist_ring->text); } LASTALLOC; sfcontext = SFC_HOOK; doshfunc("preexec", prelist, args, 0, 1); @@ -642,11 +641,13 @@ setupvals(void) wrappers = NULL; #ifdef TIOCGWINSZ - adjustwinsize(); + adjustwinsize(0); #else - /* Using zero below sets the defaults from termcap */ - setiparam("COLUMNS", 0); - setiparam("LINES", 0); + /* columns and lines are normally zero, unless something different * + * was inhereted from the environment. If either of them are zero * + * the setiparam calls below set them to the defaults from termcap */ + setiparam("COLUMNS", columns); + setiparam("LINES", lines); #endif #ifdef HAVE_GETRLIMIT @@ -828,7 +829,7 @@ init_misc(void) } if (interact && isset(RCS)) - readhistfile(getsparam("HISTFILE"), 0); + readhistfile(NULL, 0, HFILE_USE_OPTIONS); } /* source a file */ diff --git a/Src/jobs.c b/Src/jobs.c index e94dd77e2..6ddef0f70 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -180,11 +180,14 @@ update_job(Job jn) } else { /* job is done, so remember return value */ lastval2 = val; /* If last process was run in the current shell, keep old status - * and let it handle its own traps + * and let it handle its own traps, but always allow the test + * for the pgrp. */ - if (job == thisjob && !(jn->stat & STAT_CURSH)) { - lastval = val; - inforeground = 1; + if (jn->stat & STAT_CURSH) + inforeground = 1; + else if (job == thisjob) { + lastval = val; + inforeground = 2; } } @@ -198,8 +201,20 @@ update_job(Job jn) /* is this job in the foreground of an interactive shell? */ if (mypgrp != pgrp && inforeground && (jn->gleader == pgrp || (pgrp > 1 && kill(-pgrp, 0) == -1))) { - attachtty(mypgrp); - adjustwinsize(); /* check window size and adjust if necessary */ + if (list_pipe) { + /* + * Oh, dear, we're right in the middle of some confusion + * of shell jobs on the righthand side of a pipeline, so + * it's death to call attachtty() just yet. Mark the + * fact in the job, so that the attachtty() will be called + * when the job is finally deleted. + */ + jn->stat |= STAT_ATTACH; + } else { + attachtty(mypgrp); + /* check window size and adjust if necessary */ + adjustwinsize(0); + } } } @@ -223,7 +238,7 @@ update_job(Job jn) * process group from the shell, so the shell will not receive * * terminal signals, therefore we we pretend that the shell got * * the signal too. */ - if (inforeground && isset(MONITOR) && WIFSIGNALED(status)) { + if (inforeground == 2 && isset(MONITOR) && WIFSIGNALED(status)) { int sig = WTERMSIG(status); if (sig == SIGINT || sig == SIGQUIT) { @@ -609,6 +624,11 @@ deletejob(Job jn) { struct process *pn, *nx; + if (jn->stat & STAT_ATTACH) { + attachtty(mypgrp); + adjustwinsize(0); + } + pn = jn->procs; jn->procs = NULL; for (; pn; pn = nx) { diff --git a/Src/module.c b/Src/module.c index 09f1fd5db..c966d4497 100644 --- a/Src/module.c +++ b/Src/module.c @@ -142,6 +142,7 @@ addwrapper(Module m, FuncWrap w) return 0; } +/**/ #ifdef DYNAMIC /* $module_path ($MODULE_PATH) */ @@ -238,6 +239,7 @@ deletewrapper(Module m, FuncWrap w) return 1; } +/**/ #ifdef AIXDYNAMIC #include @@ -273,6 +275,7 @@ load_and_bind(const char *fn) #define dlclose(X) unload(X) #define dlerror() (dlerrstr[0]) +/**/ #else #ifdef HAVE_DLFCN_H @@ -289,6 +292,7 @@ load_and_bind(const char *fn) # endif #endif +/**/ #ifdef HPUXDYNAMIC # define dlopen(file,mode) (void *)shl_load((file), (mode), (long) 0) # define dlclose(handle) shl_unload((shl_t)(handle)) @@ -309,6 +313,7 @@ hpux_dlsym(void *handle, char *name) # ifndef HAVE_DLCLOSE # define dlclose(X) ((X), 0) # endif +/**/ #endif #ifdef DLSYM_NEEDS_UNDERSCORE @@ -331,6 +336,7 @@ hpux_dlsym(void *handle, char *name) # define STR_FINISH_S "finish_%s" #endif /* !DLSYM_NEEDS_UNDERSCORE */ +/**/ #endif /* !AIXDYNAMIC */ #ifndef RTLD_LAZY @@ -408,6 +414,7 @@ find_module(const char *name) return NULL; } +/**/ #ifdef AIXDYNAMIC /**/ @@ -438,6 +445,7 @@ finish_module(Module m) return ((int (*)_((int,Module))) m->handle)(3, m); } +/**/ #else static Module_func @@ -523,6 +531,7 @@ finish_module(Module m) return r; } +/**/ #endif /* !AIXDYNAMIC */ /**/ @@ -664,7 +673,7 @@ autoloadscan(HashNode hn, int printflags) if(bn->flags & BINF_ADDED) return; if(printflags & PRINT_LIST) { - fputs("zmodload -a ", stdout); + fputs("zmodload -ab ", stdout); if(bn->optstr[0] == '-') fputs("-- ", stdout); quotedzputs(bn->optstr, stdout); @@ -687,7 +696,12 @@ autoloadscan(HashNode hn, int printflags) int bin_zmodload(char *nam, char **args, char *ops, int func) { - if(ops['d'] && ops['a']) { + if ((ops['b'] || ops['c'] || ops['p']) && !(ops['a'] || ops['u'])) { + zwarnnam(nam, "-b, -c, and -p must be combined with -a or -u", + NULL, 0); + return 1; + } + if (ops['d'] && ops['a']) { zwarnnam(nam, "-d cannot be combined with -a", NULL, 0); return 1; } @@ -695,16 +709,20 @@ bin_zmodload(char *nam, char **args, char *ops, int func) zwarnnam(nam, "what do you want to unload?", NULL, 0); return 1; } - if(ops['d']) + if (ops['d']) return bin_zmodload_dep(nam, args, ops); - else if(ops['a']) + else if ((ops['a'] || ops['b']) && !(ops['c'] || ops['p'])) return bin_zmodload_auto(nam, args, ops); - else if (ops['c'] || ops['C']) + else if (ops['c'] && !(ops['b'] || ops['p'])) return bin_zmodload_cond(nam, args, ops); - else if (ops['p']) + else if (ops['p'] && !(ops['b'] || ops['c'])) return bin_zmodload_param(nam, args, ops); - else + else if (!(ops['a'] || ops['b'] || ops['c'] || ops['p'])) return bin_zmodload_load(nam, args, ops); + else + zwarnnam(nam, "use only one of -b, -c, or -p", NULL, 0); + + return 1; } /**/ @@ -865,7 +883,7 @@ bin_zmodload_cond(char *nam, char **args, char *ops) for (p = condtab; p; p = p->next) { if (p->module) { if (ops['L']) { - fputs("zmodload -c", stdout); + fputs("zmodload -ac", stdout); if (p->flags & CONDF_INFIX) putchar('I'); printf(" %s %s\n", p->module, p->name); @@ -908,7 +926,7 @@ printautoparams(HashNode hn, int lon) if (pm->flags & PM_AUTOLOAD) { if (lon) - printf("zmodload -p %s %s\n", pm->u.str, pm->nam); + printf("zmodload -ap %s %s\n", pm->u.str, pm->nam); else printf("%s (%s)\n", pm->nam, pm->u.str); } @@ -1097,6 +1115,7 @@ bin_zmodload_load(char *nam, char **args, char *ops) } } +/**/ #endif /* DYNAMIC */ /* The list of module-defined conditions. */ @@ -1252,6 +1271,7 @@ deleteparamdefs(char const *nam, Paramdef d, int size) return 1; } +/**/ #ifdef DYNAMIC /* This adds a definition for autoloading a module for a condition. */ @@ -1342,4 +1362,5 @@ add_autoparam(char *nam, char *module) pm->flags |= PM_AUTOLOAD; } +/**/ #endif diff --git a/Src/options.c b/Src/options.c index 9010831c0..c0042a662 100644 --- a/Src/options.c +++ b/Src/options.c @@ -124,15 +124,20 @@ static struct optname optns[] = { {NULL, "hashlistall", OPT_ALL, HASHLISTALL}, {NULL, "histallowclobber", 0, HISTALLOWCLOBBER}, {NULL, "histbeep", OPT_ALL, HISTBEEP}, +{NULL, "histexpiredupsfirst", 0, HISTEXPIREDUPSFIRST}, +{NULL, "histfindnodups", 0, HISTFINDNODUPS}, +{NULL, "histignorealldups", 0, HISTIGNOREALLDUPS}, {NULL, "histignoredups", 0, HISTIGNOREDUPS}, {NULL, "histignorespace", 0, HISTIGNORESPACE}, {NULL, "histnofunctions", 0, HISTNOFUNCTIONS}, {NULL, "histnostore", 0, HISTNOSTORE}, {NULL, "histreduceblanks", 0, HISTREDUCEBLANKS}, +{NULL, "histsavenodups", 0, HISTSAVENODUPS}, {NULL, "histverify", 0, HISTVERIFY}, {NULL, "hup", OPT_EMULATE|OPT_ZSH, HUP}, {NULL, "ignorebraces", OPT_EMULATE|OPT_SH, IGNOREBRACES}, {NULL, "ignoreeof", 0, IGNOREEOF}, +{NULL, "incrementalappendhistory",0, INCREMENTALAPPENDHISTORY}, {NULL, "interactive", OPT_SPECIAL, INTERACTIVE}, {NULL, "interactivecomments", OPT_EMULATE|OPT_BOURNE, INTERACTIVECOMMENTS}, {NULL, "ksharrays", OPT_EMULATE|OPT_BOURNE, KSHARRAYS}, @@ -176,6 +181,7 @@ static struct optname optns[] = { {NULL, "restricted", OPT_SPECIAL, RESTRICTED}, {NULL, "rmstarsilent", OPT_BOURNE, RMSTARSILENT}, {NULL, "rmstarwait", 0, RMSTARWAIT}, +{NULL, "sharehistory", OPT_KSH, SHAREHISTORY}, {NULL, "shfileexpansion", OPT_EMULATE|OPT_BOURNE, SHFILEEXPANSION}, {NULL, "shglob", OPT_EMULATE|OPT_BOURNE, SHGLOB}, {NULL, "shinstdin", OPT_SPECIAL, SHINSTDIN}, @@ -378,9 +384,9 @@ printoptionnode(HashNode hn, int set) optno = -optno; if (isset(KSHOPTIONPRINT)) { if (defset(on)) - printf("no%-20s%s\n", on->nam, isset(optno) ? "off" : "on"); + printf("no%-19s %s\n", on->nam, isset(optno) ? "off" : "on"); else - printf("%-22s%s\n", on->nam, isset(optno) ? "on" : "off"); + printf("%-21s %s\n", on->nam, isset(optno) ? "on" : "off"); } else if (set == (isset(optno) ^ defset(on))) { if (set ^ isset(optno)) fputs("no", stdout); @@ -399,6 +405,7 @@ createoptiontable(void) optiontab->hash = hasher; optiontab->emptytable = NULL; optiontab->filltable = NULL; + optiontab->cmpnodes = strcmp; optiontab->addnode = addhashnode; optiontab->getnode = gethashnode; optiontab->getnode2 = gethashnode2; @@ -635,6 +642,8 @@ dosetopt(int optno, int value, int force) } } else if(!force && (optno == INTERACTIVE || optno == SHINSTDIN || optno == SINGLECOMMAND)) { + if (opts[optno] == value) + return 0; /* it is not permitted to change the value of these options */ return -1; } else if(!force && optno == USEZLE && value) { diff --git a/Src/params.c b/Src/params.c index d60f91990..a8b027988 100644 --- a/Src/params.c +++ b/Src/params.c @@ -270,6 +270,7 @@ newparamtable(int size, char const *name) ht->hash = hasher; ht->emptytable = emptyhashtable; ht->filltable = NULL; + ht->cmpnodes = strcmp; ht->addnode = addhashnode; ht->getnode = getparamnode; ht->getnode2 = getparamnode; @@ -282,6 +283,7 @@ newparamtable(int size, char const *name) return ht; } +/**/ #ifdef DYNAMIC /**/ static HashNode @@ -299,6 +301,7 @@ getparamnode(HashTable ht, char *nam) } return hn; } +/**/ #endif /* DYNAMIC */ /* Copy a parameter hash table */ @@ -1753,7 +1756,7 @@ unsetparam_pm(Param pm, int altflag, int exp) * Some specials, such as those used in zle, still need removing * from the parameter table; they have the PM_REMOVABLE flag. */ - if ((locallevel && locallevel >= pm->level) || + if ((pm->level && locallevel >= pm->level) || (pm->flags & (PM_SPECIAL|PM_REMOVABLE)) == PM_SPECIAL) return; @@ -1963,23 +1966,11 @@ intvarsetfn(Param pm, long x) void zlevarsetfn(Param pm, long x) { - if ((long *)pm->u.data == & columns) { - if(x <= 0) - x = tccolumns > 0 ? tccolumns : 80; - if (x > 2) - termflags &= ~TERM_NARROW; - else - termflags |= TERM_NARROW; - } else if ((long *)pm->u.data == & lines) { - if(x <= 0) - x = tclines > 0 ? tclines : 24; - if (x > 2) - termflags &= ~TERM_SHORT; - else - termflags |= TERM_SHORT; - } + long *p = (long *)pm->u.data; - *((long *)pm->u.data) = x; + *p = x; + if (p == &lines || p == &columns) + adjustwinsize(2 + (p == &columns)); } /* Function to set value of generic special scalar * diff --git a/Src/signals.c b/Src/signals.c index 65bac0f52..3e655cbfd 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -129,10 +129,9 @@ intr(void) install_handler(SIGINT); } -#if 0 /* disable ^C interrupts */ -/**/ +#if 0 /**/ void nointr(void) { @@ -505,7 +504,7 @@ handler(int sig) #ifdef SIGWINCH case SIGWINCH: - adjustwinsize(); /* check window size and adjust */ + adjustwinsize(1); /* check window size and adjust */ if (sigtrapped[SIGWINCH]) dotrap(SIGWINCH); break; diff --git a/Src/subst.c b/Src/subst.c index e8e22f943..4b60de120 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -245,35 +245,43 @@ singsub(char **s) * the result is stored in *a. If `a' is zero a multiple word result is * * joined using sep or the IFS parameter if sep is zero and the result * * is returned in *s. The return value is true iff the expansion * - * resulted in an empty list */ + * resulted in an empty list. * + * The mult_isarr variable is used by paramsubst() to tell if it yields * + * an array. */ + +static int mult_isarr; /**/ static int multsub(char **s, char ***a, int *isarr, char *sep) { LinkList foo; - int l; + int l, omi = mult_isarr; char **r, **p; + mult_isarr = 0; foo = newlinklist(); addlinknode(foo, *s); prefork(foo, 0); if (errflag) { if (isarr) *isarr = 0; + mult_isarr = omi; return 0; } - if ((l = countlinknodes(foo)) > 1 || a) { + if ((l = countlinknodes(foo))) { p = r = ncalloc((l + 1) * sizeof(char*)); while (nonempty(foo)) *p++ = (char *)ugetnode(foo); *p = NULL; - if (a) { + if (a && mult_isarr) { *a = r; *isarr = 1; + mult_isarr = omi; return 0; } *s = sepjoin(r, NULL); + mult_isarr = omi; return 0; } if (l) @@ -282,6 +290,7 @@ multsub(char **s, char ***a, int *isarr, char *sep) *s = dupstring(""); if (isarr) *isarr = 0; + mult_isarr = omi; return !l; } @@ -977,16 +986,12 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) skipparens(*s, *s == Inpar ? Outpar : Outbrace, &s); sav = *s; *s = 0; - if (multsub(&val, ((!aspar && (!quoted || nojoin)) ? &aval : NULL), - &isarr, NULL) && - quoted) { + if (multsub(&val, (aspar ? NULL : &aval), &isarr, NULL) && quoted) { isarr = -1; aval = alloc(sizeof(char *)); aspar = 0; } else if (aspar) idbeg = val; - if (isarr) - isarr = -1; copied = 1; *s = sav; v = (Value) NULL; @@ -1465,6 +1470,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) val = dupstring(buf); isarr = 0; } + mult_isarr = isarr; if (isarr > 0 && !plan9 && (!aval || !aval[0])) { val = dupstring(""); isarr = 0; @@ -1485,6 +1491,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) val = aval[0]; else isarr = 2; + mult_isarr = isarr; } } if (casmod) { diff --git a/Src/text.c b/Src/text.c index 88a27495d..d3eafaf9f 100644 --- a/Src/text.c +++ b/Src/text.c @@ -72,10 +72,9 @@ taddstr(char *s) tptr += sl; } -#if 0 /* add an integer to the text buffer */ -/**/ +#if 0 /**/ void taddint(int x) { diff --git a/Src/utils.c b/Src/utils.c index 86679e90f..faeeb0c58 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -209,10 +209,9 @@ nicechar(int c) return buf; } -#if 0 /* Output a string's visible representation. */ -/**/ +#if 0 /**/ void nicefputs(char *s, FILE *f) { @@ -853,27 +852,64 @@ int resetneeded; /**/ int winchanged; #endif - -/* check the size of the window and adjust if necessary */ + +/* check the size of the window and adjust if necessary. * + * The value of from: * + * 0: called from update_job or setupvals * + * 1: called from the SIGWINCH handler * + * 2: the user have just changed LINES manually * + * 3: the user have just changed COLUMNS manually */ /**/ void -adjustwinsize(void) +adjustwinsize(int from) { -#ifdef TIOCGWINSZ int oldcols = columns, oldrows = lines; +#ifdef TIOCGWINSZ + static int userlines, usercols; + if (SHTTY == -1) return; - ioctl(SHTTY, TIOCGWINSZ, (char *)&shttyinfo.winsize); - setiparam("COLUMNS", shttyinfo.winsize.ws_col); - setiparam("LINES", shttyinfo.winsize.ws_row); - if (zleactive && (oldcols != columns || oldrows != lines)) { + if (from == 2) + userlines = lines > 0; + if (from == 3) + usercols = columns > 0; + + if (!ioctl(SHTTY, TIOCGWINSZ, (char *)&shttyinfo.winsize)) { + if (!userlines || from == 1) + lines = shttyinfo.winsize.ws_row; + if (!usercols || from == 1) + columns = shttyinfo.winsize.ws_col; + } +#endif /* TIOCGWINSZ */ + + if (lines <= 0) + lines = tclines > 0 ? tclines : 24; + if (columns <= 0) + columns = tccolumns > 0 ? tccolumns : 80; + if (lines > 2) + termflags &= ~TERM_SHORT; + else + termflags |= TERM_SHORT; + if (columns > 2) + termflags &= ~TERM_NARROW; + else + termflags |= TERM_NARROW; + +#ifdef TIOCGWINSZ + if (interact && from >= 2) { + shttyinfo.winsize.ws_row = lines; + shttyinfo.winsize.ws_col = columns; + ioctl(SHTTY, TIOCSWINSZ, (char *)&shttyinfo.winsize); + } +#endif + + if (zleactive && (from >= 2 || oldcols != columns || oldrows != lines)) { resetneeded = winchanged = 1; zrefresh(); } -#endif /* TIOCGWINSZ */ } /* Move a fd to a place >= 10 and mark the new fd in fdtable. If the fd * @@ -3343,10 +3379,9 @@ dquotedztrdup(char const *s) return ret; } -#if 0 /* Unmetafy and output a string, double quoting it in its entirety. */ -/**/ +#if 0 /**/ int dquotedzputs(char const *s, FILE *stream) { diff --git a/Src/zsh.export b/Src/zsh.export index 7f994bf29..b62621e0f 100644 --- a/Src/zsh.export +++ b/Src/zsh.export @@ -4,6 +4,7 @@ addbuiltins addconddefs addedx addhashnode +addhistnum addparamdefs addwrapper arrvargetfn @@ -45,6 +46,7 @@ deleteparamdefs deletewrapper domatch doshfunc +down_histent dputs dquotedztrdup dummy_list @@ -97,6 +99,8 @@ hgetc hgetline histentarr histentct +hist_ring +hist_skip_flags holdintr hptr hrealloc @@ -132,6 +136,7 @@ metadiffer metafy metalen mode_to_octal +movehistent mypgrp mypid nameddirtab @@ -240,6 +245,7 @@ unmetafy unsetparam unsetparam_pm untokenize +up_histent uremnode useheap winchanged diff --git a/Src/zsh.h b/Src/zsh.h index 1eefc51c1..1d635afdc 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -294,7 +294,7 @@ struct linklist { #define peekfirst(X) ((X)->first->dat) #define pushnode(X,Y) insertlinknode(X,(LinkNode) X,Y) #define incnode(X) (X = nextnode(X)) -#define gethistent(X) (histentarr+((X)%histentct)) +#define firsthist() (hist_ring? hist_ring->down->histnum : curhist) /********************************/ @@ -611,6 +611,7 @@ struct job { #define STAT_CURSH (1<<9) /* last command is in current shell */ #define STAT_NOSTTY (1<<10) /* the tty settings are not inherited */ /* from this job when it exits. */ +#define STAT_ATTACH (1<<11) /* delay reattaching shell to tty */ #define SP_RUNNING -1 /* fake status for jobs currently running */ @@ -679,6 +680,7 @@ typedef void (*AddNodeFunc) _((HashTable, char *, void *)); typedef HashNode (*GetNodeFunc) _((HashTable, char *)); typedef HashNode (*RemoveNodeFunc) _((HashTable, char *)); typedef void (*FreeNodeFunc) _((HashNode)); +typedef int (*CompareFunc) _((const char *, const char *)); /* type of function that is passed to * * scanhashtable or scanmatchtable */ @@ -698,6 +700,7 @@ struct hashtable { HashFunc hash; /* pointer to hash function for this table */ TableFunc emptytable; /* pointer to function to empty table */ TableFunc filltable; /* pointer to function to fill table */ + CompareFunc cmpnodes; /* pointer to function to compare two nodes */ AddNodeFunc addnode; /* pointer to function to add new node */ GetNodeFunc getnode; /* pointer to function to get an enabled node */ GetNodeFunc getnode2; /* pointer to function to get node */ @@ -1015,18 +1018,30 @@ struct nameddir { /* history entry */ struct histent { + HashNode hash_next; /* next in hash chain */ char *text; /* the history line itself */ + int flags; /* Misc flags */ + + Histent up; /* previous line (moving upward) */ + Histent down; /* next line (moving downward) */ char *zle_text; /* the edited history line */ time_t stim; /* command started time (datestamp) */ time_t ftim; /* command finished time */ short *words; /* Position of words in history */ /* line: as pairs of start, end */ int nwords; /* Number of words in history line */ - int flags; /* Misc flags */ + int histnum; /* A sequential history number */ }; -#define HIST_OLD 0x00000001 /* Command is already written to disk*/ -#define HIST_READ 0x00000002 /* Command was read back from disk*/ +#define HIST_MAKEUNIQUE 0x00000001 /* Kill this new entry if not unique */ +#define HIST_OLD 0x00000002 /* Command is already written to disk*/ +#define HIST_READ 0x00000004 /* Command was read back from disk*/ +#define HIST_DUP 0x00000008 /* Command duplicates a later line */ +#define HIST_FOREIGN 0x00000010 /* Command came from another shell */ + +#define GETHIST_UPWARD (-1) +#define GETHIST_DOWNWARD 1 +#define GETHIST_EXACT 0 /* Parts of the code where history expansion is disabled * * should be within a pair of STOPHIST ... ALLOWHIST */ @@ -1039,6 +1054,13 @@ struct histent { #define HISTFLAG_RECALL 4 #define HISTFLAG_SETTY 8 +#define HFILE_APPEND 0x0001 +#define HFILE_SKIPOLD 0x0002 +#define HFILE_SKIPDUPS 0x0004 +#define HFILE_SKIPFOREIGN 0x0008 +#define HFILE_FAST 0x0010 +#define HFILE_USE_OPTIONS 0x8000 + /******************************************/ /* Definitions for programable completion */ /******************************************/ @@ -1120,15 +1142,20 @@ enum { HASHLISTALL, HISTALLOWCLOBBER, HISTBEEP, + HISTEXPIREDUPSFIRST, + HISTFINDNODUPS, + HISTIGNOREALLDUPS, HISTIGNOREDUPS, HISTIGNORESPACE, HISTNOFUNCTIONS, HISTNOSTORE, HISTREDUCEBLANKS, + HISTSAVENODUPS, HISTVERIFY, HUP, IGNOREBRACES, IGNOREEOF, + INCREMENTALAPPENDHISTORY, INTERACTIVE, INTERACTIVECOMMENTS, KSHARRAYS, @@ -1172,6 +1199,7 @@ enum { RESTRICTED, RMSTARSILENT, RMSTARWAIT, + SHAREHISTORY, SHFILEEXPANSION, SHGLOB, SHINSTDIN, -- cgit 1.4.1