mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-09-26 05:51:08 +02:00
23152: make ztrcmp() respect MULTIBYTE
make sorting of printed hash tables more consistent
This commit is contained in:
parent
bae2ec88e5
commit
0108088f52
7 changed files with 110 additions and 72 deletions
|
@ -1,3 +1,10 @@
|
||||||
|
2007-02-06 Peter Stephenson <p.w.stephenson@ntlworld.com>
|
||||||
|
|
||||||
|
* 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 <pws@csr.com>
|
2007-02-06 Peter Stephenson <pws@csr.com>
|
||||||
|
|
||||||
* unposted: Src/Zle/complist.c: 23144 could leave an uninitialised
|
* unposted: Src/Zle/complist.c: 23144 could leave an uninitialised
|
||||||
|
|
|
@ -493,7 +493,7 @@ bin_enable(char *name, char **argv, Options ops, int func)
|
||||||
tokenize(*argv);
|
tokenize(*argv);
|
||||||
if ((pprog = patcompile(*argv, PAT_STATIC, 0))) {
|
if ((pprog = patcompile(*argv, PAT_STATIC, 0))) {
|
||||||
queue_signals();
|
queue_signals();
|
||||||
match += scanmatchtable(ht, pprog, 0, 0, scanfunc, 0);
|
match += scanmatchtable(ht, pprog, 0, 0, 0, scanfunc, 0);
|
||||||
unqueue_signals();
|
unqueue_signals();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -2394,7 +2394,7 @@ bin_typeset(char *name, char **argv, Options ops, int func)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (OPT_PLUS(ops,'m') && !asg->value) {
|
if (OPT_PLUS(ops,'m') && !asg->value) {
|
||||||
scanmatchtable(paramtab, pprog, on|roff, 0,
|
scanmatchtable(paramtab, pprog, 1, on|roff, 0,
|
||||||
paramtab->printnode, printflags);
|
paramtab->printnode, printflags);
|
||||||
continue;
|
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 */
|
/* with no options, just print all functions matching the glob pattern */
|
||||||
queue_signals();
|
queue_signals();
|
||||||
if (!(on|off)) {
|
if (!(on|off)) {
|
||||||
scanmatchtable(shfunctab, pprog, 0, DISABLED,
|
scanmatchtable(shfunctab, pprog, 1, 0, DISABLED,
|
||||||
shfunctab->printnode, pflags);
|
shfunctab->printnode, pflags);
|
||||||
} else {
|
} else {
|
||||||
/* apply the options to all functions matching the glob pattern */
|
/* 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 ... */
|
* We're not using it, so search for ... */
|
||||||
|
|
||||||
/* aliases ... */
|
/* aliases ... */
|
||||||
scanmatchtable(aliastab, pprog, 0, DISABLED,
|
scanmatchtable(aliastab, pprog, 1, 0, DISABLED,
|
||||||
aliastab->printnode, printflags);
|
aliastab->printnode, printflags);
|
||||||
|
|
||||||
/* and reserved words ... */
|
/* and reserved words ... */
|
||||||
scanmatchtable(reswdtab, pprog, 0, DISABLED,
|
scanmatchtable(reswdtab, pprog, 1, 0, DISABLED,
|
||||||
reswdtab->printnode, printflags);
|
reswdtab->printnode, printflags);
|
||||||
|
|
||||||
/* and shell functions... */
|
/* and shell functions... */
|
||||||
scanmatchtable(shfunctab, pprog, 0, DISABLED,
|
scanmatchtable(shfunctab, pprog, 1, 0, DISABLED,
|
||||||
shfunctab->printnode, printflags);
|
shfunctab->printnode, printflags);
|
||||||
|
|
||||||
/* and builtins. */
|
/* and builtins. */
|
||||||
scanmatchtable(builtintab, pprog, 0, DISABLED,
|
scanmatchtable(builtintab, pprog, 1, 0, DISABLED,
|
||||||
builtintab->printnode, printflags);
|
builtintab->printnode, printflags);
|
||||||
}
|
}
|
||||||
/* Done search for `internal' commands, if the -p option *
|
/* Done search for `internal' commands, if the -p option *
|
||||||
* was not used. Now search the path. */
|
* was not used. Now search the path. */
|
||||||
cmdnamtab->filltable(cmdnamtab);
|
cmdnamtab->filltable(cmdnamtab);
|
||||||
scanmatchtable(cmdnamtab, pprog, 0, 0,
|
scanmatchtable(cmdnamtab, pprog, 1, 0, 0,
|
||||||
cmdnamtab->printnode, printflags);
|
cmdnamtab->printnode, printflags);
|
||||||
|
|
||||||
unqueue_signals();
|
unqueue_signals();
|
||||||
|
@ -3193,7 +3193,7 @@ bin_hash(char *name, char **argv, Options ops, UNUSED(int func))
|
||||||
tokenize(*argv); /* expand */
|
tokenize(*argv); /* expand */
|
||||||
if ((pprog = patcompile(*argv, PAT_STATIC, NULL))) {
|
if ((pprog = patcompile(*argv, PAT_STATIC, NULL))) {
|
||||||
/* display matching hash table elements */
|
/* display matching hash table elements */
|
||||||
scanmatchtable(ht, pprog, 0, 0, ht->printnode, printflags);
|
scanmatchtable(ht, pprog, 1, 0, 0, ht->printnode, printflags);
|
||||||
} else {
|
} else {
|
||||||
untokenize(*argv);
|
untokenize(*argv);
|
||||||
zwarnnam(name, "bad pattern : %s", *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))) {
|
if ((pprog = patcompile(*argv, PAT_STATIC, NULL))) {
|
||||||
/* display the matching aliases */
|
/* display the matching aliases */
|
||||||
queue_signals();
|
queue_signals();
|
||||||
scanmatchtable(ht, pprog, flags1, flags2,
|
scanmatchtable(ht, pprog, 1, flags1, flags2,
|
||||||
ht->printnode, printflags);
|
ht->printnode, printflags);
|
||||||
unqueue_signals();
|
unqueue_signals();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -355,23 +355,42 @@ hnamcmp(const void *ap, const void *bp)
|
||||||
* the scanfunc. Replaced elements will appear in the scan exactly once,
|
* the scanfunc. Replaced elements will appear in the scan exactly once,
|
||||||
* the new version if it was not scanned before the replacement was made.
|
* the new version if it was not scanned before the replacement was made.
|
||||||
* Added elements might or might not appear in the scan.
|
* 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
|
mod_export int
|
||||||
scanhashtable(HashTable ht, int sorted, int flags1, int flags2, ScanFunc scanfunc, int scanflags)
|
scanmatchtable(HashTable ht, Patprog pprog, int sorted,
|
||||||
|
int flags1, int flags2, ScanFunc scanfunc, int scanflags)
|
||||||
{
|
{
|
||||||
|
int match = 0;
|
||||||
struct scanstatus st;
|
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);
|
ht->scantab(ht, scanfunc, scanflags);
|
||||||
return;
|
return ht->ct;
|
||||||
}
|
}
|
||||||
if (sorted) {
|
if (sorted) {
|
||||||
int i, ct = ht->ct;
|
int i, ct = ht->ct;
|
||||||
VARARR(HashNode, hnsorttab, ct);
|
VARARR(HashNode, hnsorttab, ct);
|
||||||
HashNode *htp, hn;
|
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 (htp = hnsorttab, i = 0; i < ht->hsize; i++)
|
||||||
for (hn = ht->nodes[i]; hn; hn = hn->next)
|
for (hn = ht->nodes[i]; hn; hn = hn->next)
|
||||||
*htp++ = hn;
|
*htp++ = hn;
|
||||||
|
@ -382,10 +401,14 @@ scanhashtable(HashTable ht, int sorted, int flags1, int flags2, ScanFunc scanfun
|
||||||
st.u.s.ct = ct;
|
st.u.s.ct = ct;
|
||||||
ht->scan = &st;
|
ht->scan = &st;
|
||||||
|
|
||||||
for (htp = hnsorttab, i = 0; i < ct; i++, htp++)
|
for (htp = hnsorttab, i = 0; i < ct; i++, htp++) {
|
||||||
if (*htp && ((*htp)->flags & flags1) + !flags1 &&
|
if ((!flags1 || ((*htp)->flags & flags1)) &&
|
||||||
!((*htp)->flags & flags2))
|
!((*htp)->flags & flags2) &&
|
||||||
|
(!pprog || pattry(pprog, (*htp)->nam))) {
|
||||||
|
match++;
|
||||||
scanfunc(*htp, scanflags);
|
scanfunc(*htp, scanflags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ht->scan = NULL;
|
ht->scan = NULL;
|
||||||
} else {
|
} else {
|
||||||
|
@ -399,51 +422,29 @@ scanhashtable(HashTable ht, int sorted, int flags1, int flags2, ScanFunc scanfun
|
||||||
for (st.u.u = nodes[i]; st.u.u; ) {
|
for (st.u.u = nodes[i]; st.u.u; ) {
|
||||||
HashNode hn = st.u.u;
|
HashNode hn = st.u.u;
|
||||||
st.u.u = st.u.u->next;
|
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);
|
scanfunc(hn, scanflags);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ht->scan = NULL;
|
ht->scan = NULL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* 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)
|
|
||||||
{
|
|
||||||
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 match;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**/
|
||||||
|
mod_export int
|
||||||
|
scanhashtable(HashTable ht, int sorted, int flags1, int flags2,
|
||||||
|
ScanFunc scanfunc, int scanflags)
|
||||||
|
{
|
||||||
|
return scanmatchtable(ht, NULL, sorted, flags1, flags2,
|
||||||
|
scanfunc, scanflags);
|
||||||
|
}
|
||||||
|
|
||||||
/* Expand hash tables when they get too many entries. *
|
/* Expand hash tables when they get too many entries. *
|
||||||
* The new size is 4 times the previous size. */
|
* The new size is 4 times the previous size. */
|
||||||
|
|
||||||
|
|
|
@ -1265,7 +1265,7 @@ bin_zmodload_auto(char *nam, char **args, Options ops)
|
||||||
return ret;
|
return ret;
|
||||||
} else if(!*args) {
|
} else if(!*args) {
|
||||||
/* list autoloaded builtins */
|
/* list autoloaded builtins */
|
||||||
scanhashtable(builtintab, 0, 0, 0,
|
scanhashtable(builtintab, 1, 0, 0,
|
||||||
autoloadscan, OPT_ISSET(ops,'L') ? PRINT_LIST : 0);
|
autoloadscan, OPT_ISSET(ops,'L') ? PRINT_LIST : 0);
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -578,7 +578,8 @@ bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Loop over expansions. */
|
/* Loop over expansions. */
|
||||||
scanmatchtable(optiontab, pprog, 0, OPT_ALIAS, setoption, !isun);
|
scanmatchtable(optiontab, pprog, 0, 0, OPT_ALIAS,
|
||||||
|
setoption, !isun);
|
||||||
args++;
|
args++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4266,7 +4266,7 @@ printparamnode(HashNode hn, int printflags)
|
||||||
{
|
{
|
||||||
HashTable ht = p->gsu.h->getfn(p);
|
HashTable ht = p->gsu.h->getfn(p);
|
||||||
if (ht)
|
if (ht)
|
||||||
scanhashtable(ht, 0, 0, PM_UNSET,
|
scanhashtable(ht, 1, 0, PM_UNSET,
|
||||||
ht->printnode, PRINT_KV_PAIR);
|
ht->printnode, PRINT_KV_PAIR);
|
||||||
}
|
}
|
||||||
if (!(printflags & PRINT_KV_PAIR))
|
if (!(printflags & PRINT_KV_PAIR))
|
||||||
|
|
61
Src/utils.c
61
Src/utils.c
|
@ -3700,27 +3700,56 @@ unmeta(const char *file_name)
|
||||||
int
|
int
|
||||||
ztrcmp(char const *s1, char const *s2)
|
ztrcmp(char const *s1, char const *s2)
|
||||||
{
|
{
|
||||||
int c1, c2;
|
convchar_t c1 = 0, c2;
|
||||||
|
|
||||||
while (*s1 && *s1 == *s2) {
|
#ifdef MULTIBYTE_SUPPORT
|
||||||
s1++;
|
if (isset(MULTIBYTE)) {
|
||||||
s2++;
|
mb_metacharinit();
|
||||||
|
while (*s1) {
|
||||||
|
int clen = mb_metacharlenconv(s1, &c1);
|
||||||
|
|
||||||
|
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 = 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 (c1 == c2)
|
|
||||||
return 0;
|
|
||||||
if (c1 < c2)
|
if (c1 < c2)
|
||||||
return -1;
|
return -1;
|
||||||
return 1;
|
else if (c1 == c2)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the unmetafied length of a metafied string. */
|
/* Return the unmetafied length of a metafied string. */
|
||||||
|
|
Loading…
Reference in a new issue