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.

805 lines
26 KiB

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