]> git.saurik.com Git - wxWidgets.git/blame - src/common/wxprintf.cpp
Upgrade bundled zlib to 1.2.8.
[wxWidgets.git] / src / common / wxprintf.cpp
CommitLineData
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 59template<typename CharType>
3c7f37ed
MW
60static 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
90template<typename CharType>
91static 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
212int 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
236int 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