1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/strvararg.cpp
3 // Purpose: macros for implementing type-safe vararg passing of strings
4 // Author: Vaclav Slavik
5 // Created: 2007-02-19
6 // Copyright: (c) 2007 REA Elektronik GmbH
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9
10 // ============================================================================
11 // declarations
12 // ============================================================================
13
14 // ----------------------------------------------------------------------------
15 // headers
16 // ----------------------------------------------------------------------------
17
18 // for compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
20
21
22 #include "wx/strvararg.h"
23 #include "wx/string.h"
24 #include "wx/crt.h"
25 #include "wx/private/wxprintf.h"
26
27 // ============================================================================
28 // implementation
29 // ============================================================================
30
31 // ----------------------------------------------------------------------------
32 // wxArgNormalizer<>
33 // ----------------------------------------------------------------------------
34
get() const35 const wxStringCharType *wxArgNormalizerNative<const wxString&>::get() const
36 {
37 return m_value.wx_str();
38 }
39
get() const40 const wxStringCharType *wxArgNormalizerNative<const wxCStrData&>::get() const
41 {
42 return m_value.AsInternal();
43 }
44
45 #if wxUSE_UNICODE_UTF8 && !wxUSE_UTF8_LOCALE_ONLY
wxArgNormalizerWchar(const wxString & s,const wxFormatString * fmt,unsigned index)46 wxArgNormalizerWchar<const wxString&>::wxArgNormalizerWchar(
47 const wxString& s,
48 const wxFormatString *fmt, unsigned index)
49 : wxArgNormalizerWithBuffer<wchar_t>(s.wc_str(), fmt, index)
50 {
51 }
52
wxArgNormalizerWchar(const wxCStrData & s,const wxFormatString * fmt,unsigned index)53 wxArgNormalizerWchar<const wxCStrData&>::wxArgNormalizerWchar(
54 const wxCStrData& s,
55 const wxFormatString *fmt, unsigned index)
56 : wxArgNormalizerWithBuffer<wchar_t>(s.AsWCharBuf(), fmt, index)
57 {
58 }
59 #endif // wxUSE_UNICODE_UTF8 && !wxUSE_UTF8_LOCALE_ONLY
60
61 // ----------------------------------------------------------------------------
62 // wxArgNormalizedString
63 // ----------------------------------------------------------------------------
64
GetString() const65 wxString wxArgNormalizedString::GetString() const
66 {
67 if ( !IsValid() )
68 return wxEmptyString;
69
70 #if wxUSE_UTF8_LOCALE_ONLY
71 return wxString(reinterpret_cast<const char*>(m_ptr));
72 #else
73 #if wxUSE_UNICODE_UTF8
74 if ( wxLocaleIsUtf8 )
75 return wxString(reinterpret_cast<const char*>(m_ptr));
76 else
77 #endif
78 return wxString(reinterpret_cast<const wxChar*>(m_ptr));
79 #endif // !wxUSE_UTF8_LOCALE_ONLY
80 }
81
operator wxString() const82 wxArgNormalizedString::operator wxString() const
83 {
84 return GetString();
85 }
86
87 // ----------------------------------------------------------------------------
88 // wxFormatConverter: class doing the "%s" and "%c" normalization
89 // ----------------------------------------------------------------------------
90
91 /*
92 There are four problems with wxPrintf() etc. format strings:
93
94 1) The printf vararg macros convert all forms of strings into
95 wxStringCharType* representation. This may make the format string
96 incorrect: for example, if %ls was used together with a wchar_t*
97 variadic argument, this would no longer work, because the templates
98 would change wchar_t* argument to wxStringCharType* and %ls would now
99 be incorrect in e.g. UTF-8 build. We need make sure only one specifier
100 form is used.
101
102 2) To complicate matters further, the meaning of %s and %c is different
103 under Windows and on Unix. The Windows/MS convention is as follows:
104
105 In ANSI mode:
106
107 format specifier results in
108 -----------------------------------
109 %s, %hs, %hS char*
110 %ls, %S, %lS wchar_t*
111
112 In Unicode mode:
113
114 format specifier results in
115 -----------------------------------
116 %hs, %S, %hS char*
117 %s, %ls, %lS wchar_t*
118
119 (While on POSIX systems we have %C identical to %lc and %c always means
120 char (in any mode) while %lc always means wchar_t.)
121
122 In other words, we should _only_ use %s on Windows and %ls on Unix for
123 wxUSE_UNICODE_WCHAR build.
124
125 3) To make things even worse, we need two forms in UTF-8 build: one for
126 passing strings to ANSI functions under UTF-8 locales (this one should
127 use %s) and one for widechar functions used under non-UTF-8 locales
128 (this one should use %ls).
129
130 And, of course, the same should be done for %c as well.
131
132
133 wxScanf() family of functions is simpler, because we don't normalize their
134 variadic arguments and we only have to handle 2) above and only for widechar
135 versions.
136 */
137
138 template<typename T>
139 class wxFormatConverterBase
140 {
141 public:
142 typedef T CharType;
143
wxFormatConverterBase()144 wxFormatConverterBase()
145 {
146 m_fmtOrig = NULL;
147 m_fmtLast = NULL;
148 m_nCopied = 0;
149 }
150
Convert(const CharType * format)151 wxScopedCharTypeBuffer<CharType> Convert(const CharType *format)
152 {
153 // this is reset to NULL if we modify the format string
154 m_fmtOrig = format;
155
156 while ( *format )
157 {
158 if ( CopyFmtChar(*format++) == wxT('%') )
159 {
160 #if wxUSE_PRINTF_POS_PARAMS
161 if ( *format >= '0' && *format <= '9' )
162 {
163 SkipDigits(&format);
164 if ( *format == '$' )
165 {
166 // It was a positional argument specification.
167 CopyFmtChar(*format++);
168 }
169 //else: it was a width specification, nothing else to do.
170 }
171 #endif // wxUSE_PRINTF_POS_PARAMS
172
173 // skip any flags
174 while ( IsFlagChar(*format) )
175 CopyFmtChar(*format++);
176
177 // and possible width
178 if ( *format == wxT('*') )
179 CopyFmtChar(*format++);
180 else
181 SkipDigits(&format);
182
183 // precision?
184 if ( *format == wxT('.') )
185 {
186 CopyFmtChar(*format++);
187 if ( *format == wxT('*') )
188 CopyFmtChar(*format++);
189 else
190 SkipDigits(&format);
191 }
192
193 // next we can have a size modifier
194 SizeModifier size;
195
196 switch ( *format )
197 {
198 // MSVC doesn't support C99 'z' size modifier, but it uses
199 // 'I' with exactly the same meaning.
200 //
201 // MinGW does support 'z' but only in ANSI stdio mode, and
202 // we can't be sure that this is what is actually going to
203 // be used, application code could explicitly define
204 // __USE_MINGW_ANSI_STDIO=0 (e.g. because it needs legacy
205 // behaviour for its own printf() calls), so we map it to
206 // 'I' for it too.
207 #if defined(__VISUALC__) || defined(__MINGW32__)
208 case 'z':
209 ChangeFmtChar('I');
210 format++;
211 size = Size_Default;
212 break;
213 #endif // __VISUALC__ || __MINGW32__
214
215 case 'h':
216 size = Size_Short;
217 format++;
218 break;
219
220 case 'l':
221 // "ll" has a different meaning!
222 if ( format[1] != 'l' )
223 {
224 size = Size_Long;
225 format++;
226 break;
227 }
228 wxFALLTHROUGH;
229
230 default:
231 size = Size_Default;
232 }
233
234 CharType outConv = *format;
235 SizeModifier outSize = size;
236
237 // and finally we should have the type
238 switch ( *format )
239 {
240 case wxT('S'):
241 case wxT('s'):
242 // all strings were converted into the same form by
243 // wxArgNormalizer<T>, this form depends on the context
244 // in which the value is used (scanf/printf/wprintf):
245 HandleString(*format, size, outConv, outSize);
246 break;
247
248 case wxT('C'):
249 case wxT('c'):
250 HandleChar(*format, size, outConv, outSize);
251 break;
252
253 default:
254 // nothing special to do
255 break;
256 }
257
258 if ( outConv == *format && outSize == size ) // no change
259 {
260 if ( size != Size_Default )
261 CopyFmtChar(*(format - 1));
262 CopyFmtChar(*format);
263 }
264 else // something changed
265 {
266 switch ( outSize )
267 {
268 case Size_Long:
269 InsertFmtChar(wxT('l'));
270 break;
271
272 case Size_Short:
273 InsertFmtChar(wxT('h'));
274 break;
275
276 case Size_Default:
277 // nothing to do
278 break;
279 }
280 InsertFmtChar(outConv);
281 }
282
283 format++;
284 }
285 }
286
287 // notice that we only translated the string if m_fmtOrig == NULL (as
288 // set by CopyAllBefore()), otherwise we should simply use the original
289 // format
290 if ( m_fmtOrig )
291 {
292 return wxScopedCharTypeBuffer<CharType>::CreateNonOwned(m_fmtOrig);
293 }
294 else
295 {
296 // shrink converted format string to actual size (instead of
297 // over-sized allocation from CopyAllBefore()) and NUL-terminate
298 // it:
299 m_fmt.shrink(m_fmtLast - m_fmt.data());
300 return m_fmt;
301 }
302 }
303
~wxFormatConverterBase()304 virtual ~wxFormatConverterBase() {}
305
306 protected:
307 enum SizeModifier
308 {
309 Size_Default,
310 Size_Short,
311 Size_Long
312 };
313
314 // called to handle %S or %s; 'conv' is conversion specifier ('S' or 's'
315 // respectively), 'size' is the preceding size modifier; the new values of
316 // conversion and size specifiers must be written to outConv and outSize
317 virtual void HandleString(CharType conv, SizeModifier size,
318 CharType& outConv, SizeModifier& outSize) = 0;
319
320 // ditto for %C or %c
321 virtual void HandleChar(CharType conv, SizeModifier size,
322 CharType& outConv, SizeModifier& outSize) = 0;
323
324 private:
325 // copy another character to the translated format: this function does the
326 // copy if we are translating but doesn't do anything at all if we don't,
327 // so we don't create the translated format string at all unless we really
328 // need to (i.e. InsertFmtChar() is called)
CopyFmtChar(CharType ch)329 CharType CopyFmtChar(CharType ch)
330 {
331 if ( !m_fmtOrig )
332 {
333 // we're translating, do copy
334 *(m_fmtLast++) = ch;
335 }
336 else
337 {
338 // simply increase the count which should be copied by
339 // CopyAllBefore() later if needed
340 m_nCopied++;
341 }
342
343 return ch;
344 }
345
346 // insert an extra character
InsertFmtChar(CharType ch)347 void InsertFmtChar(CharType ch)
348 {
349 if ( m_fmtOrig )
350 {
351 // so far we haven't translated anything yet
352 CopyAllBefore();
353 }
354
355 *(m_fmtLast++) = ch;
356 }
357
358 // change a character
ChangeFmtChar(CharType ch)359 void ChangeFmtChar(CharType ch)
360 {
361 if ( m_fmtOrig )
362 {
363 // so far we haven't translated anything yet
364 CopyAllBefore();
365 }
366
367 *m_fmtLast++ = ch;
368 }
369
CopyAllBefore()370 void CopyAllBefore()
371 {
372 wxASSERT_MSG( m_fmtOrig && m_fmt.data() == NULL, "logic error" );
373
374 // the modified format string is guaranteed to be no longer than
375 // 3/2 of the original (worst case: the entire format string consists
376 // of "%s" repeated and is expanded to "%ls" on Unix), so we can
377 // allocate the buffer now and not worry about running out of space if
378 // we over-allocate a bit:
379 size_t fmtLen = wxStrlen(m_fmtOrig);
380 // worst case is of even length, so there's no rounding error in *3/2:
381 m_fmt.extend(fmtLen * 3 / 2);
382
383 if ( m_nCopied > 0 )
384 wxStrncpy(m_fmt.data(), m_fmtOrig, m_nCopied);
385 m_fmtLast = m_fmt.data() + m_nCopied;
386
387 // we won't need it any longer and resetting it also indicates that we
388 // modified the format
389 m_fmtOrig = NULL;
390 }
391
IsFlagChar(CharType ch)392 static bool IsFlagChar(CharType ch)
393 {
394 return ch == wxT('-') || ch == wxT('+') ||
395 ch == wxT('0') || ch == wxT(' ') || ch == wxT('#');
396 }
397
SkipDigits(const CharType ** ptpc)398 void SkipDigits(const CharType **ptpc)
399 {
400 while ( **ptpc >= wxT('0') && **ptpc <= wxT('9') )
401 CopyFmtChar(*(*ptpc)++);
402 }
403
404 // the translated format
405 wxCharTypeBuffer<CharType> m_fmt;
406 CharType *m_fmtLast;
407
408 // the original format
409 const CharType *m_fmtOrig;
410
411 // the number of characters already copied (i.e. already parsed, but left
412 // unmodified)
413 size_t m_nCopied;
414 };
415
416 // Distinguish between the traditional Windows (and MSVC) behaviour and Cygwin
417 // (which is always Unix-like) and MinGW. The last one is the most interesting
418 // case as it can behave either as MSVC (__USE_MINGW_ANSI_STDIO=0) or as POSIX
419 // (__USE_MINGW_ANSI_STDIO=1, which is explicitly set by including any standard
420 // C++ header such as e.g. <string>). Luckily, "%ls" and "%lc" work in both
421 // cases, at least for recent MinGW versions, so just use it always.
422 #if defined(__WINDOWS__) && \
423 !defined(__CYGWIN__) && \
424 !defined(__MINGW32__)
425
426 // on Windows, we should use %s and %c regardless of the build:
427 class wxPrintfFormatConverterWchar : public wxFormatConverterBase<wchar_t>
428 {
HandleString(CharType WXUNUSED (conv),SizeModifier WXUNUSED (size),CharType & outConv,SizeModifier & outSize)429 virtual void HandleString(CharType WXUNUSED(conv),
430 SizeModifier WXUNUSED(size),
431 CharType& outConv, SizeModifier& outSize)
432 {
433 outConv = 's';
434 outSize = Size_Default;
435 }
436
HandleChar(CharType WXUNUSED (conv),SizeModifier WXUNUSED (size),CharType & outConv,SizeModifier & outSize)437 virtual void HandleChar(CharType WXUNUSED(conv),
438 SizeModifier WXUNUSED(size),
439 CharType& outConv, SizeModifier& outSize)
440 {
441 outConv = 'c';
442 outSize = Size_Default;
443 }
444 };
445
446 #else // !__WINDOWS__
447
448 // on Unix, it's %s for ANSI functions and %ls for widechar:
449
450 #if !wxUSE_UTF8_LOCALE_ONLY
451 class wxPrintfFormatConverterWchar : public wxFormatConverterBase<wchar_t>
452 {
HandleString(CharType WXUNUSED (conv),SizeModifier WXUNUSED (size),CharType & outConv,SizeModifier & outSize)453 virtual void HandleString(CharType WXUNUSED(conv),
454 SizeModifier WXUNUSED(size),
455 CharType& outConv, SizeModifier& outSize) wxOVERRIDE
456 {
457 outConv = 's';
458 outSize = Size_Long;
459 }
460
HandleChar(CharType WXUNUSED (conv),SizeModifier WXUNUSED (size),CharType & outConv,SizeModifier & outSize)461 virtual void HandleChar(CharType WXUNUSED(conv),
462 SizeModifier WXUNUSED(size),
463 CharType& outConv, SizeModifier& outSize) wxOVERRIDE
464 {
465 outConv = 'c';
466 outSize = Size_Long;
467 }
468 };
469 #endif // !wxUSE_UTF8_LOCALE_ONLY
470
471 #endif // __WINDOWS__/!__WINDOWS__
472
473 #if wxUSE_UNICODE_UTF8
474 class wxPrintfFormatConverterUtf8 : public wxFormatConverterBase<char>
475 {
HandleString(CharType WXUNUSED (conv),SizeModifier WXUNUSED (size),CharType & outConv,SizeModifier & outSize)476 virtual void HandleString(CharType WXUNUSED(conv),
477 SizeModifier WXUNUSED(size),
478 CharType& outConv, SizeModifier& outSize) wxOVERRIDE
479 {
480 outConv = 's';
481 outSize = Size_Default;
482 }
483
HandleChar(CharType WXUNUSED (conv),SizeModifier WXUNUSED (size),CharType & outConv,SizeModifier & outSize)484 virtual void HandleChar(CharType WXUNUSED(conv),
485 SizeModifier WXUNUSED(size),
486 CharType& outConv, SizeModifier& outSize) wxOVERRIDE
487 {
488 // chars are represented using wchar_t in both builds, so this is
489 // the same as above
490 outConv = 'c';
491 outSize = Size_Long;
492 }
493 };
494 #endif // wxUSE_UNICODE_UTF8
495
496 #if !wxUSE_UNICODE // FIXME-UTF8: remove
497 class wxPrintfFormatConverterANSI : public wxFormatConverterBase<char>
498 {
HandleString(CharType WXUNUSED (conv),SizeModifier WXUNUSED (size),CharType & outConv,SizeModifier & outSize)499 virtual void HandleString(CharType WXUNUSED(conv),
500 SizeModifier WXUNUSED(size),
501 CharType& outConv, SizeModifier& outSize)
502 {
503 outConv = 's';
504 outSize = Size_Default;
505 }
506
HandleChar(CharType WXUNUSED (conv),SizeModifier WXUNUSED (size),CharType & outConv,SizeModifier & outSize)507 virtual void HandleChar(CharType WXUNUSED(conv),
508 SizeModifier WXUNUSED(size),
509 CharType& outConv, SizeModifier& outSize)
510 {
511 outConv = 'c';
512 outSize = Size_Default;
513 }
514 };
515 #endif // ANSI
516
517 #ifndef __WINDOWS__
518 /*
519
520 wxScanf() format translation is different, we need to translate %s to %ls
521 and %c to %lc on Unix (but not Windows and for widechar functions only!).
522
523 So to use native functions in order to get our semantics we must do the
524 following translations in Unicode mode:
525
526 wxWidgets specifier POSIX specifier
527 ----------------------------------------
528
529 %hc, %C, %hC %c
530 %c %lc
531
532 */
533 class wxScanfFormatConverterWchar : public wxFormatConverterBase<wchar_t>
534 {
HandleString(CharType conv,SizeModifier size,CharType & outConv,SizeModifier & outSize)535 virtual void HandleString(CharType conv, SizeModifier size,
536 CharType& outConv, SizeModifier& outSize) wxOVERRIDE
537 {
538 outConv = 's';
539 outSize = GetOutSize(conv == 'S', size);
540 }
541
HandleChar(CharType conv,SizeModifier size,CharType & outConv,SizeModifier & outSize)542 virtual void HandleChar(CharType conv, SizeModifier size,
543 CharType& outConv, SizeModifier& outSize) wxOVERRIDE
544 {
545 outConv = 'c';
546 outSize = GetOutSize(conv == 'C', size);
547 }
548
GetOutSize(bool convIsUpper,SizeModifier size)549 SizeModifier GetOutSize(bool convIsUpper, SizeModifier size)
550 {
551 // %S and %hS -> %s and %lS -> %ls
552 if ( convIsUpper )
553 {
554 if ( size == Size_Long )
555 return Size_Long;
556 else
557 return Size_Default;
558 }
559 else // %s or %c
560 {
561 if ( size == Size_Default )
562 return Size_Long;
563 else
564 return size;
565 }
566 }
567 };
568
wxScanfConvertFormatW(const wchar_t * format)569 const wxScopedWCharBuffer wxScanfConvertFormatW(const wchar_t *format)
570 {
571 return wxScanfFormatConverterWchar().Convert(format);
572 }
573 #endif // !__WINDOWS__
574
575
576 // ----------------------------------------------------------------------------
577 // wxFormatString
578 // ----------------------------------------------------------------------------
579
580 #if !wxUSE_UNICODE_WCHAR
InputAsChar()581 const char* wxFormatString::InputAsChar()
582 {
583 if ( m_char )
584 return m_char.data();
585
586 // in ANSI build, wx_str() returns char*, in UTF-8 build, this function
587 // is only called under UTF-8 locales, so we should return UTF-8 string,
588 // which is, again, what wx_str() returns:
589 if ( m_str )
590 return m_str->wx_str();
591
592 // ditto wxCStrData:
593 if ( m_cstr )
594 return m_cstr->AsInternal();
595
596 // the last case is that wide string was passed in: in that case, we need
597 // to convert it:
598 wxASSERT( m_wchar );
599
600 m_char = wxConvLibc.cWC2MB(m_wchar.data());
601
602 return m_char.data();
603 }
604
AsChar()605 const char* wxFormatString::AsChar()
606 {
607 if ( !m_convertedChar )
608 #if !wxUSE_UNICODE // FIXME-UTF8: remove this
609 m_convertedChar = wxPrintfFormatConverterANSI().Convert(InputAsChar());
610 #else
611 m_convertedChar = wxPrintfFormatConverterUtf8().Convert(InputAsChar());
612 #endif
613
614 return m_convertedChar.data();
615 }
616 #endif // !wxUSE_UNICODE_WCHAR
617
618 #if wxUSE_UNICODE && !wxUSE_UTF8_LOCALE_ONLY
InputAsWChar()619 const wchar_t* wxFormatString::InputAsWChar()
620 {
621 if ( m_wchar )
622 return m_wchar.data();
623
624 #if wxUSE_UNICODE_WCHAR
625 if ( m_str )
626 return m_str->wc_str();
627 if ( m_cstr )
628 return m_cstr->AsInternal();
629 #else // wxUSE_UNICODE_UTF8
630 if ( m_str )
631 {
632 m_wchar = m_str->wc_str();
633 return m_wchar.data();
634 }
635 if ( m_cstr )
636 {
637 m_wchar = m_cstr->AsWCharBuf();
638 return m_wchar.data();
639 }
640 #endif // wxUSE_UNICODE_WCHAR/UTF8
641
642 // the last case is that narrow string was passed in: in that case, we need
643 // to convert it:
644 wxASSERT( m_char );
645
646 m_wchar = wxConvLibc.cMB2WC(m_char.data());
647
648 return m_wchar.data();
649 }
650
AsWChar()651 const wchar_t* wxFormatString::AsWChar()
652 {
653 if ( !m_convertedWChar )
654 m_convertedWChar = wxPrintfFormatConverterWchar().Convert(InputAsWChar());
655
656 return m_convertedWChar.data();
657 }
658 #endif // wxUSE_UNICODE && !wxUSE_UTF8_LOCALE_ONLY
659
InputAsString() const660 wxString wxFormatString::InputAsString() const
661 {
662 if ( m_str )
663 return *m_str;
664 if ( m_cstr )
665 return m_cstr->AsString();
666 if ( m_wchar )
667 return wxString(m_wchar);
668 if ( m_char )
669 return wxString(m_char);
670
671 wxFAIL_MSG( "invalid wxFormatString - not initialized?" );
672 return wxString();
673 }
674
675 // ----------------------------------------------------------------------------
676 // wxFormatString::GetArgumentType()
677 // ----------------------------------------------------------------------------
678
679 namespace
680 {
681
682 template<typename CharType>
DoGetArgumentType(const CharType * format,unsigned n)683 wxFormatString::ArgumentType DoGetArgumentType(const CharType *format,
684 unsigned n)
685 {
686 wxCHECK_MSG( format, wxFormatString::Arg_Unknown,
687 "empty format string not allowed here" );
688
689 wxPrintfConvSpecParser<CharType> parser(format);
690
691 if ( n > parser.nargs )
692 {
693 // The n-th argument doesn't appear in the format string and is unused.
694 // This can happen e.g. if a translation of the format string is used
695 // and the translation language tends to avoid numbers in singular forms.
696 // The translator would then typically replace "%d" with "One" (e.g. in
697 // Hebrew). Passing too many vararg arguments does not harm, so its
698 // better to be more permissive here and allow legitimate uses in favour
699 // of catching harmless errors.
700 return wxFormatString::Arg_Unused;
701 }
702
703 wxCHECK_MSG( parser.pspec[n-1] != NULL, wxFormatString::Arg_Unknown,
704 "requested argument not found - invalid format string?" );
705
706 switch ( parser.pspec[n-1]->m_type )
707 {
708 case wxPAT_CHAR:
709 case wxPAT_WCHAR:
710 return wxFormatString::Arg_Char;
711
712 case wxPAT_PCHAR:
713 case wxPAT_PWCHAR:
714 return wxFormatString::Arg_String;
715
716 case wxPAT_INT:
717 return wxFormatString::Arg_Int;
718 case wxPAT_LONGINT:
719 return wxFormatString::Arg_LongInt;
720 #ifdef wxLongLong_t
721 case wxPAT_LONGLONGINT:
722 return wxFormatString::Arg_LongLongInt;
723 #endif
724 case wxPAT_SIZET:
725 return wxFormatString::Arg_Size_t;
726
727 case wxPAT_DOUBLE:
728 return wxFormatString::Arg_Double;
729 case wxPAT_LONGDOUBLE:
730 return wxFormatString::Arg_LongDouble;
731
732 case wxPAT_POINTER:
733 return wxFormatString::Arg_Pointer;
734
735 case wxPAT_NINT:
736 return wxFormatString::Arg_IntPtr;
737 case wxPAT_NSHORTINT:
738 return wxFormatString::Arg_ShortIntPtr;
739 case wxPAT_NLONGINT:
740 return wxFormatString::Arg_LongIntPtr;
741
742 case wxPAT_STAR:
743 // "*" requires argument of type int
744 return wxFormatString::Arg_Int;
745
746 case wxPAT_INVALID:
747 // (handled after the switch statement)
748 break;
749 }
750
751 // silence warning
752 wxFAIL_MSG( "unexpected argument type" );
753 return wxFormatString::Arg_Unknown;
754 }
755
756 } // anonymous namespace
757
GetArgumentType(unsigned n) const758 wxFormatString::ArgumentType wxFormatString::GetArgumentType(unsigned n) const
759 {
760 if ( m_char )
761 return DoGetArgumentType(m_char.data(), n);
762 else if ( m_wchar )
763 return DoGetArgumentType(m_wchar.data(), n);
764 else if ( m_str )
765 return DoGetArgumentType(m_str->wx_str(), n);
766 else if ( m_cstr )
767 return DoGetArgumentType(m_cstr->AsInternal(), n);
768
769 wxFAIL_MSG( "unreachable code" );
770 return Arg_Unknown;
771 }
772