📄 old_vfprintf.c
字号:
/* * This file based on printf.c from 'Dlibs' on the atari ST (RdeBath) * * * Dale Schumacher 399 Beacon Ave. * (alias: Dalnefre') St. Paul, MN 55104 * dal@syntel.UUCP United States of America * "It's not reality that's important, but how you perceive things." *//* Altered to use stdarg, made the core function vfnprintf. * Hooked into the stdio package using 'inside information' * Altered sizeof() assumptions, now assumes all integers except chars * will be either * sizeof(xxx) == sizeof(long) or sizeof(xxx) == sizeof(short) * * -RDB *//* * Manuel Novoa III Dec 2000 * * The previous vfnprintf routine was almost completely rewritten with the * goal of fixing some shortcomings and reducing object size. * * The summary of changes: * * Converted print conversion specification parsing from one big switch * to a method using string tables. This new method verifies that the * conversion flags, field width, precision, qualifier, and specifier * appear in the correct order. Many questionable specifications were * accepted by the previous code. This new method also resulted in a * substantial reduction in object size of about 330 bytes (20%) from * the old version (1627 bytes) on i386, even with the following * improvements. * * Implemented %n specifier as required by the standards. * Implemented proper handling of precision for int types. * Implemented # for hex and pointer, fixed error for octal rep of 0. * Implemented return of -1 on stream error. * * Added optional support for the GNU extension %m which prints the string * corresponding the errno. * * Added optional support for long long ints and unsigned long long ints * using the conversion qualifiers "ll", "L", or "q" (like glibc). * * Added optional support for doubles in a very limited form. None of * the formating options are obeyed. The string returned by __dtostr * is printed directly. * * Converted to use my (un)signed long (long) to string routines, which are * smaller than the previous functions and don't require static buffers. * * Other Modifications: * Modified sprintf, snprintf, vsprintf, vsnprintf to share on fake-file. *//* * Manuel Novoa III Jan 2001 * * Removed fake file from *s*printf functions because of possible problems * if called recursively. Instead, have sprintf, snprintf, and vsprintf * call vsnprintf which allocates a fake file on the stack. * Removed WANT_FPUTC option. Always use standard putc macro to avoid * problems with the fake file used by the *s*printf functions. * Fixed bug parsing flags -- did not restart scan. * Added function asprintf. * Fixed 0-pad prefixing bug. * Converted sizeof(int) == sizeof(long) tests to compile time vs run time. * This saves 112 bytes of code on i386. * Fixed precision bug -- when negative set to default. * Added function fnprintf to support __dtostr. * Added floating point support for doubles. Yeah! * * * May 2001 Fixes from Johan Adolfsson (johan.adolfsson@axis.com) * 1) printf("%c",0) returned 0 instead of 1. * 2) unrolled loop in asprintf to reduce size and remove compile warning. * * * June 2001 * 1) fix %p so that "0x" is prepended to outputed hex val * 2) fix %p so that "(nil)" is output for (void *)0 to match glibc * * Sep 5, 2003 * Convert to new floating point conversion routine. * Fix qualifier handling on integer and %n conversions. * Add support for vsnprintf when in non-buffered/no-wchar configuration. * *//*****************************************************************************//* OPTIONS *//*****************************************************************************//* The optional support for long longs and doubles comes in two forms. * * 1) Normal (or partial for doubles) output support. Set to 1 to turn on. * Adds about 130 bytes for doubles, about 220 bytes for long longs, * and about 275 for both to the base code size of 1163 on i386. *//* These are now set in uClibc_config.h based on Config. *//*#define __UCLIBC_HAS_FLOATS__ 1*//* 2) An error message is inserted into the stream, an arg of the * appropriate size is removed from the arglist, and processing * continues. This is adds less code and may be useful in some * cases. Set to 1 to turn on. Adds about 50 bytes for doubles, * about 140 bytes for long longs, and about 175 bytes for both * to the base code size of 1163 on i386. */#define WANT_FLOAT_ERROR 0/* * Set to support GNU extension of %m to print string corresponding to errno. * * Warning: This adds about 50 bytes (i386) to the code but it also pulls in * strerror and the corresponding string table which together are about 3.8k. *//* Now controlled by uClibc_stdio.h and set below. *//* #define WANT_GNU_ERRNO 0 *//**************************************************************************/#define _ISOC99_SOURCE /* for ULLONG primarily... */#define _GNU_SOURCE /* for strnlen */#include "_stdio.h"/* #include <stdio.h> */#include <stdarg.h>#include <limits.h>#include <stdint.h>#include <string.h>#include <errno.h>#include <ctype.h>#include <bits/uClibc_uintmaxtostr.h>#define __PRINTF_INFO_NO_BITFIELD#include <printf.h>#ifdef __UCLIBC_HAS_THREADS__#include <pthread.h>#endif /* __UCLIBC_HAS_THREADS__ *//* #undef __UCLIBC_HAS_FLOATS__ *//* #undef WANT_FLOAT_ERROR *//* #define WANT_FLOAT_ERROR 1 *//* #define __isdigit(c) (((unsigned int)(c - '0')) < 10) */#ifdef __UCLIBC_HAS_PRINTF_M_SPEC__#define WANT_GNU_ERRNO 1#else#define WANT_GNU_ERRNO 0#endif#undef PUTC#undef OUTNSTR#undef _outnstr#ifdef __STDIO_BUFFERS#define PUTC(C,F) putc_unlocked((C),(F))#define OUTNSTR _outnstr#define _outnstr(stream, string, len) __stdio_fwrite(string, len, stream)#else /* __STDIO_BUFFERS */typedef struct { FILE f; unsigned char *bufend; /* pointer to 1 past end of buffer */ unsigned char *bufpos;} __FILE_vsnprintf;#ifdef __UCLIBC_HAS_FLOATS__static void _outnstr(FILE *stream, const unsigned char *s, size_t n){ __FILE_vsnprintf *f = (__FILE_vsnprintf *) stream; if (!__STDIO_STREAM_IS_FAKE_VSNPRINTF_NB(&f->f)) { __stdio_fwrite(s, n, &f->f); } else if (f->bufend > f->bufpos) { size_t r = f->bufend - f->bufpos; if (r > n) { r = n; } memcpy(f->bufpos, s, r); f->bufpos += r; }}#endifstatic void putc_unlocked_sprintf(int c, __FILE_vsnprintf *f){ if (!__STDIO_STREAM_IS_FAKE_VSNPRINTF_NB(&f->f)) { putc_unlocked(c, &f->f); } else if (f->bufpos < f->bufend) { *f->bufpos++ = c; }}#define PUTC(C,F) putc_unlocked_sprintf((C),(__FILE_vsnprintf *)(F))#define OUTNSTR _outnstr#endif /* __STDIO_BUFFERS */#ifdef __UCLIBC_HAS_FLOATS__#include <float.h>#include <bits/uClibc_fpmax.h>typedef void (__fp_outfunc_t)(FILE *fp, intptr_t type, intptr_t len, intptr_t buf);extern size_t _fpmaxtostr(FILE * fp, __fpmax_t x, struct printf_info *info, __fp_outfunc_t fp_outfunc);static void _charpad(FILE * __restrict stream, int padchar, size_t numpad){ /* TODO -- Use a buffer to cut down on function calls... */ char pad[1]; *pad = padchar; while (numpad) { OUTNSTR(stream, pad, 1); --numpad; }}static void _fp_out_narrow(FILE *fp, intptr_t type, intptr_t len, intptr_t buf){ if (type & 0x80) { /* Some type of padding needed. */ int buflen = strlen((const char *) buf); if ((len -= buflen) > 0) { _charpad(fp, (type & 0x7f), len); } len = buflen; } if (len) { OUTNSTR(fp, (const char *) buf, len); }}#endifenum { FLAG_PLUS = 0, FLAG_MINUS_LJUSTIFY, FLAG_HASH, FLAG_0_PAD, FLAG_SPACE,};/* layout 01234 */static const char spec[] = "+-#0 ";/**********************************************************************/extern void _store_inttype(void *dest, int desttype, uintmax_t val);extern uintmax_t _load_inttype(int desttype, const void *src, int uflag);/* * In order to ease translation to what arginfo and _print_info._flags expect, * we map: 0:int 1:char 2:longlong 4:long 8:short * and then _flags |= (((q << 7) + q) & 0x701) and argtype |= (_flags & 0x701) */#ifdef PDS#error PDS already defined!#endif#ifdef SS#error SS already defined!#endif#ifdef IMS#error IMS already defined!#endif#if PTRDIFF_MAX == INT_MAX#define PDS 0#elif PTRDIFF_MAX == LONG_MAX#define PDS 4#elif defined(LLONG_MAX) && (PTRDIFF_MAX == LLONG_MAX)#define PDS 8#else#error fix QUAL_CHARS ptrdiff_t entry 't'!#endif#if SIZE_MAX == UINT_MAX#define SS 0#elif SIZE_MAX == ULONG_MAX#define SS 4#elif defined(LLONG_MAX) && (SIZE_MAX == ULLONG_MAX)#define SS 8#else#error fix QUAL_CHARS size_t entries 'z', 'Z'!#endif#if INTMAX_MAX == INT_MAX#define IMS 0#elif INTMAX_MAX == LONG_MAX#define IMS 4#elif defined(LLONG_MAX) && (INTMAX_MAX == LLONG_MAX)#define IMS 8#else#error fix QUAL_CHARS intmax_t entry 'j'!#endif#define QUAL_CHARS { \ /* j:(u)intmax_t z:(s)size_t t:ptrdiff_t \0:int */ \ /* q:long_long Z:(s)size_t */ \ 'h', 'l', 'L', 'j', 'z', 't', 'q', 'Z', 0, \ 2, 4, 8, IMS, SS, PDS, 8, SS, 0, /* TODO -- fix!!! */\ 1, 8 \}static const char qual_chars[] = QUAL_CHARS;/* static const char qual[] = "hlLq"; *//**********************************************************************/#if !defined(__UCLIBC_HAS_FLOATS__) && WANT_FLOAT_ERRORstatic const char dbl_err[] = "<DOUBLE>";#endif#if defined(__UCLIBC_HAS_FLOATS__) || WANT_FLOAT_ERROR/* layout 012345678901234567 */static const char u_spec[] = "%nbopxXudicsfgGeEaA";#else/* layout 0123456789012 */static const char u_spec[] = "%nbopxXudics";#endif/* WARNING: u_spec and u_radix need to stay in agreement!!! *//* u_radix[i] <-> u_spec[i+2] for unsigned entries only */static const char u_radix[] = "\x02\x08\x10\x10\x10\x0a";int vfprintf(FILE * __restrict op, register const char * __restrict fmt, va_list ap){ union {#ifdef LLONG_MAX long long ll;#endif#if LONG_MAX != INT_MAX long l;#endif int i; } intarg; int i, cnt, dataargtype, len; const void *argptr; /* This does not need to be initialized. */ register char *p;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -