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