]>
Commit | Line | Data |
---|---|---|
1 | ///////////////////////////////////////////////////////////////////////////// | |
2 | // Name: src/common/wxprintf.cpp | |
3 | // Purpose: wxWidgets wxPrintf() implementation | |
4 | // Author: Ove Kaven | |
5 | // Modified by: Ron Lee, Francesco Montorsi | |
6 | // Created: 09/04/99 | |
7 | // Copyright: (c) wxWidgets copyright | |
8 | // Licence: wxWindows licence | |
9 | ///////////////////////////////////////////////////////////////////////////// | |
10 | ||
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__ | |
19 | #pragma hdrstop | |
20 | #endif | |
21 | ||
22 | #ifndef WX_PRECOMP | |
23 | #include "wx/string.h" | |
24 | #include "wx/hash.h" | |
25 | #include "wx/utils.h" // for wxMin and wxMax | |
26 | #include "wx/log.h" | |
27 | #endif | |
28 | ||
29 | #include "wx/private/wxprintf.h" | |
30 | ||
31 | ||
32 | // ============================================================================ | |
33 | // printf() implementation | |
34 | // ============================================================================ | |
35 | ||
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 | |
39 | #undef wxCRT_VsnprintfW | |
40 | #undef wxCRT_VsnprintfA | |
41 | #endif | |
42 | ||
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 | // ---------------------------------------------------------------------------- | |
48 | ||
49 | // ---------------------------------------------------------------------------- | |
50 | // common code for both ANSI and Unicode versions | |
51 | // ---------------------------------------------------------------------------- | |
52 | ||
53 | #if !defined(wxCRT_VsnprintfW) || !defined(wxCRT_VsnprintfA) | |
54 | ||
55 | ||
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( | |
61 | size_t maxOut, | |
62 | CharType *dest, | |
63 | size_t maxIn, | |
64 | const CharType *source) | |
65 | { | |
66 | size_t written = 0; | |
67 | ||
68 | if (maxIn == 0) | |
69 | return 0; | |
70 | ||
71 | size_t i; | |
72 | for ( i = 0; i < maxIn-1 && written < maxOut; source++, i++) | |
73 | { | |
74 | dest[written++] = *source; | |
75 | if (*(source+1) == wxT('%')) | |
76 | { | |
77 | // skip this additional '%' character | |
78 | source++; | |
79 | i++; | |
80 | } | |
81 | } | |
82 | ||
83 | if (i < maxIn && written < maxOut) | |
84 | // copy last character inconditionally | |
85 | dest[written++] = *source; | |
86 | ||
87 | return written; | |
88 | } | |
89 | ||
90 | template<typename CharType> | |
91 | static int wxDoVsnprintf(CharType *buf, size_t lenMax, | |
92 | const CharType *format, va_list argptr) | |
93 | { | |
94 | // useful for debugging, to understand if we are really using this function | |
95 | // rather than the system implementation | |
96 | #if 0 | |
97 | wprintf(L"Using wxCRT_VsnprintfW\n"); | |
98 | #endif | |
99 | ||
100 | wxPrintfConvSpecParser<CharType> parser(format); | |
101 | ||
102 | wxPrintfArg argdata[wxMAX_SVNPRINTF_ARGUMENTS]; | |
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 | ||
109 | if (parser.posarg_present && parser.nonposarg_present) | |
110 | { | |
111 | buf[0] = 0; | |
112 | return -1; // format strings with both positional and | |
113 | } // non-positional conversion specifier are unsupported !! | |
114 | ||
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 | ||
121 | // now load arguments from stack | |
122 | for (i=0; i < parser.nargs && ok; i++) | |
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... | |
127 | ok = parser.pspec[i] && parser.pspec[i]->LoadArg(&argdata[i], ap); | |
128 | } | |
129 | ||
130 | va_end(ap); | |
131 | ||
132 | // something failed while loading arguments from the variable list... | |
133 | // (e.g. the user repeated twice the same positional argument) | |
134 | if (!ok) | |
135 | { | |
136 | buf[0] = 0; | |
137 | return -1; | |
138 | } | |
139 | ||
140 | // finally, process each conversion specifier with its own argument | |
141 | const CharType *toparse = format; | |
142 | for (i=0; i < parser.nargs; i++) | |
143 | { | |
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 | ||
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 ); | |
154 | ||
155 | lenCur += wxCopyStrWithPercents(lenMax - lenCur, buf + lenCur, | |
156 | tocopy, toparse); | |
157 | if (lenCur == lenMax) | |
158 | { | |
159 | buf[lenMax - 1] = 0; | |
160 | return lenMax+1; // not enough space in the output buffer ! | |
161 | } | |
162 | ||
163 | // process this specifier directly in the output buffer | |
164 | int n = spec.Process(buf+lenCur, lenMax - lenCur, | |
165 | &argdata[spec.m_pos], lenCur); | |
166 | if (n == -1) | |
167 | { | |
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 ! | |
170 | } | |
171 | lenCur += n; | |
172 | ||
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; | |
176 | } | |
177 | ||
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 ) ; | |
183 | ||
184 | lenCur += wxCopyStrWithPercents(lenMax - lenCur, buf + lenCur, | |
185 | tocopy, toparse) - 1; | |
186 | if (buf[lenCur]) | |
187 | { | |
188 | buf[lenCur] = 0; | |
189 | return lenMax+1; // not enough space in the output buffer ! | |
190 | } | |
191 | ||
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 | ||
197 | return lenCur; | |
198 | } | |
199 | ||
200 | #endif // !defined(wxCRT_VsnprintfW) || !defined(wxCRT_VsnprintfA) | |
201 | ||
202 | // ---------------------------------------------------------------------------- | |
203 | // wxCRT_VsnprintfW | |
204 | // ---------------------------------------------------------------------------- | |
205 | ||
206 | #if !defined(wxCRT_VsnprintfW) | |
207 | ||
208 | #if !wxUSE_WXVSNPRINTFW | |
209 | #error "wxUSE_WXVSNPRINTFW must be 1 if our wxCRT_VsnprintfW is used" | |
210 | #endif | |
211 | ||
212 | int wxCRT_VsnprintfW(wchar_t *buf, size_t len, | |
213 | const wchar_t *format, va_list argptr) | |
214 | { | |
215 | return wxDoVsnprintf(buf, len, format, argptr); | |
216 | } | |
217 | ||
218 | #else // wxCRT_VsnprintfW is defined | |
219 | ||
220 | #if wxUSE_WXVSNPRINTFW | |
221 | #error "wxUSE_WXVSNPRINTFW must be 0 if our wxCRT_VsnprintfW is not used" | |
222 | #endif | |
223 | ||
224 | #endif // !wxCRT_VsnprintfW | |
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 |