From 0108088f52ee58fc8a2e83f86c9f2506165a16cd Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Tue, 6 Feb 2007 21:47:54 +0000 Subject: 23152: make ztrcmp() respect MULTIBYTE make sorting of printed hash tables more consistent --- ChangeLog | 7 +++++ Src/builtin.c | 20 +++++++------- Src/hashtable.c | 81 +++++++++++++++++++++++++++++---------------------------- Src/module.c | 2 +- Src/options.c | 3 ++- Src/params.c | 2 +- Src/utils.c | 61 +++++++++++++++++++++++++++++++------------ 7 files changed, 107 insertions(+), 69 deletions(-) diff --git a/ChangeLog b/ChangeLog index 45eb8f437..9beb2f570 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2007-02-06 Peter Stephenson + + * 23152: Src/builtin.c, Src/hashtable.c, Src/module.c, + Src/options.c, Src/params.c, Src/utils.c: fix ztrcmp() + to respect MULTIBYTE option and make sorting of printed + out hash tables more consistent. + 2007-02-06 Peter Stephenson * unposted: Src/Zle/complist.c: 23144 could leave an uninitialised diff --git a/Src/builtin.c b/Src/builtin.c index 36e829f22..cec211e67 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -493,7 +493,7 @@ bin_enable(char *name, char **argv, Options ops, int func) tokenize(*argv); if ((pprog = patcompile(*argv, PAT_STATIC, 0))) { queue_signals(); - match += scanmatchtable(ht, pprog, 0, 0, scanfunc, 0); + match += scanmatchtable(ht, pprog, 0, 0, 0, scanfunc, 0); unqueue_signals(); } else { @@ -2394,7 +2394,7 @@ bin_typeset(char *name, char **argv, Options ops, int func) continue; } if (OPT_PLUS(ops,'m') && !asg->value) { - scanmatchtable(paramtab, pprog, on|roff, 0, + scanmatchtable(paramtab, pprog, 1, on|roff, 0, paramtab->printnode, printflags); continue; } @@ -2720,7 +2720,7 @@ bin_functions(char *name, char **argv, Options ops, int func) /* with no options, just print all functions matching the glob pattern */ queue_signals(); if (!(on|off)) { - scanmatchtable(shfunctab, pprog, 0, DISABLED, + scanmatchtable(shfunctab, pprog, 1, 0, DISABLED, shfunctab->printnode, pflags); } else { /* apply the options to all functions matching the glob pattern */ @@ -2987,25 +2987,25 @@ bin_whence(char *nam, char **argv, Options ops, int func) * We're not using it, so search for ... */ /* aliases ... */ - scanmatchtable(aliastab, pprog, 0, DISABLED, + scanmatchtable(aliastab, pprog, 1, 0, DISABLED, aliastab->printnode, printflags); /* and reserved words ... */ - scanmatchtable(reswdtab, pprog, 0, DISABLED, + scanmatchtable(reswdtab, pprog, 1, 0, DISABLED, reswdtab->printnode, printflags); /* and shell functions... */ - scanmatchtable(shfunctab, pprog, 0, DISABLED, + scanmatchtable(shfunctab, pprog, 1, 0, DISABLED, shfunctab->printnode, printflags); /* and builtins. */ - scanmatchtable(builtintab, pprog, 0, DISABLED, + scanmatchtable(builtintab, pprog, 1, 0, DISABLED, builtintab->printnode, printflags); } /* Done search for `internal' commands, if the -p option * * was not used. Now search the path. */ cmdnamtab->filltable(cmdnamtab); - scanmatchtable(cmdnamtab, pprog, 0, 0, + scanmatchtable(cmdnamtab, pprog, 1, 0, 0, cmdnamtab->printnode, printflags); unqueue_signals(); @@ -3193,7 +3193,7 @@ bin_hash(char *name, char **argv, Options ops, UNUSED(int func)) tokenize(*argv); /* expand */ if ((pprog = patcompile(*argv, PAT_STATIC, NULL))) { /* display matching hash table elements */ - scanmatchtable(ht, pprog, 0, 0, ht->printnode, printflags); + scanmatchtable(ht, pprog, 1, 0, 0, ht->printnode, printflags); } else { untokenize(*argv); zwarnnam(name, "bad pattern : %s", *argv); @@ -3378,7 +3378,7 @@ bin_alias(char *name, char **argv, Options ops, UNUSED(int func)) if ((pprog = patcompile(*argv, PAT_STATIC, NULL))) { /* display the matching aliases */ queue_signals(); - scanmatchtable(ht, pprog, flags1, flags2, + scanmatchtable(ht, pprog, 1, flags1, flags2, ht->printnode, printflags); unqueue_signals(); } else { diff --git a/Src/hashtable.c b/Src/hashtable.c index 9a2f12c9c..669990566 100644 --- a/Src/hashtable.c +++ b/Src/hashtable.c @@ -355,23 +355,42 @@ hnamcmp(const void *ap, const void *bp) * the scanfunc. Replaced elements will appear in the scan exactly once, * the new version if it was not scanned before the replacement was made. * Added elements might or might not appear in the scan. + * + * pprog, if non-NULL, is a pattern that must match the name + * of the node. + * + * The function returns the number of matches, as reduced by pprog, flags1 + * and flags2. */ /**/ -mod_export void -scanhashtable(HashTable ht, int sorted, int flags1, int flags2, ScanFunc scanfunc, int scanflags) +mod_export int +scanmatchtable(HashTable ht, Patprog pprog, int sorted, + int flags1, int flags2, ScanFunc scanfunc, int scanflags) { + int match = 0; struct scanstatus st; - if (ht->scantab) { + /* + * scantab is currently only used by modules to scan + * tables where the contents are generated on the fly from + * other objects. Note the fact that in this case pprog, + * sorted, flags1 and flags2 are ignore. + */ + if (!pprog && ht->scantab) { ht->scantab(ht, scanfunc, scanflags); - return; + return ht->ct; } if (sorted) { int i, ct = ht->ct; VARARR(HashNode, hnsorttab, ct); HashNode *htp, hn; + /* + * Because the structure might change under our feet, + * we can't apply the flags and the pattern before sorting, + * tempting though that is. + */ for (htp = hnsorttab, i = 0; i < ht->hsize; i++) for (hn = ht->nodes[i]; hn; hn = hn->next) *htp++ = hn; @@ -382,10 +401,14 @@ scanhashtable(HashTable ht, int sorted, int flags1, int flags2, ScanFunc scanfun st.u.s.ct = ct; ht->scan = &st; - for (htp = hnsorttab, i = 0; i < ct; i++, htp++) - if (*htp && ((*htp)->flags & flags1) + !flags1 && - !((*htp)->flags & flags2)) + for (htp = hnsorttab, i = 0; i < ct; i++, htp++) { + if ((!flags1 || ((*htp)->flags & flags1)) && + !((*htp)->flags & flags2) && + (!pprog || pattry(pprog, (*htp)->nam))) { + match++; scanfunc(*htp, scanflags); + } + } ht->scan = NULL; } else { @@ -399,49 +422,27 @@ scanhashtable(HashTable ht, int sorted, int flags1, int flags2, ScanFunc scanfun for (st.u.u = nodes[i]; st.u.u; ) { HashNode hn = st.u.u; st.u.u = st.u.u->next; - if ((hn->flags & flags1) + !flags1 && !(hn->flags & flags2)) + if ((!flags1 || (hn->flags & flags1)) && !(hn->flags & flags2) + && (!pprog || pattry(pprog, hn->nam))) { + match++; scanfunc(hn, scanflags); + } } ht->scan = NULL; } + + return match; } -/* Scan all nodes in a hash table and executes scanfunc on the * - * nodes which meet all the following criteria: * - * The hash key must match the glob pattern given by `com'. * - * If (flags1 > 0), then any flag in flags1 must be set. * - * If (flags2 > 0), then all flags in flags2 must NOT be set. * - * * - * scanflags is passed unchanged to scanfunc (if executed). * - * The return value is the number of matches. */ /**/ -int -scanmatchtable(HashTable ht, Patprog pprog, int flags1, int flags2, ScanFunc scanfunc, int scanflags) +mod_export int +scanhashtable(HashTable ht, int sorted, int flags1, int flags2, + ScanFunc scanfunc, int scanflags) { - int i, hsize = ht->hsize; - HashNode *nodes = ht->nodes; - int match = 0; - struct scanstatus st; - - st.sorted = 0; - ht->scan = &st; - - for (i = 0; i < hsize; i++) - for (st.u.u = nodes[i]; st.u.u; ) { - HashNode hn = st.u.u; - st.u.u = st.u.u->next; - if ((hn->flags & flags1) + !flags1 && !(hn->flags & flags2) && - pattry(pprog, hn->nam)) { - scanfunc(hn, scanflags); - match++; - } - } - - ht->scan = NULL; - - return match; + return scanmatchtable(ht, NULL, sorted, flags1, flags2, + scanfunc, scanflags); } /* Expand hash tables when they get too many entries. * diff --git a/Src/module.c b/Src/module.c index 398958cce..fa6d50c6e 100644 --- a/Src/module.c +++ b/Src/module.c @@ -1265,7 +1265,7 @@ bin_zmodload_auto(char *nam, char **args, Options ops) return ret; } else if(!*args) { /* list autoloaded builtins */ - scanhashtable(builtintab, 0, 0, 0, + scanhashtable(builtintab, 1, 0, 0, autoloadscan, OPT_ISSET(ops,'L') ? PRINT_LIST : 0); return 0; } else { diff --git a/Src/options.c b/Src/options.c index d5e5ee552..d0474498c 100644 --- a/Src/options.c +++ b/Src/options.c @@ -578,7 +578,8 @@ bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun) continue; } /* Loop over expansions. */ - scanmatchtable(optiontab, pprog, 0, OPT_ALIAS, setoption, !isun); + scanmatchtable(optiontab, pprog, 0, 0, OPT_ALIAS, + setoption, !isun); args++; } } diff --git a/Src/params.c b/Src/params.c index 7d7f0e8e7..917f2ee85 100644 --- a/Src/params.c +++ b/Src/params.c @@ -4266,7 +4266,7 @@ printparamnode(HashNode hn, int printflags) { HashTable ht = p->gsu.h->getfn(p); if (ht) - scanhashtable(ht, 0, 0, PM_UNSET, + scanhashtable(ht, 1, 0, PM_UNSET, ht->printnode, PRINT_KV_PAIR); } if (!(printflags & PRINT_KV_PAIR)) diff --git a/Src/utils.c b/Src/utils.c index ce7b4caac..eb466278d 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -3700,27 +3700,56 @@ unmeta(const char *file_name) int ztrcmp(char const *s1, char const *s2) { - int c1, c2; + convchar_t c1 = 0, c2; - while (*s1 && *s1 == *s2) { - s1++; - s2++; - } +#ifdef MULTIBYTE_SUPPORT + if (isset(MULTIBYTE)) { + mb_metacharinit(); + while (*s1) { + int clen = mb_metacharlenconv(s1, &c1); - if (!(c1 = STOUC(*s1))) - c1 = -1; - else if (c1 == STOUC(Meta)) - c1 = STOUC(*++s1) ^ 32; - if (!(c2 = STOUC(*s2))) - c2 = -1; - else if (c2 == STOUC(Meta)) - c2 = STOUC(*++s2) ^ 32; + if (strncmp(s1, s2, clen)) + break; + s1 += clen; + s2 += clen; + } + } else +#endif + while (*s1 && *s1 == *s2) { + s1++; + s2++; + } + + if (!*s1) { + if (!*s2) + return 0; + return -1; + } + if (!*s2) + return 1; +#ifdef MULTIBYTE_SUPPORT + if (isset(MULTIBYTE)) { + /* TODO: shift state for s2 might be wrong? */ + mb_metacharinit(); + (void)mb_metacharlenconv(s2, &c2); + if (c1 == WEOF) + c1 = STOUC(*s1 == Meta ? s1[1] ^ 32 : *s1); + if (c2 == WEOF) + c2 = STOUC(*s2 == Meta ? s2[1] ^ 32 : *s2); + } + else +#endif + { + c1 = STOUC(*s1 == Meta ? s1[1] ^ 32 : *s1); + c2 = STOUC(*s2 == Meta ? s2[1] ^ 32 : *s2); + } - if (c1 == c2) - return 0; if (c1 < c2) return -1; - return 1; + else if (c1 == c2) + return 0; + else + return 1; } /* Return the unmetafied length of a metafied string. */ -- cgit 1.4.1