• C语言学习趣事_MSCRT_IO_SourceFile


      前些时候,贴了一段微软的printf代码,园子里的大侠们说要看看output的代码,这不最近有幸看了微软的

    output代码,所以贴上来给园子里大侠看看。

        Tip:

             源代码版权归微软所有,这里仅贴出来供大家看看。

    /***
    *output.c - printf style output to a FILE
    *
    *	Copyright (c) 1989-1991, 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 ****
    *
    *Revision History:
    *	06-01-89  PHG	Module created
    *	08-28-89  JCR	Added cast to get rid of warning (no object changes)
    *	02-15-90  GJF	Fixed copyright
    *	03-19-90  GJF	Made calling type _CALLTYPE1 and added #include
    *			<cruntime.h>.
    *	03-26-90  GJF	Changed LOCAL macro to incorporate _CALLTYPE4. Placed
    *			prototype for _output() in internal.h and #include-d
    *			it.
    *	08-01-90  SBM   Compiles cleanly with -W3, moved _cfltcvt_tab and
    *			typedefs DOUBLE and LONGDOUBLE to new header
    *			<fltintrn.h>, formerly named <struct.h>
    *	09-05-90  SBM   First attempt at adding CPRFLAG and code to generate
    *			cprintf.  Anything in #ifdef CPRFLAG untested.
    *			Still needs to have locking added for MTHREAD case.
    *	10-03-90  GJF	New-style function declarators.
    *	01-02-91  SRW	Added _WIN32_ conditional for 'C' and 'S' format chars.
    *	01-16-91  GJF	ANSI naming.
    *	01-16-91  SRW	Added #include of maketabc.out (_WIN32_)
    *	04-09-91  PNT   Use the _CRUISER_ mapping for _MAC_
    *	04-16-91  SRW	Fixed #include of maketabc.out (_WIN32_)
    *	04-25-91  SRW	Made nullstring static
    *	05-20-91  GJF	Moved state table for Win32 inline (_WIN32_).
    *	09-12-91  JCR	Bumped conversion buffer size to be ANSI-compliant
    *	09-17-91  IHJ	Add partial UNICODE (%ws, %wc) support
    *	09-28-91  GJF	Merged with crt32 and crtdll versions. For now, 9-17-91
    *			change is built only for Win32, not Dosx32 (_WIN32_).
    *	10-22-91  ETC	Complete wchar_t/mb support under _INTL.  For now,
    *			9-28-91 change is additionally under !_INTL.  Bug fix:
    *			ints and pointers are longs.
    *	11-19-91  ETC   Added support for _wsprintf, _vwsprintf with WPRFLAG;
    *			added %tc %ts (generic string handling).
    *	12-05-91  GDP	Bug fix: va_arg was used inconsistently for double
    *	12-19-91  ETC   Added some comments on wsprintf optimization, undones;
    *			check return on malloc.
    *	03-25-92  DJM	POSIX support
    *	04-16-92  KRS	Support new ISO {s|f}wprintf with Unicode format string.
    *	06-08-92  SRW	Modified to not use free and malloc for mbtowc conversion.
    *	06-10-92  KRS	Fix glitch in previous change.
    *	07-14-92  TVB	Added Alpha support (quad stuff).
    *	07-17-92  KRS	Fix typo which broke WPRFLAG support.
    *	04-16-93  SKS	Fix bug in 'S' option logic.
    *   07-16-93  SRW   ALPHA Merge
    *   08-17-93  CFW   Avoid mapping tchar macros incorrectly if _MBCS defined.
    *
    *******************************************************************************/
    
    /* temporary hack to minimize changes. This should go into fltintrn.h */
    #if	defined(_M_MRX000) || defined(_M_ALPHA) || defined(_M_PPC)
    #define DOUBLE double
    #endif
    
    
    #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 <assert.h>
    
    /* inline keyword is non-ANSI C7 extension */
    /* CONSIDER: move to cruntime.h! */
    #if	!defined(_MSC_VER) || defined(__STDC__)
    #define __inline static
    #else
    /* UNDONE: compiler is broken */
    #define __inline static
    #endif
    
    #if defined(WPRFLAG) && !defined(_UNICODE)
    #define _UNICODE 1
    #endif
    #ifdef _MBCS	/* always want either Unicode or SBCS for tchar.h */
    #undef _MBCS
    #endif
    #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 _CALLTYPE4
    
    /* 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
    
    #ifndef WPRFLAG
    #if SHORT_IS_INT
        #define get_short_arg(x) (short)get_int_arg(x)
    #endif
    #endif
    
    #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
        #error Size of pointer must be same as size of int or long
    #endif
    
    
    
    /* CONSTANTS */
    
    /* size of conversion buffer (ANSI-specified minimum is 509) */
    
    #define BUFFERSIZE    512
    
    #if (BUFFERSIZE < CVTBUFSIZE)
    #error Conversion buffer too small for max double.
    #endif
    
    /* flag definitions */
    #define FL_SIGN       0x0001	  /* put plus or minus in front */
    #define FL_SIGNSP     0x0002	  /* put space or minus in front */
    #define FL_LEFT       0x0004	  /* left justify */
    #define FL_LEADZERO   0x0008	  /* pad with leading zeros */
    #define FL_LONG       0x0010	  /* long value given */
    #define FL_SHORT      0x0020	  /* short value given */
    #define FL_SIGNED     0x0040	  /* signed data given */
    #define FL_ALTERNATE  0x0080	  /* alternate form requested */
    #define FL_NEGATIVE   0x0100	  /* value is negative */
    #define FL_FORCEOCTAL 0x0200	  /* force leading '0' for octals */
    #define FL_LONGDOUBLE 0x0400	  /* long double value given */
    #define FL_WIDECHAR   0x0800      /* wide characters */
    
    /* 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(WPRFLAG) || defined(CPRFLAG)
    extern char *__nullstring;	/* string to print on null ptr */
    extern wchar_t *__wnullstring;	/* string to print on null ptr */
    #else	/* WPRFLAG || CPRFLAG */
    char *__nullstring = "(null)";	/* string to print on null ptr */
    wchar_t *__wnullstring = L"(null)";/* string to print on null ptr */
    #endif	/* WPRFLAG || 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(WPRFLAG) || defined(CPRFLAG)
    extern const char __lookuptable[];
    #else	/* WPRFLAG/CPRFLAG */
    #if	defined(_CRUISER_) || defined(_MAC_)
    
    /* Table generated by maketabc.c built with -D_CRUISER_.		  */
    
    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, 0x20, 0x38, 0x50, 0x58, 0x07, 0x08,
    	 0x00, 0x30, 0x30, 0x30, 0x57, 0x50, 0x07, 0x00,
    	 0x00, 0x20, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00,
    	 0x08, 0x60, 0x60, 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,
    	 0x08
    };
    
    #else	/* ndef _CRUISER_ || _MAC_ */
    
    #if	defined(_WIN32_) || defined(_POSIX_)
    
    /* 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, 0x20, 0x38, 0x50, 0x58, 0x07, 0x08,
    	 0x00, 0x30, 0x30, 0x30, 0x57, 0x50, 0x07, 0x00,
    	 0x00, 0x20, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00,
    	 0x08, 0x60, 0x68, 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,
    	 0x08
    };
    
    #else	/* ndef _WIN32_ */
    
    #error ERROR - ONLY CRUISER, WIN32, POSIX, OR MAC TARGET SUPPORTED!
    
    #endif	/* _WIN32_ || _POSIX_ */
    
    #endif	/* _CRUISER_ || _MAC_ */
    
    #endif	/* WPRFLAG || 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 WPRFLAG 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 WPRFLAG
    
    #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(int 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
    
    #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
    
    __inline int _CALLTYPE4 get_int_arg(va_list *pargptr);
    
    #ifndef WPRFLAG
    #if !SHORT_IS_INT
    __inline short _CALLTYPE4 get_short_arg(va_list *pargptr);
    #endif
    #endif
    
    #if !LONG_IS_INT
    __inline long _CALLTYPE4 get_long_arg(va_list *pargptr);
    #endif
    
    #ifdef _ALPHA_
    __inline __int64 _CALLTYPE4 get_quad_arg(va_list *pargptr);
    #endif
    
    #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 _CALLTYPE2 _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 WPRFLAG
    *   The wide-character flavour returns the number of wide-characters written.
    #endif
    *
    *Exceptions:
    *
    *******************************************************************************/
    
    #ifdef CPRFLAG
    LOCAL(int) output (
    #elif WPRFLAG
    int _CALLTYPE1 _woutput (
        FILE *stream,
    #else
    int _CALLTYPE1 _output (
        FILE *stream,
    #endif
        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 WPRFLAG */
        union {
    	char sz[BUFFERSIZE];
    #ifdef WPRFLAG
    	wchar_t wz[BUFFERSIZE];
    #endif
    	} buffer;
        wchar_t wchar;	/* temp wchar_t */
        int bufferiswide;	/* non-zero = buffer contains wide chars already */
    
        charsout = 0;		/* no characters written yet */
        state = ST_NORMAL;		/* starting state */
    
        /* main loop -- loop while format character exist and no I/O errors */
        while ((ch = *format++) != _T('\0') && charsout >= 0) {
    	chclass = find_char_class(ch);	/* find character class */
    	state = find_next_state(chclass, state); /* find next state */
    
    	/* execute code for each state */
    	switch (state) {
    
    	case ST_NORMAL:
    	    /* normal state -- just write character */
    #ifdef WPRFLAG
    	    bufferiswide = 1;
    #else
    	    bufferiswide = 0;
    	    if (isleadbyte((int)(unsigned char)ch)) {
    		WRITE_CHAR(ch, &charsout);
    		ch = *format++;
    		assert (ch != _T('\0')); /* UNDONE: don't fall off format string */
    	    }
    #endif /* !WPRFLAG */
    	    WRITE_CHAR(ch, &charsout);
    	    break;
    
    	case ST_PERCENT:
    	    /* set default value of conversion parameters */
    	    prefixlen = fldwidth = no_output = capexp = 0;
    	    flags = 0;
    	    precision = -1;
    	    bufferiswide = 0;	/* default */
    	    break;
    
    	case ST_FLAG:
    	    /* set flag based on which flag character */
    	    switch (ch) {
    	    case _T('-'):
    		flags |= FL_LEFT;	/* '-' => left justify */
    		break;
    	    case _T('+'):
    		flags |= FL_SIGN;	/* '+' => force sign indicator */
    		break;
    	    case _T(' '):
    		flags |= FL_SIGNSP;	/* ' ' => force sign or space */
    		break;
    	    case _T('#'):
    		flags |= FL_ALTERNATE;	/* '#' => alternate form */
    		break;
    	    case _T('0'):
    		flags |= FL_LEADZERO;	/* '0' => pad with leading zeros */
    		break;
    	    }
    	    break;
    
    	case ST_WIDTH:
    	    /* update width value */
    	    if (ch == _T('*')) {
    		/* get width from arg list */
    		fldwidth = get_int_arg(&argptr);
    		if (fldwidth < 0) {
    		    /* ANSI says neg fld width means '-' flag and pos width */
    		    flags |= FL_LEFT;
    		    fldwidth = -fldwidth;
    		}
    	    }
    	    else {
    		/* add digit to current field width */
    		fldwidth = fldwidth * 10 + (ch - _T('0'));
    	    }
    	    break;
    
    	case ST_DOT:
    	    /* zero the precision, since dot with no number means 0
    	       not default, according to ANSI */
    	    precision = 0;
    	    break;
    
    	case ST_PRECIS:
    	    /* update precison value */
    	    if (ch == _T('*')) {
    		/* get precision from arg list */
    		precision = get_int_arg(&argptr);
    		if (precision < 0)
    		    precision = -1;	/* neg precision means default */
    	    }
    	    else {
    		/* add digit to current precision */
    		precision = precision * 10 + (ch - _T('0'));
    	    }
    	    break;
    
    	case ST_SIZE:
    	    /* just read a size specifier, set the flags based on it */
    	    switch (ch) {
    #if !LONG_IS_INT || !defined(_UNICODE)
    	    case _T('l'):
    		flags |= FL_LONG;   /* 'l' => long int or wchar_t */
    		break;
    #endif
    
    #if !LONGDOUBLE_IS_DOUBLE || defined(_ALPHA_)
    	    /*
    	     * Alpha has native 64-bit integer registers and operations.
    	     * The int and long types are 32 bits and an Alpha specific
    	     * __int64 type is 64 bits.  We also use the 'L' flag for
    	     * integer arguments to indicate 64-bit conversions (%Lx).
    	     */
    
    	    case _T('L'):
    		flags |= FL_LONGDOUBLE; /* 'L' => long double */
    		break;
    #endif
    
    #if !SHORT_IS_INT || defined(_UNICODE)
    	    case _T('h'):
    		flags |= FL_SHORT;  /* 'h' => short int or char */
    		break;
    #endif
    
    /* UNDONE: support %wc and %ws for now only for compatibility */
     	    case _T('w'):
     		flags |= FL_WIDECHAR;  /* 'w' => wide character */
     		break;
    
    	    }
    	    break;
    
    	case ST_TYPE:
    	    /* we have finally read the actual type character, so we	   */
    	    /* now format and "print" the output.  We use a big switch	   */
    	    /* statement that sets 'text' to point to the text that should */
    	    /* be printed, and 'textlen' to the length of this text.	   */
    	    /* Common code later on takes care of justifying it and	   */
    	    /* other miscellaneous chores.  Note that cases share code,    */
    	    /* in particular, all integer formatting is done in one place. */
    	    /* Look at those funky goto statements!			   */
    
    	    switch (ch) {
    
    	    case _T('C'):	/* ISO wide character */
    		if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
    #ifdef WPRFLAG
    		    /* CONSIDER: non-standard */
    		    flags |= FL_SHORT;
    #else
    		    flags |= FL_WIDECHAR;	/* ISO std. */
    #endif
    		/* fall into 'c' case */
    
    	    case _T('c'): {
    		/* print a single character specified by int argument */
    #ifdef WPRFLAG
    		bufferiswide = 1;
    		wchar = (wchar_t) get_int_arg(&argptr);
    		if (flags & FL_SHORT)
    		    {
    			/* format multibyte character */
    			/* this is an extension of ANSI */
    			char tempchar[2];
    #ifdef _OUT
    			if (isleadbyte(wchar >> 8))
    			    {
    			    tempchar[0] = (wchar >> 8);
    			    tempchar[1] = (wchar & 0x00ff);
    			    }
    			else
    #endif /* _OUT */
    			    {
    			    tempchar[0] = (char)(wchar & 0x00ff);
    			    tempchar[1] = '\0';
    			    }
    			if (mbtowc(buffer.wz,tempchar,MB_CUR_MAX) < 0)
    			    {
    			    /* ignore if conversion was unsuccessful */
    			    no_output = 1;
    			    }
    		    }
    		else
    		    {
    		    buffer.wz[0] = wchar;
    		    }
    		text.wz = buffer.wz;
    		textlen = 1;    /* print just a single character */
    #else	/* WPRFLAG */
    		if (flags & (FL_LONG|FL_WIDECHAR))
    		    {
    		    wchar = (wchar_t) get_short_arg(&argptr);
    		    /* convert to multibyte character */
    		    textlen = wctomb(buffer.sz, wchar);
    
    		    /* check that conversion was successful */
    		    if (textlen < 0)
    			no_output = 1;
    		    }
    		else
    		    {
    		    /* format multibyte character */
    		    /* this is an extension of ANSI */
    		    unsigned short temp;
    		    temp = (unsigned short) get_int_arg(&argptr);
    #ifdef _OUT
    		    if (isleadbyte(temp >> 8))
    			{
    			buffer.sz[0] = temp >> 8;
    			buffer.sz[1] = temp & 0x00ff;
    			textlen = 2;
    			}
    		    else
    #endif /* _OUT */
    			{
    			buffer.sz[0] = (char) temp;
    			textlen = 1;
    			}
    		    }
    		text.sz = buffer.sz;
    #endif	/* WPRFLAG */
    	    }
    	    break;
    
    #if defined(_WIN32_) && !defined(_DOSX32_)	/* UNDONE: NT hack */
    	    case _T('Z'): {
    		/* print a Counted String
    
    		int i;
    		char *p;       /* temps */
                    struct string {
                        short Length;
                        short MaximumLength;
                        char *Buffer;
                    } *pstr;
    
    		pstr = get_ptr_arg(&argptr);
    		if (pstr == NULL || pstr->Buffer == NULL) {
    		    /* null ptr passed, use special string */
    		    text.sz = __nullstring;
                        textlen = strlen(text.sz);
    		} else {
    		    if (flags & FL_WIDECHAR) {
                            text.wz = (wchar_t *)pstr->Buffer;
    			textlen = pstr->Length / sizeof(wchar_t);
                            bufferiswide = 1;
    		    } else {
                            bufferiswide = 0;
                            text.sz = pstr->Buffer;
    			textlen = pstr->Length;
    		    }
                    }
    	    }
    	    break;
    #endif
    
    	    case _T('S'):	/* ISO wide character string */
    #ifndef WPRFLAG
    		if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
    			flags |= FL_WIDECHAR;
    #else
    		if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
    	    		flags |= FL_SHORT;
    #endif
    	    case _T('s'): {
    		/* print a string --				*/
    		/* ANSI rules on how much of string to print:	*/
    		/*   all if precision is default,		*/
    		/*   min(precision, length) if precision given. */
    		/* prints '(null)' if a null string is passed	*/
    
    		int i;
    		char *p;       /* temps */
    		wchar_t *pwch;
    
    		/* At this point it is tempting to use strlen(), but */
    		/* if a precision is specified, we're not allowed to */
    		/* scan past there, because there might be no null   */
    		/* at all.  Thus, we must do our own scan.	     */
    
    		i = (precision == -1) ? INT_MAX : precision;
    		text.sz = get_ptr_arg(&argptr);
    
    /* UNDONE: handle '#' case properly */
    		/* scan for null upto i characters */
    #ifdef WPRFLAG
    		if (flags & FL_SHORT)
    		    {
    		    if (text.sz == NULL) /* NULL passed, use special string */
    			text.sz = __nullstring;
    		    p = text.sz;
    		    for (textlen=0; textlen<i && *p; textlen++)
    			{
    			if (isleadbyte((int)*p))
    			    ++p;
    			++p;
    			}
    		    /* textlen now contains length in multibyte chars */
    		    }
    		else
    		    {
    		    if (text.wz == NULL) /* NULL passed, use special string */
    			text.wz = __wnullstring;
    		    bufferiswide = 1;
    		    pwch = text.wz;
    		    while (i-- && *pwch)
    			++pwch;
    		    textlen = pwch - text.wz;	/* in wchar_ts */
    		    /* textlen now contains length in wide chars */
    		    }
    #else	/* WPRFLAG */
    		if (flags & (FL_LONG|FL_WIDECHAR))
    		    {
    		    size_t temp;
    		    char tchr[MB_LEN_MAX];
    		    if (text.wz == NULL) /* NULL passed, use special string */
    			text.wz = __wnullstring;
    		    bufferiswide = 1;
    		    pwch = text.wz;
    		    for (textlen=0; textlen<i && *pwch; pwch++)
    			{
    			if ((temp = wctomb(tchr, *pwch))<=0) break;
    			textlen += temp;
    			}
    		    /* textlen now contains length in bytes */
    		    }
    		else
    		    {
    		    if (text.sz == NULL) /* NULL passed, use special string */
    			text.sz = __nullstring;
    		    p = text.sz;
    		    while (i-- && *p)
    			++p;
    		    textlen = p - text.sz;    /* length of the string */
    		    }
    
    #endif	/* WPRFLAG */
    	    }
    	    break;
    
    
    	    case _T('n'): {
    		/* write count of characters seen so far into */
    		/* short/int/long thru ptr read from args */
    
    		void *p;	    /* temp */
    
    		p = get_ptr_arg(&argptr);
    
    		/* store chars out into short/long/int depending on flags */
    #if !LONG_IS_INT
    		if (flags & FL_LONG)
    		    *(long *)p = charsout;
    		else
    #endif
    
    #if !SHORT_IS_INT
    		if (flags & FL_SHORT)
    		    *(short *)p = (short) charsout;
    		else
    #endif
    		    *(int *)p = charsout;
    
    		no_output = 1;		    /* force no output */
    	    }
    	    break;
    
    
    	    case _T('E'):
    	    case _T('G'):
    		capexp = 1;		    /* capitalize exponent */
    		ch += _T('a') - _T('A');    /* convert format char to lower */
    		/* DROP THROUGH */
    	    case _T('e'):
    	    case _T('f'):
    	    case _T('g'):	{
    		/* floating point conversion -- we call cfltcvt routines */
    		/* to do the work for us.				 */
    		flags |= FL_SIGNED;	    /* floating point is signed conversion */
    		text.sz = buffer.sz;		    /* put result in buffer */
    
    		/* compute the precision value */
    		if (precision < 0)
    		    precision = 6;	/* default precision: 6 */
    		else if (precision == 0 && ch == _T('g'))
    		    precision = 1;	/* ANSI specified */
    
    #if !LONGDOUBLE_IS_DOUBLE
    		/* do the conversion */
    		if (flags & FL_LONGDOUBLE) {
    		    LONGDOUBLE tmp;
    		    tmp=va_arg(argptr, LONGDOUBLE);
    		    /* Note: assumes ch is in ASCII range */
    		    _cldcvt(&tmp, text.sz, (char)ch, precision, capexp);
    		}
    		else
    #endif
    		{
    		    DOUBLE tmp;
    		    tmp=va_arg(argptr, DOUBLE);
    		    /* Note: assumes ch is in ASCII range */
    		    _cfltcvt(&tmp,text.sz, (char)ch, precision, capexp);
    		}
    
    		/* '#' and precision == 0 means force a decimal point */
    		if ((flags & FL_ALTERNATE) && precision == 0)
    		    _forcdecpt(text.sz);
    
    		/* 'g' format means crop zero unless '#' given */
    		if (ch == _T('g') && !(flags & FL_ALTERNATE))
    		    _cropzeros(text.sz);
    
    		/* check if result was negative, save '-' for later */
    		/* and point to positive part (this is for '0' padding) */
    		if (*text.sz == '-') {
    		    flags |= FL_NEGATIVE;
    		    ++text.sz;
    		}
    
    		textlen = strlen(text.sz);     /* compute length of text */
    	    }
    	    break;
    
    	    case _T('d'):
    	    case _T('i'):
    		/* signed decimal output */
    		flags |= FL_SIGNED;
    		radix = 10;
    		goto COMMON_INT;
    
    	    case _T('u'):
    		radix = 10;
    		goto COMMON_INT;
    
    	    case _T('p'):
    		/* write a pointer -- this is like an integer or long */
    		/* except we force precision to pad with zeros and */
    		/* output in big hex. */
    
    		precision = 2 * sizeof(void *);     /* number of hex digits needed */
    #if !PTR_IS_INT
    		flags |= FL_LONG;	/* assume we're converting a long */
    #endif
    		/* DROP THROUGH to hex formatting */
    
    	    case _T('X'):
    		/* unsigned upper hex output */
    		hexadd = _T('A') - _T('9') - 1;     /* set hexadd for uppercase hex */
    		goto COMMON_HEX;
    
    	    case _T('x'):
    		/* unsigned lower hex output */
    		hexadd = _T('a') - _T('9') - 1;     /* set hexadd for lowercase hex */
    		/* DROP THROUGH TO COMMON_HEX */
    
    	    COMMON_HEX:
    		radix = 16;
    		if (flags & FL_ALTERNATE) {
    		    /* alternate form means '0x' prefix */
    		    prefix[0] = _T('0');
    		    prefix[1] = (TCHAR)(_T('x') - _T('a') + _T('9') + 1 + hexadd);	/* 'x' or 'X' */
    		    prefixlen = 2;
    		}
    		goto COMMON_INT;
    
    	    case _T('o'):
    		/* unsigned octal output */
    		radix = 8;
    		if (flags & FL_ALTERNATE) {
    		    /* alternate form means force a leading 0 */
    		    flags |= FL_FORCEOCTAL;
    		}
    		/* DROP THROUGH to COMMON_INT */
    
    	    COMMON_INT: {
    		/* This is the general integer formatting routine. */
    		/* Basically, we get an argument, make it positive */
    		/* if necessary, and convert it according to the */
    		/* correct radix, setting text and textlen */
    		/* appropriately. */
    
    #ifdef _ALPHA_
    		unsigned __int64 number; /* number to convert */
    		int digit;		/* ascii value of digit */
    		__int64 l; 		/* temp long value */
    #else
    		unsigned long number;	/* number to convert */
    		int digit;		/* ascii value of digit */
    		long l; 		/* temp long value */
    #endif
    
    		/* 1. read argument into l, sign extend as needed */
    #ifdef _ALPHA_
    		if (flags & FL_LONGDOUBLE)
    		    l = get_quad_arg(&argptr);
    		else
    #endif
    #if !LONG_IS_INT
    		if (flags & FL_LONG)
    		    l = get_long_arg(&argptr);
    		else
    #endif
    
    #if !SHORT_IS_INT
    		if (flags & FL_SHORT) {
    		    if (flags & FL_SIGNED)
    			l = (short) get_int_arg(&argptr); /* sign extend */
    		    else
    			l = (unsigned short) get_int_arg(&argptr);    /* zero-extend*/
    		}
    		else
    #endif
    		{
    		    if (flags & FL_SIGNED)
    			l = get_int_arg(&argptr); /* sign extend */
    		    else
    			l = (unsigned int) get_int_arg(&argptr);    /* zero-extend*/
    		}
    
    		/* 2. check for negative; copy into number */
    		if ( (flags & FL_SIGNED) && l < 0) {
    		    number = -l;
    		    flags |= FL_NEGATIVE;   /* remember negative sign */
    		}
    		else {
    		    number = l;
    		}
    #ifdef _ALPHA_
    		if ((flags & FL_LONGDOUBLE) == 0) {
    		    /*
    		     * Unless printing a full 64-bit value, insure values
    		     * here are not in cananical longword format to prevent
    		     * the sign extended upper 32-bits from being printed.
    		     */
    		    number &= 0xffffffff;
    		}
    #endif
    
    		/* 3. check precision value for default; non-default */
    		/*    turns off 0 flag, according to ANSI. */
    		if (precision < 0)
    		    precision = 1;		/* default precision */
    		else
    		    flags &= ~FL_LEADZERO;
    
    		/* 4. Check if data is 0; if so, turn off hex prefix */
    		if (number == 0)
    		    prefixlen = 0;
    
    		/* 5. Convert data to ASCII -- note if precision is zero */
    		/*    and number is zero, we get no digits at all.	 */
    
    		text.sz = &buffer.sz[BUFFERSIZE-1];	   /* last digit at end of buffer */
    
    		while (precision-- > 0 || number != 0) {
    		    digit = (int)(number % radix) + '0';
    		    number /= radix;		/* reduce number */
    		    if (digit > '9') {
    			/* a hex digit, make it a letter */
    			digit += hexadd;
    		    }
    		    *text.sz-- = (char)digit;	/* store the digit */
    		}
    
    		textlen = (char *)&buffer.sz[BUFFERSIZE-1] - text.sz; /* compute length of number */
    		++text.sz; 	/* text points to first digit now */
    
    
    		/* 6. Force a leading zero if FORCEOCTAL flag set */
    		if ((flags & FL_FORCEOCTAL) && (text.sz[0] != '0' || textlen == 0)) {
    		    *--text.sz = '0';
    		    ++textlen;		/* add a zero */
    		}
    	    }
    	    break;
    	    }
    
    	    /* At this point, we have done the specific conversion, and */
    	    /* 'text' points to text to print; 'textlen' is length.  Now we */
    	    /* justify it, put on prefixes, leading zeros, and then */
    	    /* print it. */
    
    	    if (!no_output) {
    		int padding;	/* amount of padding, negative means zero */
    
    		if (flags & FL_SIGNED) {
    		    if (flags & FL_NEGATIVE) {
    			/* prefix is a '-' */
    			prefix[0] = _T('-');
    			prefixlen = 1;
    		    }
    		    else if (flags & FL_SIGN) {
    			/* prefix is '+' */
    			prefix[0] = _T('+');
    			prefixlen = 1;
    		    }
    		    else if (flags & FL_SIGNSP) {
    			/* prefix is ' ' */
    			prefix[0] = _T(' ');
    			prefixlen = 1;
    		    }
    		}
    
    		/* calculate amount of padding -- might be negative, */
    		/* but this will just mean zero */
    		padding = fldwidth - textlen - prefixlen;
    
    		/* put out the padding, prefix, and text, in the correct order */
    
    		if (!(flags & (FL_LEFT | FL_LEADZERO))) {
    		    /* pad on left with blanks */
    		    WRITE_MULTI_CHAR(_T(' '), padding, &charsout);
    		}
    
    		/* write prefix */
    		WRITE_STRING(prefix, prefixlen, &charsout);
    
    		if ((flags & FL_LEADZERO) && !(flags & FL_LEFT)) {
    		    /* write leading zeros */
    		    WRITE_MULTI_CHAR(_T('0'), padding, &charsout);
    		}
    
    		/* write text */
    #ifndef WPRFLAG
    		if (bufferiswide && (textlen > 0))
    		    {
                        wchar_t *p;
                        int retval, count;
                        char buffer[MB_LEN_MAX+1];
    
                        p = text.wz;
                        count = textlen;
                        while (count--) {
                            retval = wctomb(buffer, *p++);
                            if (retval <= 0)
                                break;
                            WRITE_STRING(buffer, retval, &charsout);
                        }
    		    }
    		else
    		    {
    		    WRITE_STRING(text.sz, textlen, &charsout);
    		    }
    #else
    		if (!bufferiswide && textlen > 0) {
                        char *p;
                        int retval, count;
    
                        p = text.sz;
                        count = textlen;
                        while (count-- > 0) {
                            retval = mbtowc(&wchar, p, MB_CUR_MAX);
                            if (retval <= 0)
                                break;
                            WRITE_CHAR(wchar, &charsout);
                            p += retval;
                        }
    		} else {
    		    WRITE_STRING(text.wz, textlen, &charsout);
    		}
    #endif /* WPRFLAG */
    
    		if (flags & FL_LEFT) {
    		    /* pad on right with blanks */
    		    WRITE_MULTI_CHAR(_T(' '), padding, &charsout);
    		}
    
    		/* we're done! */
    	    }
    	    break;
    	}
        }
    
        return charsout;	    /* return value = number of characters written */
    }
    
    /*
     *  Future Optimizations for swprintf:
     *  - Don't free the memory used for converting the buffer to wide chars.
     *    Use realloc if the memory is not sufficient.  Free it at the end.
     */
    
    /***
    *void write_char(int ch, int *pnumwritten)
    #ifdef WPRFLAG
    *void write_char(wchar_t ch, FILE *f, int *pnumwritten)
    #endif
    *void write_char(int ch, FILE *f, int *pnumwritten)
    *
    *Purpose:
    *   Writes a single character to the given file/console.  If no error occurs,
    *   then *pnumwritten is incremented; otherwise, *pnumwritten is set
    *   to -1.
    *
    *Entry:
    *   int ch	     - character to write
    *   FILE *f	     - file to write to
    *   int *pnumwritten - pointer to integer to update with total chars written
    *
    *Exit:
    *   No return value.
    *
    *Exceptions:
    *
    *******************************************************************************/
    
    #ifdef CPRFLAG
    
    LOCAL(void) write_char (
        int ch,
        int *pnumwritten
        )
    {
        if (_putch_lk(ch) == EOF)
    	*pnumwritten = -1;
        else
    	++(*pnumwritten);
    }
    
    #elif WPRFLAG
    
    LOCAL(void) write_char (
        int ch,
        FILE *f,
        int *pnumwritten
        )
    {
        if (_putwc_lk(ch, f) == WEOF)
    	*pnumwritten = -1;
        else
    	++(*pnumwritten);
    }
    
    #else
    
    LOCAL(void) write_char (
        int ch,
        FILE *f,
        int *pnumwritten
        )
    {
        if (_putc_lk(ch, f) == EOF)
    	*pnumwritten = -1;
        else
    	++(*pnumwritten);
    }
    
    #endif
    
    /***
    *void write_multi_char(int ch, int num, int *pnumwritten)
    #ifdef WPRFLAG
    *void write_multi_char(wchar_t ch, int num, FILE *f, int *pnumwritten)
    #endif
    *void write_multi_char(int ch, int num, FILE *f, int *pnumwritten)
    *
    *Purpose:
    *   Writes num copies of a character to the given file/console.  If no error occurs,
    *   then *pnumwritten is incremented by num; otherwise, *pnumwritten is set
    *   to -1.  If num is negative, it is treated as zero.
    *
    *Entry:
    *   int ch	     - character to write
    *   int num	     - number of times to write the characters
    *   FILE *f	     - file to write to
    *   int *pnumwritten - pointer to integer to update with total chars written
    *
    *Exit:
    *   No return value.
    *
    *Exceptions:
    *
    *******************************************************************************/
    
    #ifdef CPRFLAG
    
    LOCAL(void) write_multi_char (
        int ch,
        int num,
        int *pnumwritten
        )
    {
        while (num-- > 0)
    	write_char(ch, pnumwritten);
    }
    
    #else	/* CPRFLAG */
    #if WPRFLAG
    
    LOCAL(void) write_multi_char (
        wchar_t ch,
        int num,
        FILE *f,
        int *pnumwritten
        )
    #else
    
    LOCAL(void) write_multi_char (
        int ch,
        int num,
        FILE *f,
        int *pnumwritten
        )
    #endif	/* WPRFLAG */
    {
        while (num-- > 0)
    	write_char(ch, f, pnumwritten);
    }
    
    #endif	/* CPRFLAG */
    
    /***
    *void write_string(char *string, int len, int *pnumwritten)
    *void write_string(char *string, int len, FILE *f, int *pnumwritten)
    #ifdef WPRFLAG
    *void write_string(wchar_t *string, int len, FILE *f, int *pnumwritten)
    #endif
    *void write_wstring(wchar_t *string, int len, int *pnumwritten)
    *void write_wstring(wchar_t *string, int len, FILE *f, int *pnumwritten)
    *
    *Purpose:
    *   Writes a string of the given length to the given file.  If no error occurs,
    *   then *pnumwritten is incremented by len; otherwise, *pnumwritten is set
    *   to -1.  If len is negative, it is treated as zero.
    *
    *Entry:
    *   char *string     - string to write (NOT null-terminated)
    *   int len	     - length of string
    *   FILE *f	     - file to write to
    *   int *pnumwritten - pointer to integer to update with total chars written
    *
    *Exit:
    *   No return value.
    *
    *Exceptions:
    *
    *******************************************************************************/
    
    #ifdef CPRFLAG
    
    LOCAL(void) write_string (
        char *string,
        int len,
        int *pnumwritten
        )
    {
        while (len-- > 0)
    	write_char(*string++, pnumwritten);
    }
    
    #else	/* CPRFLAG */
    #if WPRFLAG
    
    LOCAL(void) write_string (
        wchar_t *string,
        int len,
        FILE *f,
        int *pnumwritten
        )
    #else
    
    LOCAL(void) write_string (
        char *string,
        int len,
        FILE *f,
        int *pnumwritten
        )
    #endif	/* WPRFLAG */
    {
    #ifdef _POSIX_
        while (len-- > 0) {
    	write_char(*string++, f, pnumwritten);
    	if (*pnumwritten < 0)
    	    return;
        }
    #else
        while (len-- > 0)
    	write_char(*string++, f, pnumwritten);
    #endif
    }
    #endif	/* CPRFLAG */
    
    
    /***
    *int get_int_arg(va_list *pargptr)
    *
    *Purpose:
    *   Gets an int argument off the given argument list and updates *pargptr.
    *
    *Entry:
    *   va_list *pargptr - pointer to argument list; updated by function
    *
    *Exit:
    *   Returns the integer argument read from the argument list.
    *
    *Exceptions:
    *
    *******************************************************************************/
    
    __inline int _CALLTYPE4 get_int_arg (
        va_list *pargptr
        )
    {
        return va_arg(*pargptr, int);
    }
    
    /***
    *long get_long_arg(va_list *pargptr)
    *
    *Purpose:
    *   Gets an long argument off the given argument list and updates *pargptr.
    *
    *Entry:
    *   va_list *pargptr - pointer to argument list; updated by function
    *
    *Exit:
    *   Returns the long argument read from the argument list.
    *
    *Exceptions:
    *
    *******************************************************************************/
    
    #if !LONG_IS_INT
    __inline long _CALLTYPE4 get_long_arg (
        va_list *pargptr
        )
    {
        return va_arg(*pargptr, long);
    }
    #endif
    
    #ifdef _ALPHA_
    __inline __int64 _CALLTYPE4 get_quad_arg (
        va_list *pargptr
        )
    {
        return va_arg(*pargptr, __int64);
    }
    #endif
    
    #ifndef WPRFLAG
    /***
    *short get_short_arg(va_list *pargptr)
    *
    *Purpose:
    *   Gets a short argument off the given argument list and updates *pargptr.
    *   *** CURRENTLY ONLY USED TO GET A WCHAR_T, IFDEF _INTL ***
    *
    *Entry:
    *   va_list *pargptr - pointer to argument list; updated by function
    *
    *Exit:
    *   Returns the short argument read from the argument list.
    *
    *Exceptions:
    *
    *******************************************************************************/
    
    #if !SHORT_IS_INT
    __inline short _CALLTYPE4 get_short_arg (
        va_list *pargptr
        )
    {
        return va_arg(*pargptr, short);
    }
    #endif
    #endif
    

      发现园子网页代码的一个bug,请管理员注意。

          将上面这段代码用另外一种代码上传工具,那么就会提示错误。

  • 相关阅读:
    jupyter notebook 将当前目录设置为工作目录
    推荐个不错的服务器管理软件
    jupyter notebook 安装记录
    微软发布 Pylance:改善 VS Code 中的 Python 体验
    paddleocr安装笔记
    开源免费!7款服务器管理工具
    极简Linux下安装极简桌面
    解决 win7 win10 等 64位 支持access数据库问题
    泓格WINPAC主机与第三方模块rs 485 modbus rtu通信测试
    ajax
  • 原文地址:https://www.cnblogs.com/volcanol/p/2404426.html
Copyright © 2020-2023  润新知