| 1 |
1325 |
phoenix |
/* Copyright (C) 2002, 2003 Manuel Novoa III
|
| 2 |
|
|
* My stdio library for linux and (soon) elks.
|
| 3 |
|
|
*
|
| 4 |
|
|
* This library is free software; you can redistribute it and/or
|
| 5 |
|
|
* modify it under the terms of the GNU Library General Public
|
| 6 |
|
|
* License as published by the Free Software Foundation; either
|
| 7 |
|
|
* version 2 of the License, or (at your option) any later version.
|
| 8 |
|
|
*
|
| 9 |
|
|
* This library is distributed in the hope that it will be useful,
|
| 10 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 11 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 12 |
|
|
* Library General Public License for more details.
|
| 13 |
|
|
*
|
| 14 |
|
|
* You should have received a copy of the GNU Library General Public
|
| 15 |
|
|
* License along with this library; if not, write to the Free
|
| 16 |
|
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
| 17 |
|
|
*/
|
| 18 |
|
|
|
| 19 |
|
|
/* This code needs a lot of clean up. Some of that is on hold until uClibc
|
| 20 |
|
|
* gets a better configuration system (on Erik's todo list).
|
| 21 |
|
|
* The other cleanup will take place during the implementation/integration of
|
| 22 |
|
|
* the wide char (un)formatted i/o functions which I'm currently working on.
|
| 23 |
|
|
*/
|
| 24 |
|
|
|
| 25 |
|
|
/* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION!
|
| 26 |
|
|
*
|
| 27 |
|
|
* This code is currently under development. Also, I plan to port
|
| 28 |
|
|
* it to elks which is a 16-bit environment with a fairly limited
|
| 29 |
|
|
* compiler. Therefore, please refrain from modifying this code
|
| 30 |
|
|
* and, instead, pass any bug-fixes, etc. to me. Thanks. Manuel
|
| 31 |
|
|
*
|
| 32 |
|
|
* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! */
|
| 33 |
|
|
|
| 34 |
|
|
|
| 35 |
|
|
/* April 1, 2002
|
| 36 |
|
|
* Initialize thread locks for fake files in vsnprintf and vdprintf.
|
| 37 |
|
|
* reported by Erik Andersen (andersen@codepoet.com)
|
| 38 |
|
|
* Fix an arg promotion handling bug in _do_one_spec for %c.
|
| 39 |
|
|
* reported by Ilguiz Latypov <ilatypov@superbt.com>
|
| 40 |
|
|
*
|
| 41 |
|
|
* May 10, 2002
|
| 42 |
|
|
* Remove __isdigit and use new ctype.h version.
|
| 43 |
|
|
* Add conditional setting of QUAL_CHARS for size_t and ptrdiff_t.
|
| 44 |
|
|
*
|
| 45 |
|
|
* Aug 16, 2002
|
| 46 |
|
|
* Fix two problems that showed up with the python 2.2.1 tests; one
|
| 47 |
|
|
* involving %o and one involving %f.
|
| 48 |
|
|
*
|
| 49 |
|
|
* Oct 28, 2002
|
| 50 |
|
|
* Fix a problem in vasprintf (reported by vodz a while back) when built
|
| 51 |
|
|
* without custom stream support. In that case, it is necessary to do
|
| 52 |
|
|
* a va_copy.
|
| 53 |
|
|
* Make sure each va_copy has a matching va_end, as required by C99.
|
| 54 |
|
|
*
|
| 55 |
|
|
* Nov 4, 2002
|
| 56 |
|
|
* Add locale-specific grouping support for integer decimal conversion.
|
| 57 |
|
|
* Add locale-specific decimal point support for floating point conversion.
|
| 58 |
|
|
* Note: grouping will have to wait for _dtostr() rewrite.
|
| 59 |
|
|
* Add printf wchar support for %lc (%C) and %ls (%S).
|
| 60 |
|
|
* Require printf format strings to be valid multibyte strings beginning and
|
| 61 |
|
|
* ending in their initial shift state, as per the stds.
|
| 62 |
|
|
*
|
| 63 |
|
|
* Nov 21, 2002
|
| 64 |
|
|
* Add *wprintf functions. Currently they don't support floating point
|
| 65 |
|
|
* conversions. That will wait until the rewrite of _dtostr.
|
| 66 |
|
|
*
|
| 67 |
|
|
* Aug 1, 2003
|
| 68 |
|
|
* Optional hexadecimal float notation support for %a/%A.
|
| 69 |
|
|
* Floating point output now works for *wprintf.
|
| 70 |
|
|
* Support for glibc locale-specific digit grouping for floats.
|
| 71 |
|
|
* Misc bug fixes.
|
| 72 |
|
|
*
|
| 73 |
|
|
* Aug 31, 2003
|
| 74 |
|
|
* Fix precision bug for %g conversion specifier when using %f style.
|
| 75 |
|
|
*
|
| 76 |
|
|
* Sep 5, 2003
|
| 77 |
|
|
* Implement *s*scanf for the non-buffered stdio case with old_vfprintf.
|
| 78 |
|
|
*
|
| 79 |
|
|
* Sep 23, 2003
|
| 80 |
|
|
* vfprintf was not always checking for narrow stream orientation.
|
| 81 |
|
|
*/
|
| 82 |
|
|
|
| 83 |
|
|
/* TODO:
|
| 84 |
|
|
*
|
| 85 |
|
|
* Should we validate that *printf format strings are valid multibyte
|
| 86 |
|
|
* strings in the current locale? ANSI/ISO C99 seems to imply this
|
| 87 |
|
|
* and Plauger's printf implementation in his Standard C Library book
|
| 88 |
|
|
* treats this as an error.
|
| 89 |
|
|
*/
|
| 90 |
|
|
|
| 91 |
|
|
|
| 92 |
|
|
#define _ISOC99_SOURCE /* for ULLONG primarily... */
|
| 93 |
|
|
#define _GNU_SOURCE
|
| 94 |
|
|
#define _STDIO_UTILITY /* We're using _uintmaxtostr. */
|
| 95 |
|
|
#include <stdio.h>
|
| 96 |
|
|
#include <stdlib.h>
|
| 97 |
|
|
#include <string.h>
|
| 98 |
|
|
#include <stddef.h>
|
| 99 |
|
|
#include <ctype.h>
|
| 100 |
|
|
#include <limits.h>
|
| 101 |
|
|
#include <stdarg.h>
|
| 102 |
|
|
#include <assert.h>
|
| 103 |
|
|
#include <stdint.h>
|
| 104 |
|
|
#include <errno.h>
|
| 105 |
|
|
#include <locale.h>
|
| 106 |
|
|
|
| 107 |
|
|
#define __PRINTF_INFO_NO_BITFIELD
|
| 108 |
|
|
#include <printf.h>
|
| 109 |
|
|
|
| 110 |
|
|
#ifdef __STDIO_THREADSAFE
|
| 111 |
|
|
#include <stdio_ext.h>
|
| 112 |
|
|
#include <pthread.h>
|
| 113 |
|
|
#endif /* __STDIO_THREADSAFE */
|
| 114 |
|
|
|
| 115 |
|
|
#ifdef __UCLIBC_HAS_WCHAR__
|
| 116 |
|
|
#include <wchar.h>
|
| 117 |
|
|
#endif /* __UCLIBC_HAS_WCHAR__ */
|
| 118 |
|
|
|
| 119 |
|
|
/* Some older or broken gcc toolchains define LONG_LONG_MAX but not
|
| 120 |
|
|
* LLONG_MAX. Since LLONG_MAX is part of the standard, that's what
|
| 121 |
|
|
* we use. So complain if we do not have it but should.
|
| 122 |
|
|
*/
|
| 123 |
|
|
#if !defined(LLONG_MAX) && defined(LONG_LONG_MAX)
|
| 124 |
|
|
#error Apparently, LONG_LONG_MAX is defined but LLONG_MAX is not. You need to fix your toolchain headers to support the standard macros for (unsigned) long long.
|
| 125 |
|
|
#endif
|
| 126 |
|
|
|
| 127 |
|
|
/**********************************************************************/
|
| 128 |
|
|
/* These provide some control over printf's feature set */
|
| 129 |
|
|
|
| 130 |
|
|
/* This is undefined below depeding on uClibc's configuration. */
|
| 131 |
|
|
#define __STDIO_PRINTF_FLOAT 1
|
| 132 |
|
|
|
| 133 |
|
|
/* Now controlled by uClibc_stdio.h. */
|
| 134 |
|
|
/* #define __STDIO_PRINTF_M_SUPPORT */
|
| 135 |
|
|
|
| 136 |
|
|
|
| 137 |
|
|
/**********************************************************************/
|
| 138 |
|
|
|
| 139 |
|
|
#if defined(__UCLIBC__) && !defined(__UCLIBC_HAS_FLOATS__)
|
| 140 |
|
|
#undef __STDIO_PRINTF_FLOAT
|
| 141 |
|
|
#endif
|
| 142 |
|
|
|
| 143 |
|
|
#ifdef __BCC__
|
| 144 |
|
|
#undef __STDIO_PRINTF_FLOAT
|
| 145 |
|
|
#endif
|
| 146 |
|
|
|
| 147 |
|
|
#ifdef __STDIO_PRINTF_FLOAT
|
| 148 |
|
|
#include <float.h>
|
| 149 |
|
|
#include <bits/uClibc_fpmax.h>
|
| 150 |
|
|
#else /* __STDIO_PRINTF_FLOAT */
|
| 151 |
|
|
#undef L__fpmaxtostr
|
| 152 |
|
|
#endif /* __STDIO_PRINTF_FLOAT */
|
| 153 |
|
|
|
| 154 |
|
|
|
| 155 |
|
|
#undef __STDIO_HAS_VSNPRINTF
|
| 156 |
|
|
#if defined(__STDIO_BUFFERS) || defined(__USE_OLD_VFPRINTF__) || defined(__STDIO_GLIBC_CUSTOM_STREAMS)
|
| 157 |
|
|
#define __STDIO_HAS_VSNPRINTF 1
|
| 158 |
|
|
#endif
|
| 159 |
|
|
|
| 160 |
|
|
/**********************************************************************/
|
| 161 |
|
|
|
| 162 |
|
|
/* Now controlled by uClibc_stdio.h. */
|
| 163 |
|
|
/* #define __STDIO_GLIBC_CUSTOM_PRINTF */
|
| 164 |
|
|
|
| 165 |
|
|
/* TODO -- move these to a configuration section? */
|
| 166 |
|
|
#define MAX_FIELD_WIDTH 4095
|
| 167 |
|
|
|
| 168 |
|
|
#ifdef __UCLIBC_MJN3_ONLY__
|
| 169 |
|
|
#ifdef L_register_printf_function
|
| 170 |
|
|
/* emit only once */
|
| 171 |
|
|
#warning WISHLIST: Make MAX_USER_SPEC configurable?
|
| 172 |
|
|
#warning WISHLIST: Make MAX_ARGS_PER_SPEC configurable?
|
| 173 |
|
|
#endif
|
| 174 |
|
|
#endif /* __UCLIBC_MJN3_ONLY__ */
|
| 175 |
|
|
|
| 176 |
|
|
#ifdef __STDIO_GLIBC_CUSTOM_PRINTF
|
| 177 |
|
|
|
| 178 |
|
|
#define MAX_USER_SPEC 10
|
| 179 |
|
|
#define MAX_ARGS_PER_SPEC 5
|
| 180 |
|
|
|
| 181 |
|
|
#else /* __STDIO_GLIBC_CUSTOM_PRINTF */
|
| 182 |
|
|
|
| 183 |
|
|
#undef MAX_USER_SPEC
|
| 184 |
|
|
#define MAX_ARGS_PER_SPEC 1
|
| 185 |
|
|
|
| 186 |
|
|
#endif /* __STDIO_GLIBC_CUSTOM_PRINTF */
|
| 187 |
|
|
|
| 188 |
|
|
#if MAX_ARGS_PER_SPEC < 1
|
| 189 |
|
|
#error MAX_ARGS_PER_SPEC < 1!
|
| 190 |
|
|
#undef MAX_ARGS_PER_SPEC
|
| 191 |
|
|
#define MAX_ARGS_PER_SPEC 1
|
| 192 |
|
|
#endif
|
| 193 |
|
|
|
| 194 |
|
|
#if defined(NL_ARGMAX) && (NL_ARGMAX < 9)
|
| 195 |
|
|
#error NL_ARGMAX < 9!
|
| 196 |
|
|
#endif
|
| 197 |
|
|
|
| 198 |
|
|
#if defined(NL_ARGMAX) && (NL_ARGMAX >= (MAX_ARGS_PER_SPEC + 2))
|
| 199 |
|
|
#define MAX_ARGS NL_ARGMAX
|
| 200 |
|
|
#else
|
| 201 |
|
|
/* N for spec itself, plus 1 each for width and precision */
|
| 202 |
|
|
#define MAX_ARGS (MAX_ARGS_PER_SPEC + 2)
|
| 203 |
|
|
#endif
|
| 204 |
|
|
|
| 205 |
|
|
|
| 206 |
|
|
/**********************************************************************/
|
| 207 |
|
|
/* Deal with pre-C99 compilers. */
|
| 208 |
|
|
|
| 209 |
|
|
#ifndef va_copy
|
| 210 |
|
|
|
| 211 |
|
|
#ifdef __va_copy
|
| 212 |
|
|
#define va_copy(A,B) __va_copy(A,B)
|
| 213 |
|
|
#else
|
| 214 |
|
|
/* TODO -- maybe create a bits/vacopy.h for arch specific versions
|
| 215 |
|
|
* to ensure we get the right behavior? Either that or fall back
|
| 216 |
|
|
* on the portable (but costly in size) method of using a va_list *.
|
| 217 |
|
|
* That means a pointer derefs in the va_arg() invocations... */
|
| 218 |
|
|
#warning Neither va_copy (C99/SUSv3) or __va_copy is defined. Using a simple copy instead. But you should really check that this is appropriate...
|
| 219 |
|
|
/* the glibc manual suggests that this will usually suffice when
|
| 220 |
|
|
__va_copy doesn't exist. */
|
| 221 |
|
|
#define va_copy(A,B) A = B
|
| 222 |
|
|
#endif
|
| 223 |
|
|
|
| 224 |
|
|
#endif /* va_copy */
|
| 225 |
|
|
|
| 226 |
|
|
/**********************************************************************/
|
| 227 |
|
|
|
| 228 |
|
|
#define __PA_FLAG_INTMASK \
|
| 229 |
|
|
(__PA_FLAG_CHAR|PA_FLAG_SHORT|__PA_FLAG_INT|PA_FLAG_LONG|PA_FLAG_LONG_LONG)
|
| 230 |
|
|
|
| 231 |
|
|
#ifdef __STDIO_GLIBC_CUSTOM_PRINTF
|
| 232 |
|
|
extern printf_function _custom_printf_handler[MAX_USER_SPEC];
|
| 233 |
|
|
extern printf_arginfo_function *_custom_printf_arginfo[MAX_USER_SPEC];
|
| 234 |
|
|
extern char *_custom_printf_spec;
|
| 235 |
|
|
#endif /* __STDIO_GLIBC_CUSTOM_PRINTF */
|
| 236 |
|
|
|
| 237 |
|
|
/**********************************************************************/
|
| 238 |
|
|
|
| 239 |
|
|
#define SPEC_FLAGS " +0-#'I"
|
| 240 |
|
|
enum {
|
| 241 |
|
|
FLAG_SPACE = 0x01,
|
| 242 |
|
|
FLAG_PLUS = 0x02, /* must be 2 * FLAG_SPACE */
|
| 243 |
|
|
FLAG_ZERO = 0x04,
|
| 244 |
|
|
FLAG_MINUS = 0x08, /* must be 2 * FLAG_ZERO */
|
| 245 |
|
|
FLAG_HASH = 0x10,
|
| 246 |
|
|
FLAG_THOUSANDS = 0x20,
|
| 247 |
|
|
FLAG_I18N = 0x40, /* only works for d, i, u */
|
| 248 |
|
|
FLAG_WIDESTREAM = 0x80
|
| 249 |
|
|
};
|
| 250 |
|
|
|
| 251 |
|
|
/**********************************************************************/
|
| 252 |
|
|
|
| 253 |
|
|
/* float layout 01234567890123456789 TODO: B?*/
|
| 254 |
|
|
#define SPEC_CHARS "npxXoudifFeEgGaACScs"
|
| 255 |
|
|
enum {
|
| 256 |
|
|
CONV_n = 0,
|
| 257 |
|
|
CONV_p,
|
| 258 |
|
|
CONV_x, CONV_X, CONV_o, CONV_u, CONV_d, CONV_i,
|
| 259 |
|
|
CONV_f, CONV_F, CONV_e, CONV_E, CONV_g, CONV_G, CONV_a, CONV_A,
|
| 260 |
|
|
CONV_C, CONV_S, CONV_c, CONV_s,
|
| 261 |
|
|
#ifdef __STDIO_PRINTF_M_SUPPORT
|
| 262 |
|
|
CONV_m,
|
| 263 |
|
|
#endif
|
| 264 |
|
|
CONV_custom0 /* must be last */
|
| 265 |
|
|
};
|
| 266 |
|
|
|
| 267 |
|
|
/* p x X o u d i */
|
| 268 |
|
|
#define SPEC_BASE { 16, 16, 16, 8, 10, 10, 10 }
|
| 269 |
|
|
|
| 270 |
|
|
#define SPEC_RANGES { CONV_n, CONV_p, CONV_i, CONV_A, \
|
| 271 |
|
|
CONV_C, CONV_S, CONV_c, CONV_s, CONV_custom0 }
|
| 272 |
|
|
|
| 273 |
|
|
#define SPEC_OR_MASK { \
|
| 274 |
|
|
/* n */ (PA_FLAG_PTR|PA_INT), \
|
| 275 |
|
|
/* p */ PA_POINTER, \
|
| 276 |
|
|
/* oxXudi */ PA_INT, \
|
| 277 |
|
|
/* fFeEgGaA */ PA_DOUBLE, \
|
| 278 |
|
|
/* C */ PA_WCHAR, \
|
| 279 |
|
|
/* S */ PA_WSTRING, \
|
| 280 |
|
|
/* c */ PA_CHAR, \
|
| 281 |
|
|
/* s */ PA_STRING, \
|
| 282 |
|
|
}
|
| 283 |
|
|
|
| 284 |
|
|
#define SPEC_AND_MASK { \
|
| 285 |
|
|
/* n */ (PA_FLAG_PTR|__PA_INTMASK), \
|
| 286 |
|
|
/* p */ PA_POINTER, \
|
| 287 |
|
|
/* oxXudi */ (__PA_INTMASK), \
|
| 288 |
|
|
/* fFeEgGaA */ (PA_FLAG_LONG_DOUBLE|PA_DOUBLE), \
|
| 289 |
|
|
/* C */ (PA_WCHAR), \
|
| 290 |
|
|
/* S */ (PA_WSTRING), \
|
| 291 |
|
|
/* c */ (PA_CHAR), \
|
| 292 |
|
|
/* s */ (PA_STRING), \
|
| 293 |
|
|
}
|
| 294 |
|
|
|
| 295 |
|
|
/**********************************************************************/
|
| 296 |
|
|
/*
|
| 297 |
|
|
* In order to ease translation to what arginfo and _print_info._flags expect,
|
| 298 |
|
|
* we map: 0:int 1:char 2:longlong 4:long 8:short
|
| 299 |
|
|
* and then _flags |= (((q << 7) + q) & 0x701) and argtype |= (_flags & 0x701)
|
| 300 |
|
|
*/
|
| 301 |
|
|
|
| 302 |
|
|
/* TODO -- Fix the table below to take into account stdint.h. */
|
| 303 |
|
|
/* #ifndef LLONG_MAX */
|
| 304 |
|
|
/* #error fix QUAL_CHARS for no long long! Affects 'L', 'j', 'q', 'll'. */
|
| 305 |
|
|
/* #else */
|
| 306 |
|
|
/* #if LLONG_MAX != INTMAX_MAX */
|
| 307 |
|
|
/* #error fix QUAL_CHARS intmax_t entry 'j'! */
|
| 308 |
|
|
/* #endif */
|
| 309 |
|
|
/* #endif */
|
| 310 |
|
|
|
| 311 |
|
|
#ifdef PDS
|
| 312 |
|
|
#error PDS already defined!
|
| 313 |
|
|
#endif
|
| 314 |
|
|
#ifdef SS
|
| 315 |
|
|
#error SS already defined!
|
| 316 |
|
|
#endif
|
| 317 |
|
|
#ifdef IMS
|
| 318 |
|
|
#error IMS already defined!
|
| 319 |
|
|
#endif
|
| 320 |
|
|
|
| 321 |
|
|
#if PTRDIFF_MAX == INT_MAX
|
| 322 |
|
|
#define PDS 0
|
| 323 |
|
|
#elif PTRDIFF_MAX == LONG_MAX
|
| 324 |
|
|
#define PDS 4
|
| 325 |
|
|
#elif defined(LLONG_MAX) && (PTRDIFF_MAX == LLONG_MAX)
|
| 326 |
|
|
#define PDS 8
|
| 327 |
|
|
#else
|
| 328 |
|
|
#error fix QUAL_CHARS ptrdiff_t entry 't'!
|
| 329 |
|
|
#endif
|
| 330 |
|
|
|
| 331 |
|
|
#if SIZE_MAX == UINT_MAX
|
| 332 |
|
|
#define SS 0
|
| 333 |
|
|
#elif SIZE_MAX == ULONG_MAX
|
| 334 |
|
|
#define SS 4
|
| 335 |
|
|
#elif defined(LLONG_MAX) && (SIZE_MAX == ULLONG_MAX)
|
| 336 |
|
|
#define SS 8
|
| 337 |
|
|
#else
|
| 338 |
|
|
#error fix QUAL_CHARS size_t entries 'z', 'Z'!
|
| 339 |
|
|
#endif
|
| 340 |
|
|
|
| 341 |
|
|
#if INTMAX_MAX == INT_MAX
|
| 342 |
|
|
#define IMS 0
|
| 343 |
|
|
#elif INTMAX_MAX == LONG_MAX
|
| 344 |
|
|
#define IMS 4
|
| 345 |
|
|
#elif defined(LLONG_MAX) && (INTMAX_MAX == LLONG_MAX)
|
| 346 |
|
|
#define IMS 8
|
| 347 |
|
|
#else
|
| 348 |
|
|
#error fix QUAL_CHARS intmax_t entry 'j'!
|
| 349 |
|
|
#endif
|
| 350 |
|
|
|
| 351 |
|
|
#define QUAL_CHARS { \
|
| 352 |
|
|
/* j:(u)intmax_t z:(s)size_t t:ptrdiff_t \0:int */ \
|
| 353 |
|
|
/* q:long_long Z:(s)size_t */ \
|
| 354 |
|
|
'h', 'l', 'L', 'j', 'z', 't', 'q', 'Z', 0, \
|
| 355 |
|
|
2, 4, 8, IMS, SS, PDS, 8, SS, 0, /* TODO -- fix!!! */\
|
| 356 |
|
|
1, 8 \
|
| 357 |
|
|
}
|
| 358 |
|
|
|
| 359 |
|
|
/**********************************************************************/
|
| 360 |
|
|
|
| 361 |
|
|
#ifdef __STDIO_VA_ARG_PTR
|
| 362 |
|
|
#ifdef __BCC__
|
| 363 |
|
|
#define __va_arg_ptr(ap,type) (((type *)(ap += sizeof(type))) - 1)
|
| 364 |
|
|
#endif
|
| 365 |
|
|
|
| 366 |
|
|
#if 1
|
| 367 |
|
|
#ifdef __GNUC__
|
| 368 |
|
|
/* TODO -- need other than for 386 as well! */
|
| 369 |
|
|
|
| 370 |
|
|
#ifndef __va_rounded_size
|
| 371 |
|
|
#define __va_rounded_size(TYPE) \
|
| 372 |
|
|
(((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
|
| 373 |
|
|
#endif
|
| 374 |
|
|
#define __va_arg_ptr(AP, TYPE) \
|
| 375 |
|
|
(AP = (va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \
|
| 376 |
|
|
((void *) ((char *) (AP) - __va_rounded_size (TYPE))))
|
| 377 |
|
|
#endif
|
| 378 |
|
|
#endif
|
| 379 |
|
|
#endif /* __STDIO_VA_ARG_PTR */
|
| 380 |
|
|
|
| 381 |
|
|
#ifdef __va_arg_ptr
|
| 382 |
|
|
#define GET_VA_ARG(AP,F,TYPE,ARGS) (*(AP) = __va_arg_ptr(ARGS,TYPE))
|
| 383 |
|
|
#define GET_ARG_VALUE(AP,F,TYPE) (*((TYPE *)(*(AP))))
|
| 384 |
|
|
#else
|
| 385 |
|
|
typedef union {
|
| 386 |
|
|
wchar_t wc;
|
| 387 |
|
|
unsigned int u;
|
| 388 |
|
|
unsigned long ul;
|
| 389 |
|
|
#ifdef ULLONG_MAX
|
| 390 |
|
|
unsigned long long ull;
|
| 391 |
|
|
#endif
|
| 392 |
|
|
#ifdef __STDIO_PRINTF_FLOAT
|
| 393 |
|
|
double d;
|
| 394 |
|
|
long double ld;
|
| 395 |
|
|
#endif /* __STDIO_PRINTF_FLOAT */
|
| 396 |
|
|
void *p;
|
| 397 |
|
|
} argvalue_t;
|
| 398 |
|
|
|
| 399 |
|
|
#define GET_VA_ARG(AU,F,TYPE,ARGS) (AU->F = va_arg(ARGS,TYPE))
|
| 400 |
|
|
#define GET_ARG_VALUE(AU,F,TYPE) ((TYPE)((AU)->F))
|
| 401 |
|
|
#endif
|
| 402 |
|
|
|
| 403 |
|
|
typedef struct {
|
| 404 |
|
|
const char *fmtpos; /* TODO: move below struct?? */
|
| 405 |
|
|
struct printf_info info;
|
| 406 |
|
|
#ifdef NL_ARGMAX
|
| 407 |
|
|
int maxposarg; /* > 0 if args are positional, 0 if not, -1 if unknown */
|
| 408 |
|
|
#endif /* NL_ARGMAX */
|
| 409 |
|
|
int num_data_args; /* TODO: use sentinal??? */
|
| 410 |
|
|
unsigned int conv_num;
|
| 411 |
|
|
unsigned char argnumber[4]; /* width | prec | 1st data | unused */
|
| 412 |
|
|
int argtype[MAX_ARGS];
|
| 413 |
|
|
va_list arg;
|
| 414 |
|
|
#ifdef __va_arg_ptr
|
| 415 |
|
|
void *argptr[MAX_ARGS];
|
| 416 |
|
|
#else
|
| 417 |
|
|
/* if defined(NL_ARGMAX) || defined(__STDIO_GLIBC_CUSTOM_PRINTF) */
|
| 418 |
|
|
/* While this is wasteful of space in the case where pos args aren't
|
| 419 |
|
|
* enabled, it is also needed to support custom printf handlers. */
|
| 420 |
|
|
argvalue_t argvalue[MAX_ARGS];
|
| 421 |
|
|
#endif
|
| 422 |
|
|
} ppfs_t; /* parse printf format state */
|
| 423 |
|
|
|
| 424 |
|
|
/**********************************************************************/
|
| 425 |
|
|
|
| 426 |
|
|
/* TODO: fix printf to return 0 and set errno if format error. Standard says
|
| 427 |
|
|
only returns -1 if sets error indicator for the stream. */
|
| 428 |
|
|
|
| 429 |
|
|
#ifdef __STDIO_PRINTF_FLOAT
|
| 430 |
|
|
typedef void (__fp_outfunc_t)(FILE *fp, intptr_t type, intptr_t len,
|
| 431 |
|
|
intptr_t buf);
|
| 432 |
|
|
|
| 433 |
|
|
extern size_t _fpmaxtostr(FILE * fp, __fpmax_t x, struct printf_info *info,
|
| 434 |
|
|
__fp_outfunc_t fp_outfunc);
|
| 435 |
|
|
#endif
|
| 436 |
|
|
|
| 437 |
|
|
extern int _ppfs_init(ppfs_t *ppfs, const char *fmt0); /* validates */
|
| 438 |
|
|
extern void _ppfs_prepargs(ppfs_t *ppfs, va_list arg); /* sets posargptrs */
|
| 439 |
|
|
extern void _ppfs_setargs(ppfs_t *ppfs); /* sets argptrs for current spec */
|
| 440 |
|
|
extern int _ppfs_parsespec(ppfs_t *ppfs); /* parses specifier */
|
| 441 |
|
|
|
| 442 |
|
|
extern void _store_inttype(void *dest, int desttype, uintmax_t val);
|
| 443 |
|
|
extern uintmax_t _load_inttype(int desttype, const void *src, int uflag);
|
| 444 |
|
|
|
| 445 |
|
|
/**********************************************************************/
|
| 446 |
|
|
#ifdef L_parse_printf_format
|
| 447 |
|
|
|
| 448 |
|
|
/* NOTE: This function differs from the glibc version in that parsing stops
|
| 449 |
|
|
* upon encountering an invalid conversion specifier. Since this is the way
|
| 450 |
|
|
* my printf functions work, I think it makes sense to do it that way here.
|
| 451 |
|
|
* Unfortunately, since glibc sets the return type as size_t, we have no way
|
| 452 |
|
|
* of returning that the template is illegal, other than returning 0.
|
| 453 |
|
|
*/
|
| 454 |
|
|
|
| 455 |
|
|
size_t parse_printf_format(register const char *template,
|
| 456 |
|
|
size_t n, register int *argtypes)
|
| 457 |
|
|
{
|
| 458 |
|
|
ppfs_t ppfs;
|
| 459 |
|
|
size_t i;
|
| 460 |
|
|
size_t count = 0;
|
| 461 |
|
|
|
| 462 |
|
|
if (_ppfs_init(&ppfs, template) >= 0) {
|
| 463 |
|
|
#ifdef NL_ARGMAX
|
| 464 |
|
|
if (ppfs.maxposarg > 0) { /* Using positional args. */
|
| 465 |
|
|
count = ppfs.maxposarg;
|
| 466 |
|
|
if (n > count) {
|
| 467 |
|
|
n = count;
|
| 468 |
|
|
}
|
| 469 |
|
|
for (i = 0 ; i < n ; i++) {
|
| 470 |
|
|
*argtypes++ = ppfs.argtype[i];
|
| 471 |
|
|
}
|
| 472 |
|
|
} else { /* Not using positional args. */
|
| 473 |
|
|
#endif /* NL_ARGMAX */
|
| 474 |
|
|
while (*template) {
|
| 475 |
|
|
if ((*template == '%') && (*++template != '%')) {
|
| 476 |
|
|
ppfs.fmtpos = template;
|
| 477 |
|
|
_ppfs_parsespec(&ppfs); /* Can't fail. */
|
| 478 |
|
|
template = ppfs.fmtpos; /* Update to one past spec end. */
|
| 479 |
|
|
if (ppfs.info.width == INT_MIN) {
|
| 480 |
|
|
++count;
|
| 481 |
|
|
if (n > 0) {
|
| 482 |
|
|
*argtypes++ = PA_INT;
|
| 483 |
|
|
--n;
|
| 484 |
|
|
}
|
| 485 |
|
|
}
|
| 486 |
|
|
if (ppfs.info.prec == INT_MIN) {
|
| 487 |
|
|
++count;
|
| 488 |
|
|
if (n > 0) {
|
| 489 |
|
|
*argtypes++ = PA_INT;
|
| 490 |
|
|
--n;
|
| 491 |
|
|
}
|
| 492 |
|
|
}
|
| 493 |
|
|
for (i = 0 ; i < ppfs.num_data_args ; i++) {
|
| 494 |
|
|
if ((ppfs.argtype[i]) != __PA_NOARG) {
|
| 495 |
|
|
++count;
|
| 496 |
|
|
if (n > 0) {
|
| 497 |
|
|
*argtypes++ = ppfs.argtype[i];
|
| 498 |
|
|
--n;
|
| 499 |
|
|
}
|
| 500 |
|
|
}
|
| 501 |
|
|
}
|
| 502 |
|
|
} else {
|
| 503 |
|
|
++template;
|
| 504 |
|
|
}
|
| 505 |
|
|
}
|
| 506 |
|
|
#ifdef NL_ARGMAX
|
| 507 |
|
|
}
|
| 508 |
|
|
#endif /* NL_ARGMAX */
|
| 509 |
|
|
}
|
| 510 |
|
|
|
| 511 |
|
|
return count;
|
| 512 |
|
|
}
|
| 513 |
|
|
|
| 514 |
|
|
#endif
|
| 515 |
|
|
/**********************************************************************/
|
| 516 |
|
|
#ifdef L__ppfs_init
|
| 517 |
|
|
|
| 518 |
|
|
int _ppfs_init(register ppfs_t *ppfs, const char *fmt0)
|
| 519 |
|
|
{
|
| 520 |
|
|
int r;
|
| 521 |
|
|
|
| 522 |
|
|
/* First, zero out everything... argnumber[], argtype[], argptr[] */
|
| 523 |
|
|
memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */
|
| 524 |
|
|
#ifdef NL_ARGMAX
|
| 525 |
|
|
--ppfs->maxposarg; /* set to -1 */
|
| 526 |
|
|
#endif /* NL_ARGMAX */
|
| 527 |
|
|
ppfs->fmtpos = fmt0;
|
| 528 |
|
|
#ifdef __UCLIBC_MJN3_ONLY__
|
| 529 |
|
|
#warning TODO: Make checking of the format string in C locale an option.
|
| 530 |
|
|
#endif
|
| 531 |
|
|
#ifdef __UCLIBC_HAS_LOCALE__
|
| 532 |
|
|
/* To support old programs, don't check mb validity if in C locale. */
|
| 533 |
|
|
if (((__UCLIBC_CURLOCALE_DATA).encoding) != __ctype_encoding_7_bit) {
|
| 534 |
|
|
/* ANSI/ISO C99 requires format string to be a valid multibyte string
|
| 535 |
|
|
* beginning and ending in its initial shift state. */
|
| 536 |
|
|
static const char invalid_mbs[] = "Invalid multibyte format string.";
|
| 537 |
|
|
mbstate_t mbstate;
|
| 538 |
|
|
const char *p;
|
| 539 |
|
|
mbstate.mask = 0; /* Initialize the mbstate. */
|
| 540 |
|
|
p = fmt0;
|
| 541 |
|
|
if (mbsrtowcs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) {
|
| 542 |
|
|
ppfs->fmtpos = invalid_mbs;
|
| 543 |
|
|
return -1;
|
| 544 |
|
|
}
|
| 545 |
|
|
}
|
| 546 |
|
|
#endif /* __UCLIBC_HAS_LOCALE__ */
|
| 547 |
|
|
/* now set all argtypes to no-arg */
|
| 548 |
|
|
{
|
| 549 |
|
|
#if 1
|
| 550 |
|
|
/* TODO - use memset here since already "paid for"? */
|
| 551 |
|
|
register int *p = ppfs->argtype;
|
| 552 |
|
|
|
| 553 |
|
|
r = MAX_ARGS;
|
| 554 |
|
|
do {
|
| 555 |
|
|
*p++ = __PA_NOARG;
|
| 556 |
|
|
} while (--r);
|
| 557 |
|
|
#else
|
| 558 |
|
|
/* TODO -- get rid of this?? */
|
| 559 |
|
|
register char *p = (char *) ((MAX_ARGS-1) * sizeof(int));
|
| 560 |
|
|
|
| 561 |
|
|
do {
|
| 562 |
|
|
*((int *)(((char *)ppfs) + ((int)p) + offsetof(ppfs_t,argtype))) = __PA_NOARG;
|
| 563 |
|
|
p -= sizeof(int);
|
| 564 |
|
|
} while (p);
|
| 565 |
|
|
#endif
|
| 566 |
|
|
}
|
| 567 |
|
|
|
| 568 |
|
|
/*
|
| 569 |
|
|
* Run through the entire format string to validate it and initialize
|
| 570 |
|
|
* the positional arg numbers (if any).
|
| 571 |
|
|
*/
|
| 572 |
|
|
{
|
| 573 |
|
|
register const char *fmt = fmt0;
|
| 574 |
|
|
|
| 575 |
|
|
while (*fmt) {
|
| 576 |
|
|
if ((*fmt == '%') && (*++fmt != '%')) {
|
| 577 |
|
|
ppfs->fmtpos = fmt; /* back up to the '%' */
|
| 578 |
|
|
if ((r = _ppfs_parsespec(ppfs)) < 0) {
|
| 579 |
|
|
return -1;
|
| 580 |
|
|
}
|
| 581 |
|
|
fmt = ppfs->fmtpos; /* update to one past end of spec */
|
| 582 |
|
|
} else {
|
| 583 |
|
|
++fmt;
|
| 584 |
|
|
}
|
| 585 |
|
|
}
|
| 586 |
|
|
ppfs->fmtpos = fmt0; /* rewind */
|
| 587 |
|
|
}
|
| 588 |
|
|
|
| 589 |
|
|
#ifdef NL_MAX_ARG
|
| 590 |
|
|
/* If we have positional args, make sure we know all the types. */
|
| 591 |
|
|
{
|
| 592 |
|
|
register int *p = ppfs->argtype;
|
| 593 |
|
|
r = ppfs->maxposarg;
|
| 594 |
|
|
while (--r >= 0) {
|
| 595 |
|
|
if ( *p == __PA_NOARG ) { /* missing arg type!!! */
|
| 596 |
|
|
return -1;
|
| 597 |
|
|
}
|
| 598 |
|
|
++p;
|
| 599 |
|
|
}
|
| 600 |
|
|
}
|
| 601 |
|
|
#endif /* NL_MAX_ARG */
|
| 602 |
|
|
|
| 603 |
|
|
return 0;
|
| 604 |
|
|
}
|
| 605 |
|
|
#endif
|
| 606 |
|
|
/**********************************************************************/
|
| 607 |
|
|
#ifdef L__ppfs_prepargs
|
| 608 |
|
|
void _ppfs_prepargs(register ppfs_t *ppfs, va_list arg)
|
| 609 |
|
|
{
|
| 610 |
|
|
int i;
|
| 611 |
|
|
|
| 612 |
|
|
va_copy(ppfs->arg, arg);
|
| 613 |
|
|
|
| 614 |
|
|
#ifdef NL_ARGMAX
|
| 615 |
|
|
if ((i = ppfs->maxposarg) > 0) { /* init for positional args */
|
| 616 |
|
|
ppfs->num_data_args = i;
|
| 617 |
|
|
ppfs->info.width = ppfs->info.prec = ppfs->maxposarg = 0;
|
| 618 |
|
|
_ppfs_setargs(ppfs);
|
| 619 |
|
|
ppfs->maxposarg = i;
|
| 620 |
|
|
}
|
| 621 |
|
|
#endif /* NL_ARGMAX */
|
| 622 |
|
|
}
|
| 623 |
|
|
#endif
|
| 624 |
|
|
/**********************************************************************/
|
| 625 |
|
|
#ifdef L__ppfs_setargs
|
| 626 |
|
|
|
| 627 |
|
|
void _ppfs_setargs(register ppfs_t *ppfs)
|
| 628 |
|
|
{
|
| 629 |
|
|
#ifdef __va_arg_ptr
|
| 630 |
|
|
register void **p = ppfs->argptr;
|
| 631 |
|
|
#else
|
| 632 |
|
|
register argvalue_t *p = ppfs->argvalue;
|
| 633 |
|
|
#endif
|
| 634 |
|
|
int i;
|
| 635 |
|
|
|
| 636 |
|
|
#ifdef NL_ARGMAX
|
| 637 |
|
|
if (ppfs->maxposarg == 0) { /* initing for or no pos args */
|
| 638 |
|
|
#endif /* NL_ARGMAX */
|
| 639 |
|
|
if (ppfs->info.width == INT_MIN) {
|
| 640 |
|
|
ppfs->info.width =
|
| 641 |
|
|
#ifdef __va_arg_ptr
|
| 642 |
|
|
*(int *)
|
| 643 |
|
|
#endif
|
| 644 |
|
|
GET_VA_ARG(p,u,unsigned int,ppfs->arg);
|
| 645 |
|
|
}
|
| 646 |
|
|
if (ppfs->info.prec == INT_MIN) {
|
| 647 |
|
|
ppfs->info.prec =
|
| 648 |
|
|
#ifdef __va_arg_ptr
|
| 649 |
|
|
*(int *)
|
| 650 |
|
|
#endif
|
| 651 |
|
|
GET_VA_ARG(p,u,unsigned int,ppfs->arg);
|
| 652 |
|
|
}
|
| 653 |
|
|
i = 0;
|
| 654 |
|
|
while (i < ppfs->num_data_args) {
|
| 655 |
|
|
switch(ppfs->argtype[i++]) {
|
| 656 |
|
|
case (PA_INT|PA_FLAG_LONG_LONG):
|
| 657 |
|
|
#ifdef ULLONG_MAX
|
| 658 |
|
|
GET_VA_ARG(p,ull,unsigned long long,ppfs->arg);
|
| 659 |
|
|
break;
|
| 660 |
|
|
#endif
|
| 661 |
|
|
case (PA_INT|PA_FLAG_LONG):
|
| 662 |
|
|
#if ULONG_MAX != UINT_MAX
|
| 663 |
|
|
GET_VA_ARG(p,ul,unsigned long,ppfs->arg);
|
| 664 |
|
|
break;
|
| 665 |
|
|
#endif
|
| 666 |
|
|
case PA_CHAR: /* TODO - be careful */
|
| 667 |
|
|
/* ... users could use above and really want below!! */
|
| 668 |
|
|
case (PA_INT|__PA_FLAG_CHAR):/* TODO -- translate this!!! */
|
| 669 |
|
|
case (PA_INT|PA_FLAG_SHORT):
|
| 670 |
|
|
case PA_INT:
|
| 671 |
|
|
GET_VA_ARG(p,u,unsigned int,ppfs->arg);
|
| 672 |
|
|
break;
|
| 673 |
|
|
case PA_WCHAR: /* TODO -- assume int? */
|
| 674 |
|
|
/* we're assuming wchar_t is at least an int */
|
| 675 |
|
|
GET_VA_ARG(p,wc,wchar_t,ppfs->arg);
|
| 676 |
|
|
break;
|
| 677 |
|
|
#ifdef __STDIO_PRINTF_FLOAT
|
| 678 |
|
|
/* PA_FLOAT */
|
| 679 |
|
|
case PA_DOUBLE:
|
| 680 |
|
|
GET_VA_ARG(p,d,double,ppfs->arg);
|
| 681 |
|
|
break;
|
| 682 |
|
|
case (PA_DOUBLE|PA_FLAG_LONG_DOUBLE):
|
| 683 |
|
|
GET_VA_ARG(p,ld,long double,ppfs->arg);
|
| 684 |
|
|
break;
|
| 685 |
|
|
#else /* __STDIO_PRINTF_FLOAT */
|
| 686 |
|
|
case PA_DOUBLE:
|
| 687 |
|
|
case (PA_DOUBLE|PA_FLAG_LONG_DOUBLE):
|
| 688 |
|
|
assert(0);
|
| 689 |
|
|
continue;
|
| 690 |
|
|
#endif /* __STDIO_PRINTF_FLOAT */
|
| 691 |
|
|
default:
|
| 692 |
|
|
/* TODO -- really need to ensure this can't happen */
|
| 693 |
|
|
assert(ppfs->argtype[i-1] & PA_FLAG_PTR);
|
| 694 |
|
|
case PA_POINTER:
|
| 695 |
|
|
case PA_STRING:
|
| 696 |
|
|
case PA_WSTRING:
|
| 697 |
|
|
GET_VA_ARG(p,p,void *,ppfs->arg);
|
| 698 |
|
|
break;
|
| 699 |
|
|
case __PA_NOARG:
|
| 700 |
|
|
continue;
|
| 701 |
|
|
}
|
| 702 |
|
|
++p;
|
| 703 |
|
|
}
|
| 704 |
|
|
#ifdef NL_ARGMAX
|
| 705 |
|
|
} else {
|
| 706 |
|
|
if (ppfs->info.width == INT_MIN) {
|
| 707 |
|
|
ppfs->info.width
|
| 708 |
|
|
= (int) GET_ARG_VALUE(p + ppfs->argnumber[0] - 1,u,unsigned int);
|
| 709 |
|
|
}
|
| 710 |
|
|
if (ppfs->info.prec == INT_MIN) {
|
| 711 |
|
|
ppfs->info.prec
|
| 712 |
|
|
= (int) GET_ARG_VALUE(p + ppfs->argnumber[1] - 1,u,unsigned int);
|
| 713 |
|
|
}
|
| 714 |
|
|
}
|
| 715 |
|
|
#endif /* NL_ARGMAX */
|
| 716 |
|
|
|
| 717 |
|
|
/* Now we know the width and precision. */
|
| 718 |
|
|
if (ppfs->info.width < 0) {
|
| 719 |
|
|
ppfs->info.width = -ppfs->info.width;
|
| 720 |
|
|
PRINT_INFO_SET_FLAG(&(ppfs->info),left);
|
| 721 |
|
|
PRINT_INFO_CLR_FLAG(&(ppfs->info),space);
|
| 722 |
|
|
ppfs->info.pad = ' ';
|
| 723 |
|
|
}
|
| 724 |
|
|
#if 0
|
| 725 |
|
|
/* NOTE -- keep neg for now so float knows! */
|
| 726 |
|
|
if (ppfs->info.prec < 0) { /* spec says treat as omitted. */
|
| 727 |
|
|
/* so use default prec... 1 for everything but floats and strings. */
|
| 728 |
|
|
ppfs->info.prec = 1;
|
| 729 |
|
|
}
|
| 730 |
|
|
#endif
|
| 731 |
|
|
}
|
| 732 |
|
|
#endif
|
| 733 |
|
|
/**********************************************************************/
|
| 734 |
|
|
#ifdef L__ppfs_parsespec
|
| 735 |
|
|
|
| 736 |
|
|
/* Notes: argtype differs from glibc for the following:
|
| 737 |
|
|
* mine glibc
|
| 738 |
|
|
* lc PA_WCHAR PA_CHAR the standard says %lc means %C
|
| 739 |
|
|
* ls PA_WSTRING PA_STRING the standard says %ls means %S
|
| 740 |
|
|
* {*}n {*}|PA_FLAG_PTR PA_FLAG_PTR size of n can be qualified
|
| 741 |
|
|
*/
|
| 742 |
|
|
|
| 743 |
|
|
/* TODO: store positions of positional args */
|
| 744 |
|
|
|
| 745 |
|
|
/* TODO -- WARNING -- assumes aligned on integer boundaries!!! */
|
| 746 |
|
|
|
| 747 |
|
|
/* TODO -- disable if not using positional args!!! */
|
| 748 |
|
|
#define _OVERLAPPING_DIFFERENT_ARGS
|
| 749 |
|
|
|
| 750 |
|
|
/* TODO -- rethink this -- perhaps we should set to largest type??? */
|
| 751 |
|
|
|
| 752 |
|
|
#ifdef _OVERLAPPING_DIFFERENT_ARGS
|
| 753 |
|
|
|
| 754 |
|
|
#define PROMOTED_SIZE_OF(X) ((sizeof(X) + sizeof(int) - 1) / sizeof(X))
|
| 755 |
|
|
|
| 756 |
|
|
static const short int type_codes[] = {
|
| 757 |
|
|
__PA_NOARG, /* must be first entry */
|
| 758 |
|
|
PA_POINTER,
|
| 759 |
|
|
PA_STRING,
|
| 760 |
|
|
PA_WSTRING,
|
| 761 |
|
|
PA_CHAR,
|
| 762 |
|
|
PA_INT|PA_FLAG_SHORT,
|
| 763 |
|
|
PA_INT,
|
| 764 |
|
|
PA_INT|PA_FLAG_LONG,
|
| 765 |
|
|
PA_INT|PA_FLAG_LONG_LONG,
|
| 766 |
|
|
PA_WCHAR,
|
| 767 |
|
|
#ifdef __STDIO_PRINTF_FLOAT
|
| 768 |
|
|
/* PA_FLOAT, */
|
| 769 |
|
|
PA_DOUBLE,
|
| 770 |
|
|
PA_DOUBLE|PA_FLAG_LONG_DOUBLE,
|
| 771 |
|
|
#endif /* __STDIO_PRINTF_FLOAT */
|
| 772 |
|
|
};
|
| 773 |
|
|
|
| 774 |
|
|
static const unsigned char type_sizes[] = {
|
| 775 |
|
|
/* unknown type consumes no arg */
|
| 776 |
|
|
0, /* must be first entry */
|
| 777 |
|
|
PROMOTED_SIZE_OF(void *),
|
| 778 |
|
|
PROMOTED_SIZE_OF(char *),
|
| 779 |
|
|
PROMOTED_SIZE_OF(wchar_t *),
|
| 780 |
|
|
PROMOTED_SIZE_OF(char),
|
| 781 |
|
|
PROMOTED_SIZE_OF(short),
|
| 782 |
|
|
PROMOTED_SIZE_OF(int),
|
| 783 |
|
|
PROMOTED_SIZE_OF(long),
|
| 784 |
|
|
#ifdef ULLONG_MAX
|
| 785 |
|
|
PROMOTED_SIZE_OF(long long),
|
| 786 |
|
|
#else
|
| 787 |
|
|
PROMOTED_SIZE_OF(long), /* TODO -- is this correct? (above too) */
|
| 788 |
|
|
#endif
|
| 789 |
|
|
PROMOTED_SIZE_OF(wchar_t),
|
| 790 |
|
|
#ifdef __STDIO_PRINTF_FLOAT
|
| 791 |
|
|
/* PROMOTED_SIZE_OF(float), */
|
| 792 |
|
|
PROMOTED_SIZE_OF(double),
|
| 793 |
|
|
PROMOTED_SIZE_OF(long double),
|
| 794 |
|
|
#endif /* __STDIO_PRINTF_FLOAT */
|
| 795 |
|
|
};
|
| 796 |
|
|
|
| 797 |
|
|
static int _promoted_size(int argtype)
|
| 798 |
|
|
{
|
| 799 |
|
|
register const short int *p;
|
| 800 |
|
|
|
| 801 |
|
|
/* note -- since any unrecognized type is treated as a pointer */
|
| 802 |
|
|
p = type_codes + sizeof(type_codes)/sizeof(type_codes[0]);
|
| 803 |
|
|
do {
|
| 804 |
|
|
if (*--p == argtype) {
|
| 805 |
|
|
break;
|
| 806 |
|
|
}
|
| 807 |
|
|
} while (p > type_codes);
|
| 808 |
|
|
|
| 809 |
|
|
return type_sizes[(int)(p - type_codes)];
|
| 810 |
|
|
}
|
| 811 |
|
|
|
| 812 |
|
|
static int _is_equal_or_bigger_arg(int curtype, int newtype)
|
| 813 |
|
|
{
|
| 814 |
|
|
/* Quick test */
|
| 815 |
|
|
if (newtype == __PA_NOARG) {
|
| 816 |
|
|
return 0;
|
| 817 |
|
|
}
|
| 818 |
|
|
if ((curtype == __PA_NOARG) || (curtype == newtype)) {
|
| 819 |
|
|
return 1;
|
| 820 |
|
|
}
|
| 821 |
|
|
/* Ok... slot is already filled and types are different in name. */
|
| 822 |
|
|
/* So, compare promoted sizes of curtype and newtype args. */
|
| 823 |
|
|
return _promoted_size(curtype) <= _promoted_size(newtype);
|
| 824 |
|
|
}
|
| 825 |
|
|
|
| 826 |
|
|
#else
|
| 827 |
|
|
|
| 828 |
|
|
#define _is_equal_or_bigger_arg(C,N) (((C) == __PA_NOARG) || ((C) == (N)))
|
| 829 |
|
|
|
| 830 |
|
|
#endif
|
| 831 |
|
|
|
| 832 |
|
|
#ifdef __STDIO_GLIBC_CUSTOM_PRINTF
|
| 833 |
|
|
/* TODO - do this differently? */
|
| 834 |
|
|
static char _bss_custom_printf_spec[MAX_USER_SPEC]; /* 0-init'd for us. */
|
| 835 |
|
|
|
| 836 |
|
|
char *_custom_printf_spec = _bss_custom_printf_spec;
|
| 837 |
|
|
printf_arginfo_function *_custom_printf_arginfo[MAX_USER_SPEC];
|
| 838 |
|
|
printf_function _custom_printf_handler[MAX_USER_SPEC];
|
| 839 |
|
|
#endif /* __STDIO_GLIBC_CUSTOM_PRINTF */
|
| 840 |
|
|
|
| 841 |
|
|
extern int _ppfs_parsespec(ppfs_t *ppfs)
|
| 842 |
|
|
{
|
| 843 |
|
|
register const char *fmt;
|
| 844 |
|
|
register const char *p;
|
| 845 |
|
|
int preci;
|
| 846 |
|
|
int width;
|
| 847 |
|
|
int flags;
|
| 848 |
|
|
int dataargtype;
|
| 849 |
|
|
int i;
|
| 850 |
|
|
int dpoint;
|
| 851 |
|
|
#ifdef NL_ARGMAX
|
| 852 |
|
|
int maxposarg;
|
| 853 |
|
|
#endif /* NL_ARGMAX */
|
| 854 |
|
|
int p_m_spec_chars;
|
| 855 |
|
|
int n;
|
| 856 |
|
|
int argtype[MAX_ARGS_PER_SPEC+2];
|
| 857 |
|
|
int argnumber[3]; /* width, precision, 1st data arg */
|
| 858 |
|
|
static const char spec_flags[] = SPEC_FLAGS;
|
| 859 |
|
|
static const char spec_chars[] = SPEC_CHARS;/* TODO: b? */
|
| 860 |
|
|
static const char spec_ranges[] = SPEC_RANGES;
|
| 861 |
|
|
static const short spec_or_mask[] = SPEC_OR_MASK;
|
| 862 |
|
|
static const short spec_and_mask[] = SPEC_AND_MASK;
|
| 863 |
|
|
static const char qual_chars[] = QUAL_CHARS;
|
| 864 |
|
|
#ifdef __UCLIBC_HAS_WCHAR__
|
| 865 |
|
|
char buf[32];
|
| 866 |
|
|
#endif /* __UCLIBC_HAS_WCHAR__ */
|
| 867 |
|
|
|
| 868 |
|
|
/* WIDE note: we can test against '%' here since we don't allow */
|
| 869 |
|
|
/* WIDE note: other mappings of '%' in the wide char set. */
|
| 870 |
|
|
preci = -1;
|
| 871 |
|
|
argnumber[0] = 0;
|
| 872 |
|
|
argnumber[1] = 0;
|
| 873 |
|
|
argtype[0] = __PA_NOARG;
|
| 874 |
|
|
argtype[1] = __PA_NOARG;
|
| 875 |
|
|
#ifdef NL_ARGMAX
|
| 876 |
|
|
maxposarg = ppfs->maxposarg;
|
| 877 |
|
|
#endif /* NL_ARGMAX */
|
| 878 |
|
|
|
| 879 |
|
|
#ifdef __UCLIBC_HAS_WCHAR__
|
| 880 |
|
|
/* This is somewhat lame, but saves a lot of code. If we're dealing with
|
| 881 |
|
|
* a wide stream, that means the format is a wchar string. So, copy it
|
| 882 |
|
|
* char-by-char into a normal char buffer for processing. Make the buffer
|
| 883 |
|
|
* (buf) big enough so that any reasonable format specifier will fit.
|
| 884 |
|
|
* While there a legal specifiers that won't, the all involve duplicate
|
| 885 |
|
|
* flags or outrageous field widths/precisions. */
|
| 886 |
|
|
width = dpoint = 0;
|
| 887 |
|
|
if ((flags = ppfs->info._flags & FLAG_WIDESTREAM) == 0) {
|
| 888 |
|
|
fmt = ppfs->fmtpos;
|
| 889 |
|
|
} else {
|
| 890 |
|
|
fmt = buf + 1;
|
| 891 |
|
|
i = 0;
|
| 892 |
|
|
do {
|
| 893 |
|
|
if ((buf[i] = (char) (((wchar_t *) ppfs->fmtpos)[i-1]))
|
| 894 |
|
|
!= (((wchar_t *) ppfs->fmtpos)[i-1])
|
| 895 |
|
|
) {
|
| 896 |
|
|
return -1;
|
| 897 |
|
|
}
|
| 898 |
|
|
} while (buf[i++]);
|
| 899 |
|
|
buf[sizeof(buf)-1] = 0;
|
| 900 |
|
|
}
|
| 901 |
|
|
#else /* __UCLIBC_HAS_WCHAR__ */
|
| 902 |
|
|
width = flags = dpoint = 0;
|
| 903 |
|
|
fmt = ppfs->fmtpos;
|
| 904 |
|
|
#endif /* __UCLIBC_HAS_WCHAR__ */
|
| 905 |
|
|
|
| 906 |
|
|
assert(fmt[-1] == '%');
|
| 907 |
|
|
assert(fmt[0] != '%');
|
| 908 |
|
|
|
| 909 |
|
|
/* Process arg pos and/or flags and/or width and/or precision. */
|
| 910 |
|
|
width_precision:
|
| 911 |
|
|
p = fmt;
|
| 912 |
|
|
if (*fmt == '*') {
|
| 913 |
|
|
argtype[-dpoint] = PA_INT;
|
| 914 |
|
|
++fmt;
|
| 915 |
|
|
}
|
| 916 |
|
|
i = 0;
|
| 917 |
|
|
while (isdigit(*fmt)) {
|
| 918 |
|
|
if (i < MAX_FIELD_WIDTH) { /* Avoid overflow. */
|
| 919 |
|
|
i = (i * 10) + (*fmt - '0');
|
| 920 |
|
|
}
|
| 921 |
|
|
++fmt;
|
| 922 |
|
|
}
|
| 923 |
|
|
if (p[-1] == '%') { /* Check for a position. */
|
| 924 |
|
|
|
| 925 |
|
|
/* TODO: if val not in range, then error */
|
| 926 |
|
|
|
| 927 |
|
|
#ifdef NL_ARGMAX
|
| 928 |
|
|
if ((*fmt == '$') && (i > 0)) {/* Positional spec. */
|
| 929 |
|
|
++fmt;
|
| 930 |
|
|
if (maxposarg == 0) {
|
| 931 |
|
|
return -1;
|
| 932 |
|
|
}
|
| 933 |
|
|
if ((argnumber[2] = i) > maxposarg) {
|
| 934 |
|
|
maxposarg = i;
|
| 935 |
|
|
}
|
| 936 |
|
|
/* Now fall through to check flags. */
|
| 937 |
|
|
} else {
|
| 938 |
|
|
if (maxposarg > 0) {
|
| 939 |
|
|
#ifdef __STDIO_PRINTF_M_SUPPORT
|
| 940 |
|
|
#ifdef __UCLIBC_MJN3_ONLY__
|
| 941 |
|
|
#warning TODO: Support prec and width for %m when positional args used
|
| 942 |
|
|
/* Actually, positional arg processing will fail in general
|
| 943 |
|
|
* for specifiers that don't require an arg. */
|
| 944 |
|
|
#endif /* __UCLIBC_MJN3_ONLY__ */
|
| 945 |
|
|
if (*fmt == 'm') {
|
| 946 |
|
|
goto PREC_WIDTH;
|
| 947 |
|
|
}
|
| 948 |
|
|
#endif /* __STDIO_PRINTF_M_SUPPORT */
|
| 949 |
|
|
return -1;
|
| 950 |
|
|
}
|
| 951 |
|
|
maxposarg = 0; /* Possible redundant store, but cuts size. */
|
| 952 |
|
|
|
| 953 |
|
|
if ((fmt > p) && (*p != '0')) {
|
| 954 |
|
|
goto PREC_WIDTH;
|
| 955 |
|
|
}
|
| 956 |
|
|
|
| 957 |
|
|
fmt = p; /* Back up for possible '0's flag. */
|
| 958 |
|
|
/* Now fall through to check flags. */
|
| 959 |
|
|
}
|
| 960 |
|
|
#else /* NL_ARGMAX */
|
| 961 |
|
|
if (*fmt == '$') { /* Positional spec. */
|
| 962 |
|
|
return -1;
|
| 963 |
|
|
}
|
| 964 |
|
|
|
| 965 |
|
|
if ((fmt > p) && (*p != '0')) {
|
| 966 |
|
|
goto PREC_WIDTH;
|
| 967 |
|
|
}
|
| 968 |
|
|
|
| 969 |
|
|
fmt = p; /* Back up for possible '0's flag. */
|
| 970 |
|
|
/* Now fall through to check flags. */
|
| 971 |
|
|
#endif /* NL_ARGMAX */
|
| 972 |
|
|
|
| 973 |
|
|
restart_flags: /* Process flags. */
|
| 974 |
|
|
i = 1;
|
| 975 |
|
|
p = spec_flags;
|
| 976 |
|
|
|
| 977 |
|
|
do {
|
| 978 |
|
|
if (*fmt == *p++) {
|
| 979 |
|
|
++fmt;
|
| 980 |
|
|
flags |= i;
|
| 981 |
|
|
goto restart_flags;
|
| 982 |
|
|
}
|
| 983 |
|
|
i += i; /* Better than i <<= 1 for bcc */
|
| 984 |
|
|
} while (*p);
|
| 985 |
|
|
i = 0;
|
| 986 |
|
|
|
| 987 |
|
|
/* If '+' then ignore ' ', and if '-' then ignore '0'. */
|
| 988 |
|
|
/* Note: Need to ignore '0' when prec is an arg with val < 0, */
|
| 989 |
|
|
/* but that test needs to wait until the arg is retrieved. */
|
| 990 |
|
|
flags &= ~((flags & (FLAG_PLUS|FLAG_MINUS)) >> 1);
|
| 991 |
|
|
/* Note: Ignore '0' when prec is specified < 0 too (in printf). */
|
| 992 |
|
|
|
| 993 |
|
|
if (fmt[-1] != '%') { /* If we've done anything, loop for width. */
|
| 994 |
|
|
goto width_precision;
|
| 995 |
|
|
}
|
| 996 |
|
|
}
|
| 997 |
|
|
PREC_WIDTH:
|
| 998 |
|
|
if (*p == '*') { /* Prec or width takes an arg. */
|
| 999 |
|
|
#ifdef NL_ARGMAX
|
| 1000 |
|
|
if (maxposarg) {
|
| 1001 |
|
|
if ((*fmt++ != '$') || (i <= 0)) {
|
| 1002 |
|
|
/* Using pos args and no $ or invalid arg number. */
|
| 1003 |
|
|
return -1;
|
| 1004 |
|
|
}
|
| 1005 |
|
|
argnumber[-dpoint] = i;
|
| 1006 |
|
|
} else
|
| 1007 |
|
|
#endif /* NL_ARGMAX */
|
| 1008 |
|
|
if (++p != fmt) {
|
| 1009 |
|
|
/* Not using pos args but digits followed *. */
|
| 1010 |
|
|
return -1;
|
| 1011 |
|
|
}
|
| 1012 |
|
|
i = INT_MIN;
|
| 1013 |
|
|
}
|
| 1014 |
|
|
|
| 1015 |
|
|
if (!dpoint) {
|
| 1016 |
|
|
width = i;
|
| 1017 |
|
|
if (*fmt == '.') {
|
| 1018 |
|
|
++fmt;
|
| 1019 |
|
|
dpoint = -1; /* To use as default precison. */
|
| 1020 |
|
|
goto width_precision;
|
| 1021 |
|
|
}
|
| 1022 |
|
|
} else {
|
| 1023 |
|
|
preci = i;
|
| 1024 |
|
|
}
|
| 1025 |
|
|
|
| 1026 |
|
|
/* Process qualifier. */
|
| 1027 |
|
|
p = qual_chars;
|
| 1028 |
|
|
do {
|
| 1029 |
|
|
if (*fmt == *p) {
|
| 1030 |
|
|
++fmt;
|
| 1031 |
|
|
break;
|
| 1032 |
|
|
}
|
| 1033 |
|
|
} while (*++p);
|
| 1034 |
|
|
if ((p - qual_chars < 2) && (*fmt == *p)) {
|
| 1035 |
|
|
p += ((sizeof(qual_chars)-2) / 2);
|
| 1036 |
|
|
++fmt;
|
| 1037 |
|
|
}
|
| 1038 |
|
|
dataargtype = ((int)(p[(sizeof(qual_chars)-2) / 2])) << 8;
|
| 1039 |
|
|
|
| 1040 |
|
|
/* Process conversion specifier. */
|
| 1041 |
|
|
if (!*fmt) {
|
| 1042 |
|
|
return -1;
|
| 1043 |
|
|
}
|
| 1044 |
|
|
|
| 1045 |
|
|
p = spec_chars;
|
| 1046 |
|
|
|
| 1047 |
|
|
do {
|
| 1048 |
|
|
if (*fmt == *p) {
|
| 1049 |
|
|
p_m_spec_chars = p - spec_chars;
|
| 1050 |
|
|
|
| 1051 |
|
|
if ((p_m_spec_chars >= CONV_c)
|
| 1052 |
|
|
&& (dataargtype & PA_FLAG_LONG)) {
|
| 1053 |
|
|
p_m_spec_chars -= 2; /* lc -> C and ls -> S */
|
| 1054 |
|
|
}
|
| 1055 |
|
|
|
| 1056 |
|
|
ppfs->conv_num = p_m_spec_chars;
|
| 1057 |
|
|
p = spec_ranges-1;
|
| 1058 |
|
|
while (p_m_spec_chars > *++p) {}
|
| 1059 |
|
|
|
| 1060 |
|
|
i = p - spec_ranges;
|
| 1061 |
|
|
argtype[2] = (dataargtype | spec_or_mask[i]) & spec_and_mask[i];
|
| 1062 |
|
|
p = spec_chars;
|
| 1063 |
|
|
break;
|
| 1064 |
|
|
}
|
| 1065 |
|
|
} while(*++p);
|
| 1066 |
|
|
|
| 1067 |
|
|
ppfs->info.spec = *fmt;
|
| 1068 |
|
|
ppfs->info.prec = preci;
|
| 1069 |
|
|
ppfs->info.width = width;
|
| 1070 |
|
|
ppfs->info.pad = ((flags & FLAG_ZERO) ? '0' : ' ');
|
| 1071 |
|
|
ppfs->info._flags = (flags & ~FLAG_ZERO) | (dataargtype & __PA_INTMASK);
|
| 1072 |
|
|
ppfs->num_data_args = 1;
|
| 1073 |
|
|
|
| 1074 |
|
|
if (!*p) {
|
| 1075 |
|
|
#ifdef __STDIO_PRINTF_M_SUPPORT
|
| 1076 |
|
|
if (*fmt == 'm') {
|
| 1077 |
|
|
ppfs->conv_num = CONV_m;
|
| 1078 |
|
|
ppfs->num_data_args = 0;
|
| 1079 |
|
|
goto DONE;
|
| 1080 |
|
|
}
|
| 1081 |
|
|
#endif
|
| 1082 |
|
|
#ifdef __STDIO_GLIBC_CUSTOM_PRINTF
|
| 1083 |
|
|
|
| 1084 |
|
|
/* Handle custom arg -- WARNING -- overwrites p!!! */
|
| 1085 |
|
|
ppfs->conv_num = CONV_custom0;
|
| 1086 |
|
|
p = _custom_printf_spec;
|
| 1087 |
|
|
do {
|
| 1088 |
|
|
if (*p == *fmt) {
|
| 1089 |
|
|
if ((ppfs->num_data_args
|
| 1090 |
|
|
= ((*_custom_printf_arginfo[(int)(p-_custom_printf_spec)])
|
| 1091 |
|
|
(&(ppfs->info), MAX_ARGS_PER_SPEC, argtype+2)))
|
| 1092 |
|
|
> MAX_ARGS_PER_SPEC) {
|
| 1093 |
|
|
break; /* Error -- too many args! */
|
| 1094 |
|
|
}
|
| 1095 |
|
|
goto DONE;
|
| 1096 |
|
|
}
|
| 1097 |
|
|
} while (++p < (_custom_printf_spec + MAX_USER_SPEC));
|
| 1098 |
|
|
#endif /* __STDIO_GLIBC_CUSTOM_PRINTF */
|
| 1099 |
|
|
/* Otherwise error. */
|
| 1100 |
|
|
return -1;
|
| 1101 |
|
|
}
|
| 1102 |
|
|
|
| 1103 |
|
|
#if defined(__STDIO_GLIBC_CUSTOM_PRINTF) || defined(__STDIO_PRINTF_M_SUPPORT)
|
| 1104 |
|
|
DONE:
|
| 1105 |
|
|
#endif
|
| 1106 |
|
|
|
| 1107 |
|
|
#ifdef NL_ARGMAX
|
| 1108 |
|
|
if (maxposarg > 0) {
|
| 1109 |
|
|
i = 0;
|
| 1110 |
|
|
do {
|
| 1111 |
|
|
/* Update maxposarg and check that NL_ARGMAX is not exceeded. */
|
| 1112 |
|
|
n = ((i <= 2)
|
| 1113 |
|
|
? (ppfs->argnumber[i] = argnumber[i])
|
| 1114 |
|
|
: argnumber[2] + (i-2));
|
| 1115 |
|
|
if (n > maxposarg) {
|
| 1116 |
|
|
if ((maxposarg = n) > NL_ARGMAX) {
|
| 1117 |
|
|
return -1;
|
| 1118 |
|
|
}
|
| 1119 |
|
|
}
|
| 1120 |
|
|
--n;
|
| 1121 |
|
|
/* Record argtype with largest size (current, new). */
|
| 1122 |
|
|
if (_is_equal_or_bigger_arg(ppfs->argtype[n], argtype[i])) {
|
| 1123 |
|
|
ppfs->argtype[n] = argtype[i];
|
| 1124 |
|
|
}
|
| 1125 |
|
|
} while (++i < ppfs->num_data_args + 2);
|
| 1126 |
|
|
} else {
|
| 1127 |
|
|
#endif /* NL_ARGMAX */
|
| 1128 |
|
|
ppfs->argnumber[2] = 1;
|
| 1129 |
|
|
memcpy(ppfs->argtype, argtype + 2, ppfs->num_data_args * sizeof(int));
|
| 1130 |
|
|
#ifdef NL_ARGMAX
|
| 1131 |
|
|
}
|
| 1132 |
|
|
|
| 1133 |
|
|
ppfs->maxposarg = maxposarg;
|
| 1134 |
|
|
#endif /* NL_ARGMAX */
|
| 1135 |
|
|
|
| 1136 |
|
|
#ifdef __UCLIBC_HAS_WCHAR__
|
| 1137 |
|
|
if ((flags = ppfs->info._flags & FLAG_WIDESTREAM) == 0) {
|
| 1138 |
|
|
ppfs->fmtpos = ++fmt;
|
| 1139 |
|
|
} else {
|
| 1140 |
|
|
ppfs->fmtpos = (const char *) (((const wchar_t *)(ppfs->fmtpos))
|
| 1141 |
|
|
+ (fmt - buf) );
|
| 1142 |
|
|
}
|
| 1143 |
|
|
#else /* __UCLIBC_HAS_WCHAR__ */
|
| 1144 |
|
|
ppfs->fmtpos = ++fmt;
|
| 1145 |
|
|
#endif /* __UCLIBC_HAS_WCHAR__ */
|
| 1146 |
|
|
|
| 1147 |
|
|
return ppfs->num_data_args + 2;
|
| 1148 |
|
|
}
|
| 1149 |
|
|
|
| 1150 |
|
|
#endif
|
| 1151 |
|
|
/**********************************************************************/
|
| 1152 |
|
|
#ifdef L_register_printf_function
|
| 1153 |
|
|
|
| 1154 |
|
|
#ifdef __STDIO_GLIBC_CUSTOM_PRINTF
|
| 1155 |
|
|
|
| 1156 |
|
|
int register_printf_function(int spec, printf_function handler,
|
| 1157 |
|
|
printf_arginfo_function arginfo)
|
| 1158 |
|
|
{
|
| 1159 |
|
|
register char *r;
|
| 1160 |
|
|
register char *p;
|
| 1161 |
|
|
|
| 1162 |
|
|
if (spec && (arginfo != NULL)) { /* TODO -- check if spec is valid char */
|
| 1163 |
|
|
r = NULL;
|
| 1164 |
|
|
p = _custom_printf_spec + MAX_USER_SPEC;
|
| 1165 |
|
|
do {
|
| 1166 |
|
|
--p;
|
| 1167 |
|
|
if (!*p) {
|
| 1168 |
|
|
r = p;
|
| 1169 |
|
|
}
|
| 1170 |
|
|
#ifdef __BCC__
|
| 1171 |
|
|
else /* bcc generates less code with fall-through */
|
| 1172 |
|
|
#endif
|
| 1173 |
|
|
if (*p == spec) {
|
| 1174 |
|
|
r = p;
|
| 1175 |
|
|
p = _custom_printf_spec;
|
| 1176 |
|
|
}
|
| 1177 |
|
|
} while (p > _custom_printf_spec);
|
| 1178 |
|
|
|
| 1179 |
|
|
if (r) {
|
| 1180 |
|
|
if (handler) {
|
| 1181 |
|
|
*r = spec;
|
| 1182 |
|
|
_custom_printf_handler[(int)(r - p)] = handler;
|
| 1183 |
|
|
_custom_printf_arginfo[(int)(r - p)] = arginfo;
|
| 1184 |
|
|
} else {
|
| 1185 |
|
|
*r = 0;
|
| 1186 |
|
|
}
|
| 1187 |
|
|
return 0;
|
| 1188 |
|
|
}
|
| 1189 |
|
|
/* TODO -- if asked to unregister a non-existent spec, return what? */
|
| 1190 |
|
|
}
|
| 1191 |
|
|
return -1;
|
| 1192 |
|
|
}
|
| 1193 |
|
|
|
| 1194 |
|
|
#endif
|
| 1195 |
|
|
|
| 1196 |
|
|
#endif
|
| 1197 |
|
|
/**********************************************************************/
|
| 1198 |
|
|
#ifdef L_vsnprintf
|
| 1199 |
|
|
|
| 1200 |
|
|
#ifdef __UCLIBC_MJN3_ONLY__
|
| 1201 |
|
|
#warning WISHLIST: Implement vsnprintf for non-buffered and no custom stream case.
|
| 1202 |
|
|
#endif /* __UCLIBC_MJN3_ONLY__ */
|
| 1203 |
|
|
|
| 1204 |
|
|
#ifdef __STDIO_BUFFERS
|
| 1205 |
|
|
|
| 1206 |
|
|
int vsnprintf(char *__restrict buf, size_t size,
|
| 1207 |
|
|
const char * __restrict format, va_list arg)
|
| 1208 |
|
|
{
|
| 1209 |
|
|
FILE f;
|
| 1210 |
|
|
int rv;
|
| 1211 |
|
|
|
| 1212 |
|
|
#ifdef __STDIO_GETC_MACRO
|
| 1213 |
|
|
f.bufgetc =
|
| 1214 |
|
|
#endif
|
| 1215 |
|
|
f.bufpos = f.bufread = f.bufstart = buf;
|
| 1216 |
|
|
|
| 1217 |
|
|
if (size > SIZE_MAX - (size_t) buf) {
|
| 1218 |
|
|
size = SIZE_MAX - (size_t) buf;
|
| 1219 |
|
|
}
|
| 1220 |
|
|
#ifdef __STDIO_PUTC_MACRO
|
| 1221 |
|
|
f.bufputc =
|
| 1222 |
|
|
#endif
|
| 1223 |
|
|
f.bufend = buf + size;
|
| 1224 |
|
|
|
| 1225 |
|
|
#if 0 /* shouldn't be necessary */
|
| 1226 |
|
|
/* #ifdef __STDIO_GLIBC_CUSTOM_STREAMS */
|
| 1227 |
|
|
f.cookie = &(f.filedes);
|
| 1228 |
|
|
f.gcs.read = 0;
|
| 1229 |
|
|
f.gcs.write = 0;
|
| 1230 |
|
|
f.gcs.seek = 0;
|
| 1231 |
|
|
f.gcs.close = 0;
|
| 1232 |
|
|
#endif
|
| 1233 |
|
|
f.filedes = -2; /* for debugging */
|
| 1234 |
|
|
f.modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
|
| 1235 |
|
|
|
| 1236 |
|
|
#ifdef __STDIO_MBSTATE
|
| 1237 |
|
|
__INIT_MBSTATE(&(f.state));
|
| 1238 |
|
|
#endif /* __STDIO_MBSTATE */
|
| 1239 |
|
|
|
| 1240 |
|
|
#ifdef __STDIO_THREADSAFE
|
| 1241 |
|
|
f.user_locking = 0;
|
| 1242 |
|
|
__stdio_init_mutex(&f.lock);
|
| 1243 |
|
|
#endif
|
| 1244 |
|
|
|
| 1245 |
|
|
rv = vfprintf(&f, format, arg);
|
| 1246 |
|
|
if (size) {
|
| 1247 |
|
|
if (f.bufpos == f.bufend) {
|
| 1248 |
|
|
--f.bufpos;
|
| 1249 |
|
|
}
|
| 1250 |
|
|
*f.bufpos = 0;
|
| 1251 |
|
|
}
|
| 1252 |
|
|
return rv;
|
| 1253 |
|
|
}
|
| 1254 |
|
|
|
| 1255 |
|
|
#elif defined(__USE_OLD_VFPRINTF__)
|
| 1256 |
|
|
|
| 1257 |
|
|
typedef struct {
|
| 1258 |
|
|
FILE f;
|
| 1259 |
|
|
unsigned char *bufend; /* pointer to 1 past end of buffer */
|
| 1260 |
|
|
unsigned char *bufpos;
|
| 1261 |
|
|
} __FILE_vsnprintf;
|
| 1262 |
|
|
|
| 1263 |
|
|
int vsnprintf(char *__restrict buf, size_t size,
|
| 1264 |
|
|
const char * __restrict format, va_list arg)
|
| 1265 |
|
|
{
|
| 1266 |
|
|
__FILE_vsnprintf f;
|
| 1267 |
|
|
int rv;
|
| 1268 |
|
|
|
| 1269 |
|
|
f.bufpos = buf;
|
| 1270 |
|
|
|
| 1271 |
|
|
if (size > SIZE_MAX - (size_t) buf) {
|
| 1272 |
|
|
size = SIZE_MAX - (size_t) buf;
|
| 1273 |
|
|
}
|
| 1274 |
|
|
f.bufend = buf + size;
|
| 1275 |
|
|
|
| 1276 |
|
|
#if 0 /* shouldn't be necessary */
|
| 1277 |
|
|
/* #ifdef __STDIO_GLIBC_CUSTOM_STREAMS */
|
| 1278 |
|
|
f.f.cookie = &(f.f.filedes);
|
| 1279 |
|
|
f.f.gcs.read = 0;
|
| 1280 |
|
|
f.f.gcs.write = 0;
|
| 1281 |
|
|
f.f.gcs.seek = 0;
|
| 1282 |
|
|
f.f.gcs.close = 0;
|
| 1283 |
|
|
#endif
|
| 1284 |
|
|
f.f.filedes = -2; /* for debugging */
|
| 1285 |
|
|
f.f.modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
|
| 1286 |
|
|
|
| 1287 |
|
|
#ifdef __STDIO_MBSTATE
|
| 1288 |
|
|
__INIT_MBSTATE(&(f.f.state));
|
| 1289 |
|
|
#endif /* __STDIO_MBSTATE */
|
| 1290 |
|
|
|
| 1291 |
|
|
#ifdef __STDIO_THREADSAFE
|
| 1292 |
|
|
f.f.user_locking = 0;
|
| 1293 |
|
|
__stdio_init_mutex(&f.f.lock);
|
| 1294 |
|
|
#endif
|
| 1295 |
|
|
|
| 1296 |
|
|
rv = vfprintf((FILE *) &f, format, arg);
|
| 1297 |
|
|
if (size) {
|
| 1298 |
|
|
if (f.bufpos == f.bufend) {
|
| 1299 |
|
|
--f.bufpos;
|
| 1300 |
|
|
}
|
| 1301 |
|
|
*f.bufpos = 0;
|
| 1302 |
|
|
}
|
| 1303 |
|
|
return rv;
|
| 1304 |
|
|
}
|
| 1305 |
|
|
|
| 1306 |
|
|
#elif defined(__STDIO_GLIBC_CUSTOM_STREAMS)
|
| 1307 |
|
|
|
| 1308 |
|
|
typedef struct {
|
| 1309 |
|
|
size_t pos;
|
| 1310 |
|
|
size_t len;
|
| 1311 |
|
|
unsigned char *buf;
|
| 1312 |
|
|
FILE *fp;
|
| 1313 |
|
|
} __snpf_cookie;
|
| 1314 |
|
|
|
| 1315 |
|
|
#define COOKIE ((__snpf_cookie *) cookie)
|
| 1316 |
|
|
|
| 1317 |
|
|
static ssize_t snpf_write(register void *cookie, const char *buf,
|
| 1318 |
|
|
size_t bufsize)
|
| 1319 |
|
|
{
|
| 1320 |
|
|
size_t count;
|
| 1321 |
|
|
register char *p;
|
| 1322 |
|
|
|
| 1323 |
|
|
/* Note: bufsize < SSIZE_MAX because of _stdio_WRITE. */
|
| 1324 |
|
|
|
| 1325 |
|
|
if (COOKIE->len > COOKIE->pos) {
|
| 1326 |
|
|
count = COOKIE->len - COOKIE->pos - 1; /* Leave space for nul. */
|
| 1327 |
|
|
if (count > bufsize) {
|
| 1328 |
|
|
count = bufsize;
|
| 1329 |
|
|
}
|
| 1330 |
|
|
|
| 1331 |
|
|
p = COOKIE->buf + COOKIE->pos;
|
| 1332 |
|
|
while (count) {
|
| 1333 |
|
|
*p++ = *buf++;
|
| 1334 |
|
|
--count;
|
| 1335 |
|
|
}
|
| 1336 |
|
|
*p = 0;
|
| 1337 |
|
|
}
|
| 1338 |
|
|
|
| 1339 |
|
|
COOKIE->pos += bufsize;
|
| 1340 |
|
|
|
| 1341 |
|
|
return bufsize;
|
| 1342 |
|
|
}
|
| 1343 |
|
|
|
| 1344 |
|
|
#undef COOKIE
|
| 1345 |
|
|
|
| 1346 |
|
|
int vsnprintf(char *__restrict buf, size_t size,
|
| 1347 |
|
|
const char * __restrict format, va_list arg)
|
| 1348 |
|
|
{
|
| 1349 |
|
|
FILE f;
|
| 1350 |
|
|
__snpf_cookie cookie;
|
| 1351 |
|
|
int rv;
|
| 1352 |
|
|
|
| 1353 |
|
|
cookie.buf = buf;
|
| 1354 |
|
|
cookie.len = size;
|
| 1355 |
|
|
cookie.pos = 0;
|
| 1356 |
|
|
cookie.fp = &f;
|
| 1357 |
|
|
|
| 1358 |
|
|
f.cookie = &cookie;
|
| 1359 |
|
|
f.gcs.write = snpf_write;
|
| 1360 |
|
|
f.gcs.read = NULL;
|
| 1361 |
|
|
f.gcs.seek = NULL;
|
| 1362 |
|
|
f.gcs.close = NULL;
|
| 1363 |
|
|
|
| 1364 |
|
|
f.filedes = -1; /* For debugging. */
|
| 1365 |
|
|
f.modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
|
| 1366 |
|
|
|
| 1367 |
|
|
#ifdef __STDIO_MBSTATE
|
| 1368 |
|
|
__INIT_MBSTATE(&(f.state));
|
| 1369 |
|
|
#endif /* __STDIO_MBSTATE */
|
| 1370 |
|
|
|
| 1371 |
|
|
#ifdef __STDIO_THREADSAFE
|
| 1372 |
|
|
f.user_locking = 0;
|
| 1373 |
|
|
__stdio_init_mutex(&f.lock);
|
| 1374 |
|
|
#endif
|
| 1375 |
|
|
|
| 1376 |
|
|
rv = vfprintf(&f, format, arg);
|
| 1377 |
|
|
|
| 1378 |
|
|
return rv;
|
| 1379 |
|
|
}
|
| 1380 |
|
|
|
| 1381 |
|
|
#else
|
| 1382 |
|
|
#warning Skipping vsnprintf since no buffering, no custom streams, and not old vfprintf!
|
| 1383 |
|
|
#ifdef __STDIO_HAS_VSNPRINTF
|
| 1384 |
|
|
#error WHOA! __STDIO_HAS_VSNPRINTF is defined!
|
| 1385 |
|
|
#endif
|
| 1386 |
|
|
#endif
|
| 1387 |
|
|
|
| 1388 |
|
|
#endif
|
| 1389 |
|
|
/**********************************************************************/
|
| 1390 |
|
|
#ifdef L_vdprintf
|
| 1391 |
|
|
|
| 1392 |
|
|
int vdprintf(int filedes, const char * __restrict format, va_list arg)
|
| 1393 |
|
|
{
|
| 1394 |
|
|
FILE f;
|
| 1395 |
|
|
int rv;
|
| 1396 |
|
|
#ifdef __STDIO_BUFFERS
|
| 1397 |
|
|
char buf[64]; /* TODO: provide _optional_ buffering? */
|
| 1398 |
|
|
|
| 1399 |
|
|
#ifdef __STDIO_GETC_MACRO
|
| 1400 |
|
|
f.bufgetc =
|
| 1401 |
|
|
#endif
|
| 1402 |
|
|
f.bufpos = f.bufread = f.bufstart = buf;
|
| 1403 |
|
|
#ifdef __STDIO_PUTC_MACRO
|
| 1404 |
|
|
f.bufputc =
|
| 1405 |
|
|
#endif
|
| 1406 |
|
|
f.bufend = buf + sizeof(buf);
|
| 1407 |
|
|
#endif /* __STDIO_BUFFERS */
|
| 1408 |
|
|
#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
|
| 1409 |
|
|
f.cookie = &(f.filedes);
|
| 1410 |
|
|
f.gcs.read = _cs_read;
|
| 1411 |
|
|
f.gcs.write = _cs_write;
|
| 1412 |
|
|
f.gcs.seek = 0; /* The internal seek func handles normals. */
|
| 1413 |
|
|
f.gcs.close = _cs_close;
|
| 1414 |
|
|
#endif
|
| 1415 |
|
|
f.filedes = filedes;
|
| 1416 |
|
|
f.modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
|
| 1417 |
|
|
|
| 1418 |
|
|
#ifdef __STDIO_MBSTATE
|
| 1419 |
|
|
__INIT_MBSTATE(&(f.state));
|
| 1420 |
|
|
#endif /* __STDIO_MBSTATE */
|
| 1421 |
|
|
|
| 1422 |
|
|
#ifdef __STDIO_THREADSAFE
|
| 1423 |
|
|
f.user_locking = 0;
|
| 1424 |
|
|
__stdio_init_mutex(&f.lock);
|
| 1425 |
|
|
#endif
|
| 1426 |
|
|
|
| 1427 |
|
|
rv = vfprintf(&f, format, arg);
|
| 1428 |
|
|
|
| 1429 |
|
|
return fflush(&f) ? -1 : rv;
|
| 1430 |
|
|
}
|
| 1431 |
|
|
|
| 1432 |
|
|
#endif
|
| 1433 |
|
|
/**********************************************************************/
|
| 1434 |
|
|
#ifdef L_vasprintf
|
| 1435 |
|
|
|
| 1436 |
|
|
#ifndef __STDIO_HAS_VSNPRINTF
|
| 1437 |
|
|
#warning Skipping vasprintf since no vsnprintf!
|
| 1438 |
|
|
#else
|
| 1439 |
|
|
|
| 1440 |
|
|
int vasprintf(char **__restrict buf, const char * __restrict format,
|
| 1441 |
|
|
va_list arg)
|
| 1442 |
|
|
{
|
| 1443 |
|
|
/* TODO -- change the default implementation? */
|
| 1444 |
|
|
#ifndef __STDIO_GLIBC_CUSTOM_STREAMS
|
| 1445 |
|
|
/* This implementation actually calls the printf machinery twice, but only
|
| 1446 |
|
|
* only does one malloc. This can be a problem though when custom printf
|
| 1447 |
|
|
* specs or the %m specifier are involved because the results of the
|
| 1448 |
|
|
* second call might be different from the first. */
|
| 1449 |
|
|
va_list arg2;
|
| 1450 |
|
|
int rv;
|
| 1451 |
|
|
|
| 1452 |
|
|
va_copy(arg2, arg);
|
| 1453 |
|
|
rv = vsnprintf(NULL, 0, format, arg2);
|
| 1454 |
|
|
va_end(arg2);
|
| 1455 |
|
|
|
| 1456 |
|
|
return (((rv >= 0) && ((*buf = malloc(++rv)) != NULL))
|
| 1457 |
|
|
? vsnprintf(*buf, rv, format, arg)
|
| 1458 |
|
|
: -1);
|
| 1459 |
|
|
#else
|
| 1460 |
|
|
FILE *f;
|
| 1461 |
|
|
size_t size;
|
| 1462 |
|
|
int rv;
|
| 1463 |
|
|
|
| 1464 |
|
|
/* TODO - do the memstream stuff inline here to avoid fclose and the openlist? */
|
| 1465 |
|
|
if ((f = open_memstream(buf, &size)) == NULL) {
|
| 1466 |
|
|
return -1;
|
| 1467 |
|
|
}
|
| 1468 |
|
|
rv = vfprintf(f, format, arg);
|
| 1469 |
|
|
fclose(f);
|
| 1470 |
|
|
if (rv < 0) {
|
| 1471 |
|
|
free(*buf);
|
| 1472 |
|
|
*buf = NULL;
|
| 1473 |
|
|
return -1;
|
| 1474 |
|
|
}
|
| 1475 |
|
|
return rv;
|
| 1476 |
|
|
#endif
|
| 1477 |
|
|
}
|
| 1478 |
|
|
#endif
|
| 1479 |
|
|
#endif
|
| 1480 |
|
|
/**********************************************************************/
|
| 1481 |
|
|
#ifdef L_vprintf
|
| 1482 |
|
|
int vprintf(const char * __restrict format, va_list arg)
|
| 1483 |
|
|
{
|
| 1484 |
|
|
return vfprintf(stdout, format, arg);
|
| 1485 |
|
|
}
|
| 1486 |
|
|
#endif
|
| 1487 |
|
|
/**********************************************************************/
|
| 1488 |
|
|
#ifdef L_vsprintf
|
| 1489 |
|
|
|
| 1490 |
|
|
#ifndef __STDIO_HAS_VSNPRINTF
|
| 1491 |
|
|
#warning Skipping vsprintf since no vsnprintf!
|
| 1492 |
|
|
#else
|
| 1493 |
|
|
|
| 1494 |
|
|
int vsprintf(char *__restrict buf, const char * __restrict format,
|
| 1495 |
|
|
va_list arg)
|
| 1496 |
|
|
{
|
| 1497 |
|
|
return vsnprintf(buf, SIZE_MAX, format, arg);
|
| 1498 |
|
|
}
|
| 1499 |
|
|
|
| 1500 |
|
|
#endif
|
| 1501 |
|
|
#endif
|
| 1502 |
|
|
/**********************************************************************/
|
| 1503 |
|
|
#ifdef L_fprintf
|
| 1504 |
|
|
|
| 1505 |
|
|
int fprintf(FILE * __restrict stream, const char * __restrict format, ...)
|
| 1506 |
|
|
{
|
| 1507 |
|
|
va_list arg;
|
| 1508 |
|
|
int rv;
|
| 1509 |
|
|
|
| 1510 |
|
|
va_start(arg, format);
|
| 1511 |
|
|
rv = vfprintf(stream, format, arg);
|
| 1512 |
|
|
va_end(arg);
|
| 1513 |
|
|
|
| 1514 |
|
|
return rv;
|
| 1515 |
|
|
}
|
| 1516 |
|
|
|
| 1517 |
|
|
#endif
|
| 1518 |
|
|
/**********************************************************************/
|
| 1519 |
|
|
#ifdef L_snprintf
|
| 1520 |
|
|
|
| 1521 |
|
|
#ifndef __STDIO_HAS_VSNPRINTF
|
| 1522 |
|
|
#warning Skipping snprintf since no vsnprintf!
|
| 1523 |
|
|
#else
|
| 1524 |
|
|
|
| 1525 |
|
|
int snprintf(char *__restrict buf, size_t size,
|
| 1526 |
|
|
const char * __restrict format, ...)
|
| 1527 |
|
|
{
|
| 1528 |
|
|
va_list arg;
|
| 1529 |
|
|
int rv;
|
| 1530 |
|
|
|
| 1531 |
|
|
va_start(arg, format);
|
| 1532 |
|
|
rv = vsnprintf(buf, size, format, arg);
|
| 1533 |
|
|
va_end(arg);
|
| 1534 |
|
|
return rv;
|
| 1535 |
|
|
}
|
| 1536 |
|
|
|
| 1537 |
|
|
#endif
|
| 1538 |
|
|
#endif
|
| 1539 |
|
|
/**********************************************************************/
|
| 1540 |
|
|
#ifdef L_dprintf
|
| 1541 |
|
|
|
| 1542 |
|
|
int dprintf(int filedes, const char * __restrict format, ...)
|
| 1543 |
|
|
{
|
| 1544 |
|
|
va_list arg;
|
| 1545 |
|
|
int rv;
|
| 1546 |
|
|
|
| 1547 |
|
|
va_start(arg, format);
|
| 1548 |
|
|
rv = vdprintf(filedes, format, arg);
|
| 1549 |
|
|
va_end(arg);
|
| 1550 |
|
|
|
| 1551 |
|
|
return rv;
|
| 1552 |
|
|
}
|
| 1553 |
|
|
|
| 1554 |
|
|
#endif
|
| 1555 |
|
|
/**********************************************************************/
|
| 1556 |
|
|
#ifdef L_asprintf
|
| 1557 |
|
|
|
| 1558 |
|
|
#ifndef __STDIO_HAS_VSNPRINTF
|
| 1559 |
|
|
#warning Skipping asprintf and __asprintf since no vsnprintf!
|
| 1560 |
|
|
#else
|
| 1561 |
|
|
|
| 1562 |
|
|
weak_alias(__asprintf,asprintf)
|
| 1563 |
|
|
|
| 1564 |
|
|
int __asprintf(char **__restrict buf, const char * __restrict format, ...)
|
| 1565 |
|
|
{
|
| 1566 |
|
|
va_list arg;
|
| 1567 |
|
|
int rv;
|
| 1568 |
|
|
|
| 1569 |
|
|
va_start(arg, format);
|
| 1570 |
|
|
rv = vasprintf(buf, format, arg);
|
| 1571 |
|
|
va_end(arg);
|
| 1572 |
|
|
|
| 1573 |
|
|
return rv;
|
| 1574 |
|
|
}
|
| 1575 |
|
|
|
| 1576 |
|
|
#endif
|
| 1577 |
|
|
#endif
|
| 1578 |
|
|
/**********************************************************************/
|
| 1579 |
|
|
#ifdef L_printf
|
| 1580 |
|
|
int printf(const char * __restrict format, ...)
|
| 1581 |
|
|
{
|
| 1582 |
|
|
va_list arg;
|
| 1583 |
|
|
int rv;
|
| 1584 |
|
|
|
| 1585 |
|
|
va_start(arg, format);
|
| 1586 |
|
|
rv = vfprintf(stdout, format, arg);
|
| 1587 |
|
|
va_end(arg);
|
| 1588 |
|
|
|
| 1589 |
|
|
return rv;
|
| 1590 |
|
|
}
|
| 1591 |
|
|
#endif
|
| 1592 |
|
|
/**********************************************************************/
|
| 1593 |
|
|
#ifdef L_sprintf
|
| 1594 |
|
|
|
| 1595 |
|
|
#ifndef __STDIO_HAS_VSNPRINTF
|
| 1596 |
|
|
#warning Skipping sprintf since no vsnprintf!
|
| 1597 |
|
|
#else
|
| 1598 |
|
|
|
| 1599 |
|
|
int sprintf(char *__restrict buf, const char * __restrict format, ...)
|
| 1600 |
|
|
{
|
| 1601 |
|
|
va_list arg;
|
| 1602 |
|
|
int rv;
|
| 1603 |
|
|
|
| 1604 |
|
|
va_start(arg, format);
|
| 1605 |
|
|
rv = vsnprintf(buf, SIZE_MAX, format, arg);
|
| 1606 |
|
|
va_end(arg);
|
| 1607 |
|
|
|
| 1608 |
|
|
return rv;
|
| 1609 |
|
|
}
|
| 1610 |
|
|
|
| 1611 |
|
|
#endif
|
| 1612 |
|
|
#endif
|
| 1613 |
|
|
/**********************************************************************/
|
| 1614 |
|
|
#ifdef L_vswprintf
|
| 1615 |
|
|
|
| 1616 |
|
|
#ifdef __STDIO_BUFFERS
|
| 1617 |
|
|
int vswprintf(wchar_t *__restrict buf, size_t size,
|
| 1618 |
|
|
const wchar_t * __restrict format, va_list arg)
|
| 1619 |
|
|
{
|
| 1620 |
|
|
FILE f;
|
| 1621 |
|
|
int rv;
|
| 1622 |
|
|
|
| 1623 |
|
|
#ifdef __STDIO_GETC_MACRO
|
| 1624 |
|
|
f.bufgetc =
|
| 1625 |
|
|
#endif
|
| 1626 |
|
|
f.bufpos = f.bufread = f.bufstart = (char *) buf;
|
| 1627 |
|
|
|
| 1628 |
|
|
/* if (size > SIZE_MAX - (size_t) buf) { */
|
| 1629 |
|
|
/* size = SIZE_MAX - (size_t) buf; */
|
| 1630 |
|
|
/* } */
|
| 1631 |
|
|
#ifdef __STDIO_PUTC_MACRO
|
| 1632 |
|
|
f.bufputc =
|
| 1633 |
|
|
#endif
|
| 1634 |
|
|
f.bufend = (char *)(buf + size);
|
| 1635 |
|
|
|
| 1636 |
|
|
#if 0 /* shouldn't be necessary */
|
| 1637 |
|
|
/* #ifdef __STDIO_GLIBC_CUSTOM_STREAMS */
|
| 1638 |
|
|
f.cookie = &(f.filedes);
|
| 1639 |
|
|
f.gcs.read = 0;
|
| 1640 |
|
|
f.gcs.write = 0;
|
| 1641 |
|
|
f.gcs.seek = 0;
|
| 1642 |
|
|
f.gcs.close = 0;
|
| 1643 |
|
|
#endif
|
| 1644 |
|
|
f.filedes = -3; /* for debugging */
|
| 1645 |
|
|
f.modeflags = (__FLAG_WIDE|__FLAG_WRITEONLY|__FLAG_WRITING);
|
| 1646 |
|
|
|
| 1647 |
|
|
#ifdef __STDIO_MBSTATE
|
| 1648 |
|
|
__INIT_MBSTATE(&(f.state));
|
| 1649 |
|
|
#endif /* __STDIO_MBSTATE */
|
| 1650 |
|
|
|
| 1651 |
|
|
#ifdef __STDIO_THREADSAFE
|
| 1652 |
|
|
f.user_locking = 0;
|
| 1653 |
|
|
__stdio_init_mutex(&f.lock);
|
| 1654 |
|
|
#endif
|
| 1655 |
|
|
|
| 1656 |
|
|
rv = vfwprintf(&f, format, arg);
|
| 1657 |
|
|
|
| 1658 |
|
|
/* NOTE: Return behaviour differs from snprintf... */
|
| 1659 |
|
|
if (f.bufpos == f.bufend) {
|
| 1660 |
|
|
rv = -1;
|
| 1661 |
|
|
if (size) {
|
| 1662 |
|
|
f.bufpos = (char *)(((wchar_t *) f.bufpos) - 1);
|
| 1663 |
|
|
}
|
| 1664 |
|
|
}
|
| 1665 |
|
|
if (size) {
|
| 1666 |
|
|
*((wchar_t *) f.bufpos) = 0;
|
| 1667 |
|
|
}
|
| 1668 |
|
|
return rv;
|
| 1669 |
|
|
}
|
| 1670 |
|
|
#else /* __STDIO_BUFFERS */
|
| 1671 |
|
|
#warning Skipping vswprintf since no buffering!
|
| 1672 |
|
|
#endif /* __STDIO_BUFFERS */
|
| 1673 |
|
|
#endif
|
| 1674 |
|
|
/**********************************************************************/
|
| 1675 |
|
|
#ifdef L_swprintf
|
| 1676 |
|
|
#ifdef __STDIO_BUFFERS
|
| 1677 |
|
|
|
| 1678 |
|
|
int swprintf(wchar_t *__restrict buf, size_t size,
|
| 1679 |
|
|
const wchar_t * __restrict format, ...)
|
| 1680 |
|
|
{
|
| 1681 |
|
|
va_list arg;
|
| 1682 |
|
|
int rv;
|
| 1683 |
|
|
|
| 1684 |
|
|
va_start(arg, format);
|
| 1685 |
|
|
rv = vswprintf(buf, size, format, arg);
|
| 1686 |
|
|
va_end(arg);
|
| 1687 |
|
|
return rv;
|
| 1688 |
|
|
}
|
| 1689 |
|
|
|
| 1690 |
|
|
#else /* __STDIO_BUFFERS */
|
| 1691 |
|
|
#warning Skipping vsWprintf since no buffering!
|
| 1692 |
|
|
#endif /* __STDIO_BUFFERS */
|
| 1693 |
|
|
#endif
|
| 1694 |
|
|
/**********************************************************************/
|
| 1695 |
|
|
#ifdef L_fwprintf
|
| 1696 |
|
|
|
| 1697 |
|
|
int fwprintf(FILE * __restrict stream, const wchar_t * __restrict format, ...)
|
| 1698 |
|
|
{
|
| 1699 |
|
|
va_list arg;
|
| 1700 |
|
|
int rv;
|
| 1701 |
|
|
|
| 1702 |
|
|
va_start(arg, format);
|
| 1703 |
|
|
rv = vfwprintf(stream, format, arg);
|
| 1704 |
|
|
va_end(arg);
|
| 1705 |
|
|
|
| 1706 |
|
|
return rv;
|
| 1707 |
|
|
}
|
| 1708 |
|
|
|
| 1709 |
|
|
#endif
|
| 1710 |
|
|
/**********************************************************************/
|
| 1711 |
|
|
#ifdef L_vwprintf
|
| 1712 |
|
|
int vwprintf(const wchar_t * __restrict format, va_list arg)
|
| 1713 |
|
|
{
|
| 1714 |
|
|
return vfwprintf(stdout, format, arg);
|
| 1715 |
|
|
}
|
| 1716 |
|
|
#endif
|
| 1717 |
|
|
/**********************************************************************/
|
| 1718 |
|
|
#ifdef L_wprintf
|
| 1719 |
|
|
int wprintf(const wchar_t * __restrict format, ...)
|
| 1720 |
|
|
{
|
| 1721 |
|
|
va_list arg;
|
| 1722 |
|
|
int rv;
|
| 1723 |
|
|
|
| 1724 |
|
|
va_start(arg, format);
|
| 1725 |
|
|
rv = vfwprintf(stdout, format, arg);
|
| 1726 |
|
|
va_end(arg);
|
| 1727 |
|
|
|
| 1728 |
|
|
return rv;
|
| 1729 |
|
|
}
|
| 1730 |
|
|
#endif
|
| 1731 |
|
|
/**********************************************************************/
|
| 1732 |
|
|
#ifdef L__fpmaxtostr
|
| 1733 |
|
|
|
| 1734 |
|
|
/* Copyright (C) 2000, 2001, 2003 Manuel Novoa III
|
| 1735 |
|
|
*
|
| 1736 |
|
|
* Function:
|
| 1737 |
|
|
*
|
| 1738 |
|
|
* size_t _fpmaxtostr(FILE * fp, __fpmax_t x, struct printf_info *info,
|
| 1739 |
|
|
* __fp_outfunc_t fp_outfunc);
|
| 1740 |
|
|
*
|
| 1741 |
|
|
* This is derived from the old _dtostr, whic I wrote for uClibc to provide
|
| 1742 |
|
|
* floating point support for the printf functions. It handles +/- infinity,
|
| 1743 |
|
|
* nan, and signed 0 assuming you have ieee arithmetic. It also now handles
|
| 1744 |
|
|
* digit grouping (for the uClibc supported locales) and hexadecimal float
|
| 1745 |
|
|
* notation. Finally, via the fp_outfunc parameter, it now supports wide
|
| 1746 |
|
|
* output.
|
| 1747 |
|
|
*
|
| 1748 |
|
|
* Notes:
|
| 1749 |
|
|
*
|
| 1750 |
|
|
* At most DECIMAL_DIG significant digits are kept. Any trailing digits
|
| 1751 |
|
|
* are treated as 0 as they are really just the results of rounding noise
|
| 1752 |
|
|
* anyway. If you want to do better, use an arbitary precision arithmetic
|
| 1753 |
|
|
* package. ;-)
|
| 1754 |
|
|
*
|
| 1755 |
|
|
* It should also be fairly portable, as no assumptions are made about the
|
| 1756 |
|
|
* bit-layout of doubles. Of course, that does make it less efficient than
|
| 1757 |
|
|
* it could be.
|
| 1758 |
|
|
*
|
| 1759 |
|
|
*/
|
| 1760 |
|
|
|
| 1761 |
|
|
/*****************************************************************************/
|
| 1762 |
|
|
/* Don't change anything that follows unless you know what you're doing. */
|
| 1763 |
|
|
/*****************************************************************************/
|
| 1764 |
|
|
/* Fairly portable nan check. Bitwise for i386 generated larger code.
|
| 1765 |
|
|
* If you have a better version, comment this out.
|
| 1766 |
|
|
*/
|
| 1767 |
|
|
#define isnan(x) ((x) != (x))
|
| 1768 |
|
|
|
| 1769 |
|
|
/* Without seminumerical functions to examine the sign bit, this is
|
| 1770 |
|
|
* about the best we can do to test for '-0'.
|
| 1771 |
|
|
*/
|
| 1772 |
|
|
#define zeroisnegative(x) ((1./(x)) < 0)
|
| 1773 |
|
|
|
| 1774 |
|
|
/*****************************************************************************/
|
| 1775 |
|
|
/* Don't change anything that follows peroid!!! ;-) */
|
| 1776 |
|
|
/*****************************************************************************/
|
| 1777 |
|
|
#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
|
| 1778 |
|
|
#if FLT_RADIX != 2
|
| 1779 |
|
|
#error FLT_RADIX != 2 is not currently supported
|
| 1780 |
|
|
#endif
|
| 1781 |
|
|
#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
|
| 1782 |
|
|
|
| 1783 |
|
|
#define NUM_HEX_DIGITS ((FPMAX_MANT_DIG + 3)/ 4)
|
| 1784 |
|
|
|
| 1785 |
|
|
/* WARNING: Adjust _fp_out_wide() below if this changes! */
|
| 1786 |
|
|
/* With 32 bit ints, we can get 9 decimal digits per block. */
|
| 1787 |
|
|
#define DIGITS_PER_BLOCK 9
|
| 1788 |
|
|
#define HEX_DIGITS_PER_BLOCK 8
|
| 1789 |
|
|
|
| 1790 |
|
|
/* Maximum number of subcases to output double is...
|
| 1791 |
|
|
* 0 - sign
|
| 1792 |
|
|
* 1 - padding and initial digit
|
| 1793 |
|
|
* 2 - digits left of the radix
|
| 1794 |
|
|
* 3 - 0s left of the radix or radix
|
| 1795 |
|
|
* 4 - radix or digits right of the radix
|
| 1796 |
|
|
* 5 - 0s right of the radix
|
| 1797 |
|
|
* 6 - exponent
|
| 1798 |
|
|
* 7 - trailing space padding
|
| 1799 |
|
|
* although not all cases may occur.
|
| 1800 |
|
|
*/
|
| 1801 |
|
|
#define MAX_CALLS 8
|
| 1802 |
|
|
|
| 1803 |
|
|
/*****************************************************************************/
|
| 1804 |
|
|
|
| 1805 |
|
|
#define NUM_DIGIT_BLOCKS ((DECIMAL_DIG+DIGITS_PER_BLOCK-1)/DIGITS_PER_BLOCK)
|
| 1806 |
|
|
#define NUM_HEX_DIGIT_BLOCKS \
|
| 1807 |
|
|
((NUM_HEX_DIGITS+HEX_DIGITS_PER_BLOCK-1)/HEX_DIGITS_PER_BLOCK)
|
| 1808 |
|
|
|
| 1809 |
|
|
/* WARNING: Adjust _fp_out_wide() below if this changes! */
|
| 1810 |
|
|
|
| 1811 |
|
|
/* extra space for '-', '.', 'e+###', and nul */
|
| 1812 |
|
|
#define BUF_SIZE ( 3 + NUM_DIGIT_BLOCKS * DIGITS_PER_BLOCK )
|
| 1813 |
|
|
|
| 1814 |
|
|
/*****************************************************************************/
|
| 1815 |
|
|
|
| 1816 |
|
|
static const char fmt[] = "inf\0INF\0nan\0NAN\0.\0,";
|
| 1817 |
|
|
|
| 1818 |
|
|
#define INF_OFFSET 0 /* must be 1st */
|
| 1819 |
|
|
#define NAN_OFFSET 8 /* must be 2nd.. see hex sign handling */
|
| 1820 |
|
|
#define DECPT_OFFSET 16
|
| 1821 |
|
|
#define THOUSEP_OFFSET 18
|
| 1822 |
|
|
|
| 1823 |
|
|
#define EMPTY_STRING_OFFSET 3
|
| 1824 |
|
|
|
| 1825 |
|
|
/*****************************************************************************/
|
| 1826 |
|
|
#if FPMAX_MAX_10_EXP < -FPMAX_MIN_10_EXP
|
| 1827 |
|
|
#error scaling code can not handle FPMAX_MAX_10_EXP < -FPMAX_MIN_10_EXP
|
| 1828 |
|
|
#endif
|
| 1829 |
|
|
|
| 1830 |
|
|
static const __fpmax_t exp10_table[] =
|
| 1831 |
|
|
{
|
| 1832 |
|
|
1e1L, 1e2L, 1e4L, 1e8L, 1e16L, 1e32L, /* floats */
|
| 1833 |
|
|
#if FPMAX_MAX_10_EXP < 32
|
| 1834 |
|
|
#error unsupported FPMAX_MAX_10_EXP (< 32). ANSI/ISO C requires >= 37.
|
| 1835 |
|
|
#endif
|
| 1836 |
|
|
#if FPMAX_MAX_10_EXP >= 64
|
| 1837 |
|
|
1e64L,
|
| 1838 |
|
|
#endif
|
| 1839 |
|
|
#if FPMAX_MAX_10_EXP >= 128
|
| 1840 |
|
|
1e128L,
|
| 1841 |
|
|
#endif
|
| 1842 |
|
|
#if FPMAX_MAX_10_EXP >= 256
|
| 1843 |
|
|
1e256L,
|
| 1844 |
|
|
#endif
|
| 1845 |
|
|
#if FPMAX_MAX_10_EXP >= 512
|
| 1846 |
|
|
1e512L,
|
| 1847 |
|
|
#endif
|
| 1848 |
|
|
#if FPMAX_MAX_10_EXP >= 1024
|
| 1849 |
|
|
1e1024L,
|
| 1850 |
|
|
#endif
|
| 1851 |
|
|
#if FPMAX_MAX_10_EXP >= 2048
|
| 1852 |
|
|
1e2048L,
|
| 1853 |
|
|
#endif
|
| 1854 |
|
|
#if FPMAX_MAX_10_EXP >= 4096
|
| 1855 |
|
|
1e4096L
|
| 1856 |
|
|
#endif
|
| 1857 |
|
|
#if FPMAX_MAX_10_EXP >= 8192
|
| 1858 |
|
|
#error unsupported FPMAX_MAX_10_EXP. please increase table
|
| 1859 |
|
|
#endif
|
| 1860 |
|
|
};
|
| 1861 |
|
|
|
| 1862 |
|
|
#define EXP10_TABLE_SIZE (sizeof(exp10_table)/sizeof(exp10_table[0]))
|
| 1863 |
|
|
#define EXP10_TABLE_MAX (1U<<(EXP10_TABLE_SIZE-1))
|
| 1864 |
|
|
|
| 1865 |
|
|
/*****************************************************************************/
|
| 1866 |
|
|
#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
|
| 1867 |
|
|
|
| 1868 |
|
|
#if FLT_RADIX != 2
|
| 1869 |
|
|
#error FLT_RADIX != 2 is not currently supported
|
| 1870 |
|
|
#endif
|
| 1871 |
|
|
|
| 1872 |
|
|
#if FPMAX_MAX_EXP < -FPMAX_MIN_EXP
|
| 1873 |
|
|
#error scaling code can not handle FPMAX_MAX_EXP < -FPMAX_MIN_EXP
|
| 1874 |
|
|
#endif
|
| 1875 |
|
|
|
| 1876 |
|
|
static const __fpmax_t exp16_table[] = {
|
| 1877 |
|
|
0x1.0p4L, 0x1.0p8L, 0x1.0p16L, 0x1.0p32L, 0x1.0p64L,
|
| 1878 |
|
|
#if FPMAX_MAX_EXP >= 128
|
| 1879 |
|
|
0x1.0p128L,
|
| 1880 |
|
|
#endif
|
| 1881 |
|
|
#if FPMAX_MAX_EXP >= 256
|
| 1882 |
|
|
0x1.0p256L,
|
| 1883 |
|
|
#endif
|
| 1884 |
|
|
#if FPMAX_MAX_EXP >= 512
|
| 1885 |
|
|
0x1.0p512L,
|
| 1886 |
|
|
#endif
|
| 1887 |
|
|
#if FPMAX_MAX_EXP >= 1024
|
| 1888 |
|
|
0x1.0p1024L,
|
| 1889 |
|
|
#endif
|
| 1890 |
|
|
#if FPMAX_MAX_EXP >= 2048
|
| 1891 |
|
|
0x1.0p2048L,
|
| 1892 |
|
|
#endif
|
| 1893 |
|
|
#if FPMAX_MAX_EXP >= 4096
|
| 1894 |
|
|
0x1.0p4096L,
|
| 1895 |
|
|
#endif
|
| 1896 |
|
|
#if FPMAX_MAX_EXP >= 8192
|
| 1897 |
|
|
0x1.0p8192L,
|
| 1898 |
|
|
#endif
|
| 1899 |
|
|
#if FPMAX_MAX_EXP >= 16384
|
| 1900 |
|
|
0x1.0p16384L
|
| 1901 |
|
|
#endif
|
| 1902 |
|
|
#if FPMAX_MAX_EXP >= 32768
|
| 1903 |
|
|
#error unsupported FPMAX_MAX_EXP. please increase table
|
| 1904 |
|
|
#endif
|
| 1905 |
|
|
};
|
| 1906 |
|
|
|
| 1907 |
|
|
#define EXP16_TABLE_SIZE (sizeof(exp16_table)/sizeof(exp16_table[0]))
|
| 1908 |
|
|
#define EXP16_TABLE_MAX (1U<<(EXP16_TABLE_SIZE-1))
|
| 1909 |
|
|
|
| 1910 |
|
|
#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
|
| 1911 |
|
|
/*****************************************************************************/
|
| 1912 |
|
|
|
| 1913 |
|
|
#define FPO_ZERO_PAD (0x80 | '0')
|
| 1914 |
|
|
#define FPO_STR_WIDTH (0x80 | ' ');
|
| 1915 |
|
|
#define FPO_STR_PREC 'p'
|
| 1916 |
|
|
|
| 1917 |
|
|
size_t _fpmaxtostr(FILE * fp, __fpmax_t x, struct printf_info *info,
|
| 1918 |
|
|
__fp_outfunc_t fp_outfunc)
|
| 1919 |
|
|
{
|
| 1920 |
|
|
#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
|
| 1921 |
|
|
__fpmax_t lower_bnd;
|
| 1922 |
|
|
__fpmax_t upper_bnd = 1e9;
|
| 1923 |
|
|
#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
|
| 1924 |
|
|
uint_fast32_t digit_block;
|
| 1925 |
|
|
#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
|
| 1926 |
|
|
uint_fast32_t base = 10;
|
| 1927 |
|
|
const __fpmax_t *power_table;
|
| 1928 |
|
|
int dpb = DIGITS_PER_BLOCK;
|
| 1929 |
|
|
int ndb = NUM_DIGIT_BLOCKS;
|
| 1930 |
|
|
int nd = DECIMAL_DIG;
|
| 1931 |
|
|
int sufficient_precision = 0;
|
| 1932 |
|
|
#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
|
| 1933 |
|
|
#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
|
| 1934 |
|
|
int num_groups = 0;
|
| 1935 |
|
|
int initial_group; /* This does not need to be initialized. */
|
| 1936 |
|
|
int tslen; /* This does not need to be initialized. */
|
| 1937 |
|
|
int nblk2; /* This does not need to be initialized. */
|
| 1938 |
|
|
const char *ts; /* This does not need to be initialized. */
|
| 1939 |
|
|
#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
|
| 1940 |
|
|
int i, j;
|
| 1941 |
|
|
int round, o_exp;
|
| 1942 |
|
|
int exp, exp_neg;
|
| 1943 |
|
|
int width, preci;
|
| 1944 |
|
|
int cnt;
|
| 1945 |
|
|
char *s;
|
| 1946 |
|
|
char *e;
|
| 1947 |
|
|
intptr_t pc_fwi[3*MAX_CALLS];
|
| 1948 |
|
|
intptr_t *ppc;
|
| 1949 |
|
|
intptr_t *ppc_last;
|
| 1950 |
|
|
#ifdef __UCLIBC_MJN3_ONLY__
|
| 1951 |
|
|
#warning TODO: The size of exp_buf[] should really be determined by the float constants.
|
| 1952 |
|
|
#endif /* __UCLIBC_MJN3_ONLY__ */
|
| 1953 |
|
|
char exp_buf[16];
|
| 1954 |
|
|
char buf[BUF_SIZE];
|
| 1955 |
|
|
char sign_str[6]; /* Last 2 are for 1st digit + nul. */
|
| 1956 |
|
|
char o_mode;
|
| 1957 |
|
|
char mode;
|
| 1958 |
|
|
|
| 1959 |
|
|
|
| 1960 |
|
|
width = info->width;
|
| 1961 |
|
|
preci = info->prec;
|
| 1962 |
|
|
mode = info->spec;
|
| 1963 |
|
|
|
| 1964 |
|
|
*exp_buf = 'e';
|
| 1965 |
|
|
if ((mode|0x20) == 'a') {
|
| 1966 |
|
|
#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
|
| 1967 |
|
|
*exp_buf = 'p';
|
| 1968 |
|
|
if (preci < 0) {
|
| 1969 |
|
|
preci = NUM_HEX_DIGITS;
|
| 1970 |
|
|
sufficient_precision = 1;
|
| 1971 |
|
|
}
|
| 1972 |
|
|
#else
|
| 1973 |
|
|
mode += ('g' - 'a');
|
| 1974 |
|
|
#endif
|
| 1975 |
|
|
}
|
| 1976 |
|
|
|
| 1977 |
|
|
if (preci < 0) {
|
| 1978 |
|
|
preci = 6;
|
| 1979 |
|
|
}
|
| 1980 |
|
|
|
| 1981 |
|
|
*sign_str = '\0';
|
| 1982 |
|
|
if (PRINT_INFO_FLAG_VAL(info,showsign)) {
|
| 1983 |
|
|
*sign_str = '+';
|
| 1984 |
|
|
} else if (PRINT_INFO_FLAG_VAL(info,space)) {
|
| 1985 |
|
|
*sign_str = ' ';
|
| 1986 |
|
|
}
|
| 1987 |
|
|
|
| 1988 |
|
|
*(sign_str+1) = 0;
|
| 1989 |
|
|
pc_fwi[5] = INF_OFFSET;
|
| 1990 |
|
|
if (isnan(x)) { /* First, check for nan. */
|
| 1991 |
|
|
pc_fwi[5] = NAN_OFFSET;
|
| 1992 |
|
|
goto INF_NAN;
|
| 1993 |
|
|
}
|
| 1994 |
|
|
|
| 1995 |
|
|
if (x == 0) { /* Handle 0 now to avoid false positive. */
|
| 1996 |
|
|
#if 1
|
| 1997 |
|
|
if (zeroisnegative(x)) { /* Handle 'signed' zero. */
|
| 1998 |
|
|
*sign_str = '-';
|
| 1999 |
|
|
}
|
| 2000 |
|
|
#endif
|
| 2001 |
|
|
exp = -1;
|
| 2002 |
|
|
goto GENERATE_DIGITS;
|
| 2003 |
|
|
}
|
| 2004 |
|
|
|
| 2005 |
|
|
if (x < 0) { /* Convert negatives to positives. */
|
| 2006 |
|
|
*sign_str = '-';
|
| 2007 |
|
|
x = -x;
|
| 2008 |
|
|
}
|
| 2009 |
|
|
|
| 2010 |
|
|
if (__FPMAX_ZERO_OR_INF_CHECK(x)) { /* Inf since zero handled above. */
|
| 2011 |
|
|
INF_NAN:
|
| 2012 |
|
|
info->pad = ' ';
|
| 2013 |
|
|
ppc = pc_fwi + 6;
|
| 2014 |
|
|
pc_fwi[3] = FPO_STR_PREC;
|
| 2015 |
|
|
pc_fwi[4] = 3;
|
| 2016 |
|
|
if (mode < 'a') {
|
| 2017 |
|
|
pc_fwi[5] += 4;
|
| 2018 |
|
|
}
|
| 2019 |
|
|
pc_fwi[5] = (intptr_t)(fmt + pc_fwi[5]);
|
| 2020 |
|
|
goto EXIT_SPECIAL;
|
| 2021 |
|
|
}
|
| 2022 |
|
|
|
| 2023 |
|
|
#ifdef __UCLIBC_MJN3_ONLY__
|
| 2024 |
|
|
#warning TODO: Clean up defines when hexadecimal float notation is unsupported.
|
| 2025 |
|
|
#endif /* __UCLIBC_MJN3_ONLY__ */
|
| 2026 |
|
|
|
| 2027 |
|
|
#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
|
| 2028 |
|
|
|
| 2029 |
|
|
if ((mode|0x20) == 'a') {
|
| 2030 |
|
|
lower_bnd = 0x1.0p31L;
|
| 2031 |
|
|
upper_bnd = 0x1.0p32L;
|
| 2032 |
|
|
power_table = exp16_table;
|
| 2033 |
|
|
exp = HEX_DIGITS_PER_BLOCK - 1;
|
| 2034 |
|
|
i = EXP16_TABLE_SIZE;
|
| 2035 |
|
|
j = EXP16_TABLE_MAX;
|
| 2036 |
|
|
dpb = HEX_DIGITS_PER_BLOCK;
|
| 2037 |
|
|
ndb = NUM_HEX_DIGIT_BLOCKS;
|
| 2038 |
|
|
nd = NUM_HEX_DIGITS;
|
| 2039 |
|
|
base = 16;
|
| 2040 |
|
|
} else {
|
| 2041 |
|
|
lower_bnd = 1e8;
|
| 2042 |
|
|
/* upper_bnd = 1e9; */
|
| 2043 |
|
|
power_table = exp10_table;
|
| 2044 |
|
|
exp = DIGITS_PER_BLOCK - 1;
|
| 2045 |
|
|
i = EXP10_TABLE_SIZE;
|
| 2046 |
|
|
j = EXP10_TABLE_MAX;
|
| 2047 |
|
|
/* dpb = DIGITS_PER_BLOCK; */
|
| 2048 |
|
|
/* ndb = NUM_DIGIT_BLOCKS; */
|
| 2049 |
|
|
/* base = 10; */
|
| 2050 |
|
|
}
|
| 2051 |
|
|
|
| 2052 |
|
|
|
| 2053 |
|
|
|
| 2054 |
|
|
#else /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
|
| 2055 |
|
|
|
| 2056 |
|
|
#define lower_bnd 1e8
|
| 2057 |
|
|
#define upper_bnd 1e9
|
| 2058 |
|
|
#define power_table exp10_table
|
| 2059 |
|
|
#define dpb DIGITS_PER_BLOCK
|
| 2060 |
|
|
#define base 10
|
| 2061 |
|
|
#define ndb NUM_DIGIT_BLOCKS
|
| 2062 |
|
|
#define nd DECIMAL_DIG
|
| 2063 |
|
|
|
| 2064 |
|
|
exp = DIGITS_PER_BLOCK - 1;
|
| 2065 |
|
|
i = EXP10_TABLE_SIZE;
|
| 2066 |
|
|
j = EXP10_TABLE_MAX;
|
| 2067 |
|
|
|
| 2068 |
|
|
#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
|
| 2069 |
|
|
|
| 2070 |
|
|
exp_neg = 0;
|
| 2071 |
|
|
if (x < lower_bnd) { /* Do we need to scale up or down? */
|
| 2072 |
|
|
exp_neg = 1;
|
| 2073 |
|
|
}
|
| 2074 |
|
|
|
| 2075 |
|
|
do {
|
| 2076 |
|
|
--i;
|
| 2077 |
|
|
if (exp_neg) {
|
| 2078 |
|
|
if (x * power_table[i] < upper_bnd) {
|
| 2079 |
|
|
x *= power_table[i];
|
| 2080 |
|
|
exp -= j;
|
| 2081 |
|
|
}
|
| 2082 |
|
|
} else {
|
| 2083 |
|
|
if (x / power_table[i] >= lower_bnd) {
|
| 2084 |
|
|
x /= power_table[i];
|
| 2085 |
|
|
exp += j;
|
| 2086 |
|
|
}
|
| 2087 |
|
|
}
|
| 2088 |
|
|
j >>= 1;
|
| 2089 |
|
|
} while (i);
|
| 2090 |
|
|
if (x >= upper_bnd) { /* Handle bad rounding case. */
|
| 2091 |
|
|
x /= power_table[0];
|
| 2092 |
|
|
++exp;
|
| 2093 |
|
|
}
|
| 2094 |
|
|
assert(x < upper_bnd);
|
| 2095 |
|
|
|
| 2096 |
|
|
GENERATE_DIGITS:
|
| 2097 |
|
|
s = buf + 2; /* Leave space for '\0' and '0'. */
|
| 2098 |
|
|
i = 0;
|
| 2099 |
|
|
do {
|
| 2100 |
|
|
digit_block = (uint_fast32_t) x;
|
| 2101 |
|
|
assert(digit_block < upper_bnd);
|
| 2102 |
|
|
#ifdef __UCLIBC_MJN3_ONLY__
|
| 2103 |
|
|
#warning CONSIDER: Can rounding be a problem?
|
| 2104 |
|
|
#endif /* __UCLIBC_MJN3_ONLY__ */
|
| 2105 |
|
|
x = (x - digit_block) * upper_bnd;
|
| 2106 |
|
|
s += dpb;
|
| 2107 |
|
|
j = 0;
|
| 2108 |
|
|
do {
|
| 2109 |
|
|
s[- ++j] = '0' + (digit_block % base);
|
| 2110 |
|
|
digit_block /= base;
|
| 2111 |
|
|
} while (j < dpb);
|
| 2112 |
|
|
} while (++i < ndb);
|
| 2113 |
|
|
|
| 2114 |
|
|
/*************************************************************************/
|
| 2115 |
|
|
|
| 2116 |
|
|
if (mode < 'a') {
|
| 2117 |
|
|
*exp_buf -= ('a' - 'A'); /* e->E and p->P */
|
| 2118 |
|
|
mode += ('a' - 'A');
|
| 2119 |
|
|
}
|
| 2120 |
|
|
|
| 2121 |
|
|
o_mode = mode;
|
| 2122 |
|
|
if ((mode == 'g') && (preci > 0)){
|
| 2123 |
|
|
--preci;
|
| 2124 |
|
|
}
|
| 2125 |
|
|
round = preci;
|
| 2126 |
|
|
|
| 2127 |
|
|
if (mode == 'f') {
|
| 2128 |
|
|
round += exp;
|
| 2129 |
|
|
if (round < -1) {
|
| 2130 |
|
|
memset(buf, '0', DECIMAL_DIG); /* OK, since 'f' -> decimal case. */
|
| 2131 |
|
|
exp = -1;
|
| 2132 |
|
|
round = -1;
|
| 2133 |
|
|
}
|
| 2134 |
|
|
}
|
| 2135 |
|
|
|
| 2136 |
|
|
s = buf;
|
| 2137 |
|
|
*s++ = 0; /* Terminator for rounding and 0-triming. */
|
| 2138 |
|
|
*s = '0'; /* Space to round. */
|
| 2139 |
|
|
|
| 2140 |
|
|
i = 0;
|
| 2141 |
|
|
e = s + nd + 1;
|
| 2142 |
|
|
if (round < nd) {
|
| 2143 |
|
|
e = s + round + 2;
|
| 2144 |
|
|
if (*e >= '0' + (base/2)) { /* NOTE: We always round away from 0! */
|
| 2145 |
|
|
i = 1;
|
| 2146 |
|
|
}
|
| 2147 |
|
|
}
|
| 2148 |
|
|
|
| 2149 |
|
|
do { /* Handle rounding and trim trailing 0s. */
|
| 2150 |
|
|
*--e += i; /* Add the carry. */
|
| 2151 |
|
|
} while ((*e == '0') || (*e > '0' - 1 + base));
|
| 2152 |
|
|
|
| 2153 |
|
|
#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
|
| 2154 |
|
|
if ((mode|0x20) == 'a') {
|
| 2155 |
|
|
char *q;
|
| 2156 |
|
|
|
| 2157 |
|
|
for (q = e ; *q ; --q) {
|
| 2158 |
|
|
if (*q > '9') {
|
| 2159 |
|
|
*q += (*exp_buf - ('p' - 'a') - '9' - 1);
|
| 2160 |
|
|
}
|
| 2161 |
|
|
}
|
| 2162 |
|
|
|
| 2163 |
|
|
if (e > s) {
|
| 2164 |
|
|
exp *= 4; /* Change from base 16 to base 2. */
|
| 2165 |
|
|
}
|
| 2166 |
|
|
}
|
| 2167 |
|
|
#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
|
| 2168 |
|
|
|
| 2169 |
|
|
o_exp = exp;
|
| 2170 |
|
|
if (e <= s) { /* We carried into an extra digit. */
|
| 2171 |
|
|
++o_exp;
|
| 2172 |
|
|
e = s; /* Needed if all 0s. */
|
| 2173 |
|
|
} else {
|
| 2174 |
|
|
++s;
|
| 2175 |
|
|
}
|
| 2176 |
|
|
*++e = 0; /* Terminating nul char. */
|
| 2177 |
|
|
|
| 2178 |
|
|
if ((mode == 'g') && ((o_exp >= -4) && (o_exp <= round))) {
|
| 2179 |
|
|
mode = 'f';
|
| 2180 |
|
|
preci = round - o_exp;
|
| 2181 |
|
|
}
|
| 2182 |
|
|
|
| 2183 |
|
|
exp = o_exp;
|
| 2184 |
|
|
if (mode != 'f') {
|
| 2185 |
|
|
o_exp = 0;
|
| 2186 |
|
|
}
|
| 2187 |
|
|
|
| 2188 |
|
|
if (o_exp < 0) { /* Exponent is < 0, so */
|
| 2189 |
|
|
*--s = '0'; /* fake the first 0 digit. */
|
| 2190 |
|
|
}
|
| 2191 |
|
|
|
| 2192 |
|
|
pc_fwi[3] = FPO_ZERO_PAD;
|
| 2193 |
|
|
pc_fwi[4] = 1;
|
| 2194 |
|
|
pc_fwi[5] = (intptr_t)(sign_str + 4);
|
| 2195 |
|
|
sign_str[4] = *s++;
|
| 2196 |
|
|
sign_str[5] = 0;
|
| 2197 |
|
|
ppc = pc_fwi + 6;
|
| 2198 |
|
|
|
| 2199 |
|
|
i = e - s; /* Total digits is 'i'. */
|
| 2200 |
|
|
if (o_exp >= 0) {
|
| 2201 |
|
|
#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
|
| 2202 |
|
|
|
| 2203 |
|
|
const char *p;
|
| 2204 |
|
|
|
| 2205 |
|
|
if (PRINT_INFO_FLAG_VAL(info,group)
|
| 2206 |
|
|
&& *(p = __UCLIBC_CURLOCALE_DATA.grouping)
|
| 2207 |
|
|
) {
|
| 2208 |
|
|
int nblk1;
|
| 2209 |
|
|
|
| 2210 |
|
|
nblk2 = nblk1 = *p;
|
| 2211 |
|
|
if (*++p) {
|
| 2212 |
|
|
nblk2 = *p;
|
| 2213 |
|
|
assert(!*++p);
|
| 2214 |
|
|
}
|
| 2215 |
|
|
|
| 2216 |
|
|
if (o_exp >= nblk1) {
|
| 2217 |
|
|
num_groups = (o_exp - nblk1) / nblk2 + 1;
|
| 2218 |
|
|
initial_group = (o_exp - nblk1) % nblk2;
|
| 2219 |
|
|
|
| 2220 |
|
|
#ifdef __UCLIBC_HAS_WCHAR__
|
| 2221 |
|
|
if (PRINT_INFO_FLAG_VAL(info,wide)) {
|
| 2222 |
|
|
/* _fp_out_wide() will fix this up. */
|
| 2223 |
|
|
ts = fmt + THOUSEP_OFFSET;
|
| 2224 |
|
|
tslen = 1;
|
| 2225 |
|
|
} else {
|
| 2226 |
|
|
#endif /* __UCLIBC_HAS_WCHAR__ */
|
| 2227 |
|
|
ts = __UCLIBC_CURLOCALE_DATA.thousands_sep;
|
| 2228 |
|
|
tslen = __UCLIBC_CURLOCALE_DATA.thousands_sep_len;
|
| 2229 |
|
|
#ifdef __UCLIBC_HAS_WCHAR__
|
| 2230 |
|
|
}
|
| 2231 |
|
|
#endif /* __UCLIBC_HAS_WCHAR__ */
|
| 2232 |
|
|
|
| 2233 |
|
|
width -= num_groups * tslen;
|
| 2234 |
|
|
}
|
| 2235 |
|
|
}
|
| 2236 |
|
|
|
| 2237 |
|
|
|
| 2238 |
|
|
#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
|
| 2239 |
|
|
ppc[0] = FPO_STR_PREC;
|
| 2240 |
|
|
ppc[2] = (intptr_t)(s);
|
| 2241 |
|
|
if (o_exp >= i) { /* all digit(s) left of decimal */
|
| 2242 |
|
|
ppc[1] = i;
|
| 2243 |
|
|
ppc += 3;
|
| 2244 |
|
|
o_exp -= i;
|
| 2245 |
|
|
i = 0;
|
| 2246 |
|
|
if (o_exp>0) { /* have 0s left of decimal */
|
| 2247 |
|
|
ppc[0] = FPO_ZERO_PAD;
|
| 2248 |
|
|
ppc[1] = o_exp;
|
| 2249 |
|
|
ppc[2] = (intptr_t)(fmt + EMPTY_STRING_OFFSET);
|
| 2250 |
|
|
ppc += 3;
|
| 2251 |
|
|
}
|
| 2252 |
|
|
} else if (o_exp > 0) { /* decimal between digits */
|
| 2253 |
|
|
ppc[1] = o_exp;
|
| 2254 |
|
|
ppc += 3;
|
| 2255 |
|
|
s += o_exp;
|
| 2256 |
|
|
i -= o_exp;
|
| 2257 |
|
|
}
|
| 2258 |
|
|
o_exp = -1;
|
| 2259 |
|
|
}
|
| 2260 |
|
|
|
| 2261 |
|
|
if (PRINT_INFO_FLAG_VAL(info,alt)
|
| 2262 |
|
|
|| (i)
|
| 2263 |
|
|
|| ((o_mode != 'g')
|
| 2264 |
|
|
#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
|
| 2265 |
|
|
&& (o_mode != 'a')
|
| 2266 |
|
|
#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
|
| 2267 |
|
|
&& (preci > 0))
|
| 2268 |
|
|
) {
|
| 2269 |
|
|
ppc[0] = FPO_STR_PREC;
|
| 2270 |
|
|
#ifdef __LOCALE_C_ONLY
|
| 2271 |
|
|
ppc[1] = 1;
|
| 2272 |
|
|
ppc[2] = (intptr_t)(fmt + DECPT_OFFSET);
|
| 2273 |
|
|
#else /* __LOCALE_C_ONLY */
|
| 2274 |
|
|
#ifdef __UCLIBC_HAS_WCHAR__
|
| 2275 |
|
|
if (PRINT_INFO_FLAG_VAL(info,wide)) {
|
| 2276 |
|
|
/* _fp_out_wide() will fix this up. */
|
| 2277 |
|
|
ppc[1] = 1;
|
| 2278 |
|
|
ppc[2] = (intptr_t)(fmt + DECPT_OFFSET);
|
| 2279 |
|
|
} else {
|
| 2280 |
|
|
#endif /* __UCLIBC_HAS_WCHAR__ */
|
| 2281 |
|
|
ppc[1] = __UCLIBC_CURLOCALE_DATA.decimal_point_len;
|
| 2282 |
|
|
ppc[2] = (intptr_t)(__UCLIBC_CURLOCALE_DATA.decimal_point);
|
| 2283 |
|
|
#ifdef __UCLIBC_HAS_WCHAR__
|
| 2284 |
|
|
}
|
| 2285 |
|
|
#endif /* __UCLIBC_HAS_WCHAR__ */
|
| 2286 |
|
|
#endif /* __LOCALE_C_ONLY */
|
| 2287 |
|
|
ppc += 3;
|
| 2288 |
|
|
}
|
| 2289 |
|
|
|
| 2290 |
|
|
if (++o_exp < 0) { /* Have 0s right of decimal. */
|
| 2291 |
|
|
ppc[0] = FPO_ZERO_PAD;
|
| 2292 |
|
|
ppc[1] = -o_exp;
|
| 2293 |
|
|
ppc[2] = (intptr_t)(fmt + EMPTY_STRING_OFFSET);
|
| 2294 |
|
|
ppc += 3;
|
| 2295 |
|
|
}
|
| 2296 |
|
|
if (i) { /* Have digit(s) right of decimal. */
|
| 2297 |
|
|
ppc[0] = FPO_STR_PREC;
|
| 2298 |
|
|
ppc[1] = i;
|
| 2299 |
|
|
ppc[2] = (intptr_t)(s);
|
| 2300 |
|
|
ppc += 3;
|
| 2301 |
|
|
}
|
| 2302 |
|
|
|
| 2303 |
|
|
if (((o_mode != 'g') || PRINT_INFO_FLAG_VAL(info,alt))
|
| 2304 |
|
|
#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
|
| 2305 |
|
|
&& !sufficient_precision
|
| 2306 |
|
|
#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
|
| 2307 |
|
|
) {
|
| 2308 |
|
|
i -= o_exp;
|
| 2309 |
|
|
if (i < preci) { /* Have 0s right of digits. */
|
| 2310 |
|
|
i = preci - i;
|
| 2311 |
|
|
ppc[0] = FPO_ZERO_PAD;
|
| 2312 |
|
|
ppc[1] = i;
|
| 2313 |
|
|
ppc[2] = (intptr_t)(fmt + EMPTY_STRING_OFFSET);
|
| 2314 |
|
|
ppc += 3;
|
| 2315 |
|
|
}
|
| 2316 |
|
|
}
|
| 2317 |
|
|
|
| 2318 |
|
|
/* Build exponent string. */
|
| 2319 |
|
|
if (mode != 'f') {
|
| 2320 |
|
|
char *p = exp_buf + sizeof(exp_buf);
|
| 2321 |
|
|
char exp_char = *exp_buf;
|
| 2322 |
|
|
char exp_sign = '+';
|
| 2323 |
|
|
#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
|
| 2324 |
|
|
int min_exp_dig_plus_2 = ((o_mode != 'a') ? (2+2) : (2+1));
|
| 2325 |
|
|
#else /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
|
| 2326 |
|
|
#define min_exp_dig_plus_2 (2+2)
|
| 2327 |
|
|
#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
|
| 2328 |
|
|
|
| 2329 |
|
|
if (exp < 0) {
|
| 2330 |
|
|
exp_sign = '-';
|
| 2331 |
|
|
exp = -exp;
|
| 2332 |
|
|
}
|
| 2333 |
|
|
|
| 2334 |
|
|
*--p = 0; /* nul-terminate */
|
| 2335 |
|
|
j = 2; /* Count exp_char and exp_sign. */
|
| 2336 |
|
|
do {
|
| 2337 |
|
|
*--p = '0' + (exp % 10);
|
| 2338 |
|
|
exp /= 10;
|
| 2339 |
|
|
} while ((++j < min_exp_dig_plus_2) || exp); /* char+sign+mindigits */
|
| 2340 |
|
|
*--p = exp_sign;
|
| 2341 |
|
|
*--p = exp_char;
|
| 2342 |
|
|
|
| 2343 |
|
|
ppc[0] = FPO_STR_PREC;
|
| 2344 |
|
|
ppc[1] = j;
|
| 2345 |
|
|
ppc[2] = (intptr_t)(p);
|
| 2346 |
|
|
ppc += 3;
|
| 2347 |
|
|
}
|
| 2348 |
|
|
|
| 2349 |
|
|
EXIT_SPECIAL:
|
| 2350 |
|
|
ppc_last = ppc;
|
| 2351 |
|
|
ppc = pc_fwi + 4; /* Need width fields starting with second. */
|
| 2352 |
|
|
do {
|
| 2353 |
|
|
width -= *ppc;
|
| 2354 |
|
|
ppc += 3;
|
| 2355 |
|
|
} while (ppc < ppc_last);
|
| 2356 |
|
|
|
| 2357 |
|
|
ppc = pc_fwi;
|
| 2358 |
|
|
ppc[0] = FPO_STR_WIDTH;
|
| 2359 |
|
|
ppc[1] = i = ((*sign_str) != 0);
|
| 2360 |
|
|
ppc[2] = (intptr_t) sign_str;
|
| 2361 |
|
|
|
| 2362 |
|
|
#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
|
| 2363 |
|
|
if (((mode|0x20) == 'a') && (pc_fwi[3] >= 16)) { /* Hex sign handling. */
|
| 2364 |
|
|
/* Hex and not inf or nan, so prefix with 0x. */
|
| 2365 |
|
|
char *h = sign_str + i;
|
| 2366 |
|
|
*h = '0';
|
| 2367 |
|
|
*++h = 'x' - 'p' + *exp_buf;
|
| 2368 |
|
|
*++h = 0;
|
| 2369 |
|
|
ppc[1] = (i += 2);
|
| 2370 |
|
|
}
|
| 2371 |
|
|
#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
|
| 2372 |
|
|
|
| 2373 |
|
|
if ((width -= i) > 0) {
|
| 2374 |
|
|
if (PRINT_INFO_FLAG_VAL(info,left)) { /* Left-justified. */
|
| 2375 |
|
|
ppc_last[0] = FPO_STR_WIDTH;
|
| 2376 |
|
|
ppc_last[1] = width;
|
| 2377 |
|
|
ppc_last[2] = (intptr_t)(fmt + EMPTY_STRING_OFFSET);
|
| 2378 |
|
|
ppc_last += 3;
|
| 2379 |
|
|
} else if (info->pad == '0') { /* 0 padding */
|
| 2380 |
|
|
ppc[4] += width; /* Pad second field. */
|
| 2381 |
|
|
} else {
|
| 2382 |
|
|
ppc[1] += width; /* Pad first (sign) field. */
|
| 2383 |
|
|
}
|
| 2384 |
|
|
}
|
| 2385 |
|
|
|
| 2386 |
|
|
cnt = 0;
|
| 2387 |
|
|
|
| 2388 |
|
|
do {
|
| 2389 |
|
|
#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
|
| 2390 |
|
|
|
| 2391 |
|
|
if ((ppc == pc_fwi + 6) && num_groups) {
|
| 2392 |
|
|
const char *gp = (const char *) ppc[2];
|
| 2393 |
|
|
int len = ppc[1];
|
| 2394 |
|
|
int blk = initial_group;
|
| 2395 |
|
|
|
| 2396 |
|
|
cnt += num_groups * tslen; /* Adjust count now for sep chars. */
|
| 2397 |
|
|
|
| 2398 |
|
|
/* printf("\n"); */
|
| 2399 |
|
|
do {
|
| 2400 |
|
|
if (!blk) { /* Initial group could be 0 digits long! */
|
| 2401 |
|
|
blk = nblk2;
|
| 2402 |
|
|
} else if (len >= blk) { /* Enough digits for a group. */
|
| 2403 |
|
|
/* printf("norm: len=%d blk=%d \"%.*s\"\n", len, blk, blk, gp); */
|
| 2404 |
|
|
fp_outfunc(fp, *ppc, blk, (intptr_t) gp);
|
| 2405 |
|
|
assert(gp);
|
| 2406 |
|
|
if (*gp) {
|
| 2407 |
|
|
gp += blk;
|
| 2408 |
|
|
}
|
| 2409 |
|
|
len -= blk;
|
| 2410 |
|
|
} else { /* Transition to 0s. */
|
| 2411 |
|
|
/* printf("trans: len=%d blk=%d \"%.*s\"\n", len, blk, len, gp); */
|
| 2412 |
|
|
if (len) {
|
| 2413 |
|
|
/* printf("len\n"); */
|
| 2414 |
|
|
fp_outfunc(fp, *ppc, len, (intptr_t) gp);
|
| 2415 |
|
|
gp += len;
|
| 2416 |
|
|
}
|
| 2417 |
|
|
|
| 2418 |
|
|
if (ppc[3] == FPO_ZERO_PAD) { /* Need to group 0s */
|
| 2419 |
|
|
/* printf("zeropad\n"); */
|
| 2420 |
|
|
cnt += ppc[1];
|
| 2421 |
|
|
ppc += 3;
|
| 2422 |
|
|
gp = (const char *) ppc[2];
|
| 2423 |
|
|
blk -= len; /* blk > len, so blk still > 0. */
|
| 2424 |
|
|
len = ppc[1];
|
| 2425 |
|
|
continue; /* Don't decrement num_groups here. */
|
| 2426 |
|
|
} else {
|
| 2427 |
|
|
assert(num_groups == 0);
|
| 2428 |
|
|
break;
|
| 2429 |
|
|
}
|
| 2430 |
|
|
}
|
| 2431 |
|
|
|
| 2432 |
|
|
if (num_groups <= 0) {
|
| 2433 |
|
|
break;
|
| 2434 |
|
|
}
|
| 2435 |
|
|
--num_groups;
|
| 2436 |
|
|
|
| 2437 |
|
|
fp_outfunc(fp, FPO_STR_PREC, tslen, (intptr_t) ts);
|
| 2438 |
|
|
blk = nblk2;
|
| 2439 |
|
|
|
| 2440 |
|
|
/* printf("num_groups=%d blk=%d\n", num_groups, blk); */
|
| 2441 |
|
|
|
| 2442 |
|
|
} while (1);
|
| 2443 |
|
|
} else
|
| 2444 |
|
|
|
| 2445 |
|
|
#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
|
| 2446 |
|
|
|
| 2447 |
|
|
fp_outfunc(fp, *ppc, ppc[1], ppc[2]); /* NOTE: Remember 'else' above! */
|
| 2448 |
|
|
|
| 2449 |
|
|
cnt += ppc[1];
|
| 2450 |
|
|
ppc += 3;
|
| 2451 |
|
|
} while (ppc < ppc_last);
|
| 2452 |
|
|
|
| 2453 |
|
|
return cnt;
|
| 2454 |
|
|
}
|
| 2455 |
|
|
|
| 2456 |
|
|
#endif
|
| 2457 |
|
|
/**********************************************************************/
|
| 2458 |
|
|
#ifdef L__store_inttype
|
| 2459 |
|
|
|
| 2460 |
|
|
/* Right now, we assume intmax_t is either long or long long */
|
| 2461 |
|
|
|
| 2462 |
|
|
#ifdef INTMAX_MAX
|
| 2463 |
|
|
|
| 2464 |
|
|
#ifdef LLONG_MAX
|
| 2465 |
|
|
|
| 2466 |
|
|
#if INTMAX_MAX > LLONG_MAX
|
| 2467 |
|
|
#error INTMAX_MAX > LLONG_MAX! The printf code needs to be updated!
|
| 2468 |
|
|
#endif
|
| 2469 |
|
|
|
| 2470 |
|
|
#elif INTMAX_MAX > LONG_MAX
|
| 2471 |
|
|
|
| 2472 |
|
|
#error No LLONG_MAX and INTMAX_MAX > LONG_MAX! The printf code needs to be updated!
|
| 2473 |
|
|
|
| 2474 |
|
|
#endif /* LLONG_MAX */
|
| 2475 |
|
|
|
| 2476 |
|
|
#endif /* INTMAX_MAX */
|
| 2477 |
|
|
|
| 2478 |
|
|
/* We assume int may be short or long, but short and long are different. */
|
| 2479 |
|
|
|
| 2480 |
|
|
void _store_inttype(register void *dest, int desttype, uintmax_t val)
|
| 2481 |
|
|
{
|
| 2482 |
|
|
if (desttype == __PA_FLAG_CHAR) { /* assume char not int */
|
| 2483 |
|
|
*((unsigned char *) dest) = val;
|
| 2484 |
|
|
return;
|
| 2485 |
|
|
}
|
| 2486 |
|
|
#if defined(LLONG_MAX) && (LONG_MAX != LLONG_MAX)
|
| 2487 |
|
|
if (desttype == PA_FLAG_LONG_LONG) {
|
| 2488 |
|
|
*((unsigned long long int *) dest) = val;
|
| 2489 |
|
|
return;
|
| 2490 |
|
|
}
|
| 2491 |
|
|
#endif /* LLONG_MAX */
|
| 2492 |
|
|
#if SHRT_MAX != INT_MAX
|
| 2493 |
|
|
if (desttype == PA_FLAG_SHORT) {
|
| 2494 |
|
|
*((unsigned short int *) dest) = val;
|
| 2495 |
|
|
return;
|
| 2496 |
|
|
}
|
| 2497 |
|
|
#endif /* SHRT_MAX */
|
| 2498 |
|
|
#if LONG_MAX != INT_MAX
|
| 2499 |
|
|
if (desttype == PA_FLAG_LONG) {
|
| 2500 |
|
|
*((unsigned long int *) dest) = val;
|
| 2501 |
|
|
return;
|
| 2502 |
|
|
}
|
| 2503 |
|
|
#endif /* LONG_MAX */
|
| 2504 |
|
|
|
| 2505 |
|
|
*((unsigned int *) dest) = val;
|
| 2506 |
|
|
}
|
| 2507 |
|
|
|
| 2508 |
|
|
#endif
|
| 2509 |
|
|
/**********************************************************************/
|
| 2510 |
|
|
#ifdef L__load_inttype
|
| 2511 |
|
|
|
| 2512 |
|
|
extern uintmax_t _load_inttype(int desttype, register const void *src,
|
| 2513 |
|
|
int uflag)
|
| 2514 |
|
|
{
|
| 2515 |
|
|
if (uflag >= 0) { /* unsigned */
|
| 2516 |
|
|
#if LONG_MAX != INT_MAX
|
| 2517 |
|
|
if (desttype & (PA_FLAG_LONG|PA_FLAG_LONG_LONG)) {
|
| 2518 |
|
|
#ifdef LLONG_MAX
|
| 2519 |
|
|
if (desttype == PA_FLAG_LONG_LONG) {
|
| 2520 |
|
|
return *((unsigned long long int *) src);
|
| 2521 |
|
|
}
|
| 2522 |
|
|
#endif
|
| 2523 |
|
|
return *((unsigned long int *) src);
|
| 2524 |
|
|
}
|
| 2525 |
|
|
#else /* LONG_MAX != INT_MAX */
|
| 2526 |
|
|
#ifdef LLONG_MAX
|
| 2527 |
|
|
if (desttype & PA_FLAG_LONG_LONG) {
|
| 2528 |
|
|
return *((unsigned long long int *) src);
|
| 2529 |
|
|
}
|
| 2530 |
|
|
#endif
|
| 2531 |
|
|
#endif /* LONG_MAX != INT_MAX */
|
| 2532 |
|
|
{
|
| 2533 |
|
|
unsigned int x;
|
| 2534 |
|
|
x = *((unsigned int *) src);
|
| 2535 |
|
|
if (desttype == __PA_FLAG_CHAR) x = (unsigned char) x;
|
| 2536 |
|
|
#if SHRT_MAX != INT_MAX
|
| 2537 |
|
|
if (desttype == PA_FLAG_SHORT) x = (unsigned short int) x;
|
| 2538 |
|
|
#endif
|
| 2539 |
|
|
return x;
|
| 2540 |
|
|
}
|
| 2541 |
|
|
} else { /* signed */
|
| 2542 |
|
|
#if LONG_MAX != INT_MAX
|
| 2543 |
|
|
if (desttype & (PA_FLAG_LONG|PA_FLAG_LONG_LONG)) {
|
| 2544 |
|
|
#ifdef LLONG_MAX
|
| 2545 |
|
|
if (desttype == PA_FLAG_LONG_LONG) {
|
| 2546 |
|
|
return *((long long int *) src);
|
| 2547 |
|
|
}
|
| 2548 |
|
|
#endif
|
| 2549 |
|
|
return *((long int *) src);
|
| 2550 |
|
|
}
|
| 2551 |
|
|
#else /* LONG_MAX != INT_MAX */
|
| 2552 |
|
|
#ifdef LLONG_MAX
|
| 2553 |
|
|
if (desttype & PA_FLAG_LONG_LONG) {
|
| 2554 |
|
|
return *((long long int *) src);
|
| 2555 |
|
|
}
|
| 2556 |
|
|
#endif
|
| 2557 |
|
|
#endif /* LONG_MAX != INT_MAX */
|
| 2558 |
|
|
{
|
| 2559 |
|
|
int x;
|
| 2560 |
|
|
x = *((int *) src);
|
| 2561 |
|
|
if (desttype == __PA_FLAG_CHAR) x = (char) x;
|
| 2562 |
|
|
#if SHRT_MAX != INT_MAX
|
| 2563 |
|
|
if (desttype == PA_FLAG_SHORT) x = (short int) x;
|
| 2564 |
|
|
#endif
|
| 2565 |
|
|
return x;
|
| 2566 |
|
|
}
|
| 2567 |
|
|
}
|
| 2568 |
|
|
}
|
| 2569 |
|
|
|
| 2570 |
|
|
#endif
|
| 2571 |
|
|
/**********************************************************************/
|
| 2572 |
|
|
#if defined(L_vfprintf) || defined(L_vfwprintf)
|
| 2573 |
|
|
|
| 2574 |
|
|
/* We only support ascii digits (or their USC equivalent codes) in
|
| 2575 |
|
|
* precision and width settings in *printf (wide) format strings.
|
| 2576 |
|
|
* In other words, we don't currently support glibc's 'I' flag.
|
| 2577 |
|
|
* We do accept it, but it is currently ignored. */
|
| 2578 |
|
|
|
| 2579 |
|
|
static void _charpad(FILE * __restrict stream, int padchar, size_t numpad);
|
| 2580 |
|
|
|
| 2581 |
|
|
#ifdef L_vfprintf
|
| 2582 |
|
|
|
| 2583 |
|
|
#define VFPRINTF vfprintf
|
| 2584 |
|
|
#define FMT_TYPE char
|
| 2585 |
|
|
#define OUTNSTR _outnstr
|
| 2586 |
|
|
#define STRLEN strlen
|
| 2587 |
|
|
#define _PPFS_init _ppfs_init
|
| 2588 |
|
|
#define OUTPUT(F,S) fputs(S,F)
|
| 2589 |
|
|
#define _outnstr(stream, string, len) _stdio_fwrite(string, len, stream)
|
| 2590 |
|
|
#define FP_OUT _fp_out_narrow
|
| 2591 |
|
|
|
| 2592 |
|
|
#ifdef __STDIO_PRINTF_FLOAT
|
| 2593 |
|
|
|
| 2594 |
|
|
static void _fp_out_narrow(FILE *fp, intptr_t type, intptr_t len, intptr_t buf)
|
| 2595 |
|
|
{
|
| 2596 |
|
|
if (type & 0x80) { /* Some type of padding needed. */
|
| 2597 |
|
|
int buflen = strlen((const char *) buf);
|
| 2598 |
|
|
if ((len -= buflen) > 0) {
|
| 2599 |
|
|
_charpad(fp, (type & 0x7f), len);
|
| 2600 |
|
|
}
|
| 2601 |
|
|
len = buflen;
|
| 2602 |
|
|
}
|
| 2603 |
|
|
OUTNSTR(fp, (const char *) buf, len);
|
| 2604 |
|
|
}
|
| 2605 |
|
|
|
| 2606 |
|
|
#endif /* __STDIO_PRINTF_FLOAT */
|
| 2607 |
|
|
|
| 2608 |
|
|
#else /* L_vfprintf */
|
| 2609 |
|
|
|
| 2610 |
|
|
#define VFPRINTF vfwprintf
|
| 2611 |
|
|
#define FMT_TYPE wchar_t
|
| 2612 |
|
|
#define OUTNSTR _outnwcs
|
| 2613 |
|
|
#define STRLEN wcslen
|
| 2614 |
|
|
#define _PPFS_init _ppwfs_init
|
| 2615 |
|
|
#define OUTPUT(F,S) fputws(S,F)
|
| 2616 |
|
|
#define _outnwcs(stream, wstring, len) _wstdio_fwrite(wstring, len, stream)
|
| 2617 |
|
|
#define FP_OUT _fp_out_wide
|
| 2618 |
|
|
|
| 2619 |
|
|
static void _outnstr(FILE *stream, const char *s, size_t wclen)
|
| 2620 |
|
|
{
|
| 2621 |
|
|
/* NOTE!!! len here is the number of wchars we want to generate!!! */
|
| 2622 |
|
|
wchar_t wbuf[64];
|
| 2623 |
|
|
mbstate_t mbstate;
|
| 2624 |
|
|
size_t todo, r;
|
| 2625 |
|
|
|
| 2626 |
|
|
mbstate.mask = 0;
|
| 2627 |
|
|
todo = wclen;
|
| 2628 |
|
|
|
| 2629 |
|
|
while (todo) {
|
| 2630 |
|
|
r = mbsrtowcs(wbuf, &s,
|
| 2631 |
|
|
((todo <= sizeof(wbuf)/sizeof(wbuf[0]))
|
| 2632 |
|
|
? todo
|
| 2633 |
|
|
: sizeof(wbuf)/sizeof(wbuf[0])),
|
| 2634 |
|
|
&mbstate);
|
| 2635 |
|
|
assert(((ssize_t)r) > 0);
|
| 2636 |
|
|
_outnwcs(stream, wbuf, r);
|
| 2637 |
|
|
todo -= r;
|
| 2638 |
|
|
}
|
| 2639 |
|
|
}
|
| 2640 |
|
|
|
| 2641 |
|
|
#ifdef __STDIO_PRINTF_FLOAT
|
| 2642 |
|
|
|
| 2643 |
|
|
#ifdef __UCLIBC_MJN3_ONLY__
|
| 2644 |
|
|
#warning TODO: Move defines from _fpmaxtostr. Put them in a common header.
|
| 2645 |
|
|
#endif
|
| 2646 |
|
|
|
| 2647 |
|
|
/* The following defines are from _fpmaxtostr.*/
|
| 2648 |
|
|
#define DIGITS_PER_BLOCK 9
|
| 2649 |
|
|
#define NUM_DIGIT_BLOCKS ((DECIMAL_DIG+DIGITS_PER_BLOCK-1)/DIGITS_PER_BLOCK)
|
| 2650 |
|
|
#define BUF_SIZE ( 3 + NUM_DIGIT_BLOCKS * DIGITS_PER_BLOCK )
|
| 2651 |
|
|
|
| 2652 |
|
|
static void _fp_out_wide(FILE *fp, intptr_t type, intptr_t len, intptr_t buf)
|
| 2653 |
|
|
{
|
| 2654 |
|
|
wchar_t wbuf[BUF_SIZE];
|
| 2655 |
|
|
const char *s = (const char *) buf;
|
| 2656 |
|
|
int i;
|
| 2657 |
|
|
|
| 2658 |
|
|
if (type & 0x80) { /* Some type of padding needed */
|
| 2659 |
|
|
int buflen = strlen(s);
|
| 2660 |
|
|
if ((len -= buflen) > 0) {
|
| 2661 |
|
|
_charpad(fp, (type & 0x7f), len);
|
| 2662 |
|
|
}
|
| 2663 |
|
|
len = buflen;
|
| 2664 |
|
|
}
|
| 2665 |
|
|
|
| 2666 |
|
|
if (len > 0) {
|
| 2667 |
|
|
i = 0;
|
| 2668 |
|
|
do {
|
| 2669 |
|
|
#ifdef __LOCALE_C_ONLY
|
| 2670 |
|
|
wbuf[i] = s[i];
|
| 2671 |
|
|
#else /* __LOCALE_C_ONLY */
|
| 2672 |
|
|
|
| 2673 |
|
|
#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
|
| 2674 |
|
|
if (s[i] == ',') {
|
| 2675 |
|
|
wbuf[i] = __UCLIBC_CURLOCALE_DATA.thousands_sep_wc;
|
| 2676 |
|
|
} else
|
| 2677 |
|
|
#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
|
| 2678 |
|
|
if (s[i] == '.') {
|
| 2679 |
|
|
wbuf[i] = __UCLIBC_CURLOCALE_DATA.decimal_point_wc;
|
| 2680 |
|
|
} else {
|
| 2681 |
|
|
wbuf[i] = s[i];
|
| 2682 |
|
|
}
|
| 2683 |
|
|
#endif /* __LOCALE_C_ONLY */
|
| 2684 |
|
|
|
| 2685 |
|
|
} while (++i < len);
|
| 2686 |
|
|
|
| 2687 |
|
|
OUTNSTR(fp, wbuf, len);
|
| 2688 |
|
|
}
|
| 2689 |
|
|
}
|
| 2690 |
|
|
|
| 2691 |
|
|
#endif /* __STDIO_PRINTF_FLOAT */
|
| 2692 |
|
|
|
| 2693 |
|
|
static int _ppwfs_init(register ppfs_t *ppfs, const wchar_t *fmt0)
|
| 2694 |
|
|
{
|
| 2695 |
|
|
static const wchar_t invalid_wcs[] = L"Invalid wide format string.";
|
| 2696 |
|
|
int r;
|
| 2697 |
|
|
|
| 2698 |
|
|
/* First, zero out everything... argnumber[], argtype[], argptr[] */
|
| 2699 |
|
|
memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */
|
| 2700 |
|
|
#ifdef NL_ARGMAX
|
| 2701 |
|
|
--ppfs->maxposarg; /* set to -1 */
|
| 2702 |
|
|
#endif /* NL_ARGMAX */
|
| 2703 |
|
|
ppfs->fmtpos = (const char *) fmt0;
|
| 2704 |
|
|
ppfs->info._flags = FLAG_WIDESTREAM;
|
| 2705 |
|
|
|
| 2706 |
|
|
{
|
| 2707 |
|
|
mbstate_t mbstate;
|
| 2708 |
|
|
const wchar_t *p;
|
| 2709 |
|
|
mbstate.mask = 0; /* Initialize the mbstate. */
|
| 2710 |
|
|
p = fmt0;
|
| 2711 |
|
|
if (wcsrtombs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) {
|
| 2712 |
|
|
ppfs->fmtpos = (const char *) invalid_wcs;
|
| 2713 |
|
|
return -1;
|
| 2714 |
|
|
}
|
| 2715 |
|
|
}
|
| 2716 |
|
|
|
| 2717 |
|
|
/* now set all argtypes to no-arg */
|
| 2718 |
|
|
{
|
| 2719 |
|
|
#if 1
|
| 2720 |
|
|
/* TODO - use memset here since already "paid for"? */
|
| 2721 |
|
|
register int *p = ppfs->argtype;
|
| 2722 |
|
|
|
| 2723 |
|
|
r = MAX_ARGS;
|
| 2724 |
|
|
do {
|
| 2725 |
|
|
*p++ = __PA_NOARG;
|
| 2726 |
|
|
} while (--r);
|
| 2727 |
|
|
#else
|
| 2728 |
|
|
/* TODO -- get rid of this?? */
|
| 2729 |
|
|
register char *p = (char *) ((MAX_ARGS-1) * sizeof(int));
|
| 2730 |
|
|
|
| 2731 |
|
|
do {
|
| 2732 |
|
|
*((int *)(((char *)ppfs) + ((int)p) + offsetof(ppfs_t,argtype))) = __PA_NOARG;
|
| 2733 |
|
|
p -= sizeof(int);
|
| 2734 |
|
|
} while (p);
|
| 2735 |
|
|
#endif
|
| 2736 |
|
|
}
|
| 2737 |
|
|
|
| 2738 |
|
|
/*
|
| 2739 |
|
|
* Run through the entire format string to validate it and initialize
|
| 2740 |
|
|
* the positional arg numbers (if any).
|
| 2741 |
|
|
*/
|
| 2742 |
|
|
{
|
| 2743 |
|
|
register const wchar_t *fmt = fmt0;
|
| 2744 |
|
|
|
| 2745 |
|
|
while (*fmt) {
|
| 2746 |
|
|
if ((*fmt == '%') && (*++fmt != '%')) {
|
| 2747 |
|
|
ppfs->fmtpos = (const char *) fmt; /* back up to the '%' */
|
| 2748 |
|
|
if ((r = _ppfs_parsespec(ppfs)) < 0) {
|
| 2749 |
|
|
return -1;
|
| 2750 |
|
|
}
|
| 2751 |
|
|
fmt = (const wchar_t *) ppfs->fmtpos; /* update to one past end of spec */
|
| 2752 |
|
|
} else {
|
| 2753 |
|
|
++fmt;
|
| 2754 |
|
|
}
|
| 2755 |
|
|
}
|
| 2756 |
|
|
ppfs->fmtpos = (const char *) fmt0; /* rewind */
|
| 2757 |
|
|
}
|
| 2758 |
|
|
|
| 2759 |
|
|
#ifdef NL_ARGMAX
|
| 2760 |
|
|
/* If we have positional args, make sure we know all the types. */
|
| 2761 |
|
|
{
|
| 2762 |
|
|
register int *p = ppfs->argtype;
|
| 2763 |
|
|
r = ppfs->maxposarg;
|
| 2764 |
|
|
while (--r >= 0) {
|
| 2765 |
|
|
if ( *p == __PA_NOARG ) { /* missing arg type!!! */
|
| 2766 |
|
|
return -1;
|
| 2767 |
|
|
}
|
| 2768 |
|
|
++p;
|
| 2769 |
|
|
}
|
| 2770 |
|
|
}
|
| 2771 |
|
|
#endif /* NL_ARGMAX */
|
| 2772 |
|
|
|
| 2773 |
|
|
return 0;
|
| 2774 |
|
|
}
|
| 2775 |
|
|
|
| 2776 |
|
|
#endif /* L_vfprintf */
|
| 2777 |
|
|
|
| 2778 |
|
|
static void _charpad(FILE * __restrict stream, int padchar, size_t numpad)
|
| 2779 |
|
|
{
|
| 2780 |
|
|
/* TODO -- Use a buffer to cut down on function calls... */
|
| 2781 |
|
|
FMT_TYPE pad[1];
|
| 2782 |
|
|
|
| 2783 |
|
|
*pad = padchar;
|
| 2784 |
|
|
while (numpad) {
|
| 2785 |
|
|
OUTNSTR(stream, pad, 1);
|
| 2786 |
|
|
--numpad;
|
| 2787 |
|
|
}
|
| 2788 |
|
|
}
|
| 2789 |
|
|
|
| 2790 |
|
|
/* TODO -- Dynamically allocate work space to accomodate stack-poor archs? */
|
| 2791 |
|
|
static int _do_one_spec(FILE * __restrict stream,
|
| 2792 |
|
|
register ppfs_t *ppfs, int *count)
|
| 2793 |
|
|
{
|
| 2794 |
|
|
static const char spec_base[] = SPEC_BASE;
|
| 2795 |
|
|
#ifdef L_vfprintf
|
| 2796 |
|
|
static const char prefix[] = "+\0-\0 \0000x\0000X";
|
| 2797 |
|
|
/* 0 2 4 6 9 11*/
|
| 2798 |
|
|
#else /* L_vfprintf */
|
| 2799 |
|
|
static const wchar_t prefix[] = L"+\0-\0 \0000x\0000X";
|
| 2800 |
|
|
#endif /* L_vfprintf */
|
| 2801 |
|
|
enum {
|
| 2802 |
|
|
PREFIX_PLUS = 0,
|
| 2803 |
|
|
PREFIX_MINUS = 2,
|
| 2804 |
|
|
PREFIX_SPACE = 4,
|
| 2805 |
|
|
PREFIX_LWR_X = 6,
|
| 2806 |
|
|
PREFIX_UPR_X = 9,
|
| 2807 |
|
|
PREFIX_NONE = 11
|
| 2808 |
|
|
};
|
| 2809 |
|
|
|
| 2810 |
|
|
#ifdef __va_arg_ptr
|
| 2811 |
|
|
const void * const *argptr;
|
| 2812 |
|
|
#else
|
| 2813 |
|
|
const void * argptr[MAX_ARGS_PER_SPEC];
|
| 2814 |
|
|
#endif
|
| 2815 |
|
|
int *argtype;
|
| 2816 |
|
|
#ifdef __UCLIBC_HAS_WCHAR__
|
| 2817 |
|
|
const wchar_t *ws = NULL;
|
| 2818 |
|
|
mbstate_t mbstate;
|
| 2819 |
|
|
#endif /* __UCLIBC_HAS_WCHAR__ */
|
| 2820 |
|
|
size_t slen;
|
| 2821 |
|
|
#ifdef L_vfprintf
|
| 2822 |
|
|
#define SLEN slen
|
| 2823 |
|
|
#else
|
| 2824 |
|
|
size_t SLEN;
|
| 2825 |
|
|
wchar_t wbuf[2];
|
| 2826 |
|
|
#endif
|
| 2827 |
|
|
int base;
|
| 2828 |
|
|
int numpad;
|
| 2829 |
|
|
int alphacase;
|
| 2830 |
|
|
int numfill = 0; /* TODO: fix */
|
| 2831 |
|
|
int prefix_num = PREFIX_NONE;
|
| 2832 |
|
|
char padchar = ' ';
|
| 2833 |
|
|
#ifdef __UCLIBC_MJN3_ONLY__
|
| 2834 |
|
|
#warning TODO: Determine appropriate buf size.
|
| 2835 |
|
|
#endif /* __UCLIBC_MJN3_ONLY__ */
|
| 2836 |
|
|
/* TODO: buf needs to be big enough for any possible error return strings
|
| 2837 |
|
|
* and also for any locale-grouped long long integer strings generated.
|
| 2838 |
|
|
* This should be large enough for any of the current archs/locales, but
|
| 2839 |
|
|
* eventually this should be handled robustly. */
|
| 2840 |
|
|
char buf[128];
|
| 2841 |
|
|
|
| 2842 |
|
|
#ifdef NDEBUG
|
| 2843 |
|
|
_ppfs_parsespec(ppfs);
|
| 2844 |
|
|
#else
|
| 2845 |
|
|
if (_ppfs_parsespec(ppfs) < 0) { /* TODO: just for debugging */
|
| 2846 |
|
|
abort();
|
| 2847 |
|
|
}
|
| 2848 |
|
|
#endif
|
| 2849 |
|
|
_ppfs_setargs(ppfs);
|
| 2850 |
|
|
|
| 2851 |
|
|
argtype = ppfs->argtype + ppfs->argnumber[2] - 1;
|
| 2852 |
|
|
/* Deal with the argptr vs argvalue issue. */
|
| 2853 |
|
|
#ifdef __va_arg_ptr
|
| 2854 |
|
|
argptr = (const void * const *) ppfs->argptr;
|
| 2855 |
|
|
#ifdef NL_ARGMAX
|
| 2856 |
|
|
if (ppfs->maxposarg > 0) { /* Using positional args... */
|
| 2857 |
|
|
argptr += ppfs->argnumber[2] - 1;
|
| 2858 |
|
|
}
|
| 2859 |
|
|
#endif /* NL_ARGMAX */
|
| 2860 |
|
|
#else
|
| 2861 |
|
|
/* Need to build a local copy... */
|
| 2862 |
|
|
{
|
| 2863 |
|
|
register argvalue_t *p = ppfs->argvalue;
|
| 2864 |
|
|
int i;
|
| 2865 |
|
|
#ifdef NL_ARGMAX
|
| 2866 |
|
|
if (ppfs->maxposarg > 0) { /* Using positional args... */
|
| 2867 |
|
|
p += ppfs->argnumber[2] - 1;
|
| 2868 |
|
|
}
|
| 2869 |
|
|
#endif /* NL_ARGMAX */
|
| 2870 |
|
|
for (i = 0 ; i < ppfs->num_data_args ; i++ ) {
|
| 2871 |
|
|
argptr[i] = (void *) p++;
|
| 2872 |
|
|
}
|
| 2873 |
|
|
}
|
| 2874 |
|
|
#endif
|
| 2875 |
|
|
{
|
| 2876 |
|
|
register char *s = NULL; /* TODO: Should s be unsigned char * ? */
|
| 2877 |
|
|
|
| 2878 |
|
|
if (ppfs->conv_num == CONV_n) {
|
| 2879 |
|
|
_store_inttype(*(void **)*argptr,
|
| 2880 |
|
|
ppfs->info._flags & __PA_INTMASK,
|
| 2881 |
|
|
(intmax_t) (*count));
|
| 2882 |
|
|
return 0;
|
| 2883 |
|
|
}
|
| 2884 |
|
|
if (ppfs->conv_num <= CONV_i) { /* pointer or (un)signed int */
|
| 2885 |
|
|
alphacase = __UIM_LOWER;
|
| 2886 |
|
|
|
| 2887 |
|
|
#ifdef __UCLIBC_MJN3_ONLY__
|
| 2888 |
|
|
#ifdef L_vfprintf
|
| 2889 |
|
|
#warning CONSIDER: Should we ignore these flags if stub locale? What about custom specs?
|
| 2890 |
|
|
#endif
|
| 2891 |
|
|
#endif /* __UCLIBC_MJN3_ONLY__ */
|
| 2892 |
|
|
if ((base = spec_base[(int)(ppfs->conv_num - CONV_p)]) == 10) {
|
| 2893 |
|
|
if (PRINT_INFO_FLAG_VAL(&(ppfs->info),group)) {
|
| 2894 |
|
|
alphacase = __UIM_GROUP;
|
| 2895 |
|
|
}
|
| 2896 |
|
|
if (PRINT_INFO_FLAG_VAL(&(ppfs->info),i18n)) {
|
| 2897 |
|
|
alphacase |= 0x80;
|
| 2898 |
|
|
}
|
| 2899 |
|
|
}
|
| 2900 |
|
|
|
| 2901 |
|
|
if (ppfs->conv_num <= CONV_u) { /* pointer or unsigned int */
|
| 2902 |
|
|
if (ppfs->conv_num == CONV_X) {
|
| 2903 |
|
|
alphacase = __UIM_UPPER;
|
| 2904 |
|
|
}
|
| 2905 |
|
|
if (ppfs->conv_num == CONV_p) { /* pointer */
|
| 2906 |
|
|
prefix_num = PREFIX_LWR_X;
|
| 2907 |
|
|
} else { /* unsigned int */
|
| 2908 |
|
|
}
|
| 2909 |
|
|
} else { /* signed int */
|
| 2910 |
|
|
base = -base;
|
| 2911 |
|
|
}
|
| 2912 |
|
|
if (ppfs->info.prec < 0) { /* Ignore '0' flag if prec specified. */
|
| 2913 |
|
|
padchar = ppfs->info.pad;
|
| 2914 |
|
|
}
|
| 2915 |
|
|
#ifdef __UCLIBC_MJN3_ONLY__
|
| 2916 |
|
|
#ifdef L_vfprintf
|
| 2917 |
|
|
#warning CONSIDER: If using outdigits and/or grouping, how should we interpret precision?
|
| 2918 |
|
|
#endif
|
| 2919 |
|
|
#endif /* __UCLIBC_MJN3_ONLY__ */
|
| 2920 |
|
|
s = _uintmaxtostr(buf + sizeof(buf) - 1,
|
| 2921 |
|
|
(uintmax_t)
|
| 2922 |
|
|
_load_inttype(*argtype & __PA_INTMASK,
|
| 2923 |
|
|
*argptr, base), base, alphacase);
|
| 2924 |
|
|
if (ppfs->conv_num > CONV_u) { /* signed int */
|
| 2925 |
|
|
if (*s == '-') {
|
| 2926 |
|
|
PRINT_INFO_SET_FLAG(&(ppfs->info),showsign);
|
| 2927 |
|
|
++s; /* handle '-' in the prefix string */
|
| 2928 |
|
|
prefix_num = PREFIX_MINUS;
|
| 2929 |
|
|
} else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),showsign)) {
|
| 2930 |
|
|
prefix_num = PREFIX_PLUS;
|
| 2931 |
|
|
} else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),space)) {
|
| 2932 |
|
|
prefix_num = PREFIX_SPACE;
|
| 2933 |
|
|
}
|
| 2934 |
|
|
}
|
| 2935 |
|
|
slen = (char *)(buf + sizeof(buf) - 1) - s;
|
| 2936 |
|
|
#ifdef L_vfwprintf
|
| 2937 |
|
|
{
|
| 2938 |
|
|
const char *q = s;
|
| 2939 |
|
|
mbstate.mask = 0; /* Initialize the mbstate. */
|
| 2940 |
|
|
SLEN = mbsrtowcs(NULL, &q, 0, &mbstate);
|
| 2941 |
|
|
}
|
| 2942 |
|
|
#endif
|
| 2943 |
|
|
numfill = ((ppfs->info.prec < 0) ? 1 : ppfs->info.prec);
|
| 2944 |
|
|
if (PRINT_INFO_FLAG_VAL(&(ppfs->info),alt)) {
|
| 2945 |
|
|
if (ppfs->conv_num <= CONV_x) { /* x or p */
|
| 2946 |
|
|
prefix_num = PREFIX_LWR_X;
|
| 2947 |
|
|
}
|
| 2948 |
|
|
if (ppfs->conv_num == CONV_X) {
|
| 2949 |
|
|
prefix_num = PREFIX_UPR_X;
|
| 2950 |
|
|
}
|
| 2951 |
|
|
if ((ppfs->conv_num == CONV_o) && (numfill <= SLEN)) {
|
| 2952 |
|
|
numfill = ((*s == '0') ? 1 : SLEN + 1);
|
| 2953 |
|
|
}
|
| 2954 |
|
|
}
|
| 2955 |
|
|
if (*s == '0') {
|
| 2956 |
|
|
if (prefix_num >= PREFIX_LWR_X) {
|
| 2957 |
|
|
prefix_num = PREFIX_NONE;
|
| 2958 |
|
|
}
|
| 2959 |
|
|
if (ppfs->conv_num == CONV_p) {/* null pointer */
|
| 2960 |
|
|
s = "(nil)";
|
| 2961 |
|
|
#ifdef L_vfwprintf
|
| 2962 |
|
|
SLEN =
|
| 2963 |
|
|
#endif
|
| 2964 |
|
|
slen = 5;
|
| 2965 |
|
|
numfill = 0;
|
| 2966 |
|
|
} else if (numfill == 0) { /* if precision 0, no output */
|
| 2967 |
|
|
#ifdef L_vfwprintf
|
| 2968 |
|
|
SLEN =
|
| 2969 |
|
|
#endif
|
| 2970 |
|
|
slen = 0;
|
| 2971 |
|
|
}
|
| 2972 |
|
|
}
|
| 2973 |
|
|
numfill = ((numfill > SLEN) ? numfill - SLEN : 0);
|
| 2974 |
|
|
} else if (ppfs->conv_num <= CONV_A) { /* floating point */
|
| 2975 |
|
|
#ifdef __STDIO_PRINTF_FLOAT
|
| 2976 |
|
|
*count +=
|
| 2977 |
|
|
_fpmaxtostr(stream,
|
| 2978 |
|
|
(__fpmax_t)
|
| 2979 |
|
|
(PRINT_INFO_FLAG_VAL(&(ppfs->info),is_long_double)
|
| 2980 |
|
|
? *(long double *) *argptr
|
| 2981 |
|
|
: (long double) (* (double *) *argptr)),
|
| 2982 |
|
|
&ppfs->info, FP_OUT );
|
| 2983 |
|
|
return 0;
|
| 2984 |
|
|
#else /* __STDIO_PRINTF_FLOAT */
|
| 2985 |
|
|
return -1; /* TODO -- try to continue? */
|
| 2986 |
|
|
#endif /* __STDIO_PRINTF_FLOAT */
|
| 2987 |
|
|
} else if (ppfs->conv_num <= CONV_S) { /* wide char or string */
|
| 2988 |
|
|
#ifdef L_vfprintf
|
| 2989 |
|
|
|
| 2990 |
|
|
#ifdef __UCLIBC_HAS_WCHAR__
|
| 2991 |
|
|
mbstate.mask = 0; /* Initialize the mbstate. */
|
| 2992 |
|
|
if (ppfs->conv_num == CONV_S) { /* wide string */
|
| 2993 |
|
|
if (!(ws = *((const wchar_t **) *argptr))) {
|
| 2994 |
|
|
goto NULL_STRING;
|
| 2995 |
|
|
}
|
| 2996 |
|
|
/* We use an awful uClibc-specific hack here, passing
|
| 2997 |
|
|
* (char*) &ws as the conversion destination. This signals
|
| 2998 |
|
|
* uClibc's wcsrtombs that we want a "restricted" length
|
| 2999 |
|
|
* such that the mbs fits in a buffer of the specified
|
| 3000 |
|
|
* size with no partial conversions. */
|
| 3001 |
|
|
if ((slen = wcsrtombs((char *) &ws, &ws, /* Use awful hack! */
|
| 3002 |
|
|
((ppfs->info.prec >= 0)
|
| 3003 |
|
|
? ppfs->info.prec
|
| 3004 |
|
|
: SIZE_MAX), &mbstate))
|
| 3005 |
|
|
== ((size_t)-1)
|
| 3006 |
|
|
) {
|
| 3007 |
|
|
return -1; /* EILSEQ */
|
| 3008 |
|
|
}
|
| 3009 |
|
|
} else { /* wide char */
|
| 3010 |
|
|
s = buf;
|
| 3011 |
|
|
slen = wcrtomb(s, (*((const wchar_t *) *argptr)), &mbstate);
|
| 3012 |
|
|
if (slen == ((size_t)-1)) {
|
| 3013 |
|
|
return -1; /* EILSEQ */
|
| 3014 |
|
|
}
|
| 3015 |
|
|
s[slen] = 0; /* TODO - Is this necessary? */
|
| 3016 |
|
|
}
|
| 3017 |
|
|
#else /* __UCLIBC_HAS_WCHAR__ */
|
| 3018 |
|
|
return -1;
|
| 3019 |
|
|
#endif /* __UCLIBC_HAS_WCHAR__ */
|
| 3020 |
|
|
} else if (ppfs->conv_num <= CONV_s) { /* char or string */
|
| 3021 |
|
|
if (ppfs->conv_num == CONV_s) { /* string */
|
| 3022 |
|
|
s = *((char **) (*argptr));
|
| 3023 |
|
|
if (s) {
|
| 3024 |
|
|
#ifdef __STDIO_PRINTF_M_SUPPORT
|
| 3025 |
|
|
SET_STRING_LEN:
|
| 3026 |
|
|
#endif
|
| 3027 |
|
|
slen = strnlen(s, ((ppfs->info.prec >= 0)
|
| 3028 |
|
|
? ppfs->info.prec : SIZE_MAX));
|
| 3029 |
|
|
} else {
|
| 3030 |
|
|
#ifdef __UCLIBC_HAS_WCHAR__
|
| 3031 |
|
|
NULL_STRING:
|
| 3032 |
|
|
#endif
|
| 3033 |
|
|
s = "(null)";
|
| 3034 |
|
|
slen = 6;
|
| 3035 |
|
|
}
|
| 3036 |
|
|
} else { /* char */
|
| 3037 |
|
|
s = buf;
|
| 3038 |
|
|
*s = (unsigned char)(*((const int *) *argptr));
|
| 3039 |
|
|
s[1] = 0;
|
| 3040 |
|
|
slen = 1;
|
| 3041 |
|
|
}
|
| 3042 |
|
|
|
| 3043 |
|
|
#else /* L_vfprintf */
|
| 3044 |
|
|
|
| 3045 |
|
|
if (ppfs->conv_num == CONV_S) { /* wide string */
|
| 3046 |
|
|
ws = *((wchar_t **) (*argptr));
|
| 3047 |
|
|
if (!ws) {
|
| 3048 |
|
|
goto NULL_STRING;
|
| 3049 |
|
|
}
|
| 3050 |
|
|
SLEN = wcsnlen(ws, ((ppfs->info.prec >= 0)
|
| 3051 |
|
|
? ppfs->info.prec : SIZE_MAX));
|
| 3052 |
|
|
} else { /* wide char */
|
| 3053 |
|
|
*wbuf = (wchar_t)(*((const wint_t *) *argptr));
|
| 3054 |
|
|
CHAR_CASE:
|
| 3055 |
|
|
ws = wbuf;
|
| 3056 |
|
|
wbuf[1] = 0;
|
| 3057 |
|
|
SLEN = 1;
|
| 3058 |
|
|
}
|
| 3059 |
|
|
|
| 3060 |
|
|
} else if (ppfs->conv_num <= CONV_s) { /* char or string */
|
| 3061 |
|
|
|
| 3062 |
|
|
if (ppfs->conv_num == CONV_s) { /* string */
|
| 3063 |
|
|
#ifdef __UCLIBC_MJN3_ONLY__
|
| 3064 |
|
|
#warning TODO: Fix %s for vfwprintf... output upto illegal sequence?
|
| 3065 |
|
|
#endif /* __UCLIBC_MJN3_ONLY__ */
|
| 3066 |
|
|
s = *((char **) (*argptr));
|
| 3067 |
|
|
if (s) {
|
| 3068 |
|
|
#ifdef __STDIO_PRINTF_M_SUPPORT
|
| 3069 |
|
|
SET_STRING_LEN:
|
| 3070 |
|
|
#endif
|
| 3071 |
|
|
/* We use an awful uClibc-specific hack here, passing
|
| 3072 |
|
|
* (wchar_t*) &mbstate as the conversion destination.
|
| 3073 |
|
|
* This signals uClibc's mbsrtowcs that we want a
|
| 3074 |
|
|
* "restricted" length such that the mbs fits in a buffer
|
| 3075 |
|
|
* of the specified size with no partial conversions. */
|
| 3076 |
|
|
{
|
| 3077 |
|
|
const char *q = s;
|
| 3078 |
|
|
mbstate.mask = 0; /* Initialize the mbstate. */
|
| 3079 |
|
|
SLEN = mbsrtowcs((wchar_t *) &mbstate, &q,
|
| 3080 |
|
|
((ppfs->info.prec >= 0)
|
| 3081 |
|
|
? ppfs->info.prec : SIZE_MAX),
|
| 3082 |
|
|
&mbstate);
|
| 3083 |
|
|
}
|
| 3084 |
|
|
if (SLEN == ((size_t)(-1))) {
|
| 3085 |
|
|
return -1; /* EILSEQ */
|
| 3086 |
|
|
}
|
| 3087 |
|
|
} else {
|
| 3088 |
|
|
NULL_STRING:
|
| 3089 |
|
|
s = "(null)";
|
| 3090 |
|
|
SLEN = slen = 6;
|
| 3091 |
|
|
}
|
| 3092 |
|
|
} else { /* char */
|
| 3093 |
|
|
*wbuf = btowc( (unsigned char)(*((const int *) *argptr)) );
|
| 3094 |
|
|
goto CHAR_CASE;
|
| 3095 |
|
|
}
|
| 3096 |
|
|
|
| 3097 |
|
|
#endif /* L_vfprintf */
|
| 3098 |
|
|
|
| 3099 |
|
|
#ifdef __STDIO_PRINTF_M_SUPPORT
|
| 3100 |
|
|
} else if (ppfs->conv_num == CONV_m) {
|
| 3101 |
|
|
s = _glibc_strerror_r(errno, buf, sizeof(buf));
|
| 3102 |
|
|
goto SET_STRING_LEN;
|
| 3103 |
|
|
#endif
|
| 3104 |
|
|
} else {
|
| 3105 |
|
|
#ifdef __STDIO_GLIBC_CUSTOM_PRINTF
|
| 3106 |
|
|
assert(ppfs->conv_num == CONV_custom0);
|
| 3107 |
|
|
|
| 3108 |
|
|
s = _custom_printf_spec;
|
| 3109 |
|
|
do {
|
| 3110 |
|
|
if (*s == ppfs->info.spec) {
|
| 3111 |
|
|
int rv;
|
| 3112 |
|
|
/* TODO -- check return value for sanity? */
|
| 3113 |
|
|
rv = (*_custom_printf_handler
|
| 3114 |
|
|
[(int)(s-_custom_printf_spec)])
|
| 3115 |
|
|
(stream, &ppfs->info, argptr);
|
| 3116 |
|
|
if (rv < 0) {
|
| 3117 |
|
|
return -1;
|
| 3118 |
|
|
}
|
| 3119 |
|
|
*count += rv;
|
| 3120 |
|
|
return 0;
|
| 3121 |
|
|
}
|
| 3122 |
|
|
} while (++s < (_custom_printf_spec + MAX_USER_SPEC));
|
| 3123 |
|
|
#endif /* __STDIO_GLIBC_CUSTOM_PRINTF */
|
| 3124 |
|
|
assert(0);
|
| 3125 |
|
|
return -1;
|
| 3126 |
|
|
}
|
| 3127 |
|
|
|
| 3128 |
|
|
#ifdef __UCLIBC_MJN3_ONLY__
|
| 3129 |
|
|
#ifdef L_vfprintf
|
| 3130 |
|
|
#warning CONSIDER: If using outdigits and/or grouping, how should we pad?
|
| 3131 |
|
|
#endif
|
| 3132 |
|
|
#endif /* __UCLIBC_MJN3_ONLY__ */
|
| 3133 |
|
|
{
|
| 3134 |
|
|
size_t t;
|
| 3135 |
|
|
|
| 3136 |
|
|
t = SLEN + numfill;
|
| 3137 |
|
|
if (prefix_num != PREFIX_NONE) {
|
| 3138 |
|
|
t += ((prefix_num < PREFIX_LWR_X) ? 1 : 2);
|
| 3139 |
|
|
}
|
| 3140 |
|
|
numpad = ((ppfs->info.width > t) ? (ppfs->info.width - t) : 0);
|
| 3141 |
|
|
*count += t + numpad;
|
| 3142 |
|
|
}
|
| 3143 |
|
|
if (padchar == '0') { /* TODO: check this */
|
| 3144 |
|
|
numfill += numpad;
|
| 3145 |
|
|
numpad = 0;
|
| 3146 |
|
|
}
|
| 3147 |
|
|
|
| 3148 |
|
|
/* Now handle the output itself. */
|
| 3149 |
|
|
if (!PRINT_INFO_FLAG_VAL(&(ppfs->info),left)) {
|
| 3150 |
|
|
_charpad(stream, ' ', numpad);
|
| 3151 |
|
|
numpad = 0;
|
| 3152 |
|
|
}
|
| 3153 |
|
|
OUTPUT(stream, prefix + prefix_num);
|
| 3154 |
|
|
_charpad(stream, '0', numfill);
|
| 3155 |
|
|
|
| 3156 |
|
|
#ifdef L_vfprintf
|
| 3157 |
|
|
|
| 3158 |
|
|
#ifdef __UCLIBC_HAS_WCHAR__
|
| 3159 |
|
|
if (!ws) {
|
| 3160 |
|
|
assert(s);
|
| 3161 |
|
|
_outnstr(stream, s, slen);
|
| 3162 |
|
|
} else { /* wide string */
|
| 3163 |
|
|
size_t t;
|
| 3164 |
|
|
mbstate.mask = 0; /* Initialize the mbstate. */
|
| 3165 |
|
|
while (slen) {
|
| 3166 |
|
|
t = (slen <= sizeof(buf)) ? slen : sizeof(buf);
|
| 3167 |
|
|
t = wcsrtombs(buf, &ws, t, &mbstate);
|
| 3168 |
|
|
assert (t != ((size_t)(-1)));
|
| 3169 |
|
|
_outnstr(stream, buf, t);
|
| 3170 |
|
|
slen -= t;
|
| 3171 |
|
|
}
|
| 3172 |
|
|
}
|
| 3173 |
|
|
#else /* __UCLIBC_HAS_WCHAR__ */
|
| 3174 |
|
|
_outnstr(stream, s, slen);
|
| 3175 |
|
|
#endif /* __UCLIBC_HAS_WCHAR__ */
|
| 3176 |
|
|
|
| 3177 |
|
|
#else /* L_vfprintf */
|
| 3178 |
|
|
|
| 3179 |
|
|
if (!ws) {
|
| 3180 |
|
|
assert(s);
|
| 3181 |
|
|
_outnstr(stream, s, SLEN);
|
| 3182 |
|
|
} else {
|
| 3183 |
|
|
_outnwcs(stream, ws, SLEN);
|
| 3184 |
|
|
}
|
| 3185 |
|
|
|
| 3186 |
|
|
#endif /* L_vfprintf */
|
| 3187 |
|
|
_charpad(stream, ' ', numpad);
|
| 3188 |
|
|
}
|
| 3189 |
|
|
|
| 3190 |
|
|
return 0;
|
| 3191 |
|
|
}
|
| 3192 |
|
|
|
| 3193 |
|
|
int VFPRINTF (FILE * __restrict stream,
|
| 3194 |
|
|
register const FMT_TYPE * __restrict format,
|
| 3195 |
|
|
va_list arg)
|
| 3196 |
|
|
{
|
| 3197 |
|
|
ppfs_t ppfs;
|
| 3198 |
|
|
int count, r;
|
| 3199 |
|
|
register const FMT_TYPE *s;
|
| 3200 |
|
|
|
| 3201 |
|
|
__STDIO_THREADLOCK(stream);
|
| 3202 |
|
|
|
| 3203 |
|
|
count = 0;
|
| 3204 |
|
|
s = format;
|
| 3205 |
|
|
|
| 3206 |
|
|
#if defined(L_vfprintf) && defined(__UCLIBC_HAS_WCHAR__)
|
| 3207 |
|
|
/* Sigh... I forgot that by calling _stdio_fwrite, vfprintf doesn't
|
| 3208 |
|
|
* always check the stream's orientation. This is just a temporary
|
| 3209 |
|
|
* fix until I rewrite the stdio core work routines. */
|
| 3210 |
|
|
if (stream->modeflags & __FLAG_WIDE) {
|
| 3211 |
|
|
stream->modeflags |= __FLAG_ERROR;
|
| 3212 |
|
|
count = -1;
|
| 3213 |
|
|
goto DONE;
|
| 3214 |
|
|
}
|
| 3215 |
|
|
stream->modeflags |= __FLAG_NARROW;
|
| 3216 |
|
|
#endif
|
| 3217 |
|
|
|
| 3218 |
|
|
if (_PPFS_init(&ppfs, format) < 0) { /* Bad format string. */
|
| 3219 |
|
|
OUTNSTR(stream, (const FMT_TYPE *) ppfs.fmtpos,
|
| 3220 |
|
|
STRLEN((const FMT_TYPE *)(ppfs.fmtpos)));
|
| 3221 |
|
|
#if defined(L_vfprintf) && !defined(NDEBUG)
|
| 3222 |
|
|
fprintf(stderr,"\nIMbS: \"%s\"\n\n", format);
|
| 3223 |
|
|
#endif
|
| 3224 |
|
|
count = -1;
|
| 3225 |
|
|
} else {
|
| 3226 |
|
|
_ppfs_prepargs(&ppfs, arg); /* This did a va_copy!!! */
|
| 3227 |
|
|
|
| 3228 |
|
|
do {
|
| 3229 |
|
|
while (*format && (*format != '%')) {
|
| 3230 |
|
|
++format;
|
| 3231 |
|
|
}
|
| 3232 |
|
|
|
| 3233 |
|
|
if (format-s) { /* output any literal text in format string */
|
| 3234 |
|
|
if ( (r = OUTNSTR(stream, s, format-s)) < 0) {
|
| 3235 |
|
|
count = -1;
|
| 3236 |
|
|
break;
|
| 3237 |
|
|
}
|
| 3238 |
|
|
count += r;
|
| 3239 |
|
|
}
|
| 3240 |
|
|
|
| 3241 |
|
|
if (!*format) { /* we're done */
|
| 3242 |
|
|
break;
|
| 3243 |
|
|
}
|
| 3244 |
|
|
|
| 3245 |
|
|
if (format[1] != '%') { /* if we get here, *format == '%' */
|
| 3246 |
|
|
/* TODO: _do_one_spec needs to know what the output funcs are!!! */
|
| 3247 |
|
|
ppfs.fmtpos = (const char *)(++format);
|
| 3248 |
|
|
/* TODO: check -- should only fail on stream error */
|
| 3249 |
|
|
if ( (r = _do_one_spec(stream, &ppfs, &count)) < 0) {
|
| 3250 |
|
|
count = -1;
|
| 3251 |
|
|
break;
|
| 3252 |
|
|
}
|
| 3253 |
|
|
s = format = (const FMT_TYPE *) ppfs.fmtpos;
|
| 3254 |
|
|
} else { /* %% means literal %, so start new string */
|
| 3255 |
|
|
s = ++format;
|
| 3256 |
|
|
++format;
|
| 3257 |
|
|
}
|
| 3258 |
|
|
} while (1);
|
| 3259 |
|
|
|
| 3260 |
|
|
va_end(ppfs.arg); /* Need to clean up after va_copy! */
|
| 3261 |
|
|
}
|
| 3262 |
|
|
|
| 3263 |
|
|
#if defined(L_vfprintf) && defined(__UCLIBC_HAS_WCHAR__)
|
| 3264 |
|
|
DONE:
|
| 3265 |
|
|
#endif
|
| 3266 |
|
|
|
| 3267 |
|
|
__STDIO_THREADUNLOCK(stream);
|
| 3268 |
|
|
|
| 3269 |
|
|
return count;
|
| 3270 |
|
|
}
|
| 3271 |
|
|
#endif
|
| 3272 |
|
|
/**********************************************************************/
|