Source code of Windows XP (NT5)
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.

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