2003-11-05 Jeff Johnston <jjohnstn@redhat.com>

Artem B. Bityuckiy  <mail_lists@mail.ru>

        * libc/stdio/vfprintf.c (_VFPRINTF_R): Add support for
        %ls, %S, %lc, and %C format specifiers.
        (get_arg): Ditto.
        * libc/stdio/sprintf.c: Add documentation regarding new
        format specifiers added in vfprintf.c.
This commit is contained in:
Jeff Johnston 2003-11-06 00:50:57 +00:00
parent da2d12279b
commit d2ffac097d
3 changed files with 119 additions and 11 deletions

View File

@ -1,3 +1,12 @@
2003-11-05 Jeff Johnston <jjohnstn@redhat.com>
Artem B. Bityuckiy <mail_lists@mail.ru>
* libc/stdio/vfprintf.c (_VFPRINTF_R): Add support for
%ls, %S, %lc, and %C format specifiers.
(get_arg): Ditto.
* libc/stdio/sprintf.c: Add documentation regarding new
format specifiers added in vfprintf.c.
2003-11-05 Jeff Johnston <jjohnstn@redhat.com> 2003-11-05 Jeff Johnston <jjohnstn@redhat.com>
* libc/stdlib/wcsrtombs.c (_wcsrtombs_r): Numerous fixes * libc/stdlib/wcsrtombs.c (_wcsrtombs_r): Numerous fixes

View File

@ -205,7 +205,8 @@ DESCRIPTION
<<l>> forces the following <<d>>, <<i>>, <<o>>, <<u>>, <<l>> forces the following <<d>>, <<i>>, <<o>>, <<u>>,
<<x>> or <<X>> conversion <[type]> to apply to a <<long>> or <<x>> or <<X>> conversion <[type]> to apply to a <<long>> or
<<unsigned long>>. <<l>> also forces a following <<n>> <[type]> to <<unsigned long>>. <<l>> also forces a following <<n>> <[type]> to
apply to a pointer to a <<long>>. If an <<h>> apply to a pointer to a <<long>>. <<l>> with <<c>>, <<s>> is
equivalent to <<C>>, <<S>> respectively. If an <<h>>
or an <<l>> appears with another conversion or an <<l>> appears with another conversion
specifier, the behavior is undefined. <<L>> forces a specifier, the behavior is undefined. <<L>> forces a
following <<e>>, <<E>>, <<f>>, <<g>> or <<G>> conversion <[type]> to following <<e>>, <<E>>, <<f>>, <<g>> or <<G>> conversion <[type]> to
@ -224,10 +225,18 @@ DESCRIPTION
o c o c
prints <[arg]> as single character prints <[arg]> as single character
o C
prints wchar_t <[arg]> as single multibyte character
o s o s
prints characters until precision is reached or a null terminator prints characters until precision is reached or a null terminator
is encountered; takes a string pointer is encountered; takes a string pointer
o S
converts wchar_t characters to multibyte output characters until
precision is reached or a null wchar_t terminator
is encountered; takes a wchar_t pointer
o d o d
prints a signed decimal integer; takes an <<int>> (same as <<i>>) prints a signed decimal integer; takes an <<int>> (same as <<i>>)

View File

@ -183,6 +183,7 @@ static char *rcsid = "$Id$";
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <limits.h>
#include <reent.h> #include <reent.h>
#include <wchar.h> #include <wchar.h>
#include <string.h> #include <string.h>
@ -267,7 +268,12 @@ __sbprintf(fp, fmt, ap)
#include <math.h> #include <math.h>
#include "floatio.h" #include "floatio.h"
#define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ #if ((MAXEXP+MAXFRACT+1) > MB_LEN_MAX)
# define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
#else
# define BUF MB_LEN_MAX
#endif
#define DEFPREC 6 #define DEFPREC 6
#ifdef _NO_LONGDBL #ifdef _NO_LONGDBL
@ -320,6 +326,7 @@ union arg_val
void_ptr_t val_void_ptr_t; void_ptr_t val_void_ptr_t;
quad_t val_quad_t; quad_t val_quad_t;
u_quad_t val_u_quad_t; u_quad_t val_u_quad_t;
wint_t val_wint_t;
}; };
static union arg_val *get_arg (struct _reent *data, int n, char *fmt, static union arg_val *get_arg (struct _reent *data, int n, char *fmt,
@ -428,7 +435,8 @@ _DEFUN (_VFPRINTF_R, (data, fp, fmt0, ap),
struct __siov iov[NIOV];/* ... and individual io vectors */ struct __siov iov[NIOV];/* ... and individual io vectors */
char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
char ox[2]; /* space for 0x hex-prefix */ char ox[2]; /* space for 0x hex-prefix */
mbstate_t state; /* mbtowc calls from library must not change state */ mbstate_t state; /* mbtowc calls from library must not change state */
char *malloc_buf = NULL;/* handy pointer for malloced buffers */
/* /*
* Choose PADSIZE to trade efficiency vs. size. If larger printf * Choose PADSIZE to trade efficiency vs. size. If larger printf
@ -728,8 +736,21 @@ reswitch: switch (ch) {
flags |= QUADINT; flags |= QUADINT;
goto rflag; goto rflag;
case 'c': case 'c':
*(cp = buf) = GET_ARG(N, ap, int); case 'C':
size = 1; cp = buf;
if (*fmt == 'C' || (flags & LONGINT)) {
mbstate_t ps;
memset((void *)&ps, '\0', sizeof(mbstate_t));
if ((size = (int)wcrtomb(cp,
(wchar_t)GET_ARG(N, ap, wint_t),
&ps)) == -1)
goto error;
}
else {
*cp = GET_ARG(N, ap, int);
size = 1;
}
sign = '\0'; sign = '\0';
break; break;
case 'D': case 'D':
@ -881,9 +902,61 @@ reswitch: switch (ch) {
ch = 'x'; ch = 'x';
goto nosign; goto nosign;
case 's': case 's':
if ((cp = GET_ARG(N, ap, char_ptr_t)) == NULL) case 'S':
sign = '\0';
if ((cp = GET_ARG(N, ap, char_ptr_t)) == NULL) {
cp = "(null)"; cp = "(null)";
if (prec >= 0) { size = 6;
}
else if (ch == 'S' || (flags & LONGINT)) {
mbstate_t ps;
_CONST wchar_t *wcp;
wcp = (_CONST wchar_t *)cp;
size = m = 0;
memset((void *)&ps, '\0', sizeof(mbstate_t));
/* Count number of bytes needed for multibyte
string that will be produced from widechar
string. */
if (prec >= 0) {
while (1) {
if (wcp[m] == L'\0')
break;
if ((n = (int)wcrtomb(buf,
wcp[m], &ps)) == -1)
goto error;
if (n + size > prec)
break;
m += 1;
size += n;
if (size == prec)
break;
}
}
else {
if ((size = (int)wcsrtombs(NULL, &wcp,
0, &ps)) == -1)
goto error;
wcp = (_CONST wchar_t *)cp;
}
if (size == 0)
break;
if ((malloc_buf =
(char *)malloc(size + 1)) == NULL)
goto error;
/* Convert widechar string to multibyte string. */
memset((void *)&ps, '\0', sizeof(mbstate_t));
if (wcsrtombs(malloc_buf, &wcp, size, &ps)
!= size)
goto error;
cp = malloc_buf;
cp[size] = '\0';
}
else if (prec >= 0) {
/* /*
* can't use strlen; can only look for the * can't use strlen; can only look for the
* NUL in the first `prec' characters, and * NUL in the first `prec' characters, and
@ -899,7 +972,7 @@ reswitch: switch (ch) {
size = prec; size = prec;
} else } else
size = strlen(cp); size = strlen(cp);
sign = '\0';
break; break;
case 'U': case 'U':
flags |= LONGINT; flags |= LONGINT;
@ -1097,10 +1170,17 @@ number: if ((dprec = prec) >= 0)
ret += width > realsz ? width : realsz; ret += width > realsz ? width : realsz;
FLUSH(); /* copy out the I/O vectors */ FLUSH(); /* copy out the I/O vectors */
if (malloc_buf != NULL) {
free(malloc_buf);
malloc_buf = NULL;
}
} }
done: done:
FLUSH(); FLUSH();
error: error:
if (malloc_buf != NULL)
free(malloc_buf);
return (__sferror(fp) ? EOF : ret); return (__sferror(fp) ? EOF : ret);
/* NOTREACHED */ /* NOTREACHED */
} }
@ -1302,9 +1382,9 @@ const static CH_CLASS chclass[256] = {
/* 28-2f */ OTHER, OTHER, STAR, FLAG, OTHER, FLAG, DOT, OTHER, /* 28-2f */ OTHER, OTHER, STAR, FLAG, OTHER, FLAG, DOT, OTHER,
/* 30-37 */ ZERO, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, /* 30-37 */ ZERO, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT,
/* 38-3f */ DIGIT, DIGIT, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* 38-3f */ DIGIT, DIGIT, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
/* 40-47 */ OTHER, OTHER, OTHER, OTHER, SPEC, SPEC, OTHER, SPEC, /* 40-47 */ OTHER, OTHER, OTHER, SPEC, SPEC, SPEC, OTHER, SPEC,
/* 48-4f */ OTHER, OTHER, OTHER, OTHER, MODFR, OTHER, OTHER, SPEC, /* 48-4f */ OTHER, OTHER, OTHER, OTHER, MODFR, OTHER, OTHER, SPEC,
/* 50-57 */ OTHER, OTHER, OTHER, OTHER, OTHER, SPEC, OTHER, SPEC, /* 50-57 */ OTHER, OTHER, OTHER, SPEC, OTHER, SPEC, OTHER, SPEC,
/* 58-5f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* 58-5f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
/* 60-67 */ OTHER, OTHER, OTHER, SPEC, SPEC, SPEC, SPEC, SPEC, /* 60-67 */ OTHER, OTHER, OTHER, SPEC, SPEC, SPEC, SPEC, SPEC,
/* 68-6f */ MODFR, SPEC, OTHER, OTHER, MODFR, OTHER, OTHER, SPEC, /* 68-6f */ MODFR, SPEC, OTHER, OTHER, MODFR, OTHER, OTHER, SPEC,
@ -1375,7 +1455,7 @@ get_arg (struct _reent *data, int n, char *fmt, va_list *ap,
int pos, last_arg; int pos, last_arg;
mbstate_t wc_state; mbstate_t wc_state;
int max_pos_arg = n; int max_pos_arg = n;
enum types { INT, LONG_INT, SHORT_INT, QUAD_INT, CHAR, CHAR_PTR, DOUBLE, LONG_DOUBLE }; enum types { INT, LONG_INT, SHORT_INT, QUAD_INT, CHAR, CHAR_PTR, DOUBLE, LONG_DOUBLE, WIDE_CHAR };
/* if this isn't the first call, pick up where we left off last time */ /* if this isn't the first call, pick up where we left off last time */
if (*last_fmt != NULL) if (*last_fmt != NULL)
@ -1481,12 +1561,16 @@ get_arg (struct _reent *data, int n, char *fmt, va_list *ap,
spec_type = DOUBLE; spec_type = DOUBLE;
break; break;
case 's': case 's':
case 'S':
case 'p': case 'p':
spec_type = CHAR_PTR; spec_type = CHAR_PTR;
break; break;
case 'c': case 'c':
spec_type = CHAR; spec_type = CHAR;
break; break;
case 'C':
spec_type = WIDE_CHAR;
break;
} }
/* if we have a positional parameter, just store the type, otherwise /* if we have a positional parameter, just store the type, otherwise
@ -1503,6 +1587,9 @@ get_arg (struct _reent *data, int n, char *fmt, va_list *ap,
case QUAD_INT: case QUAD_INT:
args[numargs++].val_quad_t = va_arg(*ap, quad_t); args[numargs++].val_quad_t = va_arg(*ap, quad_t);
break; break;
case WIDE_CHAR:
args[numargs++].val_wint_t = va_arg(*ap, wint_t);
break;
case CHAR: case CHAR:
case SHORT_INT: case SHORT_INT:
case INT: case INT:
@ -1585,6 +1672,9 @@ get_arg (struct _reent *data, int n, char *fmt, va_list *ap,
case LONG_DOUBLE: case LONG_DOUBLE:
args[numargs++].val__LONG_DOUBLE = va_arg(*ap, _LONG_DOUBLE); args[numargs++].val__LONG_DOUBLE = va_arg(*ap, _LONG_DOUBLE);
break; break;
case WIDE_CHAR:
args[numargs++].val_wint_t = va_arg(*ap, wint_t);
break;
case INT: case INT:
case SHORT_INT: case SHORT_INT:
case CHAR: case CHAR: