about summary refs log tree commit diff
path: root/Src/builtin.c
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2007-05-20 17:57:23 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2007-05-20 17:57:23 +0000
commit86ff81f82d97b0118eddb729a2d4956fcbdd7c7a (patch)
treeec8bde0e3e4ab9917e3a6bb2b1241b0f02b3e319 /Src/builtin.c
parent75e6e9806a6d252f67bcc5a3c55cc0d7e44ff791 (diff)
downloadzsh-86ff81f82d97b0118eddb729a2d4956fcbdd7c7a.tar.gz
zsh-86ff81f82d97b0118eddb729a2d4956fcbdd7c7a.tar.xz
zsh-86ff81f82d97b0118eddb729a2d4956fcbdd7c7a.zip
23444: handle multibyte characters in print -c/-C
Diffstat (limited to 'Src/builtin.c')
-rw-r--r--Src/builtin.c64
1 files changed, 55 insertions, 9 deletions
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++)