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