From 815cc9fc0d8b6af3674eb9ea7971c1a5ce79b77e Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sat, 27 Mar 2010 19:04:35 +0000 Subject: rationalise widths of non-printing characters to zero. --- ChangeLog | 8 +++++- Doc/Zsh/expn.yo | 8 ++++++ Src/subst.c | 84 ++++++++++++++++++++++++++++++++++++++------------------- Src/utils.c | 16 ++++++----- 4 files changed, 81 insertions(+), 35 deletions(-) diff --git a/ChangeLog b/ChangeLog index d37eb8daa..aeca52fe1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2010-03-26 Peter Stephenson + + * 27831: Doc/Zsh/expn.yo, Src/input.c, Src/subst.c, Src/utils.c: + add ${(mm)...} to count displayed characters and rationalise use + of wcwidth so that negative numbers are treated as zero. + 2010-03-25 Peter Stephenson * unposted: Test/A02alias.ztst: change sort to cat to @@ -12968,5 +12974,5 @@ ***************************************************** * This is used by the shell to define $ZSH_PATCHLEVEL -* $Revision: 1.4945 $ +* $Revision: 1.4946 $ ***************************************************** diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo index 52d4cac9e..f04d6ea17 100644 --- a/Doc/Zsh/expn.yo +++ b/Doc/Zsh/expn.yo @@ -1004,6 +1004,14 @@ calculating the how much of the string it occupies or the overall length of the string. Most printable characters have a width of one unit, however certain Asian character sets and certain special effects use wider characters; combining characters have zero width. +Non-printable characters are arbitrarily counted as zero width; how they +would actually be displayed will vary. + +If the tt(m) is repeated, the character either counts zero (if it has +zero width), else one. For printable character strings this has the +effect of counting the number of glyphs (visibly separate characters), +except for the case where combining characters themselves have non-zero +width (true in certain alphabets). ) item(tt(r:)var(expr)tt(::)var(string1)tt(::)var(string2)tt(:))( As tt(l), but pad the words on the right and insert var(string2) diff --git a/Src/subst.c b/Src/subst.c index a5ed289be..52288b741 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -675,6 +675,40 @@ strcatsub(char **d, char *pb, char *pe, char *src, int l, char *s, int glbsub, return dest; } +#ifdef MULTIBYTE_SUPPORT +#define WCPADWIDTH(cchar, mw) wcpadwidth(cchar, mw) + +/* + * Width of character for padding purposes. + * 0: all characters count 1. + * 1: use width of multibyte character. + * 2: non-zero width characters count 1, zero width 0. + */ +static int +wcpadwidth(wchar_t wc, int multi_width) +{ + int width; + + switch (multi_width) + { + case 0: + return 1; + + case 1: + width = WCWIDTH(wc); + if (width >= 0) + return width; + return 0; + + default: + return WCWIDTH(wc) > 0 ? 1 : 0; + } +} + +#else +#define WCPADWIDTH(cchar, mw) (1) +#endif + /* * Pad the string str, returning a result from the heap (or str itself, * if it didn't need padding). If str is too large, it will be truncated. @@ -703,12 +737,6 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, #endif ) { -#ifdef MULTIBYTE_SUPPORT -#define WCPADWIDTH(cchar) (multi_width ? WCWIDTH(cchar) : 1) -#else -#define WCPADWIDTH(cchar) (1) -#endif - char *def, *ret, *t, *r; int ls, ls2, lpreone, lpostone, lpremul, lpostmul, lr, f, m, c, cc, cl; convchar_t cchar; @@ -775,14 +803,14 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, MB_METACHARINIT(); while (f > 0) { str += MB_METACHARLENCONV(str, &cchar); - f -= WCPADWIDTH(cchar); + f -= WCPADWIDTH(cchar, multi_width); } /* Now finish the first half. */ for (c = prenum; c > 0; ) { cl = MB_METACHARLENCONV(str, &cchar); while (cl--) *r++ = *str++; - c -= WCPADWIDTH(cchar); + c -= WCPADWIDTH(cchar, multi_width); } } else { if (f <= lpreone) { @@ -796,7 +824,7 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, /* So skip. */ for (t = preone; f > 0; ) { t += MB_METACHARLENCONV(t, &cchar); - f -= WCPADWIDTH(cchar); + f -= WCPADWIDTH(cchar, multi_width); } /* Then copy the entire remainder. */ while (*t) @@ -814,7 +842,7 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, m = lpremul - m; for (t = premul; m > 0; ) { t += MB_METACHARLENCONV(t, &cchar); - m -= WCPADWIDTH(cchar); + m -= WCPADWIDTH(cchar, multi_width); } /* Output the rest. */ while (*t) @@ -827,7 +855,7 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, cl = MB_METACHARLENCONV(t, &cchar); while (cl--) *r++ = *t++; - c -= WCPADWIDTH(cchar); + c -= WCPADWIDTH(cchar, multi_width); } } } @@ -840,7 +868,7 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, /* Output the first half width of the original string. */ for (c = ls2; c > 0; ) { cl = MB_METACHARLENCONV(str, &cchar); - c -= WCPADWIDTH(cchar); + c -= WCPADWIDTH(cchar, multi_width); while (cl--) *r++ = *str++; } @@ -854,7 +882,7 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, MB_METACHARINIT(); for (c = postnum; c > 0; ) { cl = MB_METACHARLENCONV(str, &cchar); - c -= WCPADWIDTH(cchar); + c -= WCPADWIDTH(cchar, multi_width); while (cl--) *r++ = *str++; } @@ -867,7 +895,7 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, /* Can't fit unrepeated string, truncate it */ for (c = f; c > 0; ) { cl = MB_METACHARLENCONV(postone, &cchar); - c -= WCPADWIDTH(cchar); + c -= WCPADWIDTH(cchar, multi_width); while (cl--) *r++ = *postone++; } @@ -890,7 +918,7 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, MB_METACHARINIT(); while (m > 0) { cl = MB_METACHARLENCONV(postmul, &cchar); - m -= WCPADWIDTH(cchar); + m -= WCPADWIDTH(cchar, multi_width); while (cl--) *r++ = *postmul++; } @@ -914,14 +942,14 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, MB_METACHARINIT(); while (f > 0) { str += MB_METACHARLENCONV(str, &cchar); - f -= WCPADWIDTH(cchar); + f -= WCPADWIDTH(cchar, multi_width); } /* Copy the rest of the original string */ for (c = prenum; c > 0; ) { cl = MB_METACHARLENCONV(str, &cchar); while (cl--) *r++ = *str++; - c -= WCPADWIDTH(cchar); + c -= WCPADWIDTH(cchar, multi_width); } } else { /* @@ -942,7 +970,7 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, MB_METACHARINIT(); for (t = preone; f > 0; ) { t += MB_METACHARLENCONV(t, &cchar); - f -= WCPADWIDTH(cchar); + f -= WCPADWIDTH(cchar, multi_width); } /* Copy the rest of preone */ while (*t) @@ -966,14 +994,14 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, MB_METACHARINIT(); for (t = premul; m > 0; ) { t += MB_METACHARLENCONV(t, &cchar); - m -= WCPADWIDTH(cchar); + m -= WCPADWIDTH(cchar, multi_width); } /* Now the rest of the repeated string. */ while (c > 0) { cl = MB_METACHARLENCONV(t, &cchar); while (cl--) *r++ = *t++; - c -= WCPADWIDTH(cchar); + c -= WCPADWIDTH(cchar, multi_width); } } for (cc = f / lpremul; cc--;) { @@ -985,7 +1013,7 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, cl = MB_METACHARLENCONV(t, &cchar); while (cl--) *r++ = *t++; - c -= WCPADWIDTH(cchar); + c -= WCPADWIDTH(cchar, multi_width); } } } @@ -1023,7 +1051,7 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, cl = MB_METACHARLENCONV(str, &cchar); while (cl--) *r++ = *str++; - c -= WCPADWIDTH(cchar); + c -= WCPADWIDTH(cchar, multi_width); } } else { /* @@ -1035,7 +1063,7 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, cl = MB_METACHARLENCONV(str, &cchar); while (cl--) *r++ = *str++; - c -= WCPADWIDTH(cchar); + c -= WCPADWIDTH(cchar, multi_width); } MB_METACHARINIT(); if (f <= lpostone) { @@ -1048,7 +1076,7 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, cl = MB_METACHARLENCONV(postone, &cchar); while (cl--) *r++ = *postone++; - c -= WCPADWIDTH(cchar); + c -= WCPADWIDTH(cchar, multi_width); } } } else { @@ -1059,7 +1087,7 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, cl = MB_METACHARLENCONV(postone, &cchar); while (cl--) *r++ = *postone++; - c -= WCPADWIDTH(cchar); + c -= WCPADWIDTH(cchar, multi_width); } } if (lpostmul) { @@ -1070,7 +1098,7 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, cl = MB_METACHARLENCONV(t, &cchar); while (cl--) *r++ = *t++; - c -= WCPADWIDTH(cchar); + c -= WCPADWIDTH(cchar, multi_width); } } /* @@ -1083,7 +1111,7 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, cl = MB_METACHARLENCONV(postmul, &cchar); while (cl--) *r++ = *postmul++; - m -= WCPADWIDTH(cchar); + m -= WCPADWIDTH(cchar, multi_width); } } } @@ -1782,7 +1810,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) case 'm': #ifdef MULTIBYTE_SUPPORT - multi_width = 1; + multi_width++; #endif break; diff --git a/Src/utils.c b/Src/utils.c index 38c820f29..1d7b3109a 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -4406,6 +4406,8 @@ mb_metacharlenconv(const char *s, wint_t *wcp) * until end of string. * * If width is 1, return total character width rather than number. + * If width is greater than 1, return 1 if character has non-zero width, + * else 0. */ /**/ @@ -4444,13 +4446,15 @@ mb_metastrlen(char *ptr, int width) } else if (width) { /* * Returns -1 if not a printable character. We - * turn this into 1 for backward compatibility. + * turn this into 0. */ int wcw = WCWIDTH(wc); - if (wcw >= 0) - num += wcw; - else - num++; + if (wcw > 0) { + if (width == 1) + num += wcw; + else + num++; + } } else num++; laststart = ptr; @@ -5859,8 +5863,8 @@ privasserted(void) cap_free(caps); return 1; } - cap_free(caps); } + cap_free(caps); } #endif /* HAVE_CAP_GET_PROC */ return 0; -- cgit 1.4.1