summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2010-03-27 19:04:35 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2010-03-27 19:04:35 +0000
commit815cc9fc0d8b6af3674eb9ea7971c1a5ce79b77e (patch)
tree0b9c4ecd66aae8bc3b958522ced9388a4d9d69ee
parent691be6d0fcf43bf21a9c4c3122380fb4f92db055 (diff)
downloadzsh-815cc9fc0d8b6af3674eb9ea7971c1a5ce79b77e.tar.gz
zsh-815cc9fc0d8b6af3674eb9ea7971c1a5ce79b77e.zip
rationalise widths of non-printing characters to zero.
-rw-r--r--ChangeLog8
-rw-r--r--Doc/Zsh/expn.yo8
-rw-r--r--Src/subst.c84
-rw-r--r--Src/utils.c16
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 <p.w.stephenson@ntlworld.com>
+
+ * 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 <pws@csr.com>
* 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;