output.c
来自「C语言库函数的原型,有用的拿去」· C语言 代码 · 共 1,893 行 · 第 1/5 页
C
1,893 行
/***
*output.c - printf style output to a FILE
*
* Copyright (c) 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 ****
*
*Note:
* this file is included in safecrt.lib build directly, plese refer
* to safecrt_[w]output_s.c
*
*******************************************************************************/
/* temporary work-around for compiler without 64-bit support */
#ifndef _SAFECRT_IMPL
extern "C"
{
#endif /* _SAFECRT_IMPL */
#ifdef POSITIONAL_PARAMETERS
#define FORMAT_VALIDATIONS
#endif /* POSITIONAL_PARAMETERS */
#include <mtdll.h>
#include <cruntime.h>
#include <limits.h>
#include <string.h>
#include <stddef.h>
#include <crtdefs.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>
#include <setlocal.h>
#ifndef _MBTOWC
#define _MBTOWC mbtowc
#endif /* _MBTOWC */
#ifndef _WCTOMB_S
#define _WCTOMB_S wctomb_s
#endif /* _WCTOMB_S */
#ifdef _SAFECRT_IMPL
#undef _malloc_crt
#define _malloc_crt malloc
#undef _free_crt
#define _free_crt free
/* we assume that safecrt implements only sprintf, and not the stream printf */
#undef _putwc_nolock
#define _putwc_nolock(_c, _stream) ((_stream->_cnt -= sizeof(wchar_t)) >= 0 ? (wint_t) (0xffff & (*((wchar_t *)(_stream->_ptr))++ = (wchar_t)_c)) : WEOF)
/* Wrapper for _output_s so that we do not expose FILE in the _output_s signature.
* Always ensure null-termination. Returns the number of written chars, not including the terminating null.
* Returns -1 if something went wrong during the formatting (in _output_s), e.g. mbcs conversions.
* Returns -2 if the string has been truncated.
* _output_s calls _invalid_parameter (and returns -1, possibly) if the format string is malformed.
*/
#ifndef _UNICODE
int __cdecl _soutput_s(char *_Dst, size_t _Size, const char *_Format, va_list _ArgList)
#else /* _UNICODE */
int __cdecl _swoutput_s(wchar_t *_Dst, size_t _Size, const wchar_t *_Format, va_list _ArgList)
#endif /* _UNICODE */
{
FILE stream = { 0 };
FILE *outfile = &stream;
int written = -1;
/* validation section */
#ifndef _UNICODE
if(_Size==SIZE_MAX)
{
/* user is attempting to make us unbounded, but we don't fit that much */
outfile->_cnt = INT_MAX;
}
else
{
_VALIDATE_RETURN(_Size <= INT_MAX, EINVAL, -1);
outfile->_cnt = (int)_Size;
}
outfile->_ptr = outfile->_base = _Dst;
#else /* _UNICODE */
if(_Size==SIZE_MAX)
{
/* user is attempting to make us unbounded, but we don't fit that much */
outfile->_cnt = INT_MAX;
}
else if(_Size>(INT_MAX/sizeof(wchar_t)))
{
/* we can't represent the amount of output the user asked for */
_VALIDATE_RETURN( FALSE, EINVAL, -1 );
}
else
{
outfile->_cnt = (int)(_Size*sizeof(wchar_t));
}
outfile->_ptr = outfile->_base = (char*)_Dst;
#endif /* _UNICODE */
outfile->_flag = _IOWRT | _IOSTRG;
#ifndef _UNICODE
written = _output_s(outfile, _Format, _ArgList);
#else /* _UNICODE */
written = _woutput_s(outfile, _Format, _ArgList);
#endif /* _UNICODE */
_Dst[_Size - 1] = 0;
if (written < 0)
{
if (outfile->_cnt < 0)
{
/* the buffer was too small; we return -2 to indicate truncation */
return -2;
}
/* otherwise, something else failed: we reset the string and we return */
if (_Dst != NULL && _Size > 0)
{
*_Dst = 0;
}
return written;
}
#ifndef _UNICODE
if ((_putc_nolock('\0', outfile) != EOF))
#else /* _UNICODE */
if ((_putc_nolock('\0', outfile) != EOF) && (_putc_nolock('\0', outfile) != EOF))
#endif /* _UNICODE */
{
return written;
}
/* the last putc failed, so it means there is not enough space in the buffer */
return -2;
}
#endif /* _SAFECRT_IMPL */
#ifndef _CFLTCVT
#define _CFLTCVT _cfltcvt
#endif /* _CFLTCVT */
#ifndef _CLDCVT
#define _CLDCVT _cldcvt
#endif /* _CLDCVT */
/* inline keyword is non-ANSI C7 extension */
#if defined (__STDC__)
#define __inline static
#endif /* 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 LONGLONG_IS_INT64 1 /* 1 means long long is same as int64 */
#if defined (_WIN64)
#define PTR_IS_INT 0 /* 1 means ptr is same size as int */
#define PTR_IS_LONG 0 /* 1 means ptr is same size as long */
#define PTR_IS_INT64 1 /* 1 means ptr is same size as int64 */
#else /* defined (_WIN64) */
#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 */
#define PTR_IS_INT64 0 /* 1 means ptr is same size as int64 */
#endif /* defined (_WIN64) */
#if LONGLONG_IS_INT64
#define get_long_long_arg(x) (long long)get_int64_arg(x)
#endif /* LONGLONG_IS_INT64 */
#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 *)(intptr_t)get_int_arg(x)
#elif PTR_IS_LONG
#define get_ptr_arg(x) (void *)(intptr_t)get_long_arg(x)
#elif PTR_IS_INT64
#define get_ptr_arg(x) (void *)get_int64_arg(x)
#else /* PTR_IS_INT64 */
#error Size of pointer must be same as size of int or long
#endif /* PTR_IS_INT64 */
/* 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_LONGLONG 0x01000 /* long long value given */
#define FL_I64 0x08000 /* __int64 value given */
#ifdef POSITIONAL_PARAMETERS
/* We set this flag if %I is passed without I32 or I64 */
#define FL_PTRSIZE 0x10000 /* platform dependent number */
#endif /* POSITIONAL_PARAMETERS */
/* 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 */
#ifdef FORMAT_VALIDATIONS
,ST_INVALID /* Invalid format */
#endif /* FORMAT_VALIDATIONS */
};
#ifdef FORMAT_VALIDATIONS
#define NUMSTATES (ST_INVALID + 1)
#else /* FORMAT_VALIDATIONS */
#define NUMSTATES (ST_TYPE + 1)
#endif /* FORMAT_VALIDATIONS */
/* 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) || defined (FORMAT_VALIDATIONS)
extern char *__nullstring; /* string to print on null ptr */
extern wchar_t *__wnullstring; /* string to print on null ptr */
#else /* defined (_UNICODE) || defined (CPRFLAG) || defined (FORMAT_VALIDATIONS) */
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) || defined (FORMAT_VALIDATIONS) */
/* 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. */
#ifndef FORMAT_VALIDATIONS
#if defined (_UNICODE) || defined (CPRFLAG)
extern const char __lookuptable[];
#else /* defined (_UNICODE) || defined (CPRFLAG) */
extern const char __lookuptable[] = {
/* ' ' */ 0x06,
/* '!' */ 0x00,
/* '"' */ 0x00,
/* '#' */ 0x06,
/* '$' */ 0x00,
/* '%' */ 0x01,
/* '&' */ 0x00,
/* ''' */ 0x00,
/* '(' */ 0x10,
/* ')' */ 0x00,
/* '*' */ 0x03,
/* '+' */ 0x06,
/* ',' */ 0x00,
/* '-' */ 0x06,
/* '.' */ 0x02,
/* '/' */ 0x10,
/* '0' */ 0x04,
/* '1' */ 0x45,
/* '2' */ 0x45,
/* '3' */ 0x45,
/* '4' */ 0x05,
/* '5' */ 0x05,
/* '6' */ 0x05,
/* '7' */ 0x05,
/* '8' */ 0x05,
/* '9' */ 0x35,
/* ':' */ 0x30,
/* ';' */ 0x00,
/* '<' */ 0x50,
/* '=' */ 0x00,
/* '>' */ 0x00,
/* '?' */ 0x00,
/* '@' */ 0x00,
#if defined (_SAFECRT_IMPL)
/* 'A' */ 0x20, // Disable %A format
#else /* defined (_SAFECRT_IMPL) */
/* 'A' */ 0x28,
#endif /* defined (_SAFECRT_IMPL) */
/* 'B' */ 0x20,
/* 'C' */ 0x38,
/* 'D' */ 0x50,
/* 'E' */ 0x58,
/* 'F' */ 0x07,
/* 'G' */ 0x08,
/* 'H' */ 0x00,
/* 'I' */ 0x37,
/* 'J' */ 0x30,
/* 'K' */ 0x30,
/* 'L' */ 0x57,
/* 'M' */ 0x50,
/* 'N' */ 0x07,
/* 'O' */ 0x00,
/* 'P' */ 0x00,
/* 'Q' */ 0x20,
/* 'R' */ 0x20,
/* 'S' */ 0x08,
/* 'T' */ 0x00,
/* 'U' */ 0x00,
/* 'V' */ 0x00,
/* 'W' */ 0x00,
/* 'X' */ 0x08,
/* 'Y' */ 0x60,
/* 'Z' */ 0x68,
/* '[' */ 0x60,
/* '\' */ 0x60,
/* ']' */ 0x60,
/* '^' */ 0x60,
/* '_' */ 0x00,
/* '`' */ 0x00,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?