]>
Commit | Line | Data |
---|---|---|
c9e089e9 | 1 | ///////////////////////////////////////////////////////////////////////////// |
dd0ef332 VS |
2 | // Name: src/common/wxprintf.cpp |
3 | // Purpose: wxWidgets wxPrintf() implementation | |
247c23b4 VZ |
4 | // Author: Ove Kaven |
5 | // Modified by: Ron Lee, Francesco Montorsi | |
c9e089e9 | 6 | // Created: 09/04/99 |
77ffb593 | 7 | // Copyright: (c) wxWidgets copyright |
65571936 | 8 | // Licence: wxWindows licence |
c9e089e9 OK |
9 | ///////////////////////////////////////////////////////////////////////////// |
10 | ||
c9e089e9 OK |
11 | // =========================================================================== |
12 | // headers, declarations, constants | |
13 | // =========================================================================== | |
14 | ||
15 | // For compilers that support precompilation, includes "wx.h". | |
16 | #include "wx/wxprec.h" | |
17 | ||
18 | #ifdef __BORLANDC__ | |
8898456d | 19 | #pragma hdrstop |
c9e089e9 OK |
20 | #endif |
21 | ||
c9e089e9 | 22 | #ifndef WX_PRECOMP |
8898456d WS |
23 | #include "wx/string.h" |
24 | #include "wx/hash.h" | |
5ff14574 PC |
25 | #include "wx/utils.h" // for wxMin and wxMax |
26 | #include "wx/log.h" | |
c9e089e9 OK |
27 | #endif |
28 | ||
47346406 | 29 | #include "wx/private/wxprintf.h" |
31907d03 | 30 | |
434d2cb3 | 31 | |
f6f5941b | 32 | // ============================================================================ |
dd0ef332 | 33 | // printf() implementation |
f6f5941b VZ |
34 | // ============================================================================ |
35 | ||
df17b887 VZ |
36 | // special test mode: define all functions below even if we don't really need |
37 | // them to be able to test them | |
38 | #ifdef wxTEST_PRINTF | |
50e27899 | 39 | #undef wxCRT_VsnprintfW |
dd25c6ee | 40 | #undef wxCRT_VsnprintfA |
df17b887 VZ |
41 | #endif |
42 | ||
f6f5941b VZ |
43 | // ---------------------------------------------------------------------------- |
44 | // implement [v]snprintf() if the system doesn't provide a safe one | |
7a828c7f VZ |
45 | // or if the system's one does not support positional parameters |
46 | // (very useful for i18n purposes) | |
f6f5941b VZ |
47 | // ---------------------------------------------------------------------------- |
48 | ||
dd25c6ee VS |
49 | // ---------------------------------------------------------------------------- |
50 | // common code for both ANSI and Unicode versions | |
51 | // ---------------------------------------------------------------------------- | |
7a828c7f | 52 | |
50e27899 | 53 | #if !defined(wxCRT_VsnprintfW) || !defined(wxCRT_VsnprintfA) |
f2bbe5b6 | 54 | |
7a828c7f | 55 | |
3c7f37ed MW |
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. | |
dd25c6ee | 59 | template<typename CharType> |
3c7f37ed MW |
60 | static int wxCopyStrWithPercents( |
61 | size_t maxOut, | |
dd25c6ee | 62 | CharType *dest, |
3c7f37ed | 63 | size_t maxIn, |
dd25c6ee | 64 | const CharType *source) |
247c23b4 VZ |
65 | { |
66 | size_t written = 0; | |
67 | ||
3c7f37ed | 68 | if (maxIn == 0) |
247c23b4 VZ |
69 | return 0; |
70 | ||
71 | size_t i; | |
3c7f37ed | 72 | for ( i = 0; i < maxIn-1 && written < maxOut; source++, i++) |
247c23b4 VZ |
73 | { |
74 | dest[written++] = *source; | |
75 | if (*(source+1) == wxT('%')) | |
76 | { | |
77 | // skip this additional '%' character | |
78 | source++; | |
79 | i++; | |
80 | } | |
81 | } | |
82 | ||
3c7f37ed | 83 | if (i < maxIn && written < maxOut) |
247c23b4 VZ |
84 | // copy last character inconditionally |
85 | dest[written++] = *source; | |
86 | ||
87 | return written; | |
88 | } | |
89 | ||
dd25c6ee VS |
90 | template<typename CharType> |
91 | static int wxDoVsnprintf(CharType *buf, size_t lenMax, | |
92 | const CharType *format, va_list argptr) | |
7a828c7f | 93 | { |
412a5c57 VZ |
94 | // useful for debugging, to understand if we are really using this function |
95 | // rather than the system implementation | |
96 | #if 0 | |
50e27899 | 97 | wprintf(L"Using wxCRT_VsnprintfW\n"); |
412a5c57 VZ |
98 | #endif |
99 | ||
47346406 VS |
100 | wxPrintfConvSpecParser<CharType> parser(format); |
101 | ||
412a5c57 | 102 | wxPrintfArg argdata[wxMAX_SVNPRINTF_ARGUMENTS]; |
7a828c7f VZ |
103 | |
104 | size_t i; | |
105 | ||
106 | // number of characters in the buffer so far, must be less than lenMax | |
107 | size_t lenCur = 0; | |
108 | ||
47346406 | 109 | if (parser.posarg_present && parser.nonposarg_present) |
3c7f37ed MW |
110 | { |
111 | buf[0] = 0; | |
7a828c7f | 112 | return -1; // format strings with both positional and |
3c7f37ed | 113 | } // non-positional conversion specifier are unsupported !! |
7a828c7f | 114 | |
3aa077ce MW |
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. | |
117 | bool ok = true; | |
118 | va_list ap; | |
119 | wxVaCopy(ap, argptr); | |
120 | ||
7a828c7f | 121 | // now load arguments from stack |
47346406 | 122 | for (i=0; i < parser.nargs && ok; i++) |
412a5c57 VZ |
123 | { |
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... | |
47346406 | 127 | ok = parser.pspec[i] && parser.pspec[i]->LoadArg(&argdata[i], ap); |
7a828c7f VZ |
128 | } |
129 | ||
3aa077ce MW |
130 | va_end(ap); |
131 | ||
247c23b4 | 132 | // something failed while loading arguments from the variable list... |
f2bbe5b6 | 133 | // (e.g. the user repeated twice the same positional argument) |
3aa077ce | 134 | if (!ok) |
3c7f37ed MW |
135 | { |
136 | buf[0] = 0; | |
3aa077ce | 137 | return -1; |
3c7f37ed | 138 | } |
3aa077ce | 139 | |
7a828c7f | 140 | // finally, process each conversion specifier with its own argument |
bb809a9a | 141 | const CharType *toparse = format; |
47346406 | 142 | for (i=0; i < parser.nargs; i++) |
7a828c7f | 143 | { |
75ac34ce VZ |
144 | wxPrintfConvSpec<CharType>& spec = parser.specs[i]; |
145 | ||
146 | // skip any asterisks, they're processed as part of the conversion they | |
147 | // apply to | |
148 | if ( spec.m_type == wxPAT_STAR ) | |
149 | continue; | |
150 | ||
7a828c7f VZ |
151 | // copy in the output buffer the portion of the format string between |
152 | // last specifier and the current one | |
75ac34ce | 153 | size_t tocopy = ( spec.m_pArgPos - toparse ); |
3c7f37ed MW |
154 | |
155 | lenCur += wxCopyStrWithPercents(lenMax - lenCur, buf + lenCur, | |
156 | tocopy, toparse); | |
157 | if (lenCur == lenMax) | |
412a5c57 | 158 | { |
3c7f37ed | 159 | buf[lenMax - 1] = 0; |
f2bbe5b6 | 160 | return lenMax+1; // not enough space in the output buffer ! |
412a5c57 | 161 | } |
7a828c7f | 162 | |
7a828c7f | 163 | // process this specifier directly in the output buffer |
75ac34ce VZ |
164 | int n = spec.Process(buf+lenCur, lenMax - lenCur, |
165 | &argdata[spec.m_pos], lenCur); | |
7a828c7f | 166 | if (n == -1) |
412a5c57 VZ |
167 | { |
168 | buf[lenMax-1] = wxT('\0'); // be sure to always NUL-terminate the string | |
f2bbe5b6 | 169 | return lenMax+1; // not enough space in the output buffer ! |
412a5c57 | 170 | } |
7a828c7f VZ |
171 | lenCur += n; |
172 | ||
412a5c57 | 173 | // the +1 is because wxPrintfConvSpec::m_pArgEnd points to the last character |
7a828c7f | 174 | // of the format specifier, but we are not interested to it... |
75ac34ce | 175 | toparse = spec.m_pArgEnd + 1; |
5f1d3069 RR |
176 | } |
177 | ||
7a828c7f VZ |
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 ) ; | |
247c23b4 | 183 | |
55339e8c | 184 | lenCur += wxCopyStrWithPercents(lenMax - lenCur, buf + lenCur, |
3c7f37ed MW |
185 | tocopy, toparse) - 1; |
186 | if (buf[lenCur]) | |
187 | { | |
188 | buf[lenCur] = 0; | |
f2bbe5b6 | 189 | return lenMax+1; // not enough space in the output buffer ! |
3c7f37ed | 190 | } |
7a828c7f | 191 | |
13ab552e VZ |
192 | // Don't do: |
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 | |
196 | ||
f6f5941b VZ |
197 | return lenCur; |
198 | } | |
5f1d3069 | 199 | |
50e27899 | 200 | #endif // !defined(wxCRT_VsnprintfW) || !defined(wxCRT_VsnprintfA) |
dd25c6ee VS |
201 | |
202 | // ---------------------------------------------------------------------------- | |
50e27899 | 203 | // wxCRT_VsnprintfW |
dd25c6ee VS |
204 | // ---------------------------------------------------------------------------- |
205 | ||
50e27899 | 206 | #if !defined(wxCRT_VsnprintfW) |
dd25c6ee VS |
207 | |
208 | #if !wxUSE_WXVSNPRINTFW | |
50e27899 | 209 | #error "wxUSE_WXVSNPRINTFW must be 1 if our wxCRT_VsnprintfW is used" |
dd25c6ee VS |
210 | #endif |
211 | ||
50e27899 VS |
212 | int wxCRT_VsnprintfW(wchar_t *buf, size_t len, |
213 | const wchar_t *format, va_list argptr) | |
dd25c6ee VS |
214 | { |
215 | return wxDoVsnprintf(buf, len, format, argptr); | |
216 | } | |
217 | ||
50e27899 | 218 | #else // wxCRT_VsnprintfW is defined |
f2bbe5b6 | 219 | |
52de37c7 | 220 | #if wxUSE_WXVSNPRINTFW |
50e27899 | 221 | #error "wxUSE_WXVSNPRINTFW must be 0 if our wxCRT_VsnprintfW is not used" |
f2bbe5b6 VZ |
222 | #endif |
223 | ||
50e27899 | 224 | #endif // !wxCRT_VsnprintfW |
dd25c6ee VS |
225 | |
226 | // ---------------------------------------------------------------------------- | |
227 | // wxCRT_VsnprintfA | |
228 | // ---------------------------------------------------------------------------- | |
229 | ||
230 | #ifndef wxCRT_VsnprintfA | |
231 | ||
232 | #if !wxUSE_WXVSNPRINTFA | |
233 | #error "wxUSE_WXVSNPRINTFA must be 1 if our wxCRT_VsnprintfA is used" | |
234 | #endif | |
235 | ||
236 | int wxCRT_VsnprintfA(char *buf, size_t len, | |
237 | const char *format, va_list argptr) | |
238 | { | |
239 | return wxDoVsnprintf(buf, len, format, argptr); | |
240 | } | |
241 | ||
242 | #else // wxCRT_VsnprintfA is defined | |
243 | ||
244 | #if wxUSE_WXVSNPRINTFA | |
245 | #error "wxUSE_WXVSNPRINTFA must be 0 if our wxCRT_VsnprintfA is not used" | |
246 | #endif | |
247 | ||
248 | #endif // !wxCRT_VsnprintfA |