]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/wxprintf.cpp
Corrected IMPLEMENT_CLASS/BEGIN_EVENT_TABLE base class
[wxWidgets.git] / src / common / wxprintf.cpp
... / ...
CommitLineData
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.
60template<typename CharType>
61static 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
91template<typename CharType>
92static 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
206int 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
230int 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