]> git.saurik.com Git - wxWidgets.git/blame - src/common/wxchar.cpp
Use same type in both results of A?B:C operator (Tinderbox build fix).
[wxWidgets.git] / src / common / wxchar.cpp
CommitLineData
c9e089e9 1/////////////////////////////////////////////////////////////////////////////
41e155b4 2// Name: src/common/wxchar.cpp
c9e089e9 3// Purpose: wxChar implementation
247c23b4
VZ
4// Author: Ove Kaven
5// Modified by: Ron Lee, Francesco Montorsi
c9e089e9
OK
6// Created: 09/04/99
7// RCS-ID: $Id$
77ffb593 8// Copyright: (c) wxWidgets copyright
65571936 9// Licence: wxWindows licence
c9e089e9
OK
10/////////////////////////////////////////////////////////////////////////////
11
c9e089e9
OK
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__
8898456d 20 #pragma hdrstop
c9e089e9
OK
21#endif
22
4400c1a4
OK
23#define _ISOC9X_SOURCE 1 // to get vsscanf()
24#define _BSD_SOURCE 1 // to still get strdup()
25
84fff0b3 26#include <stdio.h>
c9e089e9
OK
27#include <stdlib.h>
28#include <string.h>
1c193821
JS
29
30#ifndef __WXWINCE__
8898456d
WS
31 #include <time.h>
32 #include <locale.h>
1c193821 33#else
8898456d 34 #include "wx/msw/wince/time.h"
1c193821 35#endif
c9e089e9
OK
36
37#ifndef WX_PRECOMP
8898456d
WS
38 #include "wx/wxchar.h"
39 #include "wx/string.h"
40 #include "wx/hash.h"
c9e089e9 41#endif
7a828c7f 42 #include "wx/utils.h" // for wxMin and wxMax
c9e089e9 43
57f6da0d 44#if defined(__WIN32__) && defined(wxNEED_WX_CTYPE_H)
b3e8d00a 45 #include <windef.h>
8898456d
WS
46 #include <winbase.h>
47 #include <winnls.h>
48 #include <winnt.h>
57f6da0d
OK
49#endif
50
31907d03 51#if defined(__MWERKS__) && __MSL__ >= 0x6000
52cbcda3 52namespace std {}
31907d03
SC
53using namespace std ;
54#endif
55
d0bdc3ca 56#if wxUSE_WCHAR_T
434d2cb3 57size_t WXDLLEXPORT wxMB2WC(wchar_t *buf, const char *psz, size_t n)
c9e089e9 58{
2b5f62a0 59 // assume that we have mbsrtowcs() too if we have wcsrtombs()
fe190003 60#ifdef HAVE_WCSRTOMBS
2b5f62a0
VZ
61 mbstate_t mbstate;
62 memset(&mbstate, 0, sizeof(mbstate_t));
63#endif
64
c9e089e9 65 if (buf) {
923d3156 66 if (!n || !*psz) {
223d09f6 67 if (n) *buf = wxT('\0');
923d3156
OK
68 return 0;
69 }
2b5f62a0
VZ
70#ifdef HAVE_WCSRTOMBS
71 return mbsrtowcs(buf, &psz, n, &mbstate);
72#else
1e96e503 73 return wxMbstowcs(buf, psz, n);
2b5f62a0 74#endif
c9e089e9
OK
75 }
76
0d8c57c0
VZ
77 // note that we rely on common (and required by Unix98 but unfortunately not
78 // C99) extension which allows to call mbs(r)towcs() with NULL output pointer
79 // to just get the size of the needed buffer -- this is needed as otherwise
80 // we have no idea about how much space we need and if the CRT doesn't
81 // support it (the only currently known example being Metrowerks, see
82 // wx/wxchar.h) we don't use its mbstowcs() at all
b3e8d00a 83#ifdef HAVE_WCSRTOMBS
c9e089e9 84 return mbsrtowcs((wchar_t *) NULL, &psz, 0, &mbstate);
2b5f62a0 85#else
1e96e503 86 return wxMbstowcs((wchar_t *) NULL, psz, 0);
2b5f62a0 87#endif
c9e089e9
OK
88}
89
434d2cb3 90size_t WXDLLEXPORT wxWC2MB(char *buf, const wchar_t *pwz, size_t n)
c9e089e9 91{
fe190003 92#ifdef HAVE_WCSRTOMBS
2b5f62a0
VZ
93 mbstate_t mbstate;
94 memset(&mbstate, 0, sizeof(mbstate_t));
95#endif
96
c9e089e9 97 if (buf) {
923d3156
OK
98 if (!n || !*pwz) {
99 // glibc2.1 chokes on null input
100 if (n) *buf = '\0';
101 return 0;
102 }
fe190003 103#ifdef HAVE_WCSRTOMBS
2b5f62a0
VZ
104 return wcsrtombs(buf, &pwz, n, &mbstate);
105#else
1e96e503 106 return wxWcstombs(buf, pwz, n);
2b5f62a0 107#endif
c9e089e9
OK
108 }
109
fe190003 110#ifdef HAVE_WCSRTOMBS
c9e089e9 111 return wcsrtombs((char *) NULL, &pwz, 0, &mbstate);
2b5f62a0 112#else
1e96e503 113 return wxWcstombs((char *) NULL, pwz, 0);
2b5f62a0 114#endif
c9e089e9 115}
b3e8d00a 116#endif // wxUSE_WCHAR_T
c9e089e9 117
434d2cb3
OK
118bool WXDLLEXPORT wxOKlibc()
119{
5283098e 120#if wxUSE_WCHAR_T && defined(__UNIX__) && defined(__GLIBC__) && !defined(__WINE__)
66b3ec7f
OK
121 // glibc 2.0 uses UTF-8 even when it shouldn't
122 wchar_t res = 0;
434d2cb3 123 if ((MB_CUR_MAX == 2) &&
66b3ec7f 124 (wxMB2WC(&res, "\xdd\xa5", 1) == 1) &&
434d2cb3
OK
125 (res==0x765)) {
126 // this is UTF-8 allright, check whether that's what we want
66b3ec7f 127 char *cur_locale = setlocale(LC_CTYPE, NULL);
434d2cb3 128 if ((strlen(cur_locale) < 4) ||
f6f5941b
VZ
129 (strcasecmp(cur_locale + strlen(cur_locale) - 4, "utf8")) ||
130 (strcasecmp(cur_locale + strlen(cur_locale) - 5, "utf-8"))) {
434d2cb3 131 // nope, don't use libc conversion
cab1a605 132 return false;
434d2cb3
OK
133 }
134 }
135#endif
cab1a605 136 return true;
434d2cb3
OK
137}
138
f6f5941b
VZ
139// ============================================================================
140// printf() functions business
141// ============================================================================
142
df17b887
VZ
143// special test mode: define all functions below even if we don't really need
144// them to be able to test them
145#ifdef wxTEST_PRINTF
146 #undef wxFprintf
147 #undef wxPrintf
148 #undef wxSprintf
149 #undef wxVfprintf
150 #undef wxVsprintf
151 #undef wxVprintf
152 #undef wxVsnprintf_
153 #undef wxSnprintf_
154
155 #define wxNEED_WPRINTF
156
157 int wxVfprintf( FILE *stream, const wxChar *format, va_list argptr );
158#endif
159
f6f5941b
VZ
160// ----------------------------------------------------------------------------
161// implement [v]snprintf() if the system doesn't provide a safe one
7a828c7f
VZ
162// or if the system's one does not support positional parameters
163// (very useful for i18n purposes)
f6f5941b
VZ
164// ----------------------------------------------------------------------------
165
166#if !defined(wxVsnprintf_)
7a828c7f
VZ
167
168// wxUSE_STRUTILS says our wxVsnprintf_ implementation to use or not to
169// use wxStrlen and wxStrncpy functions over one-char processing loops.
170//
171// Some benchmarking revealed that wxUSE_STRUTILS == 1 has the following
172// effects:
173// -> on Windows:
174// when in ANSI mode, this setting does not change almost anything
175// when in Unicode mode, it gives ~ 50% of slowdown !
176// -> on Linux:
177// both in ANSI and Unicode mode it gives ~ 60% of speedup !
178//
179#if defined(WIN32) && wxUSE_UNICODE
180#define wxUSE_STRUTILS 0
181#else
182#define wxUSE_STRUTILS 1
183#endif
184
185// some limits of our implementation
186#define wxMAX_SVNPRINTF_ARGUMENTS 64
187#define wxMAX_SVNPRINTF_FLAGBUFFER_LEN 32
188
7d70c309 189// the conversion specifiers accepted by wxVsnprintf_
7a828c7f
VZ
190enum wxPrintfArgType {
191 wxPAT_INVALID = -1,
192
193 wxPAT_INT, // %d, %i, %o, %u, %x, %X
194 wxPAT_LONGINT, // %ld, etc
195#if SIZEOF_LONG_LONG
196 wxPAT_LONGLONGINT, // %Ld, etc
197#endif
198 wxPAT_SIZET, // %Zd, etc
199
200 wxPAT_DOUBLE, // %e, %E, %f, %g, %G
201 wxPAT_LONGDOUBLE, // %le, etc
202
203 wxPAT_POINTER, // %p
204
205 wxPAT_CHAR, // %hc (in ANSI mode: %c, too)
206 wxPAT_WCHAR, // %lc (in Unicode mode: %c, too)
207
208 wxPAT_PCHAR, // %s (related to a char *)
209 wxPAT_PWCHAR, // %s (related to a wchar_t *)
210
211 wxPAT_NINT, // %n
212 wxPAT_NSHORTINT, // %hn
213 wxPAT_NLONGINT // %ln
214};
215
7d70c309 216// an argument passed to wxVsnprintf_
7a828c7f
VZ
217typedef union {
218 int pad_int; // %d, %i, %o, %u, %x, %X
219 long int pad_longint; // %ld, etc
220#if SIZEOF_LONG_LONG
221 long long int pad_longlongint; // %Ld, etc
222#endif
223 size_t pad_sizet; // %Zd, etc
224
225 double pad_double; // %e, %E, %f, %g, %G
226 long double pad_longdouble; // %le, etc
227
228 void *pad_pointer; // %p
229
230 char pad_char; // %hc (in ANSI mode: %c, too)
231 wchar_t pad_wchar; // %lc (in Unicode mode: %c, too)
232
233 char *pad_pchar; // %s (related to a char *)
234 wchar_t *pad_pwchar; // %s (related to a wchar_t *)
235
236 int *pad_nint; // %n
237 short int *pad_nshortint; // %hn
238 long int *pad_nlongint; // %ln
239} wxPrintfArg;
240
241
242// Contains parsed data relative to a conversion specifier given to
7d70c309 243// wxVsnprintf_ and parsed from the format string
7a828c7f
VZ
244// NOTE: in C++ there is almost no difference between struct & classes thus
245// there is no performance gain by using a struct here...
246class wxPrintfConvSpec
f6f5941b 247{
7a828c7f 248public:
f6f5941b 249
7a828c7f
VZ
250 // the position of the argument relative to this conversion specifier
251 size_t pos;
252
253 // the type of this conversion specifier
254 wxPrintfArgType type;
255
256 // the minimum and maximum width
257 // when one of this var is set to -1 it means: use the following argument
258 // in the stack as minimum/maximum width for this conversion specifier
259 int min_width, max_width;
5f1d3069 260
7a828c7f
VZ
261 // does the argument need to the be aligned to left ?
262 bool adj_left;
263
264 // pointer to the '%' of this conversion specifier in the format string
265 // NOTE: this points somewhere in the string given to the Parse() function -
266 // it's task of the caller ensure that memory is still valid !
267 const wxChar *argpos;
268
269 // pointer to the last character of this conversion specifier in the
270 // format string
271 // NOTE: this points somewhere in the string given to the Parse() function -
272 // it's task of the caller ensure that memory is still valid !
273 const wxChar *argend;
274
275 // a little buffer where formatting flags like #+\.hlqLZ are stored by Parse()
276 // for use in Process()
7d70c309
WS
277 // NB: this buffer can be safely a char buffer instead of a wchar_t buffer
278 // since it's used only for numeric conversion specifier and always
279 // with sprintf().
7a828c7f
VZ
280 char szFlags[wxMAX_SVNPRINTF_FLAGBUFFER_LEN];
281
282
283public:
284
285 // we don't declare this as a constructor otherwise it would be called
7d70c309 286 // automatically and we don't want this: to be optimized, wxVsnprintf_
7a828c7f
VZ
287 // calls this function only on really-used instances of this class.
288 void Init();
289
290 // Parses the first conversion specifier in the given string, which must
291 // begin with a '%'. Returns false if the first '%' does not introduce a
292 // (valid) conversion specifier and thus should be ignored.
293 bool Parse(const wxChar *format);
294
295 // Process this conversion specifier and puts the result in the given
296 // buffer. Returns the number of characters written in 'buf' or -1 if
297 // there's not enough space.
298 int Process(wxChar *buf, size_t lenMax, wxPrintfArg *p);
299
300 // Loads the argument of this conversion specifier from given va_list.
301 bool LoadArg(wxPrintfArg *p, va_list &argptr);
302
303private:
304 // An helper function of LoadArg() which is used to handle the '*' flag
305 void ReplaceAsteriskWith(int w);
306};
307
308void wxPrintfConvSpec::Init()
309{
310 min_width = 0;
311 max_width = 0xFFFF;
312 pos = 0;
313 adj_left = false;
314 argpos = argend = NULL;
315 type = wxPAT_INVALID;
7d70c309
WS
316
317 // this character will never be removed from szFlags array and
318 // is important when calling sprintf() in wxPrintfConvSpec::Process() !
319 szFlags[0] = '%';
7a828c7f
VZ
320}
321
322bool wxPrintfConvSpec::Parse(const wxChar *format)
323{
324 bool done = false;
325
326 // temporary parse data
327 size_t flagofs = 1;
328 bool in_prec, prec_dot;
329 int ilen = 0;
330
331 adj_left = in_prec = prec_dot = false;
332 argpos = argend = format;
333 do
f6f5941b 334 {
7a828c7f
VZ
335#define CHECK_PREC \
336 if (in_prec && !prec_dot) \
337 { \
7d70c309 338 szFlags[flagofs++] = (char)'.'; \
7a828c7f
VZ
339 prec_dot = true; \
340 }
df17b887 341
7a828c7f
VZ
342 // what follows '%'?
343 const wxChar ch = *(++argend);
344 switch ( ch )
df17b887 345 {
7a828c7f
VZ
346 case wxT('\0'):
347 return false; // not really an argument
348
349 case wxT('%'):
350 return false; // not really an argument
351
352 case wxT('#'):
353 case wxT('0'):
354 case wxT(' '):
355 case wxT('+'):
356 case wxT('\''):
357 CHECK_PREC
7d70c309 358 szFlags[flagofs++] = (char)ch;
7a828c7f
VZ
359 break;
360
361 case wxT('-'):
362 CHECK_PREC
363 adj_left = true;
7d70c309 364 szFlags[flagofs++] = (char)ch;
7a828c7f
VZ
365 break;
366
367 case wxT('.'):
368 CHECK_PREC
369 in_prec = true;
370 prec_dot = false;
371 max_width = 0;
372 // dot will be auto-added to szFlags if non-negative
373 // number follows
374 break;
375
376 case wxT('h'):
377 ilen = -1;
378 CHECK_PREC
7d70c309 379 szFlags[flagofs++] = (char)ch;
7a828c7f
VZ
380 break;
381
382 case wxT('l'):
383 ilen = 1;
384 CHECK_PREC
7d70c309 385 szFlags[flagofs++] = (char)ch;
7a828c7f
VZ
386 break;
387
388 case wxT('q'):
389 case wxT('L'):
390 ilen = 2;
391 CHECK_PREC
7d70c309 392 szFlags[flagofs++] = (char)ch;
7a828c7f
VZ
393 break;
394
395 case wxT('Z'):
396 ilen = 3;
397 CHECK_PREC
7d70c309 398 szFlags[flagofs++] = (char)ch;
7a828c7f
VZ
399 break;
400
401 case wxT('*'):
402 if (in_prec)
403 {
404 CHECK_PREC
f6f5941b 405
7a828c7f
VZ
406 // tell Process() to use the next argument
407 // in the stack as maxwidth...
408 max_width = -1;
409 }
410 else
411 {
412 // tell Process() to use the next argument
413 // in the stack as minwidth...
414 min_width = -1;
415 }
416
417 // save the * in our formatting buffer...
418 // will be replaced later by Process()
7d70c309 419 szFlags[flagofs++] = (char)ch;
7a828c7f
VZ
420 break;
421
422 case wxT('1'): case wxT('2'): case wxT('3'):
423 case wxT('4'): case wxT('5'): case wxT('6'):
424 case wxT('7'): case wxT('8'): case wxT('9'):
425 {
426 int len = 0;
427 CHECK_PREC
428 while ( (*argend >= wxT('0')) &&
429 (*argend <= wxT('9')) )
430 {
7d70c309 431 szFlags[flagofs++] = (char)(*argend);
7a828c7f
VZ
432 len = len*10 + (*argend - wxT('0'));
433 argend++;
434 }
435
436 if (in_prec)
437 max_width = len;
438 else
439 min_width = len;
440
441 argend--; // the main loop pre-increments n again
f6f5941b 442 }
7a828c7f
VZ
443 break;
444
445 case wxT('$'): // a positional parameter (e.g. %2$s) ?
446 {
447 if (min_width <= 0)
448 break; // ignore this formatting flag as no
449 // numbers are preceding it
450
451 // remove from szFlags all digits previously added
452 do {
453 flagofs--;
454 } while (szFlags[flagofs] >= '1' &&
455 szFlags[flagofs] <= '9');
456
457 // re-adjust the offset making it point to the
458 // next free char of szFlags
459 flagofs++;
460
461 pos = min_width;
462 min_width = 0;
463 }
464 break;
465
466 case wxT('d'):
467 case wxT('i'):
468 case wxT('o'):
469 case wxT('u'):
470 case wxT('x'):
471 case wxT('X'):
472 CHECK_PREC
7d70c309
WS
473 szFlags[flagofs++] = (char)ch;
474 szFlags[flagofs] = (char)'\0';
7a828c7f
VZ
475 if (ilen == 0)
476 type = wxPAT_INT;
477 else if (ilen == -1)
478 // NB: 'short int' value passed through '...'
479 // is promoted to 'int', so we have to get
480 // an int from stack even if we need a short
481 type = wxPAT_INT;
482 else if (ilen == 1)
483 type = wxPAT_LONGINT;
484 else if (ilen == 2)
485#if SIZEOF_LONG_LONG
486 type = wxPAT_LONGLONGINT;
487#else // !long long
488 type = wxPAT_LONGINT;
489#endif // long long/!long long
490 else if (ilen == 3)
491 type = wxPAT_SIZET;
492 done = true;
493 break;
494
495 case wxT('e'):
496 case wxT('E'):
497 case wxT('f'):
498 case wxT('g'):
499 case wxT('G'):
500 CHECK_PREC
7d70c309
WS
501 szFlags[flagofs++] = (char)ch;
502 szFlags[flagofs] = (char)'\0';
7a828c7f
VZ
503 if (ilen == 2)
504 type = wxPAT_LONGDOUBLE;
505 else
506 type = wxPAT_DOUBLE;
507 done = true;
508 break;
509
510 case wxT('p'):
511 type = wxPAT_POINTER;
512 done = true;
513 break;
514
515 case wxT('c'):
516 if (ilen == -1)
517 {
518 // in Unicode mode %hc == ANSI character
519 // and in ANSI mode, %hc == %c == ANSI...
520 type = wxPAT_CHAR;
521 }
522 else if (ilen == 1)
523 {
524 // in ANSI mode %lc == Unicode character
525 // and in Unicode mode, %lc == %c == Unicode...
526 type = wxPAT_WCHAR;
527 }
528 else
529 {
530#if wxUSE_UNICODE
531 // in Unicode mode, %c == Unicode character
532 type = wxPAT_WCHAR;
533#else
534 // in ANSI mode, %c == ANSI character
535 type = wxPAT_CHAR;
536#endif
537 }
538 done = true;
539 break;
540
541 case wxT('s'):
542 if (ilen == -1)
543 {
544 // Unicode mode wx extension: we'll let %hs mean non-Unicode
545 // strings (when in ANSI mode, %s == %hs == ANSI string)
546 type = wxPAT_PCHAR;
547 }
548 else if (ilen == 1)
549 {
550 // in Unicode mode, %ls == %s == Unicode string
551 // in ANSI mode, %ls == Unicode string
552 type = wxPAT_PWCHAR;
553 }
554 else
555 {
556#if wxUSE_UNICODE
557 type = wxPAT_PWCHAR;
558#else
559 type = wxPAT_PCHAR;
560#endif
561 }
562 done = true;
563 break;
564
565 case wxT('n'):
566 if (ilen == 0)
567 type = wxPAT_NINT;
568 else if (ilen == -1)
569 type = wxPAT_NSHORTINT;
570 else if (ilen >= 1)
571 type = wxPAT_NLONGINT;
572 done = true;
573 break;
574
575 default:
576 // bad format, don't consider this an argument;
577 // leave it unchanged
578 return false;
579 }
580 }
581 while (!done);
582
583 return true; // parsing was successful
584}
585
586
587void wxPrintfConvSpec::ReplaceAsteriskWith(int w)
588{
589 char temp[wxMAX_SVNPRINTF_FLAGBUFFER_LEN];
590
591 // find the first * in our flag buffer
592 char *pwidth = strchr(szFlags, '*');
593 wxASSERT(pwidth);
594
595 // save what follows the * (the +1 is to skip it!)
596 strcpy(temp, pwidth+1);
597 if (w < 0) {
598 pwidth[0] = '-';
599 pwidth++;
600 }
601
602 // replace * with the actual integer given as width
603 int offset = ::sprintf(pwidth,"%d",abs(w));
604
605 // restore after the expanded * what was following it
606 strcpy(pwidth+offset, temp);
607}
608
609bool wxPrintfConvSpec::LoadArg(wxPrintfArg *p, va_list &argptr)
610{
611 // did the '*' width/precision specifier was used ?
612 if (max_width == -1)
613 {
614 // take the maxwidth specifier from the stack
615 max_width = va_arg(argptr, int);
616 if (max_width < 0)
617 max_width = 0;
618 else
619 ReplaceAsteriskWith(max_width);
620 }
621
622 if (min_width == -1)
623 {
624 // take the minwidth specifier from the stack
625 min_width = va_arg(argptr, int);
626
627 ReplaceAsteriskWith(min_width);
628 if (min_width < 0)
629 {
630 adj_left = !adj_left;
631 min_width = -min_width;
632 }
633 }
634
635 switch (type) {
636 case wxPAT_INT:
637 p->pad_int = va_arg(argptr, int);
638 break;
639 case wxPAT_LONGINT:
640 p->pad_longint = va_arg(argptr, long int);
641 break;
642#if SIZEOF_LONG_LONG
643 case wxPAT_LONGLONGINT:
644 p->pad_longlongint = va_arg(argptr, long long int);
645 break;
646#endif
647 case wxPAT_SIZET:
648 p->pad_sizet = va_arg(argptr, size_t);
649 break;
650 case wxPAT_DOUBLE:
651 p->pad_double = va_arg(argptr, double);
652 break;
653 case wxPAT_LONGDOUBLE:
654 p->pad_longdouble = va_arg(argptr, long double);
655 break;
656 case wxPAT_POINTER:
657 p->pad_pointer = va_arg(argptr, void *);
658 break;
659
660 case wxPAT_CHAR:
7d70c309 661 p->pad_char = (char)va_arg(argptr, int); // char is promoted to int when passed through '...'
7a828c7f
VZ
662 break;
663 case wxPAT_WCHAR:
7d70c309 664 p->pad_wchar = (wchar_t)va_arg(argptr, int); // char is promoted to int when passed through '...'
7a828c7f
VZ
665 break;
666
667 case wxPAT_PCHAR:
668 p->pad_pchar = va_arg(argptr, char *);
669 break;
670 case wxPAT_PWCHAR:
671 p->pad_pwchar = va_arg(argptr, wchar_t *);
672 break;
673
674 case wxPAT_NINT:
675 p->pad_nint = va_arg(argptr, int *);
676 break;
677 case wxPAT_NSHORTINT:
678 p->pad_nshortint = va_arg(argptr, short int *);
679 break;
680 case wxPAT_NLONGINT:
681 p->pad_nlongint = va_arg(argptr, long int *);
682 break;
683
684 case wxPAT_INVALID:
685 default:
686 return false;
687 }
688
689 return true; // loading was successful
690}
691
692int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p)
693{
694 // buffer to avoid dynamic memory allocation each time for small strings
695 static char szScratch[1024];
696 size_t lenCur = 0;
f6f5941b
VZ
697
698#define APPEND_CH(ch) \
210f4bcd
VS
699 { \
700 if ( lenCur == lenMax ) \
701 return -1; \
702 \
703 buf[lenCur++] = ch; \
704 }
f6f5941b
VZ
705
706#define APPEND_STR(s) \
f6f5941b 707 { \
1af48460
VZ
708 for ( const wxChar *p = s; *p; p++ ) \
709 { \
710 APPEND_CH(*p); \
711 } \
f6f5941b
VZ
712 }
713
7a828c7f
VZ
714 switch ( type )
715 {
716 case wxPAT_INT:
717 ::sprintf(szScratch, szFlags, p->pad_int);
718 break;
719
720 case wxPAT_LONGINT:
721 ::sprintf(szScratch, szFlags, p->pad_longint);
722 break;
723
f6f5941b 724#if SIZEOF_LONG_LONG
7a828c7f
VZ
725 case wxPAT_LONGLONGINT:
726 ::sprintf(szScratch, szFlags, p->pad_longlongint);
727 break;
728#endif // SIZEOF_LONG_LONG
729
730 case wxPAT_SIZET:
731 ::sprintf(szScratch, szFlags, p->pad_sizet);
732 break;
733
734 case wxPAT_LONGDOUBLE:
735 ::sprintf(szScratch, szFlags, p->pad_longdouble);
736 break;
737
738 case wxPAT_DOUBLE:
739 ::sprintf(szScratch, szFlags, p->pad_double);
740 break;
741
742 case wxPAT_POINTER:
743 ::sprintf(szScratch, szFlags, p->pad_pointer);
744 break;
745
746 case wxPAT_CHAR:
747 case wxPAT_WCHAR:
748 {
749 wxChar val =
210f4bcd 750#if wxUSE_UNICODE
7a828c7f
VZ
751 p->pad_wchar;
752
753 if (type == wxPAT_CHAR) {
754 // user passed a character explicitely indicated as ANSI...
755 const char buf[2] = { p->pad_char, 0 };
756 val = wxString(buf, wxConvLibc)[0u];
757 }
758#else
759 p->pad_char;
760
34deaa93 761#if wxUSE_WCHAR_T
7a828c7f
VZ
762 if (type == wxPAT_WCHAR) {
763 // user passed a character explicitely indicated as Unicode...
764 const wchar_t buf[2] = { p->pad_wchar, 0 };
765 val = wxString(buf, wxConvLibc)[0u];
766 }
34deaa93 767#endif
210f4bcd 768#endif
210f4bcd 769
7a828c7f 770 size_t i;
210f4bcd 771
7a828c7f
VZ
772 if (!adj_left)
773 for (i = 1; i < (size_t)min_width; i++)
774 APPEND_CH(_T(' '));
f6f5941b 775
7a828c7f 776 APPEND_CH(val);
210f4bcd 777
7a828c7f
VZ
778 if (adj_left)
779 for (i = 1; i < (size_t)min_width; i++)
780 APPEND_CH(_T(' '));
781 }
782 break;
f6f5941b 783
7a828c7f
VZ
784 case wxPAT_PCHAR:
785 case wxPAT_PWCHAR:
786 {
787 wxString s;
788 const wxChar *val =
f6f5941b 789#if wxUSE_UNICODE
7a828c7f
VZ
790 p->pad_pwchar;
791
792 if (type == wxPAT_PCHAR) {
793 // user passed a string explicitely indicated as ANSI...
a31746c7 794 val = s = wxString(p->pad_pchar, wxConvLibc);
7a828c7f
VZ
795 }
796#else
797 p->pad_pchar;
798
34deaa93 799#if wxUSE_WCHAR_T
7a828c7f
VZ
800 if (type == wxPAT_PWCHAR) {
801 // user passed a string explicitely indicated as Unicode...
a31746c7 802 val = s = wxString(p->pad_pwchar, wxConvLibc);
7a828c7f 803 }
34deaa93 804#endif
7a828c7f
VZ
805#endif
806 int len;
807
808 if (val)
809 {
810#if wxUSE_STRUTILS
a31746c7
VZ
811 // at this point we are sure that max_width is positive or null
812 // (see top of wxPrintfConvSpec::LoadArg)
813 len = wxMin((unsigned int)max_width, wxStrlen(val));
7a828c7f
VZ
814#else
815 for ( len = 0; val[len] && (len < max_width); len++ )
816 ;
f6f5941b 817#endif
7a828c7f
VZ
818 }
819 else if (max_width >= 6)
820 {
821 val = wxT("(null)");
822 len = 6;
823 }
824 else
825 {
826 val = wxEmptyString;
827 len = 0;
828 }
829
830 int i;
831
832 if (!adj_left)
833 {
834 for (i = len; i < min_width; i++)
835 APPEND_CH(_T(' '));
836 }
837
838#if wxUSE_STRUTILS
a31746c7
VZ
839 // at this point we are sure that max_width is positive or null
840 // (see top of wxPrintfConvSpec::LoadArg)
841 len = wxMin((unsigned int)len, lenMax-lenCur);
7a828c7f
VZ
842 wxStrncpy(buf+lenCur, val, len);
843 lenCur += len;
844#else
845 for (i = 0; i < len; i++)
846 APPEND_CH(val[i]);
847#endif
848
849 if (adj_left)
850 {
851 for (i = len; i < min_width; i++)
852 APPEND_CH(_T(' '));
f6f5941b 853 }
df17b887 854 }
7a828c7f
VZ
855 break;
856
857 case wxPAT_NINT:
858 *p->pad_nint = lenCur;
859 break;
860
861 case wxPAT_NSHORTINT:
7d70c309 862 *p->pad_nshortint = (short int)lenCur;
7a828c7f
VZ
863 break;
864
865 case wxPAT_NLONGINT:
866 *p->pad_nlongint = lenCur;
867 break;
868
869 case wxPAT_INVALID:
870 default:
871 return -1;
872 }
873
874 // if we used system's sprintf() then we now need to append the s_szScratch
875 // buffer to the given one...
876 switch (type)
877 {
878 case wxPAT_INT:
879 case wxPAT_LONGINT:
880#if SIZEOF_LONG_LONG
881 case wxPAT_LONGLONGINT:
882#endif
883 case wxPAT_SIZET:
884 case wxPAT_LONGDOUBLE:
885 case wxPAT_DOUBLE:
886 case wxPAT_POINTER:
887#if wxUSE_STRUTILS
888 {
889 const wxMB2WXbuf tmp = wxConvLibc.cMB2WX(szScratch);
890 size_t len = wxMin(lenMax, wxStrlen(tmp));
891 wxStrncpy(buf, tmp, len);
892 lenCur += len;
893 }
894#else
895 {
896 const wxMB2WXbuf tmp =
897 wxConvLibc.cMB2WX(szScratch);
898 APPEND_STR(tmp);
899 }
900#endif
901 break;
902
903 default:
904 break; // all other cases were completed previously
905 }
906
907 return lenCur;
908}
909
247c23b4
VZ
910// differences from standard strncpy:
911// 1) copies everything from 'source' except for '%%' sequence which is copied as '%'
912// 2) returns the number of written characters in 'dest' as it could differ from given 'n'
913// 3) much less optimized, unfortunately...
914static int wxCopyStrWithPercents(wxChar *dest, const wxChar *source, size_t n)
915{
916 size_t written = 0;
917
918 if (n == 0)
919 return 0;
920
921 size_t i;
922 for ( i = 0; i < n-1; source++, i++)
923 {
924 dest[written++] = *source;
925 if (*(source+1) == wxT('%'))
926 {
927 // skip this additional '%' character
928 source++;
929 i++;
930 }
931 }
932
933 if (i < n)
934 // copy last character inconditionally
935 dest[written++] = *source;
936
937 return written;
938}
939
7a828c7f
VZ
940int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax,
941 const wxChar *format, va_list argptr)
942{
943 // cached data
944 static wxPrintfConvSpec arg[wxMAX_SVNPRINTF_ARGUMENTS];
945 static wxPrintfArg argdata[wxMAX_SVNPRINTF_ARGUMENTS];
946 static wxPrintfConvSpec *pspec[wxMAX_SVNPRINTF_ARGUMENTS] = { NULL };
947
948 size_t i;
949
950 // number of characters in the buffer so far, must be less than lenMax
951 size_t lenCur = 0;
952
953 size_t nargs = 0;
954 const wxChar *toparse = format;
955
956 // parse the format string
957 bool posarg_present = false, nonposarg_present = false;
958 for (; *toparse != wxT('\0'); toparse++)
959 {
960 if (*toparse == wxT('%') )
f6f5941b 961 {
7a828c7f
VZ
962 arg[nargs].Init();
963
964 // let's see if this is a (valid) conversion specifier...
965 if (arg[nargs].Parse(toparse))
966 {
967 // ...yes it is
968 wxPrintfConvSpec *current = &arg[nargs];
969
970 // make toparse point to the end of this specifier
971 toparse = current->argend;
972
973 if (current->pos > 0) {
974 // the positionals start from number 1... adjust the index
975 current->pos--;
976 posarg_present = true;
977 } else {
978 // not a positional argument...
979 current->pos = nargs;
980 nonposarg_present = true;
981 }
982
983 // this conversion specifier is tied to the pos-th argument...
984 pspec[current->pos] = current;
985 nargs++;
986
987 if (nargs == wxMAX_SVNPRINTF_ARGUMENTS)
988 break; // cannot handle any additional conv spec
989 }
f6f5941b 990 }
7a828c7f 991 }
df17b887 992
7a828c7f
VZ
993 if (posarg_present && nonposarg_present)
994 return -1; // format strings with both positional and
995 // non-positional conversion specifier are unsupported !!
996
3aa077ce
MW
997 // on platforms where va_list is an array type, it is necessary to make a
998 // copy to be able to pass it to LoadArg as a reference.
999 bool ok = true;
1000 va_list ap;
1001 wxVaCopy(ap, argptr);
1002
7a828c7f 1003 // now load arguments from stack
3aa077ce
MW
1004 for (i=0; i < nargs && ok; i++) {
1005 // !pspec[i] if user forgot a positional parameter (e.g. %$1s %$3s) ?
1006 // or LoadArg false if wxPrintfConvSpec::Parse failed to set its 'type'
1007 // to a valid value...
1008 ok = pspec[i] && pspec[i]->LoadArg(&argdata[i], ap);
7a828c7f
VZ
1009 }
1010
3aa077ce
MW
1011 va_end(ap);
1012
247c23b4 1013 // something failed while loading arguments from the variable list...
3aa077ce
MW
1014 if (!ok)
1015 return -1;
1016
7a828c7f
VZ
1017 // finally, process each conversion specifier with its own argument
1018 toparse = format;
1019 for (i=0; i < nargs; i++)
1020 {
1021 // copy in the output buffer the portion of the format string between
1022 // last specifier and the current one
1023 size_t tocopy = ( arg[i].argpos - toparse );
1024 if (lenCur+tocopy >= lenMax)
1025 return -1; // not enough space in the output buffer !
1026
247c23b4 1027 lenCur += wxCopyStrWithPercents(buf+lenCur, toparse, tocopy);
7a828c7f
VZ
1028
1029 // process this specifier directly in the output buffer
1030 int n = arg[i].Process(buf+lenCur, lenMax - lenCur, &argdata[arg[i].pos]);
1031 if (n == -1)
1032 return -1; // not enough space in the output buffer !
1033 lenCur += n;
1034
1035 // the +1 is because wxPrintfConvSpec::argend points to the last character
1036 // of the format specifier, but we are not interested to it...
1037 toparse = arg[i].argend + 1;
5f1d3069
RR
1038 }
1039
7a828c7f
VZ
1040 // copy portion of the format string after last specifier
1041 // NOTE: toparse is pointing to the character just after the last processed
1042 // conversion specifier
1043 // NOTE2: the +1 is because we want to copy also the '\0'
1044 size_t tocopy = wxStrlen(format) + 1 - ( toparse - format ) ;
1045 if (lenCur+tocopy >= lenMax)
1046 return -1; // not enough space in the output buffer !
247c23b4
VZ
1047
1048 // the -1 is because of the '\0'
1049 lenCur += wxCopyStrWithPercents(buf+lenCur, toparse, tocopy) - 1;
7a828c7f
VZ
1050
1051 // clean the static array portion used...
1052 // NOTE: other arrays do not need cleanup!
1053 memset(pspec, 0, sizeof(wxPrintfConvSpec*)*nargs);
1054
1055 wxASSERT(lenCur == wxStrlen(buf));
f6f5941b
VZ
1056 return lenCur;
1057}
5f1d3069 1058
f6f5941b
VZ
1059#undef APPEND_CH
1060#undef APPEND_STR
1061#undef CHECK_PREC
5f1d3069 1062
f6f5941b
VZ
1063#endif // !wxVsnprintfA
1064
1065#if !defined(wxSnprintf_)
1066int WXDLLEXPORT wxSnprintf_(wxChar *buf, size_t len, const wxChar *format, ...)
1067{
5f1d3069
RR
1068 va_list argptr;
1069 va_start(argptr, format);
1070
f6f5941b 1071 int iLen = wxVsnprintf_(buf, len, format, argptr);
5f1d3069
RR
1072
1073 va_end(argptr);
f6f5941b
VZ
1074
1075 return iLen;
5f1d3069 1076}
f6f5941b 1077#endif // wxSnprintf_
5f1d3069 1078
8dfb846e
CE
1079#if defined(__DMC__)
1080 /* Digital Mars adds count to _stprintf (C99) so convert */
1081 #if wxUSE_UNICODE
1082 int wxSprintf (wchar_t * __RESTRICT s, const wchar_t * __RESTRICT format, ... )
1083 {
1084 va_list arglist;
1085
1086 va_start( arglist, format );
1087 int iLen = swprintf ( s, -1, format, arglist );
1088 va_end( arglist );
1089 return iLen ;
1090 }
1091
1092 #endif // wxUSE_UNICODE
1093
1094#endif //__DMC__
1095
f6f5941b
VZ
1096// ----------------------------------------------------------------------------
1097// implement the standard IO functions for wide char if libc doesn't have them
1098// ----------------------------------------------------------------------------
5f1d3069 1099
fbe47c7b 1100#ifdef wxNEED_FPUTS
f6f5941b
VZ
1101int wxFputs(const wchar_t *ws, FILE *stream)
1102{
1103 // counting the number of wide characters written isn't worth the trouble,
1104 // simply distinguish between ok and error
1105 return fputs(wxConvLibc.cWC2MB(ws), stream) == -1 ? -1 : 0;
1106}
fbe47c7b 1107#endif // wxNEED_FPUTS
5f1d3069 1108
19b65a30
VZ
1109#ifdef wxNEED_PUTS
1110int wxPuts(const wxChar *ws)
1111{
1112 int rc = wxFputs(ws, stdout);
1113 if ( rc != -1 )
1114 {
1115 if ( wxFputs(L"\n", stdout) == -1 )
1116 return -1;
1117
1118 rc++;
1119 }
1120
1121 return rc;
1122}
1123#endif // wxNEED_PUTS
1124
fbe47c7b 1125#ifdef wxNEED_PUTC
f6f5941b
VZ
1126int /* not wint_t */ wxPutc(wchar_t wc, FILE *stream)
1127{
1128 wchar_t ws[2] = { wc, L'\0' };
5f1d3069 1129
f6f5941b 1130 return wxFputs(ws, stream);
5f1d3069 1131}
fbe47c7b 1132#endif // wxNEED_PUTC
f6f5941b
VZ
1133
1134// NB: we only implement va_list functions here, the ones taking ... are
1135// defined below for wxNEED_PRINTF_CONVERSION case anyhow and we reuse
1136// the definitions there to avoid duplicating them here
1137#ifdef wxNEED_WPRINTF
1138
1139// TODO: implement the scanf() functions
df17b887 1140int vwscanf(const wxChar *format, va_list argptr)
5f1d3069 1141{
f6f5941b 1142 wxFAIL_MSG( _T("TODO") );
5f1d3069 1143
f6f5941b
VZ
1144 return -1;
1145}
1146
df17b887 1147int vswscanf(const wxChar *ws, const wxChar *format, va_list argptr)
f6f5941b 1148{
63de666d
VS
1149 // The best we can do without proper Unicode support in glibc is to
1150 // convert the strings into MB representation and run ANSI version
1151 // of the function. This doesn't work with %c and %s because of difference
1152 // in size of char and wchar_t, though.
525d8583 1153
63de666d
VS
1154 wxCHECK_MSG( wxStrstr(format, _T("%s")) == NULL, -1,
1155 _T("incomplete vswscanf implementation doesn't allow %s") );
1156 wxCHECK_MSG( wxStrstr(format, _T("%c")) == NULL, -1,
1157 _T("incomplete vswscanf implementation doesn't allow %c") );
525d8583 1158
63de666d
VS
1159 va_list argcopy;
1160 wxVaCopy(argcopy, argptr);
1161 return vsscanf(wxConvLibc.cWX2MB(ws), wxConvLibc.cWX2MB(format), argcopy);
f6f5941b 1162}
5f1d3069 1163
df17b887 1164int vfwscanf(FILE *stream, const wxChar *format, va_list argptr)
f6f5941b
VZ
1165{
1166 wxFAIL_MSG( _T("TODO") );
5f1d3069 1167
f6f5941b 1168 return -1;
5f1d3069
RR
1169}
1170
f6f5941b
VZ
1171#define vswprintf wxVsnprintf_
1172
df17b887 1173int vfwprintf(FILE *stream, const wxChar *format, va_list argptr)
5f1d3069 1174{
f6f5941b
VZ
1175 wxString s;
1176 int rc = s.PrintfV(format, argptr);
5f1d3069 1177
f6f5941b
VZ
1178 if ( rc != -1 )
1179 {
1180 // we can't do much better without Unicode support in libc...
50b079e5 1181 if ( fprintf(stream, "%s", (const char*)s.mb_str() ) == -1 )
f6f5941b
VZ
1182 return -1;
1183 }
5f1d3069 1184
f6f5941b 1185 return rc;
5f1d3069
RR
1186}
1187
df17b887 1188int vwprintf(const wxChar *format, va_list argptr)
5f1d3069 1189{
f6f5941b
VZ
1190 return wxVfprintf(stdout, format, argptr);
1191}
5f1d3069 1192
f6f5941b 1193#endif // wxNEED_WPRINTF
5f1d3069 1194
f6f5941b 1195#ifdef wxNEED_PRINTF_CONVERSION
5f1d3069 1196
f6f5941b
VZ
1197// ----------------------------------------------------------------------------
1198// wxFormatConverter: class doing the "%s" -> "%ls" conversion
1199// ----------------------------------------------------------------------------
5f1d3069 1200
f6f5941b
VZ
1201/*
1202 Here are the gory details. We want to follow the Windows/MS conventions,
1203 that is to have
1204
1205 In ANSI mode:
1206
1207 format specifier results in
1208 -----------------------------------
1209 %c, %hc, %hC char
1210 %lc, %C, %lC wchar_t
1211
1212 In Unicode mode:
1213
1214 format specifier results in
1215 -----------------------------------
1216 %hc, %C, %hC char
1217 %c, %lc, %lC wchar_t
1218
1219
1220 while on POSIX systems we have %C identical to %lc and %c always means char
1221 (in any mode) while %lc always means wchar_t,
1222
1223 So to use native functions in order to get our semantics we must do the
1224 following translations in Unicode mode (nothing to do in ANSI mode):
1225
77ffb593 1226 wxWidgets specifier POSIX specifier
f6f5941b
VZ
1227 ----------------------------------------
1228
1229 %hc, %C, %hC %c
1230 %c %lc
1231
1232
1233 And, of course, the same should be done for %s as well.
1234*/
1235
1236class wxFormatConverter
5f1d3069 1237{
f6f5941b
VZ
1238public:
1239 wxFormatConverter(const wxChar *format);
1240
c03d0035
VZ
1241 // notice that we only translated the string if m_fmtOrig == NULL (as set
1242 // by CopyAllBefore()), otherwise we should simply use the original format
1243 operator const wxChar *() const
1244 { return m_fmtOrig ? m_fmtOrig : m_fmt.c_str(); }
f6f5941b
VZ
1245
1246private:
1247 // copy another character to the translated format: this function does the
1248 // copy if we are translating but doesn't do anything at all if we don't,
1249 // so we don't create the translated format string at all unless we really
1250 // need to (i.e. InsertFmtChar() is called)
1251 wxChar CopyFmtChar(wxChar ch)
1252 {
1253 if ( !m_fmtOrig )
1254 {
c03d0035 1255 // we're translating, do copy
f6f5941b
VZ
1256 m_fmt += ch;
1257 }
1258 else
1259 {
1260 // simply increase the count which should be copied by
1261 // CopyAllBefore() later if needed
1262 m_nCopied++;
1263 }
1264
1265 return ch;
1266 }
1267
1268 // insert an extra character
1269 void InsertFmtChar(wxChar ch)
1270 {
1271 if ( m_fmtOrig )
1272 {
1273 // so far we haven't translated anything yet
1274 CopyAllBefore();
1275 }
1276
1277 m_fmt += ch;
1278 }
1279
1280 void CopyAllBefore()
1281 {
1282 wxASSERT_MSG( m_fmtOrig && m_fmt.empty(), _T("logic error") );
1283
1284 m_fmt = wxString(m_fmtOrig, m_nCopied);
1285
1286 // we won't need it any longer
1287 m_fmtOrig = NULL;
1288 }
5f1d3069 1289
f6f5941b
VZ
1290 static bool IsFlagChar(wxChar ch)
1291 {
1292 return ch == _T('-') || ch == _T('+') ||
1293 ch == _T('0') || ch == _T(' ') || ch == _T('#');
1294 }
1295
41d9940d 1296 void SkipDigits(const wxChar **ptpc)
f6f5941b 1297 {
41d9940d
SC
1298 while ( **ptpc >= _T('0') && **ptpc <= _T('9') )
1299 CopyFmtChar(*(*ptpc)++);
f6f5941b
VZ
1300 }
1301
1302 // the translated format
1303 wxString m_fmt;
1304
1305 // the original format
1306 const wxChar *m_fmtOrig;
1307
1308 // the number of characters already copied
1309 size_t m_nCopied;
1310};
1311
1312wxFormatConverter::wxFormatConverter(const wxChar *format)
1313{
1314 m_fmtOrig = format;
1315 m_nCopied = 0;
1316
1317 while ( *format )
1318 {
1319 if ( CopyFmtChar(*format++) == _T('%') )
1320 {
1321 // skip any flags
1322 while ( IsFlagChar(*format) )
1323 CopyFmtChar(*format++);
1324
1325 // and possible width
1326 if ( *format == _T('*') )
1327 CopyFmtChar(*format++);
1328 else
1329 SkipDigits(&format);
1330
1331 // precision?
1332 if ( *format == _T('.') )
1333 {
cfee166d
JS
1334 CopyFmtChar(*format++);
1335 if ( *format == _T('*') )
1336 CopyFmtChar(*format++);
1337 else
1338 SkipDigits(&format);
f6f5941b
VZ
1339 }
1340
1341 // next we can have a size modifier
1342 enum
1343 {
1344 Default,
1345 Short,
1346 Long
1347 } size;
1348
1349 switch ( *format )
1350 {
1351 case _T('h'):
1352 size = Short;
1353 format++;
1354 break;
1355
1356 case _T('l'):
1357 // "ll" has a different meaning!
1358 if ( format[1] != _T('l') )
1359 {
1360 size = Long;
1361 format++;
1362 break;
1363 }
1364 //else: fall through
1365
1366 default:
1367 size = Default;
1368 }
1369
1370 // and finally we should have the type
1371 switch ( *format )
1372 {
1373 case _T('C'):
1374 case _T('S'):
1375 // %C and %hC -> %c and %lC -> %lc
1376 if ( size == Long )
1377 CopyFmtChar(_T('l'));
1378
1379 InsertFmtChar(*format++ == _T('C') ? _T('c') : _T('s'));
1380 break;
1381
1382 case _T('c'):
1383 case _T('s'):
1384 // %c -> %lc but %hc stays %hc and %lc is still %lc
cfee166d
JS
1385 if ( size == Default)
1386 InsertFmtChar(_T('l'));
f6f5941b
VZ
1387 // fall through
1388
1389 default:
1390 // nothing special to do
cfee166d
JS
1391 if ( size != Default )
1392 CopyFmtChar(*(format - 1));
f6f5941b
VZ
1393 CopyFmtChar(*format++);
1394 }
1395 }
1396 }
1397}
1398
1399#else // !wxNEED_PRINTF_CONVERSION
1400 // no conversion necessary
1401 #define wxFormatConverter(x) (x)
1402#endif // wxNEED_PRINTF_CONVERSION/!wxNEED_PRINTF_CONVERSION
1403
cfee166d
JS
1404#ifdef __WXDEBUG__
1405// For testing the format converter
1406wxString wxConvertFormat(const wxChar *format)
1407{
1408 return wxString(wxFormatConverter(format));
1409}
1410#endif
1411
f6f5941b
VZ
1412// ----------------------------------------------------------------------------
1413// wxPrintf(), wxScanf() and relatives
1414// ----------------------------------------------------------------------------
1415
1416#if defined(wxNEED_PRINTF_CONVERSION) || defined(wxNEED_WPRINTF)
1417
df17b887 1418int wxScanf( const wxChar *format, ... )
f6f5941b 1419{
5f1d3069
RR
1420 va_list argptr;
1421 va_start(argptr, format);
1422
f6f5941b 1423 int ret = vwscanf(wxFormatConverter(format), argptr );
5f1d3069
RR
1424
1425 va_end(argptr);
1426
1427 return ret;
1428}
1429
df17b887 1430int wxSscanf( const wxChar *str, const wxChar *format, ... )
5f1d3069 1431{
5f1d3069
RR
1432 va_list argptr;
1433 va_start(argptr, format);
1434
f6f5941b 1435 int ret = vswscanf( str, wxFormatConverter(format), argptr );
5f1d3069
RR
1436
1437 va_end(argptr);
1438
1439 return ret;
1440}
1441
df17b887 1442int wxFscanf( FILE *stream, const wxChar *format, ... )
5f1d3069 1443{
5f1d3069 1444 va_list argptr;
f6f5941b 1445 va_start(argptr, format);
f6f5941b 1446 int ret = vfwscanf(stream, wxFormatConverter(format), argptr);
5f1d3069
RR
1447
1448 va_end(argptr);
1449
1450 return ret;
1451}
1452
df17b887 1453int wxPrintf( const wxChar *format, ... )
5f1d3069 1454{
f6f5941b
VZ
1455 va_list argptr;
1456 va_start(argptr, format);
df17b887 1457
f6f5941b 1458 int ret = vwprintf( wxFormatConverter(format), argptr );
5f1d3069 1459
f6f5941b 1460 va_end(argptr);
5f1d3069
RR
1461
1462 return ret;
1463}
1464
f6f5941b 1465#ifndef wxSnprintf
df17b887 1466int wxSnprintf( wxChar *str, size_t size, const wxChar *format, ... )
5f1d3069 1467{
f6f5941b
VZ
1468 va_list argptr;
1469 va_start(argptr, format);
5f1d3069 1470
f6f5941b 1471 int ret = vswprintf( str, size, wxFormatConverter(format), argptr );
5f1d3069 1472
f6f5941b 1473 va_end(argptr);
5f1d3069
RR
1474
1475 return ret;
1476}
f6f5941b 1477#endif // wxSnprintf
5f1d3069 1478
df17b887 1479int wxSprintf( wxChar *str, const wxChar *format, ... )
5f1d3069 1480{
f6f5941b
VZ
1481 va_list argptr;
1482 va_start(argptr, format);
5f1d3069 1483
56413ebf 1484 // note that wxString::FormatV() uses wxVsnprintf(), not wxSprintf(), so
f8991003 1485 // it's safe to implement this one in terms of it
56413ebf 1486 wxString s(wxString::FormatV(format, argptr));
a4e0917b 1487 wxStrcpy(str, s);
5f1d3069 1488
f6f5941b 1489 va_end(argptr);
5f1d3069 1490
a4e0917b 1491 return s.length();
5f1d3069
RR
1492}
1493
df17b887 1494int wxFprintf( FILE *stream, const wxChar *format, ... )
5f1d3069 1495{
f6f5941b
VZ
1496 va_list argptr;
1497 va_start( argptr, format );
5f1d3069 1498
f6f5941b 1499 int ret = vfwprintf( stream, wxFormatConverter(format), argptr );
5f1d3069 1500
f6f5941b 1501 va_end(argptr);
5f1d3069
RR
1502
1503 return ret;
1504}
f06e3075 1505
f6f5941b 1506int wxVsscanf( const wxChar *str, const wxChar *format, va_list argptr )
5f1d3069 1507{
f6f5941b
VZ
1508 return vswscanf( str, wxFormatConverter(format), argptr );
1509}
5f1d3069 1510
f6f5941b
VZ
1511int wxVfprintf( FILE *stream, const wxChar *format, va_list argptr )
1512{
1513 return vfwprintf( stream, wxFormatConverter(format), argptr );
1514}
5f1d3069 1515
f6f5941b
VZ
1516int wxVprintf( const wxChar *format, va_list argptr )
1517{
1518 return vwprintf( wxFormatConverter(format), argptr );
5f1d3069 1519}
5f1d3069 1520
f6f5941b
VZ
1521#ifndef wxVsnprintf
1522int wxVsnprintf( wxChar *str, size_t size, const wxChar *format, va_list argptr )
5f1d3069 1523{
f6f5941b
VZ
1524 return vswprintf( str, size, wxFormatConverter(format), argptr );
1525}
1526#endif // wxVsnprintf
5f1d3069 1527
f6f5941b
VZ
1528int wxVsprintf( wxChar *str, const wxChar *format, va_list argptr )
1529{
1530 // same as for wxSprintf()
b63b07a8 1531 return vswprintf(str, INT_MAX / 4, wxFormatConverter(format), argptr);
f6f5941b 1532}
5f1d3069 1533
f6f5941b 1534#endif // wxNEED_PRINTF_CONVERSION
5f1d3069 1535
33a7c3dd
VZ
1536#if wxUSE_WCHAR_T
1537
f6f5941b
VZ
1538// ----------------------------------------------------------------------------
1539// ctype.h stuff (currently unused)
1540// ----------------------------------------------------------------------------
5f1d3069 1541
57f6da0d
OK
1542#if defined(__WIN32__) && defined(wxNEED_WX_CTYPE_H)
1543inline WORD wxMSW_ctype(wxChar ch)
1544{
1545 WORD ret;
1546 GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, &ch, 1, &ret);
1547 return ret;
1548}
1549
b0655a87
OK
1550WXDLLEXPORT int wxIsalnum(wxChar ch) { return IsCharAlphaNumeric(ch); }
1551WXDLLEXPORT int wxIsalpha(wxChar ch) { return IsCharAlpha(ch); }
4eb7c4b1 1552WXDLLEXPORT int wxIscntrl(wxChar ch) { return wxMSW_ctype(ch) & C1_CNTRL; }
b0655a87
OK
1553WXDLLEXPORT int wxIsdigit(wxChar ch) { return wxMSW_ctype(ch) & C1_DIGIT; }
1554WXDLLEXPORT int wxIsgraph(wxChar ch) { return wxMSW_ctype(ch) & (C1_DIGIT|C1_PUNCT|C1_ALPHA); }
1555WXDLLEXPORT int wxIslower(wxChar ch) { return IsCharLower(ch); }
1556WXDLLEXPORT int wxIsprint(wxChar ch) { return wxMSW_ctype(ch) & (C1_DIGIT|C1_SPACE|C1_PUNCT|C1_ALPHA); }
1557WXDLLEXPORT int wxIspunct(wxChar ch) { return wxMSW_ctype(ch) & C1_PUNCT; }
1558WXDLLEXPORT int wxIsspace(wxChar ch) { return wxMSW_ctype(ch) & C1_SPACE; }
1559WXDLLEXPORT int wxIsupper(wxChar ch) { return IsCharUpper(ch); }
1560WXDLLEXPORT int wxIsxdigit(wxChar ch) { return wxMSW_ctype(ch) & C1_XDIGIT; }
1561WXDLLEXPORT int wxTolower(wxChar ch) { return (wxChar)CharLower((LPTSTR)(ch)); }
1562WXDLLEXPORT int wxToupper(wxChar ch) { return (wxChar)CharUpper((LPTSTR)(ch)); }
57f6da0d
OK
1563#endif
1564
dbf9aa46 1565#ifdef wxNEED_WX_MBSTOWCS
dcb68102 1566
1e96e503 1567WXDLLEXPORT size_t wxMbstowcs (wchar_t * out, const char * in, size_t outlen)
dcb68102
RN
1568{
1569 if (!out)
1570 {
1571 size_t outsize = 0;
1572 while(*in++)
1573 outsize++;
1574 return outsize;
1575 }
525d8583 1576
dcb68102 1577 const char* origin = in;
525d8583 1578
dcb68102
RN
1579 while (outlen-- && *in)
1580 {
1581 *out++ = (wchar_t) *in++;
1582 }
525d8583 1583
dcb68102 1584 *out = '\0';
525d8583 1585
dcb68102
RN
1586 return in - origin;
1587}
1588
41e155b4 1589WXDLLEXPORT size_t wxWcstombs (char * out, const wchar_t * in, size_t outlen)
dcb68102
RN
1590{
1591 if (!out)
1592 {
1593 size_t outsize = 0;
1594 while(*in++)
1595 outsize++;
1596 return outsize;
1597 }
525d8583 1598
dcb68102 1599 const wchar_t* origin = in;
525d8583 1600
dcb68102
RN
1601 while (outlen-- && *in)
1602 {
1603 *out++ = (char) *in++;
1604 }
525d8583 1605
dcb68102 1606 *out = '\0';
525d8583 1607
dcb68102
RN
1608 return in - origin;
1609}
525d8583 1610
dbf9aa46
VZ
1611#endif // wxNEED_WX_MBSTOWCS
1612
dcb68102
RN
1613#if defined(wxNEED_WX_CTYPE_H)
1614
1615#include <CoreFoundation/CoreFoundation.h>
1616
eaceebf6
RN
1617#define cfalnumset CFCharacterSetGetPredefined(kCFCharacterSetAlphaNumeric)
1618#define cfalphaset CFCharacterSetGetPredefined(kCFCharacterSetLetter)
1619#define cfcntrlset CFCharacterSetGetPredefined(kCFCharacterSetControl)
1620#define cfdigitset CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit)
dcb68102 1621//CFCharacterSetRef cfgraphset = kCFCharacterSetControl && !' '
eaceebf6 1622#define cflowerset CFCharacterSetGetPredefined(kCFCharacterSetLowercaseLetter)
dcb68102 1623//CFCharacterSetRef cfprintset = !kCFCharacterSetControl
eaceebf6
RN
1624#define cfpunctset CFCharacterSetGetPredefined(kCFCharacterSetPunctuation)
1625#define cfspaceset CFCharacterSetGetPredefined(kCFCharacterSetWhitespaceAndNewline)
1626#define cfupperset CFCharacterSetGetPredefined(kCFCharacterSetUppercaseLetter)
dcb68102
RN
1627
1628WXDLLEXPORT int wxIsalnum(wxChar ch) { return CFCharacterSetIsCharacterMember(cfalnumset, ch); }
1629WXDLLEXPORT int wxIsalpha(wxChar ch) { return CFCharacterSetIsCharacterMember(cfalphaset, ch); }
1630WXDLLEXPORT int wxIscntrl(wxChar ch) { return CFCharacterSetIsCharacterMember(cfcntrlset, ch); }
1631WXDLLEXPORT int wxIsdigit(wxChar ch) { return CFCharacterSetIsCharacterMember(cfdigitset, ch); }
1632WXDLLEXPORT int wxIsgraph(wxChar ch) { return !CFCharacterSetIsCharacterMember(cfcntrlset, ch) && ch != ' '; }
1633WXDLLEXPORT int wxIslower(wxChar ch) { return CFCharacterSetIsCharacterMember(cflowerset, ch); }
1634WXDLLEXPORT int wxIsprint(wxChar ch) { return !CFCharacterSetIsCharacterMember(cfcntrlset, ch); }
1635WXDLLEXPORT int wxIspunct(wxChar ch) { return CFCharacterSetIsCharacterMember(cfpunctset, ch); }
1636WXDLLEXPORT int wxIsspace(wxChar ch) { return CFCharacterSetIsCharacterMember(cfspaceset, ch); }
1637WXDLLEXPORT int wxIsupper(wxChar ch) { return CFCharacterSetIsCharacterMember(cfupperset, ch); }
1638WXDLLEXPORT int wxIsxdigit(wxChar ch) { return wxIsdigit(ch) || (ch>='a' && ch<='f') || (ch>='A' && ch<='F'); }
1639WXDLLEXPORT int wxTolower(wxChar ch) { return (wxChar)tolower((char)(ch)); }
1640WXDLLEXPORT int wxToupper(wxChar ch) { return (wxChar)toupper((char)(ch)); }
dcb68102 1641
8a9c20b0
RN
1642#endif // wxNEED_WX_CTYPE_H
1643
07243717
VZ
1644#ifndef wxStrdupA
1645
1646WXDLLEXPORT char *wxStrdupA(const char *s)
1647{
1648 return strcpy((char *)malloc(strlen(s) + 1), s);
1649}
1650
1651#endif // wxStrdupA
1652
1653#ifndef wxStrdupW
1654
1655WXDLLEXPORT wchar_t * wxStrdupW(const wchar_t *pwz)
c9e089e9 1656{
07243717
VZ
1657 size_t size = (wxWcslen(pwz) + 1) * sizeof(wchar_t);
1658 wchar_t *ret = (wchar_t *) malloc(size);
1659 memcpy(ret, pwz, size);
c9e089e9
OK
1660 return ret;
1661}
07243717
VZ
1662
1663#endif // wxStrdupW
c9e089e9 1664
d0bdc3ca
OK
1665#ifndef wxStricmp
1666int WXDLLEXPORT wxStricmp(const wxChar *psz1, const wxChar *psz2)
1667{
1668 register wxChar c1, c2;
1669 do {
1670 c1 = wxTolower(*psz1++);
1671 c2 = wxTolower(*psz2++);
1672 } while ( c1 && (c1 == c2) );
1673 return c1 - c2;
1674}
1675#endif
1676
e766c8a9
SC
1677#ifndef wxStricmp
1678int WXDLLEXPORT wxStrnicmp(const wxChar *s1, const wxChar *s2, size_t n)
1679{
a400a823
VZ
1680 // initialize the variables just to suppress stupid gcc warning
1681 register wxChar c1 = 0, c2 = 0;
e766c8a9
SC
1682 while (n && ((c1 = wxTolower(*s1)) == (c2 = wxTolower(*s2)) ) && c1) n--, s1++, s2++;
1683 if (n) {
1684 if (c1 < c2) return -1;
1685 if (c1 > c2) return 1;
1686 }
1687 return 0;
1688}
1689#endif
1690
c9e089e9 1691#ifndef wxSetlocale
191ab39a 1692WXDLLEXPORT wxWCharBuffer wxSetlocale(int category, const wxChar *locale)
c9e089e9 1693{
ddf14c13 1694 char *localeOld = setlocale(category, wxConvLibc.cWX2MB(locale));
929eed47 1695
ddf14c13 1696 return wxWCharBuffer(wxConvLibc.cMB2WC(localeOld));
c9e089e9
OK
1697}
1698#endif
1699
30261041
RN
1700#if wxUSE_WCHAR_T && !defined(HAVE_WCSLEN)
1701WXDLLEXPORT size_t wxWcslen(const wchar_t *s)
1702{
1703 size_t n = 0;
1704 while ( *s++ )
1705 n++;
1706
1707 return n;
1708}
1709#endif
1710
f6f5941b
VZ
1711// ----------------------------------------------------------------------------
1712// string.h functions
1713// ----------------------------------------------------------------------------
1714
b0655a87 1715#ifdef wxNEED_WX_STRING_H
30261041
RN
1716
1717// RN: These need to be c externed for the regex lib
1718#ifdef __cplusplus
1719extern "C" {
1720#endif
1721
b0655a87
OK
1722WXDLLEXPORT wxChar * wxStrcat(wxChar *dest, const wxChar *src)
1723{
1724 wxChar *ret = dest;
1725 while (*dest) dest++;
1726 while ((*dest++ = *src++));
1727 return ret;
1728}
1729
109c7768 1730WXDLLEXPORT const wxChar * wxStrchr(const wxChar *s, wxChar c)
b0655a87 1731{
109c7768
VZ
1732 // be careful here as the terminating NUL makes part of the string
1733 while ( *s != c )
1734 {
1735 if ( !*s++ )
1736 return NULL;
1737 }
1738
1739 return s;
b0655a87
OK
1740}
1741
1742WXDLLEXPORT int wxStrcmp(const wxChar *s1, const wxChar *s2)
1743{
1744 while ((*s1 == *s2) && *s1) s1++, s2++;
1745 if ((wxUChar)*s1 < (wxUChar)*s2) return -1;
1746 if ((wxUChar)*s1 > (wxUChar)*s2) return 1;
1747 return 0;
1748}
1749
1750WXDLLEXPORT wxChar * wxStrcpy(wxChar *dest, const wxChar *src)
1751{
1752 wxChar *ret = dest;
1753 while ((*dest++ = *src++));
1754 return ret;
1755}
1756
dcb68102
RN
1757WXDLLEXPORT size_t wxStrlen_(const wxChar *s)
1758{
1759 size_t n = 0;
1760 while ( *s++ )
1761 n++;
525d8583 1762
dcb68102
RN
1763 return n;
1764}
1765
1766
b0655a87
OK
1767WXDLLEXPORT wxChar * wxStrncat(wxChar *dest, const wxChar *src, size_t n)
1768{
1769 wxChar *ret = dest;
1770 while (*dest) dest++;
1771 while (n && (*dest++ = *src++)) n--;
1772 return ret;
1773}
1774
a5e0b1e8
OK
1775WXDLLEXPORT int wxStrncmp(const wxChar *s1, const wxChar *s2, size_t n)
1776{
1777 while (n && (*s1 == *s2) && *s1) n--, s1++, s2++;
1778 if (n) {
1779 if ((wxUChar)*s1 < (wxUChar)*s2) return -1;
1780 if ((wxUChar)*s1 > (wxUChar)*s2) return 1;
1781 }
1782 return 0;
1783}
1784
b0655a87
OK
1785WXDLLEXPORT wxChar * wxStrncpy(wxChar *dest, const wxChar *src, size_t n)
1786{
1787 wxChar *ret = dest;
1788 while (n && (*dest++ = *src++)) n--;
1789 while (n) *dest++=0, n--; // the docs specify padding with zeroes
1790 return ret;
1791}
1792
109c7768 1793WXDLLEXPORT const wxChar * wxStrpbrk(const wxChar *s, const wxChar *accept)
b0655a87 1794{
109c7768
VZ
1795 while (*s && !wxStrchr(accept, *s))
1796 s++;
1797
1798 return *s ? s : NULL;
b0655a87
OK
1799}
1800
109c7768 1801WXDLLEXPORT const wxChar * wxStrrchr(const wxChar *s, wxChar c)
b0655a87 1802{
109c7768
VZ
1803 const wxChar *ret = NULL;
1804 do
1805 {
1806 if ( *s == c )
1807 ret = s;
1808 s++;
1809 }
1810 while ( *s );
1811
1812 return ret;
b0655a87
OK
1813}
1814
1815WXDLLEXPORT size_t wxStrspn(const wxChar *s, const wxChar *accept)
1816{
1817 size_t len = 0;
1818 while (wxStrchr(accept, *s++)) len++;
1819 return len;
1820}
1821
109c7768 1822WXDLLEXPORT const wxChar *wxStrstr(const wxChar *haystack, const wxChar *needle)
b0655a87 1823{
dcb68102 1824 wxASSERT_MSG( needle != NULL, _T("NULL argument in wxStrstr") );
9f6fe288 1825
109c7768
VZ
1826 // VZ: this is not exactly the most efficient string search algorithm...
1827
9f6fe288
VZ
1828 const size_t len = wxStrlen(needle);
1829
109c7768 1830 while ( const wxChar *fnd = wxStrchr(haystack, *needle) )
9f6fe288
VZ
1831 {
1832 if ( !wxStrncmp(fnd, needle, len) )
1833 return fnd;
1834
1835 haystack = fnd + 1;
1836 }
1837
109c7768 1838 return NULL;
b0655a87
OK
1839}
1840
30261041
RN
1841#ifdef __cplusplus
1842}
1843#endif
1844
b0655a87
OK
1845WXDLLEXPORT double wxStrtod(const wxChar *nptr, wxChar **endptr)
1846{
1847 const wxChar *start = nptr;
1848
1849 // FIXME: only correct for C locale
1850 while (wxIsspace(*nptr)) nptr++;
223d09f6 1851 if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++;
b0655a87 1852 while (wxIsdigit(*nptr)) nptr++;
223d09f6 1853 if (*nptr == wxT('.')) {
b0655a87
OK
1854 nptr++;
1855 while (wxIsdigit(*nptr)) nptr++;
1856 }
223d09f6 1857 if (*nptr == wxT('E') || *nptr == wxT('e')) {
b0655a87 1858 nptr++;
223d09f6 1859 if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++;
b0655a87
OK
1860 while (wxIsdigit(*nptr)) nptr++;
1861 }
1862
1863 wxString data(nptr, nptr-start);
ddf14c13 1864 wxWX2MBbuf dat = data.mb_str(wxConvLibc);
e90c1d2a 1865 char *rdat = wxMBSTRINGCAST dat;
b0655a87
OK
1866 double ret = strtod(dat, &rdat);
1867
1868 if (endptr) *endptr = (wxChar *)(start + (rdat - (const char *)dat));
1869
1870 return ret;
1871}
1872
1873WXDLLEXPORT long int wxStrtol(const wxChar *nptr, wxChar **endptr, int base)
1874{
1875 const wxChar *start = nptr;
1876
1877 // FIXME: only correct for C locale
1878 while (wxIsspace(*nptr)) nptr++;
223d09f6 1879 if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++;
b0655a87 1880 if (((base == 0) || (base == 16)) &&
223d09f6 1881 (nptr[0] == wxT('0') && nptr[1] == wxT('x'))) {
b0655a87
OK
1882 nptr += 2;
1883 base = 16;
1884 }
223d09f6 1885 else if ((base == 0) && (nptr[0] == wxT('0'))) base = 8;
b0655a87
OK
1886 else if (base == 0) base = 10;
1887
223d09f6
KB
1888 while ((wxIsdigit(*nptr) && (*nptr - wxT('0') < base)) ||
1889 (wxIsalpha(*nptr) && (wxToupper(*nptr) - wxT('A') + 10 < base))) nptr++;
b0655a87 1890
dcb68102 1891 wxString data(start, nptr-start);
ddf14c13 1892 wxWX2MBbuf dat = data.mb_str(wxConvLibc);
e90c1d2a 1893 char *rdat = wxMBSTRINGCAST dat;
b0655a87
OK
1894 long int ret = strtol(dat, &rdat, base);
1895
1896 if (endptr) *endptr = (wxChar *)(start + (rdat - (const char *)dat));
1897
1898 return ret;
1899}
dcb68102
RN
1900
1901WXDLLEXPORT unsigned long int wxStrtoul(const wxChar *nptr, wxChar **endptr, int base)
1902{
1903 return (unsigned long int) wxStrtol(nptr, endptr, base);
1904}
1905
f6f5941b 1906#endif // wxNEED_WX_STRING_H
b0655a87 1907
c9e089e9 1908#ifdef wxNEED_WX_STDIO_H
e7b3d6ba
OK
1909WXDLLEXPORT FILE * wxFopen(const wxChar *path, const wxChar *mode)
1910{
b1ac3b56
RR
1911 char mode_buffer[10];
1912 for (size_t i = 0; i < wxStrlen(mode)+1; i++)
1913 mode_buffer[i] = (char) mode[i];
f6f5941b 1914
b1ac3b56 1915 return fopen( wxConvFile.cWX2MB(path), mode_buffer );
e7b3d6ba
OK
1916}
1917
1918WXDLLEXPORT FILE * wxFreopen(const wxChar *path, const wxChar *mode, FILE *stream)
1919{
b1ac3b56
RR
1920 char mode_buffer[10];
1921 for (size_t i = 0; i < wxStrlen(mode)+1; i++)
1922 mode_buffer[i] = (char) mode[i];
f6f5941b 1923
b1ac3b56 1924 return freopen( wxConvFile.cWX2MB(path), mode_buffer, stream );
e7b3d6ba
OK
1925}
1926
f6bcfd97
BP
1927WXDLLEXPORT int wxRemove(const wxChar *path)
1928{
92980e90 1929 return remove( wxConvFile.cWX2MB(path) );
f6bcfd97
BP
1930}
1931
1932WXDLLEXPORT int wxRename(const wxChar *oldpath, const wxChar *newpath)
1933{
92980e90 1934 return rename( wxConvFile.cWX2MB(oldpath), wxConvFile.cWX2MB(newpath) );
f6bcfd97 1935}
c9e089e9
OK
1936#endif
1937
b7a5d6ca 1938#ifndef wxAtof
c9e089e9
OK
1939double WXDLLEXPORT wxAtof(const wxChar *psz)
1940{
4676948b
JS
1941#ifdef __WXWINCE__
1942 double d;
1943 wxString str(psz);
1944 if (str.ToDouble(& d))
1945 return d;
41e155b4
WS
1946
1947 return 0.0;
4676948b 1948#else
ddf14c13 1949 return atof(wxConvLibc.cWX2MB(psz));
4676948b 1950#endif
c9e089e9 1951}
b7a5d6ca 1952#endif
c9e089e9 1953
b7a5d6ca 1954#ifdef wxNEED_WX_STDLIB_H
c9e089e9
OK
1955int WXDLLEXPORT wxAtoi(const wxChar *psz)
1956{
ddf14c13 1957 return atoi(wxConvLibc.cWX2MB(psz));
c9e089e9
OK
1958}
1959
1960long WXDLLEXPORT wxAtol(const wxChar *psz)
1961{
ddf14c13 1962 return atol(wxConvLibc.cWX2MB(psz));
c9e089e9
OK
1963}
1964
1965wxChar * WXDLLEXPORT wxGetenv(const wxChar *name)
1966{
78868257 1967#if wxUSE_UNICODE
4772f8e1
VS
1968 // NB: buffer returned by getenv() is allowed to be overwritten next
1969 // time getenv() is called, so it is OK to use static string
1970 // buffer to hold the data.
1971 static wxWCharBuffer value((wxChar*)NULL);
ddf14c13 1972 value = wxConvLibc.cMB2WX(getenv(wxConvLibc.cWX2MB(name)));
4772f8e1 1973 return value.data();
92980e90 1974#else
4772f8e1 1975 return getenv(name);
92980e90 1976#endif
c9e089e9
OK
1977}
1978
b1ac3b56 1979int WXDLLEXPORT wxSystem(const wxChar *psz)
c9e089e9 1980{
ddf14c13 1981 return system(wxConvLibc.cWX2MB(psz));
c9e089e9
OK
1982}
1983
33a7c3dd 1984#endif // wxNEED_WX_STDLIB_H
e7b3d6ba
OK
1985
1986#ifdef wxNEED_WX_TIME_H
26378b41
VZ
1987WXDLLEXPORT size_t
1988wxStrftime(wxChar *s, size_t maxsize, const wxChar *fmt, const struct tm *tm)
e7b3d6ba 1989{
26378b41
VZ
1990 if ( !maxsize )
1991 return 0;
f6f5941b 1992
26378b41
VZ
1993 wxCharBuffer buf(maxsize);
1994
ddf14c13 1995 wxCharBuffer bufFmt(wxConvLibc.cWX2MB(fmt));
26378b41 1996 if ( !bufFmt )
b1ac3b56 1997 return 0;
26378b41
VZ
1998
1999 size_t ret = strftime(buf.data(), maxsize, bufFmt, tm);
2000 if ( !ret )
2001 return 0;
2002
ddf14c13 2003 wxWCharBuffer wbuf = wxConvLibc.cMB2WX(buf);
26378b41
VZ
2004 if ( !wbuf )
2005 return 0;
2006
2007 wxStrncpy(s, wbuf, maxsize);
2008 return wxStrlen(s);
e7b3d6ba 2009}
33a7c3dd
VZ
2010#endif // wxNEED_WX_TIME_H
2011
b63b07a8
RL
2012#ifndef wxCtime
2013WXDLLEXPORT wxChar *wxCtime(const time_t *timep)
2014{
9348da2f
VZ
2015 // normally the string is 26 chars but give one more in case some broken
2016 // DOS compiler decides to use "\r\n" instead of "\n" at the end
2017 static wxChar buf[27];
2018
2019 // ctime() is guaranteed to return a string containing only ASCII
2020 // characters, as its format is always the same for any locale
2021 wxStrncpy(buf, wxString::FromAscii(ctime(timep)), WXSIZEOF(buf));
2022 buf[WXSIZEOF(buf) - 1] = _T('\0');
b63b07a8
RL
2023
2024 return buf;
2025}
2026#endif // wxCtime
2027
33a7c3dd
VZ
2028#endif // wxUSE_WCHAR_T
2029
2030// ----------------------------------------------------------------------------
2031// functions which we may need even if !wxUSE_WCHAR_T
2032// ----------------------------------------------------------------------------
2033
2034#ifndef wxStrtok
2035
2036WXDLLEXPORT wxChar * wxStrtok(wxChar *psz, const wxChar *delim, wxChar **save_ptr)
2037{
2038 if (!psz)
2039 {
2040 psz = *save_ptr;
2041 if ( !psz )
2042 return NULL;
2043 }
2044
2045 psz += wxStrspn(psz, delim);
2046 if (!*psz)
2047 {
2048 *save_ptr = (wxChar *)NULL;
2049 return (wxChar *)NULL;
2050 }
2051
2052 wxChar *ret = psz;
2053 psz = wxStrpbrk(psz, delim);
2054 if (!psz)
2055 {
2056 *save_ptr = (wxChar*)NULL;
2057 }
2058 else
2059 {
2060 *psz = wxT('\0');
2061 *save_ptr = psz + 1;
2062 }
2063
2064 return ret;
2065}
2066
2067#endif // wxStrtok
2068
2bb1e1f4
SC
2069// ----------------------------------------------------------------------------
2070// missing C RTL functions
2071// ----------------------------------------------------------------------------
2072
896e226a 2073#ifdef wxNEED_STRDUP
27db4210 2074
2bb1e1f4
SC
2075char *strdup(const char *s)
2076{
d314acc0
SC
2077 char *dest = (char*) malloc( strlen( s ) + 1 ) ;
2078 if ( dest )
2079 strcpy( dest , s ) ;
2080 return dest ;
2bb1e1f4 2081}
27db4210 2082#endif // wxNEED_STRDUP
0be9ace2 2083
eae4425d 2084#if defined(__WXWINCE__) && (_WIN32_WCE <= 211)
27db4210 2085
0be9ace2
JS
2086void *calloc( size_t num, size_t size )
2087{
2088 void** ptr = (void **)malloc(num * size);
2089 memset( ptr, 0, num * size);
2090 return ptr;
2091}
42d11c8e 2092
27db4210 2093#endif // __WXWINCE__ <= 211
4c663122 2094
619be6d0
JS
2095#ifdef __WXWINCE__
2096
2097int wxRemove(const wxChar *path)
2098{
2099 return ::DeleteFile(path) == 0;
2100}
2101
2102#endif