about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--Src/builtin.c64
2 files changed, 60 insertions, 9 deletions
diff --git a/ChangeLog b/ChangeLog
index e2f7511cb..912837e01 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2007-05-20  Peter Stephenson  <p.w.stephenson@ntlworld.com>
+
+	* 23444: Src/builtin.c: print -c/-C didn't take into
+	account multibyte characters.
+
 2007-05-17  Clint Adams  <clint@zsh.org>
 
 	* Nikolai Weibull: 23443: Completion/Unix/Command/_vim:
diff --git a/Src/builtin.c b/Src/builtin.c
index 78e4d4b2a..d8732af45 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -3617,12 +3617,58 @@ bin_print(char *name, char **args, Options ops, int func)
     /* -c -- output in columns */
     if (!fmt && (OPT_ISSET(ops,'c') || OPT_ISSET(ops,'C'))) {
 	int l, nc, nr, sc, n, t, i;
+#ifdef MULTIBYTE_SUPPORT
+	int *widths;
+
+	if (isset(MULTIBYTE)) {
+	    int *wptr;
+
+	    /*
+	     * We need the character widths to align output in
+	     * columns.
+	     */
+	    wptr = widths = (int *) zhalloc(argc * sizeof(int));
+	    for (i = 0; i < argc && args[i]; i++, wptr++) {
+		int l = len[i], width = 0;
+		char *aptr = args[i];
+		mbstate_t mbs;
+
+		memset(&mbs, 0, sizeof(mbstate_t));
+		while (l > 0) {
+		    wchar_t wc;
+		    size_t cnt = mbrtowc(&wc, aptr, l, &mbs);
+		    int wcw;
+
+		    if (cnt == MB_INCOMPLETE || cnt == MB_INVALID)
+		    {
+			/* treat as ordinary string */
+			width += l;
+			break;
+		    }
+		    wcw = wcwidth(wc);
+		    /* treat unprintable as 0 */
+		    if (wcw > 0)
+			width += wcw;
+		    /* skip over NUL normally */
+		    if (cnt == 0)
+			cnt = 1;
+		    aptr += cnt;
+		    l -= cnt;
+		}
+		widths[i] = width;
+	    }
+	}
+	else
+	    widths = len;
+#else
+	int *widths = len;
+#endif
 
 	if (OPT_ISSET(ops,'C')) {
 	    char *eptr, *argptr = OPT_ARG(ops,'C');
 	    nc = (int)zstrtol(argptr, &eptr, 10);
 	    if (*eptr) {
-		zwarnnam(name, "number expected after -%c: %s", 'C', argptr);
+		zwarnnam(name, "number expcted after -%c: %s", 'C', argptr);
 		return 1;
 	    }
 	    if (nc <= 0) {
@@ -3652,8 +3698,8 @@ bin_print(char *name, char **args, Options ops, int func)
 		    if (i >= nr * (nc - 1))
 			break;
 		}
-		if (l < len[i])
-		    l = len[i];
+		if (l < widths[i])
+		    l = widths[i];
 	    }
 	    sc = l + 2;
 	}
@@ -3664,8 +3710,8 @@ bin_print(char *name, char **args, Options ops, int func)
 	     * l: maximum length seen
 	     */
 	    for (n = l = 0; n < argc; n++)
-		if (l < len[n])
-		    l = len[n];
+		if (l < widths[n])
+		    l = widths[n];
 
 	    /*
 	     * sc: column width
@@ -3686,8 +3732,8 @@ bin_print(char *name, char **args, Options ops, int func)
 		int ic;
 		for (ic = 0; ic < nc && n < argc; ic++, n++)
 		{
-		    l = len[n];
-		    fwrite(args[n], l, 1, fout);
+		    fwrite(args[n], len[n], 1, fout);
+		    l = widths[n];
 		    if (n < argc)
 			for (; l < sc; l++)
 			    fputc(' ', fout);
@@ -3697,8 +3743,8 @@ bin_print(char *name, char **args, Options ops, int func)
 	    {
 		n = i;
 		do {
-		    l = len[n];
-		    fwrite(args[n], l, 1, fout);
+		    fwrite(args[n], len[n], 1, fout);
+		    l = widths[n];
 		    for (t = nr; t && n < argc; t--, n++);
 		    if (n < argc)
 			for (; l < sc; l++)