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