wxprintf.h 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934
  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name: wx/private/wxprintf.h
  3. // Purpose: wxWidgets wxPrintf() implementation
  4. // Author: Ove Kaven
  5. // Modified by: Ron Lee, Francesco Montorsi
  6. // Created: 09/04/99
  7. // Copyright: (c) wxWidgets copyright
  8. // Licence: wxWindows licence
  9. /////////////////////////////////////////////////////////////////////////////
  10. #ifndef _WX_PRIVATE_WXPRINTF_H_
  11. #define _WX_PRIVATE_WXPRINTF_H_
  12. // ---------------------------------------------------------------------------
  13. // headers and macros
  14. // ---------------------------------------------------------------------------
  15. #include "wx/crt.h"
  16. #include "wx/log.h"
  17. #include "wx/utils.h"
  18. #include <string.h>
  19. // prefer snprintf over sprintf
  20. #if defined(__VISUALC__) || \
  21. (defined(__BORLANDC__) && __BORLANDC__ >= 0x540)
  22. #define system_sprintf(buff, max, flags, data) \
  23. ::_snprintf(buff, max, flags, data)
  24. #elif defined(HAVE_SNPRINTF)
  25. #define system_sprintf(buff, max, flags, data) \
  26. ::snprintf(buff, max, flags, data)
  27. #else // NB: at least sprintf() should always be available
  28. // since 'max' is not used in this case, wxVsnprintf() should always
  29. // ensure that 'buff' is big enough for all common needs
  30. // (see wxMAX_SVNPRINTF_FLAGBUFFER_LEN and wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN)
  31. #define system_sprintf(buff, max, flags, data) \
  32. ::sprintf(buff, flags, data)
  33. #define SYSTEM_SPRINTF_IS_UNSAFE
  34. #endif
  35. // ---------------------------------------------------------------------------
  36. // printf format string parsing
  37. // ---------------------------------------------------------------------------
  38. // some limits of our implementation
  39. #define wxMAX_SVNPRINTF_ARGUMENTS 64
  40. #define wxMAX_SVNPRINTF_FLAGBUFFER_LEN 32
  41. #define wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN 512
  42. // the conversion specifiers accepted by wxCRT_VsnprintfW
  43. enum wxPrintfArgType
  44. {
  45. wxPAT_INVALID = -1,
  46. wxPAT_INT, // %d, %i, %o, %u, %x, %X
  47. wxPAT_LONGINT, // %ld, etc
  48. #ifdef wxLongLong_t
  49. wxPAT_LONGLONGINT, // %Ld, etc
  50. #endif
  51. wxPAT_SIZET, // %zd, etc
  52. wxPAT_DOUBLE, // %e, %E, %f, %g, %G
  53. wxPAT_LONGDOUBLE, // %le, etc
  54. wxPAT_POINTER, // %p
  55. wxPAT_CHAR, // %hc (in ANSI mode: %c, too)
  56. wxPAT_WCHAR, // %lc (in Unicode mode: %c, too)
  57. wxPAT_PCHAR, // %s (related to a char *)
  58. wxPAT_PWCHAR, // %s (related to a wchar_t *)
  59. wxPAT_NINT, // %n
  60. wxPAT_NSHORTINT, // %hn
  61. wxPAT_NLONGINT, // %ln
  62. wxPAT_STAR // '*' used for width or precision
  63. };
  64. // an argument passed to wxCRT_VsnprintfW
  65. union wxPrintfArg
  66. {
  67. int pad_int; // %d, %i, %o, %u, %x, %X
  68. long int pad_longint; // %ld, etc
  69. #ifdef wxLongLong_t
  70. wxLongLong_t pad_longlongint; // %Ld, etc
  71. #endif
  72. size_t pad_sizet; // %zd, etc
  73. double pad_double; // %e, %E, %f, %g, %G
  74. long double pad_longdouble; // %le, etc
  75. void *pad_pointer; // %p
  76. char pad_char; // %hc (in ANSI mode: %c, too)
  77. wchar_t pad_wchar; // %lc (in Unicode mode: %c, too)
  78. void *pad_str; // %s
  79. int *pad_nint; // %n
  80. short int *pad_nshortint; // %hn
  81. long int *pad_nlongint; // %ln
  82. };
  83. // helper for converting string into either char* or wchar_t* depending
  84. // on the type of wxPrintfConvSpec<T> instantiation:
  85. template<typename CharType> struct wxPrintfStringHelper {};
  86. template<> struct wxPrintfStringHelper<char>
  87. {
  88. typedef const wxWX2MBbuf ConvertedType;
  89. static ConvertedType Convert(const wxString& s) { return s.mb_str(); }
  90. };
  91. template<> struct wxPrintfStringHelper<wchar_t>
  92. {
  93. typedef const wxWX2WCbuf ConvertedType;
  94. static ConvertedType Convert(const wxString& s) { return s.wc_str(); }
  95. };
  96. // Contains parsed data relative to a conversion specifier given to
  97. // wxCRT_VsnprintfW and parsed from the format string
  98. // NOTE: in C++ there is almost no difference between struct & classes thus
  99. // there is no performance gain by using a struct here...
  100. template<typename CharType>
  101. class wxPrintfConvSpec
  102. {
  103. public:
  104. // the position of the argument relative to this conversion specifier
  105. size_t m_pos;
  106. // the type of this conversion specifier
  107. wxPrintfArgType m_type;
  108. // the minimum and maximum width
  109. // when one of this var is set to -1 it means: use the following argument
  110. // in the stack as minimum/maximum width for this conversion specifier
  111. int m_nMinWidth, m_nMaxWidth;
  112. // does the argument need to the be aligned to left ?
  113. bool m_bAlignLeft;
  114. // pointer to the '%' of this conversion specifier in the format string
  115. // NOTE: this points somewhere in the string given to the Parse() function -
  116. // it's task of the caller ensure that memory is still valid !
  117. const CharType *m_pArgPos;
  118. // pointer to the last character of this conversion specifier in the
  119. // format string
  120. // NOTE: this points somewhere in the string given to the Parse() function -
  121. // it's task of the caller ensure that memory is still valid !
  122. const CharType *m_pArgEnd;
  123. // a little buffer where formatting flags like #+\.hlqLz are stored by Parse()
  124. // for use in Process()
  125. char m_szFlags[wxMAX_SVNPRINTF_FLAGBUFFER_LEN];
  126. public:
  127. // we don't declare this as a constructor otherwise it would be called
  128. // automatically and we don't want this: to be optimized, wxCRT_VsnprintfW
  129. // calls this function only on really-used instances of this class.
  130. void Init();
  131. // Parses the first conversion specifier in the given string, which must
  132. // begin with a '%'. Returns false if the first '%' does not introduce a
  133. // (valid) conversion specifier and thus should be ignored.
  134. bool Parse(const CharType *format);
  135. // Process this conversion specifier and puts the result in the given
  136. // buffer. Returns the number of characters written in 'buf' or -1 if
  137. // there's not enough space.
  138. int Process(CharType *buf, size_t lenMax, wxPrintfArg *p, size_t written);
  139. // Loads the argument of this conversion specifier from given va_list.
  140. bool LoadArg(wxPrintfArg *p, va_list &argptr);
  141. private:
  142. // An helper function of LoadArg() which is used to handle the '*' flag
  143. void ReplaceAsteriskWith(int w);
  144. };
  145. template<typename CharType>
  146. void wxPrintfConvSpec<CharType>::Init()
  147. {
  148. m_nMinWidth = 0;
  149. m_nMaxWidth = 0xFFFF;
  150. m_pos = 0;
  151. m_bAlignLeft = false;
  152. m_pArgPos = m_pArgEnd = NULL;
  153. m_type = wxPAT_INVALID;
  154. memset(m_szFlags, 0, sizeof(m_szFlags));
  155. // this character will never be removed from m_szFlags array and
  156. // is important when calling sprintf() in wxPrintfConvSpec::Process() !
  157. m_szFlags[0] = '%';
  158. }
  159. template<typename CharType>
  160. bool wxPrintfConvSpec<CharType>::Parse(const CharType *format)
  161. {
  162. bool done = false;
  163. // temporary parse data
  164. size_t flagofs = 1;
  165. bool in_prec, // true if we found the dot in some previous iteration
  166. prec_dot; // true if the dot has been already added to m_szFlags
  167. int ilen = 0;
  168. m_bAlignLeft = in_prec = prec_dot = false;
  169. m_pArgPos = m_pArgEnd = format;
  170. do
  171. {
  172. #define CHECK_PREC \
  173. if (in_prec && !prec_dot) \
  174. { \
  175. m_szFlags[flagofs++] = '.'; \
  176. prec_dot = true; \
  177. }
  178. // what follows '%'?
  179. const CharType ch = *(++m_pArgEnd);
  180. switch ( ch )
  181. {
  182. case wxT('\0'):
  183. return false; // not really an argument
  184. case wxT('%'):
  185. return false; // not really an argument
  186. case wxT('#'):
  187. case wxT('0'):
  188. case wxT(' '):
  189. case wxT('+'):
  190. case wxT('\''):
  191. CHECK_PREC
  192. m_szFlags[flagofs++] = char(ch);
  193. break;
  194. case wxT('-'):
  195. CHECK_PREC
  196. m_bAlignLeft = true;
  197. m_szFlags[flagofs++] = char(ch);
  198. break;
  199. case wxT('.'):
  200. // don't use CHECK_PREC here to avoid warning about the value
  201. // assigned to prec_dot inside it being never used (because
  202. // overwritten just below) from Borland in release build
  203. if (in_prec && !prec_dot)
  204. m_szFlags[flagofs++] = '.';
  205. in_prec = true;
  206. prec_dot = false;
  207. m_nMaxWidth = 0;
  208. // dot will be auto-added to m_szFlags if non-negative
  209. // number follows
  210. break;
  211. case wxT('h'):
  212. ilen = -1;
  213. CHECK_PREC
  214. m_szFlags[flagofs++] = char(ch);
  215. break;
  216. case wxT('l'):
  217. // NB: it's safe to use flagofs-1 as flagofs always start from 1
  218. if (m_szFlags[flagofs-1] == 'l') // 'll' modifier is the same as 'L' or 'q'
  219. ilen = 2;
  220. else
  221. ilen = 1;
  222. CHECK_PREC
  223. m_szFlags[flagofs++] = char(ch);
  224. break;
  225. case wxT('q'):
  226. case wxT('L'):
  227. ilen = 2;
  228. CHECK_PREC
  229. m_szFlags[flagofs++] = char(ch);
  230. break;
  231. #ifdef __WINDOWS__
  232. // under Windows we support the special '%I64' notation as longlong
  233. // integer conversion specifier for MSVC compatibility
  234. // (it behaves exactly as '%lli' or '%Li' or '%qi')
  235. case wxT('I'):
  236. if (*(m_pArgEnd+1) == wxT('6') &&
  237. *(m_pArgEnd+2) == wxT('4'))
  238. {
  239. m_pArgEnd++;
  240. m_pArgEnd++;
  241. ilen = 2;
  242. CHECK_PREC
  243. m_szFlags[flagofs++] = char(ch);
  244. m_szFlags[flagofs++] = '6';
  245. m_szFlags[flagofs++] = '4';
  246. break;
  247. }
  248. // else: fall-through, 'I' is MSVC equivalent of C99 'z'
  249. #endif // __WINDOWS__
  250. case wxT('z'):
  251. case wxT('Z'):
  252. // 'z' is C99 standard for size_t and ptrdiff_t, 'Z' was used
  253. // for this purpose in libc5 and by wx <= 2.8
  254. ilen = 3;
  255. CHECK_PREC
  256. m_szFlags[flagofs++] = char(ch);
  257. break;
  258. case wxT('*'):
  259. if (in_prec)
  260. {
  261. CHECK_PREC
  262. // tell Process() to use the next argument
  263. // in the stack as maxwidth...
  264. m_nMaxWidth = -1;
  265. }
  266. else
  267. {
  268. // tell Process() to use the next argument
  269. // in the stack as minwidth...
  270. m_nMinWidth = -1;
  271. }
  272. // save the * in our formatting buffer...
  273. // will be replaced later by Process()
  274. m_szFlags[flagofs++] = char(ch);
  275. break;
  276. case wxT('1'): case wxT('2'): case wxT('3'):
  277. case wxT('4'): case wxT('5'): case wxT('6'):
  278. case wxT('7'): case wxT('8'): case wxT('9'):
  279. {
  280. int len = 0;
  281. CHECK_PREC
  282. while ( (*m_pArgEnd >= CharType('0')) &&
  283. (*m_pArgEnd <= CharType('9')) )
  284. {
  285. m_szFlags[flagofs++] = char(*m_pArgEnd);
  286. len = len*10 + (*m_pArgEnd - wxT('0'));
  287. m_pArgEnd++;
  288. }
  289. if (in_prec)
  290. m_nMaxWidth = len;
  291. else
  292. m_nMinWidth = len;
  293. m_pArgEnd--; // the main loop pre-increments n again
  294. }
  295. break;
  296. case wxT('$'): // a positional parameter (e.g. %2$s) ?
  297. {
  298. if (m_nMinWidth <= 0)
  299. break; // ignore this formatting flag as no
  300. // numbers are preceding it
  301. // remove from m_szFlags all digits previously added
  302. do {
  303. flagofs--;
  304. } while (m_szFlags[flagofs] >= '1' &&
  305. m_szFlags[flagofs] <= '9');
  306. // re-adjust the offset making it point to the
  307. // next free char of m_szFlags
  308. flagofs++;
  309. m_pos = m_nMinWidth;
  310. m_nMinWidth = 0;
  311. }
  312. break;
  313. case wxT('d'):
  314. case wxT('i'):
  315. case wxT('o'):
  316. case wxT('u'):
  317. case wxT('x'):
  318. case wxT('X'):
  319. CHECK_PREC
  320. m_szFlags[flagofs++] = char(ch);
  321. if (ilen == 0)
  322. m_type = wxPAT_INT;
  323. else if (ilen == -1)
  324. // NB: 'short int' value passed through '...'
  325. // is promoted to 'int', so we have to get
  326. // an int from stack even if we need a short
  327. m_type = wxPAT_INT;
  328. else if (ilen == 1)
  329. m_type = wxPAT_LONGINT;
  330. else if (ilen == 2)
  331. #ifdef wxLongLong_t
  332. m_type = wxPAT_LONGLONGINT;
  333. #else // !wxLongLong_t
  334. m_type = wxPAT_LONGINT;
  335. #endif // wxLongLong_t/!wxLongLong_t
  336. else if (ilen == 3)
  337. m_type = wxPAT_SIZET;
  338. done = true;
  339. break;
  340. case wxT('e'):
  341. case wxT('E'):
  342. case wxT('f'):
  343. case wxT('g'):
  344. case wxT('G'):
  345. CHECK_PREC
  346. m_szFlags[flagofs++] = char(ch);
  347. if (ilen == 2)
  348. m_type = wxPAT_LONGDOUBLE;
  349. else
  350. m_type = wxPAT_DOUBLE;
  351. done = true;
  352. break;
  353. case wxT('p'):
  354. m_type = wxPAT_POINTER;
  355. m_szFlags[flagofs++] = char(ch);
  356. done = true;
  357. break;
  358. case wxT('c'):
  359. if (ilen == -1)
  360. {
  361. // in Unicode mode %hc == ANSI character
  362. // and in ANSI mode, %hc == %c == ANSI...
  363. m_type = wxPAT_CHAR;
  364. }
  365. else if (ilen == 1)
  366. {
  367. // in ANSI mode %lc == Unicode character
  368. // and in Unicode mode, %lc == %c == Unicode...
  369. m_type = wxPAT_WCHAR;
  370. }
  371. else
  372. {
  373. #if wxUSE_UNICODE
  374. // in Unicode mode, %c == Unicode character
  375. m_type = wxPAT_WCHAR;
  376. #else
  377. // in ANSI mode, %c == ANSI character
  378. m_type = wxPAT_CHAR;
  379. #endif
  380. }
  381. done = true;
  382. break;
  383. case wxT('s'):
  384. if (ilen == -1)
  385. {
  386. // Unicode mode wx extension: we'll let %hs mean non-Unicode
  387. // strings (when in ANSI mode, %s == %hs == ANSI string)
  388. m_type = wxPAT_PCHAR;
  389. }
  390. else if (ilen == 1)
  391. {
  392. // in Unicode mode, %ls == %s == Unicode string
  393. // in ANSI mode, %ls == Unicode string
  394. m_type = wxPAT_PWCHAR;
  395. }
  396. else
  397. {
  398. #if wxUSE_UNICODE
  399. m_type = wxPAT_PWCHAR;
  400. #else
  401. m_type = wxPAT_PCHAR;
  402. #endif
  403. }
  404. done = true;
  405. break;
  406. case wxT('n'):
  407. if (ilen == 0)
  408. m_type = wxPAT_NINT;
  409. else if (ilen == -1)
  410. m_type = wxPAT_NSHORTINT;
  411. else if (ilen >= 1)
  412. m_type = wxPAT_NLONGINT;
  413. done = true;
  414. break;
  415. default:
  416. // bad format, don't consider this an argument;
  417. // leave it unchanged
  418. return false;
  419. }
  420. if (flagofs == wxMAX_SVNPRINTF_FLAGBUFFER_LEN)
  421. {
  422. wxLogDebug(wxT("Too many flags specified for a single conversion specifier!"));
  423. return false;
  424. }
  425. }
  426. while (!done);
  427. return true; // parsing was successful
  428. }
  429. template<typename CharType>
  430. void wxPrintfConvSpec<CharType>::ReplaceAsteriskWith(int width)
  431. {
  432. char temp[wxMAX_SVNPRINTF_FLAGBUFFER_LEN];
  433. // find the first * in our flag buffer
  434. char *pwidth = strchr(m_szFlags, '*');
  435. wxCHECK_RET(pwidth, wxT("field width must be specified"));
  436. // save what follows the * (the +1 is to skip the asterisk itself!)
  437. strcpy(temp, pwidth+1);
  438. if (width < 0)
  439. {
  440. pwidth[0] = wxT('-');
  441. pwidth++;
  442. }
  443. // replace * with the actual integer given as width
  444. #ifndef SYSTEM_SPRINTF_IS_UNSAFE
  445. int maxlen = (m_szFlags + wxMAX_SVNPRINTF_FLAGBUFFER_LEN - pwidth) /
  446. sizeof(*m_szFlags);
  447. #endif
  448. int offset = system_sprintf(pwidth, maxlen, "%d", abs(width));
  449. // restore after the expanded * what was following it
  450. strcpy(pwidth+offset, temp);
  451. }
  452. template<typename CharType>
  453. bool wxPrintfConvSpec<CharType>::LoadArg(wxPrintfArg *p, va_list &argptr)
  454. {
  455. // did the '*' width/precision specifier was used ?
  456. if (m_nMaxWidth == -1)
  457. {
  458. // take the maxwidth specifier from the stack
  459. m_nMaxWidth = va_arg(argptr, int);
  460. if (m_nMaxWidth < 0)
  461. m_nMaxWidth = 0;
  462. else
  463. ReplaceAsteriskWith(m_nMaxWidth);
  464. }
  465. if (m_nMinWidth == -1)
  466. {
  467. // take the minwidth specifier from the stack
  468. m_nMinWidth = va_arg(argptr, int);
  469. ReplaceAsteriskWith(m_nMinWidth);
  470. if (m_nMinWidth < 0)
  471. {
  472. m_bAlignLeft = !m_bAlignLeft;
  473. m_nMinWidth = -m_nMinWidth;
  474. }
  475. }
  476. switch (m_type) {
  477. case wxPAT_INT:
  478. p->pad_int = va_arg(argptr, int);
  479. break;
  480. case wxPAT_LONGINT:
  481. p->pad_longint = va_arg(argptr, long int);
  482. break;
  483. #ifdef wxLongLong_t
  484. case wxPAT_LONGLONGINT:
  485. p->pad_longlongint = va_arg(argptr, wxLongLong_t);
  486. break;
  487. #endif // wxLongLong_t
  488. case wxPAT_SIZET:
  489. p->pad_sizet = va_arg(argptr, size_t);
  490. break;
  491. case wxPAT_DOUBLE:
  492. p->pad_double = va_arg(argptr, double);
  493. break;
  494. case wxPAT_LONGDOUBLE:
  495. p->pad_longdouble = va_arg(argptr, long double);
  496. break;
  497. case wxPAT_POINTER:
  498. p->pad_pointer = va_arg(argptr, void *);
  499. break;
  500. case wxPAT_CHAR:
  501. p->pad_char = (char)va_arg(argptr, int); // char is promoted to int when passed through '...'
  502. break;
  503. case wxPAT_WCHAR:
  504. p->pad_wchar = (wchar_t)va_arg(argptr, int); // char is promoted to int when passed through '...'
  505. break;
  506. case wxPAT_PCHAR:
  507. case wxPAT_PWCHAR:
  508. p->pad_str = va_arg(argptr, void *);
  509. break;
  510. case wxPAT_NINT:
  511. p->pad_nint = va_arg(argptr, int *);
  512. break;
  513. case wxPAT_NSHORTINT:
  514. p->pad_nshortint = va_arg(argptr, short int *);
  515. break;
  516. case wxPAT_NLONGINT:
  517. p->pad_nlongint = va_arg(argptr, long int *);
  518. break;
  519. case wxPAT_STAR:
  520. // this will be handled as part of the next argument
  521. return true;
  522. case wxPAT_INVALID:
  523. default:
  524. return false;
  525. }
  526. return true; // loading was successful
  527. }
  528. template<typename CharType>
  529. int wxPrintfConvSpec<CharType>::Process(CharType *buf, size_t lenMax, wxPrintfArg *p, size_t written)
  530. {
  531. // buffer to avoid dynamic memory allocation each time for small strings;
  532. // note that this buffer is used only to hold results of number formatting,
  533. // %s directly writes user's string in buf, without using szScratch
  534. char szScratch[wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN];
  535. size_t lenScratch = 0, lenCur = 0;
  536. #define APPEND_CH(ch) \
  537. { \
  538. if ( lenCur == lenMax ) \
  539. return -1; \
  540. \
  541. buf[lenCur++] = ch; \
  542. }
  543. switch ( m_type )
  544. {
  545. case wxPAT_INT:
  546. lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_int);
  547. break;
  548. case wxPAT_LONGINT:
  549. lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_longint);
  550. break;
  551. #ifdef wxLongLong_t
  552. case wxPAT_LONGLONGINT:
  553. lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_longlongint);
  554. break;
  555. #endif // SIZEOF_LONG_LONG
  556. case wxPAT_SIZET:
  557. lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_sizet);
  558. break;
  559. case wxPAT_LONGDOUBLE:
  560. lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_longdouble);
  561. break;
  562. case wxPAT_DOUBLE:
  563. lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_double);
  564. break;
  565. case wxPAT_POINTER:
  566. lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_pointer);
  567. break;
  568. case wxPAT_CHAR:
  569. case wxPAT_WCHAR:
  570. {
  571. wxUniChar ch;
  572. if (m_type == wxPAT_CHAR)
  573. ch = p->pad_char;
  574. else // m_type == wxPAT_WCHAR
  575. ch = p->pad_wchar;
  576. CharType val = ch;
  577. size_t i;
  578. if (!m_bAlignLeft)
  579. for (i = 1; i < (size_t)m_nMinWidth; i++)
  580. APPEND_CH(wxT(' '));
  581. APPEND_CH(val);
  582. if (m_bAlignLeft)
  583. for (i = 1; i < (size_t)m_nMinWidth; i++)
  584. APPEND_CH(wxT(' '));
  585. }
  586. break;
  587. case wxPAT_PCHAR:
  588. case wxPAT_PWCHAR:
  589. {
  590. wxString s;
  591. if ( !p->pad_str )
  592. {
  593. if ( m_nMaxWidth >= 6 )
  594. s = wxT("(null)");
  595. }
  596. else if (m_type == wxPAT_PCHAR)
  597. s.assign(static_cast<const char *>(p->pad_str));
  598. else // m_type == wxPAT_PWCHAR
  599. s.assign(static_cast<const wchar_t *>(p->pad_str));
  600. typename wxPrintfStringHelper<CharType>::ConvertedType strbuf(
  601. wxPrintfStringHelper<CharType>::Convert(s));
  602. // at this point we are sure that m_nMaxWidth is positive or
  603. // null (see top of wxPrintfConvSpec::LoadArg)
  604. int len = wxMin((unsigned int)m_nMaxWidth, wxStrlen(strbuf));
  605. int i;
  606. if (!m_bAlignLeft)
  607. {
  608. for (i = len; i < m_nMinWidth; i++)
  609. APPEND_CH(wxT(' '));
  610. }
  611. len = wxMin((unsigned int)len, lenMax-lenCur);
  612. wxStrncpy(buf+lenCur, strbuf, len);
  613. lenCur += len;
  614. if (m_bAlignLeft)
  615. {
  616. for (i = len; i < m_nMinWidth; i++)
  617. APPEND_CH(wxT(' '));
  618. }
  619. }
  620. break;
  621. case wxPAT_NINT:
  622. *p->pad_nint = written;
  623. break;
  624. case wxPAT_NSHORTINT:
  625. *p->pad_nshortint = (short int)written;
  626. break;
  627. case wxPAT_NLONGINT:
  628. *p->pad_nlongint = written;
  629. break;
  630. case wxPAT_INVALID:
  631. default:
  632. return -1;
  633. }
  634. // if we used system's sprintf() then we now need to append the s_szScratch
  635. // buffer to the given one...
  636. switch (m_type)
  637. {
  638. case wxPAT_INT:
  639. case wxPAT_LONGINT:
  640. #ifdef wxLongLong_t
  641. case wxPAT_LONGLONGINT:
  642. #endif
  643. case wxPAT_SIZET:
  644. case wxPAT_LONGDOUBLE:
  645. case wxPAT_DOUBLE:
  646. case wxPAT_POINTER:
  647. wxASSERT(lenScratch < wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN);
  648. // NB: 1) we can compare lenMax (for CharType*, i.e. possibly
  649. // wchar_t*) with lenScratch (char*) because this code is
  650. // formatting integers and that will have the same length
  651. // even in UTF-8 (the only case when char* length may be
  652. // more than wchar_t* length of the same string)
  653. // 2) wxStrncpy converts the 2nd argument to 1st argument's
  654. // type transparently if their types differ, so this code
  655. // works for both instantiations
  656. if (lenMax < lenScratch)
  657. {
  658. // fill output buffer and then return -1
  659. wxStrncpy(buf, szScratch, lenMax);
  660. return -1;
  661. }
  662. wxStrncpy(buf, szScratch, lenScratch);
  663. lenCur += lenScratch;
  664. break;
  665. default:
  666. break; // all other cases were completed previously
  667. }
  668. return lenCur;
  669. }
  670. // helper that parses format string
  671. template<typename CharType>
  672. struct wxPrintfConvSpecParser
  673. {
  674. typedef wxPrintfConvSpec<CharType> ConvSpec;
  675. wxPrintfConvSpecParser(const CharType *fmt)
  676. {
  677. nargs = 0;
  678. posarg_present =
  679. nonposarg_present = false;
  680. memset(pspec, 0, sizeof(pspec));
  681. // parse the format string
  682. for ( const CharType *toparse = fmt; *toparse != wxT('\0'); toparse++ )
  683. {
  684. // skip everything except format specifications
  685. if ( *toparse != '%' )
  686. continue;
  687. // also skip escaped percent signs
  688. if ( toparse[1] == '%' )
  689. {
  690. toparse++;
  691. continue;
  692. }
  693. ConvSpec *spec = &specs[nargs];
  694. spec->Init();
  695. // attempt to parse this format specification
  696. if ( !spec->Parse(toparse) )
  697. continue;
  698. // advance to the end of this specifier
  699. toparse = spec->m_pArgEnd;
  700. // special handling for specifications including asterisks: we need
  701. // to reserve an extra slot (or two if asterisks were used for both
  702. // width and precision) in specs array in this case
  703. if ( const char *f = strchr(spec->m_szFlags, '*') )
  704. {
  705. unsigned numAsterisks = 1;
  706. if ( strchr(++f, '*') )
  707. numAsterisks++;
  708. for ( unsigned n = 0; n < numAsterisks; n++ )
  709. {
  710. if ( nargs++ == wxMAX_SVNPRINTF_ARGUMENTS )
  711. break;
  712. // TODO: we need to support specifiers of the form "%2$*1$s"
  713. // (this is the same as "%*s") as if any positional arguments
  714. // are used all asterisks must be positional as well but this
  715. // requires a lot of changes in this code (basically we'd need
  716. // to rewrite Parse() to return "*" and conversion itself as
  717. // separate entries)
  718. if ( posarg_present )
  719. {
  720. wxFAIL_MSG
  721. (
  722. wxString::Format
  723. (
  724. "Format string \"%s\" uses both positional "
  725. "parameters and '*' but this is not currently "
  726. "supported by this implementation, sorry.",
  727. fmt
  728. )
  729. );
  730. }
  731. specs[nargs] = *spec;
  732. // make an entry for '*' and point to it from pspec
  733. spec->Init();
  734. spec->m_type = wxPAT_STAR;
  735. pspec[nargs - 1] = spec;
  736. spec = &specs[nargs];
  737. }
  738. }
  739. // check if this is a positional or normal argument
  740. if ( spec->m_pos > 0 )
  741. {
  742. // the positional arguments start from number 1 so we need
  743. // to adjust the index
  744. spec->m_pos--;
  745. posarg_present = true;
  746. }
  747. else // not a positional argument...
  748. {
  749. spec->m_pos = nargs;
  750. nonposarg_present = true;
  751. }
  752. // this conversion specifier is tied to the pos-th argument...
  753. pspec[spec->m_pos] = spec;
  754. if ( nargs++ == wxMAX_SVNPRINTF_ARGUMENTS )
  755. break;
  756. }
  757. // warn if we lost any arguments (the program probably will crash
  758. // anyhow because of stack corruption...)
  759. if ( nargs == wxMAX_SVNPRINTF_ARGUMENTS )
  760. {
  761. wxFAIL_MSG
  762. (
  763. wxString::Format
  764. (
  765. "wxVsnprintf() currently supports only %d arguments, "
  766. "but format string \"%s\" defines more of them.\n"
  767. "You need to change wxMAX_SVNPRINTF_ARGUMENTS and "
  768. "recompile if more are really needed.",
  769. fmt, wxMAX_SVNPRINTF_ARGUMENTS
  770. )
  771. );
  772. }
  773. }
  774. // total number of valid elements in specs
  775. unsigned nargs;
  776. // all format specifications in this format string in order of their
  777. // appearance (which may be different from arguments order)
  778. ConvSpec specs[wxMAX_SVNPRINTF_ARGUMENTS];
  779. // pointer to specs array element for the N-th argument
  780. ConvSpec *pspec[wxMAX_SVNPRINTF_ARGUMENTS];
  781. // true if any positional/non-positional parameters are used
  782. bool posarg_present,
  783. nonposarg_present;
  784. };
  785. #undef APPEND_CH
  786. #undef CHECK_PREC
  787. #endif // _WX_PRIVATE_WXPRINTF_H_