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

801 lines
26 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. rprintf.cxx
  5. Abstract:
  6. Contains my own version of printf(), sprintf() and vprintf(). Useful since
  7. adding new printf escape sequences becomes easy
  8. Contents:
  9. rprintf limited re-entrant version of printf
  10. rsprintf limited re-entrant version of sprintf
  11. _sprintf routine which does the work
  12. Author:
  13. Richard L Firth (rfirth) 20-Jun-1995
  14. Revision History:
  15. 29-Aug-1989 rfirth
  16. Created
  17. --*/
  18. #include <wininetp.h>
  19. #include "rprintf.h"
  20. //
  21. // defines for flags word
  22. //
  23. #define F_SPACES 0x00000001 // prefix field with spaces
  24. #define F_ZEROES 0x00000002 // prefix field with zeroes
  25. #define F_MINUS 0x00000004 // field is left justified
  26. #define F_HASH 0x00000008 // hex field is prefixed with 0x/0X
  27. #define F_XUPPER 0x00000010 // hex field has upper case letters
  28. #define F_LONG 0x00000020 // long int/hex/oct prefix
  29. #define F_PLUS 0x00000040 // prefix +'ve signed number with +
  30. #define F_DOT 0x00000080 // separator for field and precision
  31. #define F_NEAR 0x00000100 // far pointer has near prefix
  32. #define F_FAR 0x00000200 // near pointer has far prefix
  33. #define F_SREPLICATE 0x00000400 // this field replicated
  34. #define F_EREPLICATE 0x00000800 // end of replications
  35. #define F_UNICODE 0x00001000 // string is wide character (%ws/%wq)
  36. #define F_QUOTING 0x00002000 // strings enclosed in double quotes
  37. #define F_ELLIPSE 0x00004000 // a sized, quoted string ends in "..."
  38. #define BUFFER_SIZE 1024
  39. //
  40. // minimum field widths for various ASCII representations of numbers
  41. //
  42. #define MIN_BIN_WIDTH 16 // minimum field width in btoa
  43. #define MIN_HEX_WIDTH 8 // minimum field width in xtoa
  44. #define MIN_INT_WIDTH 10 // minimum field width in itoa
  45. #define MIN_LHEX_WIDTH 8 // minimum field width in long xtoa
  46. #define MIN_LINT_WIDTH 10 // minimum field width in long itoa
  47. #define MIN_LOCT_WIDTH 11 // minimum field width in long otoa
  48. #define MIN_OCT_WIDTH 11 // minimum field width in otoa
  49. #define MIN_UINT_WIDTH 10 // minimum field width in utoa
  50. //
  51. // character defines
  52. //
  53. #define EOSTR '\0'
  54. #define CR '\x0d'
  55. #define LF '\x0a'
  56. #if !defined(min)
  57. #define min(a, b) ((a)<(b)) ? (a) : (b)
  58. #endif
  59. PRIVATE int _atoi(char**);
  60. PRIVATE void convert(char**, ULONG_PTR, int, int, unsigned, char(*)(ULONG_PTR*));
  61. PRIVATE char btoa(ULONG_PTR *);
  62. PRIVATE char otoa(ULONG_PTR *);
  63. PRIVATE char utoa(ULONG_PTR *);
  64. PRIVATE char xtoa(ULONG_PTR *);
  65. PRIVATE char Xasc(ULONG_PTR *);
  66. /*** rprintf - a re-entrant cut-down version of printf. Understands usual
  67. * printf format characters introduced by '%' plus one or
  68. * two additions
  69. *
  70. * ENTRY format - pointer to buffer containing format string defining
  71. * the output. As per usual printf the arguments to
  72. * fill in the blanks in the format string are on the
  73. * the stack after the format string
  74. *
  75. * <args> - arguments on stack, size and type determined from
  76. * the format string
  77. *
  78. * EXIT format string used to convert arguments (if any) and print
  79. * the results to stdout.
  80. * The number of character copied is the value returned
  81. */
  82. #ifdef UNUSED
  83. int cdecl rprintf(char* format, ...) {
  84. int charsPrinted = 0;
  85. char buffer[BUFFER_SIZE];
  86. DWORD nwritten;
  87. va_list args;
  88. /* print the output into buffer then print the formatted buffer to the
  89. * screen
  90. */
  91. va_start(args, format);
  92. charsPrinted = _sprintf(buffer, format, args);
  93. va_end(args);
  94. WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),
  95. buffer,
  96. charsPrinted,
  97. &nwritten,
  98. 0
  99. );
  100. return nwritten;
  101. }
  102. #endif
  103. /*** rsprintf - a re-entrant cut-down version of sprintf. See rprintf for
  104. * details
  105. *
  106. * ENTRY buffer - pointer to the buffer which will receive the
  107. * formatted output
  108. *
  109. * format - pointer to buffer which defines the formatted
  110. * output. Consists of normal printing characters
  111. * and printf-style format characters (see rprintf)
  112. *
  113. * EXIT characters from format string and arguments converted to
  114. * character format based on format string are copied into the
  115. * buffer
  116. * The number of character copied is the value returned
  117. */
  118. int cdecl rsprintf(char* buffer, char* format, ...) {
  119. va_list args;
  120. int n;
  121. va_start(args, format);
  122. n = _sprintf(buffer, format, args);
  123. va_end(args);
  124. return n;
  125. }
  126. /*** _sprintf - performs the sprintf function. Receives an extra parameter
  127. * on the stack which is the pointer to the variable argument
  128. * list of rprintf and rsprintf
  129. *
  130. * ENTRY buffer - pointer to buffer which will receive the output
  131. *
  132. * format - pointer to the format string
  133. *
  134. * args - variable argument list which will be used to fill in
  135. * the escape sequences in the format string
  136. *
  137. * EXIT The characters in the format string are used to convert the
  138. * arguments and copy them to the buffer.
  139. * The number of character copied is the value returned
  140. */
  141. int cdecl _sprintf(char* buffer, char* format, va_list args) {
  142. char* original = buffer;
  143. int FieldWidth;
  144. int FieldPrecision;
  145. int FieldLen;
  146. BOOL SubDone;
  147. int StrLen;
  148. int i;
  149. DWORD flags;
  150. int replications;
  151. while (*format) {
  152. switch ((unsigned)*format) {
  153. case '\n':
  154. //
  155. // convert line-feed to carriage-return, line-feed. But only if the
  156. // format string doesn't already contain a carriage-return directly
  157. // before the line-feed! This way we can make multiple calls into
  158. // this function, with the same buffer, and only once expand the
  159. // line-feed
  160. //
  161. if (*(buffer - 1) != CR) {
  162. *buffer++ = CR;
  163. }
  164. *buffer++ = LF;
  165. break;
  166. case '%':
  167. SubDone = FALSE;
  168. flags = 0;
  169. FieldWidth = 0;
  170. FieldPrecision = 0;
  171. replications = 1; /* default replication is 1 */
  172. while (!SubDone) {
  173. switch ((unsigned)*++format) {
  174. case '%':
  175. *buffer++ = '%';
  176. SubDone = TRUE;
  177. break;
  178. case ' ':
  179. flags |= F_SPACES;
  180. break;
  181. case '#':
  182. flags |= F_HASH;
  183. break;
  184. case '-':
  185. flags |= F_MINUS;
  186. break;
  187. case '+':
  188. flags |= F_PLUS;
  189. break;
  190. case '.':
  191. flags |= F_DOT;
  192. break;
  193. case '*':
  194. if (flags & F_DOT) {
  195. FieldPrecision = va_arg(args, int);
  196. } else {
  197. FieldWidth = va_arg(args, int);
  198. }
  199. break;
  200. case '@':
  201. replications = _atoi(&format);
  202. break;
  203. case '[':
  204. flags |= F_SREPLICATE;
  205. break;
  206. case ']':
  207. flags |= F_EREPLICATE;
  208. break;
  209. case '0':
  210. /* if this is leading zero then caller wants
  211. * zero prefixed number of given width (%04x)
  212. */
  213. if (!(flags & F_ZEROES)) {
  214. flags |= F_ZEROES;
  215. break;
  216. }
  217. case '1':
  218. case '2':
  219. case '3':
  220. case '4':
  221. case '5':
  222. case '6':
  223. case '7':
  224. case '8':
  225. case '9':
  226. if (flags & F_DOT) {
  227. FieldPrecision = _atoi(&format);
  228. } else {
  229. FieldWidth = _atoi(&format);
  230. }
  231. break;
  232. case 'b':
  233. //
  234. // Binary representation
  235. //
  236. while (replications--) {
  237. convert(&buffer,
  238. va_arg(args, unsigned int),
  239. (FieldWidth) ? FieldWidth : MIN_BIN_WIDTH,
  240. MIN_BIN_WIDTH,
  241. flags,
  242. btoa
  243. );
  244. }
  245. SubDone = TRUE;
  246. break;
  247. case 'B':
  248. //
  249. // Boolean representation
  250. //
  251. if (va_arg(args, BOOL)) {
  252. *buffer++ = 'T';
  253. *buffer++ = 'R';
  254. *buffer++ = 'U';
  255. *buffer++ = 'E';
  256. } else {
  257. *buffer++ = 'F';
  258. *buffer++ = 'A';
  259. *buffer++ = 'L';
  260. *buffer++ = 'S';
  261. *buffer++ = 'E';
  262. }
  263. SubDone = TRUE;
  264. break;
  265. case 'c':
  266. //
  267. // assume that a character is the size of the
  268. // width of the stack which in turn has the same
  269. // width as an integer
  270. //
  271. --FieldWidth;
  272. while (replications--) {
  273. for (i = 0; i < FieldWidth; i++) {
  274. *buffer++ = ' ';
  275. }
  276. *buffer++ = (char) va_arg(args, int);
  277. }
  278. SubDone = TRUE;
  279. break;
  280. case 'd':
  281. case 'i':
  282. while (replications--) {
  283. long l;
  284. l = (flags & F_LONG) ? va_arg(args, long) : (long)va_arg(args, int);
  285. if (l < 0) {
  286. *buffer++ = '-';
  287. if (flags & F_LONG) {
  288. l = -(long)l;
  289. } else {
  290. l = -(int)l;
  291. }
  292. } else if (flags & F_PLUS) {
  293. *buffer++ = '+';
  294. }
  295. convert(&buffer,
  296. l,
  297. FieldWidth,
  298. (flags & F_LONG) ? MIN_LINT_WIDTH : MIN_INT_WIDTH,
  299. flags,
  300. utoa
  301. );
  302. }
  303. SubDone = TRUE;
  304. break;
  305. case 'e':
  306. /* not currently handled */
  307. break;
  308. case 'f':
  309. /* not currently handled */
  310. break;
  311. case 'F':
  312. flags |= F_FAR;
  313. break;
  314. case 'g':
  315. case 'G':
  316. /* not currently handled */
  317. break;
  318. case 'h':
  319. /* not currently handled */
  320. break;
  321. case 'l':
  322. flags |= F_LONG;
  323. break;
  324. case 'L':
  325. /* not currently handled */
  326. break;
  327. case 'n':
  328. *(va_arg(args, int*)) = (int)(buffer - original);
  329. SubDone = TRUE;
  330. break;
  331. case 'N':
  332. flags |= F_NEAR;
  333. break;
  334. case 'o':
  335. while (replications--) {
  336. convert(&buffer,
  337. (flags & F_LONG) ? va_arg(args, unsigned long) : (unsigned long)va_arg(args, unsigned),
  338. FieldWidth,
  339. (flags & F_LONG) ? MIN_LOCT_WIDTH : MIN_OCT_WIDTH,
  340. flags,
  341. otoa
  342. );
  343. }
  344. SubDone = TRUE;
  345. break;
  346. case 'p':
  347. while (replications--) {
  348. void* p;
  349. if (!(flags & F_NEAR)) {
  350. convert(&buffer,
  351. (ULONG_PTR) va_arg(args, char near *),
  352. MIN_HEX_WIDTH,
  353. MIN_HEX_WIDTH,
  354. flags | F_XUPPER,
  355. Xasc
  356. );
  357. *buffer++ = ':';
  358. }
  359. convert(&buffer,
  360. (ULONG_PTR)va_arg(args, unsigned),
  361. MIN_HEX_WIDTH,
  362. MIN_HEX_WIDTH,
  363. flags | F_XUPPER,
  364. Xasc
  365. );
  366. }
  367. SubDone = TRUE;
  368. break;
  369. case 'Q': // quoted unicode string
  370. flags |= F_UNICODE;
  371. // *** FALL THROUGH ***
  372. case 'q':
  373. *buffer++ = '"';
  374. flags |= F_QUOTING;
  375. //
  376. // *** FALL THROUGH ***
  377. //
  378. case 's':
  379. while (replications--) {
  380. char* s;
  381. s = va_arg(args, char*);
  382. if (s != NULL) {
  383. // darrenmi 2/24/00 Note that if the string has a field precision,
  384. // it's not always null terminated!! Don't depend on it being psz
  385. // and stop when we hit our max length.
  386. StrLen = 0;
  387. if (flags & F_UNICODE) {
  388. WCHAR *pWork = (LPWSTR)s;
  389. while((!FieldPrecision || StrLen < FieldPrecision) && *pWork)
  390. {
  391. pWork++;
  392. StrLen++;
  393. }
  394. } else {
  395. CHAR *pWork = s;
  396. while((!FieldPrecision || StrLen < FieldPrecision) && *pWork)
  397. {
  398. pWork++;
  399. StrLen++;
  400. }
  401. }
  402. FieldLen = (FieldPrecision)
  403. ? min(StrLen, FieldPrecision)
  404. : StrLen
  405. ;
  406. if ((flags & F_QUOTING) && (FieldPrecision > 3) && (FieldLen < StrLen)) {
  407. FieldLen -= 3;
  408. flags |= F_ELLIPSE;
  409. }
  410. for (i = 0; i < (FieldWidth - FieldLen); i++) {
  411. *buffer++ = ' ';
  412. }
  413. if (flags & F_UNICODE) {
  414. char wbuf[4096];
  415. int wi;
  416. WideCharToMultiByte(CP_ACP, 0,
  417. (LPWSTR)s, -1,
  418. wbuf, 4096,
  419. NULL, NULL);
  420. for (wi = 0; wbuf[wi] && FieldLen; ++wi) {
  421. *buffer = wbuf[wi];
  422. //
  423. // if this is a quoted string, and it contains
  424. // \r and/or \n, then we reverse-convert these
  425. // characters, since we don't want then to
  426. // break the string. Do the same for \t
  427. //
  428. if (flags & F_QUOTING) {
  429. char ch;
  430. ch = *buffer;
  431. if ((ch == '\r') || (ch == '\n') || (ch == '\t')) {
  432. *buffer++ = '\\';
  433. *buffer = (ch == '\r')
  434. ? 'r'
  435. : (ch == '\n')
  436. ? 'n'
  437. : 't'
  438. ;
  439. }
  440. }
  441. ++buffer;
  442. --FieldLen;
  443. }
  444. } else {
  445. while (*s && FieldLen) {
  446. *buffer = *s++;
  447. //
  448. // if this is a quoted string, and it contains
  449. // \r and/or \n, then we reverse-convert these
  450. // characters, since we don't want then to
  451. // break the string. Do the same for \t
  452. //
  453. if (flags & F_QUOTING) {
  454. char ch;
  455. ch = *buffer;
  456. if ((ch == '\r') || (ch == '\n') || (ch == '\t')) {
  457. *buffer++ = '\\';
  458. *buffer = (ch == '\r')
  459. ? 'r'
  460. : (ch == '\n')
  461. ? 'n'
  462. : 't'
  463. ;
  464. }
  465. }
  466. ++buffer;
  467. --FieldLen;
  468. }
  469. }
  470. if (flags & F_ELLIPSE) {
  471. *buffer++ = '.';
  472. *buffer++ = '.';
  473. *buffer++ = '.';
  474. }
  475. } else if (!(flags & F_QUOTING)) {
  476. *buffer++ = '(';
  477. *buffer++ = 'n';
  478. *buffer++ = 'u';
  479. *buffer++ = 'l';
  480. *buffer++ = 'l';
  481. *buffer++ = ')';
  482. }
  483. }
  484. if (flags & F_QUOTING) {
  485. *buffer++ = '"';
  486. }
  487. SubDone = TRUE;
  488. break;
  489. case 'S':
  490. break;
  491. case 'u':
  492. while (replications--) {
  493. convert(&buffer,
  494. va_arg(args, unsigned),
  495. FieldWidth,
  496. MIN_UINT_WIDTH,
  497. flags,
  498. utoa
  499. );
  500. }
  501. SubDone = TRUE;
  502. break;
  503. case 'w':
  504. flags |= F_UNICODE;
  505. break;
  506. case 'X':
  507. flags |= F_XUPPER;
  508. //
  509. // *** FALL THROUGH ***
  510. //
  511. case 'x':
  512. while (replications--) {
  513. if (flags & F_HASH) {
  514. *buffer++ = '0';
  515. *buffer++ = (flags & F_XUPPER) ? (char)'X' : (char)'x';
  516. }
  517. convert(&buffer,
  518. (flags & F_LONG) ? va_arg(args, unsigned long) : va_arg(args, unsigned),
  519. FieldWidth,
  520. (flags & F_LONG) ? MIN_LHEX_WIDTH : MIN_HEX_WIDTH,
  521. flags,
  522. (flags & F_XUPPER) ? Xasc : xtoa
  523. );
  524. }
  525. SubDone = TRUE;
  526. break;
  527. } /* switch <%-specifier> */
  528. }
  529. break;
  530. default:
  531. *buffer++ = *format;
  532. } /* switch <character> */
  533. ++format;
  534. } /* while */
  535. *buffer = EOSTR;
  536. return (int)(buffer - original);
  537. }
  538. /*** _atoi - ascii to integer conversion used to get the field width out
  539. * of the format string
  540. *
  541. * ENTRY p - pointer to pointer to format string
  542. *
  543. * EXIT returns the number found in the prefix string as a (16-bit)
  544. * int format string pointer is updated past the field width
  545. */
  546. PRIVATE
  547. int _atoi(char** p) {
  548. int n = 0;
  549. int i = 5;
  550. while ((**p >= '0' && **p <= '9') && i--) {
  551. n = n*10+((int)(*(*p)++)-(int)'0');
  552. }
  553. /* put the format pointer back one since the major loop tests *++format */
  554. --*p;
  555. return n;
  556. }
  557. /*** convert - convert number to representation defined by procedure
  558. *
  559. * ENTRY buffer - pointer to buffer to receive conversion
  560. * n - number to convert
  561. * width - user defined field width
  562. * mwidth - minimum width for representation
  563. * flags - flags controlling conversion
  564. * proc - pointer to conversion routine
  565. *
  566. * EXIT buffer is updated to point past the number representation
  567. * just put into it
  568. */
  569. PRIVATE
  570. void
  571. convert(
  572. char** buffer,
  573. ULONG_PTR n,
  574. int width,
  575. int mwidth,
  576. unsigned flags,
  577. char (*proc)(ULONG_PTR*)
  578. )
  579. {
  580. char numarray[33];
  581. int MinWidth;
  582. int i;
  583. MinWidth = (width < mwidth) ? mwidth : width;
  584. i = MinWidth;
  585. do {
  586. numarray[--i] = (*proc)(&n);
  587. } while (n);
  588. while (width > MinWidth-i) {
  589. numarray[--i] = (char)((flags & F_SPACES) ? ' ' : '0');
  590. }
  591. while (i < MinWidth) {
  592. *(*buffer)++ = numarray[i++];
  593. }
  594. }
  595. /*** btoa - return next (least significant) char in a binary to ASCII
  596. * conversion
  597. *
  598. * ENTRY pn - pointer to number to convert
  599. *
  600. * EXIT returns next (LS) character, updates original number
  601. */
  602. PRIVATE
  603. char btoa(ULONG_PTR *pn) {
  604. char rch;
  605. rch = (char)(*pn&1)+'0';
  606. *pn >>= 1;
  607. return rch;
  608. }
  609. /*** otoa - return next (least significant) char in an octal to ASCII
  610. * conversion
  611. *
  612. * ENTRY pn - pointer to number to convert
  613. *
  614. * EXIT returns next (LS) character, updates original number
  615. */
  616. PRIVATE
  617. char otoa(ULONG_PTR *pn) {
  618. char rch;
  619. rch = (char)'0'+(char)(*pn&7);
  620. *pn >>= 3;
  621. return rch;
  622. }
  623. /*** utoa - return next (least significant) char in an unsigned int to
  624. * ASCII conversion
  625. *
  626. * ENTRY pn - pointer to number to convert
  627. *
  628. * EXIT returns next (LS) character, updates original number
  629. */
  630. PRIVATE
  631. char utoa(ULONG_PTR *pn) {
  632. char rch;
  633. rch = (char)'0'+(char)(*pn%10);
  634. *pn /= 10;
  635. return rch;
  636. }
  637. /*** xtoa - return next (least significant) char in a hexadecimal to
  638. * ASCII conversion. Returns lower case hex characters
  639. *
  640. * ENTRY pn - pointer to number to convert
  641. *
  642. * EXIT returns next (LS) character, updates original number
  643. */
  644. PRIVATE
  645. char xtoa(ULONG_PTR *pn) {
  646. ULONG_PTR n = *pn & 0x000f;
  647. char rch = (n <= 9) /* decimal digit? */
  648. ? (char)n+'0'
  649. : (char)n+'0'+('a'-'9'-1);
  650. *pn >>= 4;
  651. return rch;
  652. }
  653. /*** Xasc - return next (least significant) char in a hexadecimal to
  654. * ASCII conversion. Returns upper case hex characters
  655. *
  656. * ENTRY pn - pointer to number to convert
  657. *
  658. * EXIT returns next (LS) character, updates original number
  659. */
  660. PRIVATE
  661. char Xasc(ULONG_PTR *pn) {
  662. ULONG_PTR n = *pn & 0x000f;
  663. char rch = (n <= 9) /* decimal digit? */
  664. ? (char)n+'0'
  665. : (char)n+'0'+('A'-'9'-1);
  666. *pn >>= 4;
  667. return rch;
  668. }