1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/wxprintf.cpp
3 // Purpose: wxWidgets wxPrintf() implementation
5 // Modified by: Ron Lee, Francesco Montorsi
7 // Copyright: (c) wxWidgets copyright
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // ===========================================================================
12 // headers, declarations, constants
13 // ===========================================================================
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
23 #include "wx/string.h"
25 #include "wx/utils.h" // for wxMin and wxMax
29 #include "wx/private/wxprintf.h"
32 // ============================================================================
33 // printf() implementation
34 // ============================================================================
36 // special test mode: define all functions below even if we don't really need
37 // them to be able to test them
39 #undef wxCRT_VsnprintfW
40 #undef wxCRT_VsnprintfA
43 // ----------------------------------------------------------------------------
44 // implement [v]snprintf() if the system doesn't provide a safe one
45 // or if the system's one does not support positional parameters
46 // (very useful for i18n purposes)
47 // ----------------------------------------------------------------------------
49 // ----------------------------------------------------------------------------
50 // common code for both ANSI and Unicode versions
51 // ----------------------------------------------------------------------------
53 #if !defined(wxCRT_VsnprintfW) || !defined(wxCRT_VsnprintfA)
56 // Copy chars from source to dest converting '%%' to '%'. Takes at most maxIn
57 // chars from source and write at most outMax chars to dest, returns the
58 // number of chars actually written. Does not treat null specially.
59 template<typename CharType
>
60 static int wxCopyStrWithPercents(
64 const CharType
*source
)
72 for ( i
= 0; i
< maxIn
-1 && written
< maxOut
; source
++, i
++)
74 dest
[written
++] = *source
;
75 if (*(source
+1) == wxT('%'))
77 // skip this additional '%' character
83 if (i
< maxIn
&& written
< maxOut
)
84 // copy last character inconditionally
85 dest
[written
++] = *source
;
90 template<typename CharType
>
91 static int wxDoVsnprintf(CharType
*buf
, size_t lenMax
,
92 const CharType
*format
, va_list argptr
)
94 // useful for debugging, to understand if we are really using this function
95 // rather than the system implementation
97 wprintf(L
"Using wxCRT_VsnprintfW\n");
100 wxPrintfConvSpecParser
<CharType
> parser(format
);
102 wxPrintfArg argdata
[wxMAX_SVNPRINTF_ARGUMENTS
];
106 // number of characters in the buffer so far, must be less than lenMax
109 if (parser
.posarg_present
&& parser
.nonposarg_present
)
112 return -1; // format strings with both positional and
113 } // non-positional conversion specifier are unsupported !!
115 // on platforms where va_list is an array type, it is necessary to make a
116 // copy to be able to pass it to LoadArg as a reference.
119 wxVaCopy(ap
, argptr
);
121 // now load arguments from stack
122 for (i
=0; i
< parser
.nargs
&& ok
; i
++)
124 // !pspec[i] means that the user forgot a positional parameter (e.g. %$1s %$3s);
125 // LoadArg == false means that wxPrintfConvSpec::Parse failed to set the
126 // conversion specifier 'type' to a valid value...
127 ok
= parser
.pspec
[i
] && parser
.pspec
[i
]->LoadArg(&argdata
[i
], ap
);
132 // something failed while loading arguments from the variable list...
133 // (e.g. the user repeated twice the same positional argument)
140 // finally, process each conversion specifier with its own argument
141 const CharType
*toparse
= format
;
142 for (i
=0; i
< parser
.nargs
; i
++)
144 wxPrintfConvSpec
<CharType
>& spec
= parser
.specs
[i
];
146 // skip any asterisks, they're processed as part of the conversion they
148 if ( spec
.m_type
== wxPAT_STAR
)
151 // copy in the output buffer the portion of the format string between
152 // last specifier and the current one
153 size_t tocopy
= ( spec
.m_pArgPos
- toparse
);
155 lenCur
+= wxCopyStrWithPercents(lenMax
- lenCur
, buf
+ lenCur
,
157 if (lenCur
== lenMax
)
160 return lenMax
+1; // not enough space in the output buffer !
163 // process this specifier directly in the output buffer
164 int n
= spec
.Process(buf
+lenCur
, lenMax
- lenCur
,
165 &argdata
[spec
.m_pos
], lenCur
);
168 buf
[lenMax
-1] = wxT('\0'); // be sure to always NUL-terminate the string
169 return lenMax
+1; // not enough space in the output buffer !
173 // the +1 is because wxPrintfConvSpec::m_pArgEnd points to the last character
174 // of the format specifier, but we are not interested to it...
175 toparse
= spec
.m_pArgEnd
+ 1;
178 // copy portion of the format string after last specifier
179 // NOTE: toparse is pointing to the character just after the last processed
180 // conversion specifier
181 // NOTE2: the +1 is because we want to copy also the '\0'
182 size_t tocopy
= wxStrlen(format
) + 1 - ( toparse
- format
) ;
184 lenCur
+= wxCopyStrWithPercents(lenMax
- lenCur
, buf
+ lenCur
,
185 tocopy
, toparse
) - 1;
189 return lenMax
+1; // not enough space in the output buffer !
193 // wxASSERT(lenCur == wxStrlen(buf));
194 // in fact if we embedded NULLs in the output buffer (using %c with a '\0')
195 // such check would fail
200 #endif // !defined(wxCRT_VsnprintfW) || !defined(wxCRT_VsnprintfA)
202 // ----------------------------------------------------------------------------
204 // ----------------------------------------------------------------------------
206 #if !defined(wxCRT_VsnprintfW)
208 #if !wxUSE_WXVSNPRINTFW
209 #error "wxUSE_WXVSNPRINTFW must be 1 if our wxCRT_VsnprintfW is used"
212 int wxCRT_VsnprintfW(wchar_t *buf
, size_t len
,
213 const wchar_t *format
, va_list argptr
)
215 return wxDoVsnprintf(buf
, len
, format
, argptr
);
218 #else // wxCRT_VsnprintfW is defined
220 #if wxUSE_WXVSNPRINTFW
221 #error "wxUSE_WXVSNPRINTFW must be 0 if our wxCRT_VsnprintfW is not used"
224 #endif // !wxCRT_VsnprintfW
226 // ----------------------------------------------------------------------------
228 // ----------------------------------------------------------------------------
230 #ifndef wxCRT_VsnprintfA
232 #if !wxUSE_WXVSNPRINTFA
233 #error "wxUSE_WXVSNPRINTFA must be 1 if our wxCRT_VsnprintfA is used"
236 int wxCRT_VsnprintfA(char *buf
, size_t len
,
237 const char *format
, va_list argptr
)
239 return wxDoVsnprintf(buf
, len
, format
, argptr
);
242 #else // wxCRT_VsnprintfA is defined
244 #if wxUSE_WXVSNPRINTFA
245 #error "wxUSE_WXVSNPRINTFA must be 0 if our wxCRT_VsnprintfA is not used"
248 #endif // !wxCRT_VsnprintfA