|
@@ -59,6 +59,10 @@
|
|
|
* Add printf wchar support for %lc (%C) and %ls (%S).
|
|
|
* Require printf format strings to be valid multibyte strings beginning and
|
|
|
* ending in their initial shift state, as per the stds.
|
|
|
+ *
|
|
|
+ * Nov 21, 2002
|
|
|
+ * Add *wprintf functions. Currently they don't support floating point
|
|
|
+ * conversions. That will wait until the rewrite of _dtostr.
|
|
|
*/
|
|
|
|
|
|
|
|
@@ -177,7 +181,8 @@ enum {
|
|
|
FLAG_MINUS = 0x08,
|
|
|
FLAG_HASH = 0x10,
|
|
|
FLAG_THOUSANDS = 0x20,
|
|
|
- FLAG_I18N = 0x40
|
|
|
+ FLAG_I18N = 0x40,
|
|
|
+ FLAG_WIDESTREAM = 0x80
|
|
|
};
|
|
|
|
|
|
|
|
@@ -359,15 +364,14 @@ typedef struct {
|
|
|
extern size_t _dtostr(FILE * fp, long double x, struct printf_info *info);
|
|
|
#endif
|
|
|
|
|
|
-#define _outnstr(stream, string, len) _stdio_fwrite(string, len, stream)
|
|
|
-
|
|
|
-extern int _do_one_spec(FILE * __restrict stream, ppfs_t *ppfs, int *count);
|
|
|
-
|
|
|
extern int _ppfs_init(ppfs_t *ppfs, const char *fmt0);
|
|
|
extern void _ppfs_prepargs(ppfs_t *ppfs, va_list arg);
|
|
|
extern void _ppfs_setargs(ppfs_t *ppfs);
|
|
|
extern int _ppfs_parsespec(ppfs_t *ppfs);
|
|
|
|
|
|
+extern void _store_inttype(void *dest, int desttype, uintmax_t val);
|
|
|
+extern uintmax_t _load_inttype(int desttype, const void *src, int uflag);
|
|
|
+
|
|
|
|
|
|
#ifdef L_parse_printf_format
|
|
|
|
|
@@ -433,72 +437,6 @@ size_t parse_printf_format(register const char *template,
|
|
|
return count;
|
|
|
}
|
|
|
|
|
|
-#endif
|
|
|
-
|
|
|
-#ifdef L_vfprintf
|
|
|
-
|
|
|
-
|
|
|
- * precision and width settings in *printf (wide) format strings.
|
|
|
- * In other words, we don't currently support glibc's 'I' flag.
|
|
|
- * We do accept it, but it is currently ignored. */
|
|
|
-
|
|
|
-int vfprintf(FILE * __restrict stream, register const char * __restrict format,
|
|
|
- va_list arg)
|
|
|
-{
|
|
|
- ppfs_t ppfs;
|
|
|
- int count, r;
|
|
|
- register const char *s;
|
|
|
-
|
|
|
- __STDIO_THREADLOCK(stream);
|
|
|
-
|
|
|
- count = 0;
|
|
|
- s = format;
|
|
|
-
|
|
|
- if (_ppfs_init(&ppfs, format) < 0) {
|
|
|
- _outnstr(stream, ppfs.fmtpos, strlen(ppfs.fmtpos));
|
|
|
- count = -1;
|
|
|
- } else {
|
|
|
- _ppfs_prepargs(&ppfs, arg);
|
|
|
-
|
|
|
- do {
|
|
|
- while (*format && (*format != '%')) {
|
|
|
- ++format;
|
|
|
- }
|
|
|
-
|
|
|
- if (format-s) {
|
|
|
- if ( (r = _outnstr(stream, s, format-s)) < 0) {
|
|
|
- count = -1;
|
|
|
- break;
|
|
|
- }
|
|
|
- count += r;
|
|
|
- }
|
|
|
-
|
|
|
- if (!*format) {
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (format[1] != '%') {
|
|
|
-
|
|
|
- ppfs.fmtpos = ++format;
|
|
|
-
|
|
|
- if ( (r = _do_one_spec(stream, &ppfs, &count)) < 0) {
|
|
|
- count = -1;
|
|
|
- break;
|
|
|
- }
|
|
|
- s = format = ppfs.fmtpos;
|
|
|
- } else {
|
|
|
- s = ++format;
|
|
|
- ++format;
|
|
|
- }
|
|
|
- } while (1);
|
|
|
-
|
|
|
- va_end(ppfs.arg);
|
|
|
- }
|
|
|
-
|
|
|
- __STDIO_THREADUNLOCK(stream);
|
|
|
-
|
|
|
- return count;
|
|
|
-}
|
|
|
#endif
|
|
|
|
|
|
#ifdef L__ppfs_init
|
|
@@ -514,9 +452,7 @@ int _ppfs_init(register ppfs_t *ppfs, const char *fmt0)
|
|
|
memset(ppfs, 0, sizeof(ppfs_t));
|
|
|
--ppfs->maxposarg;
|
|
|
ppfs->fmtpos = fmt0;
|
|
|
-#if defined(__UCLIBC_HAS_WCHAR__) && defined(__UCLIBC_HAS_LOCALE__)
|
|
|
-
|
|
|
- * support the C locale. */
|
|
|
+#ifdef __UCLIBC_HAS_WCHAR__
|
|
|
{
|
|
|
mbstate_t mbstate;
|
|
|
const char *p;
|
|
@@ -527,7 +463,7 @@ int _ppfs_init(register ppfs_t *ppfs, const char *fmt0)
|
|
|
return -1;
|
|
|
}
|
|
|
}
|
|
|
-#endif
|
|
|
+#endif
|
|
|
|
|
|
{
|
|
|
#if 1
|
|
@@ -810,6 +746,7 @@ static char _bss_custom_printf_spec[MAX_USER_SPEC];
|
|
|
|
|
|
char *_custom_printf_spec = _bss_custom_printf_spec;
|
|
|
printf_arginfo_function *_custom_printf_arginfo[MAX_USER_SPEC];
|
|
|
+printf_function _custom_printf_handler[MAX_USER_SPEC];
|
|
|
|
|
|
extern int _ppfs_parsespec(ppfs_t *ppfs)
|
|
|
{
|
|
@@ -833,17 +770,44 @@ extern int _ppfs_parsespec(ppfs_t *ppfs)
|
|
|
static const short spec_or_mask[] = SPEC_OR_MASK;
|
|
|
static const short spec_and_mask[] = SPEC_AND_MASK;
|
|
|
static const char qual_chars[] = QUAL_CHARS;
|
|
|
+#ifdef __UCLIBC_HAS_WCHAR__
|
|
|
+ char buf[32];
|
|
|
+#endif
|
|
|
|
|
|
|
|
|
|
|
|
preci = -1;
|
|
|
- width = flags = dpoint = 0;
|
|
|
argnumber[0] = 0;
|
|
|
argnumber[1] = 0;
|
|
|
argtype[0] = __PA_NOARG;
|
|
|
argtype[1] = __PA_NOARG;
|
|
|
maxposarg = ppfs->maxposarg;
|
|
|
+#ifdef __UCLIBC_HAS_WCHAR__
|
|
|
+
|
|
|
+ * a wide stream, that means the format is a wchar string. So, copy it
|
|
|
+ * char-by-char into a normal char buffer for processing. Make the buffer
|
|
|
+ * (buf) big enough so that any reasonable format specifier will fit.
|
|
|
+ * While there a legal specifiers that won't, the all involve duplicate
|
|
|
+ * flags or outrageous field widths/precisions. */
|
|
|
+ width = dpoint = 0;
|
|
|
+ if ((flags = ppfs->info._flags & FLAG_WIDESTREAM) == 0) {
|
|
|
+ fmt = ppfs->fmtpos;
|
|
|
+ } else {
|
|
|
+ fmt = buf + 1;
|
|
|
+ i = 0;
|
|
|
+ do {
|
|
|
+ if ((buf[i] = (char) (((wchar_t *) ppfs->fmtpos)[i-1]))
|
|
|
+ != (((wchar_t *) ppfs->fmtpos)[i-1])
|
|
|
+ ) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ } while (buf[i++]);
|
|
|
+ buf[sizeof(buf)-1] = 0;
|
|
|
+ }
|
|
|
+#else
|
|
|
+ width = flags = dpoint = 0;
|
|
|
fmt = ppfs->fmtpos;
|
|
|
+#endif
|
|
|
|
|
|
assert(fmt[-1] == '%');
|
|
|
assert(fmt[0] != '%');
|
|
@@ -877,6 +841,16 @@ extern int _ppfs_parsespec(ppfs_t *ppfs)
|
|
|
|
|
|
} else {
|
|
|
if (maxposarg > 0) {
|
|
|
+#ifdef __STDIO_PRINTF_M_SUPPORT
|
|
|
+#ifdef __UCLIBC_MJN3_ONLY__
|
|
|
+#warning TODO: Support prec and width for %m when positional args used
|
|
|
+
|
|
|
+ * for specifiers that don't require an arg. */
|
|
|
+#endif
|
|
|
+ if (*fmt == 'm') {
|
|
|
+ goto PREC_WIDTH;
|
|
|
+ }
|
|
|
+#endif
|
|
|
return -1;
|
|
|
}
|
|
|
maxposarg = 0;
|
|
@@ -1045,9 +1019,19 @@ extern int _ppfs_parsespec(ppfs_t *ppfs)
|
|
|
}
|
|
|
|
|
|
ppfs->maxposarg = maxposarg;
|
|
|
- ppfs->fmtpos = ++fmt;
|
|
|
ppfs->conv_num = conv_num;
|
|
|
|
|
|
+#ifdef __UCLIBC_HAS_WCHAR__
|
|
|
+ if ((flags = ppfs->info._flags & FLAG_WIDESTREAM) == 0) {
|
|
|
+ ppfs->fmtpos = ++fmt;
|
|
|
+ } else {
|
|
|
+ ppfs->fmtpos = (const char *) (((const wchar_t *)(ppfs->fmtpos))
|
|
|
+ + (fmt - buf) );
|
|
|
+ }
|
|
|
+#else
|
|
|
+ ppfs->fmtpos = ++fmt;
|
|
|
+#endif
|
|
|
+
|
|
|
return ppfs->num_data_args + 2;
|
|
|
}
|
|
|
|
|
@@ -1094,337 +1078,165 @@ int register_printf_function(int spec, printf_function handler,
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
-#ifdef L__do_one_spec
|
|
|
+#ifdef L_vsnprintf
|
|
|
|
|
|
-printf_function _custom_printf_handler[MAX_USER_SPEC];
|
|
|
+#ifdef __STDIO_BUFFERS
|
|
|
+int vsnprintf(char *__restrict buf, size_t size,
|
|
|
+ const char * __restrict format, va_list arg)
|
|
|
+{
|
|
|
+ FILE f;
|
|
|
+ int rv;
|
|
|
|
|
|
-extern void _store_inttype(void *dest, int desttype, uintmax_t val);
|
|
|
-extern uintmax_t _load_inttype(int desttype, const void *src, int uflag);
|
|
|
-extern void _charpad(FILE * __restrict stream, char padchar, size_t numpad);
|
|
|
-extern void output(FILE * __restrict stream, const char *s);
|
|
|
+#ifdef __STDIO_GETC_MACRO
|
|
|
+ f.bufgetc =
|
|
|
+#endif
|
|
|
+ f.bufpos = f.bufread = f.bufstart = buf;
|
|
|
|
|
|
-#define output(F,S) fputs(S,F)
|
|
|
+ if (size > SIZE_MAX - (size_t) buf) {
|
|
|
+ size = SIZE_MAX - (size_t) buf;
|
|
|
+ }
|
|
|
+#ifdef __STDIO_PUTC_MACRO
|
|
|
+ f.bufputc =
|
|
|
+#endif
|
|
|
+ f.bufend = buf + size;
|
|
|
|
|
|
-#undef putc
|
|
|
-void _charpad(FILE * __restrict stream, char padchar, size_t numpad)
|
|
|
-{
|
|
|
-
|
|
|
- char pad[1];
|
|
|
+#if 0
|
|
|
+
|
|
|
+ f.cookie = &(f.filedes);
|
|
|
+ f.gcs.read = 0;
|
|
|
+ f.gcs.write = 0;
|
|
|
+ f.gcs.seek = 0;
|
|
|
+ f.gcs.close = 0;
|
|
|
+#endif
|
|
|
+ f.filedes = -2;
|
|
|
+ f.modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
|
|
|
|
|
|
- *pad = padchar;
|
|
|
- while (numpad) {
|
|
|
- _stdio_fwrite(pad, 1, stream);
|
|
|
- --numpad;
|
|
|
+#ifdef __STDIO_MBSTATE
|
|
|
+ __INIT_MBSTATE(&(f.state));
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef __STDIO_THREADSAFE
|
|
|
+ f.user_locking = 0;
|
|
|
+ __stdio_init_mutex(&f.lock);
|
|
|
+#endif
|
|
|
+
|
|
|
+ rv = vfprintf(&f, format, arg);
|
|
|
+ if (size) {
|
|
|
+ if (f.bufpos == f.bufend) {
|
|
|
+ --f.bufpos;
|
|
|
+ }
|
|
|
+ *f.bufpos = 0;
|
|
|
}
|
|
|
+ return rv;
|
|
|
}
|
|
|
+#else
|
|
|
+#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
|
|
|
|
|
|
-
|
|
|
+typedef struct {
|
|
|
+ size_t pos;
|
|
|
+ size_t len;
|
|
|
+ unsigned char *buf;
|
|
|
+ FILE *fp;
|
|
|
+} __snpf_cookie;
|
|
|
|
|
|
-int _do_one_spec(FILE * __restrict stream, register ppfs_t *ppfs, int *count)
|
|
|
-{
|
|
|
- static const char spec_base[] = SPEC_BASE;
|
|
|
- static const char prefix[] = "+\0-\0 \0000x\0000X";
|
|
|
-
|
|
|
- enum {
|
|
|
- PREFIX_PLUS = 0,
|
|
|
- PREFIX_MINUS = 2,
|
|
|
- PREFIX_SPACE = 4,
|
|
|
- PREFIX_LWR_X = 6,
|
|
|
- PREFIX_UPR_X = 9,
|
|
|
- PREFIX_NONE = 11
|
|
|
- };
|
|
|
+#define COOKIE ((__snpf_cookie *) cookie)
|
|
|
|
|
|
-#ifdef __va_arg_ptr
|
|
|
- const void * const *argptr;
|
|
|
-#else
|
|
|
- const void * argptr[MAX_ARGS_PER_SPEC];
|
|
|
-#endif
|
|
|
- int *argtype;
|
|
|
-#ifdef __UCLIBC_HAS_WCHAR__
|
|
|
- const wchar_t *ws = NULL;
|
|
|
- mbstate_t mbstate;
|
|
|
-#endif
|
|
|
- size_t slen;
|
|
|
- int base;
|
|
|
- int numpad;
|
|
|
- int alphacase;
|
|
|
- int numfill = 0;
|
|
|
- int prefix_num = PREFIX_NONE;
|
|
|
- char padchar = ' ';
|
|
|
-#ifdef __UCLIBC_MJN3_ONLY__
|
|
|
-#warning REMINDER: buf size
|
|
|
-#endif
|
|
|
-
|
|
|
- * and also for any locale-grouped long long integer strings generated.
|
|
|
- * This should be large enough for any of the current archs/locales, but
|
|
|
- * eventually this should be handled robustly. */
|
|
|
- char buf[128];
|
|
|
+static ssize_t snpf_write(register void *cookie, const char *buf,
|
|
|
+ size_t bufsize)
|
|
|
+{
|
|
|
+ size_t count;
|
|
|
+ register char *p;
|
|
|
|
|
|
-#ifdef NDEBUG
|
|
|
- _ppfs_parsespec(ppfs);
|
|
|
-#else
|
|
|
- if (_ppfs_parsespec(ppfs) < 0) {
|
|
|
- abort();
|
|
|
- }
|
|
|
-#endif
|
|
|
- _ppfs_setargs(ppfs);
|
|
|
+
|
|
|
|
|
|
- argtype = ppfs->argtype + ppfs->argnumber[2] - 1;
|
|
|
-
|
|
|
-#ifdef __va_arg_ptr
|
|
|
- argptr = (const void * const *) ppfs->argptr;
|
|
|
- if (ppfs->maxposarg > 0) {
|
|
|
- argptr += ppfs->argnumber[2] - 1;
|
|
|
- }
|
|
|
-#else
|
|
|
-
|
|
|
- {
|
|
|
- register argvalue_t *p = ppfs->argvalue;
|
|
|
- int i;
|
|
|
- if (ppfs->maxposarg > 0) {
|
|
|
- p += ppfs->argnumber[2] - 1;
|
|
|
+ if (COOKIE->len > COOKIE->pos) {
|
|
|
+ count = COOKIE->len - COOKIE->pos - 1;
|
|
|
+ if (count > bufsize) {
|
|
|
+ count = bufsize;
|
|
|
}
|
|
|
- for (i = 0 ; i < ppfs->num_data_args ; i++ ) {
|
|
|
- argptr[i] = (void *) p++;
|
|
|
+
|
|
|
+ p = COOKIE->buf + COOKIE->pos;
|
|
|
+ while (count) {
|
|
|
+ *p++ = *buf++;
|
|
|
+ --count;
|
|
|
}
|
|
|
+ *p = 0;
|
|
|
}
|
|
|
-#endif
|
|
|
- {
|
|
|
- register char *s;
|
|
|
|
|
|
- if (ppfs->conv_num == CONV_n) {
|
|
|
- _store_inttype(*(void **)*argptr,
|
|
|
- ppfs->info._flags & __PA_INTMASK,
|
|
|
- (intmax_t) (*count));
|
|
|
- return 0;
|
|
|
- }
|
|
|
- if (ppfs->conv_num <= CONV_i) {
|
|
|
- alphacase = __UIM_LOWER;
|
|
|
- if (((base = spec_base[(int)(ppfs->conv_num - CONV_p)]) == 10)
|
|
|
- && (PRINT_INFO_FLAG_VAL(&(ppfs->info),group))
|
|
|
- ) {
|
|
|
- alphacase = __UIM_GROUP;
|
|
|
- }
|
|
|
- if (ppfs->conv_num <= CONV_u) {
|
|
|
- if (ppfs->conv_num == CONV_X) {
|
|
|
- alphacase = __UIM_UPPER;
|
|
|
- }
|
|
|
- if (ppfs->conv_num == CONV_p) {
|
|
|
- prefix_num = PREFIX_LWR_X;
|
|
|
- } else {
|
|
|
- }
|
|
|
- } else {
|
|
|
- base = -base;
|
|
|
- }
|
|
|
- if (ppfs->info.prec < 0) {
|
|
|
- padchar = ppfs->info.pad;
|
|
|
- }
|
|
|
- s = _uintmaxtostr(buf + sizeof(buf) - 1,
|
|
|
- (uintmax_t)
|
|
|
- _load_inttype(*argtype & __PA_INTMASK,
|
|
|
- *argptr, base), base, alphacase);
|
|
|
- if (ppfs->conv_num > CONV_u) {
|
|
|
- if (*s == '-') {
|
|
|
- PRINT_INFO_SET_FLAG(&(ppfs->info),showsign);
|
|
|
- ++s;
|
|
|
- prefix_num = PREFIX_MINUS;
|
|
|
- } else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),showsign)) {
|
|
|
- prefix_num = PREFIX_PLUS;
|
|
|
- } else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),space)) {
|
|
|
- prefix_num = PREFIX_SPACE;
|
|
|
- }
|
|
|
- }
|
|
|
- slen = (char *)(buf + sizeof(buf) - 1) - s;
|
|
|
- numfill = ((ppfs->info.prec < 0) ? 1 : ppfs->info.prec);
|
|
|
- if (PRINT_INFO_FLAG_VAL(&(ppfs->info),alt)) {
|
|
|
- if (ppfs->conv_num <= CONV_x) {
|
|
|
- prefix_num = PREFIX_LWR_X;
|
|
|
- }
|
|
|
- if (ppfs->conv_num == CONV_X) {
|
|
|
- prefix_num = PREFIX_UPR_X;
|
|
|
- }
|
|
|
- if ((ppfs->conv_num == CONV_o) && (numfill <= slen)) {
|
|
|
- numfill = ((*s == '0') ? 1 : slen + 1);
|
|
|
- }
|
|
|
- }
|
|
|
- if (*s == '0') {
|
|
|
- if (prefix_num >= PREFIX_LWR_X) {
|
|
|
- prefix_num = PREFIX_NONE;
|
|
|
- }
|
|
|
- if (ppfs->conv_num == CONV_p) {
|
|
|
- s = "(nil)";
|
|
|
- slen = 5;
|
|
|
- numfill = 0;
|
|
|
- } else if (numfill == 0) {
|
|
|
- slen = 0;
|
|
|
- }
|
|
|
- }
|
|
|
- numfill = ((numfill > slen) ? numfill - slen : 0);
|
|
|
- } else if (ppfs->conv_num <= CONV_A) {
|
|
|
-#ifdef __STDIO_PRINTF_FLOAT
|
|
|
- *count += _dtostr(stream,
|
|
|
- (PRINT_INFO_FLAG_VAL(&(ppfs->info),is_long_double)
|
|
|
- ? *(long double *) *argptr
|
|
|
- : (long double) (* (double *) *argptr)),
|
|
|
- &ppfs->info);
|
|
|
- return 0;
|
|
|
-#else
|
|
|
- return -1;
|
|
|
-#endif
|
|
|
- } else if (ppfs->conv_num <= CONV_S) {
|
|
|
-#ifdef __UCLIBC_HAS_WCHAR__
|
|
|
- mbstate.mask = 0;
|
|
|
- if (ppfs->conv_num == CONV_S) {
|
|
|
- if (!(ws = *((const wchar_t **) *argptr))) {
|
|
|
- goto NULL_STRING;
|
|
|
- }
|
|
|
-
|
|
|
- * (char*) &ws as the conversion destination. This signals
|
|
|
- * uClibc's wcsrtombs that we want a "restricted" length
|
|
|
- * such that the mbs fits in a buffer of the specified
|
|
|
- * size with no partial conversions. */
|
|
|
- if ((slen = wcsrtombs((char *) &ws, &ws,
|
|
|
- ((ppfs->info.prec >= 0)
|
|
|
- ? ppfs->info.prec
|
|
|
- : SIZE_MAX), &mbstate))
|
|
|
- == ((size_t)-1)
|
|
|
- ) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
- } else {
|
|
|
- s = buf;
|
|
|
- slen = wcrtomb(s, (*((const wchar_t *) *argptr)), &mbstate);
|
|
|
- if (slen == ((size_t)-1)) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
- s[slen] = 0;
|
|
|
- }
|
|
|
-#else
|
|
|
- return -1;
|
|
|
-#endif
|
|
|
- } else if (ppfs->conv_num <= CONV_s) {
|
|
|
- if (ppfs->conv_num == CONV_s) {
|
|
|
- s = *((char **) (*argptr));
|
|
|
- if (s) {
|
|
|
- SET_STRING_LEN:
|
|
|
- slen = strnlen(s, ((ppfs->info.prec >= 0)
|
|
|
- ? ppfs->info.prec : SIZE_MAX));
|
|
|
- } else {
|
|
|
- NULL_STRING:
|
|
|
- s = "(null)";
|
|
|
- slen = 6;
|
|
|
- }
|
|
|
- } else {
|
|
|
- s = buf;
|
|
|
- *s = (unsigned char)(*((const int *) *argptr));
|
|
|
- s[1] = 0;
|
|
|
- slen = 1;
|
|
|
- }
|
|
|
-#ifdef __STDIO_PRINTF_M_SUPPORT
|
|
|
- } else if (ppfs->conv_num == CONV_m) {
|
|
|
- s = _glibc_strerror_r(errno, buf, sizeof(buf));
|
|
|
- goto SET_STRING_LEN;
|
|
|
-#endif
|
|
|
- } else {
|
|
|
- assert(ppfs->conv_num == CONV_custom0);
|
|
|
+ COOKIE->pos += bufsize;
|
|
|
|
|
|
- s = _custom_printf_spec;
|
|
|
- do {
|
|
|
- if (*s == ppfs->info.spec) {
|
|
|
- int rv;
|
|
|
-
|
|
|
- rv = (*_custom_printf_handler
|
|
|
- [(int)(s-_custom_printf_spec)])
|
|
|
- (stream, &ppfs->info, argptr);
|
|
|
- if (rv < 0) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
- *count += rv;
|
|
|
- return 0;
|
|
|
- }
|
|
|
- } while (++s < (_custom_printf_spec + MAX_USER_SPEC));
|
|
|
- assert(0);
|
|
|
- return -1;
|
|
|
- }
|
|
|
+ return bufsize;
|
|
|
+}
|
|
|
|
|
|
- {
|
|
|
- size_t t;
|
|
|
+#undef COOKIE
|
|
|
|
|
|
- t = slen + numfill;
|
|
|
- if (prefix_num != PREFIX_NONE) {
|
|
|
- t += ((prefix_num < PREFIX_LWR_X) ? 1 : 2);
|
|
|
- }
|
|
|
- numpad = ((ppfs->info.width > t) ? (ppfs->info.width - t) : 0);
|
|
|
- *count += t + numpad;
|
|
|
- }
|
|
|
- if (padchar == '0') {
|
|
|
- numfill += numpad;
|
|
|
- numpad = 0;
|
|
|
- }
|
|
|
+int vsnprintf(char *__restrict buf, size_t size,
|
|
|
+ const char * __restrict format, va_list arg)
|
|
|
+{
|
|
|
+ FILE f;
|
|
|
+ __snpf_cookie cookie;
|
|
|
+ int rv;
|
|
|
|
|
|
-
|
|
|
- if (!PRINT_INFO_FLAG_VAL(&(ppfs->info),left)) {
|
|
|
- _charpad(stream, ' ', numpad);
|
|
|
- numpad = 0;
|
|
|
- }
|
|
|
- output(stream, prefix + prefix_num);
|
|
|
- _charpad(stream, '0', numfill);
|
|
|
-#ifdef __UCLIBC_HAS_WCHAR__
|
|
|
- if (!ws) {
|
|
|
- _outnstr(stream, s, slen);
|
|
|
- } else {
|
|
|
- size_t t;
|
|
|
- mbstate.mask = 0;
|
|
|
- while (slen) {
|
|
|
- t = (slen <= sizeof(buf)) ? slen : sizeof(buf);
|
|
|
- t = wcsrtombs(buf, &ws, t, &mbstate);
|
|
|
- assert (t != ((size_t)(-1)));
|
|
|
- _outnstr(stream, buf, t);
|
|
|
- slen -= t;
|
|
|
- }
|
|
|
- ws = NULL;
|
|
|
- }
|
|
|
-#else
|
|
|
- _outnstr(stream, s, slen);
|
|
|
-#endif
|
|
|
- _charpad(stream, ' ', numpad);
|
|
|
- }
|
|
|
+ cookie.buf = buf;
|
|
|
+ cookie.len = size;
|
|
|
+ cookie.pos = 0;
|
|
|
+ cookie.fp = &f;
|
|
|
|
|
|
- return 0;
|
|
|
+ f.cookie = &cookie;
|
|
|
+ f.gcs.write = snpf_write;
|
|
|
+ f.gcs.read = NULL;
|
|
|
+ f.gcs.seek = NULL;
|
|
|
+ f.gcs.close = NULL;
|
|
|
+
|
|
|
+ f.filedes = -1;
|
|
|
+ f.modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
|
|
|
+
|
|
|
+#ifdef __STDIO_MBSTATE
|
|
|
+ __INIT_MBSTATE(&(f.state));
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef __STDIO_THREADSAFE
|
|
|
+ f.user_locking = 0;
|
|
|
+ __stdio_init_mutex(&f.lock);
|
|
|
+#endif
|
|
|
+
|
|
|
+ rv = vfprintf(&f, format, arg);
|
|
|
+
|
|
|
+ return rv;
|
|
|
}
|
|
|
+
|
|
|
+#else
|
|
|
+#warning skipping vsnprintf since no buffering and no custom streams!
|
|
|
+#endif
|
|
|
+#endif
|
|
|
#endif
|
|
|
|
|
|
-#ifdef L_vsnprintf
|
|
|
+#ifdef L_vdprintf
|
|
|
|
|
|
-#ifdef __STDIO_BUFFERS
|
|
|
-int vsnprintf(char *__restrict buf, size_t size,
|
|
|
- const char * __restrict format, va_list arg)
|
|
|
+int vdprintf(int filedes, const char * __restrict format, va_list arg)
|
|
|
{
|
|
|
FILE f;
|
|
|
int rv;
|
|
|
+#ifdef __STDIO_BUFFERS
|
|
|
+ char buf[64];
|
|
|
|
|
|
#ifdef __STDIO_GETC_MACRO
|
|
|
f.bufgetc =
|
|
|
#endif
|
|
|
f.bufpos = f.bufread = f.bufstart = buf;
|
|
|
-
|
|
|
- if (size > SIZE_MAX - (size_t) buf) {
|
|
|
- size = SIZE_MAX - (size_t) buf;
|
|
|
- }
|
|
|
#ifdef __STDIO_PUTC_MACRO
|
|
|
- f.bufputc =
|
|
|
+ f.bufputc =
|
|
|
#endif
|
|
|
- f.bufend = buf + size;
|
|
|
-
|
|
|
-#if 0
|
|
|
-
|
|
|
+ f.bufend = buf + sizeof(buf);
|
|
|
+#endif
|
|
|
+#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
|
|
|
f.cookie = &(f.filedes);
|
|
|
- f.gcs.read = 0;
|
|
|
- f.gcs.write = 0;
|
|
|
- f.gcs.seek = 0;
|
|
|
- f.gcs.close = 0;
|
|
|
+ f.gcs.read = _cs_read;
|
|
|
+ f.gcs.write = _cs_write;
|
|
|
+ f.gcs.seek = 0;
|
|
|
+ f.gcs.close = _cs_close;
|
|
|
#endif
|
|
|
- f.filedes = -2;
|
|
|
+ f.filedes = filedes;
|
|
|
f.modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
|
|
|
|
|
|
#ifdef __STDIO_MBSTATE
|
|
@@ -1437,136 +1249,8 @@ int vsnprintf(char *__restrict buf, size_t size,
|
|
|
#endif
|
|
|
|
|
|
rv = vfprintf(&f, format, arg);
|
|
|
- if (size) {
|
|
|
- if (f.bufpos == f.bufend) {
|
|
|
- --f.bufpos;
|
|
|
- }
|
|
|
- *f.bufpos = 0;
|
|
|
- }
|
|
|
- return rv;
|
|
|
-}
|
|
|
-#else
|
|
|
-#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
|
|
|
-
|
|
|
-typedef struct {
|
|
|
- size_t pos;
|
|
|
- size_t len;
|
|
|
- unsigned char *buf;
|
|
|
- FILE *fp;
|
|
|
-} __snpf_cookie;
|
|
|
-
|
|
|
-#define COOKIE ((__snpf_cookie *) cookie)
|
|
|
-
|
|
|
-static ssize_t snpf_write(register void *cookie, const char *buf,
|
|
|
- size_t bufsize)
|
|
|
-{
|
|
|
- size_t count;
|
|
|
- register char *p;
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- if (COOKIE->len > COOKIE->pos) {
|
|
|
- count = COOKIE->len - COOKIE->pos - 1;
|
|
|
- if (count > bufsize) {
|
|
|
- count = bufsize;
|
|
|
- }
|
|
|
-
|
|
|
- p = COOKIE->buf + COOKIE->pos;
|
|
|
- while (count) {
|
|
|
- *p++ = *buf++;
|
|
|
- --count;
|
|
|
- }
|
|
|
- *p = 0;
|
|
|
- }
|
|
|
-
|
|
|
- COOKIE->pos += bufsize;
|
|
|
-
|
|
|
- return bufsize;
|
|
|
-}
|
|
|
-
|
|
|
-#undef COOKIE
|
|
|
-
|
|
|
-int vsnprintf(char *__restrict buf, size_t size,
|
|
|
- const char * __restrict format, va_list arg)
|
|
|
-{
|
|
|
- FILE f;
|
|
|
- __snpf_cookie cookie;
|
|
|
- int rv;
|
|
|
-
|
|
|
- cookie.buf = buf;
|
|
|
- cookie.len = size;
|
|
|
- cookie.pos = 0;
|
|
|
- cookie.fp = &f;
|
|
|
-
|
|
|
- f.cookie = &cookie;
|
|
|
- f.gcs.write = snpf_write;
|
|
|
- f.gcs.read = NULL;
|
|
|
- f.gcs.seek = NULL;
|
|
|
- f.gcs.close = NULL;
|
|
|
-
|
|
|
- f.filedes = -1;
|
|
|
- f.modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
|
|
|
-
|
|
|
-#ifdef __STDIO_MBSTATE
|
|
|
- __INIT_MBSTATE(&(f.state));
|
|
|
-#endif
|
|
|
-
|
|
|
-#ifdef __STDIO_THREADSAFE
|
|
|
- f.user_locking = 0;
|
|
|
- __stdio_init_mutex(&f.lock);
|
|
|
-#endif
|
|
|
-
|
|
|
- rv = vfprintf(&f, format, arg);
|
|
|
-
|
|
|
- return rv;
|
|
|
-}
|
|
|
-
|
|
|
-#else
|
|
|
-#warning skipping vsnprintf since no buffering and no custom streams!
|
|
|
-#endif
|
|
|
-#endif
|
|
|
-#endif
|
|
|
-
|
|
|
-#ifdef L_vdprintf
|
|
|
-
|
|
|
-int vdprintf(int filedes, const char * __restrict format, va_list arg)
|
|
|
-{
|
|
|
- FILE f;
|
|
|
- int rv;
|
|
|
-#ifdef __STDIO_BUFFERS
|
|
|
- char buf[64];
|
|
|
-
|
|
|
-#ifdef __STDIO_GETC_MACRO
|
|
|
- f.bufgetc =
|
|
|
-#endif
|
|
|
- f.bufpos = f.bufread = f.bufstart = buf;
|
|
|
-#ifdef __STDIO_PUTC_MACRO
|
|
|
- f.bufputc =
|
|
|
-#endif
|
|
|
- f.bufend = buf + sizeof(buf);
|
|
|
-#endif
|
|
|
-#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
|
|
|
- f.cookie = &(f.filedes);
|
|
|
- f.gcs.read = _cs_read;
|
|
|
- f.gcs.write = _cs_write;
|
|
|
- f.gcs.seek = 0;
|
|
|
- f.gcs.close = _cs_close;
|
|
|
-#endif
|
|
|
- f.filedes = filedes;
|
|
|
- f.modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
|
|
|
-
|
|
|
-#ifdef __STDIO_MBSTATE
|
|
|
- __INIT_MBSTATE(&(f.state));
|
|
|
-#endif
|
|
|
-
|
|
|
-#ifdef __STDIO_THREADSAFE
|
|
|
- f.user_locking = 0;
|
|
|
- __stdio_init_mutex(&f.lock);
|
|
|
-#endif
|
|
|
-
|
|
|
- rv = vfprintf(&f, format, arg);
|
|
|
-
|
|
|
- return fflush(&f) ? -1 : rv;
|
|
|
+
|
|
|
+ return fflush(&f) ? -1 : rv;
|
|
|
}
|
|
|
|
|
|
#endif
|
|
@@ -1751,6 +1435,124 @@ int sprintf(char *__restrict buf, const char * __restrict format, ...)
|
|
|
#endif
|
|
|
#endif
|
|
|
|
|
|
+#ifdef L_vswprintf
|
|
|
+
|
|
|
+#ifdef __STDIO_BUFFERS
|
|
|
+int vswprintf(wchar_t *__restrict buf, size_t size,
|
|
|
+ const wchar_t * __restrict format, va_list arg)
|
|
|
+{
|
|
|
+ FILE f;
|
|
|
+ int rv;
|
|
|
+
|
|
|
+#ifdef __STDIO_GETC_MACRO
|
|
|
+ f.bufgetc =
|
|
|
+#endif
|
|
|
+ f.bufpos = f.bufread = f.bufstart = (char *) buf;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+#ifdef __STDIO_PUTC_MACRO
|
|
|
+ f.bufputc =
|
|
|
+#endif
|
|
|
+ f.bufend = (char *)(buf + size);
|
|
|
+
|
|
|
+#if 0
|
|
|
+
|
|
|
+ f.cookie = &(f.filedes);
|
|
|
+ f.gcs.read = 0;
|
|
|
+ f.gcs.write = 0;
|
|
|
+ f.gcs.seek = 0;
|
|
|
+ f.gcs.close = 0;
|
|
|
+#endif
|
|
|
+ f.filedes = -3;
|
|
|
+ f.modeflags = (__FLAG_WIDE|__FLAG_WRITEONLY|__FLAG_WRITING);
|
|
|
+
|
|
|
+#ifdef __STDIO_MBSTATE
|
|
|
+ __INIT_MBSTATE(&(f.state));
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef __STDIO_THREADSAFE
|
|
|
+ f.user_locking = 0;
|
|
|
+ __stdio_init_mutex(&f.lock);
|
|
|
+#endif
|
|
|
+
|
|
|
+ rv = vfwprintf(&f, format, arg);
|
|
|
+
|
|
|
+
|
|
|
+ if (f.bufpos == f.bufend) {
|
|
|
+ rv = -1;
|
|
|
+ if (size) {
|
|
|
+ f.bufpos = (char *)(((wchar_t *) f.bufpos) - 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (size) {
|
|
|
+ *((wchar_t *) f.bufpos) = 0;
|
|
|
+ }
|
|
|
+ return rv;
|
|
|
+}
|
|
|
+#else
|
|
|
+#warning skipping vswprintf since no buffering!
|
|
|
+#endif
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef L_swprintf
|
|
|
+#ifdef __STDIO_BUFFERS
|
|
|
+
|
|
|
+int swprintf(wchar_t *__restrict buf, size_t size,
|
|
|
+ const wchar_t * __restrict format, ...)
|
|
|
+{
|
|
|
+ va_list arg;
|
|
|
+ int rv;
|
|
|
+
|
|
|
+ va_start(arg, format);
|
|
|
+ rv = vswprintf(buf, size, format, arg);
|
|
|
+ va_end(arg);
|
|
|
+ return rv;
|
|
|
+}
|
|
|
+
|
|
|
+#else
|
|
|
+#warning skipping vsWprintf since no buffering!
|
|
|
+#endif
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef L_fwprintf
|
|
|
+
|
|
|
+int fwprintf(FILE * __restrict stream, const wchar_t * __restrict format, ...)
|
|
|
+{
|
|
|
+ va_list arg;
|
|
|
+ int rv;
|
|
|
+
|
|
|
+ va_start(arg, format);
|
|
|
+ rv = vfwprintf(stream, format, arg);
|
|
|
+ va_end(arg);
|
|
|
+
|
|
|
+ return rv;
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef L_vwprintf
|
|
|
+int vwprintf(const wchar_t * __restrict format, va_list arg)
|
|
|
+{
|
|
|
+ return vfwprintf(stdout, format, arg);
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef L_wprintf
|
|
|
+int wprintf(const wchar_t * __restrict format, ...)
|
|
|
+{
|
|
|
+ va_list arg;
|
|
|
+ int rv;
|
|
|
+
|
|
|
+ va_start(arg, format);
|
|
|
+ rv = vfwprintf(stdout, format, arg);
|
|
|
+ va_end(arg);
|
|
|
+
|
|
|
+ return rv;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
#ifdef L__dtostr
|
|
|
|
|
|
* Copyright (C) 2000, 2001 Manuel Novoa III
|
|
@@ -2298,3 +2100,581 @@ extern uintmax_t _load_inttype(int desttype, register const void *src,
|
|
|
|
|
|
#endif
|
|
|
|
|
|
+#if defined(L_vfprintf) || defined(L_vfwprintf)
|
|
|
+
|
|
|
+
|
|
|
+ * precision and width settings in *printf (wide) format strings.
|
|
|
+ * In other words, we don't currently support glibc's 'I' flag.
|
|
|
+ * We do accept it, but it is currently ignored. */
|
|
|
+
|
|
|
+
|
|
|
+#ifdef L_vfprintf
|
|
|
+
|
|
|
+#define VFPRINTF vfprintf
|
|
|
+#define FMT_TYPE char
|
|
|
+#define OUTNSTR _outnstr
|
|
|
+#define STRLEN strlen
|
|
|
+#define _PPFS_init _ppfs_init
|
|
|
+#define OUTPUT(F,S) fputs(S,F)
|
|
|
+#define _outnstr(stream, string, len) _stdio_fwrite(string, len, stream)
|
|
|
+
|
|
|
+#else
|
|
|
+
|
|
|
+#define VFPRINTF vfwprintf
|
|
|
+#define FMT_TYPE wchar_t
|
|
|
+#define OUTNSTR _outnwcs
|
|
|
+#define STRLEN wcslen
|
|
|
+#define _PPFS_init _ppwfs_init
|
|
|
+#define OUTPUT(F,S) fputws(S,F)
|
|
|
+#define _outnwcs(stream, wstring, len) _wstdio_fwrite(wstring, len, stream)
|
|
|
+
|
|
|
+static void _outnstr(FILE *stream, const char *s, size_t wclen)
|
|
|
+{
|
|
|
+
|
|
|
+ wchar_t wbuf[64];
|
|
|
+ mbstate_t mbstate;
|
|
|
+ size_t todo, r;
|
|
|
+
|
|
|
+ mbstate.mask = 0;
|
|
|
+ todo = wclen;
|
|
|
+
|
|
|
+ while (todo) {
|
|
|
+ r = mbsrtowcs(wbuf, &s, sizeof(wbuf)/sizeof(wbuf[0]), &mbstate);
|
|
|
+ assert(((ssize_t)r) > 0);
|
|
|
+ _outnwcs(stream, wbuf, r);
|
|
|
+ todo -= r;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int _ppwfs_init(register ppfs_t *ppfs, const wchar_t *fmt0)
|
|
|
+{
|
|
|
+ static const wchar_t invalid_wcs[] = L"Invalid wide format string.";
|
|
|
+ int r;
|
|
|
+
|
|
|
+
|
|
|
+ memset(ppfs, 0, sizeof(ppfs_t));
|
|
|
+ --ppfs->maxposarg;
|
|
|
+ ppfs->fmtpos = (const char *) fmt0;
|
|
|
+ ppfs->info._flags = FLAG_WIDESTREAM;
|
|
|
+
|
|
|
+ {
|
|
|
+ mbstate_t mbstate;
|
|
|
+ const wchar_t *p;
|
|
|
+ mbstate.mask = 0;
|
|
|
+ p = fmt0;
|
|
|
+ if (wcsrtombs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) {
|
|
|
+ ppfs->fmtpos = (const char *) invalid_wcs;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ {
|
|
|
+#if 1
|
|
|
+
|
|
|
+ register int *p = ppfs->argtype;
|
|
|
+
|
|
|
+ r = MAX_ARGS;
|
|
|
+ do {
|
|
|
+ *p++ = __PA_NOARG;
|
|
|
+ } while (--r);
|
|
|
+#else
|
|
|
+
|
|
|
+ register char *p = (char *) ((MAX_ARGS-1) * sizeof(int));
|
|
|
+
|
|
|
+ do {
|
|
|
+ *((int *)(((char *)ppfs) + ((int)p) + offsetof(ppfs_t,argtype))) = __PA_NOARG;
|
|
|
+ p -= sizeof(int);
|
|
|
+ } while (p);
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * Run through the entire format string to validate it and initialize
|
|
|
+ * the positional arg numbers (if any).
|
|
|
+ */
|
|
|
+ {
|
|
|
+ register const wchar_t *fmt = fmt0;
|
|
|
+
|
|
|
+ while (*fmt) {
|
|
|
+ if ((*fmt == '%') && (*++fmt != '%')) {
|
|
|
+ ppfs->fmtpos = (const char *) fmt;
|
|
|
+ if ((r = _ppfs_parsespec(ppfs)) < 0) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ fmt = (const wchar_t *) ppfs->fmtpos;
|
|
|
+ } else {
|
|
|
+ ++fmt;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ppfs->fmtpos = (const char *) fmt0;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ {
|
|
|
+ register int *p = ppfs->argtype;
|
|
|
+ r = ppfs->maxposarg;
|
|
|
+ while (--r >= 0) {
|
|
|
+ if ( *p == __PA_NOARG ) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ ++p;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+static void _charpad(FILE * __restrict stream, int padchar, size_t numpad)
|
|
|
+{
|
|
|
+
|
|
|
+ FMT_TYPE pad[1];
|
|
|
+
|
|
|
+ *pad = padchar;
|
|
|
+ while (numpad) {
|
|
|
+ OUTNSTR(stream, pad, 1);
|
|
|
+ --numpad;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int _do_one_spec(FILE * __restrict stream,
|
|
|
+ register ppfs_t *ppfs, int *count)
|
|
|
+{
|
|
|
+ static const char spec_base[] = SPEC_BASE;
|
|
|
+#ifdef L_vfprintf
|
|
|
+ static const char prefix[] = "+\0-\0 \0000x\0000X";
|
|
|
+
|
|
|
+#else
|
|
|
+ static const wchar_t prefix[] = L"+\0-\0 \0000x\0000X";
|
|
|
+#endif
|
|
|
+ enum {
|
|
|
+ PREFIX_PLUS = 0,
|
|
|
+ PREFIX_MINUS = 2,
|
|
|
+ PREFIX_SPACE = 4,
|
|
|
+ PREFIX_LWR_X = 6,
|
|
|
+ PREFIX_UPR_X = 9,
|
|
|
+ PREFIX_NONE = 11
|
|
|
+ };
|
|
|
+
|
|
|
+#ifdef __va_arg_ptr
|
|
|
+ const void * const *argptr;
|
|
|
+#else
|
|
|
+ const void * argptr[MAX_ARGS_PER_SPEC];
|
|
|
+#endif
|
|
|
+ int *argtype;
|
|
|
+#ifdef __UCLIBC_HAS_WCHAR__
|
|
|
+ const wchar_t *ws = NULL;
|
|
|
+ mbstate_t mbstate;
|
|
|
+#endif
|
|
|
+ size_t slen;
|
|
|
+#ifdef L_vfprintf
|
|
|
+#define SLEN slen
|
|
|
+#else
|
|
|
+ size_t SLEN;
|
|
|
+ wchar_t wbuf[2];
|
|
|
+#endif
|
|
|
+ int base;
|
|
|
+ int numpad;
|
|
|
+ int alphacase;
|
|
|
+ int numfill = 0;
|
|
|
+ int prefix_num = PREFIX_NONE;
|
|
|
+ char padchar = ' ';
|
|
|
+#ifdef __UCLIBC_MJN3_ONLY__
|
|
|
+#warning REMINDER: buf size
|
|
|
+#endif
|
|
|
+
|
|
|
+ * and also for any locale-grouped long long integer strings generated.
|
|
|
+ * This should be large enough for any of the current archs/locales, but
|
|
|
+ * eventually this should be handled robustly. */
|
|
|
+ char buf[128];
|
|
|
+
|
|
|
+#ifdef NDEBUG
|
|
|
+ _ppfs_parsespec(ppfs);
|
|
|
+#else
|
|
|
+ if (_ppfs_parsespec(ppfs) < 0) {
|
|
|
+ abort();
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ _ppfs_setargs(ppfs);
|
|
|
+
|
|
|
+ argtype = ppfs->argtype + ppfs->argnumber[2] - 1;
|
|
|
+
|
|
|
+#ifdef __va_arg_ptr
|
|
|
+ argptr = (const void * const *) ppfs->argptr;
|
|
|
+ if (ppfs->maxposarg > 0) {
|
|
|
+ argptr += ppfs->argnumber[2] - 1;
|
|
|
+ }
|
|
|
+#else
|
|
|
+
|
|
|
+ {
|
|
|
+ register argvalue_t *p = ppfs->argvalue;
|
|
|
+ int i;
|
|
|
+ if (ppfs->maxposarg > 0) {
|
|
|
+ p += ppfs->argnumber[2] - 1;
|
|
|
+ }
|
|
|
+ for (i = 0 ; i < ppfs->num_data_args ; i++ ) {
|
|
|
+ argptr[i] = (void *) p++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ {
|
|
|
+ register char *s;
|
|
|
+
|
|
|
+ if (ppfs->conv_num == CONV_n) {
|
|
|
+ _store_inttype(*(void **)*argptr,
|
|
|
+ ppfs->info._flags & __PA_INTMASK,
|
|
|
+ (intmax_t) (*count));
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ if (ppfs->conv_num <= CONV_i) {
|
|
|
+ alphacase = __UIM_LOWER;
|
|
|
+ if (((base = spec_base[(int)(ppfs->conv_num - CONV_p)]) == 10)
|
|
|
+ && (PRINT_INFO_FLAG_VAL(&(ppfs->info),group))
|
|
|
+ ) {
|
|
|
+ alphacase = __UIM_GROUP;
|
|
|
+ }
|
|
|
+ if (ppfs->conv_num <= CONV_u) {
|
|
|
+ if (ppfs->conv_num == CONV_X) {
|
|
|
+ alphacase = __UIM_UPPER;
|
|
|
+ }
|
|
|
+ if (ppfs->conv_num == CONV_p) {
|
|
|
+ prefix_num = PREFIX_LWR_X;
|
|
|
+ } else {
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ base = -base;
|
|
|
+ }
|
|
|
+ if (ppfs->info.prec < 0) {
|
|
|
+ padchar = ppfs->info.pad;
|
|
|
+ }
|
|
|
+ s = _uintmaxtostr(buf + sizeof(buf) - 1,
|
|
|
+ (uintmax_t)
|
|
|
+ _load_inttype(*argtype & __PA_INTMASK,
|
|
|
+ *argptr, base), base, alphacase);
|
|
|
+ if (ppfs->conv_num > CONV_u) {
|
|
|
+ if (*s == '-') {
|
|
|
+ PRINT_INFO_SET_FLAG(&(ppfs->info),showsign);
|
|
|
+ ++s;
|
|
|
+ prefix_num = PREFIX_MINUS;
|
|
|
+ } else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),showsign)) {
|
|
|
+ prefix_num = PREFIX_PLUS;
|
|
|
+ } else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),space)) {
|
|
|
+ prefix_num = PREFIX_SPACE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ slen = (char *)(buf + sizeof(buf) - 1) - s;
|
|
|
+#ifdef L_vfwprintf
|
|
|
+ {
|
|
|
+ const char *q = s;
|
|
|
+ mbstate.mask = 0;
|
|
|
+ SLEN = mbsrtowcs(NULL, &q, 0, &mbstate);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ numfill = ((ppfs->info.prec < 0) ? 1 : ppfs->info.prec);
|
|
|
+ if (PRINT_INFO_FLAG_VAL(&(ppfs->info),alt)) {
|
|
|
+ if (ppfs->conv_num <= CONV_x) {
|
|
|
+ prefix_num = PREFIX_LWR_X;
|
|
|
+ }
|
|
|
+ if (ppfs->conv_num == CONV_X) {
|
|
|
+ prefix_num = PREFIX_UPR_X;
|
|
|
+ }
|
|
|
+ if ((ppfs->conv_num == CONV_o) && (numfill <= SLEN)) {
|
|
|
+ numfill = ((*s == '0') ? 1 : SLEN + 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (*s == '0') {
|
|
|
+ if (prefix_num >= PREFIX_LWR_X) {
|
|
|
+ prefix_num = PREFIX_NONE;
|
|
|
+ }
|
|
|
+ if (ppfs->conv_num == CONV_p) {
|
|
|
+ s = "(nil)";
|
|
|
+#ifdef L_vfwprintf
|
|
|
+ SLEN =
|
|
|
+#endif
|
|
|
+ slen = 5;
|
|
|
+ numfill = 0;
|
|
|
+ } else if (numfill == 0) {
|
|
|
+#ifdef L_vfwprintf
|
|
|
+ SLEN =
|
|
|
+#endif
|
|
|
+ slen = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ numfill = ((numfill > SLEN) ? numfill - SLEN : 0);
|
|
|
+ } else if (ppfs->conv_num <= CONV_A) {
|
|
|
+#ifdef L_vfwprintf
|
|
|
+#ifdef __UCLIBC_MJN3_ONLY__
|
|
|
+#warning fix dtostr
|
|
|
+#endif
|
|
|
+ return -1;
|
|
|
+#else
|
|
|
+#ifdef __STDIO_PRINTF_FLOAT
|
|
|
+ *count += _dtostr(stream,
|
|
|
+ (PRINT_INFO_FLAG_VAL(&(ppfs->info),is_long_double)
|
|
|
+ ? *(long double *) *argptr
|
|
|
+ : (long double) (* (double *) *argptr)),
|
|
|
+ &ppfs->info);
|
|
|
+ return 0;
|
|
|
+#else
|
|
|
+ return -1;
|
|
|
+#endif
|
|
|
+#endif
|
|
|
+ } else if (ppfs->conv_num <= CONV_S) {
|
|
|
+#ifdef L_vfprintf
|
|
|
+
|
|
|
+#ifdef __UCLIBC_HAS_WCHAR__
|
|
|
+ mbstate.mask = 0;
|
|
|
+ if (ppfs->conv_num == CONV_S) {
|
|
|
+ if (!(ws = *((const wchar_t **) *argptr))) {
|
|
|
+ goto NULL_STRING;
|
|
|
+ }
|
|
|
+
|
|
|
+ * (char*) &ws as the conversion destination. This signals
|
|
|
+ * uClibc's wcsrtombs that we want a "restricted" length
|
|
|
+ * such that the mbs fits in a buffer of the specified
|
|
|
+ * size with no partial conversions. */
|
|
|
+ if ((slen = wcsrtombs((char *) &ws, &ws,
|
|
|
+ ((ppfs->info.prec >= 0)
|
|
|
+ ? ppfs->info.prec
|
|
|
+ : SIZE_MAX), &mbstate))
|
|
|
+ == ((size_t)-1)
|
|
|
+ ) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ s = buf;
|
|
|
+ slen = wcrtomb(s, (*((const wchar_t *) *argptr)), &mbstate);
|
|
|
+ if (slen == ((size_t)-1)) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ s[slen] = 0;
|
|
|
+ }
|
|
|
+#else
|
|
|
+ return -1;
|
|
|
+#endif
|
|
|
+ } else if (ppfs->conv_num <= CONV_s) {
|
|
|
+ if (ppfs->conv_num == CONV_s) {
|
|
|
+ s = *((char **) (*argptr));
|
|
|
+ if (s) {
|
|
|
+ SET_STRING_LEN:
|
|
|
+ slen = strnlen(s, ((ppfs->info.prec >= 0)
|
|
|
+ ? ppfs->info.prec : SIZE_MAX));
|
|
|
+ } else {
|
|
|
+#ifdef __UCLIBC_HAS_WCHAR__
|
|
|
+ NULL_STRING:
|
|
|
+#endif
|
|
|
+ s = "(null)";
|
|
|
+ slen = 6;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ s = buf;
|
|
|
+ *s = (unsigned char)(*((const int *) *argptr));
|
|
|
+ s[1] = 0;
|
|
|
+ slen = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+#else
|
|
|
+
|
|
|
+ if (ppfs->conv_num == CONV_S) {
|
|
|
+ ws = *((wchar_t **) (*argptr));
|
|
|
+ if (!ws) {
|
|
|
+ goto NULL_STRING;
|
|
|
+ }
|
|
|
+ SLEN = wcsnlen(ws, ((ppfs->info.prec >= 0)
|
|
|
+ ? ppfs->info.prec : SIZE_MAX));
|
|
|
+ } else {
|
|
|
+ *wbuf = (wchar_t)(*((const wint_t *) *argptr));
|
|
|
+ CHAR_CASE:
|
|
|
+ ws = wbuf;
|
|
|
+ wbuf[1] = 0;
|
|
|
+ SLEN = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ } else if (ppfs->conv_num <= CONV_s) {
|
|
|
+
|
|
|
+ if (ppfs->conv_num == CONV_s) {
|
|
|
+#ifdef __UCLIBC_MJN3_ONLY__
|
|
|
+#warning Fix %s for vfwprintf... output upto illegal sequence?
|
|
|
+#endif
|
|
|
+ s = *((char **) (*argptr));
|
|
|
+ if (s) {
|
|
|
+ SET_STRING_LEN:
|
|
|
+
|
|
|
+ * (wchar_t*) &mbstate as the conversion destination.
|
|
|
+ * This signals uClibc's mbsrtowcs that we want a
|
|
|
+ * "restricted" length such that the mbs fits in a buffer
|
|
|
+ * of the specified size with no partial conversions. */
|
|
|
+ {
|
|
|
+ const char *q = s;
|
|
|
+ mbstate.mask = 0;
|
|
|
+ SLEN = mbsrtowcs((wchar_t *) &mbstate, &q,
|
|
|
+ ((ppfs->info.prec >= 0)
|
|
|
+ ? ppfs->info.prec : SIZE_MAX),
|
|
|
+ &mbstate);
|
|
|
+ }
|
|
|
+ if (SLEN == ((size_t)(-1))) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ NULL_STRING:
|
|
|
+ s = "(null)";
|
|
|
+ SLEN = slen = 6;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ *wbuf = btowc( (unsigned char)(*((const int *) *argptr)) );
|
|
|
+ goto CHAR_CASE;
|
|
|
+ }
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef __STDIO_PRINTF_M_SUPPORT
|
|
|
+ } else if (ppfs->conv_num == CONV_m) {
|
|
|
+ s = _glibc_strerror_r(errno, buf, sizeof(buf));
|
|
|
+ goto SET_STRING_LEN;
|
|
|
+#endif
|
|
|
+ } else {
|
|
|
+ assert(ppfs->conv_num == CONV_custom0);
|
|
|
+
|
|
|
+ s = _custom_printf_spec;
|
|
|
+ do {
|
|
|
+ if (*s == ppfs->info.spec) {
|
|
|
+ int rv;
|
|
|
+
|
|
|
+ rv = (*_custom_printf_handler
|
|
|
+ [(int)(s-_custom_printf_spec)])
|
|
|
+ (stream, &ppfs->info, argptr);
|
|
|
+ if (rv < 0) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ *count += rv;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ } while (++s < (_custom_printf_spec + MAX_USER_SPEC));
|
|
|
+ assert(0);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ {
|
|
|
+ size_t t;
|
|
|
+
|
|
|
+ t = SLEN + numfill;
|
|
|
+ if (prefix_num != PREFIX_NONE) {
|
|
|
+ t += ((prefix_num < PREFIX_LWR_X) ? 1 : 2);
|
|
|
+ }
|
|
|
+ numpad = ((ppfs->info.width > t) ? (ppfs->info.width - t) : 0);
|
|
|
+ *count += t + numpad;
|
|
|
+ }
|
|
|
+ if (padchar == '0') {
|
|
|
+ numfill += numpad;
|
|
|
+ numpad = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (!PRINT_INFO_FLAG_VAL(&(ppfs->info),left)) {
|
|
|
+ _charpad(stream, ' ', numpad);
|
|
|
+ numpad = 0;
|
|
|
+ }
|
|
|
+ OUTPUT(stream, prefix + prefix_num);
|
|
|
+ _charpad(stream, '0', numfill);
|
|
|
+
|
|
|
+#ifdef L_vfprintf
|
|
|
+
|
|
|
+#ifdef __UCLIBC_HAS_WCHAR__
|
|
|
+ if (!ws) {
|
|
|
+ _outnstr(stream, s, slen);
|
|
|
+ } else {
|
|
|
+ size_t t;
|
|
|
+ mbstate.mask = 0;
|
|
|
+ while (slen) {
|
|
|
+ t = (slen <= sizeof(buf)) ? slen : sizeof(buf);
|
|
|
+ t = wcsrtombs(buf, &ws, t, &mbstate);
|
|
|
+ assert (t != ((size_t)(-1)));
|
|
|
+ _outnstr(stream, buf, t);
|
|
|
+ slen -= t;
|
|
|
+ }
|
|
|
+ ws = NULL;
|
|
|
+ }
|
|
|
+#else
|
|
|
+ _outnstr(stream, s, slen);
|
|
|
+#endif
|
|
|
+
|
|
|
+#else
|
|
|
+
|
|
|
+ if (!ws) {
|
|
|
+ _outnstr(stream, s, SLEN);
|
|
|
+ } else {
|
|
|
+ _outnwcs(stream, ws, SLEN);
|
|
|
+ ws = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+#endif
|
|
|
+ _charpad(stream, ' ', numpad);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int VFPRINTF (FILE * __restrict stream,
|
|
|
+ register const FMT_TYPE * __restrict format,
|
|
|
+ va_list arg)
|
|
|
+{
|
|
|
+ ppfs_t ppfs;
|
|
|
+ int count, r;
|
|
|
+ register const FMT_TYPE *s;
|
|
|
+
|
|
|
+ __STDIO_THREADLOCK(stream);
|
|
|
+
|
|
|
+ count = 0;
|
|
|
+ s = format;
|
|
|
+
|
|
|
+ if (_PPFS_init(&ppfs, format) < 0) {
|
|
|
+ OUTNSTR(stream, (const FMT_TYPE *) ppfs.fmtpos,
|
|
|
+ STRLEN((const FMT_TYPE *)(ppfs.fmtpos)));
|
|
|
+ count = -1;
|
|
|
+ } else {
|
|
|
+ _ppfs_prepargs(&ppfs, arg);
|
|
|
+
|
|
|
+ do {
|
|
|
+ while (*format && (*format != '%')) {
|
|
|
+ ++format;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (format-s) {
|
|
|
+ if ( (r = OUTNSTR(stream, s, format-s)) < 0) {
|
|
|
+ count = -1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ count += r;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!*format) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (format[1] != '%') {
|
|
|
+
|
|
|
+ ppfs.fmtpos = (const char *)(++format);
|
|
|
+
|
|
|
+ if ( (r = _do_one_spec(stream, &ppfs, &count)) < 0) {
|
|
|
+ count = -1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ s = format = (const FMT_TYPE *) ppfs.fmtpos;
|
|
|
+ } else {
|
|
|
+ s = ++format;
|
|
|
+ ++format;
|
|
|
+ }
|
|
|
+ } while (1);
|
|
|
+
|
|
|
+ va_end(ppfs.arg);
|
|
|
+ }
|
|
|
+
|
|
|
+ __STDIO_THREADUNLOCK(stream);
|
|
|
+
|
|
|
+ return count;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|