in CoreCLRProfiler/native/coreclr_headers/src/pal/src/safecrt/safecrt_output_l.cpp [520:1263]
_CRTIMP int __cdecl _vtcprintf_l (
#else /* FORMAT_VALIDATIONS */
_CRTIMP int __cdecl _vtcprintf_s_l (
#endif /* FORMAT_VALIDATIONS */
#else /* CPRFLAG */
#ifdef _UNICODE
#ifndef FORMAT_VALIDATIONS
int __cdecl _woutput (
miniFILE *stream,
#else /* FORMAT_VALIDATIONS */
int __cdecl _woutput_s (
miniFILE *stream,
#endif /* FORMAT_VALIDATIONS */
#else /* _UNICODE */
#ifndef FORMAT_VALIDATIONS
int __cdecl _output (
miniFILE *stream,
#else /* FORMAT_VALIDATIONS */
int __cdecl _output_s (
miniFILE *stream,
#endif /* FORMAT_VALIDATIONS */
#endif /* _UNICODE */
#endif /* CPRFLAG */
const _TCHAR *format,
va_list argptr
)
{
int hexadd=0; /* offset to add to number to get 'a'..'f' */
TCHAR ch; /* character just read */
int flags=0; /* 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 = 0; /* selected field width -- 0 means default */
int precision = 0; /* selected precision -- -1 means default */
TCHAR prefix[2]; /* numeric prefix -- up to two characters */
int prefixlen=0; /* length of prefix -- 0 means no prefix */
int capexp = 0; /* non-zero = 'E' exponent signifient, zero = 'e' */
int no_output=0; /* non-zero = prodcue no output for this specifier */
union {
const char *sz; /* pointer text to be printed, not zero terminated */
const char16_t *wz;
} text;
int textlen; /* length of the text in bytes/wchars to be printed.
textlen is in multibyte or wide chars if _UNICODE */
union {
char sz[BUFFERSIZE];
#ifdef _UNICODE
char16_t wz[BUFFERSIZE];
#endif /* _UNICODE */
} buffer;
char16_t wchar; /* temp char16_t */
int buffersize; /* size of text.sz (used only for the call to _cfltcvt) */
int bufferiswide=0; /* non-zero = buffer contains wide chars already */
#ifndef CPRFLAG
_VALIDATE_RETURN( (stream != NULL), EINVAL, -1);
#endif /* CPRFLAG */
_VALIDATE_RETURN( (format != NULL), EINVAL, -1);
charsout = 0; /* no characters written yet */
textlen = 0; /* no text yet */
state = ST_NORMAL; /* starting state */
buffersize = 0;
/* main loop -- loop while format character exist and no I/O errors */
while ((ch = *format++) != _T('\0') && charsout >= 0) {
#ifndef FORMAT_VALIDATIONS
chclass = FIND_CHAR_CLASS(__lookuptable, ch); /* find character class */
state = FIND_NEXT_STATE(__lookuptable, chclass, state); /* find next state */
#else /* FORMAT_VALIDATIONS */
chclass = FIND_CHAR_CLASS(__lookuptable_s, ch); /* find character class */
state = FIND_NEXT_STATE(__lookuptable_s, chclass, state); /* find next state */
_VALIDATE_RETURN((state != ST_INVALID), EINVAL, -1);
#endif /* FORMAT_VALIDATIONS */
/* execute code for each state */
switch (state) {
case ST_NORMAL:
NORMAL_STATE:
/* normal state -- just write character */
#ifdef _UNICODE
bufferiswide = 1;
#else /* _UNICODE */
bufferiswide = 0;
#endif /* _UNICODE */
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) {
case _T('l'):
/*
* In order to handle the ll case, we depart from the
* simple deterministic state machine.
*/
if (*format == _T('l'))
{
++format;
flags |= FL_LONGLONG; /* 'll' => long long */
}
else
{
flags |= FL_LONG; /* 'l' => long int or char16_t */
}
break;
case _T('I'):
/*
* In order to handle the I, I32, and I64 size modifiers, we
* depart from the simple deterministic state machine. The
* code below scans for characters following the 'I',
* and defaults to 64 bit on WIN64 and 32 bit on WIN32
*/
#if PTR_IS_INT64
flags |= FL_I64; /* 'I' => __int64 on WIN64 systems */
#endif /* PTR_IS_INT64 */
if ( (*format == _T('6')) && (*(format + 1) == _T('4')) )
{
format += 2;
flags |= FL_I64; /* I64 => __int64 */
}
else if ( (*format == _T('3')) && (*(format + 1) == _T('2')) )
{
format += 2;
flags &= ~FL_I64; /* I32 => __int32 */
}
else if ( (*format == _T('d')) ||
(*format == _T('i')) ||
(*format == _T('o')) ||
(*format == _T('u')) ||
(*format == _T('x')) ||
(*format == _T('X')) )
{
/*
* Nothing further needed. %Id (et al) is
* handled just like %d, except that it defaults to 64 bits
* on WIN64. Fall through to the next iteration.
*/
}
else {
state = ST_NORMAL;
goto NORMAL_STATE;
}
break;
case _T('h'):
flags |= FL_SHORT; /* 'h' => short int or char */
break;
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 _UNICODE
flags |= FL_SHORT;
#else /* _UNICODE */
flags |= FL_WIDECHAR; /* ISO std. */
#endif /* _UNICODE */
/* fall into 'c' case */
case _T('c'): {
/* print a single character specified by int argument */
#ifdef _UNICODE
bufferiswide = 1;
wchar = (char16_t) get_int_arg(&argptr);
if (flags & FL_SHORT) {
/* format multibyte character */
/* this is an extension of ANSI */
char tempchar[2];
{
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 /* _UNICODE */
if (flags & (FL_LONG|FL_WIDECHAR)) {
wchar = (char16_t) get_short_arg(&argptr);
no_output = 1;
} else {
/* format multibyte character */
/* this is an extension of ANSI */
unsigned short temp;
wchar = (char16_t)get_int_arg(&argptr);
temp = (unsigned short)wchar;
{
buffer.sz[0] = (char) temp;
textlen = 1;
}
}
text.sz = buffer.sz;
#endif /* _UNICODE */
}
break;
case _T('Z'): {
/* print a Counted String */
struct _count_string {
short Length;
short MaximumLength;
char *Buffer;
} *pstr;
pstr = (struct _count_string *)get_ptr_arg(&argptr);
if (pstr == NULL || pstr->Buffer == NULL) {
/* null ptr passed, use special string */
text.sz = __nullstring;
textlen = (int)strlen(text.sz);
} else {
if (flags & FL_WIDECHAR) {
text.wz = (char16_t *)pstr->Buffer;
textlen = pstr->Length / (int)sizeof(char16_t);
bufferiswide = 1;
} else {
bufferiswide = 0;
text.sz = pstr->Buffer;
textlen = pstr->Length;
}
}
}
break;
case _T('S'): /* ISO wide character string */
#ifndef _UNICODE
if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
flags |= FL_WIDECHAR;
#else /* _UNICODE */
if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
flags |= FL_SHORT;
#endif /* _UNICODE */
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;
const char *p; /* temps */
const char16_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 = (char *)get_ptr_arg(&argptr);
/* scan for null upto i characters */
#ifdef _UNICODE
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++) {
++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 = (int)(pwch - text.wz); /* in char16_ts */
/* textlen now contains length in wide chars */
}
#else /* _UNICODE */
if (flags & (FL_LONG|FL_WIDECHAR)) {
if (text.wz == NULL) /* NULL passed, use special string */
text.wz = __wnullstring;
bufferiswide = 1;
pwch = text.wz;
while ( i-- && *pwch )
++pwch;
textlen = (int)(pwch - text.wz);
/* textlen now contains length in wide chars */
} else {
if (text.sz == NULL) /* NULL passed, use special string */
text.sz = __nullstring;
p = text.sz;
while (i-- && *p)
++p;
textlen = (int)(p - text.sz); /* length of the string */
}
#endif /* _UNICODE */
}
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);
/* %n is disabled */
_VALIDATE_RETURN(("'n' format specifier disabled" && 0), EINVAL, -1);
break;
/* store chars out into short/long/int depending on flags */
#if !LONG_IS_INT
if (flags & FL_LONG)
*(long *)p = charsout;
else
#endif /* !LONG_IS_INT */
#if !SHORT_IS_INT
if (flags & FL_SHORT)
*(short *)p = (short) charsout;
else
#endif /* !SHORT_IS_INT */
*(int *)p = charsout;
no_output = 1; /* force no output */
}
break;
case _T('E'):
case _T('G'):
case _T('A'):
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'):
case _T('a'): {
/* 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 */
buffersize = BUFFERSIZE;
/* compute the precision value */
if (precision < 0)
precision = 6; /* default precision: 6 */
else if (precision == 0 && ch == _T('g'))
precision = 1; /* ANSI specified */
else if (precision > MAXPRECISION)
precision = MAXPRECISION;
if (precision > BUFFERSIZE - _CVTBUFSIZE) {
precision = BUFFERSIZE - _CVTBUFSIZE;
}
/* for safecrt, we pass along the FL_ALTERNATE flag to _safecrt_cfltcvt */
if (flags & FL_ALTERNATE)
{
capexp |= FL_ALTERNATE;
}
_CRT_DOUBLE tmp;
tmp=va_arg(argptr, _CRT_DOUBLE);
/* Note: assumes ch is in ASCII range */
/* In safecrt, we provide a special version of _cfltcvt which internally calls printf (see safecrt_output_s.c) */
_CFLTCVT(&tmp, buffer.sz, buffersize, (char)ch, precision, capexp);
/* 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 = (int)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_INT64
flags |= FL_I64; /* assume we're converting an int64 */
#elif !PTR_IS_INT
flags |= FL_LONG; /* assume we're converting a long */
#endif /* !PTR_IS_INT */
/* 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. */
#if _INTEGRAL_MAX_BITS >= 64
// unsigned __int64 number; /* number to convert */
uint64_t number; /* number to convert */
int digit; /* ascii value of digit */
__int64 l; /* temp long value */
#else /* _INTEGRAL_MAX_BITS >= 64 */
unsigned long number; /* number to convert */
int digit; /* ascii value of digit */
long l; /* temp long value */
#endif /* _INTEGRAL_MAX_BITS >= 64 */
/* 1. read argument into l, sign extend as needed */
#if _INTEGRAL_MAX_BITS >= 64
if (flags & FL_I64)
l = get_int64_arg(&argptr);
else
#endif /* _INTEGRAL_MAX_BITS >= 64 */
if (flags & FL_LONGLONG)
l = get_long_long_arg(&argptr);
else
#if !LONG_IS_INT
if (flags & FL_LONG)
l = get_long_arg(&argptr);
else
#endif /* !LONG_IS_INT */
#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 /* !SHORT_IS_INT */
{
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;
}
#if _INTEGRAL_MAX_BITS >= 64
if ( (flags & FL_I64) == 0 && (flags & FL_LONGLONG) == 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 /* _INTEGRAL_MAX_BITS >= 64 */
/* 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;
if (precision > MAXPRECISION)
precision = MAXPRECISION;
}
/* 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. */
char *sz;
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;
}
*sz-- = (char)digit; /* store the digit */
}
textlen = (int)((char *)&buffer.sz[BUFFERSIZE-1] - sz); /* compute length of number */
++sz; /* text points to first digit now */
/* 6. Force a leading zero if FORCEOCTAL flag set */
if ((flags & FL_FORCEOCTAL) && (textlen == 0 || sz[0] != '0')) {
*--sz = '0';
++textlen; /* add a zero */
}
text.sz = sz;
}
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 _UNICODE
if (bufferiswide && (textlen > 0)) {
charsout = -1;
} else {
WRITE_STRING(text.sz, textlen, &charsout);
}
#else /* _UNICODE */
if (!bufferiswide && textlen > 0) {
char *p;
int retval = 0
int count;
p = text.sz;
count = textlen;
while (count-- > 0) {
retval = _MBTOWC(&wchar, p, MB_CUR_MAX);
if (retval <= 0) {
charsout = -1;
break;
}
WRITE_CHAR(wchar, &charsout);
p += retval;
}
} else {
WRITE_STRING(text.wz, textlen, &charsout);
}
#endif /* _UNICODE */
if (charsout >= 0 && (flags & FL_LEFT)) {
/* pad on right with blanks */
WRITE_MULTI_CHAR(_T(' '), padding, &charsout);
}
/* we're done! */
}
break;
}
}
#ifdef FORMAT_VALIDATIONS
/* The format string shouldn't be incomplete - i.e. when we are finished
with the format string, the last thing we should have encountered
should have been a regular char to be output or a type specifier. Else
the format string was incomplete */
_VALIDATE_RETURN(((state == ST_NORMAL) || (state == ST_TYPE)), EINVAL, -1);
#endif /* FORMAT_VALIDATIONS */
return charsout; /* return value = number of characters written */
}