1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/wxprintf.cpp
3 // Purpose: wxWidgets wxPrintf() implementation
5 // Modified by: Ron Lee, Francesco Montorsi
8 // Copyright: (c) wxWidgets copyright
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
13 // headers, declarations, constants
14 // ===========================================================================
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
28 #include "wx/string.h"
30 #include "wx/utils.h" // for wxMin and wxMax
34 #if defined(__MWERKS__) && __MSL__ >= 0x6000
40 // ============================================================================
41 // printf() implementation
42 // ============================================================================
44 // special test mode: define all functions below even if we don't really need
45 // them to be able to test them
47 #undef wxCRT_VsnprintfW_
50 // ----------------------------------------------------------------------------
51 // implement [v]snprintf() if the system doesn't provide a safe one
52 // or if the system's one does not support positional parameters
53 // (very useful for i18n purposes)
54 // ----------------------------------------------------------------------------
56 #if !defined(wxCRT_VsnprintfW_)
58 #if !wxUSE_WXVSNPRINTFW
59 #error "wxUSE_WXVSNPRINTFW must be 1 if our wxCRT_VsnprintfW_ is used"
62 // wxUSE_STRUTILS says our wxCRT_VsnprintfW_ implementation to use or not to
63 // use wxStrlen and wxStrncpy functions over one-char processing loops.
65 // Some benchmarking revealed that wxUSE_STRUTILS == 1 has the following
68 // when in ANSI mode, this setting does not change almost anything
69 // when in Unicode mode, it gives ~ 50% of slowdown !
71 // both in ANSI and Unicode mode it gives ~ 60% of speedup !
73 #if defined(WIN32) && wxUSE_UNICODE
74 #define wxUSE_STRUTILS 0
76 #define wxUSE_STRUTILS 1
79 // some limits of our implementation
80 #define wxMAX_SVNPRINTF_ARGUMENTS 64
81 #define wxMAX_SVNPRINTF_FLAGBUFFER_LEN 32
82 #define wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN 512
84 // prefer snprintf over sprintf
85 #if defined(__VISUALC__) || \
86 (defined(__BORLANDC__) && __BORLANDC__ >= 0x540)
87 #define system_sprintf(buff, max, flags, data) \
88 ::_snprintf(buff, max, flags, data)
89 #elif defined(HAVE_SNPRINTF)
90 #define system_sprintf(buff, max, flags, data) \
91 ::snprintf(buff, max, flags, data)
92 #else // NB: at least sprintf() should always be available
93 // since 'max' is not used in this case, wxVsnprintf() should always
94 // ensure that 'buff' is big enough for all common needs
95 // (see wxMAX_SVNPRINTF_FLAGBUFFER_LEN and wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN)
96 #define system_sprintf(buff, max, flags, data) \
97 ::sprintf(buff, flags, data)
99 #define SYSTEM_SPRINTF_IS_UNSAFE
102 // the conversion specifiers accepted by wxCRT_VsnprintfW_
103 enum wxPrintfArgType
{
106 wxPAT_INT
, // %d, %i, %o, %u, %x, %X
107 wxPAT_LONGINT
, // %ld, etc
109 wxPAT_LONGLONGINT
, // %Ld, etc
111 wxPAT_SIZET
, // %Zd, etc
113 wxPAT_DOUBLE
, // %e, %E, %f, %g, %G
114 wxPAT_LONGDOUBLE
, // %le, etc
118 wxPAT_CHAR
, // %hc (in ANSI mode: %c, too)
119 wxPAT_WCHAR
, // %lc (in Unicode mode: %c, too)
121 wxPAT_PCHAR
, // %s (related to a char *)
122 wxPAT_PWCHAR
, // %s (related to a wchar_t *)
125 wxPAT_NSHORTINT
, // %hn
126 wxPAT_NLONGINT
// %ln
129 // an argument passed to wxCRT_VsnprintfW_
131 int pad_int
; // %d, %i, %o, %u, %x, %X
132 long int pad_longint
; // %ld, etc
134 wxLongLong_t pad_longlongint
; // %Ld, etc
136 size_t pad_sizet
; // %Zd, etc
138 double pad_double
; // %e, %E, %f, %g, %G
139 long double pad_longdouble
; // %le, etc
141 void *pad_pointer
; // %p
143 char pad_char
; // %hc (in ANSI mode: %c, too)
144 wchar_t pad_wchar
; // %lc (in Unicode mode: %c, too)
149 short int *pad_nshortint
; // %hn
150 long int *pad_nlongint
; // %ln
154 // Contains parsed data relative to a conversion specifier given to
155 // wxCRT_VsnprintfW_ and parsed from the format string
156 // NOTE: in C++ there is almost no difference between struct & classes thus
157 // there is no performance gain by using a struct here...
158 class wxPrintfConvSpec
162 // the position of the argument relative to this conversion specifier
165 // the type of this conversion specifier
166 wxPrintfArgType m_type
;
168 // the minimum and maximum width
169 // when one of this var is set to -1 it means: use the following argument
170 // in the stack as minimum/maximum width for this conversion specifier
171 int m_nMinWidth
, m_nMaxWidth
;
173 // does the argument need to the be aligned to left ?
176 // pointer to the '%' of this conversion specifier in the format string
177 // NOTE: this points somewhere in the string given to the Parse() function -
178 // it's task of the caller ensure that memory is still valid !
179 const wchar_t *m_pArgPos
;
181 // pointer to the last character of this conversion specifier in the
183 // NOTE: this points somewhere in the string given to the Parse() function -
184 // it's task of the caller ensure that memory is still valid !
185 const wchar_t *m_pArgEnd
;
187 // a little buffer where formatting flags like #+\.hlqLZ are stored by Parse()
188 // for use in Process()
189 // NB: even if this buffer is used only for numeric conversion specifiers and
190 // thus could be safely declared as a char[] buffer, we want it to be wchar_t
191 // so that in Unicode builds we can avoid to convert its contents to Unicode
192 // chars when copying it in user's buffer.
193 char m_szFlags
[wxMAX_SVNPRINTF_FLAGBUFFER_LEN
];
198 // we don't declare this as a constructor otherwise it would be called
199 // automatically and we don't want this: to be optimized, wxCRT_VsnprintfW_
200 // calls this function only on really-used instances of this class.
203 // Parses the first conversion specifier in the given string, which must
204 // begin with a '%'. Returns false if the first '%' does not introduce a
205 // (valid) conversion specifier and thus should be ignored.
206 bool Parse(const wchar_t *format
);
208 // Process this conversion specifier and puts the result in the given
209 // buffer. Returns the number of characters written in 'buf' or -1 if
210 // there's not enough space.
211 int Process(wchar_t *buf
, size_t lenMax
, wxPrintfArg
*p
, size_t written
);
213 // Loads the argument of this conversion specifier from given va_list.
214 bool LoadArg(wxPrintfArg
*p
, va_list &argptr
);
217 // An helper function of LoadArg() which is used to handle the '*' flag
218 void ReplaceAsteriskWith(int w
);
221 void wxPrintfConvSpec::Init()
224 m_nMaxWidth
= 0xFFFF;
226 m_bAlignLeft
= false;
227 m_pArgPos
= m_pArgEnd
= NULL
;
228 m_type
= wxPAT_INVALID
;
230 // this character will never be removed from m_szFlags array and
231 // is important when calling sprintf() in wxPrintfConvSpec::Process() !
235 bool wxPrintfConvSpec::Parse(const wchar_t *format
)
239 // temporary parse data
241 bool in_prec
, // true if we found the dot in some previous iteration
242 prec_dot
; // true if the dot has been already added to m_szFlags
245 m_bAlignLeft
= in_prec
= prec_dot
= false;
246 m_pArgPos
= m_pArgEnd
= format
;
250 if (in_prec && !prec_dot) \
252 m_szFlags[flagofs++] = '.'; \
257 const wchar_t ch
= *(++m_pArgEnd
);
261 return false; // not really an argument
264 return false; // not really an argument
272 m_szFlags
[flagofs
++] = char(ch
);
278 m_szFlags
[flagofs
++] = char(ch
);
286 // dot will be auto-added to m_szFlags if non-negative
293 m_szFlags
[flagofs
++] = char(ch
);
297 // NB: it's safe to use flagofs-1 as flagofs always start from 1
298 if (m_szFlags
[flagofs
-1] == 'l') // 'll' modifier is the same as 'L' or 'q'
303 m_szFlags
[flagofs
++] = char(ch
);
310 m_szFlags
[flagofs
++] = char(ch
);
313 // under Windows we support the special '%I64' notation as longlong
314 // integer conversion specifier for MSVC compatibility
315 // (it behaves exactly as '%lli' or '%Li' or '%qi')
317 if (*(m_pArgEnd
+1) != wxT('6') ||
318 *(m_pArgEnd
+2) != wxT('4'))
319 return false; // bad format
326 m_szFlags
[flagofs
++] = char(ch
);
327 m_szFlags
[flagofs
++] = '6';
328 m_szFlags
[flagofs
++] = '4';
335 m_szFlags
[flagofs
++] = char(ch
);
343 // tell Process() to use the next argument
344 // in the stack as maxwidth...
349 // tell Process() to use the next argument
350 // in the stack as minwidth...
354 // save the * in our formatting buffer...
355 // will be replaced later by Process()
356 m_szFlags
[flagofs
++] = char(ch
);
359 case wxT('1'): case wxT('2'): case wxT('3'):
360 case wxT('4'): case wxT('5'): case wxT('6'):
361 case wxT('7'): case wxT('8'): case wxT('9'):
365 while ( (*m_pArgEnd
>= wxT('0')) &&
366 (*m_pArgEnd
<= wxT('9')) )
368 m_szFlags
[flagofs
++] = char(*m_pArgEnd
);
369 len
= len
*10 + (*m_pArgEnd
- wxT('0'));
378 m_pArgEnd
--; // the main loop pre-increments n again
382 case wxT('$'): // a positional parameter (e.g. %2$s) ?
384 if (m_nMinWidth
<= 0)
385 break; // ignore this formatting flag as no
386 // numbers are preceding it
388 // remove from m_szFlags all digits previously added
391 } while (m_szFlags
[flagofs
] >= '1' &&
392 m_szFlags
[flagofs
] <= '9');
394 // re-adjust the offset making it point to the
395 // next free char of m_szFlags
410 m_szFlags
[flagofs
++] = char(ch
);
411 m_szFlags
[flagofs
] = '\0';
415 // NB: 'short int' value passed through '...'
416 // is promoted to 'int', so we have to get
417 // an int from stack even if we need a short
420 m_type
= wxPAT_LONGINT
;
423 m_type
= wxPAT_LONGLONGINT
;
424 #else // !wxLongLong_t
425 m_type
= wxPAT_LONGINT
;
426 #endif // wxLongLong_t/!wxLongLong_t
428 m_type
= wxPAT_SIZET
;
438 m_szFlags
[flagofs
++] = char(ch
);
439 m_szFlags
[flagofs
] = '\0';
441 m_type
= wxPAT_LONGDOUBLE
;
443 m_type
= wxPAT_DOUBLE
;
448 m_type
= wxPAT_POINTER
;
449 m_szFlags
[flagofs
++] = char(ch
);
450 m_szFlags
[flagofs
] = '\0';
457 // in Unicode mode %hc == ANSI character
458 // and in ANSI mode, %hc == %c == ANSI...
463 // in ANSI mode %lc == Unicode character
464 // and in Unicode mode, %lc == %c == Unicode...
465 m_type
= wxPAT_WCHAR
;
470 // in Unicode mode, %c == Unicode character
471 m_type
= wxPAT_WCHAR
;
473 // in ANSI mode, %c == ANSI character
483 // Unicode mode wx extension: we'll let %hs mean non-Unicode
484 // strings (when in ANSI mode, %s == %hs == ANSI string)
485 m_type
= wxPAT_PCHAR
;
489 // in Unicode mode, %ls == %s == Unicode string
490 // in ANSI mode, %ls == Unicode string
491 m_type
= wxPAT_PWCHAR
;
496 m_type
= wxPAT_PWCHAR
;
498 m_type
= wxPAT_PCHAR
;
508 m_type
= wxPAT_NSHORTINT
;
510 m_type
= wxPAT_NLONGINT
;
515 // bad format, don't consider this an argument;
516 // leave it unchanged
520 if (flagofs
== wxMAX_SVNPRINTF_FLAGBUFFER_LEN
)
522 wxLogDebug(wxT("Too many flags specified for a single conversion specifier!"));
528 return true; // parsing was successful
532 void wxPrintfConvSpec::ReplaceAsteriskWith(int width
)
534 char temp
[wxMAX_SVNPRINTF_FLAGBUFFER_LEN
];
536 // find the first * in our flag buffer
537 char *pwidth
= strchr(m_szFlags
, '*');
538 wxCHECK_RET(pwidth
, _T("field width must be specified"));
540 // save what follows the * (the +1 is to skip the asterisk itself!)
541 strcpy(temp
, pwidth
+1);
544 pwidth
[0] = wxT('-');
548 // replace * with the actual integer given as width
549 #ifndef SYSTEM_SPRINTF_IS_UNSAFE
550 int maxlen
= (m_szFlags
+ wxMAX_SVNPRINTF_FLAGBUFFER_LEN
- pwidth
) /
553 int offset
= system_sprintf(pwidth
, maxlen
, "%d", abs(width
));
555 // restore after the expanded * what was following it
556 strcpy(pwidth
+offset
, temp
);
559 bool wxPrintfConvSpec::LoadArg(wxPrintfArg
*p
, va_list &argptr
)
561 // did the '*' width/precision specifier was used ?
562 if (m_nMaxWidth
== -1)
564 // take the maxwidth specifier from the stack
565 m_nMaxWidth
= va_arg(argptr
, int);
569 ReplaceAsteriskWith(m_nMaxWidth
);
572 if (m_nMinWidth
== -1)
574 // take the minwidth specifier from the stack
575 m_nMinWidth
= va_arg(argptr
, int);
577 ReplaceAsteriskWith(m_nMinWidth
);
580 m_bAlignLeft
= !m_bAlignLeft
;
581 m_nMinWidth
= -m_nMinWidth
;
587 p
->pad_int
= va_arg(argptr
, int);
590 p
->pad_longint
= va_arg(argptr
, long int);
593 case wxPAT_LONGLONGINT
:
594 p
->pad_longlongint
= va_arg(argptr
, wxLongLong_t
);
596 #endif // wxLongLong_t
598 p
->pad_sizet
= va_arg(argptr
, size_t);
601 p
->pad_double
= va_arg(argptr
, double);
603 case wxPAT_LONGDOUBLE
:
604 p
->pad_longdouble
= va_arg(argptr
, long double);
607 p
->pad_pointer
= va_arg(argptr
, void *);
611 p
->pad_char
= (char)va_arg(argptr
, int); // char is promoted to int when passed through '...'
614 p
->pad_wchar
= (wchar_t)va_arg(argptr
, int); // char is promoted to int when passed through '...'
619 p
->pad_str
= va_arg(argptr
, void *);
623 p
->pad_nint
= va_arg(argptr
, int *);
625 case wxPAT_NSHORTINT
:
626 p
->pad_nshortint
= va_arg(argptr
, short int *);
629 p
->pad_nlongint
= va_arg(argptr
, long int *);
637 return true; // loading was successful
640 int wxPrintfConvSpec::Process(wchar_t *buf
, size_t lenMax
, wxPrintfArg
*p
, size_t written
)
642 // buffer to avoid dynamic memory allocation each time for small strings;
643 // note that this buffer is used only to hold results of number formatting,
644 // %s directly writes user's string in buf, without using szScratch
645 char szScratch
[wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN
];
646 size_t lenScratch
= 0, lenCur
= 0;
648 #define APPEND_CH(ch) \
650 if ( lenCur == lenMax ) \
653 buf[lenCur++] = ch; \
659 lenScratch
= system_sprintf(szScratch
, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN
, m_szFlags
, p
->pad_int
);
663 lenScratch
= system_sprintf(szScratch
, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN
, m_szFlags
, p
->pad_longint
);
667 case wxPAT_LONGLONGINT
:
668 lenScratch
= system_sprintf(szScratch
, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN
, m_szFlags
, p
->pad_longlongint
);
670 #endif // SIZEOF_LONG_LONG
673 lenScratch
= system_sprintf(szScratch
, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN
, m_szFlags
, p
->pad_sizet
);
676 case wxPAT_LONGDOUBLE
:
677 lenScratch
= system_sprintf(szScratch
, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN
, m_szFlags
, p
->pad_longdouble
);
681 lenScratch
= system_sprintf(szScratch
, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN
, m_szFlags
, p
->pad_double
);
685 lenScratch
= system_sprintf(szScratch
, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN
, m_szFlags
, p
->pad_pointer
);
695 if (m_type
== wxPAT_CHAR
)
697 // user passed a character explicitely indicated as ANSI...
698 const char buf
[2] = { p
->pad_char
, 0 };
699 val
= wxString(buf
, wxConvLibc
)[0u];
701 //wprintf(L"converting ANSI=>Unicode"); // for debug
707 if (m_type
== wxPAT_WCHAR
)
709 // user passed a character explicitely indicated as Unicode...
710 const wchar_t buf
[2] = { p
->pad_wchar
, 0 };
711 val
= wxString(buf
, wxConvLibc
)[0u];
713 //printf("converting Unicode=>ANSI"); // for debug
721 for (i
= 1; i
< (size_t)m_nMinWidth
; i
++)
727 for (i
= 1; i
< (size_t)m_nMinWidth
; i
++)
735 wxArgNormalizedString
arg(p
->pad_str
);
738 if ( !arg
.IsValid() && m_nMaxWidth
>= 6 )
741 // at this point we are sure that m_nMaxWidth is positive or
742 // null (see top of wxPrintfConvSpec::LoadArg)
743 int len
= wxMin((unsigned int)m_nMaxWidth
, s
.length());
749 for (i
= len
; i
< m_nMinWidth
; i
++)
754 len
= wxMin((unsigned int)len
, lenMax
-lenCur
);
755 #if wxUSE_UNICODE // FIXME-UTF8
756 wxStrncpy(buf
+lenCur
, s
.wc_str(), len
);
758 wxStrncpy(buf
+lenCur
, s
.mb_str(), len
);
762 wxString::const_iterator end
= s
.begin() + len
;
763 for (wxString::const_iterator j
= s
.begin(); j
!= end
; ++j
)
769 for (i
= len
; i
< m_nMinWidth
; i
++)
776 *p
->pad_nint
= written
;
779 case wxPAT_NSHORTINT
:
780 *p
->pad_nshortint
= (short int)written
;
784 *p
->pad_nlongint
= written
;
792 // if we used system's sprintf() then we now need to append the s_szScratch
793 // buffer to the given one...
799 case wxPAT_LONGLONGINT
:
802 case wxPAT_LONGDOUBLE
:
805 wxASSERT(lenScratch
< wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN
);
808 if (lenMax
< lenScratch
)
810 // fill output buffer and then return -1
811 wxStrncpy(buf
, szScratch
, lenMax
);
814 wxStrncpy(buf
, szScratch
, lenScratch
);
815 lenCur
+= lenScratch
;
819 // Copy the char scratch to the wide output. This requires
820 // conversion, but we can optimise by making use of the fact
821 // that we are formatting numbers, this should mean only 7-bit
822 // ascii characters are involved.
823 wchar_t *bufptr
= buf
;
824 const wchar_t *bufend
= buf
+ lenMax
;
825 const char *scratchptr
= szScratch
;
827 // Simply copy each char to a wchar_t, stopping on the first
828 // null or non-ascii byte. Checking '(signed char)*scratchptr
829 // > 0' is an extra optimisation over '*scratchptr != 0 &&
830 // isascii(*scratchptr)', though it assumes signed char is
831 // 8-bit 2 complement.
832 while ((signed char)*scratchptr
> 0 && bufptr
!= bufend
)
833 *bufptr
++ = *scratchptr
++;
835 if (bufptr
== bufend
)
838 lenCur
+= bufptr
- buf
;
840 // check if the loop stopped on a non-ascii char, if yes then
841 // fall back to wxMB2WX
844 size_t len
= wxMB2WX(bufptr
, scratchptr
, bufend
- bufptr
);
846 if (len
&& len
!= (size_t)(-1))
857 break; // all other cases were completed previously
863 // Copy chars from source to dest converting '%%' to '%'. Takes at most maxIn
864 // chars from source and write at most outMax chars to dest, returns the
865 // number of chars actually written. Does not treat null specially.
867 static int wxCopyStrWithPercents(
871 const wchar_t *source
)
879 for ( i
= 0; i
< maxIn
-1 && written
< maxOut
; source
++, i
++)
881 dest
[written
++] = *source
;
882 if (*(source
+1) == wxT('%'))
884 // skip this additional '%' character
890 if (i
< maxIn
&& written
< maxOut
)
891 // copy last character inconditionally
892 dest
[written
++] = *source
;
897 int WXDLLEXPORT
wxCRT_VsnprintfW_(wchar_t *buf
, size_t lenMax
,
898 const wchar_t *format
, va_list argptr
)
900 // useful for debugging, to understand if we are really using this function
901 // rather than the system implementation
903 wprintf(L
"Using wxCRT_VsnprintfW_\n");
907 wxPrintfConvSpec arg
[wxMAX_SVNPRINTF_ARGUMENTS
];
908 wxPrintfArg argdata
[wxMAX_SVNPRINTF_ARGUMENTS
];
909 wxPrintfConvSpec
*pspec
[wxMAX_SVNPRINTF_ARGUMENTS
] = { NULL
};
913 // number of characters in the buffer so far, must be less than lenMax
917 const wchar_t *toparse
= format
;
919 // parse the format string
920 bool posarg_present
= false, nonposarg_present
= false;
921 for (; *toparse
!= wxT('\0'); toparse
++)
923 if (*toparse
== wxT('%') )
927 // let's see if this is a (valid) conversion specifier...
928 if (arg
[nargs
].Parse(toparse
))
931 wxPrintfConvSpec
*current
= &arg
[nargs
];
933 // make toparse point to the end of this specifier
934 toparse
= current
->m_pArgEnd
;
936 if (current
->m_pos
> 0)
938 // the positionals start from number 1... adjust the index
940 posarg_present
= true;
944 // not a positional argument...
945 current
->m_pos
= nargs
;
946 nonposarg_present
= true;
949 // this conversion specifier is tied to the pos-th argument...
950 pspec
[current
->m_pos
] = current
;
953 if (nargs
== wxMAX_SVNPRINTF_ARGUMENTS
)
955 wxLogDebug(wxT("A single call to wxVsnprintf() has more than %d arguments; ")
956 wxT("ignoring all remaining arguments."), wxMAX_SVNPRINTF_ARGUMENTS
);
957 break; // cannot handle any additional conv spec
962 // it's safe to look in the next character of toparse as at worst
964 if (*(toparse
+1) == wxT('%'))
965 toparse
++; // the Parse() returned false because we've found a %%
970 if (posarg_present
&& nonposarg_present
)
973 return -1; // format strings with both positional and
974 } // non-positional conversion specifier are unsupported !!
976 // on platforms where va_list is an array type, it is necessary to make a
977 // copy to be able to pass it to LoadArg as a reference.
980 wxVaCopy(ap
, argptr
);
982 // now load arguments from stack
983 for (i
=0; i
< nargs
&& ok
; i
++)
985 // !pspec[i] means that the user forgot a positional parameter (e.g. %$1s %$3s);
986 // LoadArg == false means that wxPrintfConvSpec::Parse failed to set the
987 // conversion specifier 'type' to a valid value...
988 ok
= pspec
[i
] && pspec
[i
]->LoadArg(&argdata
[i
], ap
);
993 // something failed while loading arguments from the variable list...
994 // (e.g. the user repeated twice the same positional argument)
1001 // finally, process each conversion specifier with its own argument
1003 for (i
=0; i
< nargs
; i
++)
1005 // copy in the output buffer the portion of the format string between
1006 // last specifier and the current one
1007 size_t tocopy
= ( arg
[i
].m_pArgPos
- toparse
);
1009 lenCur
+= wxCopyStrWithPercents(lenMax
- lenCur
, buf
+ lenCur
,
1011 if (lenCur
== lenMax
)
1013 buf
[lenMax
- 1] = 0;
1014 return lenMax
+1; // not enough space in the output buffer !
1017 // process this specifier directly in the output buffer
1018 int n
= arg
[i
].Process(buf
+lenCur
, lenMax
- lenCur
, &argdata
[arg
[i
].m_pos
], lenCur
);
1021 buf
[lenMax
-1] = wxT('\0'); // be sure to always NUL-terminate the string
1022 return lenMax
+1; // not enough space in the output buffer !
1026 // the +1 is because wxPrintfConvSpec::m_pArgEnd points to the last character
1027 // of the format specifier, but we are not interested to it...
1028 toparse
= arg
[i
].m_pArgEnd
+ 1;
1031 // copy portion of the format string after last specifier
1032 // NOTE: toparse is pointing to the character just after the last processed
1033 // conversion specifier
1034 // NOTE2: the +1 is because we want to copy also the '\0'
1035 size_t tocopy
= wxStrlen(format
) + 1 - ( toparse
- format
) ;
1037 lenCur
+= wxCopyStrWithPercents(lenMax
- lenCur
, buf
+ lenCur
,
1038 tocopy
, toparse
) - 1;
1042 return lenMax
+1; // not enough space in the output buffer !
1046 // wxASSERT(lenCur == wxStrlen(buf));
1047 // in fact if we embedded NULLs in the output buffer (using %c with a '\0')
1048 // such check would fail
1056 #else // wxCRT_VsnprintfW_ is defined
1058 #if wxUSE_WXVSNPRINTFW
1059 #error "wxUSE_WXVSNPRINTFW must be 0 if our wxCRT_VsnprintfW_ is not used"
1062 #endif // !wxCRT_VsnprintfW_