Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1001 lines
35 KiB

  1. /***
  2. *output.c - printf style output to a struct w4io
  3. *
  4. * Copyright (c) 1989-1991, 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, we
  11. * also try to be efficient. We do assume that pointers are the same size
  12. * as either ints or longs.
  13. *
  14. *Revision History:
  15. * 06-01-89 PHG Module created
  16. * 08-28-89 JCR Added cast to get rid of warning (no object changes)
  17. * 02-15-90 GJF Fixed copyright
  18. * 10-03-90 WHB Defined LOCAL(x) to "static x" for local procedures
  19. * 06-05-95 SVA Added support for printing GUIDs.
  20. *
  21. *******************************************************************************/
  22. #include <stdlib.h>
  23. #include <limits.h>
  24. #include <string.h>
  25. #include <stdarg.h>
  26. #include <basetsd.h>
  27. #include "wchar.h"
  28. #include "w4io.h"
  29. /* this macro defines a function which is private and as fast as possible: */
  30. /* for example, in C 6.0, it might be static _fastcall <type>. */
  31. #define LOCAL(x) static x // 100390--WHB
  32. #define NOFLOATS // Win 4 doesn't need floating point
  33. /* int/long/short/pointer sizes */
  34. /* the following should be set depending on the sizes of various types */
  35. // FLAT or LARGE model is assumed
  36. #ifdef FLAT
  37. # define LONG_IS_INT 1 /* 1 means long is same size as int */
  38. # define SHORT_IS_INT 0 /* 1 means short is same size as int */
  39. #ifdef _WIN64
  40. # define PTR_IS_INT 0 /* 1 means ptr is same size as int */
  41. #else // !_WIN64
  42. # define PTR_IS_INT 1 /* 1 means ptr is same size as int */
  43. #endif // !_WIN64
  44. # define PTR_IS_LONG 0 /* 1 means ptr is same size as long */
  45. #else // LARGE model
  46. # define LONG_IS_INT 0 /* 1 means long is same size as int */
  47. # define SHORT_IS_INT 1 /* 1 means short is same size as int */
  48. # define PTR_IS_INT 0 /* 1 means ptr is same size as int */
  49. # define PTR_IS_LONG 1 /* 1 means ptr is same size as long */
  50. #endif
  51. #define LONGDOUBLE_IS_DOUBLE 0 /* 1 means long double is same as double */
  52. #if LONG_IS_INT
  53. #define get_long_arg(x) (long)get_int_arg(x)
  54. #endif
  55. #if PTR_IS_INT
  56. #define get_ptr_arg(x) (void *)get_int_arg(x)
  57. #elif PTR_IS_LONG
  58. #define get_ptr_arg(x) (void *)get_long_arg(x)
  59. #elif _WIN64
  60. #define get_ptr_arg(x) (void *)get_int64_arg(x)
  61. #else
  62. #error Size of pointer must be same as size of int or long
  63. #endif
  64. #ifndef NOFLOATS
  65. /* These are "fake" double and long doubles to fool the compiler,
  66. so we don't drag in floating point. */
  67. typedef struct {
  68. char x[sizeof(double)];
  69. } DOUBLE;
  70. typedef struct {
  71. char x[sizeof(long double)];
  72. } LONGDOUBLE;
  73. #endif
  74. /* CONSTANTS */
  75. //#define BUFFERSIZE CVTBUFSIZE /* buffer size for maximum double conv */
  76. #define BUFFERSIZE 20
  77. /* flag definitions */
  78. #define FL_SIGN 0x0001 /* put plus or minus in front */
  79. #define FL_SIGNSP 0x0002 /* put space or minus in front */
  80. #define FL_LEFT 0x0004 /* left justify */
  81. #define FL_LEADZERO 0x0008 /* pad with leading zeros */
  82. #define FL_LONG 0x0010 /* long value given */
  83. #define FL_SHORT 0x0020 /* short value given */
  84. #define FL_SIGNED 0x0040 /* signed data given */
  85. #define FL_ALTERNATE 0x0080 /* alternate form requested */
  86. #define FL_NEGATIVE 0x0100 /* value is negative */
  87. #define FL_FORCEOCTAL 0x0200 /* force leading '0' for octals */
  88. #define FL_LONGDOUBLE 0x0400 /* long double value given */
  89. #define FL_WIDE 0x0800 /* wide character/string given */
  90. #define FL_PTR64 0x1000 /* wide character/string given */
  91. #ifdef _WIN64
  92. #define FL_PTR FL_PTR64
  93. #else // !_WIN64
  94. #define FL_PTR FL_LONG /* as the processing specified originally... */
  95. #endif // !_WIN64
  96. /* state definitions */
  97. enum STATE {
  98. ST_NORMAL, /* normal state; outputting literal chars */
  99. ST_PERCENT, /* just read '%' */
  100. ST_FLAG, /* just read flag character */
  101. ST_WIDTH, /* just read width specifier */
  102. ST_DOT, /* just read '.' */
  103. ST_PRECIS, /* just read precision specifier */
  104. ST_SIZE, /* just read size specifier */
  105. ST_TYPE /* just read type specifier */
  106. };
  107. #define NUMSTATES (ST_TYPE + 1)
  108. /* character type values */
  109. enum CHARTYPE {
  110. CH_OTHER, /* character with no special meaning */
  111. CH_PERCENT, /* '%' */
  112. CH_DOT, /* '.' */
  113. CH_STAR, /* '*' */
  114. CH_ZERO, /* '0' */
  115. CH_DIGIT, /* '1'..'9' */
  116. CH_FLAG, /* ' ', '+', '-', '#' */
  117. CH_SIZE, /* 'h', 'l', 'L', 'N', 'F' */
  118. CH_TYPE /* type specifying character */
  119. };
  120. /* static data (read only, since we are re-entrant) */
  121. char *nullstring = "(null)"; /* string to print on null ptr */
  122. /* The state table. This table is actually two tables combined into one. */
  123. /* The lower nybble of each byte gives the character class of any */
  124. /* character; while the uper nybble of the byte gives the next state */
  125. /* to enter. See the macros below the table for details. */
  126. /* */
  127. /* The table is generated by maketab.c -- use the maketab program to make */
  128. /* changes. */
  129. /* Brief description of the table, since I can't find maketab.c - t-stevan */
  130. /* Each entry in form 0xYZ. Here Z is a character class used in the macro */
  131. /* find_char_class defined below. The character classes are defined in the */
  132. /* CHARTYPE enum. For example, 'I' maps to CH_TYPE. To find a particular entry */
  133. /* Subtract the ASCI value for the space char from the character, and that is */
  134. /* the index to look up. The Y value is holds state transition information. */
  135. /* It is used in the macro find_next_state. */
  136. static char lookuptable[] = {
  137. 0x06, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00,
  138. 0x10, 0x00, 0x03, 0x06, 0x00, 0x06, 0x02, 0x10,
  139. 0x04, 0x45, 0x45, 0x45, 0x05, 0x05, 0x05, 0x05,
  140. 0x05, 0x35, 0x30, 0x00, 0x50, 0x00, 0x00, 0x00,
  141. 0x00, 0x20, 0x28, 0x38, 0x50, 0x58, 0x07, 0x08,
  142. 0x00, 0x38, 0x30, 0x30, 0x57, 0x50, 0x07, 0x00,
  143. 0x00, 0x20, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00,
  144. 0x08, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
  145. 0x00, 0x70, 0x70, 0x78, 0x78, 0x78, 0x78, 0x08,
  146. 0x07, 0x08, 0x00, 0x00, 0x07, 0x00, 0x08, 0x08,
  147. 0x08, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x07,
  148. 0x08
  149. };
  150. #define find_char_class(c) \
  151. ((c) < ' ' || (c) > 'x' ? \
  152. CH_OTHER \
  153. : \
  154. lookuptable[(c)-' '] & 0xF)
  155. #define find_next_state(class, state) \
  156. (lookuptable[(class) * NUMSTATES + (state)] >> 4)
  157. #ifdef _WIN64
  158. LOCAL(__int64) get_int64_arg(va_list *pargptr);
  159. #endif
  160. #if !LONG_IS_INT
  161. LOCAL(long) get_long_arg(va_list *pargptr);
  162. #endif
  163. LOCAL(int) get_int_arg(va_list *pargptr);
  164. LOCAL(void) writestring(char *string,
  165. int len,
  166. struct w4io *f,
  167. int *pcchwritten,
  168. int fwide);
  169. #ifndef NOFLOATS
  170. /* extern float convert routines */
  171. typedef int (* PFI)();
  172. extern PFI _cfltcvt_tab[5];
  173. #define _cfltcvt(a,b,c,d,e) (*_cfltcvt_tab[0])(a,b,c,d,e)
  174. #define _cropzeros(a) (*_cfltcvt_tab[1])(a)
  175. #define _fassign(a,b,c) (*_cfltcvt_tab[2])(a,b,c)
  176. #define _forcdecpt(a) (*_cfltcvt_tab[3])(a)
  177. #define _positive(a) (*_cfltcvt_tab[4])(a)
  178. #define _cldcvt(a,b,c,d,e) (*_cfltcvt_tab[5])(a,b,c,d,e)
  179. #endif
  180. /* Defines for printing out GUIDs */
  181. #ifndef GUID_DEFINED
  182. #define GUID_DEFINED
  183. /* size is 16 */
  184. typedef struct _GUID
  185. {
  186. unsigned long Data1;
  187. unsigned short Data2;
  188. unsigned short Data3;
  189. unsigned char Data4[ 8 ];
  190. } GUID;
  191. #endif // !GUID_DEFINED
  192. #ifndef _REFGUID_DEFINED
  193. #define _REFGUID_DEFINED
  194. #define REFGUID const GUID * const
  195. #endif // !_REFGUID_DEFINED
  196. /* This is actually one less than the normal GUIDSTR_MAX */
  197. /* Because we don't tag on a NULL byte */
  198. #define GUIDSTR_MAX (1+ 8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1 /* + 1 */)
  199. /* Make sure our buffer size is big enough to hold a GUID */
  200. #if BUFFERSIZE < GUIDSTR_MAX
  201. #undef BUFFERSIZE
  202. #define BUFFERSIZE GUIDSTR_MAX
  203. #endif
  204. /* Function used to write a GUID to a string */
  205. int StrFromGUID(REFGUID rguid, char * lpsz, int cbMax);
  206. /***
  207. *int w4iooutput(f, format, argptr)
  208. *
  209. *Purpose:
  210. * Output performs printf style output onto a stream. It is called by
  211. * printf/fprintf/sprintf/vprintf/vfprintf/vsprintf to so the dirty
  212. * work. In multi-thread situations, w4iooutput assumes that the given
  213. * stream is already locked.
  214. *
  215. * Algorithm:
  216. * The format string is parsed by using a finite state automaton
  217. * based on the current state and the current character read from
  218. * the format string. Thus, looping is on a per-character basis,
  219. * not a per conversion specifier basis. Once the format specififying
  220. * character is read, output is performed.
  221. *
  222. *Entry:
  223. * struct w4io *f - stream for output
  224. * char *format - printf style format string
  225. * va_list argptr - pointer to list of subsidiary arguments
  226. *
  227. *Exit:
  228. * Returns the number of characters written, or -1 if an output error
  229. * occurs.
  230. *
  231. *Exceptions:
  232. *
  233. *Notes:
  234. * FIXFIX - This code does not handle I64 for __int64 and derived types.
  235. * FIXFIX - This code does not handle I64 10byte floats.
  236. * FIXFIX - This code has to be tested for IA64 8byte floats.
  237. *
  238. *******************************************************************************/
  239. int _cdecl w4iooutput(struct w4io *f, const char *format, va_list argptr)
  240. {
  241. int hexadd; /* offset to add to number to get 'a'..'f' */
  242. char ch; /* character just read */
  243. wchar_t wc; /* wide character temp */
  244. wchar_t *pwc; /* wide character temp pointer */
  245. int flags; /* flag word -- see #defines above for flag values */
  246. enum STATE state; /* current state */
  247. enum CHARTYPE chclass; /* class of current character */
  248. int radix; /* current conversion radix */
  249. int charsout; /* characters currently written so far, -1 = IO error */
  250. int fldwidth; /* selected field with -- 0 means default */
  251. int fwide;
  252. int precision = -1; /* selected precision -- -1 means default */
  253. char prefix[2]; /* numeric prefix -- up to two characters */
  254. int prefixlen; /* length of prefix -- 0 means no prefix */
  255. int capexp; /* non-zero = 'E' exponent signifiet, zero = 'e' */
  256. int no_output; /* non-zero = prodcue no output for this specifier */
  257. char *text; /* pointer text to be printed, not zero terminated */
  258. int textlen; /* length of the text to be printed */
  259. char buffer[BUFFERSIZE]; /* buffer for conversions */
  260. charsout = 0; /* no characters written yet */
  261. state = ST_NORMAL; /* starting state */
  262. /* main loop -- loop while format character exist and no I/O errors */
  263. while ((ch = *format++) != '\0' && charsout >= 0) {
  264. chclass = find_char_class(ch); /* find character class */
  265. state = find_next_state(chclass, state); /* find next state */
  266. /* execute code for each state */
  267. switch (state) {
  268. case ST_NORMAL:
  269. /* normal state -- just write character */
  270. f->writechar(ch, 1, f, &charsout);
  271. break;
  272. case ST_PERCENT:
  273. /* set default value of conversion parameters */
  274. prefixlen = fldwidth = no_output = capexp = 0;
  275. flags = 0;
  276. precision = -1;
  277. fwide = 0;
  278. break;
  279. case ST_FLAG:
  280. /* set flag based on which flag character */
  281. switch (ch) {
  282. case '-':
  283. flags |= FL_LEFT; /* '-' => left justify */
  284. break;
  285. case '+':
  286. flags |= FL_SIGN; /* '+' => force sign indicator */
  287. break;
  288. case ' ':
  289. flags |= FL_SIGNSP; /* ' ' => force sign or space */
  290. break;
  291. case '#':
  292. flags |= FL_ALTERNATE; /* '#' => alternate form */
  293. break;
  294. case '0':
  295. flags |= FL_LEADZERO; /* '0' => pad with leading zeros */
  296. break;
  297. }
  298. break;
  299. case ST_WIDTH:
  300. /* update width value */
  301. if (ch == '*') {
  302. /* get width from arg list */
  303. fldwidth = get_int_arg(&argptr);
  304. if (fldwidth < 0) {
  305. /* ANSI says neg fld width means '-' flag and pos width */
  306. flags |= FL_LEFT;
  307. fldwidth = -fldwidth;
  308. }
  309. }
  310. else {
  311. /* add digit to current field width */
  312. fldwidth = fldwidth * 10 + (ch - '0');
  313. }
  314. break;
  315. case ST_DOT:
  316. /* zero the precision, since dot with no number means 0
  317. not default, according to ANSI */
  318. precision = 0;
  319. break;
  320. case ST_PRECIS:
  321. /* update precison value */
  322. if (ch == '*') {
  323. /* get precision from arg list */
  324. precision = get_int_arg(&argptr);
  325. if (precision < 0)
  326. precision = -1; /* neg precision means default */
  327. }
  328. else {
  329. /* add digit to current precision */
  330. precision = precision * 10 + (ch - '0');
  331. }
  332. break;
  333. case ST_SIZE:
  334. /* just read a size specifier, set the flags based on it */
  335. switch (ch) {
  336. #if !LONG_IS_INT
  337. case 'l':
  338. flags |= FL_LONG; /* 'l' => long int */
  339. break;
  340. #endif
  341. #if !LONGDOUBLE_IS_DOUBLE
  342. case 'L':
  343. flags |= FL_LONGDOUBLE; /* 'L' => long double */
  344. break;
  345. #endif
  346. #if !SHORT_IS_INT
  347. case 'h':
  348. flags |= FL_SHORT; /* 'h' => short int */
  349. break;
  350. #endif
  351. case 'w':
  352. flags |= FL_WIDE; /* 'w' => wide character */
  353. break;
  354. }
  355. break;
  356. case ST_TYPE:
  357. /* we have finally read the actual type character, so we */
  358. /* now format and "print" the output. We use a big switch */
  359. /* statement that sets 'text' to point to the text that should */
  360. /* be printed, and 'textlen' to the length of this text. */
  361. /* Common code later on takes care of justifying it and */
  362. /* other miscellaneous chores. Note that cases share code, */
  363. /* in particular, all integer formatting is doen in one place. */
  364. /* Look at those funky goto statements! */
  365. switch (ch) {
  366. case 'c': {
  367. /* print a single character specified by int argument */
  368. wc = (wchar_t) get_int_arg(&argptr); /* get char to print */
  369. * (wchar_t *) buffer = wc;
  370. text = buffer;
  371. textlen = 1; /* print just a single character */
  372. }
  373. break;
  374. case 'S': {
  375. /* print a Counted String */
  376. struct string {
  377. short Length;
  378. short MaximumLength;
  379. char *Buffer;
  380. } *pstr;
  381. pstr = get_ptr_arg(&argptr);
  382. if (pstr == NULL || pstr->Buffer == NULL) {
  383. /* null ptr passed, use special string */
  384. text = nullstring;
  385. textlen = strlen(text);
  386. flags &= ~FL_WIDE;
  387. } else {
  388. text = pstr->Buffer;
  389. /* The length field is a count of bytes, not characters. */
  390. if (flags & FL_WIDE)
  391. textlen = pstr->Length / sizeof( wchar_t );
  392. else
  393. textlen = pstr->Length;
  394. if (precision != -1)
  395. textlen = min( textlen, precision );
  396. }
  397. }
  398. break;
  399. case 's': {
  400. /* print a string -- */
  401. /* ANSI rules on how much of string to print: */
  402. /* all if precision is default, */
  403. /* min(precision, length) if precision given. */
  404. /* prints '(null)' if a null string is passed */
  405. int i;
  406. char *p; /* temps */
  407. text = get_ptr_arg(&argptr);
  408. if (text == NULL) {
  409. /* null ptr passed, use special string */
  410. text = nullstring;
  411. flags &= ~FL_WIDE;
  412. }
  413. /* At this point it is tempting to use strlen(), but */
  414. /* if a precision is specified, we're not allowed to */
  415. /* scan past there, because there might be no null */
  416. /* at all. Thus, we must do our own scan. */
  417. i = (precision == -1) ? INT_MAX : precision;
  418. /* scan for null upto i characters */
  419. if (flags & FL_WIDE) {
  420. pwc = (wchar_t *) text;
  421. while (i-- && (wc = *pwc) && (wc & 0x00ff)) {
  422. ++pwc;
  423. if (wc & 0xff00) { // if high byte set,
  424. break; // error will be indicated
  425. }
  426. }
  427. textlen = (int) (pwc - (wchar_t*)text); /* length of string */
  428. } else {
  429. p = text;
  430. while (i-- && *p) {
  431. ++p;
  432. }
  433. textlen = (int) (p - text); /* length of the string */
  434. }
  435. }
  436. break;
  437. /* print a GUID */
  438. case 'I':
  439. {
  440. void *p; /* temp */
  441. p = get_ptr_arg(&argptr);
  442. if (p == NULL)
  443. {
  444. /* null ptr passed, use special string */
  445. text = nullstring;
  446. textlen = strlen(nullstring);
  447. }
  448. else
  449. {
  450. textlen = StrFromGUID(p, buffer, BUFFERSIZE);
  451. text = buffer;
  452. }
  453. }
  454. break;
  455. case 'n': {
  456. /* write count of characters seen so far into */
  457. /* short/int/long thru ptr read from args */
  458. void *p; /* temp */
  459. p = get_ptr_arg(&argptr);
  460. /* store chars out into short/long/int depending on flags */
  461. #if !LONG_IS_INT
  462. if (flags & FL_LONG)
  463. *(long *)p = charsout;
  464. else
  465. #endif
  466. #if !SHORT_IS_INT
  467. if (flags & FL_SHORT)
  468. *(short *)p = (short) charsout;
  469. else
  470. #endif
  471. *(int *)p = charsout;
  472. no_output = 1; /* force no output */
  473. }
  474. break;
  475. #ifndef NOFLOATS
  476. case 'E':
  477. case 'G':
  478. capexp = 1; /* capitalize exponent */
  479. ch += 'a' - 'A'; /* convert format char to lower */
  480. /* DROP THROUGH */
  481. case 'e':
  482. case 'f':
  483. case 'g': {
  484. /* floating point conversion -- we call cfltcvt routines */
  485. /* to do the work for us. */
  486. flags |= FL_SIGNED; /* floating point is signed conversion */
  487. text = buffer; /* put result in buffer */
  488. flags &= ~FL_WIDE; /* 8 bit string */
  489. /* compute the precision value */
  490. if (precision < 0)
  491. precision = 6; /* default precision: 6 */
  492. else if (precision == 0 && ch == 'g')
  493. precision = 1; /* ANSI specified */
  494. #if !LONGDOUBLE_IS_DOUBLE
  495. /* do the conversion */
  496. if (flags & FL_LONGDOUBLE) {
  497. _cldcvt(argptr, text, ch, precision, capexp);
  498. va_arg(argptr, LONGDOUBLE);
  499. }
  500. else
  501. #endif
  502. {
  503. _cfltcvt(argptr, text, ch, precision, capexp);
  504. va_arg(argptr, DOUBLE);
  505. }
  506. /* '#' and precision == 0 means force a decimal point */
  507. if ((flags & FL_ALTERNATE) && precision == 0)
  508. _forcdecpt(text);
  509. /* 'g' format means crop zero unless '#' given */
  510. if (ch == 'g' && !(flags & FL_ALTERNATE))
  511. _cropzeros(text);
  512. /* check if result was negative, save '-' for later */
  513. /* and point to positive part (this is for '0' padding) */
  514. if (*text == '-') {
  515. flags |= FL_NEGATIVE;
  516. ++text;
  517. }
  518. textlen = strlen(text); /* compute length of text */
  519. }
  520. break;
  521. #endif // NOFLOATS
  522. case 'd':
  523. case 'i':
  524. /* signed decimal output */
  525. flags |= FL_SIGNED;
  526. radix = 10;
  527. goto COMMON_INT;
  528. case 'u':
  529. radix = 10;
  530. goto COMMON_INT;
  531. case 'p':
  532. /* write a pointer */
  533. /* this is like an integer or long for Win32, __int64 for Win64 */
  534. /* except we force precision to pad with zeros and */
  535. /* output in big hex. */
  536. precision = 2 * sizeof(void *); /* number of hex digits needed */
  537. #if !PTR_IS_INT
  538. flags |= FL_PTR; /* assume we're converting a long in the Win32 case */
  539. #endif
  540. /* DROP THROUGH to hex formatting */
  541. case 'C':
  542. case 'X':
  543. /* unsigned upper hex output */
  544. hexadd = 'A' - '9' - 1; /* set hexadd for uppercase hex */
  545. goto COMMON_HEX;
  546. case 'x':
  547. /* unsigned lower hex output */
  548. hexadd = 'a' - '9' - 1; /* set hexadd for lowercase hex */
  549. /* DROP THROUGH TO COMMON_HEX */
  550. COMMON_HEX:
  551. radix = 16;
  552. if (flags & FL_ALTERNATE) {
  553. /* alternate form means '0x' prefix */
  554. prefix[0] = '0';
  555. prefix[1] = (char)('x' - 'a' + '9' + 1 + hexadd); /* 'x' or 'X' */
  556. prefixlen = 2;
  557. }
  558. goto COMMON_INT;
  559. case 'o':
  560. /* unsigned octal output */
  561. radix = 8;
  562. if (flags & FL_ALTERNATE) {
  563. /* alternate form means force a leading 0 */
  564. flags |= FL_FORCEOCTAL;
  565. }
  566. /* DROP THROUGH to COMMON_INT */
  567. COMMON_INT: {
  568. /* This is the general integer formatting routine. */
  569. /* Basically, we get an argument, make it positive */
  570. /* if necessary, and convert it according to the */
  571. /* correct radix, setting text and textlen */
  572. /* appropriately. */
  573. ULONG_PTR number; /* number to convert */
  574. int digit; /* ascii value of digit */
  575. LONG_PTR l; /* temp long value */
  576. /* 1. read argument into l, sign extend as needed */
  577. #if !LONG_IS_INT
  578. if (flags & FL_LONG)
  579. l = get_long_arg(&argptr);
  580. else
  581. #endif
  582. #if !SHORT_IS_INT
  583. if (flags & FL_SHORT) {
  584. if (flags & FL_SIGNED)
  585. l = (short) get_int_arg(&argptr); /* sign extend */
  586. else
  587. l = (unsigned short) get_int_arg(&argptr); /* zero-extend*/
  588. }
  589. else
  590. #endif
  591. #ifdef _WIN64
  592. // Sundown: if get_int64_arg() could be defined all the time,
  593. // this 'ifdef _WIN64' could be removed.
  594. if (flags & FL_PTR64) {
  595. l = get_int64_arg(&argptr);
  596. }
  597. else
  598. #endif // _WIN64
  599. {
  600. if (flags & FL_SIGNED)
  601. l = get_int_arg(&argptr); /* sign extend */
  602. else
  603. l = (unsigned int) get_int_arg(&argptr); /* zero-extend*/
  604. }
  605. /* 2. check for negative; copy into number */
  606. if ( (flags & FL_SIGNED) && l < 0) {
  607. number = -l;
  608. flags |= FL_NEGATIVE; /* remember negative sign */
  609. }
  610. else {
  611. number = l;
  612. }
  613. /* 3. check precision value for default; non-default */
  614. /* turns off 0 flag, according to ANSI. */
  615. if (precision < 0)
  616. precision = 1; /* default precision */
  617. else
  618. flags &= ~FL_LEADZERO;
  619. /* 4. Check if data is 0; if so, turn off hex prefix */
  620. if (number == 0)
  621. prefixlen = 0;
  622. /* 5. Convert data to ASCII -- note if precision is zero */
  623. /* and number is zero, we get no digits at all. */
  624. text = &buffer[BUFFERSIZE-1]; // last digit at end of buffer
  625. flags &= ~FL_WIDE; // 8 bit characters
  626. while (precision-- > 0 || number != 0) {
  627. digit = (int)(number % radix) + '0';
  628. number /= radix; /* reduce number */
  629. if (digit > '9') {
  630. /* a hex digit, make it a letter */
  631. digit += hexadd;
  632. }
  633. *text-- = (char)digit; /* store the digit */
  634. }
  635. textlen = (int) (&buffer[BUFFERSIZE-1] - text); /* compute length of number */
  636. ++text; /* text points to first digit now */
  637. /* 6. Force a leading zero if FORCEOCTAL flag set */
  638. if ((flags & FL_FORCEOCTAL) && (text[0] != '0' || textlen == 0)) {
  639. *--text = '0';
  640. ++textlen; /* add a zero */
  641. }
  642. }
  643. break;
  644. }
  645. /* At this point, we have done the specific conversion, and */
  646. /* 'text' points to text to print; 'textlen' is length. Now we */
  647. /* justify it, put on prefixes, leading zeros, and then */
  648. /* print it. */
  649. if (!no_output) {
  650. int padding; /* amount of padding, negative means zero */
  651. if (flags & FL_SIGNED) {
  652. if (flags & FL_NEGATIVE) {
  653. /* prefix is a '-' */
  654. prefix[0] = '-';
  655. prefixlen = 1;
  656. }
  657. else if (flags & FL_SIGN) {
  658. /* prefix is '+' */
  659. prefix[0] = '+';
  660. prefixlen = 1;
  661. }
  662. else if (flags & FL_SIGNSP) {
  663. /* prefix is ' ' */
  664. prefix[0] = ' ';
  665. prefixlen = 1;
  666. }
  667. }
  668. /* calculate amount of padding -- might be negative, */
  669. /* but this will just mean zero */
  670. padding = fldwidth - textlen - prefixlen;
  671. /* put out the padding, prefix, and text, in the correct order */
  672. if (!(flags & (FL_LEFT | FL_LEADZERO))) {
  673. /* pad on left with blanks */
  674. f->writechar(' ', padding, f, &charsout);
  675. }
  676. /* write prefix */
  677. writestring(prefix, prefixlen, f, &charsout, 0);
  678. if ((flags & FL_LEADZERO) && !(flags & FL_LEFT)) {
  679. /* write leading zeros */
  680. f->writechar('0', padding, f, &charsout);
  681. }
  682. /* write text */
  683. writestring(text, textlen, f, &charsout, flags & FL_WIDE);
  684. if (flags & FL_LEFT) {
  685. /* pad on right with blanks */
  686. f->writechar(' ', padding, f, &charsout);
  687. }
  688. /* we're done! */
  689. }
  690. break;
  691. }
  692. }
  693. return charsout; /* return value = number of characters written */
  694. }
  695. /***
  696. *int get_int_arg(va_list pargptr)
  697. *
  698. *Purpose:
  699. * Gets an int argument off the given argument list and updates *pargptr.
  700. *
  701. *Entry:
  702. * va_list pargptr - pointer to argument list; updated by function
  703. *
  704. *Exit:
  705. * Returns the integer argument read from the argument list.
  706. *
  707. *Exceptions:
  708. *
  709. *******************************************************************************/
  710. LOCAL(int) get_int_arg(va_list *pargptr)
  711. {
  712. return va_arg(*pargptr, int);
  713. }
  714. /***
  715. *long get_long_arg(va_list pargptr)
  716. *
  717. *Purpose:
  718. * Gets an long argument off the given argument list and updates pargptr.
  719. *
  720. *Entry:
  721. * va_list pargptr - pointer to argument list; updated by function
  722. *
  723. *Exit:
  724. * Returns the long argument read from the argument list.
  725. *
  726. *Exceptions:
  727. *
  728. *******************************************************************************/
  729. #if !LONG_IS_INT
  730. LOCAL(long) get_long_arg(va_list *pargptr)
  731. {
  732. return va_arg(*pargptr, long);
  733. }
  734. #endif
  735. #ifdef _WIN64
  736. LOCAL(__int64) get_int64_arg (
  737. va_list *pargptr
  738. )
  739. {
  740. return va_arg(*pargptr, __int64);
  741. }
  742. #endif
  743. /***
  744. *void writestring(char *string, int len, struct w4io *f, int *pcchwritten, int fwide)
  745. *
  746. *Purpose:
  747. * Writes a string of the given length to the given file. If no error occurs,
  748. * then *pcchwritten is incremented by len; otherwise, *pcchwritten is set
  749. * to -1. If len is negative, it is treated as zero.
  750. *
  751. *Entry:
  752. * char *string - string to write (NOT null-terminated)
  753. * int len - length of string
  754. * struct w4io *f - file to write to
  755. * int *pcchwritten - pointer to integer to update with total chars written
  756. * int fwide - wide character flag
  757. *
  758. *Exit:
  759. * No return value.
  760. *
  761. *Exceptions:
  762. *
  763. *******************************************************************************/
  764. LOCAL(void) writestring(
  765. char *string,
  766. int len,
  767. struct w4io *f,
  768. int *pcchwritten,
  769. int fwide)
  770. {
  771. wchar_t *pwc;
  772. //printf("string: str=%.*s, len=%d, cch=%d, f=%d\n", len, string, len, *pcchwritten, fwide);
  773. if (fwide) {
  774. pwc = (wchar_t *) string;
  775. while (len-- > 0) {
  776. if (*pwc & 0xff00) {
  777. f->writechar('^', 1, f, pcchwritten);
  778. }
  779. f->writechar((char) *pwc++, 1, f, pcchwritten);
  780. }
  781. } else {
  782. while (len-- > 0) {
  783. f->writechar(*string++, 1, f, pcchwritten);
  784. }
  785. }
  786. }
  787. const wchar_t a_wcDigits[] = L"0123456789ABCDEF";
  788. //+---------------------------------------------------------------------------
  789. //
  790. // Function: FormatHexNum
  791. //
  792. // Synopsis: Given a value, and a count of characters, translate
  793. // the value into a hex string. This is the ANSI version
  794. //
  795. // Arguments: [ulValue] -- Value to convert
  796. // [chChars] -- Number of characters to format
  797. // [pchStr] -- Pointer to output buffer
  798. //
  799. // Requires: pwcStr must be valid for chChars
  800. //
  801. // History: 5-31-95 t-stevan Copied and Modified for use in debug output function
  802. //
  803. // Notes:
  804. //
  805. //----------------------------------------------------------------------------
  806. void FormatHexNum( unsigned long ulValue, unsigned long chChars, char *pchStr)
  807. {
  808. while(chChars--)
  809. {
  810. pchStr[chChars] = (char) a_wcDigits[ulValue & 0xF];
  811. ulValue = ulValue >> 4;
  812. }
  813. }
  814. //+-------------------------------------------------------------------------
  815. //
  816. // Function: StrFromGUID (private)
  817. //
  818. // Synopsis: Converts a GUID into a string (duh!)
  819. //
  820. // Arguments: [rguid] - the guid to convert
  821. // [lpszy] - buffer to hold the results
  822. // [cbMax] - sizeof the buffer
  823. //
  824. // Returns: amount of data copied to lpsz if successful
  825. // 0 if buffer too small.
  826. //
  827. //--------------------------------------------------------------------------
  828. int StrFromGUID(REFGUID rguid, char * lpsz, int cbMax) // internal
  829. {
  830. if (cbMax < GUIDSTR_MAX)
  831. return 0;
  832. // Make the GUID into"{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
  833. *lpsz++ = '{';
  834. FormatHexNum( rguid->Data1, 8 , lpsz);
  835. lpsz += 8;
  836. *lpsz++ = '-';
  837. FormatHexNum( rguid->Data2, 4 , lpsz);
  838. lpsz += 4;
  839. *lpsz++ = '-';
  840. FormatHexNum( rguid->Data3, 4 , lpsz);
  841. lpsz += 4;
  842. *lpsz++ = '-';
  843. FormatHexNum( rguid->Data4[0], 2 , lpsz);
  844. lpsz += 2;
  845. FormatHexNum( rguid->Data4[1], 2 , lpsz);
  846. lpsz += 2;
  847. *lpsz++ = '-';
  848. FormatHexNum( rguid->Data4[2], 2 , lpsz);
  849. lpsz += 2;
  850. FormatHexNum( rguid->Data4[3], 2 , lpsz);
  851. lpsz += 2;
  852. FormatHexNum( rguid->Data4[4], 2 , lpsz);
  853. lpsz += 2;
  854. FormatHexNum( rguid->Data4[5], 2 , lpsz);
  855. lpsz += 2;
  856. FormatHexNum( rguid->Data4[6], 2 , lpsz);
  857. lpsz += 2;
  858. FormatHexNum( rguid->Data4[7], 2 , lpsz);
  859. lpsz += 2;
  860. *lpsz++ = '}';
  861. /* We don't want to tag on a NULL char because we don't need to print one out *\
  862. /* *lpsz = 0; */
  863. return GUIDSTR_MAX;
  864. }