about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--Src/builtin.c20
-rw-r--r--Src/hashtable.c81
-rw-r--r--Src/module.c2
-rw-r--r--Src/options.c3
-rw-r--r--Src/params.c2
-rw-r--r--Src/utils.c61
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  <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>
 
 	* 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. */