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 + -
显示快捷键?