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