📄 output.c
字号:
/***
*output.c - printf style output to a FILE
*
* Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
*
*Purpose:
* This file contains the code that does all the work for the
* printf family of functions. It should not be called directly, only
* by the *printf functions. We don't make any assumtions about the
* sizes of ints, longs, shorts, or long doubles, but if types do overlap,
* we also try to be efficient. We do assume that pointers are the same
* size as either ints or longs.
* If CPRFLAG is defined, defines _cprintf instead.
* **** DOESN'T CURRENTLY DO MTHREAD LOCKING ****
*
*******************************************************************************/
#ifdef _WIN32
#if defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC)
#define DOUBLE double
#endif /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
/* temporary work-around for compiler without 64-bit support */
#ifndef _INTEGRAL_MAX_BITS
#define _INTEGRAL_MAX_BITS 64
#endif /* _INTEGRAL_MAX_BITS */
#include <cruntime.h>
#include <limits.h>
#include <string.h>
#include <stddef.h>
#include <stdio.h>
#include <stdarg.h>
#include <cvt.h>
#include <conio.h>
#include <internal.h>
#include <fltintrn.h>
#include <stdlib.h>
#include <ctype.h>
#include <dbgint.h>
/* inline keyword is non-ANSI C7 extension */
#if !defined (_MSC_VER) || defined (__STDC__)
#define __inline static
#else /* !defined (_MSC_VER) || defined (__STDC__) */
/* UNDONE: compiler is broken */
#define __inline static
#endif /* !defined (_MSC_VER) || defined (__STDC__) */
#ifdef _MBCS
#undef _MBCS
#endif /* _MBCS */
#include <tchar.h>
/* this macro defines a function which is private and as fast as possible: */
/* for example, in C 6.0, it might be static _fastcall <type> near. */
#define LOCAL(x) static x __cdecl
/* int/long/short/pointer sizes */
/* the following should be set depending on the sizes of various types */
#define LONG_IS_INT 1 /* 1 means long is same size as int */
#define SHORT_IS_INT 0 /* 1 means short is same size as int */
#define LONGDOUBLE_IS_DOUBLE 1 /* 1 means long double is same as double */
#define PTR_IS_INT 1 /* 1 means ptr is same size as int */
#define PTR_IS_LONG 1 /* 1 means ptr is same size as long */
#if LONG_IS_INT
#define get_long_arg(x) (long)get_int_arg(x)
#endif /* LONG_IS_INT */
#ifndef _UNICODE
#if SHORT_IS_INT
#define get_short_arg(x) (short)get_int_arg(x)
#endif /* SHORT_IS_INT */
#endif /* _UNICODE */
#if PTR_IS_INT
#define get_ptr_arg(x) (void *)get_int_arg(x)
#elif PTR_IS_LONG
#define get_ptr_arg(x) (void *)get_long_arg(x)
#else /* PTR_IS_LONG */
#error Size of pointer must be same as size of int or long
#endif /* PTR_IS_LONG */
/* CONSTANTS */
/* size of conversion buffer (ANSI-specified minimum is 509) */
#define BUFFERSIZE 512
#define MAXPRECISION BUFFERSIZE
#if BUFFERSIZE < CVTBUFSIZE + 6
/*
* Buffer needs to be big enough for default minimum precision
* when converting floating point needs bigger buffer, and malloc
* fails
*/
#error Conversion buffer too small for max double.
#endif /* BUFFERSIZE < CVTBUFSIZE + 6 */
/* flag definitions */
#define FL_SIGN 0x00001 /* put plus or minus in front */
#define FL_SIGNSP 0x00002 /* put space or minus in front */
#define FL_LEFT 0x00004 /* left justify */
#define FL_LEADZERO 0x00008 /* pad with leading zeros */
#define FL_LONG 0x00010 /* long value given */
#define FL_SHORT 0x00020 /* short value given */
#define FL_SIGNED 0x00040 /* signed data given */
#define FL_ALTERNATE 0x00080 /* alternate form requested */
#define FL_NEGATIVE 0x00100 /* value is negative */
#define FL_FORCEOCTAL 0x00200 /* force leading '0' for octals */
#define FL_LONGDOUBLE 0x00400 /* long double value given */
#define FL_WIDECHAR 0x00800 /* wide characters */
#define FL_I64 0x08000 /* __int64 value given */
/* state definitions */
enum STATE {
ST_NORMAL, /* normal state; outputting literal chars */
ST_PERCENT, /* just read '%' */
ST_FLAG, /* just read flag character */
ST_WIDTH, /* just read width specifier */
ST_DOT, /* just read '.' */
ST_PRECIS, /* just read precision specifier */
ST_SIZE, /* just read size specifier */
ST_TYPE /* just read type specifier */
};
#define NUMSTATES (ST_TYPE + 1)
/* character type values */
enum CHARTYPE {
CH_OTHER, /* character with no special meaning */
CH_PERCENT, /* '%' */
CH_DOT, /* '.' */
CH_STAR, /* '*' */
CH_ZERO, /* '0' */
CH_DIGIT, /* '1'..'9' */
CH_FLAG, /* ' ', '+', '-', '#' */
CH_SIZE, /* 'h', 'l', 'L', 'N', 'F', 'w' */
CH_TYPE /* type specifying character */
};
/* static data (read only, since we are re-entrant) */
#if defined (_UNICODE) || defined (CPRFLAG)
extern char *__nullstring; /* string to print on null ptr */
extern wchar_t *__wnullstring; /* string to print on null ptr */
#else /* defined (_UNICODE) || defined (CPRFLAG) */
char *__nullstring = "(null)"; /* string to print on null ptr */
wchar_t *__wnullstring = L"(null)";/* string to print on null ptr */
#endif /* defined (_UNICODE) || defined (CPRFLAG) */
/* The state table. This table is actually two tables combined into one. */
/* The lower nybble of each byte gives the character class of any */
/* character; while the uper nybble of the byte gives the next state */
/* to enter. See the macros below the table for details. */
/* */
/* The table is generated by maketabc.c -- use this program to make */
/* changes. */
#if defined (_UNICODE) || defined (CPRFLAG)
extern const char __lookuptable[];
#else /* defined (_UNICODE) || defined (CPRFLAG) */
/* Table generated by maketabc.c built with -D_WIN32_. Defines additional */
/* format code %Z for counted string. */
const char __lookuptable[] = {
0x06, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00,
0x10, 0x00, 0x03, 0x06, 0x00, 0x06, 0x02, 0x10,
0x04, 0x45, 0x45, 0x45, 0x05, 0x05, 0x05, 0x05,
0x05, 0x35, 0x30, 0x00, 0x50, 0x00, 0x00, 0x00,
0x00, 0x20, 0x28, 0x38, 0x50, 0x58, 0x07, 0x08,
0x00, 0x37, 0x30, 0x30, 0x57, 0x50, 0x07, 0x00,
0x00, 0x20, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00,
0x08, 0x60,
0x68, /* 'Z' (extension for NT development) */
0x60, 0x60, 0x60, 0x60, 0x00,
0x00, 0x70, 0x70, 0x78, 0x78, 0x78, 0x78, 0x08,
0x07, 0x08, 0x00, 0x00, 0x07, 0x00, 0x08, 0x08,
0x08, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00,
0x07, /* 'w' (extension for NT development) */
0x08
};
#endif /* defined (_UNICODE) || defined (CPRFLAG) */
#define find_char_class(c) \
((c) < _T(' ') || (c) > _T('x') ? \
CH_OTHER \
: \
__lookuptable[(c)-_T(' ')] & 0xF)
#define find_next_state(class, state) \
(__lookuptable[(class) * NUMSTATES + (state)] >> 4)
/*
* Note: CPRFLAG and _UNICODE cases are currently mutually exclusive.
*/
/* prototypes */
#ifdef CPRFLAG
#define WRITE_CHAR(ch, pnw) write_char(ch, pnw)
#define WRITE_MULTI_CHAR(ch, num, pnw) write_multi_char(ch, num, pnw)
#define WRITE_STRING(s, len, pnw) write_string(s, len, pnw)
#define WRITE_WSTRING(s, len, pnw) write_wstring(s, len, pnw)
LOCAL(void) write_char(int ch, int *pnumwritten);
LOCAL(void) write_multi_char(int ch, int num, int *pnumwritten);
LOCAL(void) write_string(char *string, int len, int *numwritten);
LOCAL(void) write_wstring(wchar_t *string, int len, int *numwritten);
#elif defined (_UNICODE)
#define WRITE_CHAR(ch, pnw) write_char(ch, stream, pnw)
#define WRITE_MULTI_CHAR(ch, num, pnw) write_multi_char(ch, num, stream, pnw)
#define WRITE_STRING(s, len, pnw) write_string(s, len, stream, pnw)
LOCAL(void) write_char(wchar_t ch, FILE *f, int *pnumwritten);
LOCAL(void) write_multi_char(wchar_t ch, int num, FILE *f, int *pnumwritten);
LOCAL(void) write_string(wchar_t *string, int len, FILE *f, int *numwritten);
#else /* defined (_UNICODE) */
#define WRITE_CHAR(ch, pnw) write_char(ch, stream, pnw)
#define WRITE_MULTI_CHAR(ch, num, pnw) write_multi_char(ch, num, stream, pnw)
#define WRITE_STRING(s, len, pnw) write_string(s, len, stream, pnw)
#define WRITE_WSTRING(s, len, pnw) write_wstring(s, len, stream, pnw)
LOCAL(void) write_char(int ch, FILE *f, int *pnumwritten);
LOCAL(void) write_multi_char(int ch, int num, FILE *f, int *pnumwritten);
LOCAL(void) write_string(char *string, int len, FILE *f, int *numwritten);
LOCAL(void) write_wstring(wchar_t *string, int len, FILE *f, int *numwritten);
#endif /* defined (_UNICODE) */
__inline int __cdecl get_int_arg(va_list *pargptr);
#ifndef _UNICODE
#if !SHORT_IS_INT
__inline short __cdecl get_short_arg(va_list *pargptr);
#endif /* !SHORT_IS_INT */
#endif /* _UNICODE */
#if !LONG_IS_INT
__inline long __cdecl get_long_arg(va_list *pargptr);
#endif /* !LONG_IS_INT */
#if _INTEGRAL_MAX_BITS >= 64
__inline __int64 __cdecl get_int64_arg(va_list *pargptr);
#endif /* _INTEGRAL_MAX_BITS >= 64 */
#ifdef CPRFLAG
LOCAL(int) output(const char *, va_list);
/***
*int _cprintf(format, arglist) - write formatted output directly to console
*
*Purpose:
* Writes formatted data like printf, but uses console I/O functions.
*
*Entry:
* char *format - format string to determine data formats
* arglist - list of POINTERS to where to put data
*
*Exit:
* returns number of characters written
*
*Exceptions:
*
*******************************************************************************/
int __cdecl _cprintf (
const char * format,
...
)
{
va_list arglist;
va_start(arglist, format);
return output(format, arglist);
}
#endif /* CPRFLAG */
/***
*int _output(stream, format, argptr), static int output(format, argptr)
*
*Purpose:
* Output performs printf style output onto a stream. It is called by
* printf/fprintf/sprintf/vprintf/vfprintf/vsprintf to so the dirty
* work. In multi-thread situations, _output assumes that the given
* stream is already locked.
*
* Algorithm:
* The format string is parsed by using a finite state automaton
* based on the current state and the current character read from
* the format string. Thus, looping is on a per-character basis,
* not a per conversion specifier basis. Once the format specififying
* character is read, output is performed.
*
*Entry:
* FILE *stream - stream for output
* char *format - printf style format string
* va_list argptr - pointer to list of subsidiary arguments
*
*Exit:
* Returns the number of characters written, or -1 if an output error
* occurs.
*ifdef _UNICODE
* The wide-character flavour returns the number of wide-characters written.
*endif
*
*Exceptions:
*
*******************************************************************************/
#ifdef CPRFLAG
LOCAL(int) output (
#elif defined (_UNICODE)
int __cdecl _woutput (
FILE *stream,
#else /* defined (_UNICODE) */
int __cdecl _output (
FILE *stream,
#endif /* defined (_UNICODE) */
const TCHAR *format,
va_list argptr
)
{
int hexadd; /* offset to add to number to get 'a'..'f' */
TCHAR ch; /* character just read */
int flags; /* flag word -- see #defines above for flag values */
enum STATE state; /* current state */
enum CHARTYPE chclass; /* class of current character */
int radix; /* current conversion radix */
int charsout; /* characters currently written so far, -1 = IO error */
int fldwidth; /* selected field width -- 0 means default */
int precision; /* selected precision -- -1 means default */
TCHAR prefix[2]; /* numeric prefix -- up to two characters */
int prefixlen; /* length of prefix -- 0 means no prefix */
int capexp; /* non-zero = 'E' exponent signifient, zero = 'e' */
int no_output; /* non-zero = prodcue no output for this specifier */
union {
char *sz; /* pointer text to be printed, not zero terminated */
wchar_t *wz;
} text;
int textlen; /* length of the text in bytes/wchars to be printed.
textlen is in multibyte or wide chars if _UNICODE */
union {
char sz[BUFFERSIZE];
#ifdef _UNICODE
wchar_t wz[BUFFERSIZE];
#endif /* _UNICODE */
} buffer;
wchar_t wchar; /* temp wchar_t */
int bufferiswide; /* non-zero = buffer contains wide chars already */
char *heapbuf; /* non-zero = test.sz using heap buffer to be freed */
textlen = 0; /* no text yet */
charsout = 0; /* no characters written yet */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -