Coverage Report

Created: 2025-06-13 06:30

/src/wxwidgets/include/wx/wxcrtvararg.h
Line
Count
Source (jump to first uncovered line)
1
///////////////////////////////////////////////////////////////////////////////
2
// Name:        wx/wxcrtvararg.h
3
// Purpose:     Type-safe ANSI and Unicode builds compatible wrappers for
4
//              printf(), scanf() and related CRT functions
5
// Author:      Joel Farley, Ove Kåven
6
// Modified by: Vadim Zeitlin, Robert Roebling, Ron Lee
7
// Created:     2007-02-19
8
// Copyright:   (c) 2007 REA Elektronik GmbH
9
// Licence:     wxWindows licence
10
///////////////////////////////////////////////////////////////////////////////
11
12
#ifndef _WX_WXCRTVARARG_H_
13
#define _WX_WXCRTVARARG_H_
14
15
// NB: User code should include wx/crt.h instead of including this
16
//     header directly.
17
18
#include "wx/wxcrt.h"
19
#include "wx/strvararg.h"
20
21
#include "wx/string.h"
22
23
// ----------------------------------------------------------------------------
24
// CRT functions aliases
25
// ----------------------------------------------------------------------------
26
27
/* Required for wxPrintf() etc */
28
#include <stdarg.h>
29
30
/* printf() family saga */
31
32
/*
33
   For many old Unix systems [v]snprintf()/vsscanf() exists in the system
34
   libraries but not in the headers, so we need to declare it ourselves to be
35
   able to use it.
36
 */
37
#ifdef __UNIX__
38
39
/* Wrapper for vsnprintf if it's 3rd parameter is non-const. Note: the
40
 * same isn't done for snprintf below, the builtin wxSnprintf_ is used
41
 * instead since it's already a simple wrapper */
42
#if defined __cplusplus && defined HAVE_BROKEN_VSNPRINTF_DECL
43
    inline int wx_fixed_vsnprintf(char *str, size_t size, const char *format, va_list ap)
44
    {
45
        return vsnprintf(str, size, (char*)format, ap);
46
    }
47
#endif
48
49
#endif /* __UNIX__ */
50
51
/*
52
   mingw32 normally uses MSVCRT which has non-standard vswprintf() and so
53
   normally _vsnwprintf() is used instead, the only exception is when mingw32
54
   is used with STLPort which does have a standard vswprintf() starting from
55
   version 5.1 which we can use.
56
 */
57
#ifdef __MINGW32__
58
    #if defined(_STLPORT_VERSION) && _STLPORT_VERSION >= 0x510
59
        #ifndef HAVE_VSWPRINTF
60
            #define HAVE_VSWPRINTF
61
        #endif
62
    #elif defined(HAVE_VSWPRINTF)
63
        /* can't use non-standard vswprintf() */
64
        #undef HAVE_VSWPRINTF
65
    #endif
66
#endif /* __MINGW32__ */
67
68
#if wxUSE_PRINTF_POS_PARAMS
69
    /*
70
        The systems where vsnprintf() supports positional parameters should
71
        define the HAVE_UNIX98_PRINTF symbol.
72
73
        On systems which don't (e.g. Windows) we are forced to use
74
        our wxVsnprintf() implementation.
75
    */
76
    #if defined(HAVE_UNIX98_PRINTF)
77
        #ifdef HAVE_VSWPRINTF
78
0
            #define wxCRT_VsnprintfW   vswprintf
79
        #endif
80
        #ifdef HAVE_BROKEN_VSNPRINTF_DECL
81
            #define wxCRT_VsnprintfA    wx_fixed_vsnprintf
82
        #else
83
            #define wxCRT_VsnprintfA    vsnprintf
84
        #endif
85
    #else /* !HAVE_UNIX98_PRINTF */
86
        /*
87
            The only compiler with positional parameters support under Windows
88
            is VC++ 8.0 which provides a new xxprintf_p() functions family.
89
            The 2003 PSDK includes a slightly earlier version of VC8 than the
90
            main release and does not have the printf_p functions.
91
         */
92
        #if defined _MSC_FULL_VER && _MSC_FULL_VER >= 140050727
93
            #define wxCRT_VsnprintfA    _vsprintf_p
94
            #define wxCRT_VsnprintfW    _vswprintf_p
95
        #endif
96
    #endif /* HAVE_UNIX98_PRINTF/!HAVE_UNIX98_PRINTF */
97
#else /* !wxUSE_PRINTF_POS_PARAMS */
98
    /*
99
       We always want to define safe snprintf() function to be used instead of
100
       sprintf(). Some compilers already have it (or rather vsnprintf() which
101
       we really need...), otherwise we implement it using our own printf()
102
       code.
103
104
       We define function with a trailing underscore here because the real one
105
       is a wrapper around it as explained below
106
     */
107
108
    #if defined(__VISUALC__)
109
        #define wxCRT_VsnprintfA    _vsnprintf
110
        #define wxCRT_VsnprintfW    _vsnwprintf
111
    #else
112
        #if defined(HAVE__VSNWPRINTF)
113
            #define wxCRT_VsnprintfW    _vsnwprintf
114
        #elif defined(HAVE_VSWPRINTF)
115
            #define wxCRT_VsnprintfW     vswprintf
116
        #endif
117
118
        #if defined(HAVE_VSNPRINTF)
119
            #ifdef HAVE_BROKEN_VSNPRINTF_DECL
120
                #define wxCRT_VsnprintfA    wx_fixed_vsnprintf
121
            #else
122
                #define wxCRT_VsnprintfA    vsnprintf
123
            #endif
124
        #endif
125
    #endif
126
#endif /* wxUSE_PRINTF_POS_PARAMS/!wxUSE_PRINTF_POS_PARAMS */
127
128
#ifndef wxCRT_VsnprintfW
129
    /* no (suitable) vsnprintf(), cook our own */
130
    WXDLLIMPEXP_BASE int
131
    wxCRT_VsnprintfW(wchar_t *buf, size_t len, const wchar_t *format, va_list argptr);
132
    #define wxUSE_WXVSNPRINTFW 1
133
#else
134
    #define wxUSE_WXVSNPRINTFW 0
135
#endif
136
137
#ifndef wxCRT_VsnprintfA
138
        /* no (suitable) vsnprintf(), cook our own */
139
        WXDLLIMPEXP_BASE int
140
        wxCRT_VsnprintfA(char *buf, size_t len, const char *format, va_list argptr);
141
        #define wxUSE_WXVSNPRINTFA 1
142
#else
143
        #define wxUSE_WXVSNPRINTFA 0
144
#endif
145
146
// for wxString code, define wxUSE_WXVSNPRINTF to indicate that wx
147
// implementation is used no matter what (in UTF-8 build, either *A or *W
148
// version may be called):
149
#if wxUSE_UNICODE_WCHAR
150
    #define wxUSE_WXVSNPRINTF wxUSE_WXVSNPRINTFW
151
#elif wxUSE_UTF8_LOCALE_ONLY
152
    #define wxUSE_WXVSNPRINTF wxUSE_WXVSNPRINTFA
153
#else // UTF-8 under any locale
154
    #define wxUSE_WXVSNPRINTF (wxUSE_WXVSNPRINTFA && wxUSE_WXVSNPRINTFW)
155
#endif
156
157
#define wxCRT_FprintfA       fprintf
158
#define wxCRT_PrintfA        printf
159
#define wxCRT_VfprintfA      vfprintf
160
#define wxCRT_VprintfA       vprintf
161
#define wxCRT_VsprintfA      vsprintf
162
163
/*
164
   In Unicode mode we need to have all standard functions such as wprintf() and
165
   so on but not all systems have them so use our own implementations in this
166
   case.
167
 */
168
#if !defined(wxHAVE_TCHAR_SUPPORT) && !defined(HAVE_WPRINTF)
169
    #define wxNEED_WPRINTF
170
#endif
171
#if !defined(wxHAVE_TCHAR_SUPPORT) && !defined(HAVE_VSWSCANF) && defined(HAVE_VSSCANF)
172
    #define wxNEED_VSWSCANF
173
#endif
174
175
176
#if defined(wxNEED_WPRINTF)
177
    /*
178
        we need to implement all wide character printf functions either because
179
        we don't have them at all or because they don't have the semantics we
180
        need
181
     */
182
    int wxCRT_PrintfW( const wchar_t *format, ... );
183
    int wxCRT_FprintfW( FILE *stream, const wchar_t *format, ... );
184
    int wxCRT_VfprintfW( FILE *stream, const wchar_t *format, va_list ap );
185
    int wxCRT_VprintfW( const wchar_t *format, va_list ap );
186
    int wxCRT_VsprintfW( wchar_t *str, const wchar_t *format, va_list ap );
187
#else /* !wxNEED_WPRINTF */
188
0
    #define wxCRT_FprintfW      fwprintf
189
    #define wxCRT_PrintfW       wprintf
190
    #define wxCRT_VfprintfW     vfwprintf
191
    #define wxCRT_VprintfW      vwprintf
192
193
    #if defined(__WINDOWS__) && !defined(HAVE_VSWPRINTF)
194
        // only non-standard vswprintf() without buffer size argument can be used here
195
        #define  wxCRT_VsprintfW     vswprintf
196
    #endif
197
#endif /* wxNEED_WPRINTF */
198
199
200
/* Required for wxScanf() etc. */
201
#define wxCRT_ScanfA     scanf
202
#define wxCRT_SscanfA    sscanf
203
#define wxCRT_FscanfA    fscanf
204
205
/* vsscanf() may have a wrong declaration with non-const first parameter, fix
206
 * this by wrapping it if necessary. */
207
#if defined __cplusplus && defined HAVE_BROKEN_VSSCANF_DECL
208
    inline int wxCRT_VsscanfA(const char *str, const char *format, va_list ap)
209
    {
210
        return vsscanf(const_cast<char *>(str), format, ap);
211
    }
212
#else
213
    wxDECL_FOR_STRICT_MINGW32(int, vsscanf, (const char*, const char*, va_list))
214
215
0
    #define wxCRT_VsscanfA   vsscanf
216
#endif
217
218
#if defined(wxNEED_WPRINTF)
219
    int wxCRT_ScanfW(const wchar_t *format, ...);
220
    int wxCRT_SscanfW(const wchar_t *str, const wchar_t *format, ...);
221
    int wxCRT_FscanfW(FILE *stream, const wchar_t *format, ...);
222
#else
223
    #define wxCRT_ScanfW     wxVMS_USE_STD wscanf
224
    #define wxCRT_SscanfW    wxVMS_USE_STD swscanf
225
    #define wxCRT_FscanfW    wxVMS_USE_STD fwscanf
226
#endif
227
#ifdef wxNEED_VSWSCANF
228
    int wxCRT_VsscanfW(const wchar_t *str, const wchar_t *format, va_list ap);
229
#else
230
    wxDECL_FOR_STRICT_MINGW32(int, vswscanf, (const wchar_t*, const wchar_t*, va_list))
231
232
0
    #define wxCRT_VsscanfW   wxVMS_USE_STD vswscanf
233
#endif
234
235
// ----------------------------------------------------------------------------
236
// user-friendly wrappers to CRT functions
237
// ----------------------------------------------------------------------------
238
239
wxGCC_ONLY_WARNING_SUPPRESS(format-nonliteral)
240
wxGCC_ONLY_WARNING_SUPPRESS(format-security)
241
242
template <typename... Targs>
243
int wxPrintf(const wxFormatString& format, Targs... args)
244
{
245
    format.Validate({wxFormatStringSpecifier<Targs>::value...});
246
247
#if wxUSE_UNICODE_UTF8
248
    #if !wxUSE_UTF8_LOCALE_ONLY
249
        if ( wxLocaleIsUtf8 )
250
    #endif
251
            return wxCRT_PrintfA(format, wxArgNormalizerUtf8<Targs>{args, nullptr, 0}.get()...);
252
#endif // wxUSE_UNICODE_UTF8
253
254
#if !wxUSE_UTF8_LOCALE_ONLY
255
    return wxCRT_PrintfW(format, wxArgNormalizerWchar<Targs>{args, nullptr, 0}.get()...);
256
#endif // !wxUSE_UTF8_LOCALE_ONLY
257
}
258
259
template <typename... Targs>
260
int wxFprintf(FILE* fp, const wxFormatString& format, Targs... args)
261
0
{
262
0
    format.Validate({wxFormatStringSpecifier<Targs>::value...});
263
264
#if wxUSE_UNICODE_UTF8
265
    #if !wxUSE_UTF8_LOCALE_ONLY
266
        if ( wxLocaleIsUtf8 )
267
    #endif
268
            return wxCRT_FprintfA(fp, format, wxArgNormalizerUtf8<Targs>{args, nullptr, 0}.get()...);
269
#endif // wxUSE_UNICODE_UTF8
270
271
0
#if !wxUSE_UTF8_LOCALE_ONLY
272
0
    return wxCRT_FprintfW(fp, format, wxArgNormalizerWchar<Targs>{args, nullptr, 0}.get()...);
273
0
#endif // !wxUSE_UTF8_LOCALE_ONLY
274
0
}
275
276
wxGCC_ONLY_WARNING_RESTORE(format-security)
277
wxGCC_ONLY_WARNING_RESTORE(format-nonliteral)
278
279
// va_list versions of printf functions simply forward to the respective
280
// CRT function; note that they assume that va_list was created using
281
// wxArgNormalizer<T>!
282
#if wxUSE_UNICODE_UTF8
283
    #if wxUSE_UTF8_LOCALE_ONLY
284
        #define WX_VARARG_VFOO_IMPL(args, implW, implA)              \
285
            return implA args
286
    #else
287
        #define WX_VARARG_VFOO_IMPL(args, implW, implA)              \
288
            if ( wxLocaleIsUtf8 ) return implA args;                 \
289
            else return implW args
290
    #endif
291
#else // wxUSE_UNICODE_WCHAR
292
    #define WX_VARARG_VFOO_IMPL(args, implW, implA)                  \
293
        return implW args
294
#endif
295
296
inline int
297
wxVprintf(const wxString& format, va_list ap)
298
0
{
299
0
    WX_VARARG_VFOO_IMPL((wxFormatString(format), ap),
300
0
                        wxCRT_VprintfW, wxCRT_VprintfA);
301
0
}
302
303
inline int
304
wxVfprintf(FILE *f, const wxString& format, va_list ap)
305
0
{
306
0
    WX_VARARG_VFOO_IMPL((f, wxFormatString(format), ap),
307
0
                        wxCRT_VfprintfW, wxCRT_VfprintfA);
308
0
}
309
310
#undef WX_VARARG_VFOO_IMPL
311
312
313
// wxSprintf() and friends have to be implemented in two forms, one for
314
// writing to char* buffer and one for writing to wchar_t*:
315
316
#if !wxUSE_UTF8_LOCALE_ONLY
317
int WXDLLIMPEXP_BASE wxDoSprintfWchar(char *str, const wxChar *format, ...);
318
int WXDLLIMPEXP_BASE wxDoSprintfWchar(wchar_t *str, const wxChar *format, ...);
319
#endif
320
#if wxUSE_UNICODE_UTF8
321
int WXDLLIMPEXP_BASE wxDoSprintfUtf8(char *str, const char *format, ...);
322
int WXDLLIMPEXP_BASE wxDoSprintfUtf8(wchar_t *str, const char *format, ...);
323
#endif
324
325
template <typename CharType, typename... Targs>
326
int wxSprintf(CharType* str, const wxFormatString& format, Targs... args)
327
{
328
    format.Validate({wxFormatStringSpecifier<Targs>::value...});
329
330
#if wxUSE_UNICODE_UTF8
331
    #if !wxUSE_UTF8_LOCALE_ONLY
332
        if ( wxLocaleIsUtf8 )
333
    #endif
334
            return wxDoSprintfUtf8(str, format, wxArgNormalizerUtf8<Targs>{args, nullptr, 0}.get()...);
335
#endif // wxUSE_UNICODE_UTF8
336
337
#if !wxUSE_UTF8_LOCALE_ONLY
338
    return wxDoSprintfWchar(str, format, wxArgNormalizerWchar<Targs>{args, nullptr, 0}.get()...);
339
#endif // !wxUSE_UTF8_LOCALE_ONLY
340
}
341
342
int WXDLLIMPEXP_BASE
343
wxVsprintf(char *str, const wxString& format, va_list argptr);
344
345
#if !wxUSE_UTF8_LOCALE_ONLY
346
int WXDLLIMPEXP_BASE wxDoSnprintfWchar(char *str, size_t size, const wxChar *format, ...);
347
int WXDLLIMPEXP_BASE wxDoSnprintfWchar(wchar_t *str, size_t size, const wxChar *format, ...);
348
#endif
349
#if wxUSE_UNICODE_UTF8
350
int WXDLLIMPEXP_BASE wxDoSnprintfUtf8(char *str, size_t size, const char *format, ...);
351
int WXDLLIMPEXP_BASE wxDoSnprintfUtf8(wchar_t *str, size_t size, const char *format, ...);
352
#endif
353
354
template <typename CharType, typename... Targs>
355
int wxSnprintf(CharType* str, size_t size, const wxFormatString& format, Targs... args)
356
{
357
    format.Validate({wxFormatStringSpecifier<Targs>::value...});
358
359
#if wxUSE_UNICODE_UTF8
360
    #if !wxUSE_UTF8_LOCALE_ONLY
361
        if ( wxLocaleIsUtf8 )
362
    #endif
363
            return wxDoSnprintfUtf8(str, size, format, wxArgNormalizerUtf8<Targs>{args, nullptr, 0}.get()...);
364
#endif // wxUSE_UNICODE_UTF8
365
366
#if !wxUSE_UTF8_LOCALE_ONLY
367
    return wxDoSnprintfWchar(str, size, format, wxArgNormalizerWchar<Targs>{args, nullptr, 0}.get()...);
368
#endif // !wxUSE_UTF8_LOCALE_ONLY
369
}
370
371
int WXDLLIMPEXP_BASE
372
wxVsnprintf(char *str, size_t size, const wxString& format, va_list argptr);
373
374
#if !wxUSE_UTF8_LOCALE_ONLY
375
#endif
376
#if wxUSE_UNICODE_UTF8
377
#endif
378
379
int WXDLLIMPEXP_BASE
380
wxVsprintf(wchar_t *str, const wxString& format, va_list argptr);
381
382
int WXDLLIMPEXP_BASE
383
wxVsnprintf(wchar_t *str, size_t size, const wxString& format, va_list argptr);
384
385
// We can't use wxArgNormalizer<T> for variadic arguments to wxScanf() etc.
386
// because they are writable, so instead of providing friendly template
387
// vararg-like functions, we just provide both char* and wchar_t* variants
388
// of these functions. The type of output variadic arguments for %s must match
389
// the type of 'str' and 'format' arguments.
390
//
391
// For compatibility with earlier wx versions, we also provide wxSscanf()
392
// version with the first argument (input string) wxString; for this version,
393
// the type of output string values is determined by the type of format string
394
// only.
395
396
#define _WX_SCANFUNC_EXTRACT_ARGS_1(x)   x
397
0
#define _WX_SCANFUNC_EXTRACT_ARGS_2(x,y) x, y
398
0
#define _WX_SCANFUNC_EXTRACT_ARGS(N, args) _WX_SCANFUNC_EXTRACT_ARGS_##N args
399
400
0
#define _WX_VARARG_PASS_WRITABLE(i) a##i
401
402
#define _WX_DEFINE_SCANFUNC(N, dummy1, name, impl, passfixed, numfixed, fixed)\
403
    template<_WX_VARARG_JOIN(N, _WX_VARARG_TEMPL)>                            \
404
    int name(_WX_SCANFUNC_EXTRACT_ARGS(numfixed, fixed),                      \
405
             _WX_VARARG_JOIN(N, _WX_VARARG_ARG))                              \
406
0
    {                                                                         \
407
0
        return  impl(_WX_SCANFUNC_EXTRACT_ARGS(numfixed, passfixed),          \
408
0
                     _WX_VARARG_JOIN(N, _WX_VARARG_PASS_WRITABLE));           \
409
0
    }
Unexecuted instantiation: int wxSscanf<unsigned int*>(wchar_t const*, wchar_t const*, unsigned int*)
Unexecuted instantiation: int wxSscanf<int*, int*, int*>(wxCStrData const&, wchar_t const*, int*, int*, int*)
Unexecuted instantiation: int wxSscanf<int*, int*>(wxCStrData const&, wchar_t const*, int*, int*)
410
411
#define WX_DEFINE_SCANFUNC(name, numfixed, fixed, impl, passfixed)            \
412
    _WX_VARARG_ITER(_WX_VARARG_MAX_ARGS,                                      \
413
                    _WX_DEFINE_SCANFUNC,                                      \
414
                    dummy1, name, impl, passfixed, numfixed, fixed)
415
416
// this is needed to normalize the format string, see src/common/strvararg.cpp
417
// for more details
418
#ifdef __WINDOWS__
419
    #define wxScanfConvertFormatW(fmt) fmt
420
#else
421
    const wxScopedWCharBuffer
422
    WXDLLIMPEXP_BASE wxScanfConvertFormatW(const wchar_t *format);
423
#endif
424
425
WX_DEFINE_SCANFUNC(wxScanf, 1, (const char *format),
426
                   wxCRT_ScanfA, (format))
427
WX_DEFINE_SCANFUNC(wxScanf, 1, (const wchar_t *format),
428
                   wxCRT_ScanfW, (wxScanfConvertFormatW(format)))
429
430
WX_DEFINE_SCANFUNC(wxFscanf, 2, (FILE *stream, const char *format),
431
                   wxCRT_FscanfA, (stream, format))
432
WX_DEFINE_SCANFUNC(wxFscanf, 2, (FILE *stream, const wchar_t *format),
433
                   wxCRT_FscanfW, (stream, wxScanfConvertFormatW(format)))
434
435
WX_DEFINE_SCANFUNC(wxSscanf, 2, (const char *str, const char *format),
436
                   wxCRT_SscanfA, (str, format))
437
WX_DEFINE_SCANFUNC(wxSscanf, 2, (const wchar_t *str, const wchar_t *format),
438
                   wxCRT_SscanfW, (str, wxScanfConvertFormatW(format)))
439
WX_DEFINE_SCANFUNC(wxSscanf, 2, (const wxScopedCharBuffer& str, const char *format),
440
                   wxCRT_SscanfA, (str.data(), format))
441
WX_DEFINE_SCANFUNC(wxSscanf, 2, (const wxScopedWCharBuffer& str, const wchar_t *format),
442
                   wxCRT_SscanfW, (str.data(), wxScanfConvertFormatW(format)))
443
#ifndef wxNO_IMPLICIT_WXSTRING_ENCODING
444
WX_DEFINE_SCANFUNC(wxSscanf, 2, (const wxString& str, const char *format),
445
                   wxCRT_SscanfA, (str.mb_str(), format))
446
#endif
447
WX_DEFINE_SCANFUNC(wxSscanf, 2, (const wxString& str, const wchar_t *format),
448
                   wxCRT_SscanfW, (str.wc_str(), wxScanfConvertFormatW(format)))
449
#ifndef wxNO_IMPLICIT_WXSTRING_ENCODING
450
WX_DEFINE_SCANFUNC(wxSscanf, 2, (const wxCStrData& str, const char *format),
451
                   wxCRT_SscanfA, (str.AsCharBuf(), format))
452
#endif
453
WX_DEFINE_SCANFUNC(wxSscanf, 2, (const wxCStrData& str, const wchar_t *format),
454
                   wxCRT_SscanfW, (str.AsWCharBuf(), wxScanfConvertFormatW(format)))
455
456
// Visual C++ doesn't provide vsscanf()
457
#ifndef __VISUALC___
458
int WXDLLIMPEXP_BASE wxVsscanf(const char *str, const char *format, va_list ap);
459
int WXDLLIMPEXP_BASE wxVsscanf(const wchar_t *str, const wchar_t *format, va_list ap);
460
int WXDLLIMPEXP_BASE wxVsscanf(const wxScopedCharBuffer& str, const char *format, va_list ap);
461
int WXDLLIMPEXP_BASE wxVsscanf(const wxScopedWCharBuffer& str, const wchar_t *format, va_list ap);
462
int WXDLLIMPEXP_BASE wxVsscanf(const wxString& str, const char *format, va_list ap);
463
int WXDLLIMPEXP_BASE wxVsscanf(const wxString& str, const wchar_t *format, va_list ap);
464
int WXDLLIMPEXP_BASE wxVsscanf(const wxCStrData& str, const char *format, va_list ap);
465
int WXDLLIMPEXP_BASE wxVsscanf(const wxCStrData& str, const wchar_t *format, va_list ap);
466
#endif // !__VISUALC__
467
468
#endif /* _WX_WXCRTVARARG_H_ */