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