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.

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