1. made CRT wrappers definitions indepenent of wxUSE_UNICODE: both ANSI and Unicode...
[wxWidgets.git] / src / common / wxcrt.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/wxcrt.cpp
3 // Purpose: wxChar CRT wrappers 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 #ifdef __WXWINCE__
54 // there is no errno.h under CE apparently
55 #define wxSET_ERRNO(value)
56 #else
57 #include <errno.h>
58
59 #define wxSET_ERRNO(value) errno = value
60 #endif
61
62 #if defined(__MWERKS__) && __MSL__ >= 0x6000
63 namespace std {}
64 using namespace std ;
65 #endif
66
67 #if wxUSE_WCHAR_T
68 size_t WXDLLEXPORT wxMB2WC(wchar_t *buf, const char *psz, size_t n)
69 {
70 // assume that we have mbsrtowcs() too if we have wcsrtombs()
71 #ifdef HAVE_WCSRTOMBS
72 mbstate_t mbstate;
73 memset(&mbstate, 0, sizeof(mbstate_t));
74 #endif
75
76 if (buf) {
77 if (!n || !*psz) {
78 if (n) *buf = wxT('\0');
79 return 0;
80 }
81 #ifdef HAVE_WCSRTOMBS
82 return mbsrtowcs(buf, &psz, n, &mbstate);
83 #else
84 return wxMbstowcs(buf, psz, n);
85 #endif
86 }
87
88 // note that we rely on common (and required by Unix98 but unfortunately not
89 // C99) extension which allows to call mbs(r)towcs() with NULL output pointer
90 // to just get the size of the needed buffer -- this is needed as otherwise
91 // we have no idea about how much space we need and if the CRT doesn't
92 // support it (the only currently known example being Metrowerks, see
93 // wx/wxchar.h) we don't use its mbstowcs() at all
94 #ifdef HAVE_WCSRTOMBS
95 return mbsrtowcs((wchar_t *) NULL, &psz, 0, &mbstate);
96 #else
97 return wxMbstowcs((wchar_t *) NULL, psz, 0);
98 #endif
99 }
100
101 size_t WXDLLEXPORT wxWC2MB(char *buf, const wchar_t *pwz, size_t n)
102 {
103 #ifdef HAVE_WCSRTOMBS
104 mbstate_t mbstate;
105 memset(&mbstate, 0, sizeof(mbstate_t));
106 #endif
107
108 if (buf) {
109 if (!n || !*pwz) {
110 // glibc2.1 chokes on null input
111 if (n) *buf = '\0';
112 return 0;
113 }
114 #ifdef HAVE_WCSRTOMBS
115 return wcsrtombs(buf, &pwz, n, &mbstate);
116 #else
117 return wxWcstombs(buf, pwz, n);
118 #endif
119 }
120
121 #ifdef HAVE_WCSRTOMBS
122 return wcsrtombs((char *) NULL, &pwz, 0, &mbstate);
123 #else
124 return wxWcstombs((char *) NULL, pwz, 0);
125 #endif
126 }
127 #endif // wxUSE_WCHAR_T
128
129 bool WXDLLEXPORT wxOKlibc()
130 {
131 #if wxUSE_WCHAR_T && defined(__UNIX__) && defined(__GLIBC__) && !defined(__WINE__)
132 // glibc 2.0 uses UTF-8 even when it shouldn't
133 wchar_t res = 0;
134 if ((MB_CUR_MAX == 2) &&
135 (wxMB2WC(&res, "\xdd\xa5", 1) == 1) &&
136 (res==0x765)) {
137 // this is UTF-8 allright, check whether that's what we want
138 char *cur_locale = setlocale(LC_CTYPE, NULL);
139 if ((strlen(cur_locale) < 4) ||
140 (strcasecmp(cur_locale + strlen(cur_locale) - 4, "utf8")) ||
141 (strcasecmp(cur_locale + strlen(cur_locale) - 5, "utf-8"))) {
142 // nope, don't use libc conversion
143 return false;
144 }
145 }
146 #endif
147 return true;
148 }
149
150 char* wxSetlocale(int category, const char *locale)
151 {
152 char *rv = setlocale(category, locale);
153 if ( locale != NULL /* setting locale, not querying */ &&
154 rv /* call was successful */ )
155 {
156 wxUpdateLocaleIsUtf8();
157 }
158 return rv;
159 }
160
161 // ============================================================================
162 // printf() functions business
163 // ============================================================================
164
165 // special test mode: define all functions below even if we don't really need
166 // them to be able to test them
167 #ifdef wxTEST_PRINTF
168 #undef wxFprintf
169 #undef wxPrintf
170 #undef wxSprintf
171 #undef wxVfprintf
172 #undef wxVsprintf
173 #undef wxVprintf
174 #undef wxVsnprintf_
175
176 #define wxNEED_WPRINTF
177
178 int wxCRT_VfprintfW( FILE *stream, const wchar_t *format, va_list argptr );
179 #endif
180
181 #if defined(__DMC__)
182 /* Digital Mars adds count to _stprintf (C99) so convert */
183 int wxCRT_SprintfW (wchar_t * __RESTRICT s, const wchar_t * __RESTRICT format, ... )
184 {
185 va_list arglist;
186
187 va_start( arglist, format );
188 int iLen = swprintf ( s, -1, format, arglist );
189 va_end( arglist );
190 return iLen ;
191 }
192 #endif //__DMC__
193
194 // ----------------------------------------------------------------------------
195 // implement the standard IO functions for wide char if libc doesn't have them
196 // ----------------------------------------------------------------------------
197
198 #ifndef wxCRT_FputsW
199 int wxCRT_FputsW(const wchar_t *ws, FILE *stream)
200 {
201 wxCharBuffer buf(wxConvLibc.cWC2MB(ws));
202 if ( !buf )
203 return -1;
204
205 // counting the number of wide characters written isn't worth the trouble,
206 // simply distinguish between ok and error
207 return wxCRT_FputsA(buf, stream) == -1 ? -1 : 0;
208 }
209 #endif // !wxCRT_FputsW
210
211 #ifndef wxCRT_PutsW
212 int wxCRT_PutsW(const wchar_t *ws)
213 {
214 int rc = wxCRT_FputsW(ws, stdout);
215 if ( rc != -1 )
216 {
217 if ( wxCRT_FputsW(L"\n", stdout) == -1 )
218 return -1;
219
220 rc++;
221 }
222
223 return rc;
224 }
225 #endif // !wxCRT_PutsW
226
227 #ifndef wxCRT_FputcW
228 int /* not wint_t */ wxCRT_FputcW(wchar_t wc, FILE *stream)
229 {
230 wchar_t ws[2] = { wc, L'\0' };
231
232 return wxCRT_FputsW(ws, stream);
233 }
234 #endif // !wxCRT_FputcW
235
236 // NB: we only implement va_list functions here, the ones taking ... are
237 // defined below for wxNEED_PRINTF_CONVERSION case anyhow and we reuse
238 // the definitions there to avoid duplicating them here
239 #ifdef wxNEED_WPRINTF
240
241 // TODO: implement the scanf() functions
242 static int vwscanf(const wchar_t *format, va_list argptr)
243 {
244 wxFAIL_MSG( _T("TODO") );
245
246 return -1;
247 }
248
249 static int vswscanf(const wchar_t *ws, const wchar_t *format, va_list argptr)
250 {
251 // The best we can do without proper Unicode support in glibc is to
252 // convert the strings into MB representation and run ANSI version
253 // of the function. This doesn't work with %c and %s because of difference
254 // in size of char and wchar_t, though.
255
256 wxCHECK_MSG( wxStrstr(format, _T("%s")) == NULL, -1,
257 _T("incomplete vswscanf implementation doesn't allow %s") );
258 wxCHECK_MSG( wxStrstr(format, _T("%c")) == NULL, -1,
259 _T("incomplete vswscanf implementation doesn't allow %c") );
260
261 return vsscanf(wxConvLibc.cWX2MB(ws), wxConvLibc.cWX2MB(format), argptr);
262 }
263
264 static int vfwscanf(FILE *stream, const wchar_t *format, va_list argptr)
265 {
266 wxFAIL_MSG( _T("TODO") );
267
268 return -1;
269 }
270
271 #define vswprintf wxCRT_VsnprintfW_
272
273 static int vfwprintf(FILE *stream, const wchar_t *format, va_list argptr)
274 {
275 wxString s;
276 int rc = s.PrintfV(format, argptr);
277
278 if ( rc != -1 )
279 {
280 // we can't do much better without Unicode support in libc...
281 if ( fprintf(stream, "%s", (const char*)s.mb_str() ) == -1 )
282 return -1;
283 }
284
285 return rc;
286 }
287
288 static int vwprintf(const wchar_t *format, va_list argptr)
289 {
290 return wxCRT_VfprintfW(stdout, format, argptr);
291 }
292
293 #endif // wxNEED_WPRINTF
294
295 #ifdef wxNEED_PRINTF_CONVERSION
296
297 // ----------------------------------------------------------------------------
298 // wxFormatConverter: class doing the "%s" -> "%ls" conversion
299 // ----------------------------------------------------------------------------
300
301 /*
302 Here are the gory details. We want to follow the Windows/MS conventions,
303 that is to have
304
305 In ANSI mode:
306
307 format specifier results in
308 -----------------------------------
309 %c, %hc, %hC char
310 %lc, %C, %lC wchar_t
311
312 In Unicode mode:
313
314 format specifier results in
315 -----------------------------------
316 %hc, %C, %hC char
317 %c, %lc, %lC wchar_t
318
319
320 while on POSIX systems we have %C identical to %lc and %c always means char
321 (in any mode) while %lc always means wchar_t,
322
323 So to use native functions in order to get our semantics we must do the
324 following translations in Unicode mode (nothing to do in ANSI mode):
325
326 wxWidgets specifier POSIX specifier
327 ----------------------------------------
328
329 %hc, %C, %hC %c
330 %c %lc
331
332
333 And, of course, the same should be done for %s as well.
334 */
335
336 class wxFormatConverter
337 {
338 public:
339 wxFormatConverter(const wxChar *format);
340
341 // notice that we only translated the string if m_fmtOrig == NULL (as set
342 // by CopyAllBefore()), otherwise we should simply use the original format
343 operator const wxChar *() const
344 { return m_fmtOrig ? m_fmtOrig : m_fmt.c_str(); }
345
346 private:
347 // copy another character to the translated format: this function does the
348 // copy if we are translating but doesn't do anything at all if we don't,
349 // so we don't create the translated format string at all unless we really
350 // need to (i.e. InsertFmtChar() is called)
351 wxChar CopyFmtChar(wxChar ch)
352 {
353 if ( !m_fmtOrig )
354 {
355 // we're translating, do copy
356 m_fmt += ch;
357 }
358 else
359 {
360 // simply increase the count which should be copied by
361 // CopyAllBefore() later if needed
362 m_nCopied++;
363 }
364
365 return ch;
366 }
367
368 // insert an extra character
369 void InsertFmtChar(wxChar ch)
370 {
371 if ( m_fmtOrig )
372 {
373 // so far we haven't translated anything yet
374 CopyAllBefore();
375 }
376
377 m_fmt += ch;
378 }
379
380 void CopyAllBefore()
381 {
382 wxASSERT_MSG( m_fmtOrig && m_fmt.empty(), _T("logic error") );
383
384 m_fmt = wxString(m_fmtOrig, m_nCopied);
385
386 // we won't need it any longer
387 m_fmtOrig = NULL;
388 }
389
390 static bool IsFlagChar(wxChar ch)
391 {
392 return ch == _T('-') || ch == _T('+') ||
393 ch == _T('0') || ch == _T(' ') || ch == _T('#');
394 }
395
396 void SkipDigits(const wxChar **ptpc)
397 {
398 while ( **ptpc >= _T('0') && **ptpc <= _T('9') )
399 CopyFmtChar(*(*ptpc)++);
400 }
401
402 // the translated format
403 wxString m_fmt;
404
405 // the original format
406 const wxChar *m_fmtOrig;
407
408 // the number of characters already copied
409 size_t m_nCopied;
410 };
411
412 wxFormatConverter::wxFormatConverter(const wxChar *format)
413 {
414 m_fmtOrig = format;
415 m_nCopied = 0;
416
417 while ( *format )
418 {
419 if ( CopyFmtChar(*format++) == _T('%') )
420 {
421 // skip any flags
422 while ( IsFlagChar(*format) )
423 CopyFmtChar(*format++);
424
425 // and possible width
426 if ( *format == _T('*') )
427 CopyFmtChar(*format++);
428 else
429 SkipDigits(&format);
430
431 // precision?
432 if ( *format == _T('.') )
433 {
434 CopyFmtChar(*format++);
435 if ( *format == _T('*') )
436 CopyFmtChar(*format++);
437 else
438 SkipDigits(&format);
439 }
440
441 // next we can have a size modifier
442 enum
443 {
444 Default,
445 Short,
446 Long
447 } size;
448
449 switch ( *format )
450 {
451 case _T('h'):
452 size = Short;
453 format++;
454 break;
455
456 case _T('l'):
457 // "ll" has a different meaning!
458 if ( format[1] != _T('l') )
459 {
460 size = Long;
461 format++;
462 break;
463 }
464 //else: fall through
465
466 default:
467 size = Default;
468 }
469
470 // and finally we should have the type
471 switch ( *format )
472 {
473 case _T('C'):
474 case _T('S'):
475 // %C and %hC -> %c and %lC -> %lc
476 if ( size == Long )
477 CopyFmtChar(_T('l'));
478
479 InsertFmtChar(*format++ == _T('C') ? _T('c') : _T('s'));
480 break;
481
482 case _T('c'):
483 case _T('s'):
484 // %c -> %lc but %hc stays %hc and %lc is still %lc
485 if ( size == Default)
486 InsertFmtChar(_T('l'));
487 // fall through
488
489 default:
490 // nothing special to do
491 if ( size != Default )
492 CopyFmtChar(*(format - 1));
493 CopyFmtChar(*format++);
494 }
495 }
496 }
497 }
498
499 #else // !wxNEED_PRINTF_CONVERSION
500 // no conversion necessary
501 #define wxFormatConverter(x) (x)
502 #endif // wxNEED_PRINTF_CONVERSION/!wxNEED_PRINTF_CONVERSION
503
504 #ifdef __WXDEBUG__
505 // For testing the format converter
506 wxString wxConvertFormat(const wxChar *format)
507 {
508 return wxString(wxFormatConverter(format));
509 }
510 #endif
511
512 // ----------------------------------------------------------------------------
513 // wxPrintf(), wxScanf() and relatives
514 // ----------------------------------------------------------------------------
515
516 // FIXME-UTF8: do format conversion using (modified) wxFormatConverter in
517 // template wrappers, not here; note that it will needed to
518 // translate all forms of string specifiers to %(l)s for wxPrintf(),
519 // but it only should do what it did in 2.8 for wxScanf()!
520
521 #ifndef wxCRT_PrintfW
522 int wxCRT_PrintfW( const wchar_t *format, ... )
523 {
524 va_list argptr;
525 va_start(argptr, format);
526
527 int ret = vwprintf( wxFormatConverter(format), argptr );
528
529 va_end(argptr);
530
531 return ret;
532 }
533 #endif
534
535 #ifndef wxCRT_FprintfW
536 int wxCRT_FprintfW( FILE *stream, const wchar_t *format, ... )
537 {
538 va_list argptr;
539 va_start( argptr, format );
540
541 int ret = vfwprintf( stream, wxFormatConverter(format), argptr );
542
543 va_end(argptr);
544
545 return ret;
546 }
547 #endif
548
549 #ifndef wxCRT_VfprintfW
550 int wxCRT_VfprintfW( FILE *stream, const wchar_t *format, va_list argptr )
551 {
552 return vfwprintf( stream, wxFormatConverter(format), argptr );
553 }
554 #endif
555
556 #ifndef wxCRT_VprintfW
557 int wxCRT_VprintfW( const wchar_t *format, va_list argptr )
558 {
559 return vwprintf( wxFormatConverter(format), argptr );
560 }
561 #endif
562
563 #ifndef wxCRT_VsnprintfW
564 int wxCRT_VsnprintfW(wchar_t *str, size_t size, const wchar_t *format, va_list argptr )
565 {
566 return vswprintf( str, size, wxFormatConverter(format), argptr );
567 }
568 #endif // !wxCRT_VsnprintfW
569
570 // FIXME-UTF8: we only implement widechar version of vsnprintf() in wxprint.cpp,
571 // so this one has to convert the data for now
572 #ifndef wxCRT_VsnprintfA
573 int wxCRT_VsnprintfA(char *buf, size_t len, const char *format, va_list argptr)
574 {
575 wxWCharBuffer wbuf(len);
576 int rt = wxCRT_VsnprintfW(wbuf.data(), len,
577 (const wchar_t*)wxConvLibc.cMB2WC(format),
578 argptr);
579 if ( rt < 0 || rt >= len )
580 return rt;
581
582 if ( wxConvLibc.FromWChar(buf, len, wbuf) == wxCONV_FAILED )
583 return -1;
584
585 return rt;
586 }
587 #endif // !wxCRT_VsnprintfA
588
589 #ifndef wxCRT_VsprintfW
590 int wxCRT_VsprintfW( wchar_t *str, const wchar_t *format, va_list argptr )
591 {
592 // same as for wxSprintf()
593 return vswprintf(str, INT_MAX / 4, wxFormatConverter(format), argptr);
594 }
595 #endif
596
597 #ifndef wxCRT_ScanfW
598 int wxCRT_ScanfW(const wchar_t *format, ...)
599 {
600 va_list argptr;
601 va_start(argptr, format);
602
603 int ret = vwscanf(wxFormatConverter(format), argptr);
604
605 va_end(argptr);
606
607 return ret;
608 }
609 #endif
610
611 #ifndef wxCRT_SscanfW
612 int wxCRT_SscanfW(const wchar_t *str, const wchar_t *format, ...)
613 {
614 va_list argptr;
615 va_start(argptr, format);
616
617 int ret = vswscanf(str, wxFormatConverter(format), argptr);
618
619 va_end(argptr);
620
621 return ret;
622 }
623 #endif
624
625 #ifndef wxCRT_FscanfW
626 int wxCRT_FscanfW(FILE *stream, const wchar_t *format, ...)
627 {
628 va_list argptr;
629 va_start(argptr, format);
630 int ret = vfwscanf(stream, wxFormatConverter(format), argptr);
631
632 va_end(argptr);
633
634 return ret;
635 }
636 #endif
637
638 #ifndef wxCRT_VsscanfW
639 int wxCRT_VsscanfW(const wchar_t *str, const wchar_t *format, va_list argptr)
640 {
641 return vswscanf(str, wxFormatConverter(format), argptr);
642 }
643 #endif
644
645
646 // ----------------------------------------------------------------------------
647 // wrappers to printf and scanf function families
648 // ----------------------------------------------------------------------------
649
650 #if !wxUSE_UTF8_LOCALE_ONLY
651 int wxDoSprintfWchar(char *str, const wxChar *format, ...)
652 {
653 va_list argptr;
654 va_start(argptr, format);
655
656 int rv = wxVsprintf(str, format, argptr);
657
658 va_end(argptr);
659 return rv;
660 }
661 #endif // !wxUSE_UTF8_LOCALE_ONLY
662
663 #if wxUSE_UNICODE_UTF8
664 int wxDoSprintfUtf8(char *str, const char *format, ...)
665 {
666 va_list argptr;
667 va_start(argptr, format);
668
669 int rv = wxVsprintf(str, format, argptr);
670
671 va_end(argptr);
672 return rv;
673 }
674 #endif // wxUSE_UNICODE_UTF8
675
676 #if wxUSE_UNICODE
677
678 #if !wxUSE_UTF8_LOCALE_ONLY
679 int wxDoSprintfWchar(wchar_t *str, const wxChar *format, ...)
680 {
681 va_list argptr;
682 va_start(argptr, format);
683
684 int rv = wxVsprintf(str, format, argptr);
685
686 va_end(argptr);
687 return rv;
688 }
689 #endif // !wxUSE_UTF8_LOCALE_ONLY
690
691 #if wxUSE_UNICODE_UTF8
692 int wxDoSprintfUtf8(wchar_t *str, const char *format, ...)
693 {
694 va_list argptr;
695 va_start(argptr, format);
696
697 int rv = wxVsprintf(str, format, argptr);
698
699 va_end(argptr);
700 return rv;
701 }
702 #endif // wxUSE_UNICODE_UTF8
703
704 #endif // wxUSE_UNICODE
705
706 #if !wxUSE_UTF8_LOCALE_ONLY
707 int wxDoSnprintfWchar(char *str, size_t size, const wxChar *format, ...)
708 {
709 va_list argptr;
710 va_start(argptr, format);
711
712 int rv = wxVsnprintf(str, size, format, argptr);
713
714 va_end(argptr);
715 return rv;
716 }
717 #endif // !wxUSE_UTF8_LOCALE_ONLY
718
719 #if wxUSE_UNICODE_UTF8
720 int wxDoSnprintfUtf8(char *str, size_t size, const char *format, ...)
721 {
722 va_list argptr;
723 va_start(argptr, format);
724
725 int rv = wxVsnprintf(str, size, format, argptr);
726
727 va_end(argptr);
728 return rv;
729 }
730 #endif // wxUSE_UNICODE_UTF8
731
732 #if wxUSE_UNICODE
733
734 #if !wxUSE_UTF8_LOCALE_ONLY
735 int wxDoSnprintfWchar(wchar_t *str, size_t size, const wxChar *format, ...)
736 {
737 va_list argptr;
738 va_start(argptr, format);
739
740 int rv = wxVsnprintf(str, size, format, argptr);
741
742 va_end(argptr);
743 return rv;
744 }
745 #endif // !wxUSE_UTF8_LOCALE_ONLY
746
747 #if wxUSE_UNICODE_UTF8
748 int wxDoSnprintfUtf8(wchar_t *str, size_t size, const char *format, ...)
749 {
750 va_list argptr;
751 va_start(argptr, format);
752
753 int rv = wxVsnprintf(str, size, format, argptr);
754
755 va_end(argptr);
756 return rv;
757 }
758 #endif // wxUSE_UNICODE_UTF8
759
760 #endif // wxUSE_UNICODE
761
762
763 #ifdef HAVE_BROKEN_VSNPRINTF_DECL
764 #define vsnprintf wx_fixed_vsnprintf
765 #endif
766
767 #if wxUSE_UNICODE
768
769 #if !wxUSE_UTF8_LOCALE_ONLY
770 static int ConvertStringToBuf(const wxString& s, char *out, size_t outsize)
771 {
772 const wxWX2WCbuf buf = s.wc_str();
773
774 size_t len = wxConvLibc.FromWChar(out, outsize, buf);
775 if ( len != wxCONV_FAILED )
776 return len-1;
777 else
778 return wxConvLibc.FromWChar(NULL, 0, buf);
779 }
780 #endif // !wxUSE_UTF8_LOCALE_ONLY
781
782 #if wxUSE_UNICODE_UTF8
783 static int ConvertStringToBuf(const wxString& s, wchar_t *out, size_t outsize)
784 {
785 const wxWX2WCbuf buf(s.wc_str());
786 size_t len = wxWcslen(buf);
787 if ( outsize > len )
788 memcpy(out, buf, (len+1) * sizeof(wchar_t));
789 // else: not enough space
790 return len;
791 }
792 #endif // wxUSE_UNICODE_UTF8
793
794 template<typename T>
795 static size_t PrintfViaString(T *out, size_t outsize,
796 const wxString& format, va_list argptr)
797 {
798 wxString s;
799 s.PrintfV(format, argptr);
800
801 return ConvertStringToBuf(s, out, outsize);
802 }
803 #endif // wxUSE_UNICODE
804
805 int wxVsprintf(char *str, const wxString& format, va_list argptr)
806 {
807 #if wxUSE_UTF8_LOCALE_ONLY
808 return vsprintf(str, format.wx_str(), argptr);
809 #else
810 #if wxUSE_UNICODE_UTF8
811 if ( wxLocaleIsUtf8 )
812 return vsprintf(str, format.wx_str(), argptr);
813 else
814 #endif
815 #if wxUSE_UNICODE
816 return PrintfViaString(str, wxNO_LEN, format, argptr);
817 #else
818 return wxCRT_VsprintfA(str, format.mb_str(), argptr);
819 #endif
820 #endif
821 }
822
823 #if wxUSE_UNICODE
824 int wxVsprintf(wchar_t *str, const wxString& format, va_list argptr)
825 {
826 #if wxUSE_UNICODE_WCHAR
827 return wxCRT_VsprintfW(str, format.wc_str(), argptr);
828 #else // wxUSE_UNICODE_UTF8
829 #if !wxUSE_UTF8_LOCALE_ONLY
830 if ( !wxLocaleIsUtf8 )
831 return wxCRT_VsprintfW(str, format.wc_str(), argptr);
832 else
833 #endif
834 return PrintfViaString(str, wxNO_LEN, format, argptr);
835 #endif // wxUSE_UNICODE_UTF8
836 }
837 #endif // wxUSE_UNICODE
838
839 int wxVsnprintf(char *str, size_t size, const wxString& format, va_list argptr)
840 {
841 int rv;
842 #if wxUSE_UTF8_LOCALE_ONLY
843 rv = wxCRT_VsnprintfA(str, size, format.wx_str(), argptr);
844 #else
845 #if wxUSE_UNICODE_UTF8
846 if ( wxLocaleIsUtf8 )
847 rv = wxCRT_VsnprintfA(str, size, format.wx_str(), argptr);
848 else
849 #endif
850 #if wxUSE_UNICODE
851 {
852 // NB: if this code is called, then wxString::PrintV() would use the
853 // wchar_t* version of wxVsnprintf(), so it's safe to use PrintV()
854 // from here
855 rv = PrintfViaString(str, size, format, argptr);
856 }
857 #else
858 rv = wxCRT_VsnprintfA(str, size, format.mb_str(), argptr);
859 #endif
860 #endif
861
862 // VsnprintfTestCase reveals that glibc's implementation of vswprintf
863 // doesn't nul terminate on truncation.
864 str[size - 1] = 0;
865
866 return rv;
867 }
868
869 #if wxUSE_UNICODE
870 int wxVsnprintf(wchar_t *str, size_t size, const wxString& format, va_list argptr)
871 {
872 int rv;
873
874 #if wxUSE_UNICODE_WCHAR
875 rv = wxCRT_VsnprintfW(str, size, format.wc_str(), argptr);
876 #else // wxUSE_UNICODE_UTF8
877 #if !wxUSE_UTF8_LOCALE_ONLY
878 if ( !wxLocaleIsUtf8 )
879 rv = wxCRT_VsnprintfW(str, size, format.wc_str(), argptr);
880 else
881 #endif
882 {
883 // NB: if this code is called, then wxString::PrintV() would use the
884 // char* version of wxVsnprintf(), so it's safe to use PrintV()
885 // from here
886 rv = PrintfViaString(str, size, format, argptr);
887 }
888 #endif // wxUSE_UNICODE_UTF8
889
890 // VsnprintfTestCase reveals that glibc's implementation of vswprintf
891 // doesn't nul terminate on truncation.
892 str[size - 1] = 0;
893
894 return rv;
895 }
896 #endif // wxUSE_UNICODE
897
898 #if wxUSE_WCHAR_T
899
900 // ----------------------------------------------------------------------------
901 // ctype.h stuff (currently unused)
902 // ----------------------------------------------------------------------------
903
904 #if defined(__WIN32__) && defined(wxNEED_WX_CTYPE_H)
905 static inline WORD wxMSW_ctype(wchar_t ch)
906 {
907 WORD ret;
908 GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, &ch, 1, &ret);
909 return ret;
910 }
911
912 int wxCRT_IsalnumW(wchar_t ch) { return IsCharAlphaNumeric(ch); }
913 int wxCRT_IsalphaW(wchar_t ch) { return IsCharAlpha(ch); }
914 int wxCRT_IscntrlW(wchar_t ch) { return wxMSW_ctype(ch) & C1_CNTRL; }
915 int wxCRT_IsdigitW(wchar_t ch) { return wxMSW_ctype(ch) & C1_DIGIT; }
916 int wxCRT_IsgraphW(wchar_t ch) { return wxMSW_ctype(ch) & (C1_DIGIT|C1_PUNCT|C1_ALPHA); }
917 int wxCRT_IslowerW(wchar_t ch) { return IsCharLower(ch); }
918 int wxCRT_IsprintW(wchar_t ch) { return wxMSW_ctype(ch) & (C1_DIGIT|C1_SPACE|C1_PUNCT|C1_ALPHA); }
919 int wxCRT_IspunctW(wchar_t ch) { return wxMSW_ctype(ch) & C1_PUNCT; }
920 int wxCRT_IsspaceW(wchar_t ch) { return wxMSW_ctype(ch) & C1_SPACE; }
921 int wxCRT_IsupperW(wchar_t ch) { return IsCharUpper(ch); }
922 int wxCRT_IsxdigitW(wchar_t ch) { return wxMSW_ctype(ch) & C1_XDIGIT; }
923 int wxCRT_Tolower(wchar_t ch) { return (wchar_t)CharLower((LPTSTR)(ch)); }
924 int wxCRT_Toupper(wchar_t ch) { return (wchar_t)CharUpper((LPTSTR)(ch)); }
925 #endif
926
927 #ifdef wxNEED_WX_MBSTOWCS
928
929 WXDLLEXPORT size_t wxMbstowcs (wchar_t * out, const char * in, size_t outlen)
930 {
931 if (!out)
932 {
933 size_t outsize = 0;
934 while(*in++)
935 outsize++;
936 return outsize;
937 }
938
939 const char* origin = in;
940
941 while (outlen-- && *in)
942 {
943 *out++ = (wchar_t) *in++;
944 }
945
946 *out = '\0';
947
948 return in - origin;
949 }
950
951 WXDLLEXPORT size_t wxWcstombs (char * out, const wchar_t * in, size_t outlen)
952 {
953 if (!out)
954 {
955 size_t outsize = 0;
956 while(*in++)
957 outsize++;
958 return outsize;
959 }
960
961 const wchar_t* origin = in;
962
963 while (outlen-- && *in)
964 {
965 *out++ = (char) *in++;
966 }
967
968 *out = '\0';
969
970 return in - origin;
971 }
972
973 #endif // wxNEED_WX_MBSTOWCS
974
975 #if defined(wxNEED_WX_CTYPE_H)
976
977 #include <CoreFoundation/CoreFoundation.h>
978
979 #define cfalnumset CFCharacterSetGetPredefined(kCFCharacterSetAlphaNumeric)
980 #define cfalphaset CFCharacterSetGetPredefined(kCFCharacterSetLetter)
981 #define cfcntrlset CFCharacterSetGetPredefined(kCFCharacterSetControl)
982 #define cfdigitset CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit)
983 //CFCharacterSetRef cfgraphset = kCFCharacterSetControl && !' '
984 #define cflowerset CFCharacterSetGetPredefined(kCFCharacterSetLowercaseLetter)
985 //CFCharacterSetRef cfprintset = !kCFCharacterSetControl
986 #define cfpunctset CFCharacterSetGetPredefined(kCFCharacterSetPunctuation)
987 #define cfspaceset CFCharacterSetGetPredefined(kCFCharacterSetWhitespaceAndNewline)
988 #define cfupperset CFCharacterSetGetPredefined(kCFCharacterSetUppercaseLetter)
989
990 int wxCRT_IsalnumW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cfalnumset, ch); }
991 int wxCRT_IsalphaW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cfalphaset, ch); }
992 int wxCRT_IscntrlW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cfcntrlset, ch); }
993 int wxCRT_IsdigitW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cfdigitset, ch); }
994 int wxCRT_IsgraphW(wchar_t ch) { return !CFCharacterSetIsCharacterMember(cfcntrlset, ch) && ch != ' '; }
995 int wxCRT_IslowerW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cflowerset, ch); }
996 int wxCRT_IsprintW(wchar_t ch) { return !CFCharacterSetIsCharacterMember(cfcntrlset, ch); }
997 int wxCRT_IspunctW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cfpunctset, ch); }
998 int wxCRT_IsspaceW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cfspaceset, ch); }
999 int wxCRT_IsupperW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cfupperset, ch); }
1000 int wxCRT_IsxdigitW(wchar_t ch) { return wxCRT_IsdigitW(ch) || (ch>='a' && ch<='f') || (ch>='A' && ch<='F'); }
1001
1002 // FIXME: these are broken!
1003 extern "C" int wxCRT_TolowerW(wchar_t ch) { return (wchar_t)tolower((char)(ch)); }
1004 extern "C" int wxCRT_ToupperW(wchar_t ch) { return (wchar_t)toupper((char)(ch)); }
1005
1006 #endif // wxNEED_WX_CTYPE_H
1007
1008 #ifndef wxCRT_StrdupA
1009 WXDLLEXPORT char *wxCRT_StrdupA(const char *s)
1010 {
1011 return strcpy((char *)malloc(strlen(s) + 1), s);
1012 }
1013 #endif // wxCRT_StrdupA
1014
1015 #ifndef wxCRT_StrdupW
1016 WXDLLEXPORT wchar_t * wxCRT_StrdupW(const wchar_t *pwz)
1017 {
1018 size_t size = (wxWcslen(pwz) + 1) * sizeof(wchar_t);
1019 wchar_t *ret = (wchar_t *) malloc(size);
1020 memcpy(ret, pwz, size);
1021 return ret;
1022 }
1023 #endif // wxCRT_StrdupW
1024
1025 #ifndef wxCRT_StricmpA
1026 int WXDLLEXPORT wxCRT_StricmpA(const char *psz1, const char *psz2)
1027 {
1028 register char c1, c2;
1029 do {
1030 c1 = wxTolower(*psz1++);
1031 c2 = wxTolower(*psz2++);
1032 } while ( c1 && (c1 == c2) );
1033 return c1 - c2;
1034 }
1035 #endif // !defined(wxCRT_StricmpA)
1036
1037 #ifndef wxCRT_StricmpW
1038 int WXDLLEXPORT wxCRT_StricmpW(const wchar_t *psz1, const wchar_t *psz2)
1039 {
1040 register wchar_t c1, c2;
1041 do {
1042 c1 = wxTolower(*psz1++);
1043 c2 = wxTolower(*psz2++);
1044 } while ( c1 && (c1 == c2) );
1045 return c1 - c2;
1046 }
1047 #endif // !defined(wxCRT_StricmpW)
1048
1049 #ifndef wxCRT_StrnicmpA
1050 int WXDLLEXPORT wxCRT_StrnicmpA(const char *s1, const char *s2, size_t n)
1051 {
1052 // initialize the variables just to suppress stupid gcc warning
1053 register char c1 = 0, c2 = 0;
1054 while (n && ((c1 = wxTolower(*s1)) == (c2 = wxTolower(*s2)) ) && c1) n--, s1++, s2++;
1055 if (n) {
1056 if (c1 < c2) return -1;
1057 if (c1 > c2) return 1;
1058 }
1059 return 0;
1060 }
1061 #endif // !defined(wxCRT_StrnicmpA)
1062
1063 #ifndef wxCRT_StrnicmpW
1064 int WXDLLEXPORT wxCRT_StrnicmpW(const wchar_t *s1, const wchar_t *s2, size_t n)
1065 {
1066 // initialize the variables just to suppress stupid gcc warning
1067 register wchar_t c1 = 0, c2 = 0;
1068 while (n && ((c1 = wxTolower(*s1)) == (c2 = wxTolower(*s2)) ) && c1) n--, s1++, s2++;
1069 if (n) {
1070 if (c1 < c2) return -1;
1071 if (c1 > c2) return 1;
1072 }
1073 return 0;
1074 }
1075 #endif // !defined(wxCRT_StrnicmpW)
1076
1077 // ----------------------------------------------------------------------------
1078 // string.h functions
1079 // ----------------------------------------------------------------------------
1080
1081 #ifndef wxCRT_StrcatW
1082 WXDLLEXPORT wchar_t *wxCRT_StrcatW(wchar_t *dest, const wchar_t *src)
1083 {
1084 wchar_t *ret = dest;
1085 while (*dest) dest++;
1086 while ((*dest++ = *src++));
1087 return ret;
1088 }
1089 #endif
1090
1091 #ifndef wxCRT_StrchrW
1092 WXDLLEXPORT const wchar_t *wxCRT_StrchrW(const wchar_t *s, wchar_t c)
1093 {
1094 // be careful here as the terminating NUL makes part of the string
1095 while ( *s != c )
1096 {
1097 if ( !*s++ )
1098 return NULL;
1099 }
1100
1101 return s;
1102 }
1103 #endif
1104
1105 #ifndef wxCRT_StrcmpW
1106 WXDLLEXPORT int wxCRT_StrcmpW(const wchar_t *s1, const wchar_t *s2)
1107 {
1108 while ((*s1 == *s2) && *s1) s1++, s2++;
1109 if ((wxUChar)*s1 < (wxUChar)*s2) return -1;
1110 if ((wxUChar)*s1 > (wxUChar)*s2) return 1;
1111 return 0;
1112 }
1113 #endif
1114
1115 #ifndef wxCRT_StrcpyW
1116 WXDLLEXPORT wchar_t * wxCRT_StrcpyW(wchar_t *dest, const wchar_t *src)
1117 {
1118 wchar_t *ret = dest;
1119 while ((*dest++ = *src++));
1120 return ret;
1121 }
1122 #endif
1123
1124 template<typename T>
1125 static inline size_t wxCRT_DoStrlen(const T *s)
1126 {
1127 size_t n = 0;
1128 while ( *s++ )
1129 n++;
1130
1131 return n;
1132 }
1133
1134 // these two (and wxCRT_StrncmpW below) are extern "C" because they are needed
1135 // by regex code, the rest isn't needed, so it's not declared as extern "C"
1136 #ifndef wxCRT_StrlenA
1137 WXDLLEXPORT size_t wxCRT_StrlenA(const char *s)
1138 { return wxCRT_DoStrlen(s); }
1139 #endif
1140 #ifndef wxCRT_StrlenW
1141 extern "C" WXDLLEXPORT size_t wxCRT_StrlenW(const wchar_t *s)
1142 { return wxCRT_DoStrlen(s); }
1143 #endif
1144
1145 #ifndef wxCRT_StrncatW
1146 WXDLLEXPORT wchar_t * wxCRT_StrncatW(wchar_t *dest, const wchar_t *src, size_t n)
1147 {
1148 wchar_t *ret = dest;
1149 while (*dest) dest++;
1150 while (n && (*dest++ = *src++)) n--;
1151 return ret;
1152 }
1153 #endif
1154
1155 #ifndef wxCRT_StrncmpW
1156 extern "C"
1157 WXDLLEXPORT int wxCRT_StrncmpW(const wchar_t *s1, const wchar_t *s2, size_t n)
1158 {
1159 while (n && (*s1 == *s2) && *s1) n--, s1++, s2++;
1160 if (n) {
1161 if ((wxUChar)*s1 < (wxUChar)*s2) return -1;
1162 if ((wxUChar)*s1 > (wxUChar)*s2) return 1;
1163 }
1164 return 0;
1165 }
1166 #endif
1167
1168 #ifndef wxCRT_StrncpyW
1169 WXDLLEXPORT wchar_t * wxCRT_StrncpyW(wchar_t *dest, const wchar_t *src, size_t n)
1170 {
1171 wchar_t *ret = dest;
1172 while (n && (*dest++ = *src++)) n--;
1173 while (n) *dest++=0, n--; // the docs specify padding with zeroes
1174 return ret;
1175 }
1176 #endif
1177
1178 #ifndef wxCRT_StrpbrkW
1179 WXDLLEXPORT const wchar_t * wxCRT_StrpbrkW(const wchar_t *s, const wchar_t *accept)
1180 {
1181 while (*s && !wxCRT_Strchr(accept, *s))
1182 s++;
1183
1184 return *s ? s : NULL;
1185 }
1186 #endif
1187
1188 #ifndef wxCRT_StrrchrW
1189 WXDLLEXPORT const wchar_t * wxCRT_StrrchrW(const wchar_t *s, wchar_t c)
1190 {
1191 const wchar_t *ret = NULL;
1192 do
1193 {
1194 if ( *s == c )
1195 ret = s;
1196 s++;
1197 }
1198 while ( *s );
1199
1200 return ret;
1201 }
1202 #endif
1203
1204 #ifndef wxCRT_StrspnW
1205 WXDLLEXPORT size_t wxCRT_StrspnW(const wchar_t *s, const wchar_t *accept)
1206 {
1207 size_t len = 0;
1208 while (wxCRT_Strchr(accept, *s++)) len++;
1209 return len;
1210 }
1211 #endif
1212
1213 #ifndef wxCRT_StrstrW
1214 WXDLLEXPORT const wchar_t *wxCRT_StrstrW(const wchar_t *haystack, const wchar_t *needle)
1215 {
1216 wxASSERT_MSG( needle != NULL, _T("NULL argument in wxCRT_Strstr") );
1217
1218 // VZ: this is not exactly the most efficient string search algorithm...
1219
1220 const size_t len = wxStrlen(needle);
1221
1222 while ( const wchar_t *fnd = wxCRT_Strchr(haystack, *needle) )
1223 {
1224 if ( !wxCRT_Strncmp(fnd, needle, len) )
1225 return fnd;
1226
1227 haystack = fnd + 1;
1228 }
1229
1230 return NULL;
1231 }
1232 #endif
1233
1234 #ifndef wxCRT_StrtodW
1235 WXDLLEXPORT double wxCRT_StrtodW(const wchar_t *nptr, wchar_t **endptr)
1236 {
1237 const wchar_t *start = nptr;
1238
1239 // FIXME: only correct for C locale
1240 while (wxIsspace(*nptr)) nptr++;
1241 if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++;
1242 while (wxIsdigit(*nptr)) nptr++;
1243 if (*nptr == wxT('.')) {
1244 nptr++;
1245 while (wxIsdigit(*nptr)) nptr++;
1246 }
1247 if (*nptr == wxT('E') || *nptr == wxT('e')) {
1248 nptr++;
1249 if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++;
1250 while (wxIsdigit(*nptr)) nptr++;
1251 }
1252
1253 wxString data(nptr, nptr-start);
1254 wxWX2MBbuf dat = data.mb_str(wxConvLibc);
1255 char *rdat = wxMBSTRINGCAST dat;
1256 double ret = strtod(dat, &rdat);
1257
1258 if (endptr) *endptr = (wchar_t *)(start + (rdat - (const char *)dat));
1259
1260 return ret;
1261 }
1262 #endif // !wxCRT_StrtodW
1263
1264 #ifndef wxCRT_StrtolW
1265 WXDLLEXPORT long int wxCRT_StrtolW(const wchar_t *nptr, wchar_t **endptr, int base)
1266 {
1267 const wchar_t *start = nptr;
1268
1269 // FIXME: only correct for C locale
1270 while (wxIsspace(*nptr)) nptr++;
1271 if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++;
1272 if (((base == 0) || (base == 16)) &&
1273 (nptr[0] == wxT('0') && nptr[1] == wxT('x'))) {
1274 nptr += 2;
1275 base = 16;
1276 }
1277 else if ((base == 0) && (nptr[0] == wxT('0'))) base = 8;
1278 else if (base == 0) base = 10;
1279
1280 while ((wxIsdigit(*nptr) && (*nptr - wxT('0') < base)) ||
1281 (wxIsalpha(*nptr) && (wxToupper(*nptr) - wxT('A') + 10 < base))) nptr++;
1282
1283 wxString data(start, nptr-start);
1284 wxWX2MBbuf dat = data.mb_str(wxConvLibc);
1285 char *rdat = wxMBSTRINGCAST dat;
1286 long int ret = strtol(dat, &rdat, base);
1287
1288 if (endptr) *endptr = (wchar_t *)(start + (rdat - (const char *)dat));
1289
1290 return ret;
1291 }
1292 #endif // !wxCRT_StrtolW
1293
1294 #ifndef wxCRT_StrtoulW
1295 WXDLLEXPORT unsigned long int wxCRT_StrtoulW(const wchar_t *nptr, wchar_t **endptr, int base)
1296 {
1297 return (unsigned long int) wxCRT_StrtolW(nptr, endptr, base);
1298 }
1299 #endif
1300
1301
1302
1303 #ifndef wxCRT_GetenvW
1304 wchar_t* WXDLLEXPORT wxCRT_GetenvW(const wchar_t *name)
1305 {
1306 // NB: buffer returned by getenv() is allowed to be overwritten next
1307 // time getenv() is called, so it is OK to use static string
1308 // buffer to hold the data.
1309 static wxWCharBuffer value((wxChar*)NULL);
1310 value = wxConvLibc.cMB2WX(getenv(wxConvLibc.cWX2MB(name)));
1311 return value.data();
1312 }
1313 #endif // !wxCRT_GetenvW
1314
1315 #ifndef wxCRT_StrftimeW
1316 WXDLLEXPORT size_t
1317 wxCRT_StrftimeW(wchar_t *s, size_t maxsize, const wchar_t *fmt, const struct tm *tm)
1318 {
1319 if ( !maxsize )
1320 return 0;
1321
1322 wxCharBuffer buf(maxsize);
1323
1324 wxCharBuffer bufFmt(wxConvLibc.cWX2MB(fmt));
1325 if ( !bufFmt )
1326 return 0;
1327
1328 size_t ret = strftime(buf.data(), maxsize, bufFmt, tm);
1329 if ( !ret )
1330 return 0;
1331
1332 wxWCharBuffer wbuf = wxConvLibc.cMB2WX(buf);
1333 if ( !wbuf )
1334 return 0;
1335
1336 wxCRT_StrncpyW(s, wbuf, maxsize);
1337 return wxCRT_StrlenW(s);
1338 }
1339 #endif // !wxCRT_StrftimeW
1340
1341 #endif // wxUSE_WCHAR_T
1342
1343 template<typename T>
1344 static wxULongLong_t
1345 wxCRT_StrtoullBase(const T* nptr, T** endptr, int base, T* sign)
1346 {
1347 wxULongLong_t sum = 0;
1348 wxString wxstr(nptr);
1349 wxString::const_iterator i = wxstr.begin();
1350 wxString::const_iterator end = wxstr.end();
1351
1352 // Skip spaces
1353 while ( i != end && wxIsspace(*i) ) i++;
1354
1355 // Starts with sign?
1356 *sign = wxT(' ');
1357 if ( i != end )
1358 {
1359 T c = *i;
1360 if ( c == wxT('+') || c == wxT('-') )
1361 {
1362 *sign = c;
1363 i++;
1364 }
1365 }
1366
1367 // Starts with 0x?
1368 if ( i != end && *i == wxT('0') )
1369 {
1370 i++;
1371 if ( i != end )
1372 {
1373 if ( *i == wxT('x') && (base == 16 || base == 0) )
1374 {
1375 base = 16;
1376 i++;
1377 }
1378 else
1379 {
1380 if ( endptr )
1381 *endptr = (T*) nptr;
1382 wxSET_ERRNO(EINVAL);
1383 return sum;
1384 }
1385 }
1386 else
1387 i--;
1388 }
1389
1390 if ( base == 0 )
1391 base = 10;
1392
1393 for ( ; i != end; i++ )
1394 {
1395 unsigned int n;
1396
1397 T c = *i;
1398 if ( c >= wxT('0') )
1399 {
1400 if ( c <= wxT('9') )
1401 n = c - wxT('0');
1402 else
1403 n = wxTolower(c) - wxT('a') + 10;
1404 }
1405 else
1406 break;
1407
1408 if ( n >= (unsigned int)base )
1409 // Invalid character (for this base)
1410 break;
1411
1412 wxULongLong_t prevsum = sum;
1413 sum = (sum * base) + n;
1414
1415 if ( sum < prevsum )
1416 {
1417 wxSET_ERRNO(ERANGE);
1418 break;
1419 }
1420 }
1421
1422 if ( endptr )
1423 {
1424 *endptr = (T*)(nptr + (i - wxstr.begin()));
1425 }
1426
1427 return sum;
1428 }
1429
1430 template<typename T>
1431 static wxULongLong_t wxCRT_DoStrtoull(const T* nptr, T** endptr, int base)
1432 {
1433 T sign;
1434 wxULongLong_t uval = wxCRT_StrtoullBase(nptr, endptr, base, &sign);
1435
1436 if ( sign == wxT('-') )
1437 {
1438 wxSET_ERRNO(ERANGE);
1439 uval = 0;
1440 }
1441
1442 return uval;
1443 }
1444
1445 template<typename T>
1446 static wxLongLong_t wxCRT_DoStrtoll(const T* nptr, T** endptr, int base)
1447 {
1448 T sign;
1449 wxULongLong_t uval = wxCRT_StrtoullBase(nptr, endptr, base, &sign);
1450 wxLongLong_t val = 0;
1451
1452 if ( sign == wxT('-') )
1453 {
1454 if ( uval <= wxULL(wxINT64_MAX+1) )
1455 {
1456 if ( uval == wxULL(wxINT64_MAX+1))
1457 val = -((wxLongLong_t)wxINT64_MAX) - 1;
1458 else
1459 val = -((wxLongLong_t)uval);
1460 }
1461 else
1462 {
1463 wxSET_ERRNO(ERANGE);
1464 }
1465 }
1466 else if ( uval <= wxINT64_MAX )
1467 {
1468 val = uval;
1469 }
1470 else
1471 {
1472 wxSET_ERRNO(ERANGE);
1473 }
1474
1475 return val;
1476 }
1477
1478 #ifndef wxCRT_StrtollA
1479 wxLongLong_t wxCRT_StrtollA(const char* nptr, char** endptr, int base)
1480 { return wxCRT_DoStrtoll(nptr, endptr, base); }
1481 #endif
1482 #ifndef wxCRT_StrtollW
1483 wxLongLong_t wxCRT_StrtollW(const wchar_t* nptr, wchar_t** endptr, int base)
1484 { return wxCRT_DoStrtoll(nptr, endptr, base); }
1485 #endif
1486
1487 #ifndef wxCRT_StrtoullA
1488 wxULongLong_t wxCRT_StrtoullA(const char* nptr, char** endptr, int base)
1489 { return wxCRT_DoStrtoull(nptr, endptr, base); }
1490 #endif
1491 #ifndef wxCRT_StrtoullW
1492 wxULongLong_t wxCRT_StrtoullW(const wchar_t* nptr, wchar_t** endptr, int base)
1493 { return wxCRT_DoStrtoull(nptr, endptr, base); }
1494 #endif
1495
1496 // ----------------------------------------------------------------------------
1497 // functions which we may need even if !wxUSE_WCHAR_T
1498 // ----------------------------------------------------------------------------
1499
1500 template<typename T>
1501 static T *wxCRT_DoStrtok(T *psz, const T *delim, T **save_ptr)
1502 {
1503 if (!psz)
1504 {
1505 psz = *save_ptr;
1506 if ( !psz )
1507 return NULL;
1508 }
1509
1510 psz += wxStrspn(psz, delim);
1511 if (!*psz)
1512 {
1513 *save_ptr = (T *)NULL;
1514 return (T *)NULL;
1515 }
1516
1517 T *ret = psz;
1518 psz = wxStrpbrk(psz, delim);
1519 if (!psz)
1520 {
1521 *save_ptr = (T*)NULL;
1522 }
1523 else
1524 {
1525 *psz = wxT('\0');
1526 *save_ptr = psz + 1;
1527 }
1528
1529 return ret;
1530 }
1531
1532 #ifndef wxCRT_StrtokA
1533 char *wxCRT_StrtokA(char *psz, const char *delim, char **save_ptr)
1534 { return wxCRT_DoStrtok(psz, delim, save_ptr); }
1535 #endif
1536 #ifndef wxCRT_StrtokW
1537 wchar_t *wxCRT_StrtokW(wchar_t *psz, const wchar_t *delim, wchar_t **save_ptr)
1538 { return wxCRT_DoStrtok(psz, delim, save_ptr); }
1539 #endif
1540
1541 // ----------------------------------------------------------------------------
1542 // missing C RTL functions
1543 // ----------------------------------------------------------------------------
1544
1545 #ifdef wxNEED_STRDUP
1546
1547 char *strdup(const char *s)
1548 {
1549 char *dest = (char*) malloc( strlen( s ) + 1 ) ;
1550 if ( dest )
1551 strcpy( dest , s ) ;
1552 return dest ;
1553 }
1554 #endif // wxNEED_STRDUP
1555
1556 #if defined(__WXWINCE__) && (_WIN32_WCE <= 211)
1557
1558 void *calloc( size_t num, size_t size )
1559 {
1560 void** ptr = (void **)malloc(num * size);
1561 memset( ptr, 0, num * size);
1562 return ptr;
1563 }
1564
1565 #endif // __WXWINCE__ <= 211
1566
1567 #ifdef __WXWINCE__
1568 int wxCRT_RemoveW(const wchar_t *path)
1569 {
1570 return ::DeleteFile(path) == 0;
1571 }
1572 #endif
1573
1574 #ifndef wxCRT_TmpnamW
1575 wchar_t *wxCRT_TmpnamW(wchar_t *s)
1576 {
1577 // tmpnam_r() returns NULL if s=NULL, do the same
1578 wxCHECK_MSG( s, NULL, "wxTmpnam must be called with a buffer" );
1579
1580 #ifndef L_tmpnam
1581 #define L_tmpnam 1024
1582 #endif
1583 wxCharBuffer buf(L_tmpnam);
1584 tmpnam(buf.data());
1585
1586 wxConvLibc.ToWChar(s, L_tmpnam+1, buf.data());
1587 return s;
1588 }
1589 #endif // !wxCRT_TmpnamW
1590
1591
1592 // ============================================================================
1593 // wxLocaleIsUtf8
1594 // ============================================================================
1595
1596 #if wxUSE_UNICODE_UTF8
1597
1598 #if !wxUSE_UTF8_LOCALE_ONLY
1599 bool wxLocaleIsUtf8 = false; // the safer setting if not known
1600 #endif
1601
1602 static bool wxIsLocaleUtf8()
1603 {
1604 // NB: we intentionally don't use wxLocale::GetSystemEncodingName(),
1605 // because a) it may be unavailable in some builds and b) has slightly
1606 // different semantics (default locale instead of current)
1607
1608 #if defined(HAVE_LANGINFO_H) && defined(CODESET)
1609 // GNU libc provides current character set this way (this conforms to
1610 // Unix98)
1611 const char *charset = nl_langinfo(CODESET);
1612 if ( charset )
1613 {
1614 // "UTF-8" is used by modern glibc versions, but test other variants
1615 // as well, just in case:
1616 if ( strcmp(charset, "UTF-8") == 0 ||
1617 strcmp(charset, "utf-8") == 0 ||
1618 strcmp(charset, "UTF8") == 0 ||
1619 strcmp(charset, "utf8") == 0 )
1620 {
1621 return true;
1622 }
1623 }
1624 #endif
1625
1626 // check if we're running under the "C" locale: it is 7bit subset
1627 // of UTF-8, so it can be safely used with the UTF-8 build:
1628 const char *lc_ctype = setlocale(LC_CTYPE, NULL);
1629 if ( lc_ctype &&
1630 (strcmp(lc_ctype, "C") == 0 || strcmp(lc_ctype, "POSIX") == 0) )
1631 {
1632 return true;
1633 }
1634
1635 // we don't know what charset libc is using, so assume the worst
1636 // to be safe:
1637 return false;
1638 }
1639
1640 void wxUpdateLocaleIsUtf8()
1641 {
1642 #if wxUSE_UTF8_LOCALE_ONLY
1643 if ( !wxIsLocaleUtf8() )
1644 {
1645 wxLogFatalError(_T("This program requires UTF-8 locale to run."));
1646 }
1647 #else // !wxUSE_UTF8_LOCALE_ONLY
1648 wxLocaleIsUtf8 = wxIsLocaleUtf8();
1649 #endif
1650 }
1651
1652 #endif // wxUSE_UNICODE_UTF8
1653
1654 // ============================================================================
1655 // wx wrappers for CRT functions
1656 // ============================================================================
1657
1658 #if wxUSE_UNICODE_WCHAR
1659 #define CALL_ANSI_OR_UNICODE(callA, callW) return callW
1660 #elif wxUSE_UNICODE_UTF8 && !wxUSE_UTF8_LOCALE_ONLY
1661 #define CALL_ANSI_OR_UNICODE(callA, callW) \
1662 return wxLocaleIsUtf8 ? callA : callW
1663 #else // ANSI or UTF8 only
1664 #define CALL_ANSI_OR_UNICODE(callA, callW) return callA
1665 #endif
1666
1667 int wxPuts(const wxString& s)
1668 {
1669 CALL_ANSI_OR_UNICODE(wxCRT_PutsA(s.mb_str()),
1670 wxCRT_PutsW(s.wc_str()));
1671 }
1672
1673 int wxFputs(const wxString& s, FILE *stream)
1674 {
1675 CALL_ANSI_OR_UNICODE(wxCRT_FputsA(s.mb_str(), stream),
1676 wxCRT_FputsW(s.wc_str(), stream));
1677 }
1678
1679 int wxFputc(const wxUniChar& c, FILE *stream)
1680 {
1681 #if !wxUSE_UNICODE // FIXME-UTF8: temporary, remove this with ANSI build
1682 return wxCRT_FputcA((char)c, stream);
1683 #else
1684 CALL_ANSI_OR_UNICODE(wxCRT_FputsA(c.AsUTF8(), stream),
1685 wxCRT_FputcW((wchar_t)c, stream));
1686 #endif
1687 }
1688
1689 void wxPerror(const wxString& s)
1690 {
1691 #ifdef wxCRT_PerrorW
1692 CALL_ANSI_OR_UNICODE(wxCRT_PerrorA(s.mb_str()), wxCRT_PerrorW(s.wc_str()));
1693 #else
1694 wxCRT_PerrorA(s.mb_str());
1695 #endif
1696 }
1697
1698 wchar_t *wxFgets(wchar_t *s, int size, FILE *stream)
1699 {
1700 wxCHECK_MSG( s, NULL, "empty buffer passed to wxFgets()" );
1701
1702 wxCharBuffer buf(size - 1);
1703 // FIXME: this reads too little data if wxConvLibc uses UTF-8 ('size' wide
1704 // characters may be encoded by up to 'size'*4 bytes), but what
1705 // else can we do?
1706 if ( wxFgets(buf.data(), size, stream) == NULL )
1707 return NULL;
1708
1709 if ( wxConvLibc.ToWChar(s, size, buf, wxNO_LEN) == wxCONV_FAILED )
1710 return NULL;
1711
1712 return s;
1713 }
1714
1715 // ----------------------------------------------------------------------------
1716 // wxScanf() and friends
1717 // ----------------------------------------------------------------------------
1718
1719 #ifndef __VISUALC__
1720 int wxVsscanf(const char *str, const char *format, va_list ap)
1721 { return wxCRT_VsscanfA(str, format, ap); }
1722 int wxVsscanf(const wchar_t *str, const wchar_t *format, va_list ap)
1723 { return wxCRT_VsscanfW(str, format, ap); }
1724 int wxVsscanf(const wxCharBuffer& str, const char *format, va_list ap)
1725 { return wxCRT_VsscanfA(str, format, ap); }
1726 int wxVsscanf(const wxWCharBuffer& str, const wchar_t *format, va_list ap)
1727 { return wxCRT_VsscanfW(str, format, ap); }
1728 int wxVsscanf(const wxString& str, const char *format, va_list ap)
1729 { return wxCRT_VsscanfA(str.mb_str(), format, ap); }
1730 int wxVsscanf(const wxString& str, const wchar_t *format, va_list ap)
1731 { return wxCRT_VsscanfW(str.wc_str(), format, ap); }
1732 int wxVsscanf(const wxCStrData& str, const char *format, va_list ap)
1733 { return wxCRT_VsscanfA(str.AsCharBuf(), format, ap); }
1734 int wxVsscanf(const wxCStrData& str, const wchar_t *format, va_list ap)
1735 { return wxCRT_VsscanfW(str.AsWCharBuf(), format, ap); }
1736 #endif // !__VISUALC__