Committing in .
[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/crt.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/crt.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 wchar_t *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 wchar_t *() 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 wchar_t CopyFmtChar(wchar_t 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(wchar_t 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(wchar_t ch)
391 {
392 return ch == _T('-') || ch == _T('+') ||
393 ch == _T('0') || ch == _T(' ') || ch == _T('#');
394 }
395
396 void SkipDigits(const wchar_t **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 wchar_t *m_fmtOrig;
407
408 // the number of characters already copied
409 size_t m_nCopied;
410 };
411
412 wxFormatConverter::wxFormatConverter(const wchar_t *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 wchar_t *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 >= (int)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 #ifdef __VMS
604 #if (__DECCXX_VER >= 70100000) && !defined(__STD_CFRONT) && !defined( __NONAMESPACE_STD )
605 int ret = std::vwscanf(wxFormatConverter(format), argptr);
606 #else
607 int ret = vwscanf(wxFormatConverter(format), argptr);
608 #endif
609 #else
610 int ret = vwscanf(wxFormatConverter(format), argptr);
611 #endif
612
613 va_end(argptr);
614
615 return ret;
616 }
617 #endif
618
619 #ifndef wxCRT_SscanfW
620 int wxCRT_SscanfW(const wchar_t *str, const wchar_t *format, ...)
621 {
622 va_list argptr;
623 va_start(argptr, format);
624
625 #ifdef __VMS
626 #if (__DECCXX_VER >= 70100000) && !defined(__STD_CFRONT) && !defined( __NONAMESPACE_STD )
627 int ret = std::vswscanf(str, wxFormatConverter(format), argptr);
628 #else
629 int ret = vswscanf(str, wxFormatConverter(format), argptr);
630 #endif
631 #else
632 int ret = vswscanf(str, wxFormatConverter(format), argptr);
633 #endif
634
635 va_end(argptr);
636
637 return ret;
638 }
639 #endif
640
641 #ifndef wxCRT_FscanfW
642 int wxCRT_FscanfW(FILE *stream, const wchar_t *format, ...)
643 {
644 va_list argptr;
645 va_start(argptr, format);
646 #ifdef __VMS
647 #if (__DECCXX_VER >= 70100000) && !defined(__STD_CFRONT) && !defined( __NONAMESPACE_STD )
648 int ret = std::vfwscanf(stream, wxFormatConverter(format), argptr);
649 #else
650 int ret = vfwscanf(stream, wxFormatConverter(format), argptr);
651 #endif
652 #else
653 int ret = vfwscanf(stream, wxFormatConverter(format), argptr);
654 #endif
655
656 va_end(argptr);
657
658 return ret;
659 }
660 #endif
661
662 #ifndef wxCRT_VsscanfW
663 int wxCRT_VsscanfW(const wchar_t *str, const wchar_t *format, va_list argptr)
664 {
665 #ifdef __VMS
666 #if (__DECCXX_VER >= 70100000) && !defined(__STD_CFRONT) && !defined( __NONAMESPACE_STD )
667 return std::vswscanf(str, wxFormatConverter(format), argptr);
668 #else
669 return vswscanf(str, wxFormatConverter(format), argptr);
670 #endif
671 #else
672 return vswscanf(str, wxFormatConverter(format), argptr);
673 #endif
674 }
675 #endif
676
677
678 // ----------------------------------------------------------------------------
679 // wrappers to printf and scanf function families
680 // ----------------------------------------------------------------------------
681
682 #if !wxUSE_UTF8_LOCALE_ONLY
683 int wxDoSprintfWchar(char *str, const wxChar *format, ...)
684 {
685 va_list argptr;
686 va_start(argptr, format);
687
688 int rv = wxVsprintf(str, format, argptr);
689
690 va_end(argptr);
691 return rv;
692 }
693 #endif // !wxUSE_UTF8_LOCALE_ONLY
694
695 #if wxUSE_UNICODE_UTF8
696 int wxDoSprintfUtf8(char *str, const char *format, ...)
697 {
698 va_list argptr;
699 va_start(argptr, format);
700
701 int rv = wxVsprintf(str, format, argptr);
702
703 va_end(argptr);
704 return rv;
705 }
706 #endif // wxUSE_UNICODE_UTF8
707
708 #if wxUSE_UNICODE
709
710 #if !wxUSE_UTF8_LOCALE_ONLY
711 int wxDoSprintfWchar(wchar_t *str, const wxChar *format, ...)
712 {
713 va_list argptr;
714 va_start(argptr, format);
715
716 int rv = wxVsprintf(str, format, argptr);
717
718 va_end(argptr);
719 return rv;
720 }
721 #endif // !wxUSE_UTF8_LOCALE_ONLY
722
723 #if wxUSE_UNICODE_UTF8
724 int wxDoSprintfUtf8(wchar_t *str, const char *format, ...)
725 {
726 va_list argptr;
727 va_start(argptr, format);
728
729 int rv = wxVsprintf(str, format, argptr);
730
731 va_end(argptr);
732 return rv;
733 }
734 #endif // wxUSE_UNICODE_UTF8
735
736 #endif // wxUSE_UNICODE
737
738 #if !wxUSE_UTF8_LOCALE_ONLY
739 int wxDoSnprintfWchar(char *str, size_t size, const wxChar *format, ...)
740 {
741 va_list argptr;
742 va_start(argptr, format);
743
744 int rv = wxVsnprintf(str, size, format, argptr);
745
746 va_end(argptr);
747 return rv;
748 }
749 #endif // !wxUSE_UTF8_LOCALE_ONLY
750
751 #if wxUSE_UNICODE_UTF8
752 int wxDoSnprintfUtf8(char *str, size_t size, const char *format, ...)
753 {
754 va_list argptr;
755 va_start(argptr, format);
756
757 int rv = wxVsnprintf(str, size, format, argptr);
758
759 va_end(argptr);
760 return rv;
761 }
762 #endif // wxUSE_UNICODE_UTF8
763
764 #if wxUSE_UNICODE
765
766 #if !wxUSE_UTF8_LOCALE_ONLY
767 int wxDoSnprintfWchar(wchar_t *str, size_t size, const wxChar *format, ...)
768 {
769 va_list argptr;
770 va_start(argptr, format);
771
772 int rv = wxVsnprintf(str, size, format, argptr);
773
774 va_end(argptr);
775 return rv;
776 }
777 #endif // !wxUSE_UTF8_LOCALE_ONLY
778
779 #if wxUSE_UNICODE_UTF8
780 int wxDoSnprintfUtf8(wchar_t *str, size_t size, const char *format, ...)
781 {
782 va_list argptr;
783 va_start(argptr, format);
784
785 int rv = wxVsnprintf(str, size, format, argptr);
786
787 va_end(argptr);
788 return rv;
789 }
790 #endif // wxUSE_UNICODE_UTF8
791
792 #endif // wxUSE_UNICODE
793
794
795 #ifdef HAVE_BROKEN_VSNPRINTF_DECL
796 #define vsnprintf wx_fixed_vsnprintf
797 #endif
798
799 #if wxUSE_UNICODE
800
801 #if !wxUSE_UTF8_LOCALE_ONLY
802 static int ConvertStringToBuf(const wxString& s, char *out, size_t outsize)
803 {
804 const wxWX2WCbuf buf = s.wc_str();
805
806 size_t len = wxConvLibc.FromWChar(out, outsize, buf);
807 if ( len != wxCONV_FAILED )
808 return len-1;
809 else
810 return wxConvLibc.FromWChar(NULL, 0, buf);
811 }
812 #endif // !wxUSE_UTF8_LOCALE_ONLY
813
814 #if wxUSE_UNICODE_UTF8
815 static int ConvertStringToBuf(const wxString& s, wchar_t *out, size_t outsize)
816 {
817 const wxWX2WCbuf buf(s.wc_str());
818 size_t len = wxWcslen(buf);
819 if ( outsize > len )
820 memcpy(out, buf, (len+1) * sizeof(wchar_t));
821 // else: not enough space
822 return len;
823 }
824 #endif // wxUSE_UNICODE_UTF8
825
826 template<typename T>
827 static size_t PrintfViaString(T *out, size_t outsize,
828 const wxString& format, va_list argptr)
829 {
830 wxString s;
831 s.PrintfV(format, argptr);
832
833 return ConvertStringToBuf(s, out, outsize);
834 }
835 #endif // wxUSE_UNICODE
836
837 int wxVsprintf(char *str, const wxString& format, va_list argptr)
838 {
839 #if wxUSE_UTF8_LOCALE_ONLY
840 return vsprintf(str, format.wx_str(), argptr);
841 #else
842 #if wxUSE_UNICODE_UTF8
843 if ( wxLocaleIsUtf8 )
844 return vsprintf(str, format.wx_str(), argptr);
845 else
846 #endif
847 #if wxUSE_UNICODE
848 return PrintfViaString(str, wxNO_LEN, format, argptr);
849 #else
850 return wxCRT_VsprintfA(str, format.mb_str(), argptr);
851 #endif
852 #endif
853 }
854
855 #if wxUSE_UNICODE
856 int wxVsprintf(wchar_t *str, const wxString& format, va_list argptr)
857 {
858 #if wxUSE_UNICODE_WCHAR
859 return wxCRT_VsprintfW(str, format.wc_str(), argptr);
860 #else // wxUSE_UNICODE_UTF8
861 #if !wxUSE_UTF8_LOCALE_ONLY
862 if ( !wxLocaleIsUtf8 )
863 return wxCRT_VsprintfW(str, format.wc_str(), argptr);
864 else
865 #endif
866 return PrintfViaString(str, wxNO_LEN, format, argptr);
867 #endif // wxUSE_UNICODE_UTF8
868 }
869 #endif // wxUSE_UNICODE
870
871 int wxVsnprintf(char *str, size_t size, const wxString& format, va_list argptr)
872 {
873 int rv;
874 #if wxUSE_UTF8_LOCALE_ONLY
875 rv = wxCRT_VsnprintfA(str, size, format.wx_str(), argptr);
876 #else
877 #if wxUSE_UNICODE_UTF8
878 if ( wxLocaleIsUtf8 )
879 rv = wxCRT_VsnprintfA(str, size, format.wx_str(), argptr);
880 else
881 #endif
882 #if wxUSE_UNICODE
883 {
884 // NB: if this code is called, then wxString::PrintV() would use the
885 // wchar_t* version of wxVsnprintf(), so it's safe to use PrintV()
886 // from here
887 rv = PrintfViaString(str, size, format, argptr);
888 }
889 #else
890 rv = wxCRT_VsnprintfA(str, size, format.mb_str(), argptr);
891 #endif
892 #endif
893
894 // VsnprintfTestCase reveals that glibc's implementation of vswprintf
895 // doesn't nul terminate on truncation.
896 str[size - 1] = 0;
897
898 return rv;
899 }
900
901 #if wxUSE_UNICODE
902 int wxVsnprintf(wchar_t *str, size_t size, const wxString& format, va_list argptr)
903 {
904 int rv;
905
906 #if wxUSE_UNICODE_WCHAR
907 rv = wxCRT_VsnprintfW(str, size, format.wc_str(), argptr);
908 #else // wxUSE_UNICODE_UTF8
909 #if !wxUSE_UTF8_LOCALE_ONLY
910 if ( !wxLocaleIsUtf8 )
911 rv = wxCRT_VsnprintfW(str, size, format.wc_str(), argptr);
912 else
913 #endif
914 {
915 // NB: if this code is called, then wxString::PrintV() would use the
916 // char* version of wxVsnprintf(), so it's safe to use PrintV()
917 // from here
918 rv = PrintfViaString(str, size, format, argptr);
919 }
920 #endif // wxUSE_UNICODE_UTF8
921
922 // VsnprintfTestCase reveals that glibc's implementation of vswprintf
923 // doesn't nul terminate on truncation.
924 str[size - 1] = 0;
925
926 return rv;
927 }
928 #endif // wxUSE_UNICODE
929
930 #if wxUSE_WCHAR_T
931
932 // ----------------------------------------------------------------------------
933 // ctype.h stuff (currently unused)
934 // ----------------------------------------------------------------------------
935
936 #if defined(__WIN32__) && defined(wxNEED_WX_CTYPE_H)
937 static inline WORD wxMSW_ctype(wchar_t ch)
938 {
939 WORD ret;
940 GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, &ch, 1, &ret);
941 return ret;
942 }
943
944 int wxCRT_IsalnumW(wchar_t ch) { return IsCharAlphaNumeric(ch); }
945 int wxCRT_IsalphaW(wchar_t ch) { return IsCharAlpha(ch); }
946 int wxCRT_IscntrlW(wchar_t ch) { return wxMSW_ctype(ch) & C1_CNTRL; }
947 int wxCRT_IsdigitW(wchar_t ch) { return wxMSW_ctype(ch) & C1_DIGIT; }
948 int wxCRT_IsgraphW(wchar_t ch) { return wxMSW_ctype(ch) & (C1_DIGIT|C1_PUNCT|C1_ALPHA); }
949 int wxCRT_IslowerW(wchar_t ch) { return IsCharLower(ch); }
950 int wxCRT_IsprintW(wchar_t ch) { return wxMSW_ctype(ch) & (C1_DIGIT|C1_SPACE|C1_PUNCT|C1_ALPHA); }
951 int wxCRT_IspunctW(wchar_t ch) { return wxMSW_ctype(ch) & C1_PUNCT; }
952 int wxCRT_IsspaceW(wchar_t ch) { return wxMSW_ctype(ch) & C1_SPACE; }
953 int wxCRT_IsupperW(wchar_t ch) { return IsCharUpper(ch); }
954 int wxCRT_IsxdigitW(wchar_t ch) { return wxMSW_ctype(ch) & C1_XDIGIT; }
955 int wxCRT_Tolower(wchar_t ch) { return (wchar_t)CharLower((LPTSTR)(ch)); }
956 int wxCRT_Toupper(wchar_t ch) { return (wchar_t)CharUpper((LPTSTR)(ch)); }
957 #endif
958
959 #ifdef wxNEED_WX_MBSTOWCS
960
961 WXDLLEXPORT size_t wxMbstowcs (wchar_t * out, const char * in, size_t outlen)
962 {
963 if (!out)
964 {
965 size_t outsize = 0;
966 while(*in++)
967 outsize++;
968 return outsize;
969 }
970
971 const char* origin = in;
972
973 while (outlen-- && *in)
974 {
975 *out++ = (wchar_t) *in++;
976 }
977
978 *out = '\0';
979
980 return in - origin;
981 }
982
983 WXDLLEXPORT size_t wxWcstombs (char * out, const wchar_t * in, size_t outlen)
984 {
985 if (!out)
986 {
987 size_t outsize = 0;
988 while(*in++)
989 outsize++;
990 return outsize;
991 }
992
993 const wchar_t* origin = in;
994
995 while (outlen-- && *in)
996 {
997 *out++ = (char) *in++;
998 }
999
1000 *out = '\0';
1001
1002 return in - origin;
1003 }
1004
1005 #endif // wxNEED_WX_MBSTOWCS
1006
1007 #if defined(wxNEED_WX_CTYPE_H)
1008
1009 #include <CoreFoundation/CoreFoundation.h>
1010
1011 #define cfalnumset CFCharacterSetGetPredefined(kCFCharacterSetAlphaNumeric)
1012 #define cfalphaset CFCharacterSetGetPredefined(kCFCharacterSetLetter)
1013 #define cfcntrlset CFCharacterSetGetPredefined(kCFCharacterSetControl)
1014 #define cfdigitset CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit)
1015 //CFCharacterSetRef cfgraphset = kCFCharacterSetControl && !' '
1016 #define cflowerset CFCharacterSetGetPredefined(kCFCharacterSetLowercaseLetter)
1017 //CFCharacterSetRef cfprintset = !kCFCharacterSetControl
1018 #define cfpunctset CFCharacterSetGetPredefined(kCFCharacterSetPunctuation)
1019 #define cfspaceset CFCharacterSetGetPredefined(kCFCharacterSetWhitespaceAndNewline)
1020 #define cfupperset CFCharacterSetGetPredefined(kCFCharacterSetUppercaseLetter)
1021
1022 int wxCRT_IsalnumW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cfalnumset, ch); }
1023 int wxCRT_IsalphaW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cfalphaset, ch); }
1024 int wxCRT_IscntrlW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cfcntrlset, ch); }
1025 int wxCRT_IsdigitW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cfdigitset, ch); }
1026 int wxCRT_IsgraphW(wchar_t ch) { return !CFCharacterSetIsCharacterMember(cfcntrlset, ch) && ch != ' '; }
1027 int wxCRT_IslowerW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cflowerset, ch); }
1028 int wxCRT_IsprintW(wchar_t ch) { return !CFCharacterSetIsCharacterMember(cfcntrlset, ch); }
1029 int wxCRT_IspunctW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cfpunctset, ch); }
1030 int wxCRT_IsspaceW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cfspaceset, ch); }
1031 int wxCRT_IsupperW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cfupperset, ch); }
1032 int wxCRT_IsxdigitW(wchar_t ch) { return wxCRT_IsdigitW(ch) || (ch>='a' && ch<='f') || (ch>='A' && ch<='F'); }
1033
1034 // FIXME: these are broken!
1035 extern "C" int wxCRT_TolowerW(wchar_t ch) { return (wchar_t)tolower((char)(ch)); }
1036 extern "C" int wxCRT_ToupperW(wchar_t ch) { return (wchar_t)toupper((char)(ch)); }
1037
1038 #endif // wxNEED_WX_CTYPE_H
1039
1040 #ifndef wxCRT_StrdupA
1041 WXDLLEXPORT char *wxCRT_StrdupA(const char *s)
1042 {
1043 return strcpy((char *)malloc(strlen(s) + 1), s);
1044 }
1045 #endif // wxCRT_StrdupA
1046
1047 #ifndef wxCRT_StrdupW
1048 WXDLLEXPORT wchar_t * wxCRT_StrdupW(const wchar_t *pwz)
1049 {
1050 size_t size = (wxWcslen(pwz) + 1) * sizeof(wchar_t);
1051 wchar_t *ret = (wchar_t *) malloc(size);
1052 memcpy(ret, pwz, size);
1053 return ret;
1054 }
1055 #endif // wxCRT_StrdupW
1056
1057 #ifndef wxCRT_StricmpA
1058 int WXDLLEXPORT wxCRT_StricmpA(const char *psz1, const char *psz2)
1059 {
1060 register char c1, c2;
1061 do {
1062 c1 = wxTolower(*psz1++);
1063 c2 = wxTolower(*psz2++);
1064 } while ( c1 && (c1 == c2) );
1065 return c1 - c2;
1066 }
1067 #endif // !defined(wxCRT_StricmpA)
1068
1069 #ifndef wxCRT_StricmpW
1070 int WXDLLEXPORT wxCRT_StricmpW(const wchar_t *psz1, const wchar_t *psz2)
1071 {
1072 register wchar_t c1, c2;
1073 do {
1074 c1 = wxTolower(*psz1++);
1075 c2 = wxTolower(*psz2++);
1076 } while ( c1 && (c1 == c2) );
1077 return c1 - c2;
1078 }
1079 #endif // !defined(wxCRT_StricmpW)
1080
1081 #ifndef wxCRT_StrnicmpA
1082 int WXDLLEXPORT wxCRT_StrnicmpA(const char *s1, const char *s2, size_t n)
1083 {
1084 // initialize the variables just to suppress stupid gcc warning
1085 register char c1 = 0, c2 = 0;
1086 while (n && ((c1 = wxTolower(*s1)) == (c2 = wxTolower(*s2)) ) && c1) n--, s1++, s2++;
1087 if (n) {
1088 if (c1 < c2) return -1;
1089 if (c1 > c2) return 1;
1090 }
1091 return 0;
1092 }
1093 #endif // !defined(wxCRT_StrnicmpA)
1094
1095 #ifndef wxCRT_StrnicmpW
1096 int WXDLLEXPORT wxCRT_StrnicmpW(const wchar_t *s1, const wchar_t *s2, size_t n)
1097 {
1098 // initialize the variables just to suppress stupid gcc warning
1099 register wchar_t c1 = 0, c2 = 0;
1100 while (n && ((c1 = wxTolower(*s1)) == (c2 = wxTolower(*s2)) ) && c1) n--, s1++, s2++;
1101 if (n) {
1102 if (c1 < c2) return -1;
1103 if (c1 > c2) return 1;
1104 }
1105 return 0;
1106 }
1107 #endif // !defined(wxCRT_StrnicmpW)
1108
1109 // ----------------------------------------------------------------------------
1110 // string.h functions
1111 // ----------------------------------------------------------------------------
1112
1113 #ifndef wxCRT_StrcatW
1114 WXDLLEXPORT wchar_t *wxCRT_StrcatW(wchar_t *dest, const wchar_t *src)
1115 {
1116 wchar_t *ret = dest;
1117 while (*dest) dest++;
1118 while ((*dest++ = *src++));
1119 return ret;
1120 }
1121 #endif
1122
1123 #ifndef wxCRT_StrchrW
1124 WXDLLEXPORT const wchar_t *wxCRT_StrchrW(const wchar_t *s, wchar_t c)
1125 {
1126 // be careful here as the terminating NUL makes part of the string
1127 while ( *s != c )
1128 {
1129 if ( !*s++ )
1130 return NULL;
1131 }
1132
1133 return s;
1134 }
1135 #endif
1136
1137 #ifndef wxCRT_StrcmpW
1138 WXDLLEXPORT int wxCRT_StrcmpW(const wchar_t *s1, const wchar_t *s2)
1139 {
1140 while ((*s1 == *s2) && *s1) s1++, s2++;
1141 if ((wxUChar)*s1 < (wxUChar)*s2) return -1;
1142 if ((wxUChar)*s1 > (wxUChar)*s2) return 1;
1143 return 0;
1144 }
1145 #endif
1146
1147 #ifndef wxCRT_StrcpyW
1148 WXDLLEXPORT wchar_t * wxCRT_StrcpyW(wchar_t *dest, const wchar_t *src)
1149 {
1150 wchar_t *ret = dest;
1151 while ((*dest++ = *src++));
1152 return ret;
1153 }
1154 #endif
1155
1156 template<typename T>
1157 static inline size_t wxCRT_DoStrlen(const T *s)
1158 {
1159 size_t n = 0;
1160 while ( *s++ )
1161 n++;
1162
1163 return n;
1164 }
1165
1166 // these two (and wxCRT_StrncmpW below) are extern "C" because they are needed
1167 // by regex code, the rest isn't needed, so it's not declared as extern "C"
1168 #ifndef wxCRT_StrlenA
1169 WXDLLEXPORT size_t wxCRT_StrlenA(const char *s)
1170 { return wxCRT_DoStrlen(s); }
1171 #endif
1172 #ifndef wxCRT_StrlenW
1173 extern "C" WXDLLEXPORT size_t wxCRT_StrlenW(const wchar_t *s)
1174 { return wxCRT_DoStrlen(s); }
1175 #endif
1176
1177 #ifndef wxCRT_StrncatW
1178 WXDLLEXPORT wchar_t * wxCRT_StrncatW(wchar_t *dest, const wchar_t *src, size_t n)
1179 {
1180 wchar_t *ret = dest;
1181 while (*dest) dest++;
1182 while (n && (*dest++ = *src++)) n--;
1183 return ret;
1184 }
1185 #endif
1186
1187 #ifndef wxCRT_StrncmpW
1188 extern "C"
1189 WXDLLEXPORT int wxCRT_StrncmpW(const wchar_t *s1, const wchar_t *s2, size_t n)
1190 {
1191 while (n && (*s1 == *s2) && *s1) n--, s1++, s2++;
1192 if (n) {
1193 if ((wxUChar)*s1 < (wxUChar)*s2) return -1;
1194 if ((wxUChar)*s1 > (wxUChar)*s2) return 1;
1195 }
1196 return 0;
1197 }
1198 #endif
1199
1200 #ifndef wxCRT_StrncpyW
1201 WXDLLEXPORT wchar_t * wxCRT_StrncpyW(wchar_t *dest, const wchar_t *src, size_t n)
1202 {
1203 wchar_t *ret = dest;
1204 while (n && (*dest++ = *src++)) n--;
1205 while (n) *dest++=0, n--; // the docs specify padding with zeroes
1206 return ret;
1207 }
1208 #endif
1209
1210 #ifndef wxCRT_StrpbrkW
1211 WXDLLEXPORT const wchar_t * wxCRT_StrpbrkW(const wchar_t *s, const wchar_t *accept)
1212 {
1213 while (*s && !wxCRT_Strchr(accept, *s))
1214 s++;
1215
1216 return *s ? s : NULL;
1217 }
1218 #endif
1219
1220 #ifndef wxCRT_StrrchrW
1221 WXDLLEXPORT const wchar_t * wxCRT_StrrchrW(const wchar_t *s, wchar_t c)
1222 {
1223 const wchar_t *ret = NULL;
1224 do
1225 {
1226 if ( *s == c )
1227 ret = s;
1228 s++;
1229 }
1230 while ( *s );
1231
1232 return ret;
1233 }
1234 #endif
1235
1236 #ifndef wxCRT_StrspnW
1237 WXDLLEXPORT size_t wxCRT_StrspnW(const wchar_t *s, const wchar_t *accept)
1238 {
1239 size_t len = 0;
1240 while (wxCRT_Strchr(accept, *s++)) len++;
1241 return len;
1242 }
1243 #endif
1244
1245 #ifndef wxCRT_StrstrW
1246 WXDLLEXPORT const wchar_t *wxCRT_StrstrW(const wchar_t *haystack, const wchar_t *needle)
1247 {
1248 wxASSERT_MSG( needle != NULL, _T("NULL argument in wxCRT_Strstr") );
1249
1250 // VZ: this is not exactly the most efficient string search algorithm...
1251
1252 const size_t len = wxStrlen(needle);
1253
1254 while ( const wchar_t *fnd = wxCRT_Strchr(haystack, *needle) )
1255 {
1256 if ( !wxCRT_Strncmp(fnd, needle, len) )
1257 return fnd;
1258
1259 haystack = fnd + 1;
1260 }
1261
1262 return NULL;
1263 }
1264 #endif
1265
1266 #ifndef wxCRT_StrtodW
1267 WXDLLEXPORT double wxCRT_StrtodW(const wchar_t *nptr, wchar_t **endptr)
1268 {
1269 const wchar_t *start = nptr;
1270
1271 // FIXME: only correct for C locale
1272 while (wxIsspace(*nptr)) nptr++;
1273 if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++;
1274 while (wxIsdigit(*nptr)) nptr++;
1275 if (*nptr == wxT('.')) {
1276 nptr++;
1277 while (wxIsdigit(*nptr)) nptr++;
1278 }
1279 if (*nptr == wxT('E') || *nptr == wxT('e')) {
1280 nptr++;
1281 if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++;
1282 while (wxIsdigit(*nptr)) nptr++;
1283 }
1284
1285 wxString data(nptr, nptr-start);
1286 wxWX2MBbuf dat = data.mb_str(wxConvLibc);
1287 char *rdat = wxMBSTRINGCAST dat;
1288 double ret = strtod(dat, &rdat);
1289
1290 if (endptr) *endptr = (wchar_t *)(start + (rdat - (const char *)dat));
1291
1292 return ret;
1293 }
1294 #endif // !wxCRT_StrtodW
1295
1296 #ifndef wxCRT_StrtolW
1297 WXDLLEXPORT long int wxCRT_StrtolW(const wchar_t *nptr, wchar_t **endptr, int base)
1298 {
1299 const wchar_t *start = nptr;
1300
1301 // FIXME: only correct for C locale
1302 while (wxIsspace(*nptr)) nptr++;
1303 if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++;
1304 if (((base == 0) || (base == 16)) &&
1305 (nptr[0] == wxT('0') && nptr[1] == wxT('x'))) {
1306 nptr += 2;
1307 base = 16;
1308 }
1309 else if ((base == 0) && (nptr[0] == wxT('0'))) base = 8;
1310 else if (base == 0) base = 10;
1311
1312 while ((wxIsdigit(*nptr) && (*nptr - wxT('0') < base)) ||
1313 (wxIsalpha(*nptr) && (wxToupper(*nptr) - wxT('A') + 10 < base))) nptr++;
1314
1315 wxString data(start, nptr-start);
1316 wxWX2MBbuf dat = data.mb_str(wxConvLibc);
1317 char *rdat = wxMBSTRINGCAST dat;
1318 long int ret = strtol(dat, &rdat, base);
1319
1320 if (endptr) *endptr = (wchar_t *)(start + (rdat - (const char *)dat));
1321
1322 return ret;
1323 }
1324 #endif // !wxCRT_StrtolW
1325
1326 #ifndef wxCRT_StrtoulW
1327 WXDLLEXPORT unsigned long int wxCRT_StrtoulW(const wchar_t *nptr, wchar_t **endptr, int base)
1328 {
1329 return (unsigned long int) wxCRT_StrtolW(nptr, endptr, base);
1330 }
1331 #endif
1332
1333
1334
1335 #ifndef wxCRT_GetenvW
1336 wchar_t* WXDLLEXPORT wxCRT_GetenvW(const wchar_t *name)
1337 {
1338 // NB: buffer returned by getenv() is allowed to be overwritten next
1339 // time getenv() is called, so it is OK to use static string
1340 // buffer to hold the data.
1341 static wxWCharBuffer value((wchar_t*)NULL);
1342 value = wxConvLibc.cMB2WC(getenv(wxConvLibc.cWC2MB(name)));
1343 return value.data();
1344 }
1345 #endif // !wxCRT_GetenvW
1346
1347 #ifndef wxCRT_StrftimeW
1348 WXDLLEXPORT size_t
1349 wxCRT_StrftimeW(wchar_t *s, size_t maxsize, const wchar_t *fmt, const struct tm *tm)
1350 {
1351 if ( !maxsize )
1352 return 0;
1353
1354 wxCharBuffer buf(maxsize);
1355
1356 wxCharBuffer bufFmt(wxConvLibc.cWX2MB(fmt));
1357 if ( !bufFmt )
1358 return 0;
1359
1360 size_t ret = strftime(buf.data(), maxsize, bufFmt, tm);
1361 if ( !ret )
1362 return 0;
1363
1364 wxWCharBuffer wbuf = wxConvLibc.cMB2WX(buf);
1365 if ( !wbuf )
1366 return 0;
1367
1368 wxCRT_StrncpyW(s, wbuf, maxsize);
1369 return wxCRT_StrlenW(s);
1370 }
1371 #endif // !wxCRT_StrftimeW
1372
1373 #endif // wxUSE_WCHAR_T
1374
1375 template<typename T>
1376 static wxULongLong_t
1377 wxCRT_StrtoullBase(const T* nptr, T** endptr, int base, T* sign)
1378 {
1379 wxULongLong_t sum = 0;
1380 wxString wxstr(nptr);
1381 wxString::const_iterator i = wxstr.begin();
1382 wxString::const_iterator end = wxstr.end();
1383
1384 // Skip spaces
1385 while ( i != end && wxIsspace(*i) ) i++;
1386
1387 // Starts with sign?
1388 *sign = wxT(' ');
1389 if ( i != end )
1390 {
1391 T c = *i;
1392 if ( c == wxT('+') || c == wxT('-') )
1393 {
1394 *sign = c;
1395 i++;
1396 }
1397 }
1398
1399 // Starts with 0x?
1400 if ( i != end && *i == wxT('0') )
1401 {
1402 i++;
1403 if ( i != end )
1404 {
1405 if ( *i == wxT('x') && (base == 16 || base == 0) )
1406 {
1407 base = 16;
1408 i++;
1409 }
1410 else
1411 {
1412 if ( endptr )
1413 *endptr = (T*) nptr;
1414 wxSET_ERRNO(EINVAL);
1415 return sum;
1416 }
1417 }
1418 else
1419 i--;
1420 }
1421
1422 if ( base == 0 )
1423 base = 10;
1424
1425 for ( ; i != end; i++ )
1426 {
1427 unsigned int n;
1428
1429 T c = *i;
1430 if ( c >= wxT('0') )
1431 {
1432 if ( c <= wxT('9') )
1433 n = c - wxT('0');
1434 else
1435 n = wxTolower(c) - wxT('a') + 10;
1436 }
1437 else
1438 break;
1439
1440 if ( n >= (unsigned int)base )
1441 // Invalid character (for this base)
1442 break;
1443
1444 wxULongLong_t prevsum = sum;
1445 sum = (sum * base) + n;
1446
1447 if ( sum < prevsum )
1448 {
1449 wxSET_ERRNO(ERANGE);
1450 break;
1451 }
1452 }
1453
1454 if ( endptr )
1455 {
1456 *endptr = (T*)(nptr + (i - wxstr.begin()));
1457 }
1458
1459 return sum;
1460 }
1461
1462 template<typename T>
1463 static wxULongLong_t wxCRT_DoStrtoull(const T* nptr, T** endptr, int base)
1464 {
1465 T sign;
1466 wxULongLong_t uval = wxCRT_StrtoullBase(nptr, endptr, base, &sign);
1467
1468 if ( sign == wxT('-') )
1469 {
1470 wxSET_ERRNO(ERANGE);
1471 uval = 0;
1472 }
1473
1474 return uval;
1475 }
1476
1477 template<typename T>
1478 static wxLongLong_t wxCRT_DoStrtoll(const T* nptr, T** endptr, int base)
1479 {
1480 T sign;
1481 wxULongLong_t uval = wxCRT_StrtoullBase(nptr, endptr, base, &sign);
1482 wxLongLong_t val = 0;
1483
1484 if ( sign == wxT('-') )
1485 {
1486 if ( uval <= wxULL(wxINT64_MAX+1) )
1487 {
1488 if ( uval == wxULL(wxINT64_MAX+1))
1489 val = -((wxLongLong_t)wxINT64_MAX) - 1;
1490 else
1491 val = -((wxLongLong_t)uval);
1492 }
1493 else
1494 {
1495 wxSET_ERRNO(ERANGE);
1496 }
1497 }
1498 else if ( uval <= wxINT64_MAX )
1499 {
1500 val = uval;
1501 }
1502 else
1503 {
1504 wxSET_ERRNO(ERANGE);
1505 }
1506
1507 return val;
1508 }
1509
1510 #ifndef wxCRT_StrtollA
1511 wxLongLong_t wxCRT_StrtollA(const char* nptr, char** endptr, int base)
1512 { return wxCRT_DoStrtoll(nptr, endptr, base); }
1513 #endif
1514 #ifndef wxCRT_StrtollW
1515 wxLongLong_t wxCRT_StrtollW(const wchar_t* nptr, wchar_t** endptr, int base)
1516 { return wxCRT_DoStrtoll(nptr, endptr, base); }
1517 #endif
1518
1519 #ifndef wxCRT_StrtoullA
1520 wxULongLong_t wxCRT_StrtoullA(const char* nptr, char** endptr, int base)
1521 { return wxCRT_DoStrtoull(nptr, endptr, base); }
1522 #endif
1523 #ifndef wxCRT_StrtoullW
1524 wxULongLong_t wxCRT_StrtoullW(const wchar_t* nptr, wchar_t** endptr, int base)
1525 { return wxCRT_DoStrtoull(nptr, endptr, base); }
1526 #endif
1527
1528 // ----------------------------------------------------------------------------
1529 // functions which we may need even if !wxUSE_WCHAR_T
1530 // ----------------------------------------------------------------------------
1531
1532 template<typename T>
1533 static T *wxCRT_DoStrtok(T *psz, const T *delim, T **save_ptr)
1534 {
1535 if (!psz)
1536 {
1537 psz = *save_ptr;
1538 if ( !psz )
1539 return NULL;
1540 }
1541
1542 psz += wxStrspn(psz, delim);
1543 if (!*psz)
1544 {
1545 *save_ptr = (T *)NULL;
1546 return (T *)NULL;
1547 }
1548
1549 T *ret = psz;
1550 psz = wxStrpbrk(psz, delim);
1551 if (!psz)
1552 {
1553 *save_ptr = (T*)NULL;
1554 }
1555 else
1556 {
1557 *psz = wxT('\0');
1558 *save_ptr = psz + 1;
1559 }
1560
1561 return ret;
1562 }
1563
1564 #ifndef wxCRT_StrtokA
1565 char *wxCRT_StrtokA(char *psz, const char *delim, char **save_ptr)
1566 { return wxCRT_DoStrtok(psz, delim, save_ptr); }
1567 #endif
1568 #ifndef wxCRT_StrtokW
1569 wchar_t *wxCRT_StrtokW(wchar_t *psz, const wchar_t *delim, wchar_t **save_ptr)
1570 { return wxCRT_DoStrtok(psz, delim, save_ptr); }
1571 #endif
1572
1573 // ----------------------------------------------------------------------------
1574 // missing C RTL functions
1575 // ----------------------------------------------------------------------------
1576
1577 #ifdef wxNEED_STRDUP
1578
1579 char *strdup(const char *s)
1580 {
1581 char *dest = (char*) malloc( strlen( s ) + 1 ) ;
1582 if ( dest )
1583 strcpy( dest , s ) ;
1584 return dest ;
1585 }
1586 #endif // wxNEED_STRDUP
1587
1588 #if defined(__WXWINCE__) && (_WIN32_WCE <= 211)
1589
1590 void *calloc( size_t num, size_t size )
1591 {
1592 void** ptr = (void **)malloc(num * size);
1593 memset( ptr, 0, num * size);
1594 return ptr;
1595 }
1596
1597 #endif // __WXWINCE__ <= 211
1598
1599 #ifdef __WXWINCE__
1600 int wxCRT_RemoveW(const wchar_t *path)
1601 {
1602 return ::DeleteFile(path) == 0;
1603 }
1604 #endif
1605
1606 #ifndef wxCRT_TmpnamW
1607 wchar_t *wxCRT_TmpnamW(wchar_t *s)
1608 {
1609 // tmpnam_r() returns NULL if s=NULL, do the same
1610 wxCHECK_MSG( s, NULL, "wxTmpnam must be called with a buffer" );
1611
1612 #ifndef L_tmpnam
1613 #define L_tmpnam 1024
1614 #endif
1615 wxCharBuffer buf(L_tmpnam);
1616 tmpnam(buf.data());
1617
1618 wxConvLibc.ToWChar(s, L_tmpnam+1, buf.data());
1619 return s;
1620 }
1621 #endif // !wxCRT_TmpnamW
1622
1623
1624 // ============================================================================
1625 // wxLocaleIsUtf8
1626 // ============================================================================
1627
1628 #if wxUSE_UNICODE_UTF8
1629
1630 #if !wxUSE_UTF8_LOCALE_ONLY
1631 bool wxLocaleIsUtf8 = false; // the safer setting if not known
1632 #endif
1633
1634 static bool wxIsLocaleUtf8()
1635 {
1636 // NB: we intentionally don't use wxLocale::GetSystemEncodingName(),
1637 // because a) it may be unavailable in some builds and b) has slightly
1638 // different semantics (default locale instead of current)
1639
1640 #if defined(HAVE_LANGINFO_H) && defined(CODESET)
1641 // GNU libc provides current character set this way (this conforms to
1642 // Unix98)
1643 const char *charset = nl_langinfo(CODESET);
1644 if ( charset )
1645 {
1646 // "UTF-8" is used by modern glibc versions, but test other variants
1647 // as well, just in case:
1648 if ( strcmp(charset, "UTF-8") == 0 ||
1649 strcmp(charset, "utf-8") == 0 ||
1650 strcmp(charset, "UTF8") == 0 ||
1651 strcmp(charset, "utf8") == 0 )
1652 {
1653 return true;
1654 }
1655 }
1656 #endif
1657
1658 // check if we're running under the "C" locale: it is 7bit subset
1659 // of UTF-8, so it can be safely used with the UTF-8 build:
1660 const char *lc_ctype = setlocale(LC_CTYPE, NULL);
1661 if ( lc_ctype &&
1662 (strcmp(lc_ctype, "C") == 0 || strcmp(lc_ctype, "POSIX") == 0) )
1663 {
1664 return true;
1665 }
1666
1667 // we don't know what charset libc is using, so assume the worst
1668 // to be safe:
1669 return false;
1670 }
1671
1672 void wxUpdateLocaleIsUtf8()
1673 {
1674 #if wxUSE_UTF8_LOCALE_ONLY
1675 if ( !wxIsLocaleUtf8() )
1676 {
1677 wxLogFatalError(_T("This program requires UTF-8 locale to run."));
1678 }
1679 #else // !wxUSE_UTF8_LOCALE_ONLY
1680 wxLocaleIsUtf8 = wxIsLocaleUtf8();
1681 #endif
1682 }
1683
1684 #endif // wxUSE_UNICODE_UTF8
1685
1686 // ============================================================================
1687 // wx wrappers for CRT functions
1688 // ============================================================================
1689
1690 #if wxUSE_UNICODE_WCHAR
1691 #define CALL_ANSI_OR_UNICODE(return_kw, callA, callW) return_kw callW
1692 #elif wxUSE_UNICODE_UTF8 && !wxUSE_UTF8_LOCALE_ONLY
1693 #define CALL_ANSI_OR_UNICODE(return_kw, callA, callW) \
1694 return_kw wxLocaleIsUtf8 ? callA : callW
1695 #else // ANSI or UTF8 only
1696 #define CALL_ANSI_OR_UNICODE(return_kw, callA, callW) return_kw callA
1697 #endif
1698
1699 int wxPuts(const wxString& s)
1700 {
1701 CALL_ANSI_OR_UNICODE(return,
1702 wxCRT_PutsA(s.mb_str()),
1703 wxCRT_PutsW(s.wc_str()));
1704 }
1705
1706 int wxFputs(const wxString& s, FILE *stream)
1707 {
1708 CALL_ANSI_OR_UNICODE(return,
1709 wxCRT_FputsA(s.mb_str(), stream),
1710 wxCRT_FputsW(s.wc_str(), stream));
1711 }
1712
1713 int wxFputc(const wxUniChar& c, FILE *stream)
1714 {
1715 #if !wxUSE_UNICODE // FIXME-UTF8: temporary, remove this with ANSI build
1716 return wxCRT_FputcA((char)c, stream);
1717 #else
1718 CALL_ANSI_OR_UNICODE(return,
1719 wxCRT_FputsA(c.AsUTF8(), stream),
1720 wxCRT_FputcW((wchar_t)c, stream));
1721 #endif
1722 }
1723
1724 void wxPerror(const wxString& s)
1725 {
1726 #ifdef wxCRT_PerrorW
1727 CALL_ANSI_OR_UNICODE(wxEMPTY_PARAMETER_VALUE,
1728 wxCRT_PerrorA(s.mb_str()),
1729 wxCRT_PerrorW(s.wc_str()));
1730 #else
1731 wxCRT_PerrorA(s.mb_str());
1732 #endif
1733 }
1734
1735 wchar_t *wxFgets(wchar_t *s, int size, FILE *stream)
1736 {
1737 wxCHECK_MSG( s, NULL, "empty buffer passed to wxFgets()" );
1738
1739 wxCharBuffer buf(size - 1);
1740 // FIXME: this reads too little data if wxConvLibc uses UTF-8 ('size' wide
1741 // characters may be encoded by up to 'size'*4 bytes), but what
1742 // else can we do?
1743 if ( wxFgets(buf.data(), size, stream) == NULL )
1744 return NULL;
1745
1746 if ( wxConvLibc.ToWChar(s, size, buf, wxNO_LEN) == wxCONV_FAILED )
1747 return NULL;
1748
1749 return s;
1750 }
1751
1752 // ----------------------------------------------------------------------------
1753 // wxScanf() and friends
1754 // ----------------------------------------------------------------------------
1755
1756 #ifndef __VISUALC__
1757 int wxVsscanf(const char *str, const char *format, va_list ap)
1758 { return wxCRT_VsscanfA(str, format, ap); }
1759 int wxVsscanf(const wchar_t *str, const wchar_t *format, va_list ap)
1760 { return wxCRT_VsscanfW(str, format, ap); }
1761 int wxVsscanf(const wxCharBuffer& str, const char *format, va_list ap)
1762 { return wxCRT_VsscanfA(str, format, ap); }
1763 int wxVsscanf(const wxWCharBuffer& str, const wchar_t *format, va_list ap)
1764 { return wxCRT_VsscanfW(str, format, ap); }
1765 int wxVsscanf(const wxString& str, const char *format, va_list ap)
1766 { return wxCRT_VsscanfA(str.mb_str(), format, ap); }
1767 int wxVsscanf(const wxString& str, const wchar_t *format, va_list ap)
1768 { return wxCRT_VsscanfW(str.wc_str(), format, ap); }
1769 int wxVsscanf(const wxCStrData& str, const char *format, va_list ap)
1770 { return wxCRT_VsscanfA(str.AsCharBuf(), format, ap); }
1771 int wxVsscanf(const wxCStrData& str, const wchar_t *format, va_list ap)
1772 { return wxCRT_VsscanfW(str.AsWCharBuf(), format, ap); }
1773 #endif // !__VISUALC__