home *** CD-ROM | disk | FTP | other *** search
- /***
- *output.c - printf style output to a FILE
- *
- * Copyright (c) 1989-1997, 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 ****
- *
- *******************************************************************************/
-
- #ifdef _WIN32
-
- #if defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC)
- #define DOUBLE double
- #endif /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
-
-
- /* temporary work-around for compiler without 64-bit support */
-
- #ifndef _INTEGRAL_MAX_BITS
- #define _INTEGRAL_MAX_BITS 64
- #endif /* _INTEGRAL_MAX_BITS */
-
-
- #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 <dbgint.h>
-
- /* inline keyword is non-ANSI C7 extension */
- #if !defined (_MSC_VER) || defined (__STDC__)
- #define __inline static
- #else /* !defined (_MSC_VER) || defined (__STDC__) */
- /* UNDONE: compiler is broken */
- #define __inline static
- #endif /* !defined (_MSC_VER) || 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 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 /* 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 *)get_int_arg(x)
- #elif PTR_IS_LONG
- #define get_ptr_arg(x) (void *)get_long_arg(x)
- #else /* PTR_IS_LONG */
- #error Size of pointer must be same as size of int or long
- #endif /* PTR_IS_LONG */
-
-
-
- /* 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 /* BUFFERSIZE < CVTBUFSIZE */
-
- /* 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_I64 0x08000 /* __int64 value given */
-
- /* 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 (_UNICODE) || defined (CPRFLAG)
- extern char *__nullstring; /* string to print on null ptr */
- extern wchar_t *__wnullstring; /* string to print on null ptr */
- #else /* defined (_UNICODE) || defined (CPRFLAG) */
- 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) */
-
- /* 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 (_UNICODE) || defined (CPRFLAG)
-
- extern const char __lookuptable[];
-
- #else /* defined (_UNICODE) || defined (CPRFLAG) */
-
- /* 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, 0x28, 0x38, 0x50, 0x58, 0x07, 0x08,
- 0x00, 0x37, 0x30, 0x30, 0x57, 0x50, 0x07, 0x00,
- 0x00, 0x20, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00,
- 0x08, 0x60,
- 0x68, /* 'Z' (extension for NT development) */
- 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, /* 'w' (extension for NT development) */
- 0x08
- };
-
- #endif /* defined (_UNICODE) || defined (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 _UNICODE 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 defined (_UNICODE)
-
- #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(wchar_t 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 /* defined (_UNICODE) */
-
- #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 /* defined (_UNICODE) */
-
- __inline int __cdecl get_int_arg(va_list *pargptr);
-
- #ifndef _UNICODE
- #if !SHORT_IS_INT
- __inline short __cdecl get_short_arg(va_list *pargptr);
- #endif /* !SHORT_IS_INT */
- #endif /* _UNICODE */
-
- #if !LONG_IS_INT
- __inline long __cdecl get_long_arg(va_list *pargptr);
- #endif /* !LONG_IS_INT */
-
- #if _INTEGRAL_MAX_BITS >= 64
- __inline __int64 __cdecl get_int64_arg(va_list *pargptr);
- #endif /* _INTEGRAL_MAX_BITS >= 64 */
-
- #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 __cdecl _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 _UNICODE
- * The wide-character flavour returns the number of wide-characters written.
- *endif
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- #ifdef CPRFLAG
- LOCAL(int) output (
- #elif defined (_UNICODE)
- int __cdecl _woutput (
- FILE *stream,
- #else /* defined (_UNICODE) */
- int __cdecl _output (
- FILE *stream,
- #endif /* defined (_UNICODE) */
- 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 _UNICODE */
- union {
- char sz[BUFFERSIZE];
- #ifdef _UNICODE
- wchar_t wz[BUFFERSIZE];
- #endif /* _UNICODE */
- } buffer;
- wchar_t wchar; /* temp wchar_t */
- int bufferiswide; /* non-zero = buffer contains wide chars already */
-
- textlen = 0; /* no text yet */
- 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:
-
- /* normal state -- just write character */
- #ifdef _UNICODE
- bufferiswide = 1;
- #else /* _UNICODE */
- bufferiswide = 0;
- if (isleadbyte((int)(unsigned char)ch)) {
- WRITE_CHAR(ch, &charsout);
- ch = *format++;
- _ASSERTE (ch != _T('\0')); /* UNDONE: don't fall off format string */
- }
- #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) {
- #if !LONG_IS_INT || !defined (_UNICODE)
- case _T('l'):
- flags |= FL_LONG; /* 'l' => long int or wchar_t */
- break;
- #endif /* !LONG_IS_INT || !defined (_UNICODE) */
-
- #if !LONGDOUBLE_IS_DOUBLE || defined (_M_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_I64; /* 'L' => __int64 */
- break;
- #endif /* !LONGDOUBLE_IS_DOUBLE || defined (_M_ALPHA) */
-
- case _T('I'):
- /*
- * In order to handle the I64 size modifier, we depart from
- * the simple deterministic state machine. The code below
- * scans
- */
- if ( (*format == _T('6')) && (*(format + 1) == _T('4')) ) {
- format += 2;
- flags |= FL_I64; /* I64 => __int64 */
- }
- else {
- state = ST_NORMAL;
- goto NORMAL_STATE;
- }
- break;
-
- #if !SHORT_IS_INT || defined (_UNICODE)
- case _T('h'):
- flags |= FL_SHORT; /* 'h' => short int or char */
- break;
- #endif /* !SHORT_IS_INT || defined (_UNICODE) */
-
- /* 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 _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 = (wchar_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 = (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);
- {
- buffer.sz[0] = (char) temp;
- textlen = 1;
- }
- }
- text.sz = buffer.sz;
- #endif /* _UNICODE */
- }
- break;
-
- case _T('Z'): {
- /* print a Counted String
-
- int i;
- char *p; /* temps */
- struct _count_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;
-
- 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;
- 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 _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++) {
- 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 /* _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 = 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 = 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);
-
- /* 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'):
- 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 /* !LONGDOUBLE_IS_DOUBLE */
- {
- 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 /* !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 */
- 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 !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 ) {
- /*
- * 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;
-
- /* 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 _UNICODE
- 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 /* _UNICODE */
- 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 /* _UNICODE */
-
- 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 _UNICODE
- *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 defined (_UNICODE)
-
- LOCAL(void) write_char (
- wchar_t ch,
- FILE *f,
- int *pnumwritten
- )
- {
- if (_putwc_lk(ch, f) == WEOF)
- *pnumwritten = -1;
- else
- ++(*pnumwritten);
- }
-
- #else /* defined (_UNICODE) */
-
- LOCAL(void) write_char (
- int ch,
- FILE *f,
- int *pnumwritten
- )
- {
- if (_putc_lk(ch, f) == EOF)
- *pnumwritten = -1;
- else
- ++(*pnumwritten);
- }
-
- #endif /* defined (_UNICODE) */
-
- /***
- *void write_multi_char(int ch, int num, int *pnumwritten)
- *ifdef _UNICODE
- *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);
- if (*pnumwritten == -1)
- break;
- }
- }
-
- #else /* CPRFLAG */
- #ifdef _UNICODE
-
- LOCAL(void) write_multi_char (
- wchar_t ch,
- int num,
- FILE *f,
- int *pnumwritten
- )
- #else /* _UNICODE */
-
- LOCAL(void) write_multi_char (
- int ch,
- int num,
- FILE *f,
- int *pnumwritten
- )
- #endif /* _UNICODE */
- {
- while (num-- > 0) {
- write_char(ch, f, pnumwritten);
- if (*pnumwritten == -1)
- break;
- }
- }
-
- #endif /* CPRFLAG */
-
- /***
- *void write_string(char *string, int len, int *pnumwritten)
- *void write_string(char *string, int len, FILE *f, int *pnumwritten)
- *ifdef _UNICODE
- *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);
- if (*pnumwritten == -1)
- break;
- }
- }
-
- #else /* CPRFLAG */
- #if _UNICODE
-
- LOCAL(void) write_string (
- wchar_t *string,
- int len,
- FILE *f,
- int *pnumwritten
- )
- #else /* _UNICODE */
-
- LOCAL(void) write_string (
- char *string,
- int len,
- FILE *f,
- int *pnumwritten
- )
- #endif /* _UNICODE */
- {
- while (len-- > 0) {
- write_char(*string++, f, pnumwritten);
- if (*pnumwritten == -1)
- break;
- }
- }
- #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 __cdecl 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 __cdecl get_long_arg (
- va_list *pargptr
- )
- {
- return va_arg(*pargptr, long);
- }
- #endif /* !LONG_IS_INT */
-
- #if _INTEGRAL_MAX_BITS >= 64
- __inline __int64 __cdecl get_int64_arg (
- va_list *pargptr
- )
- {
- return va_arg(*pargptr, __int64);
- }
- #endif /* _INTEGRAL_MAX_BITS >= 64 */
-
- #ifndef _UNICODE
- /***
- *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 __cdecl get_short_arg (
- va_list *pargptr
- )
- {
- return va_arg(*pargptr, short);
- }
- #endif /* !SHORT_IS_INT */
- #endif /* _UNICODE */
-
-
- #else /* _WIN32 */
-
- #if defined (_M_MPPC) || defined (_M_M68K)
-
-
- #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 <tchar.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <dbgint.h>
-
- /*
- * Code under if defined(_WIN32_) && !defined(_DOSX32_) && !defined(_INTL)
- * is partial international support written by NT developers. This code
- * should be removed when international sources are merged with orville.
- */
-
- /* 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 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 */
-
- #ifdef _M_MPPC
- #define LONGDOUBLE_IS_DOUBLE 1 /* 1 means long double is same as double */
- #else /* _M_MPPC */
- #define LONGDOUBLE_IS_DOUBLE 0 /* 1 means long double is same as double */
- #endif /* _M_MPPC */
-
- #ifndef _INTEGRAL_MAX_BITS
- #define _INTEGRAL_MAX_BITS 64
- #endif /* _INTEGRAL_MAX_BITS */
-
- #if LONG_IS_INT
- #define get_long_arg(x) (long)get_int_arg(x)
- #endif /* LONG_IS_INT */
-
- #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 /* PTR_IS_LONG */
- #error Size of pointer must be same as size of int or long
- #endif /* PTR_IS_LONG */
-
-
-
- /* 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 /* BUFFERSIZE < CVTBUFSIZE */
-
- /* 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 */
- #define FL_I64 0x08000 /* __int64 value given */
-
- /* 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) */
- static char *nullstring = "(null)"; /* string to print on null ptr */
- #ifdef _UNICODE
- static wchar_t *wnullstring = L"(null)";/* string to print on null ptr */
- #endif /* _UNICODE */
-
- /* 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. */
-
- static 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, 0x28, 0x38, 0x50, 0x58, 0x07, 0x08,
- 0x00, 0x37, 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, 0x08, 0x08, 0x00, 0x08,
- 0x08
- };
-
- #define find_char_class(c) \
- ((c) < ' ' || (c) > 'x' ? \
- CH_OTHER \
- : \
- lookuptable[(c)-' '] & 0xF)
-
- #define find_next_state(class, state) \
- (lookuptable[(class) * NUMSTATES + (state)] >> 4)
-
-
- /*
- * Note: CPRFLAG and _UNICODE 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 defined (_UNICODE)
-
- #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(wchar_t 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 /* defined (_UNICODE) */
-
- #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 /* defined (_UNICODE) */
-
- LOCAL(int) get_int_arg(va_list *pargptr);
-
- LOCAL(short) get_short_arg(va_list *pargptr);
-
- #if !LONG_IS_INT
- LOCAL(long) get_long_arg(va_list *pargptr);
- #endif /* !LONG_IS_INT */
-
- LOCAL(__int64) get_int64_arg(va_list *pargptr);
-
- #ifdef _UNICODE
- LOCAL(int) __cdecl _woutput(FILE *, const char *, va_list);
- #endif /* _UNICODE */
-
- #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 __cdecl _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.
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- #ifdef CPRFLAG
- LOCAL(int) output (
- #elif defined (_UNICODE)
- LOCAL(int) _woutput (
- FILE *stream,
- #else /* defined (_UNICODE) */
- int __cdecl _output (
- FILE *stream,
- #endif /* defined (_UNICODE) */
- const char *format,
- va_list argptr
- )
- {
- int hexadd; /* offset to add to number to get 'a'..'f' */
- char 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 with -- 0 means default */
- int precision; /* selected precision -- -1 means default */
- char prefix[2]; /* numeric prefix -- up to two characters */
- int prefixlen; /* length of prefix -- 0 means no prefix */
- int capexp; /* non-zero = 'E' exponent signifiet, zero = 'e' */
- int no_output; /* non-zero = prodcue no output for this specifier */
- char *text; /* pointer text to be printed, not zero terminated */
- int textlen; /* length of the text in bytes to be printed */
- char buffer[BUFFERSIZE]; /* buffer for conversions */
- #ifdef _UNICODE
- /* textlen is in multibyte or wide characters for _UNICODE versions */
- wchar_t wchar; /* temp wchar_t */
- wchar_t *wchar_p; /* temp wchar_t pointer */
- int bufferiswide; /* non-zero = buffer contains wide chars already */
- #endif /* _UNICODE */
- int _tflag=0;
-
- 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++) != '\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) {
-
- NORMAL_STATE:
-
- case ST_NORMAL:
- /* normal state -- just write character */
- #ifndef _UNICODE
- if (isleadbyte((int)ch)) {
- WRITE_CHAR(ch, &charsout);
- ch = *format++;
- _ASSERTE (ch != '0'); /* UNDONE: don't fall off format string */
- }
- WRITE_CHAR(ch, &charsout);
- #else /* _UNICODE */
- format += (mbtowc (&wchar, format-1, MB_CUR_MAX) - 1);
- /* UNDONE: check for mbtowc failure */
- WRITE_CHAR(wchar, &charsout);
- #endif /* _UNICODE */
- break;
-
- case ST_PERCENT:
- /* set default value of conversion parameters */
- prefixlen = fldwidth = no_output = capexp = 0;
- flags = 0;
- precision = -1;
- #ifdef _UNICODE
- bufferiswide = 0;
- #endif /* _UNICODE */
- break;
-
- case ST_FLAG:
- /* set flag based on which flag character */
- switch (ch) {
- case '-':
- flags |= FL_LEFT; /* '-' => left justify */
- break;
- case '+':
- flags |= FL_SIGN; /* '+' => force sign indicator */
- break;
- case ' ':
- flags |= FL_SIGNSP; /* ' ' => force sign or space */
- break;
- case '#':
- flags |= FL_ALTERNATE; /* '#' => alternate form */
- break;
- case '0':
- flags |= FL_LEADZERO; /* '0' => pad with leading zeros */
- break;
- }
- break;
-
- case ST_WIDTH:
- /* update width value */
- if (ch == '*') {
- /* 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 - '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 == '*') {
- /* 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 - '0');
- }
- break;
-
- case ST_SIZE:
- /* just read a size specifier, set the flags based on it */
- switch (ch) {
- #if !LONG_IS_INT
- case 'l':
- flags |= FL_LONG; /* 'l' => long int */
- break;
- #endif /* !LONG_IS_INT */
-
- #if !LONGDOUBLE_IS_DOUBLE
- case 'L':
- flags |= FL_LONGDOUBLE; /* 'L' => long double */
- break;
- #endif /* !LONGDOUBLE_IS_DOUBLE */
-
- case 'I':
- /*
- * In order to handle the I64 size modifier, we depart from
- * the simple deterministic state machine. The code below
- * scans
- */
- if ( (*format == '6') && (*(format + 1) == '4') ) {
- format += 2;
- flags |= FL_I64; /* I64 => __int64 */
- }
- else {
- state = ST_NORMAL;
- goto NORMAL_STATE;
- }
- break;
-
- #if !SHORT_IS_INT
- case 'h':
- flags |= FL_SHORT; /* 'h' => short int */
- break;
- #endif /* !SHORT_IS_INT */
-
- }
- 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 doen in one place. */
- /* Look at those funky goto statements! */
-
- /*
- * Generic string handling support: %tc, %ts accept
- * either chars or wide-chars depending on _tflag.
- * _tflag == 1 means wide-chars.
- */
- if (ch == 't') {
- if (_tflag == 1)
- ch = 'w';
- else {
- ch = *format++;
- _ASSERTE (ch!='0'); /* UNDONE: don't fall off format string */
- }
- }
-
- switch (ch) {
-
- case 'c': {
- /* print a single character specified by int argument */
- buffer[0] = (char) get_int_arg(&argptr); /* get char to print */
- text = buffer;
- textlen = 1; /* print just a single character */
- }
- break;
-
- case '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 */
-
- text = get_ptr_arg(&argptr);
- if (text == NULL) {
- /* null ptr passed, use special string */
- text = nullstring;
- }
-
- /* 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;
-
- p = text;
-
- /* scan for null upto i characters */
- #ifndef _UNICODE
- while (i-- && *p)
- ++p;
-
- textlen = p - text; /* length of the string */
- #else /* _UNICODE */
- for (textlen=0; textlen<i && *p; textlen++) {
- if (isleadbyte((int)*p))
- ++p;
- ++p;
- }
- /* textlen now contains length in multibyte chars */
- #endif /* _UNICODE */
- }
- break;
-
- case 'w': {
- /* 'wc' print a wide character */
- /* 'ws' print a wide string */
-
- #ifdef _UNICODE
- bufferiswide = 1;
- #endif /* _UNICODE */
- ch = *format++;
- _ASSERTE (ch!='0'); /* UNDONE: don't fall off format string */
- switch (ch) {
-
- /* 'wc' case */
- case 'c': {
- #ifndef _UNICODE
- wchar_t temp;
- temp = (wchar_t) get_short_arg(&argptr);
- /* convert to multibyte characters */
- textlen = wctomb(buffer, temp);
- text = buffer;
-
- /* check that conversion was successful */
- if (textlen < 0)
- no_output = 1;
- #else /* _UNICODE */
- /* copy wide-char directly to buffer */
- *(wchar_t *)buffer = (wchar_t) get_short_arg(&argptr);
- textlen = 1; /* number of wide-chars */
- text = buffer;
- #endif /* _UNICODE */
- }
- break;
-
- /* 'ws' case */
- case 's': {
- #ifndef _UNICODE
- int i;
-
- text = get_ptr_arg(&argptr);
- if (text == NULL) {
- /*
- * null ptr passed, use special string
- */
- text = nullstring;
- textlen = strlen(nullstring);
- /*
- * if precision is specified (!= -1) use
- * minimum of precision and textlen, else use textlen
- */
- textlen = (precision < 0) ? textlen :
- ((precision < textlen) ? precision : textlen);
- } else {
- /* convert to multibyte characters */
- i = (precision < 0) ? BUFFERSIZE : precision;
- textlen = (int) wcstombs(buffer, (wchar_t *)text, (size_t)i);
- text = buffer;
-
- if (flags & FL_ALTERNATE) {
- /*
- * Don't write more than precision wide chars
- */
- char *p;
- p = text;
- while (i-- && *p) {
- if (isleadbyte((int)*p))
- ++p;
- ++p;
- }
- textlen = p - text; /* length of the string */
- }
-
- /* check that conversion was successful */
- if (textlen < 0)
- no_output = 1;
- }
- #else /* _UNICODE */
- int i;
- wchar_t *p; /* temps */
-
- text = get_ptr_arg(&argptr);
- if (text == NULL) {
- /* null ptr passed, use special string */
- text = (char *) wnullstring;
- }
-
-
- i = (precision == -1) ? INT_MAX : precision;
-
- p = (wchar_t *) text;
-
- /* scan for null up to i wide characters */
- while (i-- && *p)
- ++p;
-
- textlen = p - (wchar_t *) text; /* length in wide-chars */
-
- #endif /* _UNICODE */
- }
- break;
-
- default:
- /* error: unrecognized */
- /* ANSI: undefined behavior */
- no_output = 1;
-
- } /* switch */
- } /* case 'w' */
- break;
-
- case '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 /* !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 'E':
- case 'G':
- capexp = 1; /* capitalize exponent */
- ch += 'a' - 'A'; /* convert format char to lower */
- /* DROP THROUGH */
- case 'e':
- case 'f':
- case 'g': {
- /* floating point conversion -- we call cfltcvt routines */
- /* to do the work for us. */
- flags |= FL_SIGNED; /* floating point is signed conversion */
- text = buffer; /* put result in buffer */
-
- /* compute the precision value */
- if (precision < 0)
- precision = 6; /* default precision: 6 */
- else if (precision == 0 && ch == 'g')
- precision = 1; /* ANSI specified */
-
- #if !LONGDOUBLE_IS_DOUBLE
- /* do the conversion */
- if (flags & FL_LONGDOUBLE) {
- _cldcvt((LONGDOUBLE*)argptr, text, ch, precision, capexp);
- va_arg(argptr, LONGDOUBLE);
- }
- else
- #endif /* !LONGDOUBLE_IS_DOUBLE */
- {
- _cfltcvt((DOUBLE*)argptr, text, ch, precision, capexp);
- va_arg(argptr, DOUBLE);
- }
-
- /* '#' and precision == 0 means force a decimal point */
- if ((flags & FL_ALTERNATE) && precision == 0)
- _forcdecpt(text);
-
- /* 'g' format means crop zero unless '#' given */
- if (ch == 'g' && !(flags & FL_ALTERNATE))
- _cropzeros(text);
-
- /* check if result was negative, save '-' for later */
- /* and point to positive part (this is for '0' padding) */
- if (*text == '-') {
- flags |= FL_NEGATIVE;
- ++text;
- }
-
- textlen = strlen(text); /* compute length of text */
- }
- break;
-
- case 'd':
- case 'i':
- /* signed decimal output */
- flags |= FL_SIGNED;
- radix = 10;
- goto COMMON_INT;
-
- case 'u':
- radix = 10;
- goto COMMON_INT;
-
- case '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 */
- #ifndef _MAC
- #if !PTR_IS_INT
- flags |= FL_LONG; /* assume we're converting a long */
- #endif /* !PTR_IS_INT */
- #else /* _MAC */
- flags &= ~FL_SHORT; /* assume we're converting a long */
- flags |= FL_LONG; /* assume we're converting a long */
- #endif /* _MAC */
- /* DROP THROUGH to hex formatting */
-
- case 'X':
- /* unsigned upper hex output */
- hexadd = 'A' - '9' - 1; /* set hexadd for uppercase hex */
- goto COMMON_HEX;
-
- case 'x':
- /* unsigned lower hex output */
- hexadd = 'a' - '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] = '0';
- prefix[1] = (char)('x' - 'a' + '9' + 1 + hexadd); /* 'x' or 'X' */
- prefixlen = 2;
- }
- goto COMMON_INT;
-
- case '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. */
-
- unsigned __int64 number; /* number to convert */
- int digit; /* ascii value of digit */
- __int64 l; /* temp long value */
-
- /* 1. read argument into l, sign extend as needed */
-
- if (flags & FL_I64)
- l = get_int64_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;
- }
-
- /* 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 = &buffer[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-- = (char)digit; /* store the digit */
- }
-
- textlen = (char *)&buffer[BUFFERSIZE-1] - text; /* compute length of number */
- ++text; /* text points to first digit now */
-
-
- /* 6. Force a leading zero if FORCEOCTAL flag set */
- if ((flags & FL_FORCEOCTAL) && (text[0] != '0' || textlen == 0)) {
- *--text = '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] = '-';
- prefixlen = 1;
- }
- else if (flags & FL_SIGN) {
- /* prefix is '+' */
- prefix[0] = '+';
- prefixlen = 1;
- }
- else if (flags & FL_SIGNSP) {
- /* prefix is ' ' */
- prefix[0] = ' ';
- 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 */
- #ifndef _UNICODE
- WRITE_STRING(prefix, prefixlen, &charsout);
- #else /* _UNICODE */
- if (prefixlen > 0) {
- wchar_p = (wchar_t *)_malloc_crt (prefixlen * sizeof(wchar_t));
- if (wchar_p == NULL) {
- charsout = -1;
- break;
- }
- /* assume prefix string is single-byte characters */
- mbstowcs (wchar_p, prefix, prefixlen);
- /* UNDONE: check for mbstowcs failure */
- WRITE_STRING(wchar_p, prefixlen, &charsout);
- _free_crt (wchar_p);
- }
- #endif /* _UNICODE */
-
- if ((flags & FL_LEADZERO) && !(flags & FL_LEFT)) {
- /* write leading zeros */
- WRITE_MULTI_CHAR(_T('0'), padding, &charsout);
- }
-
- /* write text */
- #ifndef _UNICODE
- WRITE_STRING(text, textlen, &charsout);
- #else /* _UNICODE */
- if (!bufferiswide && textlen > 0) {
- wchar_p = (wchar_t *)_malloc_crt (textlen * sizeof(wchar_t));
- if (wchar_p == NULL) {
- charsout = -1;
- break;
- }
- mbstowcs (wchar_p, text, textlen);
- /* UNDONE: check for mbstowcs failure */
- WRITE_STRING(wchar_p, textlen, &charsout);
- _free_crt (wchar_p);
- } else {
- WRITE_STRING((wchar_t *)text, textlen, &charsout);
- }
- #endif /* _UNICODE */
-
- 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 wsprintf:
- * - Prefix is always 1 or 2 characters. Make this memory static rather
- * than malloc'ed.
- * - 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.
- * - Printing wide-character literal char format strings may be common.
- * This may be optimized by performing a single mbstowcs rather than
- * many mbtowc (i.e. look ahead in format string until hit a %, then
- * write it all out).
- */
-
- /***
- *void write_char(int ch, int *pnumwritten)
- *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 defined (_UNICODE)
-
- LOCAL(void) write_char (
- wchar_t ch,
- FILE *f,
- int *pnumwritten
- )
- {
- /* following code is machine dependent */
- _putc_lk((int)(ch & 0xff), f);
- if (_putc_lk((int)(ch >> 8), f) == EOF)
- *pnumwritten = -1;
- else
- ++(*pnumwritten);
- }
-
- #else /* defined (_UNICODE) */
-
- LOCAL(void) write_char (
- int ch,
- FILE *f,
- int *pnumwritten
- )
- {
- if (_putc_lk(ch, f) == EOF)
- *pnumwritten = -1;
- else
- ++(*pnumwritten);
- }
-
- #endif /* defined (_UNICODE) */
-
- /***
- *void write_multi_char(int ch, int num, int *pnumwritten)
- *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);
- }
-
- #elif defined (_UNICODE)
-
- LOCAL(void) write_multi_char (
- wchar_t ch,
- int num,
- FILE *f,
- int *pnumwritten
- )
- {
- while (num-- > 0)
- write_char(ch, f, pnumwritten);
- }
-
- #else /* defined (_UNICODE) */
-
- LOCAL(void) write_multi_char (
- int ch,
- int num,
- FILE *f,
- int *pnumwritten
- )
- {
- while (num-- > 0)
- write_char(ch, f, pnumwritten);
- }
-
- #endif /* defined (_UNICODE) */
-
- /***
- *void write_string(char *string, int len, int *pnumwritten)
- *void write_string(char *string, int len, FILE *f, int *pnumwritten)
- *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);
- }
-
- #elif defined (_UNICODE)
-
- LOCAL(void) write_string (
- wchar_t *string,
- int len,
- FILE *f,
- int *pnumwritten
- )
- {
- while (len-- > 0)
- write_char(*string++, f, pnumwritten);
- }
-
- #else /* defined (_UNICODE) */
-
- LOCAL(void) write_string (
- char *string,
- int len,
- FILE *f,
- int *pnumwritten
- )
- {
- while (len-- > 0)
- write_char(*string++, f, pnumwritten);
- }
-
- #endif /* defined (_UNICODE) */
-
- /***
- *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:
- *
- *******************************************************************************/
-
- LOCAL(int) 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
- LOCAL(long) get_long_arg (
- va_list *pargptr
- )
- {
- return va_arg(*pargptr, long);
- }
- #endif /* !LONG_IS_INT */
-
- /***
- *__int64 get_int86_arg(va_list *pargptr)
- *
- *Purpose:
- * Gets an __int64 short argument off the given argument list and updates *pargptr.
- *
- *Entry:
- * va_list *pargptr - pointer to argument list; updated by function
- *
- *Exit:
- * Returns the __int64 argument read from the argument list.
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- LOCAL(__int64) get_int64_arg (
- va_list *pargptr
- )
- {
- double dblTemp;
-
- dblTemp = va_arg(*pargptr, double);
- return *(__int64 *)&dblTemp;
-
- // return va_arg(*pargptr, __int64);
- }
-
- /***
- *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:
- *
- *******************************************************************************/
-
- LOCAL(short) get_short_arg (
- va_list *pargptr
- )
- {
- return va_arg(*pargptr, short);
- }
-
-
- #endif /* defined (_M_MPPC) || defined (_M_M68K) */
-
- #endif /* _WIN32 */
-