]> git.saurik.com Git - wxWidgets.git/blob - src/common/wxprintf.cpp
Fixed keyboard navigation in generic tree control.
[wxWidgets.git] / src / common / wxprintf.cpp
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         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
152         // copy in the output buffer the portion of the format string between
153         // last specifier and the current one
154         size_t tocopy = ( spec.m_pArgPos - toparse );
155
156         lenCur += wxCopyStrWithPercents(lenMax - lenCur, buf + lenCur,
157                                         tocopy, toparse);
158         if (lenCur == lenMax)
159         {
160             buf[lenMax - 1] = 0;
161             return lenMax+1;      // not enough space in the output buffer !
162         }
163
164         // process this specifier directly in the output buffer
165         int n = spec.Process(buf+lenCur, lenMax - lenCur,
166                                       &argdata[spec.m_pos], lenCur);
167         if (n == -1)
168         {
169             buf[lenMax-1] = wxT('\0');  // be sure to always NUL-terminate the string
170             return lenMax+1;      // not enough space in the output buffer !
171         }
172         lenCur += n;
173
174         // the +1 is because wxPrintfConvSpec::m_pArgEnd points to the last character
175         // of the format specifier, but we are not interested to it...
176         toparse = spec.m_pArgEnd + 1;
177     }
178
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 ) ;
184
185     lenCur += wxCopyStrWithPercents(lenMax - lenCur, buf + lenCur,
186                                     tocopy, toparse) - 1;
187     if (buf[lenCur])
188     {
189         buf[lenCur] = 0;
190         return lenMax+1;     // not enough space in the output buffer !
191     }
192
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
198     return lenCur;
199 }
200
201 #endif // !defined(wxCRT_VsnprintfW) || !defined(wxCRT_VsnprintfA)
202
203 // ----------------------------------------------------------------------------
204 // wxCRT_VsnprintfW
205 // ----------------------------------------------------------------------------
206
207 #if !defined(wxCRT_VsnprintfW)
208
209 #if !wxUSE_WXVSNPRINTFW
210     #error "wxUSE_WXVSNPRINTFW must be 1 if our wxCRT_VsnprintfW is used"
211 #endif
212
213 int wxCRT_VsnprintfW(wchar_t *buf, size_t len,
214                      const wchar_t *format, va_list argptr)
215 {
216     return wxDoVsnprintf(buf, len, format, argptr);
217 }
218
219 #else    // wxCRT_VsnprintfW is defined
220
221 #if wxUSE_WXVSNPRINTFW
222     #error "wxUSE_WXVSNPRINTFW must be 0 if our wxCRT_VsnprintfW is not used"
223 #endif
224
225 #endif // !wxCRT_VsnprintfW
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