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.

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