home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / output.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  87KB  |  2,568 lines

  1. /***
  2. *output.c - printf style output to a FILE
  3. *
  4. *       Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       This file contains the code that does all the work for the
  8. *       printf family of functions.  It should not be called directly, only
  9. *       by the *printf functions.  We don't make any assumtions about the
  10. *       sizes of ints, longs, shorts, or long doubles, but if types do overlap,
  11. *       we also try to be efficient.  We do assume that pointers are the same
  12. *       size as either ints or longs.
  13. *       If CPRFLAG is defined, defines _cprintf instead.
  14. *       **** DOESN'T CURRENTLY DO MTHREAD LOCKING ****
  15. *
  16. *******************************************************************************/
  17.  
  18. #ifdef _WIN32
  19.  
  20. #if defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC)
  21. #define DOUBLE double
  22. #endif  /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
  23.  
  24.  
  25. /* temporary work-around for compiler without 64-bit support */
  26.  
  27. #ifndef _INTEGRAL_MAX_BITS
  28. #define _INTEGRAL_MAX_BITS  64
  29. #endif  /* _INTEGRAL_MAX_BITS */
  30.  
  31.  
  32. #include <cruntime.h>
  33. #include <limits.h>
  34. #include <string.h>
  35. #include <stddef.h>
  36. #include <stdio.h>
  37. #include <stdarg.h>
  38. #include <cvt.h>
  39. #include <conio.h>
  40. #include <internal.h>
  41. #include <fltintrn.h>
  42. #include <stdlib.h>
  43. #include <ctype.h>
  44. #include <dbgint.h>
  45.  
  46. /* inline keyword is non-ANSI C7 extension */
  47. #if !defined (_MSC_VER) || defined (__STDC__)
  48. #define __inline static
  49. #else  /* !defined (_MSC_VER) || defined (__STDC__) */
  50. /* UNDONE: compiler is broken */
  51. #define __inline static
  52. #endif  /* !defined (_MSC_VER) || defined (__STDC__) */
  53.  
  54. #ifdef _MBCS
  55. #undef _MBCS
  56. #endif  /* _MBCS */
  57. #include <tchar.h>
  58.  
  59. /* this macro defines a function which is private and as fast as possible: */
  60. /* for example, in C 6.0, it might be static _fastcall <type> near. */
  61. #define LOCAL(x) static x __cdecl
  62.  
  63. /* int/long/short/pointer sizes */
  64.  
  65. /* the following should be set depending on the sizes of various types */
  66. #define LONG_IS_INT      1      /* 1 means long is same size as int */
  67. #define SHORT_IS_INT     0      /* 1 means short is same size as int */
  68. #define LONGDOUBLE_IS_DOUBLE 1  /* 1 means long double is same as double */
  69. #define PTR_IS_INT       1      /* 1 means ptr is same size as int */
  70. #define PTR_IS_LONG      1      /* 1 means ptr is same size as long */
  71.  
  72. #if LONG_IS_INT
  73.     #define get_long_arg(x) (long)get_int_arg(x)
  74. #endif  /* LONG_IS_INT */
  75.  
  76. #ifndef _UNICODE
  77. #if SHORT_IS_INT
  78.     #define get_short_arg(x) (short)get_int_arg(x)
  79. #endif  /* SHORT_IS_INT */
  80. #endif  /* _UNICODE */
  81.  
  82. #if PTR_IS_INT
  83.     #define get_ptr_arg(x) (void *)get_int_arg(x)
  84. #elif PTR_IS_LONG
  85.     #define get_ptr_arg(x) (void *)get_long_arg(x)
  86. #else  /* PTR_IS_LONG */
  87.     #error Size of pointer must be same as size of int or long
  88. #endif  /* PTR_IS_LONG */
  89.  
  90.  
  91.  
  92. /* CONSTANTS */
  93.  
  94. /* size of conversion buffer (ANSI-specified minimum is 509) */
  95.  
  96. #define BUFFERSIZE    512
  97.  
  98. #if BUFFERSIZE < CVTBUFSIZE
  99. #error Conversion buffer too small for max double.
  100. #endif  /* BUFFERSIZE < CVTBUFSIZE */
  101.  
  102. /* flag definitions */
  103. #define FL_SIGN       0x00001   /* put plus or minus in front */
  104. #define FL_SIGNSP     0x00002   /* put space or minus in front */
  105. #define FL_LEFT       0x00004   /* left justify */
  106. #define FL_LEADZERO   0x00008   /* pad with leading zeros */
  107. #define FL_LONG       0x00010   /* long value given */
  108. #define FL_SHORT      0x00020   /* short value given */
  109. #define FL_SIGNED     0x00040   /* signed data given */
  110. #define FL_ALTERNATE  0x00080   /* alternate form requested */
  111. #define FL_NEGATIVE   0x00100   /* value is negative */
  112. #define FL_FORCEOCTAL 0x00200   /* force leading '0' for octals */
  113. #define FL_LONGDOUBLE 0x00400   /* long double value given */
  114. #define FL_WIDECHAR   0x00800   /* wide characters */
  115. #define FL_I64        0x08000   /* __int64 value given */
  116.  
  117. /* state definitions */
  118. enum STATE {
  119.     ST_NORMAL,          /* normal state; outputting literal chars */
  120.     ST_PERCENT,         /* just read '%' */
  121.     ST_FLAG,            /* just read flag character */
  122.     ST_WIDTH,           /* just read width specifier */
  123.     ST_DOT,             /* just read '.' */
  124.     ST_PRECIS,          /* just read precision specifier */
  125.     ST_SIZE,            /* just read size specifier */
  126.     ST_TYPE             /* just read type specifier */
  127. };
  128. #define NUMSTATES (ST_TYPE + 1)
  129.  
  130. /* character type values */
  131. enum CHARTYPE {
  132.     CH_OTHER,           /* character with no special meaning */
  133.     CH_PERCENT,         /* '%' */
  134.     CH_DOT,             /* '.' */
  135.     CH_STAR,            /* '*' */
  136.     CH_ZERO,            /* '0' */
  137.     CH_DIGIT,           /* '1'..'9' */
  138.     CH_FLAG,            /* ' ', '+', '-', '#' */
  139.     CH_SIZE,            /* 'h', 'l', 'L', 'N', 'F', 'w' */
  140.     CH_TYPE             /* type specifying character */
  141. };
  142.  
  143. /* static data (read only, since we are re-entrant) */
  144. #if defined (_UNICODE) || defined (CPRFLAG)
  145. extern char *__nullstring;  /* string to print on null ptr */
  146. extern wchar_t *__wnullstring;  /* string to print on null ptr */
  147. #else  /* defined (_UNICODE) || defined (CPRFLAG) */
  148. char *__nullstring = "(null)";  /* string to print on null ptr */
  149. wchar_t *__wnullstring = L"(null)";/* string to print on null ptr */
  150. #endif  /* defined (_UNICODE) || defined (CPRFLAG) */
  151.  
  152. /* The state table.  This table is actually two tables combined into one. */
  153. /* The lower nybble of each byte gives the character class of any         */
  154. /* character; while the uper nybble of the byte gives the next state      */
  155. /* to enter.  See the macros below the table for details.                 */
  156. /*                                                                        */
  157. /* The table is generated by maketabc.c -- use this program to make       */
  158. /* changes.                                                               */
  159.  
  160. #if defined (_UNICODE) || defined (CPRFLAG)
  161.  
  162. extern const char __lookuptable[];
  163.  
  164. #else  /* defined (_UNICODE) || defined (CPRFLAG) */
  165.  
  166. /* Table generated by maketabc.c built with -D_WIN32_. Defines additional */
  167. /* format code %Z for counted string.                                     */
  168.  
  169. const char __lookuptable[] = {
  170.          0x06, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00,
  171.          0x10, 0x00, 0x03, 0x06, 0x00, 0x06, 0x02, 0x10,
  172.          0x04, 0x45, 0x45, 0x45, 0x05, 0x05, 0x05, 0x05,
  173.          0x05, 0x35, 0x30, 0x00, 0x50, 0x00, 0x00, 0x00,
  174.          0x00, 0x20, 0x28, 0x38, 0x50, 0x58, 0x07, 0x08,
  175.          0x00, 0x37, 0x30, 0x30, 0x57, 0x50, 0x07, 0x00,
  176.          0x00, 0x20, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00,
  177.          0x08, 0x60,
  178.          0x68, /* 'Z' (extension for NT development) */
  179.                            0x60, 0x60, 0x60, 0x60, 0x00,
  180.          0x00, 0x70, 0x70, 0x78, 0x78, 0x78, 0x78, 0x08,
  181.          0x07, 0x08, 0x00, 0x00, 0x07, 0x00, 0x08, 0x08,
  182.          0x08, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00,
  183.          0x07, /* 'w' (extension for NT development) */
  184.          0x08
  185. };
  186.  
  187. #endif  /* defined (_UNICODE) || defined (CPRFLAG) */
  188.  
  189. #define find_char_class(c)      \
  190.         ((c) < _T(' ') || (c) > _T('x') ? \
  191.             CH_OTHER            \
  192.             :               \
  193.         __lookuptable[(c)-_T(' ')] & 0xF)
  194.  
  195. #define find_next_state(class, state)   \
  196.         (__lookuptable[(class) * NUMSTATES + (state)] >> 4)
  197.  
  198.  
  199. /*
  200.  * Note: CPRFLAG and _UNICODE cases are currently mutually exclusive.
  201.  */
  202.  
  203. /* prototypes */
  204.  
  205. #ifdef CPRFLAG
  206.  
  207. #define WRITE_CHAR(ch, pnw)         write_char(ch, pnw)
  208. #define WRITE_MULTI_CHAR(ch, num, pnw)  write_multi_char(ch, num, pnw)
  209. #define WRITE_STRING(s, len, pnw)   write_string(s, len, pnw)
  210. #define WRITE_WSTRING(s, len, pnw)  write_wstring(s, len, pnw)
  211.  
  212. LOCAL(void) write_char(int ch, int *pnumwritten);
  213. LOCAL(void) write_multi_char(int ch, int num, int *pnumwritten);
  214. LOCAL(void) write_string(char *string, int len, int *numwritten);
  215. LOCAL(void) write_wstring(wchar_t *string, int len, int *numwritten);
  216.  
  217. #elif defined (_UNICODE)
  218.  
  219. #define WRITE_CHAR(ch, pnw)         write_char(ch, stream, pnw)
  220. #define WRITE_MULTI_CHAR(ch, num, pnw)  write_multi_char(ch, num, stream, pnw)
  221. #define WRITE_STRING(s, len, pnw)   write_string(s, len, stream, pnw)
  222.  
  223. LOCAL(void) write_char(wchar_t ch, FILE *f, int *pnumwritten);
  224. LOCAL(void) write_multi_char(wchar_t ch, int num, FILE *f, int *pnumwritten);
  225. LOCAL(void) write_string(wchar_t *string, int len, FILE *f, int *numwritten);
  226.  
  227. #else  /* defined (_UNICODE) */
  228.  
  229. #define WRITE_CHAR(ch, pnw)         write_char(ch, stream, pnw)
  230. #define WRITE_MULTI_CHAR(ch, num, pnw)  write_multi_char(ch, num, stream, pnw)
  231. #define WRITE_STRING(s, len, pnw)   write_string(s, len, stream, pnw)
  232. #define WRITE_WSTRING(s, len, pnw)  write_wstring(s, len, stream, pnw)
  233.  
  234. LOCAL(void) write_char(int ch, FILE *f, int *pnumwritten);
  235. LOCAL(void) write_multi_char(int ch, int num, FILE *f, int *pnumwritten);
  236. LOCAL(void) write_string(char *string, int len, FILE *f, int *numwritten);
  237. LOCAL(void) write_wstring(wchar_t *string, int len, FILE *f, int *numwritten);
  238.  
  239. #endif  /* defined (_UNICODE) */
  240.  
  241. __inline int __cdecl get_int_arg(va_list *pargptr);
  242.  
  243. #ifndef _UNICODE
  244. #if !SHORT_IS_INT
  245. __inline short __cdecl get_short_arg(va_list *pargptr);
  246. #endif  /* !SHORT_IS_INT */
  247. #endif  /* _UNICODE */
  248.  
  249. #if !LONG_IS_INT
  250. __inline long __cdecl get_long_arg(va_list *pargptr);
  251. #endif  /* !LONG_IS_INT */
  252.  
  253. #if _INTEGRAL_MAX_BITS >= 64   
  254. __inline __int64 __cdecl get_int64_arg(va_list *pargptr);
  255. #endif  /* _INTEGRAL_MAX_BITS >= 64    */
  256.  
  257. #ifdef CPRFLAG
  258. LOCAL(int) output(const char *, va_list);
  259.  
  260. /***
  261. *int _cprintf(format, arglist) - write formatted output directly to console
  262. *
  263. *Purpose:
  264. *   Writes formatted data like printf, but uses console I/O functions.
  265. *
  266. *Entry:
  267. *   char *format - format string to determine data formats
  268. *   arglist - list of POINTERS to where to put data
  269. *
  270. *Exit:
  271. *   returns number of characters written
  272. *
  273. *Exceptions:
  274. *
  275. *******************************************************************************/
  276.  
  277. int __cdecl _cprintf (
  278.         const char * format,
  279.         ...
  280.         )
  281. {
  282.         va_list arglist;
  283.  
  284.         va_start(arglist, format);
  285.  
  286.         return output(format, arglist);
  287. }
  288.  
  289. #endif  /* CPRFLAG */
  290.  
  291.  
  292. /***
  293. *int _output(stream, format, argptr), static int output(format, argptr)
  294. *
  295. *Purpose:
  296. *   Output performs printf style output onto a stream.  It is called by
  297. *   printf/fprintf/sprintf/vprintf/vfprintf/vsprintf to so the dirty
  298. *   work.  In multi-thread situations, _output assumes that the given
  299. *   stream is already locked.
  300. *
  301. *   Algorithm:
  302. *       The format string is parsed by using a finite state automaton
  303. *       based on the current state and the current character read from
  304. *       the format string.  Thus, looping is on a per-character basis,
  305. *       not a per conversion specifier basis.  Once the format specififying
  306. *       character is read, output is performed.
  307. *
  308. *Entry:
  309. *   FILE *stream   - stream for output
  310. *   char *format   - printf style format string
  311. *   va_list argptr - pointer to list of subsidiary arguments
  312. *
  313. *Exit:
  314. *   Returns the number of characters written, or -1 if an output error
  315. *   occurs.
  316. *ifdef _UNICODE
  317. *   The wide-character flavour returns the number of wide-characters written.
  318. *endif
  319. *
  320. *Exceptions:
  321. *
  322. *******************************************************************************/
  323.  
  324. #ifdef CPRFLAG
  325. LOCAL(int) output (
  326. #elif defined (_UNICODE)
  327. int __cdecl _woutput (
  328.     FILE *stream,
  329. #else  /* defined (_UNICODE) */
  330. int __cdecl _output (
  331.     FILE *stream,
  332. #endif  /* defined (_UNICODE) */
  333.     const TCHAR *format,
  334.     va_list argptr
  335.     )
  336. {
  337.     int hexadd;     /* offset to add to number to get 'a'..'f' */
  338.     TCHAR ch;       /* character just read */
  339.     int flags;      /* flag word -- see #defines above for flag values */
  340.     enum STATE state;   /* current state */
  341.     enum CHARTYPE chclass; /* class of current character */
  342.     int radix;      /* current conversion radix */
  343.     int charsout;   /* characters currently written so far, -1 = IO error */
  344.     int fldwidth;   /* selected field width -- 0 means default */
  345.     int precision;  /* selected precision  -- -1 means default */
  346.     TCHAR prefix[2];    /* numeric prefix -- up to two characters */
  347.     int prefixlen;  /* length of prefix -- 0 means no prefix */
  348.     int capexp;     /* non-zero = 'E' exponent signifient, zero = 'e' */
  349.     int no_output;  /* non-zero = prodcue no output for this specifier */
  350.     union {
  351.         char *sz;   /* pointer text to be printed, not zero terminated */
  352.         wchar_t *wz;
  353.         } text;
  354.  
  355.     int textlen;    /* length of the text in bytes/wchars to be printed.
  356.                        textlen is in multibyte or wide chars if _UNICODE */
  357.     union {
  358.         char sz[BUFFERSIZE];
  359. #ifdef _UNICODE
  360.         wchar_t wz[BUFFERSIZE];
  361. #endif  /* _UNICODE */
  362.         } buffer;
  363.     wchar_t wchar;      /* temp wchar_t */
  364.     int bufferiswide;   /* non-zero = buffer contains wide chars already */
  365.  
  366.     textlen = 0;        /* no text yet */
  367.     charsout = 0;       /* no characters written yet */
  368.     state = ST_NORMAL;  /* starting state */
  369.  
  370.     /* main loop -- loop while format character exist and no I/O errors */
  371.     while ((ch = *format++) != _T('\0') && charsout >= 0) {
  372.         chclass = find_char_class(ch);  /* find character class */
  373.         state = find_next_state(chclass, state); /* find next state */
  374.  
  375.         /* execute code for each state */
  376.         switch (state) {
  377.  
  378.         case ST_NORMAL:
  379.  
  380.         NORMAL_STATE:
  381.  
  382.             /* normal state -- just write character */
  383. #ifdef _UNICODE
  384.             bufferiswide = 1;
  385. #else  /* _UNICODE */
  386.             bufferiswide = 0;
  387.             if (isleadbyte((int)(unsigned char)ch)) {
  388.                 WRITE_CHAR(ch, &charsout);
  389.                 ch = *format++;
  390.                 _ASSERTE (ch != _T('\0')); /* UNDONE: don't fall off format string */
  391.             }
  392. #endif  /* _UNICODE */
  393.             WRITE_CHAR(ch, &charsout);
  394.             break;
  395.  
  396.         case ST_PERCENT:
  397.             /* set default value of conversion parameters */
  398.             prefixlen = fldwidth = no_output = capexp = 0;
  399.             flags = 0;
  400.             precision = -1;
  401.             bufferiswide = 0;   /* default */
  402.             break;
  403.  
  404.         case ST_FLAG:
  405.             /* set flag based on which flag character */
  406.             switch (ch) {
  407.             case _T('-'):
  408.                 flags |= FL_LEFT;   /* '-' => left justify */
  409.                 break;
  410.             case _T('+'):
  411.                 flags |= FL_SIGN;   /* '+' => force sign indicator */
  412.                 break;
  413.             case _T(' '):
  414.                 flags |= FL_SIGNSP; /* ' ' => force sign or space */
  415.                 break;
  416.             case _T('#'):
  417.                 flags |= FL_ALTERNATE;  /* '#' => alternate form */
  418.                 break;
  419.             case _T('0'):
  420.                 flags |= FL_LEADZERO;   /* '0' => pad with leading zeros */
  421.                 break;
  422.             }
  423.             break;
  424.  
  425.         case ST_WIDTH:
  426.             /* update width value */
  427.             if (ch == _T('*')) {
  428.                 /* get width from arg list */
  429.                 fldwidth = get_int_arg(&argptr);
  430.                 if (fldwidth < 0) {
  431.                     /* ANSI says neg fld width means '-' flag and pos width */
  432.                     flags |= FL_LEFT;
  433.                     fldwidth = -fldwidth;
  434.                 }
  435.             }
  436.             else {
  437.                 /* add digit to current field width */
  438.                 fldwidth = fldwidth * 10 + (ch - _T('0'));
  439.             }
  440.             break;
  441.  
  442.         case ST_DOT:
  443.             /* zero the precision, since dot with no number means 0
  444.                not default, according to ANSI */
  445.             precision = 0;
  446.             break;
  447.  
  448.         case ST_PRECIS:
  449.             /* update precison value */
  450.             if (ch == _T('*')) {
  451.                 /* get precision from arg list */
  452.                 precision = get_int_arg(&argptr);
  453.                 if (precision < 0)
  454.                     precision = -1; /* neg precision means default */
  455.             }
  456.             else {
  457.                 /* add digit to current precision */
  458.                 precision = precision * 10 + (ch - _T('0'));
  459.             }
  460.             break;
  461.  
  462.         case ST_SIZE:
  463.             /* just read a size specifier, set the flags based on it */
  464.             switch (ch) {
  465. #if !LONG_IS_INT || !defined (_UNICODE)
  466.             case _T('l'):
  467.                 flags |= FL_LONG;   /* 'l' => long int or wchar_t */
  468.                 break;
  469. #endif  /* !LONG_IS_INT || !defined (_UNICODE) */
  470.  
  471. #if !LONGDOUBLE_IS_DOUBLE || defined (_M_ALPHA)
  472.             /*
  473.              * Alpha has native 64-bit integer registers and operations.
  474.              * The int and long types are 32 bits and an Alpha specific
  475.              * __int64 type is 64 bits.  We also use the 'L' flag for
  476.              * integer arguments to indicate 64-bit conversions (%Lx).
  477.              */
  478.  
  479.             case _T('L'):
  480.                 flags |= FL_I64;    /* 'L' => __int64 */
  481.                 break;
  482. #endif  /* !LONGDOUBLE_IS_DOUBLE || defined (_M_ALPHA) */
  483.  
  484.             case _T('I'):
  485.                 /*
  486.                  * In order to handle the I64 size modifier, we depart from
  487.                  * the simple deterministic state machine. The code below
  488.                  * scans
  489.                  */
  490.                 if ( (*format == _T('6')) && (*(format + 1) == _T('4')) ) {
  491.                     format += 2;
  492.                     flags |= FL_I64;    /* I64 => __int64 */
  493.                 }
  494.                 else {
  495.                     state = ST_NORMAL;
  496.                     goto NORMAL_STATE;
  497.                 }
  498.                 break;
  499.  
  500. #if !SHORT_IS_INT || defined (_UNICODE)
  501.             case _T('h'):
  502.                 flags |= FL_SHORT;  /* 'h' => short int or char */
  503.                 break;
  504. #endif  /* !SHORT_IS_INT || defined (_UNICODE) */
  505.  
  506. /* UNDONE: support %wc and %ws for now only for compatibility */
  507.             case _T('w'):
  508.                 flags |= FL_WIDECHAR;  /* 'w' => wide character */
  509.                 break;
  510.  
  511.             }
  512.             break;
  513.  
  514.         case ST_TYPE:
  515.             /* we have finally read the actual type character, so we       */
  516.             /* now format and "print" the output.  We use a big switch     */
  517.             /* statement that sets 'text' to point to the text that should */
  518.             /* be printed, and 'textlen' to the length of this text.       */
  519.             /* Common code later on takes care of justifying it and        */
  520.             /* other miscellaneous chores.  Note that cases share code,    */
  521.             /* in particular, all integer formatting is done in one place. */
  522.             /* Look at those funky goto statements!                        */
  523.  
  524.             switch (ch) {
  525.  
  526.             case _T('C'):   /* ISO wide character */
  527.                 if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
  528. #ifdef _UNICODE
  529.                     flags |= FL_SHORT;
  530. #else  /* _UNICODE */
  531.                     flags |= FL_WIDECHAR;   /* ISO std. */
  532. #endif  /* _UNICODE */
  533.                 /* fall into 'c' case */
  534.  
  535.             case _T('c'): {
  536.                 /* print a single character specified by int argument */
  537. #ifdef _UNICODE
  538.                 bufferiswide = 1;
  539.                 wchar = (wchar_t) get_int_arg(&argptr);
  540.                 if (flags & FL_SHORT) {
  541.                     /* format multibyte character */
  542.                     /* this is an extension of ANSI */
  543.                     char tempchar[2];
  544.                     {
  545.                         tempchar[0] = (char)(wchar & 0x00ff);
  546.                         tempchar[1] = '\0';
  547.                     }
  548.  
  549.                     if (mbtowc(buffer.wz,tempchar,MB_CUR_MAX) < 0) {
  550.                         /* ignore if conversion was unsuccessful */
  551.                         no_output = 1;
  552.                     }
  553.                 } else {
  554.                     buffer.wz[0] = wchar;
  555.                 }
  556.                 text.wz = buffer.wz;
  557.                 textlen = 1;    /* print just a single character */
  558. #else  /* _UNICODE */
  559.                 if (flags & (FL_LONG|FL_WIDECHAR)) {
  560.                     wchar = (wchar_t) get_short_arg(&argptr);
  561.                     /* convert to multibyte character */
  562.                     textlen = wctomb(buffer.sz, wchar);
  563.  
  564.                     /* check that conversion was successful */
  565.                     if (textlen < 0)
  566.                         no_output = 1;
  567.                 } else {
  568.                     /* format multibyte character */
  569.                     /* this is an extension of ANSI */
  570.                     unsigned short temp;
  571.                     temp = (unsigned short) get_int_arg(&argptr);
  572.                     {
  573.                         buffer.sz[0] = (char) temp;
  574.                         textlen = 1;
  575.                     }
  576.                 }
  577.                 text.sz = buffer.sz;
  578. #endif  /* _UNICODE */
  579.             }
  580.             break;
  581.  
  582.             case _T('Z'): {
  583.                 /* print a Counted String
  584.  
  585.                 int i;
  586.                 char *p;       /* temps */
  587.                 struct _count_string {
  588.                     short Length;
  589.                     short MaximumLength;
  590.                     char *Buffer;
  591.                 } *pstr;
  592.  
  593.                 pstr = get_ptr_arg(&argptr);
  594.                 if (pstr == NULL || pstr->Buffer == NULL) {
  595.                     /* null ptr passed, use special string */
  596.                     text.sz = __nullstring;
  597.                     textlen = strlen(text.sz);
  598.                 } else {
  599.                     if (flags & FL_WIDECHAR) {
  600.                         text.wz = (wchar_t *)pstr->Buffer;
  601.                         textlen = pstr->Length / sizeof(wchar_t);
  602.                         bufferiswide = 1;
  603.                     } else {
  604.                         bufferiswide = 0;
  605.                         text.sz = pstr->Buffer;
  606.                         textlen = pstr->Length;
  607.                     }
  608.                 }
  609.             }
  610.             break;
  611.  
  612.             case _T('S'):   /* ISO wide character string */
  613. #ifndef _UNICODE
  614.                 if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
  615.                     flags |= FL_WIDECHAR;
  616. #else  /* _UNICODE */
  617.                 if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
  618.                     flags |= FL_SHORT;
  619. #endif  /* _UNICODE */
  620.  
  621.             case _T('s'): {
  622.                 /* print a string --                            */
  623.                 /* ANSI rules on how much of string to print:   */
  624.                 /*   all if precision is default,               */
  625.                 /*   min(precision, length) if precision given. */
  626.                 /* prints '(null)' if a null string is passed   */
  627.  
  628.                 int i;
  629.                 char *p;       /* temps */
  630.                 wchar_t *pwch;
  631.  
  632.                 /* At this point it is tempting to use strlen(), but */
  633.                 /* if a precision is specified, we're not allowed to */
  634.                 /* scan past there, because there might be no null   */
  635.                 /* at all.  Thus, we must do our own scan.           */
  636.  
  637.                 i = (precision == -1) ? INT_MAX : precision;
  638.                 text.sz = get_ptr_arg(&argptr);
  639.  
  640. /* UNDONE: handle '#' case properly */
  641.                 /* scan for null upto i characters */
  642. #ifdef _UNICODE
  643.                 if (flags & FL_SHORT) {
  644.                     if (text.sz == NULL) /* NULL passed, use special string */
  645.                         text.sz = __nullstring;
  646.                     p = text.sz;
  647.                     for (textlen=0; textlen<i && *p; textlen++) {
  648.                         if (isleadbyte((int)*p))
  649.                             ++p;
  650.                         ++p;
  651.                     }
  652.                     /* textlen now contains length in multibyte chars */
  653.                 } else {
  654.                     if (text.wz == NULL) /* NULL passed, use special string */
  655.                         text.wz = __wnullstring;
  656.                     bufferiswide = 1;
  657.                     pwch = text.wz;
  658.                     while (i-- && *pwch)
  659.                         ++pwch;
  660.                     textlen = pwch - text.wz;       /* in wchar_ts */
  661.                     /* textlen now contains length in wide chars */
  662.                 }
  663. #else  /* _UNICODE */
  664.                 if (flags & (FL_LONG|FL_WIDECHAR)) {
  665.                     if (text.wz == NULL) /* NULL passed, use special string */
  666.                         text.wz = __wnullstring;
  667.                     bufferiswide = 1;
  668.                     pwch = text.wz;
  669.                     while ( i-- && *pwch )
  670.                         ++pwch;
  671.                     textlen = pwch - text.wz;
  672.                     /* textlen now contains length in wide chars */
  673.                 } else {
  674.                     if (text.sz == NULL) /* NULL passed, use special string */
  675.                         text.sz = __nullstring;
  676.                     p = text.sz;
  677.                     while (i-- && *p)
  678.                         ++p;
  679.                     textlen = p - text.sz;    /* length of the string */
  680.                 }
  681.  
  682. #endif  /* _UNICODE */
  683.             }
  684.             break;
  685.  
  686.  
  687.             case _T('n'): {
  688.                 /* write count of characters seen so far into */
  689.                 /* short/int/long thru ptr read from args */
  690.  
  691.                 void *p;        /* temp */
  692.  
  693.                 p = get_ptr_arg(&argptr);
  694.  
  695.                 /* store chars out into short/long/int depending on flags */
  696. #if !LONG_IS_INT
  697.                 if (flags & FL_LONG)
  698.                     *(long *)p = charsout;
  699.                 else
  700. #endif  /* !LONG_IS_INT */
  701.  
  702. #if !SHORT_IS_INT
  703.                 if (flags & FL_SHORT)
  704.                     *(short *)p = (short) charsout;
  705.                 else
  706. #endif  /* !SHORT_IS_INT */
  707.                     *(int *)p = charsout;
  708.  
  709.                 no_output = 1;              /* force no output */
  710.             }
  711.             break;
  712.  
  713.  
  714.             case _T('E'):
  715.             case _T('G'):
  716.                 capexp = 1;                 /* capitalize exponent */
  717.                 ch += _T('a') - _T('A');    /* convert format char to lower */
  718.                 /* DROP THROUGH */
  719.             case _T('e'):
  720.             case _T('f'):
  721.             case _T('g'): {
  722.                 /* floating point conversion -- we call cfltcvt routines */
  723.                 /* to do the work for us.                                */
  724.                 flags |= FL_SIGNED;         /* floating point is signed conversion */
  725.                 text.sz = buffer.sz;        /* put result in buffer */
  726.  
  727.                 /* compute the precision value */
  728.                 if (precision < 0)
  729.                     precision = 6;          /* default precision: 6 */
  730.                 else if (precision == 0 && ch == _T('g'))
  731.                     precision = 1;          /* ANSI specified */
  732.  
  733. #if !LONGDOUBLE_IS_DOUBLE
  734.                 /* do the conversion */
  735.                 if (flags & FL_LONGDOUBLE) {
  736.                     LONGDOUBLE tmp;
  737.                     tmp=va_arg(argptr, LONGDOUBLE);
  738.                     /* Note: assumes ch is in ASCII range */
  739.                     _cldcvt(&tmp, text.sz, (char)ch, precision, capexp);
  740.                 } else
  741. #endif  /* !LONGDOUBLE_IS_DOUBLE */
  742.                 {
  743.                     DOUBLE tmp;
  744.                     tmp=va_arg(argptr, DOUBLE);
  745.                     /* Note: assumes ch is in ASCII range */
  746.                     _cfltcvt(&tmp,text.sz, (char)ch, precision, capexp);
  747.                 }
  748.  
  749.                 /* '#' and precision == 0 means force a decimal point */
  750.                 if ((flags & FL_ALTERNATE) && precision == 0)
  751.                     _forcdecpt(text.sz);
  752.  
  753.                 /* 'g' format means crop zero unless '#' given */
  754.                 if (ch == _T('g') && !(flags & FL_ALTERNATE))
  755.                     _cropzeros(text.sz);
  756.  
  757.                 /* check if result was negative, save '-' for later */
  758.                 /* and point to positive part (this is for '0' padding) */
  759.                 if (*text.sz == '-') {
  760.                     flags |= FL_NEGATIVE;
  761.                     ++text.sz;
  762.                 }
  763.  
  764.                 textlen = strlen(text.sz);     /* compute length of text */
  765.             }
  766.             break;
  767.  
  768.             case _T('d'):
  769.             case _T('i'):
  770.                 /* signed decimal output */
  771.                 flags |= FL_SIGNED;
  772.                 radix = 10;
  773.                 goto COMMON_INT;
  774.  
  775.             case _T('u'):
  776.                 radix = 10;
  777.                 goto COMMON_INT;
  778.  
  779.             case _T('p'):
  780.                 /* write a pointer -- this is like an integer or long */
  781.                 /* except we force precision to pad with zeros and */
  782.                 /* output in big hex. */
  783.  
  784.                 precision = 2 * sizeof(void *);     /* number of hex digits needed */
  785. #if !PTR_IS_INT
  786.                 flags |= FL_LONG;                   /* assume we're converting a long */
  787. #endif  /* !PTR_IS_INT */
  788.                 /* DROP THROUGH to hex formatting */
  789.  
  790.             case _T('X'):
  791.                 /* unsigned upper hex output */
  792.                 hexadd = _T('A') - _T('9') - 1;     /* set hexadd for uppercase hex */
  793.                 goto COMMON_HEX;
  794.  
  795.             case _T('x'):
  796.                 /* unsigned lower hex output */
  797.                 hexadd = _T('a') - _T('9') - 1;     /* set hexadd for lowercase hex */
  798.                 /* DROP THROUGH TO COMMON_HEX */
  799.  
  800.             COMMON_HEX:
  801.                 radix = 16;
  802.                 if (flags & FL_ALTERNATE) {
  803.                     /* alternate form means '0x' prefix */
  804.                     prefix[0] = _T('0');
  805.                     prefix[1] = (TCHAR)(_T('x') - _T('a') + _T('9') + 1 + hexadd);  /* 'x' or 'X' */
  806.                     prefixlen = 2;
  807.                 }
  808.                 goto COMMON_INT;
  809.  
  810.             case _T('o'):
  811.                 /* unsigned octal output */
  812.                 radix = 8;
  813.                 if (flags & FL_ALTERNATE) {
  814.                     /* alternate form means force a leading 0 */
  815.                     flags |= FL_FORCEOCTAL;
  816.                 }
  817.                 /* DROP THROUGH to COMMON_INT */
  818.  
  819.             COMMON_INT: {
  820.                 /* This is the general integer formatting routine. */
  821.                 /* Basically, we get an argument, make it positive */
  822.                 /* if necessary, and convert it according to the */
  823.                 /* correct radix, setting text and textlen */
  824.                 /* appropriately. */
  825.  
  826. #if _INTEGRAL_MAX_BITS >= 64           
  827.                 unsigned __int64 number;    /* number to convert */
  828.                 int digit;              /* ascii value of digit */
  829.                 __int64 l;              /* temp long value */
  830. #else  /* _INTEGRAL_MAX_BITS >= 64            */
  831.                 unsigned long number;   /* number to convert */
  832.                 int digit;              /* ascii value of digit */
  833.                 long l;                 /* temp long value */
  834. #endif  /* _INTEGRAL_MAX_BITS >= 64            */
  835.  
  836.                 /* 1. read argument into l, sign extend as needed */
  837. #if _INTEGRAL_MAX_BITS >= 64       
  838.                 if (flags & FL_I64)
  839.                     l = get_int64_arg(&argptr);
  840.                 else
  841. #endif  /* _INTEGRAL_MAX_BITS >= 64        */
  842.  
  843. #if !LONG_IS_INT
  844.                 if (flags & FL_LONG)
  845.                     l = get_long_arg(&argptr);
  846.                 else
  847. #endif  /* !LONG_IS_INT */
  848.  
  849. #if !SHORT_IS_INT
  850.                 if (flags & FL_SHORT) {
  851.                     if (flags & FL_SIGNED)
  852.                         l = (short) get_int_arg(&argptr); /* sign extend */
  853.                     else
  854.                         l = (unsigned short) get_int_arg(&argptr);    /* zero-extend*/
  855.                 } else
  856. #endif  /* !SHORT_IS_INT */
  857.                 {
  858.                     if (flags & FL_SIGNED)
  859.                         l = get_int_arg(&argptr); /* sign extend */
  860.                     else
  861.                         l = (unsigned int) get_int_arg(&argptr);    /* zero-extend*/
  862.                 }
  863.  
  864.                 /* 2. check for negative; copy into number */
  865.                 if ( (flags & FL_SIGNED) && l < 0) {
  866.                     number = -l;
  867.                     flags |= FL_NEGATIVE;   /* remember negative sign */
  868.                 } else {
  869.                     number = l;
  870.                 }
  871.  
  872. #if _INTEGRAL_MAX_BITS >= 64       
  873.                 if ( (flags & FL_I64) == 0 ) {
  874.                     /*
  875.                      * Unless printing a full 64-bit value, insure values
  876.                      * here are not in cananical longword format to prevent
  877.                      * the sign extended upper 32-bits from being printed.
  878.                      */
  879.                     number &= 0xffffffff;
  880.                 }
  881. #endif  /* _INTEGRAL_MAX_BITS >= 64        */
  882.  
  883.                 /* 3. check precision value for default; non-default */
  884.                 /*    turns off 0 flag, according to ANSI. */
  885.                 if (precision < 0)
  886.                     precision = 1;  /* default precision */
  887.                 else
  888.                     flags &= ~FL_LEADZERO;
  889.  
  890.                 /* 4. Check if data is 0; if so, turn off hex prefix */
  891.                 if (number == 0)
  892.                     prefixlen = 0;
  893.  
  894.                 /* 5. Convert data to ASCII -- note if precision is zero */
  895.                 /*    and number is zero, we get no digits at all.       */
  896.  
  897.                 text.sz = &buffer.sz[BUFFERSIZE-1];    /* last digit at end of buffer */
  898.  
  899.                 while (precision-- > 0 || number != 0) {
  900.                     digit = (int)(number % radix) + '0';
  901.                     number /= radix;                /* reduce number */
  902.                     if (digit > '9') {
  903.                         /* a hex digit, make it a letter */
  904.                         digit += hexadd;
  905.                     }
  906.                     *text.sz-- = (char)digit;       /* store the digit */
  907.                 }
  908.  
  909.                 textlen = (char *)&buffer.sz[BUFFERSIZE-1] - text.sz; /* compute length of number */
  910.                 ++text.sz;          /* text points to first digit now */
  911.  
  912.  
  913.                 /* 6. Force a leading zero if FORCEOCTAL flag set */
  914.                 if ((flags & FL_FORCEOCTAL) && (text.sz[0] != '0' || textlen == 0)) {
  915.                     *--text.sz = '0';
  916.                     ++textlen;      /* add a zero */
  917.                 }
  918.             }
  919.             break;
  920.             }
  921.  
  922.             /* At this point, we have done the specific conversion, and */
  923.             /* 'text' points to text to print; 'textlen' is length.  Now we */
  924.             /* justify it, put on prefixes, leading zeros, and then */
  925.             /* print it. */
  926.  
  927.             if (!no_output) {
  928.                 int padding;    /* amount of padding, negative means zero */
  929.  
  930.                 if (flags & FL_SIGNED) {
  931.                     if (flags & FL_NEGATIVE) {
  932.                         /* prefix is a '-' */
  933.                         prefix[0] = _T('-');
  934.                         prefixlen = 1;
  935.                     }
  936.                     else if (flags & FL_SIGN) {
  937.                         /* prefix is '+' */
  938.                         prefix[0] = _T('+');
  939.                         prefixlen = 1;
  940.                     }
  941.                     else if (flags & FL_SIGNSP) {
  942.                         /* prefix is ' ' */
  943.                         prefix[0] = _T(' ');
  944.                         prefixlen = 1;
  945.                     }
  946.                 }
  947.  
  948.                 /* calculate amount of padding -- might be negative, */
  949.                 /* but this will just mean zero */
  950.                 padding = fldwidth - textlen - prefixlen;
  951.  
  952.                 /* put out the padding, prefix, and text, in the correct order */
  953.  
  954.                 if (!(flags & (FL_LEFT | FL_LEADZERO))) {
  955.                     /* pad on left with blanks */
  956.                     WRITE_MULTI_CHAR(_T(' '), padding, &charsout);
  957.                 }
  958.  
  959.                 /* write prefix */
  960.                 WRITE_STRING(prefix, prefixlen, &charsout);
  961.  
  962.                 if ((flags & FL_LEADZERO) && !(flags & FL_LEFT)) {
  963.                     /* write leading zeros */
  964.                     WRITE_MULTI_CHAR(_T('0'), padding, &charsout);
  965.                 }
  966.  
  967.                 /* write text */
  968. #ifndef _UNICODE
  969.                 if (bufferiswide && (textlen > 0)) {
  970.                     wchar_t *p;
  971.                     int retval, count;
  972.                     char buffer[MB_LEN_MAX+1];
  973.  
  974.                     p = text.wz;
  975.                     count = textlen;
  976.                     while (count--) {
  977.                         retval = wctomb(buffer, *p++);
  978.                         if (retval <= 0)
  979.                             break;
  980.                         WRITE_STRING(buffer, retval, &charsout);
  981.                     }
  982.                 } else {
  983.                     WRITE_STRING(text.sz, textlen, &charsout);
  984.                 }
  985. #else  /* _UNICODE */
  986.                 if (!bufferiswide && textlen > 0) {
  987.                     char *p;
  988.                     int retval, count;
  989.  
  990.                     p = text.sz;
  991.                     count = textlen;
  992.                     while (count-- > 0) {
  993.                         retval = mbtowc(&wchar, p, MB_CUR_MAX);
  994.                         if (retval <= 0)
  995.                             break;
  996.                         WRITE_CHAR(wchar, &charsout);
  997.                         p += retval;
  998.                     }
  999.                 } else {
  1000.                     WRITE_STRING(text.wz, textlen, &charsout);
  1001.                 }
  1002. #endif  /* _UNICODE */
  1003.  
  1004.                 if (flags & FL_LEFT) {
  1005.                     /* pad on right with blanks */
  1006.                     WRITE_MULTI_CHAR(_T(' '), padding, &charsout);
  1007.                 }
  1008.  
  1009.                 /* we're done! */
  1010.             }
  1011.             break;
  1012.         }
  1013.     }
  1014.  
  1015.     return charsout;        /* return value = number of characters written */
  1016. }
  1017.  
  1018. /*
  1019.  *  Future Optimizations for swprintf:
  1020.  *  - Don't free the memory used for converting the buffer to wide chars.
  1021.  *    Use realloc if the memory is not sufficient.  Free it at the end.
  1022.  */
  1023.  
  1024. /***
  1025. *void write_char(int ch, int *pnumwritten)
  1026. *ifdef _UNICODE
  1027. *void write_char(wchar_t ch, FILE *f, int *pnumwritten)
  1028. *endif
  1029. *void write_char(int ch, FILE *f, int *pnumwritten)
  1030. *
  1031. *Purpose:
  1032. *   Writes a single character to the given file/console.  If no error occurs,
  1033. *   then *pnumwritten is incremented; otherwise, *pnumwritten is set
  1034. *   to -1.
  1035. *
  1036. *Entry:
  1037. *   int ch           - character to write
  1038. *   FILE *f          - file to write to
  1039. *   int *pnumwritten - pointer to integer to update with total chars written
  1040. *
  1041. *Exit:
  1042. *   No return value.
  1043. *
  1044. *Exceptions:
  1045. *
  1046. *******************************************************************************/
  1047.  
  1048. #ifdef CPRFLAG
  1049.  
  1050. LOCAL(void) write_char (
  1051.     int ch,
  1052.     int *pnumwritten
  1053.     )
  1054. {
  1055.     if (_putch_lk(ch) == EOF)
  1056.         *pnumwritten = -1;
  1057.     else
  1058.         ++(*pnumwritten);
  1059. }
  1060.  
  1061. #elif defined (_UNICODE)
  1062.  
  1063. LOCAL(void) write_char (
  1064.     wchar_t ch,
  1065.     FILE *f,
  1066.     int *pnumwritten
  1067.     )
  1068. {
  1069.     if (_putwc_lk(ch, f) == WEOF)
  1070.         *pnumwritten = -1;
  1071.     else
  1072.         ++(*pnumwritten);
  1073. }
  1074.  
  1075. #else  /* defined (_UNICODE) */
  1076.  
  1077. LOCAL(void) write_char (
  1078.     int ch,
  1079.     FILE *f,
  1080.     int *pnumwritten
  1081.     )
  1082. {
  1083.     if (_putc_lk(ch, f) == EOF)
  1084.         *pnumwritten = -1;
  1085.     else
  1086.         ++(*pnumwritten);
  1087. }
  1088.  
  1089. #endif  /* defined (_UNICODE) */
  1090.  
  1091. /***
  1092. *void write_multi_char(int ch, int num, int *pnumwritten)
  1093. *ifdef _UNICODE
  1094. *void write_multi_char(wchar_t ch, int num, FILE *f, int *pnumwritten)
  1095. *endif
  1096. *void write_multi_char(int ch, int num, FILE *f, int *pnumwritten)
  1097. *
  1098. *Purpose:
  1099. *   Writes num copies of a character to the given file/console.  If no error occurs,
  1100. *   then *pnumwritten is incremented by num; otherwise, *pnumwritten is set
  1101. *   to -1.  If num is negative, it is treated as zero.
  1102. *
  1103. *Entry:
  1104. *   int ch           - character to write
  1105. *   int num          - number of times to write the characters
  1106. *   FILE *f          - file to write to
  1107. *   int *pnumwritten - pointer to integer to update with total chars written
  1108. *
  1109. *Exit:
  1110. *   No return value.
  1111. *
  1112. *Exceptions:
  1113. *
  1114. *******************************************************************************/
  1115.  
  1116. #ifdef CPRFLAG
  1117.  
  1118. LOCAL(void) write_multi_char (
  1119.     int ch,
  1120.     int num,
  1121.     int *pnumwritten
  1122.     )
  1123. {
  1124.     while (num-- > 0) {
  1125.         write_char(ch, pnumwritten);
  1126.         if (*pnumwritten == -1)
  1127.             break;
  1128.     }
  1129. }
  1130.  
  1131. #else  /* CPRFLAG */
  1132. #ifdef _UNICODE
  1133.  
  1134. LOCAL(void) write_multi_char (
  1135.     wchar_t ch,
  1136.     int num,
  1137.     FILE *f,
  1138.     int *pnumwritten
  1139.     )
  1140. #else  /* _UNICODE */
  1141.  
  1142. LOCAL(void) write_multi_char (
  1143.     int ch,
  1144.     int num,
  1145.     FILE *f,
  1146.     int *pnumwritten
  1147.     )
  1148. #endif  /* _UNICODE */
  1149. {
  1150.     while (num-- > 0) {
  1151.         write_char(ch, f, pnumwritten);
  1152.         if (*pnumwritten == -1)
  1153.             break;
  1154.     }
  1155. }
  1156.  
  1157. #endif  /* CPRFLAG */
  1158.  
  1159. /***
  1160. *void write_string(char *string, int len, int *pnumwritten)
  1161. *void write_string(char *string, int len, FILE *f, int *pnumwritten)
  1162. *ifdef _UNICODE
  1163. *void write_string(wchar_t *string, int len, FILE *f, int *pnumwritten)
  1164. *endif
  1165. *void write_wstring(wchar_t *string, int len, int *pnumwritten)
  1166. *void write_wstring(wchar_t *string, int len, FILE *f, int *pnumwritten)
  1167. *
  1168. *Purpose:
  1169. *   Writes a string of the given length to the given file.  If no error occurs,
  1170. *   then *pnumwritten is incremented by len; otherwise, *pnumwritten is set
  1171. *   to -1.  If len is negative, it is treated as zero.
  1172. *
  1173. *Entry:
  1174. *   char *string     - string to write (NOT null-terminated)
  1175. *   int len          - length of string
  1176. *   FILE *f          - file to write to
  1177. *   int *pnumwritten - pointer to integer to update with total chars written
  1178. *
  1179. *Exit:
  1180. *   No return value.
  1181. *
  1182. *Exceptions:
  1183. *
  1184. *******************************************************************************/
  1185.  
  1186. #ifdef CPRFLAG
  1187.  
  1188. LOCAL(void) write_string (
  1189.     char *string,
  1190.     int len,
  1191.     int *pnumwritten
  1192.     )
  1193. {
  1194.     while (len-- > 0) {
  1195.         write_char(*string++, pnumwritten);
  1196.         if (*pnumwritten == -1)
  1197.             break;
  1198.     }
  1199. }
  1200.  
  1201. #else  /* CPRFLAG */
  1202. #if _UNICODE
  1203.  
  1204. LOCAL(void) write_string (
  1205.     wchar_t *string,
  1206.     int len,
  1207.     FILE *f,
  1208.     int *pnumwritten
  1209.     )
  1210. #else  /* _UNICODE */
  1211.  
  1212. LOCAL(void) write_string (
  1213.     char *string,
  1214.     int len,
  1215.     FILE *f,
  1216.     int *pnumwritten
  1217.     )
  1218. #endif  /* _UNICODE */
  1219. {
  1220.     while (len-- > 0) {
  1221.         write_char(*string++, f, pnumwritten);
  1222.         if (*pnumwritten == -1)
  1223.             break;
  1224.     }
  1225. }
  1226. #endif  /* CPRFLAG */
  1227.  
  1228.  
  1229. /***
  1230. *int get_int_arg(va_list *pargptr)
  1231. *
  1232. *Purpose:
  1233. *   Gets an int argument off the given argument list and updates *pargptr.
  1234. *
  1235. *Entry:
  1236. *   va_list *pargptr - pointer to argument list; updated by function
  1237. *
  1238. *Exit:
  1239. *   Returns the integer argument read from the argument list.
  1240. *
  1241. *Exceptions:
  1242. *
  1243. *******************************************************************************/
  1244.  
  1245. __inline int __cdecl get_int_arg (
  1246.     va_list *pargptr
  1247.     )
  1248. {
  1249.     return va_arg(*pargptr, int);
  1250. }
  1251.  
  1252. /***
  1253. *long get_long_arg(va_list *pargptr)
  1254. *
  1255. *Purpose:
  1256. *   Gets an long argument off the given argument list and updates *pargptr.
  1257. *
  1258. *Entry:
  1259. *   va_list *pargptr - pointer to argument list; updated by function
  1260. *
  1261. *Exit:
  1262. *   Returns the long argument read from the argument list.
  1263. *
  1264. *Exceptions:
  1265. *
  1266. *******************************************************************************/
  1267.  
  1268. #if !LONG_IS_INT
  1269. __inline long __cdecl get_long_arg (
  1270.     va_list *pargptr
  1271.     )
  1272. {
  1273.     return va_arg(*pargptr, long);
  1274. }
  1275. #endif  /* !LONG_IS_INT */
  1276.  
  1277. #if _INTEGRAL_MAX_BITS >= 64   
  1278. __inline __int64 __cdecl get_int64_arg (
  1279.     va_list *pargptr
  1280.     )
  1281. {
  1282.     return va_arg(*pargptr, __int64);
  1283. }
  1284. #endif  /* _INTEGRAL_MAX_BITS >= 64    */
  1285.  
  1286. #ifndef _UNICODE
  1287. /***
  1288. *short get_short_arg(va_list *pargptr)
  1289. *
  1290. *Purpose:
  1291. *   Gets a short argument off the given argument list and updates *pargptr.
  1292. *   *** CURRENTLY ONLY USED TO GET A WCHAR_T, IFDEF _INTL ***
  1293. *
  1294. *Entry:
  1295. *   va_list *pargptr - pointer to argument list; updated by function
  1296. *
  1297. *Exit:
  1298. *   Returns the short argument read from the argument list.
  1299. *
  1300. *Exceptions:
  1301. *
  1302. *******************************************************************************/
  1303.  
  1304. #if !SHORT_IS_INT
  1305. __inline short __cdecl get_short_arg (
  1306.     va_list *pargptr
  1307.     )
  1308. {
  1309.     return va_arg(*pargptr, short);
  1310. }
  1311. #endif  /* !SHORT_IS_INT */
  1312. #endif  /* _UNICODE */
  1313.  
  1314.  
  1315. #else  /* _WIN32 */
  1316.  
  1317. #if defined (_M_MPPC) || defined (_M_M68K)
  1318.  
  1319.  
  1320. #include <cruntime.h>
  1321. #include <limits.h>
  1322. #include <string.h>
  1323. #include <stddef.h>
  1324. #include <stdio.h>
  1325. #include <stdarg.h>
  1326. #include <cvt.h>
  1327. #include <conio.h>
  1328. #include <internal.h>
  1329. #include <fltintrn.h>
  1330. #include <tchar.h>
  1331. #include <stdlib.h>
  1332. #include <ctype.h>
  1333. #include <dbgint.h>
  1334.  
  1335. /*
  1336.  * Code under if defined(_WIN32_) && !defined(_DOSX32_) && !defined(_INTL)
  1337.  * is partial international support written by NT developers.  This code
  1338.  * should be removed when international sources are merged with orville.
  1339.  */
  1340.  
  1341. /* this macro defines a function which is private and as fast as possible: */
  1342. /* for example, in C 6.0, it might be static _fastcall <type> near. */
  1343. #define LOCAL(x) static x __cdecl
  1344.  
  1345. /* int/long/short/pointer sizes */
  1346.  
  1347. /* the following should be set depending on the sizes of various types */
  1348. #define LONG_IS_INT          1       /* 1 means long is same size as int */
  1349. #define SHORT_IS_INT         0       /* 1 means short is same size as int */
  1350. #define PTR_IS_INT           1       /* 1 means ptr is same size as int */
  1351. #define PTR_IS_LONG          1       /* 1 means ptr is same size as long */
  1352.  
  1353. #ifdef _M_MPPC
  1354. #define LONGDOUBLE_IS_DOUBLE 1       /* 1 means long double is same as double */
  1355. #else  /* _M_MPPC */
  1356. #define LONGDOUBLE_IS_DOUBLE 0       /* 1 means long double is same as double */
  1357. #endif  /* _M_MPPC */
  1358.  
  1359. #ifndef _INTEGRAL_MAX_BITS
  1360. #define _INTEGRAL_MAX_BITS  64
  1361. #endif  /* _INTEGRAL_MAX_BITS */
  1362.  
  1363. #if LONG_IS_INT
  1364.     #define get_long_arg(x) (long)get_int_arg(x)
  1365. #endif  /* LONG_IS_INT */
  1366.  
  1367. #if PTR_IS_INT
  1368.     #define get_ptr_arg(x) (void *)get_int_arg(x)
  1369. #elif PTR_IS_LONG
  1370.     #define get_ptr_arg(x) (void *)get_long_arg(x)
  1371. #else  /* PTR_IS_LONG */
  1372.     #error Size of pointer must be same as size of int or long
  1373. #endif  /* PTR_IS_LONG */
  1374.  
  1375.  
  1376.  
  1377. /* CONSTANTS */
  1378.  
  1379. /* size of conversion buffer (ANSI-specified minimum is 509) */
  1380.  
  1381. #define BUFFERSIZE    512
  1382.  
  1383. #if BUFFERSIZE < CVTBUFSIZE
  1384. #error Conversion buffer too small for max double.
  1385. #endif  /* BUFFERSIZE < CVTBUFSIZE */
  1386.  
  1387. /* flag definitions */
  1388. #define FL_SIGN       0x0001      /* put plus or minus in front */
  1389. #define FL_SIGNSP     0x0002      /* put space or minus in front */
  1390. #define FL_LEFT       0x0004      /* left justify */
  1391. #define FL_LEADZERO   0x0008      /* pad with leading zeros */
  1392. #define FL_LONG       0x0010      /* long value given */
  1393. #define FL_SHORT      0x0020      /* short value given */
  1394. #define FL_SIGNED     0x0040      /* signed data given */
  1395. #define FL_ALTERNATE  0x0080      /* alternate form requested */
  1396. #define FL_NEGATIVE   0x0100      /* value is negative */
  1397. #define FL_FORCEOCTAL 0x0200      /* force leading '0' for octals */
  1398. #define FL_LONGDOUBLE 0x0400      /* long double value given */
  1399. #define FL_WIDECHAR   0x0800      /* wide characters */
  1400. #define FL_I64        0x08000     /* __int64 value given */
  1401.  
  1402. /* state definitions */
  1403. enum STATE {
  1404.     ST_NORMAL,              /* normal state; outputting literal chars */
  1405.     ST_PERCENT,             /* just read '%' */
  1406.     ST_FLAG,                /* just read flag character */
  1407.     ST_WIDTH,               /* just read width specifier */
  1408.     ST_DOT,                 /* just read '.' */
  1409.     ST_PRECIS,              /* just read precision specifier */
  1410.     ST_SIZE,                /* just read size specifier */
  1411.     ST_TYPE                 /* just read type specifier */
  1412. };
  1413. #define NUMSTATES (ST_TYPE + 1)
  1414.  
  1415. /* character type values */
  1416. enum CHARTYPE {
  1417.     CH_OTHER,               /* character with no special meaning */
  1418.     CH_PERCENT,             /* '%' */
  1419.     CH_DOT,                 /* '.' */
  1420.     CH_STAR,                /* '*' */
  1421.     CH_ZERO,                /* '0' */
  1422.     CH_DIGIT,               /* '1'..'9' */
  1423.     CH_FLAG,                /* ' ', '+', '-', '#' */
  1424.     CH_SIZE,                /* 'h', 'l', 'L', 'N', 'F', 'w' */
  1425.     CH_TYPE                 /* type specifying character */
  1426. };
  1427.  
  1428. /* static data (read only, since we are re-entrant) */
  1429. static char *nullstring = "(null)";     /* string to print on null ptr */
  1430. #ifdef _UNICODE
  1431. static wchar_t *wnullstring = L"(null)";/* string to print on null ptr */
  1432. #endif  /* _UNICODE */
  1433.  
  1434. /* The state table.  This table is actually two tables combined into one. */
  1435. /* The lower nybble of each byte gives the character class of any         */
  1436. /* character; while the uper nybble of the byte gives the next state      */
  1437. /* to enter.  See the macros below the table for details.                 */
  1438. /*                                                                        */
  1439. /* The table is generated by maketabc.c -- use this program to make       */
  1440. /* changes.                                                               */
  1441.  
  1442. static char lookuptable[] = {
  1443.          0x06, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00,
  1444.          0x10, 0x00, 0x03, 0x06, 0x00, 0x06, 0x02, 0x10,
  1445.          0x04, 0x45, 0x45, 0x45, 0x05, 0x05, 0x05, 0x05,
  1446.          0x05, 0x35, 0x30, 0x00, 0x50, 0x00, 0x00, 0x00,
  1447.          0x00, 0x20, 0x28, 0x38, 0x50, 0x58, 0x07, 0x08,
  1448.          0x00, 0x37, 0x30, 0x30, 0x57, 0x50, 0x07, 0x00,
  1449.          0x00, 0x20, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00,
  1450.          0x08, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
  1451.          0x00, 0x70, 0x70, 0x78, 0x78, 0x78, 0x78, 0x08,
  1452.          0x07, 0x08, 0x00, 0x00, 0x07, 0x00, 0x08, 0x08,
  1453.          0x08, 0x00, 0x00, 0x08, 0x08, 0x08, 0x00, 0x08,
  1454.          0x08
  1455. };
  1456.  
  1457. #define find_char_class(c)              \
  1458.         ((c) < ' ' || (c) > 'x' ?       \
  1459.             CH_OTHER                    \
  1460.         :                               \
  1461.             lookuptable[(c)-' '] & 0xF)
  1462.  
  1463. #define find_next_state(class, state)   \
  1464.         (lookuptable[(class) * NUMSTATES + (state)] >> 4)
  1465.  
  1466.  
  1467. /*
  1468.  * Note: CPRFLAG and _UNICODE cases are currently mutually exclusive.
  1469.  */
  1470.  
  1471. /* prototypes */
  1472.  
  1473. #ifdef CPRFLAG
  1474.  
  1475. #define WRITE_CHAR(ch, pnw)             write_char(ch, pnw)
  1476. #define WRITE_MULTI_CHAR(ch, num, pnw)  write_multi_char(ch, num, pnw)
  1477. #define WRITE_STRING(s, len, pnw)       write_string(s, len, pnw)
  1478. #define WRITE_WSTRING(s, len, pnw)      write_wstring(s, len, pnw)
  1479.  
  1480. LOCAL(void) write_char(int ch, int *pnumwritten);
  1481. LOCAL(void) write_multi_char(int ch, int num, int *pnumwritten);
  1482. LOCAL(void) write_string(char *string, int len, int *numwritten);
  1483. LOCAL(void) write_wstring(wchar_t *string, int len, int *numwritten);
  1484.  
  1485. #elif defined (_UNICODE)
  1486.  
  1487. #define WRITE_CHAR(ch, pnw)             write_char(ch, stream, pnw)
  1488. #define WRITE_MULTI_CHAR(ch, num, pnw)  write_multi_char(ch, num, stream, pnw)
  1489. #define WRITE_STRING(s, len, pnw)       write_string(s, len, stream, pnw)
  1490.  
  1491. LOCAL(void) write_char(wchar_t ch, FILE *f, int *pnumwritten);
  1492. LOCAL(void) write_multi_char(wchar_t ch, int num, FILE *f, int *pnumwritten);
  1493. LOCAL(void) write_string(wchar_t *string, int len, FILE *f, int *numwritten);
  1494.  
  1495. #else  /* defined (_UNICODE) */
  1496.  
  1497. #define WRITE_CHAR(ch, pnw)             write_char(ch, stream, pnw)
  1498. #define WRITE_MULTI_CHAR(ch, num, pnw)  write_multi_char(ch, num, stream, pnw)
  1499. #define WRITE_STRING(s, len, pnw)       write_string(s, len, stream, pnw)
  1500. #define WRITE_WSTRING(s, len, pnw)      write_wstring(s, len, stream, pnw)
  1501.  
  1502. LOCAL(void) write_char(int ch, FILE *f, int *pnumwritten);
  1503. LOCAL(void) write_multi_char(int ch, int num, FILE *f, int *pnumwritten);
  1504. LOCAL(void) write_string(char *string, int len, FILE *f, int *numwritten);
  1505. LOCAL(void) write_wstring(wchar_t *string, int len, FILE *f, int *numwritten);
  1506.  
  1507. #endif  /* defined (_UNICODE) */
  1508.  
  1509. LOCAL(int) get_int_arg(va_list *pargptr);
  1510.  
  1511. LOCAL(short) get_short_arg(va_list *pargptr);
  1512.  
  1513. #if !LONG_IS_INT
  1514. LOCAL(long) get_long_arg(va_list *pargptr);
  1515. #endif  /* !LONG_IS_INT */
  1516.  
  1517. LOCAL(__int64) get_int64_arg(va_list *pargptr);
  1518.  
  1519. #ifdef _UNICODE
  1520. LOCAL(int) __cdecl _woutput(FILE *, const char *, va_list);
  1521. #endif  /* _UNICODE */
  1522.  
  1523. #ifdef CPRFLAG
  1524. LOCAL(int) output(const char *, va_list);
  1525.  
  1526. /***
  1527. *int _cprintf(format, arglist) - write formatted output directly to console
  1528. *
  1529. *Purpose:
  1530. *   Writes formatted data like printf, but uses console I/O functions.
  1531. *
  1532. *Entry:
  1533. *   char *format - format string to determine data formats
  1534. *   arglist - list of POINTERS to where to put data
  1535. *
  1536. *Exit:
  1537. *   returns number of characters written
  1538. *
  1539. *Exceptions:
  1540. *
  1541. *******************************************************************************/
  1542.  
  1543. int __cdecl _cprintf (
  1544.         const char * format,
  1545.         ...
  1546.         )
  1547. {
  1548.         va_list arglist;
  1549.  
  1550.         va_start(arglist, format);
  1551.  
  1552.         return output(format, arglist);
  1553. }
  1554.  
  1555. #endif  /* CPRFLAG */
  1556.  
  1557.  
  1558. /***
  1559. *int _output(stream, format, argptr), static int output(format, argptr)
  1560. *
  1561. *Purpose:
  1562. *   Output performs printf style output onto a stream.  It is called by
  1563. *   printf/fprintf/sprintf/vprintf/vfprintf/vsprintf to so the dirty
  1564. *   work.  In multi-thread situations, _output assumes that the given
  1565. *   stream is already locked.
  1566. *
  1567. *   Algorithm:
  1568. *       The format string is parsed by using a finite state automaton
  1569. *       based on the current state and the current character read from
  1570. *       the format string.  Thus, looping is on a per-character basis,
  1571. *       not a per conversion specifier basis.  Once the format specififying
  1572. *       character is read, output is performed.
  1573. *
  1574. *Entry:
  1575. *   FILE *stream   - stream for output
  1576. *   char *format   - printf style format string
  1577. *   va_list argptr - pointer to list of subsidiary arguments
  1578. *
  1579. *Exit:
  1580. *   Returns the number of characters written, or -1 if an output error
  1581. *   occurs.
  1582. *
  1583. *Exceptions:
  1584. *
  1585. *******************************************************************************/
  1586.  
  1587. #ifdef CPRFLAG
  1588. LOCAL(int) output (
  1589. #elif defined (_UNICODE)
  1590. LOCAL(int) _woutput (
  1591.     FILE *stream,
  1592. #else  /* defined (_UNICODE) */
  1593. int __cdecl _output (
  1594.     FILE *stream,
  1595. #endif  /* defined (_UNICODE) */
  1596.     const char *format,
  1597.     va_list argptr
  1598.     )
  1599. {
  1600.     int hexadd;         /* offset to add to number to get 'a'..'f' */
  1601.     char ch;            /* character just read */
  1602.     int flags;          /* flag word -- see #defines above for flag values */
  1603.     enum STATE state;   /* current state */
  1604.     enum CHARTYPE chclass; /* class of current character */
  1605.     int radix;          /* current conversion radix */
  1606.     int charsout;       /* characters currently written so far, -1 = IO error */
  1607.     int fldwidth;       /* selected field with -- 0 means default */
  1608.     int precision;      /* selected precision -- -1 means default */
  1609.     char prefix[2];     /* numeric prefix -- up to two characters */
  1610.     int prefixlen;      /* length of prefix -- 0 means no prefix */
  1611.     int capexp;         /* non-zero = 'E' exponent signifiet, zero = 'e' */
  1612.     int no_output;      /* non-zero = prodcue no output for this specifier */
  1613.     char *text;         /* pointer text to be printed, not zero terminated */
  1614.     int textlen;        /* length of the text in bytes to be printed */
  1615.     char buffer[BUFFERSIZE];    /* buffer for conversions */
  1616. #ifdef _UNICODE
  1617.     /* textlen is in multibyte or wide characters for _UNICODE versions */
  1618.     wchar_t wchar;      /* temp wchar_t */
  1619.     wchar_t *wchar_p;   /* temp wchar_t pointer */
  1620.     int bufferiswide;   /* non-zero = buffer contains wide chars already */
  1621. #endif  /* _UNICODE */
  1622.     int _tflag=0;
  1623.  
  1624.     charsout = 0;               /* no characters written yet */
  1625.     state = ST_NORMAL;          /* starting state */
  1626.  
  1627.     /* main loop -- loop while format character exist and no I/O errors */
  1628.     while ((ch = *format++) != '\0' && charsout >= 0) {
  1629.         chclass = find_char_class(ch);  /* find character class */
  1630.         state = find_next_state(chclass, state); /* find next state */
  1631.  
  1632.         /* execute code for each state */
  1633.         switch (state) {
  1634.  
  1635.         NORMAL_STATE:
  1636.  
  1637.         case ST_NORMAL:
  1638.             /* normal state -- just write character */
  1639. #ifndef _UNICODE
  1640.             if (isleadbyte((int)ch)) {
  1641.                 WRITE_CHAR(ch, &charsout);
  1642.                 ch = *format++;
  1643.                 _ASSERTE (ch != '0'); /* UNDONE: don't fall off format string */
  1644.             }
  1645.             WRITE_CHAR(ch, &charsout);
  1646. #else  /* _UNICODE */
  1647.             format += (mbtowc (&wchar, format-1, MB_CUR_MAX) - 1);
  1648.             /* UNDONE: check for mbtowc failure */
  1649.             WRITE_CHAR(wchar, &charsout);
  1650. #endif  /* _UNICODE */
  1651.             break;
  1652.  
  1653.         case ST_PERCENT:
  1654.             /* set default value of conversion parameters */
  1655.             prefixlen = fldwidth = no_output = capexp = 0;
  1656.             flags = 0;
  1657.             precision = -1;
  1658. #ifdef _UNICODE
  1659.             bufferiswide = 0;
  1660. #endif  /* _UNICODE */
  1661.             break;
  1662.  
  1663.         case ST_FLAG:
  1664.             /* set flag based on which flag character */
  1665.             switch (ch) {
  1666.             case '-':
  1667.                 flags |= FL_LEFT;       /* '-' => left justify */
  1668.                 break;
  1669.             case '+':
  1670.                 flags |= FL_SIGN;       /* '+' => force sign indicator */
  1671.                 break;
  1672.             case ' ':
  1673.                 flags |= FL_SIGNSP;     /* ' ' => force sign or space */
  1674.                 break;
  1675.             case '#':
  1676.                 flags |= FL_ALTERNATE;  /* '#' => alternate form */
  1677.                 break;
  1678.             case '0':
  1679.                 flags |= FL_LEADZERO;   /* '0' => pad with leading zeros */
  1680.                 break;
  1681.             }
  1682.             break;
  1683.  
  1684.         case ST_WIDTH:
  1685.             /* update width value */
  1686.             if (ch == '*') {
  1687.                 /* get width from arg list */
  1688.                 fldwidth = get_int_arg(&argptr);
  1689.                 if (fldwidth < 0) {
  1690.                     /* ANSI says neg fld width means '-' flag and pos width */
  1691.                     flags |= FL_LEFT;
  1692.                     fldwidth = -fldwidth;
  1693.                 }
  1694.             }
  1695.             else {
  1696.                 /* add digit to current field width */
  1697.                 fldwidth = fldwidth * 10 + (ch - '0');
  1698.             }
  1699.             break;
  1700.  
  1701.         case ST_DOT:
  1702.             /* zero the precision, since dot with no number means 0
  1703.                not default, according to ANSI */
  1704.             precision = 0;
  1705.             break;
  1706.  
  1707.         case ST_PRECIS:
  1708.             /* update precison value */
  1709.             if (ch == '*') {
  1710.                 /* get precision from arg list */
  1711.                 precision = get_int_arg(&argptr);
  1712.                 if (precision < 0)
  1713.                     precision = -1;     /* neg precision means default */
  1714.             }
  1715.             else {
  1716.                 /* add digit to current precision */
  1717.                 precision = precision * 10 + (ch - '0');
  1718.             }
  1719.             break;
  1720.  
  1721.         case ST_SIZE:
  1722.             /* just read a size specifier, set the flags based on it */
  1723.             switch (ch) {
  1724. #if !LONG_IS_INT
  1725.             case 'l':
  1726.                 flags |= FL_LONG;   /* 'l' => long int */
  1727.                 break;
  1728. #endif  /* !LONG_IS_INT */
  1729.  
  1730. #if !LONGDOUBLE_IS_DOUBLE
  1731.             case 'L':
  1732.                 flags |= FL_LONGDOUBLE; /* 'L' => long double */
  1733.                 break;
  1734. #endif  /* !LONGDOUBLE_IS_DOUBLE */
  1735.  
  1736.             case 'I':
  1737.                 /*
  1738.                  * In order to handle the I64 size modifier, we depart from
  1739.                  * the simple deterministic state machine. The code below
  1740.                  * scans
  1741.                  */
  1742.                 if ( (*format == '6') && (*(format + 1) == '4') ) {
  1743.                     format += 2;
  1744.                     flags |= FL_I64;    /* I64 => __int64 */
  1745.                 }
  1746.                 else {
  1747.                     state = ST_NORMAL;
  1748.                     goto NORMAL_STATE;
  1749.                 }
  1750.                 break;
  1751.  
  1752. #if !SHORT_IS_INT
  1753.             case 'h':
  1754.                 flags |= FL_SHORT;  /* 'h' => short int */
  1755.                 break;
  1756. #endif  /* !SHORT_IS_INT */
  1757.  
  1758.             }
  1759.             break;
  1760.  
  1761.         case ST_TYPE:
  1762.             /* we have finally read the actual type character, so we       */
  1763.             /* now format and "print" the output.  We use a big switch     */
  1764.             /* statement that sets 'text' to point to the text that should */
  1765.             /* be printed, and 'textlen' to the length of this text.       */
  1766.             /* Common code later on takes care of justifying it and        */
  1767.             /* other miscellaneous chores.  Note that cases share code,    */
  1768.             /* in particular, all integer formatting is doen in one place. */
  1769.             /* Look at those funky goto statements!                        */
  1770.  
  1771.             /*
  1772.              *  Generic string handling support:  %tc, %ts accept
  1773.              *  either chars or wide-chars depending on _tflag.
  1774.              *  _tflag == 1 means wide-chars.
  1775.              */
  1776.             if (ch == 't') {
  1777.                 if (_tflag == 1)
  1778.                     ch = 'w';
  1779.                 else {
  1780.                     ch = *format++;
  1781.                     _ASSERTE (ch!='0'); /* UNDONE: don't fall off format string */
  1782.                 }
  1783.             }
  1784.  
  1785.             switch (ch) {
  1786.  
  1787.             case 'c': {
  1788.                 /* print a single character specified by int argument */
  1789.                 buffer[0] = (char) get_int_arg(&argptr); /* get char to print */
  1790.                 text = buffer;
  1791.                 textlen = 1;        /* print just a single character */
  1792.             }
  1793.             break;
  1794.  
  1795.             case 's': {
  1796.                 /* print a string --                            */
  1797.                 /* ANSI rules on how much of string to print:   */
  1798.                 /*   all if precision is default,               */
  1799.                 /*   min(precision, length) if precision given. */
  1800.                 /* prints '(null)' if a null string is passed   */
  1801.  
  1802.                 int i;
  1803.                 char *p;       /* temps */
  1804.  
  1805.                 text = get_ptr_arg(&argptr);
  1806.                 if (text == NULL) {
  1807.                     /* null ptr passed, use special string */
  1808.                     text = nullstring;
  1809.                 }
  1810.  
  1811.                 /* At this point it is tempting to use strlen(), but */
  1812.                 /* if a precision is specified, we're not allowed to */
  1813.                 /* scan past there, because there might be no null   */
  1814.                 /* at all.  Thus, we must do our own scan.           */
  1815.  
  1816.                 i = (precision == -1) ? INT_MAX : precision;
  1817.  
  1818.                 p = text;
  1819.  
  1820.                 /* scan for null upto i characters */
  1821. #ifndef _UNICODE
  1822.                 while (i-- && *p)
  1823.                     ++p;
  1824.  
  1825.                 textlen = p - text;    /* length of the string */
  1826. #else  /* _UNICODE */
  1827.                 for (textlen=0; textlen<i && *p; textlen++) {
  1828.                     if (isleadbyte((int)*p))
  1829.                         ++p;
  1830.                     ++p;
  1831.                 }
  1832.                 /* textlen now contains length in multibyte chars */
  1833. #endif  /* _UNICODE */
  1834.             }
  1835.             break;
  1836.  
  1837.             case 'w': {
  1838.                 /* 'wc' print a wide character */
  1839.                 /* 'ws' print a wide string */
  1840.  
  1841. #ifdef _UNICODE
  1842.                 bufferiswide = 1;
  1843. #endif  /* _UNICODE */
  1844.                 ch = *format++;
  1845.                 _ASSERTE (ch!='0'); /* UNDONE: don't fall off format string */
  1846.                 switch (ch) {
  1847.  
  1848.                 /* 'wc' case */
  1849.                 case 'c': {
  1850. #ifndef _UNICODE
  1851.                     wchar_t temp;
  1852.                     temp = (wchar_t) get_short_arg(&argptr);
  1853.                     /* convert to multibyte characters */
  1854.                     textlen = wctomb(buffer, temp);
  1855.                     text = buffer;
  1856.  
  1857.                     /* check that conversion was successful */
  1858.                     if (textlen < 0)
  1859.                         no_output = 1;
  1860. #else  /* _UNICODE */
  1861.                     /* copy wide-char directly to buffer */
  1862.                     *(wchar_t *)buffer = (wchar_t) get_short_arg(&argptr);
  1863.                     textlen = 1; /* number of wide-chars */
  1864.                     text = buffer;
  1865. #endif  /* _UNICODE */
  1866.                 }
  1867.                 break;
  1868.  
  1869.                 /* 'ws' case */
  1870.                 case 's': {
  1871. #ifndef _UNICODE
  1872.                     int i;
  1873.  
  1874.                     text = get_ptr_arg(&argptr);
  1875.                     if (text == NULL) {
  1876.                         /*
  1877.                          * null ptr passed, use special string
  1878.                          */
  1879.                         text = nullstring;
  1880.                         textlen = strlen(nullstring);
  1881.                         /*
  1882.                          * if precision is specified (!= -1) use
  1883.                          * minimum of precision and textlen, else use textlen
  1884.                          */
  1885.                         textlen = (precision < 0) ? textlen :
  1886.                                 ((precision < textlen) ? precision : textlen);
  1887.                     } else {
  1888.                         /* convert to multibyte characters */
  1889.                         i = (precision < 0) ? BUFFERSIZE : precision;
  1890.                 textlen = (int) wcstombs(buffer, (wchar_t *)text, (size_t)i);
  1891.                         text = buffer;
  1892.  
  1893.                         if (flags & FL_ALTERNATE) {
  1894.                             /*
  1895.                              * Don't write more than precision wide chars
  1896.                              */
  1897.                             char *p;
  1898.                             p = text;
  1899.                             while (i-- && *p) {
  1900.                                 if (isleadbyte((int)*p))
  1901.                                         ++p;
  1902.                                 ++p;
  1903.                             }
  1904.                             textlen = p - text;    /* length of the string */
  1905.                         }
  1906.  
  1907.                         /* check that conversion was successful */
  1908.                         if (textlen < 0)
  1909.                             no_output = 1;
  1910.                     }
  1911. #else  /* _UNICODE */
  1912.                 int i;
  1913.                 wchar_t *p;       /* temps */
  1914.  
  1915.                 text = get_ptr_arg(&argptr);
  1916.                 if (text == NULL) {
  1917.                     /* null ptr passed, use special string */
  1918.                     text = (char *) wnullstring;
  1919.                 }
  1920.  
  1921.  
  1922.                 i = (precision == -1) ? INT_MAX : precision;
  1923.  
  1924.                 p = (wchar_t *) text;
  1925.  
  1926.                 /* scan for null up to i wide characters */
  1927.                 while (i-- && *p)
  1928.                     ++p;
  1929.  
  1930.                 textlen = p - (wchar_t *) text;    /* length in wide-chars */
  1931.  
  1932. #endif  /* _UNICODE */
  1933.                 }
  1934.                 break;
  1935.  
  1936.                 default:
  1937.                     /* error: unrecognized */
  1938.                     /* ANSI: undefined behavior */
  1939.                     no_output = 1;
  1940.  
  1941.                 } /* switch */
  1942.             } /* case 'w' */
  1943.             break;
  1944.  
  1945.             case 'n': {
  1946.                 /* write count of characters seen so far into */
  1947.                 /* short/int/long thru ptr read from args */
  1948.  
  1949.                 void *p;            /* temp */
  1950.  
  1951.                 p = get_ptr_arg(&argptr);
  1952.  
  1953.                 /* store chars out into short/long/int depending on flags */
  1954. #if !LONG_IS_INT
  1955.                 if (flags & FL_LONG)
  1956.                     *(long *)p = charsout;
  1957.                 else
  1958. #endif  /* !LONG_IS_INT */
  1959.  
  1960. #if !SHORT_IS_INT
  1961.                 if (flags & FL_SHORT)
  1962.                     *(short *)p = (short) charsout;
  1963.                 else
  1964. #endif  /* !SHORT_IS_INT */
  1965.                     *(int *)p = charsout;
  1966.  
  1967.                 no_output = 1;              /* force no output */
  1968.             }
  1969.             break;
  1970.  
  1971.  
  1972.             case 'E':
  1973.             case 'G':
  1974.                 capexp = 1;                 /* capitalize exponent */
  1975.                 ch += 'a' - 'A';            /* convert format char to lower */
  1976.                 /* DROP THROUGH */
  1977.             case 'e':
  1978.             case 'f':
  1979.             case 'g':   {
  1980.                 /* floating point conversion -- we call cfltcvt routines */
  1981.                 /* to do the work for us.                                */
  1982.                 flags |= FL_SIGNED;         /* floating point is signed conversion */
  1983.                 text = buffer;              /* put result in buffer */
  1984.  
  1985.                 /* compute the precision value */
  1986.                 if (precision < 0)
  1987.                     precision = 6;      /* default precision: 6 */
  1988.                 else if (precision == 0 && ch == 'g')
  1989.                     precision = 1;      /* ANSI specified */
  1990.  
  1991. #if !LONGDOUBLE_IS_DOUBLE
  1992.                 /* do the conversion */
  1993.                 if (flags & FL_LONGDOUBLE) {
  1994.                     _cldcvt((LONGDOUBLE*)argptr, text, ch, precision, capexp);
  1995.                     va_arg(argptr, LONGDOUBLE);
  1996.                 }
  1997.                 else
  1998. #endif  /* !LONGDOUBLE_IS_DOUBLE */
  1999.                 {
  2000.                     _cfltcvt((DOUBLE*)argptr, text, ch, precision, capexp);
  2001.                     va_arg(argptr, DOUBLE);
  2002.                 }
  2003.  
  2004.                 /* '#' and precision == 0 means force a decimal point */
  2005.                 if ((flags & FL_ALTERNATE) && precision == 0)
  2006.                     _forcdecpt(text);
  2007.  
  2008.                 /* 'g' format means crop zero unless '#' given */
  2009.                 if (ch == 'g' && !(flags & FL_ALTERNATE))
  2010.                     _cropzeros(text);
  2011.  
  2012.                 /* check if result was negative, save '-' for later */
  2013.                 /* and point to positive part (this is for '0' padding) */
  2014.                 if (*text == '-') {
  2015.                     flags |= FL_NEGATIVE;
  2016.                     ++text;
  2017.                 }
  2018.  
  2019.                 textlen = strlen(text);     /* compute length of text */
  2020.             }
  2021.             break;
  2022.  
  2023.             case 'd':
  2024.             case 'i':
  2025.                 /* signed decimal output */
  2026.                 flags |= FL_SIGNED;
  2027.                 radix = 10;
  2028.                 goto COMMON_INT;
  2029.  
  2030.             case 'u':
  2031.                 radix = 10;
  2032.                 goto COMMON_INT;
  2033.  
  2034.             case 'p':
  2035.                 /* write a pointer -- this is like an integer or long */
  2036.                 /* except we force precision to pad with zeros and */
  2037.                 /* output in big hex. */
  2038.  
  2039.                 precision = 2 * sizeof(void *);     /* number of hex digits needed */
  2040. #ifndef _MAC
  2041. #if !PTR_IS_INT
  2042.                 flags |= FL_LONG;       /* assume we're converting a long */
  2043. #endif  /* !PTR_IS_INT */
  2044. #else  /* _MAC */
  2045.                 flags &= ~FL_SHORT;     /* assume we're converting a long */
  2046.                 flags |= FL_LONG;       /* assume we're converting a long */
  2047. #endif  /* _MAC */
  2048.                 /* DROP THROUGH to hex formatting */
  2049.  
  2050.             case 'X':
  2051.                 /* unsigned upper hex output */
  2052.                 hexadd = 'A' - '9' - 1;     /* set hexadd for uppercase hex */
  2053.                 goto COMMON_HEX;
  2054.  
  2055.             case 'x':
  2056.                 /* unsigned lower hex output */
  2057.                 hexadd = 'a' - '9' - 1;     /* set hexadd for lowercase hex */
  2058.                 /* DROP THROUGH TO COMMON_HEX */
  2059.  
  2060.             COMMON_HEX:
  2061.                 radix = 16;
  2062.                 if (flags & FL_ALTERNATE) {
  2063.                     /* alternate form means '0x' prefix */
  2064.                     prefix[0] = '0';
  2065.                     prefix[1] = (char)('x' - 'a' + '9' + 1 + hexadd);   /* 'x' or 'X' */
  2066.                     prefixlen = 2;
  2067.                 }
  2068.                 goto COMMON_INT;
  2069.  
  2070.             case 'o':
  2071.                 /* unsigned octal output */
  2072.                 radix = 8;
  2073.                 if (flags & FL_ALTERNATE) {
  2074.                     /* alternate form means force a leading 0 */
  2075.                     flags |= FL_FORCEOCTAL;
  2076.                 }
  2077.                 /* DROP THROUGH to COMMON_INT */
  2078.  
  2079.             COMMON_INT: {
  2080.                 /* This is the general integer formatting routine. */
  2081.                 /* Basically, we get an argument, make it positive */
  2082.                 /* if necessary, and convert it according to the */
  2083.                 /* correct radix, setting text and textlen */
  2084.                 /* appropriately. */
  2085.  
  2086.                 unsigned __int64 number;    /* number to convert */
  2087.                 int digit;              /* ascii value of digit */
  2088.                 __int64 l;              /* temp long value */
  2089.  
  2090.                 /* 1. read argument into l, sign extend as needed */
  2091.  
  2092.                 if (flags & FL_I64)
  2093.                     l = get_int64_arg(&argptr);
  2094.                 else
  2095.  
  2096. #if !LONG_IS_INT
  2097.                 if (flags & FL_LONG)
  2098.                     l = get_long_arg(&argptr);
  2099.                 else
  2100. #endif  /* !LONG_IS_INT */
  2101.  
  2102. #if !SHORT_IS_INT
  2103.                 if (flags & FL_SHORT) {
  2104.                     if (flags & FL_SIGNED)
  2105.                         l = (short) get_int_arg(&argptr); /* sign extend */
  2106.                     else
  2107.                         l = (unsigned short) get_int_arg(&argptr);    /* zero-extend*/
  2108.                 }
  2109.                 else
  2110. #endif  /* !SHORT_IS_INT */
  2111.                 {
  2112.                     if (flags & FL_SIGNED)
  2113.                         l = get_int_arg(&argptr); /* sign extend */
  2114.                     else
  2115.                         l = (unsigned int) get_int_arg(&argptr);    /* zero-extend*/
  2116.                 }
  2117.  
  2118.                 /* 2. check for negative; copy into number */
  2119.                 if ( (flags & FL_SIGNED) && l < 0) {
  2120.                     number = -l;
  2121.                     flags |= FL_NEGATIVE;   /* remember negative sign */
  2122.                 }
  2123.                 else {
  2124.                     number = l;
  2125.                 }
  2126.  
  2127.                 /* 3. check precision value for default; non-default */
  2128.                 /*    turns off 0 flag, according to ANSI. */
  2129.                 if (precision < 0)
  2130.                     precision = 1;              /* default precision */
  2131.                 else
  2132.                     flags &= ~FL_LEADZERO;
  2133.  
  2134.                 /* 4. Check if data is 0; if so, turn off hex prefix */
  2135.                 if (number == 0)
  2136.                     prefixlen = 0;
  2137.  
  2138.                 /* 5. Convert data to ASCII -- note if precision is zero */
  2139.                 /*    and number is zero, we get no digits at all.       */
  2140.  
  2141.                 text = &buffer[BUFFERSIZE-1];      /* last digit at end of buffer */
  2142.  
  2143.                 while (precision-- > 0 || number != 0) {
  2144.                     digit = (int)(number % radix) + '0';
  2145.                     number /= radix;            /* reduce number */
  2146.                     if (digit > '9') {
  2147.                         /* a hex digit, make it a letter */
  2148.                         digit += hexadd;
  2149.                     }
  2150.                     *text-- = (char)digit;      /* store the digit */
  2151.                 }
  2152.  
  2153.                 textlen = (char *)&buffer[BUFFERSIZE-1] - text; /* compute length of number */
  2154.                 ++text;         /* text points to first digit now */
  2155.  
  2156.  
  2157.                 /* 6. Force a leading zero if FORCEOCTAL flag set */
  2158.                 if ((flags & FL_FORCEOCTAL) && (text[0] != '0' || textlen == 0)) {
  2159.                     *--text = '0';
  2160.                     ++textlen;          /* add a zero */
  2161.                 }
  2162.             }
  2163.             break;
  2164.             }
  2165.  
  2166.             /* At this point, we have done the specific conversion, and */
  2167.             /* 'text' points to text to print; 'textlen' is length.  Now we */
  2168.             /* justify it, put on prefixes, leading zeros, and then */
  2169.             /* print it. */
  2170.  
  2171.             if (!no_output) {
  2172.                 int padding;    /* amount of padding, negative means zero */
  2173.  
  2174.                 if (flags & FL_SIGNED) {
  2175.                     if (flags & FL_NEGATIVE) {
  2176.                         /* prefix is a '-' */
  2177.                         prefix[0] = '-';
  2178.                         prefixlen = 1;
  2179.                     }
  2180.                     else if (flags & FL_SIGN) {
  2181.                         /* prefix is '+' */
  2182.                         prefix[0] = '+';
  2183.                         prefixlen = 1;
  2184.                     }
  2185.                     else if (flags & FL_SIGNSP) {
  2186.                         /* prefix is ' ' */
  2187.                         prefix[0] = ' ';
  2188.                         prefixlen = 1;
  2189.                     }
  2190.                 }
  2191.  
  2192.                 /* calculate amount of padding -- might be negative, */
  2193.                 /* but this will just mean zero */
  2194.                 padding = fldwidth - textlen - prefixlen;
  2195.  
  2196.                 /* put out the padding, prefix, and text, in the correct order */
  2197.  
  2198.                 if (!(flags & (FL_LEFT | FL_LEADZERO))) {
  2199.                     /* pad on left with blanks */
  2200.                     WRITE_MULTI_CHAR(_T(' '), padding, &charsout);
  2201.                 }
  2202.  
  2203.                 /* write prefix */
  2204. #ifndef _UNICODE
  2205.                 WRITE_STRING(prefix, prefixlen, &charsout);
  2206. #else  /* _UNICODE */
  2207.                 if (prefixlen > 0) {
  2208.                     wchar_p = (wchar_t *)_malloc_crt (prefixlen * sizeof(wchar_t));
  2209.                     if (wchar_p == NULL) {
  2210.                         charsout = -1;
  2211.                         break;
  2212.                     }
  2213.                     /* assume prefix string is single-byte characters */
  2214.                     mbstowcs (wchar_p, prefix, prefixlen);
  2215.                     /* UNDONE: check for mbstowcs failure */
  2216.                     WRITE_STRING(wchar_p, prefixlen, &charsout);
  2217.                     _free_crt (wchar_p);
  2218.                 }
  2219. #endif  /* _UNICODE */
  2220.  
  2221.                 if ((flags & FL_LEADZERO) && !(flags & FL_LEFT)) {
  2222.                     /* write leading zeros */
  2223.                     WRITE_MULTI_CHAR(_T('0'), padding, &charsout);
  2224.                 }
  2225.  
  2226.                 /* write text */
  2227. #ifndef _UNICODE
  2228.                 WRITE_STRING(text, textlen, &charsout);
  2229. #else  /* _UNICODE */
  2230.                 if (!bufferiswide && textlen > 0) {
  2231.                     wchar_p = (wchar_t *)_malloc_crt (textlen * sizeof(wchar_t));
  2232.                     if (wchar_p == NULL) {
  2233.                         charsout = -1;
  2234.                         break;
  2235.                     }
  2236.                     mbstowcs (wchar_p, text, textlen);
  2237.                     /* UNDONE: check for mbstowcs failure */
  2238.                     WRITE_STRING(wchar_p, textlen, &charsout);
  2239.                     _free_crt (wchar_p);
  2240.                 } else {
  2241.                     WRITE_STRING((wchar_t *)text, textlen, &charsout);
  2242.                 }
  2243. #endif  /* _UNICODE */
  2244.  
  2245.                 if (flags & FL_LEFT) {
  2246.                     /* pad on right with blanks */
  2247.                     WRITE_MULTI_CHAR(_T(' '), padding, &charsout);
  2248.                 }
  2249.  
  2250.                 /* we're done! */
  2251.             }
  2252.             break;
  2253.         }
  2254.     }
  2255.  
  2256.     return charsout;        /* return value = number of characters written */
  2257. }
  2258.  
  2259. /*
  2260.  *  Future Optimizations for wsprintf:
  2261.  *  - Prefix is always 1 or 2 characters.  Make this memory static rather
  2262.  *    than malloc'ed.
  2263.  *  - Don't free the memory used for converting the buffer to wide chars.
  2264.  *    Use realloc if the memory is not sufficient.  Free it at the end.
  2265.  *  - Printing wide-character literal char format strings may be common.
  2266.  *    This may be optimized by performing a single mbstowcs rather than
  2267.  *    many mbtowc (i.e. look ahead in format string until hit a %, then
  2268.  *    write it all out).
  2269.  */
  2270.  
  2271. /***
  2272. *void write_char(int ch, int *pnumwritten)
  2273. *void write_char(int ch, FILE *f, int *pnumwritten)
  2274. *
  2275. *Purpose:
  2276. *   Writes a single character to the given file/console.  If no error occurs,
  2277. *   then *pnumwritten is incremented; otherwise, *pnumwritten is set
  2278. *   to -1.
  2279. *
  2280. *Entry:
  2281. *   int ch           - character to write
  2282. *   FILE *f          - file to write to
  2283. *   int *pnumwritten - pointer to integer to update with total chars written
  2284. *
  2285. *Exit:
  2286. *   No return value.
  2287. *
  2288. *Exceptions:
  2289. *
  2290. *******************************************************************************/
  2291.  
  2292. #ifdef CPRFLAG
  2293.  
  2294. LOCAL(void) write_char (
  2295.     int ch,
  2296.     int *pnumwritten
  2297.     )
  2298. {
  2299.     if (_putch_lk(ch) == EOF)
  2300.         *pnumwritten = -1;
  2301.     else
  2302.         ++(*pnumwritten);
  2303. }
  2304.  
  2305. #elif defined (_UNICODE)
  2306.  
  2307. LOCAL(void) write_char (
  2308.     wchar_t ch,
  2309.     FILE *f,
  2310.     int *pnumwritten
  2311.     )
  2312. {
  2313.     /* following code is machine dependent */
  2314.     _putc_lk((int)(ch & 0xff), f);
  2315.     if (_putc_lk((int)(ch >> 8), f) == EOF)
  2316.         *pnumwritten = -1;
  2317.     else
  2318.         ++(*pnumwritten);
  2319. }
  2320.  
  2321. #else  /* defined (_UNICODE) */
  2322.  
  2323. LOCAL(void) write_char (
  2324.     int ch,
  2325.     FILE *f,
  2326.     int *pnumwritten
  2327.     )
  2328. {
  2329.     if (_putc_lk(ch, f) == EOF)
  2330.         *pnumwritten = -1;
  2331.     else
  2332.         ++(*pnumwritten);
  2333. }
  2334.  
  2335. #endif  /* defined (_UNICODE) */
  2336.  
  2337. /***
  2338. *void write_multi_char(int ch, int num, int *pnumwritten)
  2339. *void write_multi_char(int ch, int num, FILE *f, int *pnumwritten)
  2340. *
  2341. *Purpose:
  2342. *   Writes num copies of a character to the given file/console.  If no error occurs,
  2343. *   then *pnumwritten is incremented by num; otherwise, *pnumwritten is set
  2344. *   to -1.  If num is negative, it is treated as zero.
  2345. *
  2346. *Entry:
  2347. *   int ch           - character to write
  2348. *   int num          - number of times to write the characters
  2349. *   FILE *f          - file to write to
  2350. *   int *pnumwritten - pointer to integer to update with total chars written
  2351. *
  2352. *Exit:
  2353. *   No return value.
  2354. *
  2355. *Exceptions:
  2356. *
  2357. *******************************************************************************/
  2358.  
  2359. #ifdef CPRFLAG
  2360.  
  2361. LOCAL(void) write_multi_char (
  2362.     int ch,
  2363.     int num,
  2364.     int *pnumwritten
  2365.     )
  2366. {
  2367.     while (num-- > 0)
  2368.         write_char(ch, pnumwritten);
  2369. }
  2370.  
  2371. #elif defined (_UNICODE)
  2372.  
  2373. LOCAL(void) write_multi_char (
  2374.     wchar_t ch,
  2375.     int num,
  2376.     FILE *f,
  2377.     int *pnumwritten
  2378.     )
  2379. {
  2380.     while (num-- > 0)
  2381.         write_char(ch, f, pnumwritten);
  2382. }
  2383.  
  2384. #else  /* defined (_UNICODE) */
  2385.  
  2386. LOCAL(void) write_multi_char (
  2387.     int ch,
  2388.     int num,
  2389.     FILE *f,
  2390.     int *pnumwritten
  2391.     )
  2392. {
  2393.     while (num-- > 0)
  2394.         write_char(ch, f, pnumwritten);
  2395. }
  2396.  
  2397. #endif  /* defined (_UNICODE) */
  2398.  
  2399. /***
  2400. *void write_string(char *string, int len, int *pnumwritten)
  2401. *void write_string(char *string, int len, FILE *f, int *pnumwritten)
  2402. *void write_wstring(wchar_t *string, int len, int *pnumwritten)
  2403. *void write_wstring(wchar_t *string, int len, FILE *f, int *pnumwritten)
  2404. *
  2405. *Purpose:
  2406. *   Writes a string of the given length to the given file.  If no error occurs,
  2407. *   then *pnumwritten is incremented by len; otherwise, *pnumwritten is set
  2408. *   to -1.  If len is negative, it is treated as zero.
  2409. *
  2410. *Entry:
  2411. *   char *string     - string to write (NOT null-terminated)
  2412. *   int len          - length of string
  2413. *   FILE *f          - file to write to
  2414. *   int *pnumwritten - pointer to integer to update with total chars written
  2415. *
  2416. *Exit:
  2417. *   No return value.
  2418. *
  2419. *Exceptions:
  2420. *
  2421. *******************************************************************************/
  2422.  
  2423. #ifdef CPRFLAG
  2424.  
  2425. LOCAL(void) write_string (
  2426.     char *string,
  2427.     int len,
  2428.     int *pnumwritten
  2429.     )
  2430. {
  2431.     while (len-- > 0)
  2432.         write_char(*string++, pnumwritten);
  2433. }
  2434.  
  2435. #elif defined (_UNICODE)
  2436.  
  2437. LOCAL(void) write_string (
  2438.     wchar_t *string,
  2439.     int len,
  2440.     FILE *f,
  2441.     int *pnumwritten
  2442.     )
  2443. {
  2444.     while (len-- > 0)
  2445.         write_char(*string++, f, pnumwritten);
  2446. }
  2447.  
  2448. #else  /* defined (_UNICODE) */
  2449.  
  2450. LOCAL(void) write_string (
  2451.     char *string,
  2452.     int len,
  2453.     FILE *f,
  2454.     int *pnumwritten
  2455.     )
  2456. {
  2457.     while (len-- > 0)
  2458.         write_char(*string++, f, pnumwritten);
  2459. }
  2460.  
  2461. #endif  /* defined (_UNICODE) */
  2462.  
  2463. /***
  2464. *int get_int_arg(va_list *pargptr)
  2465. *
  2466. *Purpose:
  2467. *   Gets an int argument off the given argument list and updates *pargptr.
  2468. *
  2469. *Entry:
  2470. *   va_list *pargptr - pointer to argument list; updated by function
  2471. *
  2472. *Exit:
  2473. *   Returns the integer argument read from the argument list.
  2474. *
  2475. *Exceptions:
  2476. *
  2477. *******************************************************************************/
  2478.  
  2479. LOCAL(int) get_int_arg (
  2480.     va_list *pargptr
  2481.     )
  2482. {
  2483.     return va_arg(*pargptr, int);
  2484. }
  2485.  
  2486. /***
  2487. *long get_long_arg(va_list *pargptr)
  2488. *
  2489. *Purpose:
  2490. *   Gets an long argument off the given argument list and updates *pargptr.
  2491. *
  2492. *Entry:
  2493. *   va_list *pargptr - pointer to argument list; updated by function
  2494. *
  2495. *Exit:
  2496. *   Returns the long argument read from the argument list.
  2497. *
  2498. *Exceptions:
  2499. *
  2500. *******************************************************************************/
  2501.  
  2502.  
  2503. #if !LONG_IS_INT
  2504. LOCAL(long) get_long_arg (
  2505.     va_list *pargptr
  2506.     )
  2507. {
  2508.     return va_arg(*pargptr, long);
  2509. }
  2510. #endif  /* !LONG_IS_INT */
  2511.  
  2512. /***
  2513. *__int64 get_int86_arg(va_list *pargptr)
  2514. *
  2515. *Purpose:
  2516. *   Gets an __int64 short argument off the given argument list and updates *pargptr.
  2517. *
  2518. *Entry:
  2519. *   va_list *pargptr - pointer to argument list; updated by function
  2520. *
  2521. *Exit:
  2522. *   Returns the __int64 argument read from the argument list.
  2523. *
  2524. *Exceptions:
  2525. *
  2526. *******************************************************************************/
  2527.  
  2528. LOCAL(__int64) get_int64_arg (
  2529.     va_list *pargptr
  2530.     )
  2531. {
  2532.       double    dblTemp;
  2533.  
  2534.       dblTemp = va_arg(*pargptr, double);
  2535.           return *(__int64 *)&dblTemp;
  2536.  
  2537. //    return va_arg(*pargptr, __int64);
  2538. }
  2539.  
  2540. /***
  2541. *short get_short_arg(va_list *pargptr)
  2542. *
  2543. *Purpose:
  2544. *   Gets a short argument off the given argument list and updates *pargptr.
  2545. *   *** CURRENTLY ONLY USED TO GET A WCHAR_T, IFDEF _INTL ***
  2546. *
  2547. *Entry:
  2548. *   va_list *pargptr - pointer to argument list; updated by function
  2549. *
  2550. *Exit:
  2551. *   Returns the short argument read from the argument list.
  2552. *
  2553. *Exceptions:
  2554. *
  2555. *******************************************************************************/
  2556.  
  2557. LOCAL(short) get_short_arg (
  2558.     va_list *pargptr
  2559.     )
  2560. {
  2561.     return va_arg(*pargptr, short);
  2562. }
  2563.  
  2564.  
  2565. #endif  /* defined (_M_MPPC) || defined (_M_M68K) */
  2566.  
  2567. #endif  /* _WIN32 */
  2568.