]>
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 | // RCS-ID: $Id$ | |
8 | // Copyright: (c) wxWidgets copyright | |
9 | // Licence: wxWindows licence | |
10 | ///////////////////////////////////////////////////////////////////////////// | |
11 | ||
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__ | |
20 | #pragma hdrstop | |
21 | #endif | |
22 | ||
23 | #ifndef WX_PRECOMP | |
24 | #include "wx/string.h" | |
25 | #include "wx/hash.h" | |
26 | #include "wx/utils.h" // for wxMin and wxMax | |
27 | #include "wx/log.h" | |
28 | #endif | |
29 | ||
30 | #include "wx/private/wxprintf.h" | |
31 | ||
32 | ||
33 | // ============================================================================ | |
34 | // printf() implementation | |
35 | // ============================================================================ | |
36 | ||
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 | |
40 | #undef wxCRT_VsnprintfW | |
41 | #undef wxCRT_VsnprintfA | |
42 | #endif | |
43 | ||
44 | // ---------------------------------------------------------------------------- | |
45 | // implement [v]snprintf() if the system doesn't provide a safe one | |
46 | // or if the system's one does not support positional parameters | |
47 | // (very useful for i18n purposes) | |
48 | // ---------------------------------------------------------------------------- | |
49 | ||
50 | // ---------------------------------------------------------------------------- | |
51 | // common code for both ANSI and Unicode versions | |
52 | // ---------------------------------------------------------------------------- | |
53 | ||
54 | #if !defined(wxCRT_VsnprintfW) || !defined(wxCRT_VsnprintfA) | |
55 | ||
56 | ||
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. | |
60 | template<typename CharType> | |
61 | static int wxCopyStrWithPercents( | |
62 | size_t maxOut, | |
63 | CharType *dest, | |
64 | size_t maxIn, | |
65 | const CharType *source) | |
66 | { | |
67 | size_t written = 0; | |
68 | ||
69 | if (maxIn == 0) | |
70 | return 0; | |
71 | ||
72 | size_t i; | |
73 | for ( i = 0; i < maxIn-1 && written < maxOut; source++, i++) | |
74 | { | |
75 | dest[written++] = *source; | |
76 | if (*(source+1) == wxT('%')) | |
77 | { | |
78 | // skip this additional '%' character | |
79 | source++; | |
80 | i++; | |
81 | } | |
82 | } | |
83 | ||
84 | if (i < maxIn && written < maxOut) | |
85 | // copy last character inconditionally | |
86 | dest[written++] = *source; | |
87 | ||
88 | return written; | |
89 | } | |
90 | ||
91 | template<typename CharType> | |
92 | static int wxDoVsnprintf(CharType *buf, size_t lenMax, | |
93 | const CharType *format, va_list argptr) | |
94 | { | |
95 | // useful for debugging, to understand if we are really using this function | |
96 | // rather than the system implementation | |
97 | #if 0 | |
98 | wprintf(L"Using wxCRT_VsnprintfW\n"); | |
99 | #endif | |
100 | ||
101 | wxPrintfConvSpecParser<CharType> parser(format); | |
102 | ||
103 | wxPrintfArg argdata[wxMAX_SVNPRINTF_ARGUMENTS]; | |
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 | ||
110 | if (parser.posarg_present && parser.nonposarg_present) | |
111 | { | |
112 | buf[0] = 0; | |
113 | return -1; // format strings with both positional and | |
114 | } // non-positional conversion specifier are unsupported !! | |
115 | ||
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 | ||
122 | // now load arguments from stack | |
123 | for (i=0; i < parser.nargs && ok; i++) | |
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... | |
128 | ok = parser.pspec[i] && parser.pspec[i]->LoadArg(&argdata[i], ap); | |
129 | } | |
130 | ||
131 | va_end(ap); | |
132 | ||
133 | // something failed while loading arguments from the variable list... | |
134 | // (e.g. the user repeated twice the same positional argument) | |
135 | if (!ok) | |
136 | { | |
137 | buf[0] = 0; | |
138 | return -1; | |
139 | } | |
140 | ||
141 | // finally, process each conversion specifier with its own argument | |
142 | const CharType *toparse = format; | |
143 | for (i=0; i < parser.nargs; i++) | |
144 | { | |
145 | // copy in the output buffer the portion of the format string between | |
146 | // last specifier and the current one | |
147 | size_t tocopy = ( parser.arg[i].m_pArgPos - toparse ); | |
148 | ||
149 | lenCur += wxCopyStrWithPercents(lenMax - lenCur, buf + lenCur, | |
150 | tocopy, toparse); | |
151 | if (lenCur == lenMax) | |
152 | { | |
153 | buf[lenMax - 1] = 0; | |
154 | return lenMax+1; // not enough space in the output buffer ! | |
155 | } | |
156 | ||
157 | // process this specifier directly in the output buffer | |
158 | int n = parser.arg[i].Process(buf+lenCur, lenMax - lenCur, | |
159 | &argdata[parser.arg[i].m_pos], lenCur); | |
160 | if (n == -1) | |
161 | { | |
162 | buf[lenMax-1] = wxT('\0'); // be sure to always NUL-terminate the string | |
163 | return lenMax+1; // not enough space in the output buffer ! | |
164 | } | |
165 | lenCur += n; | |
166 | ||
167 | // the +1 is because wxPrintfConvSpec::m_pArgEnd points to the last character | |
168 | // of the format specifier, but we are not interested to it... | |
169 | toparse = parser.arg[i].m_pArgEnd + 1; | |
170 | } | |
171 | ||
172 | // copy portion of the format string after last specifier | |
173 | // NOTE: toparse is pointing to the character just after the last processed | |
174 | // conversion specifier | |
175 | // NOTE2: the +1 is because we want to copy also the '\0' | |
176 | size_t tocopy = wxStrlen(format) + 1 - ( toparse - format ) ; | |
177 | ||
178 | lenCur += wxCopyStrWithPercents(lenMax - lenCur, buf + lenCur, | |
179 | tocopy, toparse) - 1; | |
180 | if (buf[lenCur]) | |
181 | { | |
182 | buf[lenCur] = 0; | |
183 | return lenMax+1; // not enough space in the output buffer ! | |
184 | } | |
185 | ||
186 | // Don't do: | |
187 | // wxASSERT(lenCur == wxStrlen(buf)); | |
188 | // in fact if we embedded NULLs in the output buffer (using %c with a '\0') | |
189 | // such check would fail | |
190 | ||
191 | return lenCur; | |
192 | } | |
193 | ||
194 | #endif // !defined(wxCRT_VsnprintfW) || !defined(wxCRT_VsnprintfA) | |
195 | ||
196 | // ---------------------------------------------------------------------------- | |
197 | // wxCRT_VsnprintfW | |
198 | // ---------------------------------------------------------------------------- | |
199 | ||
200 | #if !defined(wxCRT_VsnprintfW) | |
201 | ||
202 | #if !wxUSE_WXVSNPRINTFW | |
203 | #error "wxUSE_WXVSNPRINTFW must be 1 if our wxCRT_VsnprintfW is used" | |
204 | #endif | |
205 | ||
206 | int wxCRT_VsnprintfW(wchar_t *buf, size_t len, | |
207 | const wchar_t *format, va_list argptr) | |
208 | { | |
209 | return wxDoVsnprintf(buf, len, format, argptr); | |
210 | } | |
211 | ||
212 | #else // wxCRT_VsnprintfW is defined | |
213 | ||
214 | #if wxUSE_WXVSNPRINTFW | |
215 | #error "wxUSE_WXVSNPRINTFW must be 0 if our wxCRT_VsnprintfW is not used" | |
216 | #endif | |
217 | ||
218 | #endif // !wxCRT_VsnprintfW | |
219 | ||
220 | // ---------------------------------------------------------------------------- | |
221 | // wxCRT_VsnprintfA | |
222 | // ---------------------------------------------------------------------------- | |
223 | ||
224 | #ifndef wxCRT_VsnprintfA | |
225 | ||
226 | #if !wxUSE_WXVSNPRINTFA | |
227 | #error "wxUSE_WXVSNPRINTFA must be 1 if our wxCRT_VsnprintfA is used" | |
228 | #endif | |
229 | ||
230 | int wxCRT_VsnprintfA(char *buf, size_t len, | |
231 | const char *format, va_list argptr) | |
232 | { | |
233 | return wxDoVsnprintf(buf, len, format, argptr); | |
234 | } | |
235 | ||
236 | #else // wxCRT_VsnprintfA is defined | |
237 | ||
238 | #if wxUSE_WXVSNPRINTFA | |
239 | #error "wxUSE_WXVSNPRINTFA must be 0 if our wxCRT_VsnprintfA is not used" | |
240 | #endif | |
241 | ||
242 | #endif // !wxCRT_VsnprintfA |