From bb3628e898331edcd82da5d6291ef7c8812be267 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Fri, 15 Sep 2006 13:17:27 +0000 Subject: assume width 1 for control characters; don't crash if width of repeated padding string is 0 --- ChangeLog | 6 ++ Doc/Zsh/expn.yo | 4 +- README | 7 +++ Src/prompt.c | 17 ++++-- Src/subst.c | 178 +++++++++++++++++++++++++++++--------------------------- Src/utils.c | 20 ++++--- 6 files changed, 134 insertions(+), 98 deletions(-) diff --git a/ChangeLog b/ChangeLog index 38dadca15..189581db3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2006-09-15 Peter Stephenson + + * 22710: README, Doc/Zsh/expn.yo, Src/prompt.c, Src/subst.c, + Src/utils.c: assume width 1 for control characters; don't + crash if width of repeated padding string is 0. + 2006-09-14 Peter Stephenson * 22692: Doc/Zsh/expn.yo: additional notes on a couple of diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo index f7343b7d1..34d61ed4d 100644 --- a/Doc/Zsh/expn.yo +++ b/Doc/Zsh/expn.yo @@ -871,7 +871,9 @@ var(string1) is used to produce any remaining padding. If the tt(MULTIBYTE) option is in effect, screen character widths will be used for the calculation of padding; otherwise individual bytes are -treat as occupying one unit of width. +treat as occupying one unit of width. Control characters are always +assumed to be one unit wide; this allows the mechanism to be used +for generating repetitions of control characters. ) 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/README b/README index 88b6be3a9..78fcf5489 100644 --- a/README +++ b/README @@ -49,6 +49,13 @@ The variable HOME is no longer set by the shell if zsh is emulating any other shell at startup; it must be present in the environment or set subsequently by the user. It is valid for the variable to be unset. +The MULTIBYTE option is on by default where it is available; this +causes many operations to recognise characters as in the current locale. +Older versions of the shell always assumed a character was one byte. +In some places the width of the character will be used; this is transparent +when used for calculations of screen position, but also occurs, for +example, in calculations of padding width. + Zsh has previously been lax about whether it allows octets with the top bit set to be part of a shell identifier. Older versions of the shell assumed all such octets were allowed in identifiers, however the POSIX diff --git a/Src/prompt.c b/Src/prompt.c index 974f70e40..fc0c7ea47 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -944,10 +944,15 @@ countprompt(char *str, int *wp, int *hp, int overf) multi = 0; break; default: - /* If the character isn't printable, wcwidth() returns -1. */ + /* + * If the character isn't printable, wcwidth() returns + * -1. We assume width 1. + */ wcw = wcwidth(wc); - if (wcw > 0) + if (wcw >= 0) w += wcw; + else + w++; multi = 0; break; } @@ -1152,8 +1157,10 @@ prompttrunc(int arg, int truncchar, int doprint, int endchar) break; default: wcw = wcwidth(cc); - if (wcw > 0) + if (wcw >= 0) remw -= wcw; + else + remw--; break; } #else @@ -1215,8 +1222,10 @@ prompttrunc(int arg, int truncchar, int doprint, int endchar) break; default: wcw = wcwidth(cc); - if (wcw > 0) + if (wcw >= 0) maxwidth -= wcw; + else + maxwidth--; break; } #else diff --git a/Src/subst.c b/Src/subst.c index 2be854524..1a71a155c 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -837,29 +837,31 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, } } else { f -= lpreone; - if ((m = f % lpremul)) { - /* - * Left over fraction of repeated string. - */ - MB_METACHARINIT(); - /* Skip this much. */ - m = lpremul - m; - for (t = premul; m > 0; ) { - t += MB_METACHARLENCONV(t, &cchar); - m -= WCWIDTH(cchar); - } - /* Output the rest. */ - while (*t) - *r++ = *t++; - } - for (cc = f / lpremul; cc--;) { - /* Repeat the repeated string */ - MB_METACHARINIT(); - for (c = lpremul, t = premul; c > 0; ) { - cl = MB_METACHARLENCONV(t, &cchar); - while (cl--) + if (lpremul) { + if ((m = f % lpremul)) { + /* + * Left over fraction of repeated string. + */ + MB_METACHARINIT(); + /* Skip this much. */ + m = lpremul - m; + for (t = premul; m > 0; ) { + t += MB_METACHARLENCONV(t, &cchar); + m -= WCWIDTH(cchar); + } + /* Output the rest. */ + while (*t) *r++ = *t++; - c -= WCWIDTH(cchar); + } + for (cc = f / lpremul; cc--;) { + /* Repeat the repeated string */ + MB_METACHARINIT(); + for (c = lpremul, t = premul; c > 0; ) { + cl = MB_METACHARLENCONV(t, &cchar); + while (cl--) + *r++ = *t++; + c -= WCWIDTH(cchar); + } } } if (preone) { @@ -910,19 +912,21 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, while (*postone) *r++ = *postone++; } - for (cc = f / lpostmul; cc--;) { - /* Begin the beguine */ - for (t = postmul; *t; ) - *r++ = *t++; - } - if ((m = f % lpostmul)) { - /* Fill leftovers with chunk of repeated string */ - MB_METACHARINIT(); - while (m > 0) { - cl = MB_METACHARLENCONV(postmul, &cchar); - m -= WCWIDTH(cchar); - while (cl--) - *r++ = *postmul++; + if (lpostmul) { + for (cc = f / lpostmul; cc--;) { + /* Begin the beguine */ + for (t = postmul; *t; ) + *r++ = *t++; + } + if ((m = f % lpostmul)) { + /* Fill leftovers with chunk of repeated string */ + MB_METACHARINIT(); + while (m > 0) { + cl = MB_METACHARLENCONV(postmul, &cchar); + m -= WCWIDTH(cchar); + while (cl--) + *r++ = *postmul++; + } } } } @@ -983,37 +987,39 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, * first */ f -= lpreone; - if ((m = f % lpremul)) { - /* - * Some fraction of the repeated string needed. - */ - /* Need this much... */ - c = m; - /* ...skipping this much first. */ - m = lpremul - m; - MB_METACHARINIT(); - for (t = premul; m > 0; ) { - t += MB_METACHARLENCONV(t, &cchar); - m -= WCWIDTH(cchar); - } - /* Now the rest of the repeated string. */ - while (c > 0) { - cl = MB_METACHARLENCONV(t, &cchar); - while (cl--) - *r++ = *t++; - c -= WCWIDTH(cchar); + if (lpremul) { + if ((m = f % lpremul)) { + /* + * Some fraction of the repeated string needed. + */ + /* Need this much... */ + c = m; + /* ...skipping this much first. */ + m = lpremul - m; + MB_METACHARINIT(); + for (t = premul; m > 0; ) { + t += MB_METACHARLENCONV(t, &cchar); + m -= WCWIDTH(cchar); + } + /* Now the rest of the repeated string. */ + while (c > 0) { + cl = MB_METACHARLENCONV(t, &cchar); + while (cl--) + *r++ = *t++; + c -= WCWIDTH(cchar); + } } - } - for (cc = f / lpremul; cc--;) { - /* - * Repeat the repeated string. - */ - MB_METACHARINIT(); - for (c = lpremul, t = premul; c > 0; ) { - cl = MB_METACHARLENCONV(t, &cchar); - while (cl--) - *r++ = *t++; - c -= WCWIDTH(cchar); + for (cc = f / lpremul; cc--;) { + /* + * Repeat the repeated string. + */ + MB_METACHARINIT(); + for (c = lpremul, t = premul; c > 0; ) { + cl = MB_METACHARLENCONV(t, &cchar); + while (cl--) + *r++ = *t++; + c -= WCWIDTH(cchar); + } } } if (preone) { @@ -1089,27 +1095,29 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, c -= WCWIDTH(cchar); } } - /* Repeat the repeated string */ - for (cc = f / lpostmul; cc--;) { - MB_METACHARINIT(); - for (c = lpostmul, t = postmul; *t; ) { - cl = MB_METACHARLENCONV(t, &cchar); - while (cl--) - *r++ = *t++; - c -= WCWIDTH(cchar); + if (lpostmul) { + /* Repeat the repeated string */ + for (cc = f / lpostmul; cc--;) { + MB_METACHARINIT(); + for (c = lpostmul, t = postmul; *t; ) { + cl = MB_METACHARLENCONV(t, &cchar); + while (cl--) + *r++ = *t++; + c -= WCWIDTH(cchar); + } } - } - /* - * See if there's any fraction of the repeated - * string needed to fill up the remaining space. - */ - if ((m = f % lpostmul)) { - MB_METACHARINIT(); - while (m > 0) { - cl = MB_METACHARLENCONV(postmul, &cchar); - while (cl--) - *r++ = *postmul++; - m -= WCWIDTH(cchar); + /* + * See if there's any fraction of the repeated + * string needed to fill up the remaining space. + */ + if ((m = f % lpostmul)) { + MB_METACHARINIT(); + while (m > 0) { + cl = MB_METACHARLENCONV(postmul, &cchar); + while (cl--) + *r++ = *postmul++; + m -= WCWIDTH(cchar); + } } } } diff --git a/Src/utils.c b/Src/utils.c index 37017bdc7..415e86151 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -527,8 +527,10 @@ wcs_nicechar(wchar_t c, size_t *widthp, char **swidep) if (widthp) { int wcw = wcwidth(c); *widthp = (s - buf); - if (wcw > 0) + if (wcw >= 0) *widthp += wcw; + else + (*widthp)++; } if (swidep) *swidep = s; @@ -550,12 +552,12 @@ zwcwidth(wint_t wc) { int wcw; /* assume a single-byte character if not valid */ - if (wc == WEOF) + if (wc == WEOF || unset(MULTIBYTE)) return 1; wcw = wcwidth(wc); - /* if not printable, assume zero width */ - if (wcw <= 0) - return 0; + /* if not printable, assume width 1 */ + if (wcw < 0) + return 1; return wcw; } @@ -4077,12 +4079,14 @@ mb_metastrlen(char *ptr, int width) num++; } else if (width) { /* - * Returns -1 if not a printable character; best - * just to ignore these. + * Returns -1 if not a printable character. We + * turn this into 1 for backward compatibility. */ int wcw = wcwidth(wc); - if (wcw > 0) + if (wcw >= 0) num += wcw; + else + num++; } else num++; laststart = ptr; -- cgit 1.4.1