mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-01-19 11:31:26 +01:00
23098: printf multibyte character widths
This commit is contained in:
parent
94bdf92a06
commit
de815e3d22
3 changed files with 75 additions and 12 deletions
|
@ -1,3 +1,8 @@
|
|||
2007-01-09 Peter Stephenson <p.w.stephenson@ntlworld.com>
|
||||
|
||||
* 23098: Src/builtin.c, Test/D07multibyte.ztst: print widths
|
||||
in printf take account of multibyte characters.
|
||||
|
||||
2007-01-08 Peter Stephenson <p.w.stephenson@ntlworld.com>
|
||||
|
||||
* 23097: Src/lex.c, Src/utils.c, Src/zsh.h, Src/Zle/compcore.c:
|
||||
|
|
|
@ -3792,6 +3792,12 @@ bin_print(char *name, char **args, Options ops, int func)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* All the remaining code in this function is for printf-style
|
||||
* output (printf itself, or print -f). We still have to handle
|
||||
* special cases of printing to a ZLE buffer or the history, however.
|
||||
*/
|
||||
|
||||
if (OPT_ISSET(ops,'z') || OPT_ISSET(ops,'s')) {
|
||||
#ifdef HAVE_OPEN_MEMSTREAM
|
||||
if ((fout = open_memstream(&buf, &mcount)) == NULL)
|
||||
|
@ -3948,26 +3954,74 @@ bin_print(char *name, char **args, Options ops, int func)
|
|||
case 's':
|
||||
case 'b':
|
||||
if (curarg) {
|
||||
char *b;
|
||||
int l;
|
||||
char *b, *ptr;
|
||||
int lbytes, lchars, lleft;
|
||||
#ifdef MULTIBYTE_SUPPORT
|
||||
mbstate_t mbs;
|
||||
#endif
|
||||
|
||||
if (*c == 'b') {
|
||||
b = getkeystring(metafy(curarg, curlen, META_USEHEAP),
|
||||
&l,
|
||||
&lbytes,
|
||||
OPT_ISSET(ops,'b') ? GETKEYS_BINDKEY :
|
||||
GETKEYS_PRINTF_ARG, &nnl);
|
||||
} else {
|
||||
b = curarg;
|
||||
l = curlen;
|
||||
lbytes = curlen;
|
||||
}
|
||||
/*
|
||||
* Handle width/precision here and use fwrite so that
|
||||
* nul characters can be output.
|
||||
*
|
||||
* First, examine width of string given that it
|
||||
* may contain multibyte characters. The output
|
||||
* widths are for characters, so we need to count
|
||||
* (in lchars). However, if we need to truncate
|
||||
* the string we need the width in bytes (in lbytes).
|
||||
*/
|
||||
ptr = b;
|
||||
#ifdef MULTIBYTE_SUPPORT
|
||||
memset(&mbs, 0, sizeof(mbs));
|
||||
#endif
|
||||
|
||||
for (lchars = 0, lleft = lbytes; lleft > 0; lchars++) {
|
||||
int chars;
|
||||
|
||||
if (lchars == prec) {
|
||||
/* Truncate at this point. */
|
||||
lbytes = ptr - b;
|
||||
break;
|
||||
}
|
||||
#ifdef MULTIBYTE_SUPPORT
|
||||
if (isset(MULTIBYTE)) {
|
||||
chars = mbrlen(ptr, lleft, &mbs);
|
||||
if (chars < 0) {
|
||||
/*
|
||||
* Invalid/incomplete character at this
|
||||
* point. Assume all the rest are a
|
||||
* single byte. That's about the best we
|
||||
* can do.
|
||||
*/
|
||||
lchars += lleft;
|
||||
lbytes = (ptr - b) + lleft;
|
||||
break;
|
||||
} else if (chars == 0) {
|
||||
/* NUL, handle as real character */
|
||||
chars = 1;
|
||||
}
|
||||
}
|
||||
else /* use the non-multibyte code below */
|
||||
#endif
|
||||
chars = 1; /* compiler can optimise this...*/
|
||||
lleft -= chars;
|
||||
ptr += chars;
|
||||
}
|
||||
/* handle width/precision here and use fwrite so that
|
||||
* nul characters can be output */
|
||||
if (prec >= 0 && prec < l) l = prec;
|
||||
if (width > 0 && flags[2]) width = -width;
|
||||
if (width > 0 && l < width)
|
||||
count += fprintf(fout, "%*c", width - l, ' ');
|
||||
count += fwrite(b, 1, l, fout);
|
||||
if (width < 0 && l < -width)
|
||||
count += fprintf(fout, "%*c", -width - l, ' ');
|
||||
if (width > 0 && lchars < width)
|
||||
count += fprintf(fout, "%*c", width - lchars, ' ');
|
||||
count += fwrite(b, 1, lbytes, fout);
|
||||
if (width < 0 && lchars < -width)
|
||||
count += fprintf(fout, "%*c", -width - lchars, ' ');
|
||||
if (nnl) {
|
||||
/* If the %b arg had a \c escape, truncate the fmt. */
|
||||
flen = c - fmt + 1;
|
||||
|
|
|
@ -311,3 +311,7 @@
|
|||
0:Delimiters in parameter flags
|
||||
>barXX
|
||||
>YYYYYHIbar
|
||||
|
||||
printf "%4.3s\n" főobar
|
||||
0:Multibyte characters in printf widths
|
||||
> főo
|
||||
|
|
Loading…
Reference in a new issue