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.

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