📄 printf.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 * *//*****************************************************************************//* 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_LONG_LONG__ 1#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_LONG_LONG_ERROR 0#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. */#define WANT_GNU_ERRNO 0/**************************************************************************/#include <sys/types.h>#include <fcntl.h>#include <string.h>#include <stdlib.h>#include <limits.h>#include <assert.h>#if WANT_GNU_ERRNO#include <errno.h>#endif#ifdef __STDC__#include <stdarg.h>#define va_strt va_start#else#include <varargs.h>#define va_strt(p,i) va_start(p)#endif#include "stdio.h"extern int vfnprintf(FILE * op, size_t max_size, register __const char *fmt, register va_list ap);#ifdef L_printfint printf(const char *fmt, ...){ va_list ptr; int rv; va_strt(ptr, fmt); rv = vfnprintf(stdout, -1, fmt, ptr); va_end(ptr); return rv;}#endif#ifdef L_asprintfint asprintf(char **app, const char *fmt, ...){ va_list ptr; int rv; char *p; /* * First iteration - find out size of buffer required and allocate it. */ va_strt(ptr, fmt); rv = vsnprintf(NULL, 0, fmt, ptr); va_end(ptr); p = malloc(++rv); /* allocate the buffer */ *app = p; if (!p) { return -1; } /* * Second iteration - actually produce output. */ va_strt(ptr, fmt); rv = vsnprintf(p, rv, fmt, ptr); va_end(ptr); return rv;}#endif#ifdef L_sprintfint sprintf(char *sp, const char *fmt, ...){ va_list ptr; int rv; va_strt(ptr, fmt); rv = vsnprintf(sp, -1, fmt, ptr); va_end(ptr); return rv;}#endif#ifdef L_snprintfint snprintf(char *sp, size_t size, const char *fmt, ...){ va_list ptr; int rv; va_strt(ptr, fmt); rv = vsnprintf(sp, size, fmt, ptr); va_end(ptr); return rv;}#endif#ifdef L_fprintfint fprintf(FILE * fp, const char *fmt, ...){ va_list ptr; int rv; va_strt(ptr, fmt); rv = vfnprintf(fp, -1, fmt, ptr); va_end(ptr); return rv;}#endif#ifdef L_fnprintfint fnprintf(FILE * fp, size_t size, const char *fmt, ...){ va_list ptr; int rv; va_strt(ptr, fmt); rv = vfnprintf(fp, size, fmt, ptr); va_end(ptr); return rv;}#endif#ifdef L_vprintfint vprintf(const char *fmt, va_list ap){ return vfprintf(stdout, fmt, ap);}#endif#ifdef L_vfprintfint vfprintf(FILE * op, register __const char *fmt, register va_list ap){ return vfnprintf(op, -1, fmt, ap);}#endif#ifdef L_vsprintfint vsprintf(char *sp, __const char *fmt, va_list ap){ return vsnprintf(sp, -1, fmt, ap);}#endif#ifdef L_vsnprintfint vsnprintf(char *sp, size_t size, __const char *fmt, va_list ap){ int rv; FILE f; /* * As we're only using the putc macro in vfnprintf, we don't need to * initialize all FILE f's fields. */ f.bufwrite = (char *) ((unsigned) -1); f.bufpos = sp; f.mode = _IOFBF; rv = vfnprintf(&f, size, fmt, ap); if (size) { /* If this is going to a buffer, */ *(f.bufpos) = 0; /* don't forget to nul-terminate. */ } return rv;}#endif#ifdef L_vdprintf/* * Note: If fd has an associated buffered FILE, bad things happen. */extern int vdprintf(int fd, const char *fmt, va_list ap){ char buf[BUFSIZ]; FILE f = {buf, 0, buf+sizeof(buf), buf, buf+sizeof(buf), 0, fd, _IOFBF}; int rv; rv = vfnprintf(&f, -1, fmt, ap); if (fflush(&f)) { return -1; } return rv;}#endif#ifdef L_vfnprintfextern char *__ultostr(char *buf, unsigned long uval, int base, int uppercase);extern char *__ltostr(char *buf, long val, int base, int uppercase);extern char *__ulltostr(char *buf, unsigned long long uval, int base, int uppercase);extern char *__lltostr(char *buf, long long val, int base, int uppercase);extern int __dtostr(FILE * fp, size_t size, long double x, char flag[], int width, int preci, char mode);enum { FLAG_PLUS = 0, FLAG_MINUS_LJUSTIFY, FLAG_HASH, FLAG_0_PAD, FLAG_SPACE,};/* layout 01234 */static const char spec[] = "+-#0 ";#if defined(__UCLIBC_HAS_LONG_LONG__) || WANT_LONG_LONG_ERRORstatic const char qual[] = "hlLq";#elsestatic const char qual[] = "hl";#endif#if !defined(__UCLIBC_HAS_LONG_LONG__) && WANT_LONG_LONG_ERRORstatic const char ll_err[] = "<LONG-LONG>";#endif#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";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -