mirror of
git://git.code.sf.net/p/zsh/code
synced 2024-09-28 15:01:21 +02:00
23052: multibyte characters in typeset -L/R/Z padding
This commit is contained in:
parent
f50dfd61f6
commit
d8e36bffa2
@ -1,3 +1,8 @@
|
||||
2006-12-13 Peter Stephenson <p.w.stephenson@ntlworld.com>
|
||||
|
||||
* 23052: Doc/Zsh/builtins.yo, Src/subst.c: multibyte
|
||||
characters in typeset -L/R/Z padding.
|
||||
|
||||
2006-12-13 Peter Stephenson <pws@csr.com>
|
||||
|
||||
* 23051: Src/lex.c: using ${(Q)...} on an expression with
|
||||
|
@ -1405,6 +1405,15 @@ If var(n) is zero, the width is determined by the width of the value of
|
||||
the first assignment. In the case of numeric parameters, the length of the
|
||||
complete value assigned to the parameter is used to determine the width,
|
||||
not the value that would be output.
|
||||
|
||||
The width is the count of characters, which may be multibyte characters
|
||||
if the tt(MULTIBYTE) option is in effect. Note that the screen
|
||||
width of the character is not taken into account; if this is required,
|
||||
use padding with parameter expansion flags
|
||||
tt(${+LPAR()ml)var(...)tt(RPAR())var(...)tt(}) as described in
|
||||
`Parameter Expansion Flags' in
|
||||
ifzman(zmanref(zshexpn))ifnzman(noderef(Parameter Expansion)).
|
||||
|
||||
When the parameter is expanded, it is filled on the right with
|
||||
blanks or truncated if necessary to fit the field.
|
||||
Note truncation can lead to unexpected results with numeric parameters.
|
||||
|
76
Src/subst.c
76
Src/subst.c
@ -761,8 +761,8 @@ invinstrpcmp(const void *a, const void *b)
|
||||
/*
|
||||
* 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.
|
||||
* Calculations are in terms of width if MULTIBYTE is in effect, else
|
||||
* characters.
|
||||
* Calculations are in terms of width if MULTIBYTE is in effect and
|
||||
* multi_width is non-zero, else characters.
|
||||
*
|
||||
* prenum and postnum are the width to which the string needs padding
|
||||
* on the left and right.
|
||||
@ -2211,7 +2211,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
|
||||
val = getstrvalue(v);
|
||||
fwidth = v->pm->width ? v->pm->width : (int)strlen(val);
|
||||
switch (v->pm->node.flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) {
|
||||
char *t;
|
||||
char *t, *tend;
|
||||
unsigned int t0;
|
||||
|
||||
case PM_LEFT:
|
||||
@ -2223,21 +2223,39 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
|
||||
else
|
||||
while (iblank(*t))
|
||||
t++;
|
||||
val = (char *) hcalloc(fwidth + 1);
|
||||
val[fwidth] = '\0';
|
||||
if ((t0 = strlen(t)) > fwidth)
|
||||
t0 = fwidth;
|
||||
memset(val, ' ', fwidth);
|
||||
strncpy(val, t, t0);
|
||||
MB_METACHARINIT();
|
||||
for (tend = t, t0 = 0; t0 < fwidth && *tend; t0++)
|
||||
tend += MB_METACHARLEN(tend);
|
||||
/*
|
||||
* t0 is the number of characters from t used,
|
||||
* hence (fwidth - t0) is the number of padding
|
||||
* characters. fwidth is a misnomer: we use
|
||||
* character counts, not character widths.
|
||||
*
|
||||
* (tend - t) is the number of bytes we need
|
||||
* to get fwidth characters or the entire string;
|
||||
* the characters may be multiple bytes.
|
||||
*/
|
||||
fwidth -= t0; /* padding chars remaining */
|
||||
t0 = tend - t; /* bytes to copy from string */
|
||||
val = (char *) hcalloc(t0 + fwidth + 1);
|
||||
memcpy(val, t, t0);
|
||||
if (fwidth)
|
||||
memset(val + t0, ' ', fwidth);
|
||||
val[t0 + fwidth] = '\0';
|
||||
copied = 1;
|
||||
break;
|
||||
case PM_RIGHT_B:
|
||||
case PM_RIGHT_Z:
|
||||
case PM_RIGHT_Z | PM_RIGHT_B:
|
||||
{
|
||||
int zero = 1;
|
||||
/* Calculate length in possibly multibyte chars */
|
||||
int charlen = MB_METASTRLEN(val);
|
||||
|
||||
if (strlen(val) < fwidth) {
|
||||
if (charlen < fwidth) {
|
||||
char *valprefend = val;
|
||||
int preflen;
|
||||
if (v->pm->node.flags & PM_RIGHT_Z) {
|
||||
/*
|
||||
* This is a documented feature: when deciding
|
||||
@ -2277,33 +2295,31 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
|
||||
} else if (!idigit(*t))
|
||||
zero = 0;
|
||||
}
|
||||
t = (char *) hcalloc(fwidth + 1);
|
||||
memset(t, (((v->pm->node.flags & PM_RIGHT_B) || !zero) ?
|
||||
' ' : '0'), fwidth);
|
||||
/*
|
||||
* How can the following trigger? We
|
||||
* haven't altered val or fwidth since
|
||||
* the last time we tested this.
|
||||
*/
|
||||
if ((t0 = strlen(val)) > fwidth)
|
||||
t0 = fwidth;
|
||||
/* number of characters needed for padding */
|
||||
fwidth -= charlen;
|
||||
/* bytes from original string */
|
||||
t0 = strlen(val);
|
||||
t = (char *) hcalloc(fwidth + t0 + 1);
|
||||
/* prefix guaranteed to be single byte chars */
|
||||
preflen = valprefend - val;
|
||||
memset(t + preflen,
|
||||
(((v->pm->node.flags & PM_RIGHT_B)
|
||||
|| !zero) ? ' ' : '0'), fwidth);
|
||||
/*
|
||||
* Copy - or 0x or base# before any padding
|
||||
* zeroes.
|
||||
*/
|
||||
if (zero && val != valprefend) {
|
||||
int preflen = valprefend - val;
|
||||
if (preflen)
|
||||
memcpy(t, val, preflen);
|
||||
strcpy(t + (fwidth - t0) + preflen,
|
||||
valprefend);
|
||||
} else
|
||||
strcpy(t + (fwidth - t0), val);
|
||||
memcpy(t + preflen + fwidth,
|
||||
valprefend, t0 - preflen);
|
||||
t[fwidth + t0] = '\0';
|
||||
val = t;
|
||||
copied = 1;
|
||||
} else {
|
||||
t = (char *) hcalloc(fwidth + 1);
|
||||
t[fwidth] = '\0';
|
||||
strncpy(t, val + strlen(val) - fwidth, fwidth);
|
||||
val = t;
|
||||
/* Need to skip (charlen - fwidth) chars */
|
||||
for (t0 = charlen - fwidth; t0; t0--)
|
||||
val += MB_METACHARLEN(val);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user