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;
&n
上一篇: 一个C笔试题引出一系列的问题
下一篇: 快速计算32位数中1的位数