]> git.saurik.com Git - wxWidgets.git/blob - src/common/wxchar.cpp
Applied patch [ 1192917 ] Grids with no row or col headers cause AV under wxGTK
[wxWidgets.git] / src / common / wxchar.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: wxchar.cpp
3 // Purpose: wxChar implementation
4 // Author: Ove Kåven
5 // Modified by: Ron Lee
6 // Created: 09/04/99
7 // RCS-ID: $Id$
8 // Copyright: (c) wxWidgets copyright
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13 #pragma implementation "wxchar.h"
14 #endif
15
16 // ===========================================================================
17 // headers, declarations, constants
18 // ===========================================================================
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #define _ISOC9X_SOURCE 1 // to get vsscanf()
28 #define _BSD_SOURCE 1 // to still get strdup()
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #ifndef __WXWINCE__
35 #include <time.h>
36 #include <locale.h>
37 #else
38 #include "wx/msw/wince/time.h"
39 #endif
40
41 #ifndef WX_PRECOMP
42 #include "wx/defs.h"
43 #include "wx/wxchar.h"
44 #include "wx/string.h"
45 #include "wx/hash.h"
46 #endif
47
48 #if defined(__WIN32__) && defined(wxNEED_WX_CTYPE_H)
49 #include <windef.h>
50 #include <winbase.h>
51 #include <winnls.h>
52 #include <winnt.h>
53 #endif
54
55 #if defined(__MWERKS__) && __MSL__ >= 0x6000
56 namespace std {}
57 using namespace std ;
58 #endif
59
60 #ifdef __WXMAC__
61 #include "wx/mac/private.h"
62 #endif
63
64 #if wxUSE_WCHAR_T
65 size_t WXDLLEXPORT wxMB2WC(wchar_t *buf, const char *psz, size_t n)
66 {
67 // assume that we have mbsrtowcs() too if we have wcsrtombs()
68 #if HAVE_WCSRTOMBS
69 mbstate_t mbstate;
70 memset(&mbstate, 0, sizeof(mbstate_t));
71 #endif
72
73 if (buf) {
74 if (!n || !*psz) {
75 if (n) *buf = wxT('\0');
76 return 0;
77 }
78 #ifdef HAVE_WCSRTOMBS
79 return mbsrtowcs(buf, &psz, n, &mbstate);
80 #else
81 return wxMbstowcs(buf, psz, n);
82 #endif
83 }
84
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 #if 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 #if HAVE_WCSRTOMBS
106 return wcsrtombs(buf, &pwz, n, &mbstate);
107 #else
108 return wxWcstombs(buf, pwz, n);
109 #endif
110 }
111
112 #if 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 // ----------------------------------------------------------------------------
165
166 #if !defined(wxVsnprintf_)
167 int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax,
168 const wxChar *format, va_list argptr)
169 {
170 // buffer to avoid dynamic memory allocation each time for small strings
171 char szScratch[1024];
172
173 // number of characters in the buffer so far, must be less than lenMax
174 size_t lenCur = 0;
175
176 for ( size_t n = 0; ; n++ )
177 {
178 const wxChar chCur = format[n];
179
180 if ( chCur == wxT('%') )
181 {
182 static char s_szFlags[256] = "%";
183 size_t flagofs = 1;
184 bool adj_left = false,
185 in_prec = false,
186 prec_dot = false,
187 done = false;
188 int ilen = 0;
189 size_t min_width = 0,
190 max_width = wxSTRING_MAXLEN;
191 do
192 {
193
194 #define CHECK_PREC \
195 if (in_prec && !prec_dot) \
196 { \
197 s_szFlags[flagofs++] = '.'; \
198 prec_dot = true; \
199 }
200
201 #define APPEND_CH(ch) \
202 { \
203 if ( lenCur == lenMax ) \
204 return -1; \
205 \
206 buf[lenCur++] = ch; \
207 }
208
209 #define APPEND_STR(s) \
210 { \
211 for ( const wxChar *p = s; *p; p++ ) \
212 { \
213 APPEND_CH(*p); \
214 } \
215 }
216
217 // what follows '%'?
218 const wxChar ch = format[++n];
219 switch ( ch )
220 {
221 case wxT('\0'):
222 APPEND_CH(_T('\0'));
223
224 done = true;
225 break;
226
227 case wxT('%'):
228 APPEND_CH(_T('%'));
229 done = true;
230 break;
231
232 case wxT('#'):
233 case wxT('0'):
234 case wxT(' '):
235 case wxT('+'):
236 case wxT('\''):
237 CHECK_PREC
238 s_szFlags[flagofs++] = ch;
239 break;
240
241 case wxT('-'):
242 CHECK_PREC
243 adj_left = true;
244 s_szFlags[flagofs++] = ch;
245 break;
246
247 case wxT('.'):
248 CHECK_PREC
249 in_prec = true;
250 prec_dot = false;
251 max_width = 0;
252 // dot will be auto-added to s_szFlags if non-negative
253 // number follows
254 break;
255
256 case wxT('h'):
257 ilen = -1;
258 CHECK_PREC
259 s_szFlags[flagofs++] = ch;
260 break;
261
262 case wxT('l'):
263 ilen = 1;
264 CHECK_PREC
265 s_szFlags[flagofs++] = ch;
266 break;
267
268 case wxT('q'):
269 case wxT('L'):
270 ilen = 2;
271 CHECK_PREC
272 s_szFlags[flagofs++] = ch;
273 break;
274
275 case wxT('Z'):
276 ilen = 3;
277 CHECK_PREC
278 s_szFlags[flagofs++] = ch;
279 break;
280
281 case wxT('*'):
282 {
283 int len = va_arg(argptr, int);
284 if (in_prec)
285 {
286 if (len<0) break;
287 CHECK_PREC
288 max_width = len;
289 }
290 else
291 {
292 if (len<0)
293 {
294 adj_left = !adj_left;
295 s_szFlags[flagofs++] = '-';
296 len = -len;
297 }
298 min_width = len;
299 }
300 flagofs += ::sprintf(s_szFlags+flagofs,"%d",len);
301 }
302 break;
303
304 case wxT('1'): case wxT('2'): case wxT('3'):
305 case wxT('4'): case wxT('5'): case wxT('6'):
306 case wxT('7'): case wxT('8'): case wxT('9'):
307 {
308 int len = 0;
309 CHECK_PREC
310 while ( (format[n] >= wxT('0')) &&
311 (format[n] <= wxT('9')) )
312 {
313 s_szFlags[flagofs++] = format[n];
314 len = len*10 + (format[n] - wxT('0'));
315 n++;
316 }
317
318 if (in_prec)
319 max_width = len;
320 else
321 min_width = len;
322
323 n--; // the main loop pre-increments n again
324 }
325 break;
326
327 case wxT('d'):
328 case wxT('i'):
329 case wxT('o'):
330 case wxT('u'):
331 case wxT('x'):
332 case wxT('X'):
333 CHECK_PREC
334 s_szFlags[flagofs++] = ch;
335 s_szFlags[flagofs] = '\0';
336 if (ilen == 0 )
337 {
338 int val = va_arg(argptr, int);
339 ::sprintf(szScratch, s_szFlags, val);
340 }
341 else if (ilen == -1)
342 {
343 // NB: 'short int' value passed through '...'
344 // is promoted to 'int', so we have to get
345 // an int from stack even if we need a short
346 short int val = (short int) va_arg(argptr, int);
347 ::sprintf(szScratch, s_szFlags, val);
348 }
349 else if (ilen == 1)
350 {
351 long int val = va_arg(argptr, long int);
352 ::sprintf(szScratch, s_szFlags, val);
353 }
354 else if (ilen == 2)
355 {
356 #if SIZEOF_LONG_LONG
357 long long int val = va_arg(argptr, long long int);
358 ::sprintf(szScratch, s_szFlags, val);
359 #else // !long long
360 long int val = va_arg(argptr, long int);
361 ::sprintf(szScratch, s_szFlags, val);
362 #endif // long long/!long long
363 }
364 else if (ilen == 3)
365 {
366 size_t val = va_arg(argptr, size_t);
367 ::sprintf(szScratch, s_szFlags, val);
368 }
369
370 {
371 const wxMB2WXbuf tmp =
372 wxConvLibc.cMB2WX(szScratch);
373 APPEND_STR(tmp);
374 }
375
376 done = true;
377 break;
378
379 case wxT('e'):
380 case wxT('E'):
381 case wxT('f'):
382 case wxT('g'):
383 case wxT('G'):
384 CHECK_PREC
385 s_szFlags[flagofs++] = ch;
386 s_szFlags[flagofs] = '\0';
387 if (ilen == 2)
388 {
389 long double val = va_arg(argptr, long double);
390 ::sprintf(szScratch, s_szFlags, val);
391 }
392 else
393 {
394 double val = va_arg(argptr, double);
395 ::sprintf(szScratch, s_szFlags, val);
396 }
397
398 {
399 const wxMB2WXbuf tmp =
400 wxConvLibc.cMB2WX(szScratch);
401 APPEND_STR(tmp);
402 }
403
404 done = true;
405 break;
406
407 case wxT('p'):
408 {
409 void *val = va_arg(argptr, void *);
410 CHECK_PREC
411 s_szFlags[flagofs++] = ch;
412 s_szFlags[flagofs] = '\0';
413 ::sprintf(szScratch, s_szFlags, val);
414
415 const wxMB2WXbuf tmp =
416 wxConvLibc.cMB2WX(szScratch);
417 APPEND_STR(tmp);
418
419 done = true;
420 }
421 break;
422
423 case wxT('c'):
424 {
425 int val = va_arg(argptr, int);
426 #if wxUSE_UNICODE
427 if (ilen == -1)
428 {
429 const char buf[2] = { val, 0 };
430 val = wxString(buf, wxConvLibc)[0u];
431 }
432 #elif wxUSE_WCHAR_T
433 if (ilen == 1)
434 {
435 const wchar_t buf[2] = { val, 0 };
436 val = wxString(buf, wxConvLibc)[0u];
437 }
438 #endif
439 size_t i;
440
441 if (!adj_left)
442 for (i = 1; i < min_width; i++)
443 APPEND_CH(_T(' '));
444
445 APPEND_CH(val);
446
447 if (adj_left)
448 for (i = 1; i < min_width; i++)
449 APPEND_CH(_T(' '));
450
451 done = true;
452 }
453 break;
454
455 case wxT('s'):
456 {
457 const wxChar *val = NULL;
458 #if wxUSE_UNICODE
459 wxString s;
460
461 if (ilen == -1)
462 {
463 // wx extension: we'll let %hs mean non-Unicode
464 // strings
465 char *v = va_arg(argptr, char *);
466
467 if (v)
468 val = s = wxString(v, wxConvLibc);
469 }
470 else
471 #elif wxUSE_WCHAR_T
472 wxString s;
473
474 if (ilen == 1)
475 {
476 // %ls means Unicode strings
477 wchar_t *v = va_arg(argptr, wchar_t *);
478
479 if (v)
480 val = s = wxString(v, wxConvLibc);
481 }
482 else
483 #endif
484 {
485 val = va_arg(argptr, wxChar *);
486 }
487
488 size_t len = 0;
489
490 if (val)
491 {
492 for ( len = 0;
493 val[len] && (len < max_width);
494 len++ )
495 ;
496 }
497 else if (max_width >= 6)
498 {
499 val = wxT("(null)");
500 len = 6;
501 }
502 else
503 {
504 val = wxEmptyString;
505 len = 0;
506 }
507
508 size_t i;
509
510 if (!adj_left)
511 for (i = len; i < min_width; i++)
512 APPEND_CH(_T(' '));
513
514 for (i = 0; i < len; i++)
515 APPEND_CH(val[i]);
516
517 if (adj_left)
518 for (i = len; i < min_width; i++)
519 APPEND_CH(_T(' '));
520
521 done = true;
522 }
523 break;
524
525 case wxT('n'):
526 if (ilen == 0)
527 {
528 int *val = va_arg(argptr, int *);
529 *val = lenCur;
530 }
531 else if (ilen == -1)
532 {
533 short int *val = va_arg(argptr, short int *);
534 *val = lenCur;
535 }
536 else if (ilen >= 1)
537 {
538 long int *val = va_arg(argptr, long int *);
539 *val = lenCur;
540 }
541 done = true;
542 break;
543
544 default:
545 // bad format, leave unchanged
546 APPEND_CH(_T('%'));
547 APPEND_CH(ch);
548 done = true;
549 break;
550 }
551 }
552 while (!done);
553 }
554 else
555 {
556 APPEND_CH(chCur);
557 }
558
559 // terminating NUL?
560 if ( !chCur )
561 break;
562 }
563
564 return lenCur;
565 }
566
567 #undef APPEND_CH
568 #undef APPEND_STR
569 #undef CHECK_PREC
570
571 #endif // !wxVsnprintfA
572
573 #if !defined(wxSnprintf_)
574 int WXDLLEXPORT wxSnprintf_(wxChar *buf, size_t len, const wxChar *format, ...)
575 {
576 va_list argptr;
577 va_start(argptr, format);
578
579 int iLen = wxVsnprintf_(buf, len, format, argptr);
580
581 va_end(argptr);
582
583 return iLen;
584 }
585 #endif // wxSnprintf_
586
587 #if defined(__DMC__)
588 /* Digital Mars adds count to _stprintf (C99) so convert */
589 #if wxUSE_UNICODE
590 int wxSprintf (wchar_t * __RESTRICT s, const wchar_t * __RESTRICT format, ... )
591 {
592 va_list arglist;
593
594 va_start( arglist, format );
595 int iLen = swprintf ( s, -1, format, arglist );
596 va_end( arglist );
597 return iLen ;
598 }
599
600 #endif // wxUSE_UNICODE
601
602 #endif //__DMC__
603
604 // ----------------------------------------------------------------------------
605 // implement the standard IO functions for wide char if libc doesn't have them
606 // ----------------------------------------------------------------------------
607
608 #ifdef wxNEED_FPUTS
609 int wxFputs(const wchar_t *ws, FILE *stream)
610 {
611 // counting the number of wide characters written isn't worth the trouble,
612 // simply distinguish between ok and error
613 return fputs(wxConvLibc.cWC2MB(ws), stream) == -1 ? -1 : 0;
614 }
615 #endif // wxNEED_FPUTS
616
617 #ifdef wxNEED_PUTS
618 int wxPuts(const wxChar *ws)
619 {
620 int rc = wxFputs(ws, stdout);
621 if ( rc != -1 )
622 {
623 if ( wxFputs(L"\n", stdout) == -1 )
624 return -1;
625
626 rc++;
627 }
628
629 return rc;
630 }
631 #endif // wxNEED_PUTS
632
633 #ifdef wxNEED_PUTC
634 int /* not wint_t */ wxPutc(wchar_t wc, FILE *stream)
635 {
636 wchar_t ws[2] = { wc, L'\0' };
637
638 return wxFputs(ws, stream);
639 }
640 #endif // wxNEED_PUTC
641
642 // NB: we only implement va_list functions here, the ones taking ... are
643 // defined below for wxNEED_PRINTF_CONVERSION case anyhow and we reuse
644 // the definitions there to avoid duplicating them here
645 #ifdef wxNEED_WPRINTF
646
647 // TODO: implement the scanf() functions
648 int vwscanf(const wxChar *format, va_list argptr)
649 {
650 wxFAIL_MSG( _T("TODO") );
651
652 return -1;
653 }
654
655 int vswscanf(const wxChar *ws, const wxChar *format, va_list argptr)
656 {
657 // The best we can do without proper Unicode support in glibc is to
658 // convert the strings into MB representation and run ANSI version
659 // of the function. This doesn't work with %c and %s because of difference
660 // in size of char and wchar_t, though.
661
662 wxCHECK_MSG( wxStrstr(format, _T("%s")) == NULL, -1,
663 _T("incomplete vswscanf implementation doesn't allow %s") );
664 wxCHECK_MSG( wxStrstr(format, _T("%c")) == NULL, -1,
665 _T("incomplete vswscanf implementation doesn't allow %c") );
666
667 va_list argcopy;
668 wxVaCopy(argcopy, argptr);
669 return vsscanf(wxConvLibc.cWX2MB(ws), wxConvLibc.cWX2MB(format), argcopy);
670 }
671
672 int vfwscanf(FILE *stream, const wxChar *format, va_list argptr)
673 {
674 wxFAIL_MSG( _T("TODO") );
675
676 return -1;
677 }
678
679 #define vswprintf wxVsnprintf_
680
681 int vfwprintf(FILE *stream, const wxChar *format, va_list argptr)
682 {
683 wxString s;
684 int rc = s.PrintfV(format, argptr);
685
686 if ( rc != -1 )
687 {
688 // we can't do much better without Unicode support in libc...
689 if ( fprintf(stream, "%s", (const char*)s.mb_str() ) == -1 )
690 return -1;
691 }
692
693 return rc;
694 }
695
696 int vwprintf(const wxChar *format, va_list argptr)
697 {
698 return wxVfprintf(stdout, format, argptr);
699 }
700
701 #endif // wxNEED_WPRINTF
702
703 #ifdef wxNEED_PRINTF_CONVERSION
704
705 // ----------------------------------------------------------------------------
706 // wxFormatConverter: class doing the "%s" -> "%ls" conversion
707 // ----------------------------------------------------------------------------
708
709 /*
710 Here are the gory details. We want to follow the Windows/MS conventions,
711 that is to have
712
713 In ANSI mode:
714
715 format specifier results in
716 -----------------------------------
717 %c, %hc, %hC char
718 %lc, %C, %lC wchar_t
719
720 In Unicode mode:
721
722 format specifier results in
723 -----------------------------------
724 %hc, %C, %hC char
725 %c, %lc, %lC wchar_t
726
727
728 while on POSIX systems we have %C identical to %lc and %c always means char
729 (in any mode) while %lc always means wchar_t,
730
731 So to use native functions in order to get our semantics we must do the
732 following translations in Unicode mode (nothing to do in ANSI mode):
733
734 wxWidgets specifier POSIX specifier
735 ----------------------------------------
736
737 %hc, %C, %hC %c
738 %c %lc
739
740
741 And, of course, the same should be done for %s as well.
742 */
743
744 class wxFormatConverter
745 {
746 public:
747 wxFormatConverter(const wxChar *format);
748
749 // notice that we only translated the string if m_fmtOrig == NULL (as set
750 // by CopyAllBefore()), otherwise we should simply use the original format
751 operator const wxChar *() const
752 { return m_fmtOrig ? m_fmtOrig : m_fmt.c_str(); }
753
754 private:
755 // copy another character to the translated format: this function does the
756 // copy if we are translating but doesn't do anything at all if we don't,
757 // so we don't create the translated format string at all unless we really
758 // need to (i.e. InsertFmtChar() is called)
759 wxChar CopyFmtChar(wxChar ch)
760 {
761 if ( !m_fmtOrig )
762 {
763 // we're translating, do copy
764 m_fmt += ch;
765 }
766 else
767 {
768 // simply increase the count which should be copied by
769 // CopyAllBefore() later if needed
770 m_nCopied++;
771 }
772
773 return ch;
774 }
775
776 // insert an extra character
777 void InsertFmtChar(wxChar ch)
778 {
779 if ( m_fmtOrig )
780 {
781 // so far we haven't translated anything yet
782 CopyAllBefore();
783 }
784
785 m_fmt += ch;
786 }
787
788 void CopyAllBefore()
789 {
790 wxASSERT_MSG( m_fmtOrig && m_fmt.empty(), _T("logic error") );
791
792 m_fmt = wxString(m_fmtOrig, m_nCopied);
793
794 // we won't need it any longer
795 m_fmtOrig = NULL;
796 }
797
798 static bool IsFlagChar(wxChar ch)
799 {
800 return ch == _T('-') || ch == _T('+') ||
801 ch == _T('0') || ch == _T(' ') || ch == _T('#');
802 }
803
804 void SkipDigits(const wxChar **ptpc)
805 {
806 while ( **ptpc >= _T('0') && **ptpc <= _T('9') )
807 CopyFmtChar(*(*ptpc)++);
808 }
809
810 // the translated format
811 wxString m_fmt;
812
813 // the original format
814 const wxChar *m_fmtOrig;
815
816 // the number of characters already copied
817 size_t m_nCopied;
818 };
819
820 wxFormatConverter::wxFormatConverter(const wxChar *format)
821 {
822 m_fmtOrig = format;
823 m_nCopied = 0;
824
825 while ( *format )
826 {
827 if ( CopyFmtChar(*format++) == _T('%') )
828 {
829 // skip any flags
830 while ( IsFlagChar(*format) )
831 CopyFmtChar(*format++);
832
833 // and possible width
834 if ( *format == _T('*') )
835 CopyFmtChar(*format++);
836 else
837 SkipDigits(&format);
838
839 // precision?
840 if ( *format == _T('.') )
841 {
842 CopyFmtChar(*format++);
843 if ( *format == _T('*') )
844 CopyFmtChar(*format++);
845 else
846 SkipDigits(&format);
847 }
848
849 // next we can have a size modifier
850 enum
851 {
852 Default,
853 Short,
854 Long
855 } size;
856
857 switch ( *format )
858 {
859 case _T('h'):
860 size = Short;
861 format++;
862 break;
863
864 case _T('l'):
865 // "ll" has a different meaning!
866 if ( format[1] != _T('l') )
867 {
868 size = Long;
869 format++;
870 break;
871 }
872 //else: fall through
873
874 default:
875 size = Default;
876 }
877
878 // and finally we should have the type
879 switch ( *format )
880 {
881 case _T('C'):
882 case _T('S'):
883 // %C and %hC -> %c and %lC -> %lc
884 if ( size == Long )
885 CopyFmtChar(_T('l'));
886
887 InsertFmtChar(*format++ == _T('C') ? _T('c') : _T('s'));
888 break;
889
890 case _T('c'):
891 case _T('s'):
892 // %c -> %lc but %hc stays %hc and %lc is still %lc
893 if ( size == Default)
894 InsertFmtChar(_T('l'));
895 // fall through
896
897 default:
898 // nothing special to do
899 if ( size != Default )
900 CopyFmtChar(*(format - 1));
901 CopyFmtChar(*format++);
902 }
903 }
904 }
905 }
906
907 #else // !wxNEED_PRINTF_CONVERSION
908 // no conversion necessary
909 #define wxFormatConverter(x) (x)
910 #endif // wxNEED_PRINTF_CONVERSION/!wxNEED_PRINTF_CONVERSION
911
912 #ifdef __WXDEBUG__
913 // For testing the format converter
914 wxString wxConvertFormat(const wxChar *format)
915 {
916 return wxString(wxFormatConverter(format));
917 }
918 #endif
919
920 // ----------------------------------------------------------------------------
921 // wxPrintf(), wxScanf() and relatives
922 // ----------------------------------------------------------------------------
923
924 #if defined(wxNEED_PRINTF_CONVERSION) || defined(wxNEED_WPRINTF)
925
926 int wxScanf( const wxChar *format, ... )
927 {
928 va_list argptr;
929 va_start(argptr, format);
930
931 int ret = vwscanf(wxFormatConverter(format), argptr );
932
933 va_end(argptr);
934
935 return ret;
936 }
937
938 int wxSscanf( const wxChar *str, const wxChar *format, ... )
939 {
940 va_list argptr;
941 va_start(argptr, format);
942
943 int ret = vswscanf( str, wxFormatConverter(format), argptr );
944
945 va_end(argptr);
946
947 return ret;
948 }
949
950 int wxFscanf( FILE *stream, const wxChar *format, ... )
951 {
952 va_list argptr;
953 va_start(argptr, format);
954 int ret = vfwscanf(stream, wxFormatConverter(format), argptr);
955
956 va_end(argptr);
957
958 return ret;
959 }
960
961 int wxPrintf( const wxChar *format, ... )
962 {
963 va_list argptr;
964 va_start(argptr, format);
965
966 int ret = vwprintf( wxFormatConverter(format), argptr );
967
968 va_end(argptr);
969
970 return ret;
971 }
972
973 #ifndef wxSnprintf
974 int wxSnprintf( wxChar *str, size_t size, const wxChar *format, ... )
975 {
976 va_list argptr;
977 va_start(argptr, format);
978
979 int ret = vswprintf( str, size, wxFormatConverter(format), argptr );
980
981 va_end(argptr);
982
983 return ret;
984 }
985 #endif // wxSnprintf
986
987 int wxSprintf( wxChar *str, const wxChar *format, ... )
988 {
989 va_list argptr;
990 va_start(argptr, format);
991
992 // note that wxString::FormatV() uses wxVsnprintf(), not wxSprintf(), so
993 // it's safe to implement this one in terms of it
994 wxString s(wxString::FormatV(format, argptr));
995 wxStrcpy(str, s);
996
997 va_end(argptr);
998
999 return s.length();
1000 }
1001
1002 int wxFprintf( FILE *stream, const wxChar *format, ... )
1003 {
1004 va_list argptr;
1005 va_start( argptr, format );
1006
1007 int ret = vfwprintf( stream, wxFormatConverter(format), argptr );
1008
1009 va_end(argptr);
1010
1011 return ret;
1012 }
1013
1014 int wxVsscanf( const wxChar *str, const wxChar *format, va_list argptr )
1015 {
1016 return vswscanf( str, wxFormatConverter(format), argptr );
1017 }
1018
1019 int wxVfprintf( FILE *stream, const wxChar *format, va_list argptr )
1020 {
1021 return vfwprintf( stream, wxFormatConverter(format), argptr );
1022 }
1023
1024 int wxVprintf( const wxChar *format, va_list argptr )
1025 {
1026 return vwprintf( wxFormatConverter(format), argptr );
1027 }
1028
1029 #ifndef wxVsnprintf
1030 int wxVsnprintf( wxChar *str, size_t size, const wxChar *format, va_list argptr )
1031 {
1032 return vswprintf( str, size, wxFormatConverter(format), argptr );
1033 }
1034 #endif // wxVsnprintf
1035
1036 int wxVsprintf( wxChar *str, const wxChar *format, va_list argptr )
1037 {
1038 // same as for wxSprintf()
1039 return vswprintf(str, INT_MAX / 4, wxFormatConverter(format), argptr);
1040 }
1041
1042 #endif // wxNEED_PRINTF_CONVERSION
1043
1044 #if wxUSE_WCHAR_T
1045
1046 // ----------------------------------------------------------------------------
1047 // ctype.h stuff (currently unused)
1048 // ----------------------------------------------------------------------------
1049
1050 #if defined(__WIN32__) && defined(wxNEED_WX_CTYPE_H)
1051 inline WORD wxMSW_ctype(wxChar ch)
1052 {
1053 WORD ret;
1054 GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, &ch, 1, &ret);
1055 return ret;
1056 }
1057
1058 WXDLLEXPORT int wxIsalnum(wxChar ch) { return IsCharAlphaNumeric(ch); }
1059 WXDLLEXPORT int wxIsalpha(wxChar ch) { return IsCharAlpha(ch); }
1060 WXDLLEXPORT int wxIscntrl(wxChar ch) { return wxMSW_ctype(ch) & C1_CNTRL; }
1061 WXDLLEXPORT int wxIsdigit(wxChar ch) { return wxMSW_ctype(ch) & C1_DIGIT; }
1062 WXDLLEXPORT int wxIsgraph(wxChar ch) { return wxMSW_ctype(ch) & (C1_DIGIT|C1_PUNCT|C1_ALPHA); }
1063 WXDLLEXPORT int wxIslower(wxChar ch) { return IsCharLower(ch); }
1064 WXDLLEXPORT int wxIsprint(wxChar ch) { return wxMSW_ctype(ch) & (C1_DIGIT|C1_SPACE|C1_PUNCT|C1_ALPHA); }
1065 WXDLLEXPORT int wxIspunct(wxChar ch) { return wxMSW_ctype(ch) & C1_PUNCT; }
1066 WXDLLEXPORT int wxIsspace(wxChar ch) { return wxMSW_ctype(ch) & C1_SPACE; }
1067 WXDLLEXPORT int wxIsupper(wxChar ch) { return IsCharUpper(ch); }
1068 WXDLLEXPORT int wxIsxdigit(wxChar ch) { return wxMSW_ctype(ch) & C1_XDIGIT; }
1069 WXDLLEXPORT int wxTolower(wxChar ch) { return (wxChar)CharLower((LPTSTR)(ch)); }
1070 WXDLLEXPORT int wxToupper(wxChar ch) { return (wxChar)CharUpper((LPTSTR)(ch)); }
1071 #endif
1072
1073 #if defined(__DARWIN__) && ( MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_2 )
1074
1075 WXDLLEXPORT size_t wxMbstowcs (wchar_t * out, const char * in, size_t outlen)
1076 {
1077 if (!out)
1078 {
1079 size_t outsize = 0;
1080 while(*in++)
1081 outsize++;
1082 return outsize;
1083 }
1084
1085 const char* origin = in;
1086
1087 while (outlen-- && *in)
1088 {
1089 *out++ = (wchar_t) *in++;
1090 }
1091
1092 *out = '\0';
1093
1094 return in - origin;
1095 }
1096
1097 WXDLLEXPORT size_t wxWcstombs (char * out, const wchar_t * in, size_t outlen)
1098 {
1099 if (!out)
1100 {
1101 size_t outsize = 0;
1102 while(*in++)
1103 outsize++;
1104 return outsize;
1105 }
1106
1107 const wchar_t* origin = in;
1108
1109 while (outlen-- && *in)
1110 {
1111 *out++ = (char) *in++;
1112 }
1113
1114 *out = '\0';
1115
1116 return in - origin;
1117 }
1118
1119 #if defined(wxNEED_WX_CTYPE_H)
1120
1121 #include <CoreFoundation/CoreFoundation.h>
1122
1123 #define cfalnumset CFCharacterSetGetPredefined(kCFCharacterSetAlphaNumeric)
1124 #define cfalphaset CFCharacterSetGetPredefined(kCFCharacterSetLetter)
1125 #define cfcntrlset CFCharacterSetGetPredefined(kCFCharacterSetControl)
1126 #define cfdigitset CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit)
1127 //CFCharacterSetRef cfgraphset = kCFCharacterSetControl && !' '
1128 #define cflowerset CFCharacterSetGetPredefined(kCFCharacterSetLowercaseLetter)
1129 //CFCharacterSetRef cfprintset = !kCFCharacterSetControl
1130 #define cfpunctset CFCharacterSetGetPredefined(kCFCharacterSetPunctuation)
1131 #define cfspaceset CFCharacterSetGetPredefined(kCFCharacterSetWhitespaceAndNewline)
1132 #define cfupperset CFCharacterSetGetPredefined(kCFCharacterSetUppercaseLetter)
1133
1134 WXDLLEXPORT int wxIsalnum(wxChar ch) { return CFCharacterSetIsCharacterMember(cfalnumset, ch); }
1135 WXDLLEXPORT int wxIsalpha(wxChar ch) { return CFCharacterSetIsCharacterMember(cfalphaset, ch); }
1136 WXDLLEXPORT int wxIscntrl(wxChar ch) { return CFCharacterSetIsCharacterMember(cfcntrlset, ch); }
1137 WXDLLEXPORT int wxIsdigit(wxChar ch) { return CFCharacterSetIsCharacterMember(cfdigitset, ch); }
1138 WXDLLEXPORT int wxIsgraph(wxChar ch) { return !CFCharacterSetIsCharacterMember(cfcntrlset, ch) && ch != ' '; }
1139 WXDLLEXPORT int wxIslower(wxChar ch) { return CFCharacterSetIsCharacterMember(cflowerset, ch); }
1140 WXDLLEXPORT int wxIsprint(wxChar ch) { return !CFCharacterSetIsCharacterMember(cfcntrlset, ch); }
1141 WXDLLEXPORT int wxIspunct(wxChar ch) { return CFCharacterSetIsCharacterMember(cfpunctset, ch); }
1142 WXDLLEXPORT int wxIsspace(wxChar ch) { return CFCharacterSetIsCharacterMember(cfspaceset, ch); }
1143 WXDLLEXPORT int wxIsupper(wxChar ch) { return CFCharacterSetIsCharacterMember(cfupperset, ch); }
1144 WXDLLEXPORT int wxIsxdigit(wxChar ch) { return wxIsdigit(ch) || (ch>='a' && ch<='f') || (ch>='A' && ch<='F'); }
1145 WXDLLEXPORT int wxTolower(wxChar ch) { return (wxChar)tolower((char)(ch)); }
1146 WXDLLEXPORT int wxToupper(wxChar ch) { return (wxChar)toupper((char)(ch)); }
1147
1148 #endif // wxNEED_WX_CTYPE_H
1149
1150 #endif // defined(__DARWIN__) and OSX <= 10.2
1151
1152 #ifndef wxStrdupA
1153
1154 WXDLLEXPORT char *wxStrdupA(const char *s)
1155 {
1156 return strcpy((char *)malloc(strlen(s) + 1), s);
1157 }
1158
1159 #endif // wxStrdupA
1160
1161 #ifndef wxStrdupW
1162
1163 WXDLLEXPORT wchar_t * wxStrdupW(const wchar_t *pwz)
1164 {
1165 size_t size = (wxWcslen(pwz) + 1) * sizeof(wchar_t);
1166 wchar_t *ret = (wchar_t *) malloc(size);
1167 memcpy(ret, pwz, size);
1168 return ret;
1169 }
1170
1171 #endif // wxStrdupW
1172
1173 #ifndef wxStricmp
1174 int WXDLLEXPORT wxStricmp(const wxChar *psz1, const wxChar *psz2)
1175 {
1176 register wxChar c1, c2;
1177 do {
1178 c1 = wxTolower(*psz1++);
1179 c2 = wxTolower(*psz2++);
1180 } while ( c1 && (c1 == c2) );
1181 return c1 - c2;
1182 }
1183 #endif
1184
1185 #ifndef wxStricmp
1186 int WXDLLEXPORT wxStrnicmp(const wxChar *s1, const wxChar *s2, size_t n)
1187 {
1188 // initialize the variables just to suppress stupid gcc warning
1189 register wxChar c1 = 0, c2 = 0;
1190 while (n && ((c1 = wxTolower(*s1)) == (c2 = wxTolower(*s2)) ) && c1) n--, s1++, s2++;
1191 if (n) {
1192 if (c1 < c2) return -1;
1193 if (c1 > c2) return 1;
1194 }
1195 return 0;
1196 }
1197 #endif
1198
1199 #ifndef wxSetlocale
1200 WXDLLEXPORT wxWCharBuffer wxSetlocale(int category, const wxChar *locale)
1201 {
1202 char *localeOld = setlocale(category, wxConvLibc.cWX2MB(locale));
1203
1204 return wxWCharBuffer(wxConvLibc.cMB2WC(localeOld));
1205 }
1206 #endif
1207
1208 #if wxUSE_WCHAR_T && !defined(HAVE_WCSLEN)
1209 WXDLLEXPORT size_t wxWcslen(const wchar_t *s)
1210 {
1211 size_t n = 0;
1212 while ( *s++ )
1213 n++;
1214
1215 return n;
1216 }
1217 #endif
1218
1219 // ----------------------------------------------------------------------------
1220 // string.h functions
1221 // ----------------------------------------------------------------------------
1222
1223 #ifdef wxNEED_WX_STRING_H
1224
1225 // RN: These need to be c externed for the regex lib
1226 #ifdef __cplusplus
1227 extern "C" {
1228 #endif
1229
1230 WXDLLEXPORT wxChar * wxStrcat(wxChar *dest, const wxChar *src)
1231 {
1232 wxChar *ret = dest;
1233 while (*dest) dest++;
1234 while ((*dest++ = *src++));
1235 return ret;
1236 }
1237
1238 WXDLLEXPORT const wxChar * wxStrchr(const wxChar *s, wxChar c)
1239 {
1240 // be careful here as the terminating NUL makes part of the string
1241 while ( *s != c )
1242 {
1243 if ( !*s++ )
1244 return NULL;
1245 }
1246
1247 return s;
1248 }
1249
1250 WXDLLEXPORT int wxStrcmp(const wxChar *s1, const wxChar *s2)
1251 {
1252 while ((*s1 == *s2) && *s1) s1++, s2++;
1253 if ((wxUChar)*s1 < (wxUChar)*s2) return -1;
1254 if ((wxUChar)*s1 > (wxUChar)*s2) return 1;
1255 return 0;
1256 }
1257
1258 WXDLLEXPORT wxChar * wxStrcpy(wxChar *dest, const wxChar *src)
1259 {
1260 wxChar *ret = dest;
1261 while ((*dest++ = *src++));
1262 return ret;
1263 }
1264
1265 WXDLLEXPORT size_t wxStrlen_(const wxChar *s)
1266 {
1267 size_t n = 0;
1268 while ( *s++ )
1269 n++;
1270
1271 return n;
1272 }
1273
1274
1275 WXDLLEXPORT wxChar * wxStrncat(wxChar *dest, const wxChar *src, size_t n)
1276 {
1277 wxChar *ret = dest;
1278 while (*dest) dest++;
1279 while (n && (*dest++ = *src++)) n--;
1280 return ret;
1281 }
1282
1283 WXDLLEXPORT int wxStrncmp(const wxChar *s1, const wxChar *s2, size_t n)
1284 {
1285 while (n && (*s1 == *s2) && *s1) n--, s1++, s2++;
1286 if (n) {
1287 if ((wxUChar)*s1 < (wxUChar)*s2) return -1;
1288 if ((wxUChar)*s1 > (wxUChar)*s2) return 1;
1289 }
1290 return 0;
1291 }
1292
1293 WXDLLEXPORT wxChar * wxStrncpy(wxChar *dest, const wxChar *src, size_t n)
1294 {
1295 wxChar *ret = dest;
1296 while (n && (*dest++ = *src++)) n--;
1297 while (n) *dest++=0, n--; // the docs specify padding with zeroes
1298 return ret;
1299 }
1300
1301 WXDLLEXPORT const wxChar * wxStrpbrk(const wxChar *s, const wxChar *accept)
1302 {
1303 while (*s && !wxStrchr(accept, *s))
1304 s++;
1305
1306 return *s ? s : NULL;
1307 }
1308
1309 WXDLLEXPORT const wxChar * wxStrrchr(const wxChar *s, wxChar c)
1310 {
1311 const wxChar *ret = NULL;
1312 do
1313 {
1314 if ( *s == c )
1315 ret = s;
1316 s++;
1317 }
1318 while ( *s );
1319
1320 return ret;
1321 }
1322
1323 WXDLLEXPORT size_t wxStrspn(const wxChar *s, const wxChar *accept)
1324 {
1325 size_t len = 0;
1326 while (wxStrchr(accept, *s++)) len++;
1327 return len;
1328 }
1329
1330 WXDLLEXPORT const wxChar *wxStrstr(const wxChar *haystack, const wxChar *needle)
1331 {
1332 wxASSERT_MSG( needle != NULL, _T("NULL argument in wxStrstr") );
1333
1334 // VZ: this is not exactly the most efficient string search algorithm...
1335
1336 const size_t len = wxStrlen(needle);
1337
1338 while ( const wxChar *fnd = wxStrchr(haystack, *needle) )
1339 {
1340 if ( !wxStrncmp(fnd, needle, len) )
1341 return fnd;
1342
1343 haystack = fnd + 1;
1344 }
1345
1346 return NULL;
1347 }
1348
1349 #ifdef __cplusplus
1350 }
1351 #endif
1352
1353 WXDLLEXPORT double wxStrtod(const wxChar *nptr, wxChar **endptr)
1354 {
1355 const wxChar *start = nptr;
1356
1357 // FIXME: only correct for C locale
1358 while (wxIsspace(*nptr)) nptr++;
1359 if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++;
1360 while (wxIsdigit(*nptr)) nptr++;
1361 if (*nptr == wxT('.')) {
1362 nptr++;
1363 while (wxIsdigit(*nptr)) nptr++;
1364 }
1365 if (*nptr == wxT('E') || *nptr == wxT('e')) {
1366 nptr++;
1367 if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++;
1368 while (wxIsdigit(*nptr)) nptr++;
1369 }
1370
1371 wxString data(nptr, nptr-start);
1372 wxWX2MBbuf dat = data.mb_str(wxConvLibc);
1373 char *rdat = wxMBSTRINGCAST dat;
1374 double ret = strtod(dat, &rdat);
1375
1376 if (endptr) *endptr = (wxChar *)(start + (rdat - (const char *)dat));
1377
1378 return ret;
1379 }
1380
1381 WXDLLEXPORT long int wxStrtol(const wxChar *nptr, wxChar **endptr, int base)
1382 {
1383 const wxChar *start = nptr;
1384
1385 // FIXME: only correct for C locale
1386 while (wxIsspace(*nptr)) nptr++;
1387 if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++;
1388 if (((base == 0) || (base == 16)) &&
1389 (nptr[0] == wxT('0') && nptr[1] == wxT('x'))) {
1390 nptr += 2;
1391 base = 16;
1392 }
1393 else if ((base == 0) && (nptr[0] == wxT('0'))) base = 8;
1394 else if (base == 0) base = 10;
1395
1396 while ((wxIsdigit(*nptr) && (*nptr - wxT('0') < base)) ||
1397 (wxIsalpha(*nptr) && (wxToupper(*nptr) - wxT('A') + 10 < base))) nptr++;
1398
1399 wxString data(start, nptr-start);
1400 wxWX2MBbuf dat = data.mb_str(wxConvLibc);
1401 char *rdat = wxMBSTRINGCAST dat;
1402 long int ret = strtol(dat, &rdat, base);
1403
1404 if (endptr) *endptr = (wxChar *)(start + (rdat - (const char *)dat));
1405
1406 return ret;
1407 }
1408
1409 WXDLLEXPORT unsigned long int wxStrtoul(const wxChar *nptr, wxChar **endptr, int base)
1410 {
1411 return (unsigned long int) wxStrtol(nptr, endptr, base);
1412 }
1413
1414 #endif // wxNEED_WX_STRING_H
1415
1416 #ifdef wxNEED_WX_STDIO_H
1417 WXDLLEXPORT FILE * wxFopen(const wxChar *path, const wxChar *mode)
1418 {
1419 char mode_buffer[10];
1420 for (size_t i = 0; i < wxStrlen(mode)+1; i++)
1421 mode_buffer[i] = (char) mode[i];
1422
1423 return fopen( wxConvFile.cWX2MB(path), mode_buffer );
1424 }
1425
1426 WXDLLEXPORT FILE * wxFreopen(const wxChar *path, const wxChar *mode, FILE *stream)
1427 {
1428 char mode_buffer[10];
1429 for (size_t i = 0; i < wxStrlen(mode)+1; i++)
1430 mode_buffer[i] = (char) mode[i];
1431
1432 return freopen( wxConvFile.cWX2MB(path), mode_buffer, stream );
1433 }
1434
1435 WXDLLEXPORT int wxRemove(const wxChar *path)
1436 {
1437 return remove( wxConvFile.cWX2MB(path) );
1438 }
1439
1440 WXDLLEXPORT int wxRename(const wxChar *oldpath, const wxChar *newpath)
1441 {
1442 return rename( wxConvFile.cWX2MB(oldpath), wxConvFile.cWX2MB(newpath) );
1443 }
1444 #endif
1445
1446 #ifndef wxAtof
1447 double WXDLLEXPORT wxAtof(const wxChar *psz)
1448 {
1449 #ifdef __WXWINCE__
1450 double d;
1451 wxString str(psz);
1452 if (str.ToDouble(& d))
1453 return d;
1454 else
1455 return 0.0;
1456 #else
1457 return atof(wxConvLibc.cWX2MB(psz));
1458 #endif
1459 }
1460 #endif
1461
1462 #ifdef wxNEED_WX_STDLIB_H
1463 int WXDLLEXPORT wxAtoi(const wxChar *psz)
1464 {
1465 return atoi(wxConvLibc.cWX2MB(psz));
1466 }
1467
1468 long WXDLLEXPORT wxAtol(const wxChar *psz)
1469 {
1470 return atol(wxConvLibc.cWX2MB(psz));
1471 }
1472
1473 wxChar * WXDLLEXPORT wxGetenv(const wxChar *name)
1474 {
1475 #if wxUSE_UNICODE
1476 // NB: buffer returned by getenv() is allowed to be overwritten next
1477 // time getenv() is called, so it is OK to use static string
1478 // buffer to hold the data.
1479 static wxWCharBuffer value((wxChar*)NULL);
1480 value = wxConvLibc.cMB2WX(getenv(wxConvLibc.cWX2MB(name)));
1481 return value.data();
1482 #else
1483 return getenv(name);
1484 #endif
1485 }
1486
1487 int WXDLLEXPORT wxSystem(const wxChar *psz)
1488 {
1489 return system(wxConvLibc.cWX2MB(psz));
1490 }
1491
1492 #endif // wxNEED_WX_STDLIB_H
1493
1494 #ifdef wxNEED_WX_TIME_H
1495 WXDLLEXPORT size_t
1496 wxStrftime(wxChar *s, size_t maxsize, const wxChar *fmt, const struct tm *tm)
1497 {
1498 if ( !maxsize )
1499 return 0;
1500
1501 wxCharBuffer buf(maxsize);
1502
1503 wxCharBuffer bufFmt(wxConvLibc.cWX2MB(fmt));
1504 if ( !bufFmt )
1505 return 0;
1506
1507 size_t ret = strftime(buf.data(), maxsize, bufFmt, tm);
1508 if ( !ret )
1509 return 0;
1510
1511 wxWCharBuffer wbuf = wxConvLibc.cMB2WX(buf);
1512 if ( !wbuf )
1513 return 0;
1514
1515 wxStrncpy(s, wbuf, maxsize);
1516 return wxStrlen(s);
1517 }
1518 #endif // wxNEED_WX_TIME_H
1519
1520 #ifndef wxCtime
1521 WXDLLEXPORT wxChar *wxCtime(const time_t *timep)
1522 {
1523 // normally the string is 26 chars but give one more in case some broken
1524 // DOS compiler decides to use "\r\n" instead of "\n" at the end
1525 static wxChar buf[27];
1526
1527 // ctime() is guaranteed to return a string containing only ASCII
1528 // characters, as its format is always the same for any locale
1529 wxStrncpy(buf, wxString::FromAscii(ctime(timep)), WXSIZEOF(buf));
1530 buf[WXSIZEOF(buf) - 1] = _T('\0');
1531
1532 return buf;
1533 }
1534 #endif // wxCtime
1535
1536 #endif // wxUSE_WCHAR_T
1537
1538 // ----------------------------------------------------------------------------
1539 // functions which we may need even if !wxUSE_WCHAR_T
1540 // ----------------------------------------------------------------------------
1541
1542 #ifndef wxStrtok
1543
1544 WXDLLEXPORT wxChar * wxStrtok(wxChar *psz, const wxChar *delim, wxChar **save_ptr)
1545 {
1546 if (!psz)
1547 {
1548 psz = *save_ptr;
1549 if ( !psz )
1550 return NULL;
1551 }
1552
1553 psz += wxStrspn(psz, delim);
1554 if (!*psz)
1555 {
1556 *save_ptr = (wxChar *)NULL;
1557 return (wxChar *)NULL;
1558 }
1559
1560 wxChar *ret = psz;
1561 psz = wxStrpbrk(psz, delim);
1562 if (!psz)
1563 {
1564 *save_ptr = (wxChar*)NULL;
1565 }
1566 else
1567 {
1568 *psz = wxT('\0');
1569 *save_ptr = psz + 1;
1570 }
1571
1572 return ret;
1573 }
1574
1575 #endif // wxStrtok
1576
1577 // ----------------------------------------------------------------------------
1578 // missing C RTL functions
1579 // ----------------------------------------------------------------------------
1580
1581 #if wxNEED_STRDUP
1582
1583 char *strdup(const char *s)
1584 {
1585 char *dest = (char*) malloc( strlen( s ) + 1 ) ;
1586 if ( dest )
1587 strcpy( dest , s ) ;
1588 return dest ;
1589 }
1590 #endif // wxNEED_STRDUP
1591
1592 #if defined(__WXWINCE__) && (_WIN32_WCE <= 211)
1593
1594 void *calloc( size_t num, size_t size )
1595 {
1596 void** ptr = (void **)malloc(num * size);
1597 memset( ptr, 0, num * size);
1598 return ptr;
1599 }
1600
1601 #endif // __WXWINCE__ <= 211
1602