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.

1039 lines
30 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: wsprintf.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. * sprintf.c
  6. *
  7. * Implements Windows friendly versions of sprintf and vsprintf
  8. *
  9. * History:
  10. * 2-15-89 craigc Initial
  11. * 11-12-90 MikeHar Ported from windows 3
  12. \***************************************************************************/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #define out(c) if (cchLimit) {*lpOut++=(c); cchLimit--;} else goto errorout
  16. /***************************************************************************\
  17. * SP_PutNumber
  18. *
  19. * Takes an unsigned long integer and places it into a buffer, respecting
  20. * a buffer limit, a radix, and a case select (upper or lower, for hex).
  21. *
  22. *
  23. * History:
  24. * 11-12-90 MikeHar Ported from windows 3 asm --> C
  25. * 12-11-90 GregoryW need to increment lpstr after assignment of mod
  26. \***************************************************************************/
  27. int SP_PutNumber(
  28. LPSTR lpstr,
  29. ULONG64 n,
  30. int limit,
  31. DWORD radix,
  32. int uppercase)
  33. {
  34. DWORD mod;
  35. int count = 0;
  36. /* It might not work for some locales or digit sets */
  37. if(uppercase)
  38. uppercase = 'A'-'0'-10;
  39. else
  40. uppercase = 'a'-'0'-10;
  41. if (count < limit) {
  42. do {
  43. mod = (ULONG)(n % radix);
  44. n /= radix;
  45. mod += '0';
  46. if (mod > '9')
  47. mod += uppercase;
  48. *lpstr++ = (char)mod;
  49. count++;
  50. } while((count < limit) && n);
  51. }
  52. return count;
  53. }
  54. /***************************************************************************\
  55. * SP_Reverse
  56. *
  57. * reverses a string in place
  58. *
  59. * History:
  60. * 11-12-90 MikeHar Ported from windows 3 asm --> C
  61. * 12-11-90 GregoryW fixed boundary conditions; removed count
  62. \***************************************************************************/
  63. void SP_Reverse(
  64. LPSTR lpFirst,
  65. LPSTR lpLast)
  66. {
  67. char ch;
  68. while(lpLast > lpFirst){
  69. ch = *lpFirst;
  70. *lpFirst++ = *lpLast;
  71. *lpLast-- = ch;
  72. }
  73. }
  74. /***************************************************************************\
  75. * SP_GetFmtValue
  76. *
  77. * reads a width or precision value from the format string
  78. *
  79. * History:
  80. * 11-12-90 MikeHar Ported from windows 3
  81. \***************************************************************************/
  82. LPCSTR SP_GetFmtValue(
  83. LPCSTR lpch,
  84. int *lpw)
  85. {
  86. int ii = 0;
  87. /* It might not work for some locales or digit sets */
  88. while (*lpch >= '0' && *lpch <= '9') {
  89. ii *= 10;
  90. ii += (int)(*lpch - '0');
  91. lpch++;
  92. }
  93. *lpw = ii;
  94. /*
  95. * return the address of the first non-digit character
  96. */
  97. return lpch;
  98. }
  99. /***************************************************************************\
  100. * SP_GetFmtValueW
  101. *
  102. * reads a width or precision value from the format string
  103. *
  104. * History:
  105. * 11-12-90 MikeHar Ported from windows 3
  106. * 07-27-92 GregoryW Created Unicode version (copied from SP_GetFmtValue)
  107. \***************************************************************************/
  108. LPCWSTR SP_GetFmtValueW(
  109. LPCWSTR lpch,
  110. int *lpw)
  111. {
  112. int ii = 0;
  113. /* It might not work for some locales or digit sets */
  114. while (*lpch >= L'0' && *lpch <= L'9') {
  115. ii *= 10;
  116. ii += (int)(*lpch - L'0');
  117. lpch++;
  118. }
  119. *lpw = ii;
  120. /*
  121. * return the address of the first non-digit character
  122. */
  123. return lpch;
  124. }
  125. /***************************************************************************\
  126. * wvsprintfA (API)
  127. *
  128. * Windows version of vsprintf(). Does not support floating point or
  129. * pointer types, and all strings are assumed to be FAR. Supports only
  130. * the left alignment flag.
  131. *
  132. * Takes pointers to an output buffer, where the string is built, a
  133. * pointer to an input buffer, and a pointer to a list of parameters.
  134. *
  135. * The cdecl function wsprintf() calls this function.
  136. *
  137. * History:
  138. * 11-12-90 MikeHar Ported from windows 3
  139. * 12-11-90 GregoryW after %d format is parsed lpParms needs to be aligned
  140. * to a dword boundary.
  141. * 09-Aug-1991 mikeke no it doesn't
  142. * 11-19-91 DarrinM Now wvsprintf and wsprintf treat parameters the same
  143. * (as if they originated from a DWORD-aligned stack).
  144. \***************************************************************************/
  145. FUNCLOG3(LOG_GENERAL, int, DUMMYCALLINGTYPE, wvsprintfA, LPSTR, lpOut, LPCSTR, lpFmt, va_list, arglist)
  146. int wvsprintfA(
  147. LPSTR lpOut,
  148. LPCSTR lpFmt,
  149. va_list arglist)
  150. {
  151. BOOL fAllocateMem;
  152. char prefix, fillch;
  153. int left, width, prec, size, sign, radix, upper, hprefix;
  154. int cchLimit = WSPRINTF_LIMIT, cch;
  155. LPSTR lpT, lpTMB;
  156. LPWSTR pwsz;
  157. va_list varglist = arglist;
  158. union {
  159. LONG64 l;
  160. ULONG64 ul;
  161. char sz[2];
  162. WCHAR wsz[2];
  163. } val;
  164. while (*lpFmt != 0) {
  165. if (*lpFmt == '%') {
  166. /*
  167. * read the flags. These can be in any order
  168. */
  169. left = 0;
  170. prefix = 0;
  171. while (*++lpFmt) {
  172. if (*lpFmt == '-')
  173. left++;
  174. else if (*lpFmt == '#')
  175. prefix++;
  176. else
  177. break;
  178. }
  179. /*
  180. * find fill character
  181. */
  182. if (*lpFmt == '0') {
  183. fillch = '0';
  184. lpFmt++;
  185. } else
  186. fillch = ' ';
  187. /*
  188. * read the width specification
  189. */
  190. lpFmt = SP_GetFmtValue((LPCSTR)lpFmt, &cch);
  191. width = cch;
  192. /*
  193. * read the precision
  194. */
  195. if (*lpFmt == '.') {
  196. lpFmt = SP_GetFmtValue((LPCSTR)++lpFmt, &cch);
  197. prec = cch;
  198. } else
  199. prec = -1;
  200. /*
  201. * get the operand size
  202. * default size: size == 0
  203. * long number: size == 1
  204. * wide chars: size == 2
  205. * 64bit number: size == 3
  206. * It may be a good idea to check the value of size when it
  207. * is tested for non-zero below (IanJa)
  208. */
  209. hprefix = 0;
  210. if (*lpFmt == 'w') {
  211. size = 2;
  212. lpFmt++;
  213. } else if (*lpFmt == 'l') {
  214. size = 1;
  215. lpFmt++;
  216. } else if (*lpFmt == 't') {
  217. size = 0;
  218. lpFmt++;
  219. } else if (*lpFmt == 'I') {
  220. if (*(lpFmt+1) == '3' && *(lpFmt+2) == '2') {
  221. size = 1;
  222. lpFmt += 3;
  223. } else if (*(lpFmt+1) == '6' && *(lpFmt+2) == '4') {
  224. size = 3;
  225. lpFmt += 3;
  226. } else {
  227. size = (sizeof(INT_PTR) == sizeof(LONG)) ? 1 : 3;
  228. lpFmt++;
  229. }
  230. } else {
  231. size = 0;
  232. if (*lpFmt == 'h') {
  233. lpFmt++;
  234. hprefix = 1;
  235. } else if ((*lpFmt == 'i') || (*lpFmt == 'd')) {
  236. // %i or %d specified (no modifiers) - use long
  237. // %u seems to have always been short - leave alone
  238. size = 1;
  239. }
  240. }
  241. upper = 0;
  242. sign = 0;
  243. radix = 10;
  244. switch (*lpFmt) {
  245. case 0:
  246. goto errorout;
  247. case 'i':
  248. case 'd':
  249. sign++;
  250. /*** FALL THROUGH to case 'u' ***/
  251. case 'u':
  252. /* turn off prefix if decimal */
  253. prefix = 0;
  254. donumeric:
  255. /* special cases to act like MSC v5.10 */
  256. if (left || prec >= 0)
  257. fillch = ' ';
  258. /*
  259. * if size == 1, "%lu" was specified (good);
  260. * if size == 2, "%wu" was specified (bad)
  261. * if size == 3, "%p" was specified
  262. */
  263. if (size == 3) {
  264. val.l = va_arg(varglist, LONG64);
  265. } else if (size) {
  266. val.l = va_arg(varglist, long);
  267. } else if (sign) {
  268. val.l = (long)va_arg(varglist, short);
  269. } else {
  270. val.ul = va_arg(varglist, unsigned);
  271. }
  272. if (sign && val.l < 0L)
  273. val.l = -val.l;
  274. else
  275. sign = 0;
  276. /*
  277. * Unless printing a full 64-bit value, ensure values
  278. * here are not in canonical longword format to prevent
  279. * the sign extended upper 32-bits from being printed.
  280. */
  281. if (size != 3) {
  282. val.l &= MAXULONG;
  283. }
  284. lpT = lpOut;
  285. /*
  286. * blast the number backwards into the user buffer
  287. */
  288. cch = SP_PutNumber(lpOut, val.l, cchLimit, radix, upper);
  289. if (!(cchLimit -= cch))
  290. goto errorout;
  291. lpOut += cch;
  292. width -= cch;
  293. prec -= cch;
  294. if (prec > 0)
  295. width -= prec;
  296. /*
  297. * fill to the field precision
  298. */
  299. while (prec-- > 0)
  300. out('0');
  301. if (width > 0 && !left) {
  302. /*
  303. * if we're filling with spaces, put sign first
  304. */
  305. if (fillch != '0') {
  306. if (sign) {
  307. sign = 0;
  308. out('-');
  309. width--;
  310. }
  311. if (prefix) {
  312. out(prefix);
  313. out('0');
  314. prefix = 0;
  315. }
  316. }
  317. if (sign)
  318. width--;
  319. /*
  320. * fill to the field width
  321. */
  322. while (width-- > 0)
  323. out(fillch);
  324. /*
  325. * still have a sign?
  326. */
  327. if (sign)
  328. out('-');
  329. if (prefix) {
  330. out(prefix);
  331. out('0');
  332. }
  333. /*
  334. * now reverse the string in place
  335. */
  336. SP_Reverse(lpT, lpOut - 1);
  337. } else {
  338. /*
  339. * add the sign character
  340. */
  341. if (sign) {
  342. out('-');
  343. width--;
  344. }
  345. if (prefix) {
  346. out(prefix);
  347. out('0');
  348. }
  349. /*
  350. * reverse the string in place
  351. */
  352. SP_Reverse(lpT, lpOut - 1);
  353. /*
  354. * pad to the right of the string in case left aligned
  355. */
  356. while (width-- > 0)
  357. out(fillch);
  358. }
  359. break;
  360. case 'p':
  361. size = (sizeof(PVOID) == sizeof(LONG)) ? 1 : 3;
  362. if (prec == -1) {
  363. prec = 2 * sizeof(PVOID);
  364. }
  365. /*** FALL THROUGH to case 'X' ***/
  366. case 'X':
  367. upper++;
  368. /*** FALL THROUGH to case 'x' ***/
  369. case 'x':
  370. radix = 16;
  371. if (prefix)
  372. if (upper)
  373. prefix = 'X';
  374. else
  375. prefix = 'x';
  376. goto donumeric;
  377. case 'C':
  378. /*
  379. * explicit size specifier overrides case
  380. */
  381. if (!size && !hprefix) {
  382. size = 1; // force WCHAR
  383. }
  384. /*** FALL THROUGH to case 'c' ***/
  385. case 'c':
  386. /*
  387. * if size == 0, "%c" or "%hc" or "%tc" was specified (CHAR)
  388. * if size == 1, "%C" or "%lc" was specified (WCHAR);
  389. * if size == 2, "%wc" was specified (WCHAR)
  390. */
  391. cch = 1; /* One character must be copied to the output buffer */
  392. if (size) {
  393. val.wsz[0] = va_arg(varglist, WCHAR);
  394. val.wsz[1] = 0x0000;
  395. pwsz = val.wsz;
  396. goto putwstring;
  397. } else {
  398. val.sz[0] = va_arg(varglist, CHAR);
  399. val.sz[1] = 0;
  400. lpT = val.sz;
  401. goto putstring;
  402. }
  403. case 'S':
  404. /*
  405. * explicit size specifier overrides case
  406. */
  407. if (!size && !hprefix) {
  408. size = 1; // force LPWSTR
  409. }
  410. /*** FALL THROUGH to case 's' ***/
  411. case 's':
  412. /*
  413. * if size == 0, "%s" or "%hs" or "%ts" was specified (LPSTR);
  414. * if size == 1, "%S" or "%ls" was specified (LPWSTR);
  415. * if size == 2, "%ws" was specified (LPWSTR)
  416. */
  417. if (size) {
  418. pwsz = va_arg(varglist, LPWSTR);
  419. if (pwsz == NULL) {
  420. cch = 0;
  421. } else {
  422. cch = wcslen(pwsz);
  423. }
  424. putwstring:
  425. cch = WCSToMB(pwsz, cch, &lpTMB, -1, TRUE);
  426. fAllocateMem = (BOOL) cch;
  427. lpT = lpTMB;
  428. } else {
  429. lpT = va_arg(varglist, LPSTR);
  430. if (lpT == NULL) {
  431. cch = 0;
  432. } else {
  433. cch = strlen(lpT);
  434. }
  435. putstring:
  436. fAllocateMem = FALSE;
  437. }
  438. if (prec >= 0 && cch > prec)
  439. cch = prec;
  440. width -= cch;
  441. if (fAllocateMem) {
  442. if (cch + (width < 0 ? 0 : width) >= cchLimit) {
  443. UserLocalFree(lpTMB);
  444. goto errorout;
  445. }
  446. }
  447. if (left) {
  448. while (cch--)
  449. out(*lpT++);
  450. while (width-- > 0)
  451. out(fillch);
  452. } else {
  453. while (width-- > 0)
  454. out(fillch);
  455. while (cch--)
  456. out(*lpT++);
  457. }
  458. if (fAllocateMem) {
  459. UserLocalFree(lpTMB);
  460. }
  461. break;
  462. default:
  463. normalch:
  464. out(*lpFmt);
  465. break;
  466. } /* END OF SWITCH(*lpFmt) */
  467. } /* END OF IF(%) */ else
  468. goto normalch; /* character not a '%', just do it */
  469. /*
  470. * advance to next format string character
  471. */
  472. lpFmt++;
  473. } /* END OF OUTER WHILE LOOP */
  474. errorout:
  475. *lpOut = 0;
  476. return WSPRINTF_LIMIT - cchLimit;
  477. }
  478. /***************************************************************************\
  479. * StringPrintfA (API)
  480. *
  481. * Windows version of sprintf
  482. *
  483. * History:
  484. * 11-12-90 MikeHar Ported from windows 3
  485. * 02-05-90 DarrinM Cleaned up with STDARG.h vararg stuff.
  486. \***************************************************************************/
  487. int WINAPIV wsprintfA(
  488. LPSTR lpOut,
  489. LPCSTR lpFmt,
  490. ...)
  491. {
  492. va_list arglist;
  493. int ret;
  494. va_start(arglist, lpFmt);
  495. ret = wvsprintfA(lpOut, lpFmt, arglist);
  496. va_end(arglist);
  497. return ret;
  498. }
  499. /***************************************************************************\
  500. * SP_PutNumberW
  501. *
  502. * Takes an unsigned long integer and places it into a buffer, respecting
  503. * a buffer limit, a radix, and a case select (upper or lower, for hex).
  504. *
  505. *
  506. * History:
  507. * 11-12-90 MikeHar Ported from windows 3 asm --> C
  508. * 12-11-90 GregoryW need to increment lpstr after assignment of mod
  509. * 02-11-92 GregoryW temporary version until we have C runtime support
  510. \***************************************************************************/
  511. int SP_PutNumberW(
  512. LPWSTR lpstr,
  513. ULONG64 n,
  514. int limit,
  515. DWORD radix,
  516. int uppercase)
  517. {
  518. DWORD mod;
  519. int count = 0;
  520. /* It might not work for some locales or digit sets */
  521. if(uppercase)
  522. uppercase = 'A'-'0'-10;
  523. else
  524. uppercase = 'a'-'0'-10;
  525. if (count < limit) {
  526. do {
  527. mod = (ULONG)(n % radix);
  528. n /= radix;
  529. mod += '0';
  530. if (mod > '9')
  531. mod += uppercase;
  532. *lpstr++ = (WCHAR)mod;
  533. count++;
  534. } while((count < limit) && n);
  535. }
  536. return count;
  537. }
  538. /***************************************************************************\
  539. * SP_ReverseW
  540. *
  541. * reverses a string in place
  542. *
  543. * History:
  544. * 11-12-90 MikeHar Ported from windows 3 asm --> C
  545. * 12-11-90 GregoryW fixed boundary conditions; removed count
  546. * 02-11-92 GregoryW temporary version until we have C runtime support
  547. \***************************************************************************/
  548. void SP_ReverseW(
  549. LPWSTR lpFirst,
  550. LPWSTR lpLast)
  551. {
  552. WCHAR ch;
  553. while(lpLast > lpFirst){
  554. ch = *lpFirst;
  555. *lpFirst++ = *lpLast;
  556. *lpLast-- = ch;
  557. }
  558. }
  559. /***************************************************************************\
  560. * wvsprintfW (API)
  561. *
  562. * wsprintfW() calls this function.
  563. *
  564. * History:
  565. * 11-Feb-1992 GregoryW copied xwvsprintf
  566. * Temporary hack until we have C runtime support
  567. \***************************************************************************/
  568. FUNCLOG3(LOG_GENERAL, int, DUMMYCALLINGTYPE, wvsprintfW, LPWSTR, lpOut, LPCWSTR, lpFmt, va_list, arglist)
  569. int wvsprintfW(
  570. LPWSTR lpOut,
  571. LPCWSTR lpFmt,
  572. va_list arglist)
  573. {
  574. BOOL fAllocateMem;
  575. WCHAR prefix, fillch;
  576. int left, width, prec, size, sign, radix, upper, hprefix;
  577. int cchLimit = WSPRINTF_LIMIT, cch;
  578. LPWSTR lpT, lpTWC;
  579. LPBYTE psz;
  580. va_list varglist = arglist;
  581. union {
  582. LONG64 l;
  583. ULONG64 ul;
  584. char sz[2];
  585. WCHAR wsz[2];
  586. } val;
  587. while (*lpFmt != 0) {
  588. if (*lpFmt == L'%') {
  589. /*
  590. * read the flags. These can be in any order
  591. */
  592. left = 0;
  593. prefix = 0;
  594. while (*++lpFmt) {
  595. if (*lpFmt == L'-')
  596. left++;
  597. else if (*lpFmt == L'#')
  598. prefix++;
  599. else
  600. break;
  601. }
  602. /*
  603. * find fill character
  604. */
  605. if (*lpFmt == L'0') {
  606. fillch = L'0';
  607. lpFmt++;
  608. } else
  609. fillch = L' ';
  610. /*
  611. * read the width specification
  612. */
  613. lpFmt = SP_GetFmtValueW(lpFmt, &cch);
  614. width = cch;
  615. /*
  616. * read the precision
  617. */
  618. if (*lpFmt == L'.') {
  619. lpFmt = SP_GetFmtValueW(++lpFmt, &cch);
  620. prec = cch;
  621. } else
  622. prec = -1;
  623. /*
  624. * get the operand size
  625. * default size: size == 0
  626. * long number: size == 1
  627. * wide chars: size == 2
  628. * 64bit number: size == 3
  629. * It may be a good idea to check the value of size when it
  630. * is tested for non-zero below (IanJa)
  631. */
  632. hprefix = 0;
  633. if ((*lpFmt == L'w') || (*lpFmt == L't')) {
  634. size = 2;
  635. lpFmt++;
  636. } else if (*lpFmt == L'l') {
  637. size = 1;
  638. lpFmt++;
  639. } else if (*lpFmt == L'I') {
  640. if (*(lpFmt+1) == L'3' && *(lpFmt+2) == L'2') {
  641. size = 1;
  642. lpFmt += 3;
  643. } else if (*(lpFmt+1) == L'6' && *(lpFmt+2) == L'4') {
  644. size = 3;
  645. lpFmt += 3;
  646. } else {
  647. size = (sizeof(INT_PTR) == sizeof(LONG)) ? 1 : 3;
  648. lpFmt++;
  649. }
  650. } else {
  651. size = 0;
  652. if (*lpFmt == L'h') {
  653. lpFmt++;
  654. hprefix = 1;
  655. } else if ((*lpFmt == L'i') || (*lpFmt == L'd')) {
  656. // %i or %d specified (no modifiers) - use long
  657. // %u seems to have always been short - leave alone
  658. size = 1;
  659. }
  660. }
  661. upper = 0;
  662. sign = 0;
  663. radix = 10;
  664. switch (*lpFmt) {
  665. case 0:
  666. goto errorout;
  667. case L'i':
  668. case L'd':
  669. sign++;
  670. /*** FALL THROUGH to case 'u' ***/
  671. case L'u':
  672. /* turn off prefix if decimal */
  673. prefix = 0;
  674. donumeric:
  675. /* special cases to act like MSC v5.10 */
  676. if (left || prec >= 0)
  677. fillch = L' ';
  678. /*
  679. * if size == 1, "%lu" was specified (good);
  680. * if size == 2, "%wu" was specified (bad)
  681. * if size == 3, "%p" was specified
  682. */
  683. if (size == 3) {
  684. val.l = va_arg(varglist, LONG64);
  685. } else if (size) {
  686. val.l = va_arg(varglist, LONG);
  687. } else if (sign) {
  688. val.l = va_arg(varglist, SHORT);
  689. } else {
  690. val.ul = va_arg(varglist, unsigned);
  691. }
  692. if (sign && val.l < 0L)
  693. val.l = -val.l;
  694. else
  695. sign = 0;
  696. /*
  697. * Unless printing a full 64-bit value, ensure values
  698. * here are not in canonical longword format to prevent
  699. * the sign extended upper 32-bits from being printed.
  700. */
  701. if (size != 3) {
  702. val.l &= MAXULONG;
  703. }
  704. lpT = lpOut;
  705. /*
  706. * blast the number backwards into the user buffer
  707. */
  708. cch = SP_PutNumberW(lpOut, val.l, cchLimit, radix, upper);
  709. if (!(cchLimit -= cch))
  710. goto errorout;
  711. lpOut += cch;
  712. width -= cch;
  713. prec -= cch;
  714. if (prec > 0)
  715. width -= prec;
  716. /*
  717. * fill to the field precision
  718. */
  719. while (prec-- > 0)
  720. out(L'0');
  721. if (width > 0 && !left) {
  722. /*
  723. * if we're filling with spaces, put sign first
  724. */
  725. if (fillch != L'0') {
  726. if (sign) {
  727. sign = 0;
  728. out(L'-');
  729. width--;
  730. }
  731. if (prefix) {
  732. out(prefix);
  733. out(L'0');
  734. prefix = 0;
  735. }
  736. }
  737. if (sign)
  738. width--;
  739. /*
  740. * fill to the field width
  741. */
  742. while (width-- > 0)
  743. out(fillch);
  744. /*
  745. * still have a sign?
  746. */
  747. if (sign)
  748. out(L'-');
  749. if (prefix) {
  750. out(prefix);
  751. out(L'0');
  752. }
  753. /*
  754. * now reverse the string in place
  755. */
  756. SP_ReverseW(lpT, lpOut - 1);
  757. } else {
  758. /*
  759. * add the sign character
  760. */
  761. if (sign) {
  762. out(L'-');
  763. width--;
  764. }
  765. if (prefix) {
  766. out(prefix);
  767. out(L'0');
  768. }
  769. /*
  770. * reverse the string in place
  771. */
  772. SP_ReverseW(lpT, lpOut - 1);
  773. /*
  774. * pad to the right of the string in case left aligned
  775. */
  776. while (width-- > 0)
  777. out(fillch);
  778. }
  779. break;
  780. case L'p':
  781. size = (sizeof(PVOID) == sizeof(LONG)) ? 1 : 3;
  782. if (prec == -1) {
  783. prec = 2 * sizeof(PVOID);
  784. }
  785. /*** FALL THROUGH to case 'X' ***/
  786. case L'X':
  787. upper++;
  788. /*** FALL THROUGH to case 'x' ***/
  789. case L'x':
  790. radix = 16;
  791. if (prefix)
  792. if (upper)
  793. prefix = L'X';
  794. else
  795. prefix = L'x';
  796. goto donumeric;
  797. case L'c':
  798. if (!size && !hprefix) {
  799. size = 1; // force WCHAR
  800. }
  801. /*** FALL THROUGH to case 'C' ***/
  802. case L'C':
  803. /*
  804. * if size == 0, "%C" or "%hc" was specified (CHAR);
  805. * if size == 1, "%c" or "%lc" was specified (WCHAR);
  806. * if size == 2, "%wc" or "%tc" was specified (WCHAR)
  807. */
  808. cch = 1; /* One character must be copied to the output buffer */
  809. if (size) {
  810. val.wsz[0] = va_arg(varglist, WCHAR);
  811. val.wsz[1] = 0;
  812. lpT = val.wsz;
  813. goto putwstring;
  814. } else {
  815. val.sz[0] = va_arg(varglist, CHAR);
  816. val.sz[1] = 0;
  817. psz = val.sz;
  818. goto putstring;
  819. }
  820. case L's':
  821. if (!size && !hprefix) {
  822. size = 1; // force LPWSTR
  823. }
  824. /*** FALL THROUGH to case 'S' ***/
  825. case L'S':
  826. /*
  827. * if size == 0, "%S" or "%hs" was specified (LPSTR)
  828. * if size == 1, "%s" or "%ls" was specified (LPWSTR);
  829. * if size == 2, "%ws" or "%ts" was specified (LPWSTR)
  830. */
  831. if (size) {
  832. lpT = va_arg(varglist, LPWSTR);
  833. if (lpT == NULL) {
  834. cch = 0;
  835. } else {
  836. cch = wcslen(lpT);
  837. }
  838. putwstring:
  839. fAllocateMem = FALSE;
  840. } else {
  841. psz = va_arg(varglist, LPBYTE);
  842. if (psz == NULL) {
  843. cch = 0;
  844. } else {
  845. cch = strlen(psz);
  846. }
  847. putstring:
  848. cch = MBToWCS(psz, cch, &lpTWC, -1, TRUE);
  849. fAllocateMem = (BOOL) cch;
  850. lpT = lpTWC;
  851. }
  852. if (prec >= 0 && cch > prec)
  853. cch = prec;
  854. width -= cch;
  855. if (fAllocateMem) {
  856. if (cch + (width < 0 ? 0 : width) >= cchLimit) {
  857. UserLocalFree(lpTWC);
  858. goto errorout;
  859. }
  860. }
  861. if (left) {
  862. while (cch--)
  863. out(*lpT++);
  864. while (width-- > 0)
  865. out(fillch);
  866. } else {
  867. while (width-- > 0)
  868. out(fillch);
  869. while (cch--)
  870. out(*lpT++);
  871. }
  872. if (fAllocateMem) {
  873. UserLocalFree(lpTWC);
  874. }
  875. break;
  876. default:
  877. normalch:
  878. out((WCHAR)*lpFmt);
  879. break;
  880. } /* END OF SWITCH(*lpFmt) */
  881. } /* END OF IF(%) */ else
  882. goto normalch; /* character not a '%', just do it */
  883. /*
  884. * advance to next format string character
  885. */
  886. lpFmt++;
  887. } /* END OF OUTER WHILE LOOP */
  888. errorout:
  889. *lpOut = 0;
  890. return WSPRINTF_LIMIT - cchLimit;
  891. }
  892. int WINAPIV wsprintfW(
  893. LPWSTR lpOut,
  894. LPCWSTR lpFmt,
  895. ...)
  896. {
  897. va_list arglist;
  898. int ret;
  899. va_start(arglist, lpFmt);
  900. ret = wvsprintfW(lpOut, lpFmt, arglist);
  901. va_end(arglist);
  902. return ret;
  903. }