]> git.saurik.com Git - wxWidgets.git/blame - src/common/wxcrt.cpp
1. made CRT wrappers definitions indepenent of wxUSE_UNICODE: both ANSI and Unicode...
[wxWidgets.git] / src / common / wxcrt.cpp
CommitLineData
dd0ef332
VS
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
52de37c7
VS
53#ifdef __WXWINCE__
54 // there is no errno.h under CE apparently
55 #define wxSET_ERRNO(value)
56#else
57 #include <errno.h>
17482893 58
52de37c7 59 #define wxSET_ERRNO(value) errno = value
17482893
VZ
60#endif
61
dd0ef332
VS
62#if defined(__MWERKS__) && __MSL__ >= 0x6000
63namespace std {}
64using namespace std ;
65#endif
66
67#if wxUSE_WCHAR_T
68size_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
101size_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
129bool 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
52de37c7
VS
150char* 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
dd0ef332
VS
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_
dd0ef332
VS
175
176 #define wxNEED_WPRINTF
177
52de37c7 178 int wxCRT_VfprintfW( FILE *stream, const wchar_t *format, va_list argptr );
dd0ef332
VS
179#endif
180
dd0ef332 181#if defined(__DMC__)
52de37c7
VS
182/* Digital Mars adds count to _stprintf (C99) so convert */
183int wxCRT_SprintfW (wchar_t * __RESTRICT s, const wchar_t * __RESTRICT format, ... )
184{
185 va_list arglist;
dd0ef332 186
52de37c7
VS
187 va_start( arglist, format );
188 int iLen = swprintf ( s, -1, format, arglist );
189 va_end( arglist );
190 return iLen ;
191}
dd0ef332
VS
192#endif //__DMC__
193
194// ----------------------------------------------------------------------------
195// implement the standard IO functions for wide char if libc doesn't have them
196// ----------------------------------------------------------------------------
197
52de37c7
VS
198#ifndef wxCRT_FputsW
199int wxCRT_FputsW(const wchar_t *ws, FILE *stream)
dd0ef332
VS
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
52de37c7 207 return wxCRT_FputsA(buf, stream) == -1 ? -1 : 0;
dd0ef332 208}
52de37c7 209#endif // !wxCRT_FputsW
dd0ef332 210
52de37c7
VS
211#ifndef wxCRT_PutsW
212int wxCRT_PutsW(const wchar_t *ws)
dd0ef332 213{
52de37c7 214 int rc = wxCRT_FputsW(ws, stdout);
dd0ef332
VS
215 if ( rc != -1 )
216 {
52de37c7 217 if ( wxCRT_FputsW(L"\n", stdout) == -1 )
dd0ef332
VS
218 return -1;
219
220 rc++;
221 }
222
223 return rc;
224}
52de37c7 225#endif // !wxCRT_PutsW
dd0ef332 226
52de37c7
VS
227#ifndef wxCRT_FputcW
228int /* not wint_t */ wxCRT_FputcW(wchar_t wc, FILE *stream)
dd0ef332
VS
229{
230 wchar_t ws[2] = { wc, L'\0' };
231
52de37c7 232 return wxCRT_FputsW(ws, stream);
dd0ef332 233}
52de37c7 234#endif // !wxCRT_FputcW
dd0ef332
VS
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
52de37c7 242static int vwscanf(const wchar_t *format, va_list argptr)
dd0ef332
VS
243{
244 wxFAIL_MSG( _T("TODO") );
245
246 return -1;
247}
248
52de37c7 249static int vswscanf(const wchar_t *ws, const wchar_t *format, va_list argptr)
dd0ef332
VS
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
c6255a6e 261 return vsscanf(wxConvLibc.cWX2MB(ws), wxConvLibc.cWX2MB(format), argptr);
dd0ef332
VS
262}
263
52de37c7 264static int vfwscanf(FILE *stream, const wchar_t *format, va_list argptr)
dd0ef332
VS
265{
266 wxFAIL_MSG( _T("TODO") );
267
268 return -1;
269}
270
52de37c7 271#define vswprintf wxCRT_VsnprintfW_
dd0ef332 272
52de37c7 273static int vfwprintf(FILE *stream, const wchar_t *format, va_list argptr)
dd0ef332
VS
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
52de37c7 288static int vwprintf(const wchar_t *format, va_list argptr)
dd0ef332 289{
52de37c7 290 return wxCRT_VfprintfW(stdout, format, argptr);
dd0ef332
VS
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
336class wxFormatConverter
337{
338public:
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
346private:
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
412wxFormatConverter::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
506wxString wxConvertFormat(const wxChar *format)
507{
508 return wxString(wxFormatConverter(format));
509}
510#endif
511
512// ----------------------------------------------------------------------------
513// wxPrintf(), wxScanf() and relatives
514// ----------------------------------------------------------------------------
515
eb6cb207
VS
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
52de37c7
VS
521#ifndef wxCRT_PrintfW
522int wxCRT_PrintfW( const wchar_t *format, ... )
dd0ef332
VS
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}
52de37c7 533#endif
dd0ef332 534
52de37c7
VS
535#ifndef wxCRT_FprintfW
536int wxCRT_FprintfW( FILE *stream, const wchar_t *format, ... )
dd0ef332
VS
537{
538 va_list argptr;
2523e9b7 539 va_start( argptr, format );
dd0ef332 540
2523e9b7 541 int ret = vfwprintf( stream, wxFormatConverter(format), argptr );
dd0ef332
VS
542
543 va_end(argptr);
544
545 return ret;
546}
52de37c7 547#endif
dd0ef332 548
52de37c7
VS
549#ifndef wxCRT_VfprintfW
550int wxCRT_VfprintfW( FILE *stream, const wchar_t *format, va_list argptr )
2523e9b7
VS
551{
552 return vfwprintf( stream, wxFormatConverter(format), argptr );
553}
52de37c7 554#endif
2523e9b7 555
52de37c7
VS
556#ifndef wxCRT_VprintfW
557int wxCRT_VprintfW( const wchar_t *format, va_list argptr )
2523e9b7
VS
558{
559 return vwprintf( wxFormatConverter(format), argptr );
560}
52de37c7 561#endif
2523e9b7 562
52de37c7
VS
563#ifndef wxCRT_VsnprintfW
564int wxCRT_VsnprintfW(wchar_t *str, size_t size, const wchar_t *format, va_list argptr )
2523e9b7
VS
565{
566 return vswprintf( str, size, wxFormatConverter(format), argptr );
567}
52de37c7 568#endif // !wxCRT_VsnprintfW
2523e9b7 569
52de37c7
VS
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
573int 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
590int wxCRT_VsprintfW( wchar_t *str, const wchar_t *format, va_list argptr )
2523e9b7
VS
591{
592 // same as for wxSprintf()
593 return vswprintf(str, INT_MAX / 4, wxFormatConverter(format), argptr);
594}
52de37c7 595#endif
2523e9b7 596
52de37c7 597#ifndef wxCRT_ScanfW
eb6cb207
VS
598int 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}
52de37c7 609#endif
eb6cb207 610
52de37c7 611#ifndef wxCRT_SscanfW
eb6cb207
VS
612int 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}
52de37c7 623#endif
eb6cb207 624
52de37c7 625#ifndef wxCRT_FscanfW
eb6cb207
VS
626int 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}
52de37c7 636#endif
eb6cb207 637
52de37c7 638#ifndef wxCRT_VsscanfW
eb6cb207
VS
639int wxCRT_VsscanfW(const wchar_t *str, const wchar_t *format, va_list argptr)
640{
641 return vswscanf(str, wxFormatConverter(format), argptr);
642}
52de37c7 643#endif
2523e9b7
VS
644
645
646// ----------------------------------------------------------------------------
647// wrappers to printf and scanf function families
648// ----------------------------------------------------------------------------
649
d1f6e2cf
VS
650#if !wxUSE_UTF8_LOCALE_ONLY
651int wxDoSprintfWchar(char *str, const wxChar *format, ...)
dd0ef332
VS
652{
653 va_list argptr;
654 va_start(argptr, format);
655
2523e9b7 656 int rv = wxVsprintf(str, format, argptr);
dd0ef332
VS
657
658 va_end(argptr);
2523e9b7
VS
659 return rv;
660}
d1f6e2cf
VS
661#endif // !wxUSE_UTF8_LOCALE_ONLY
662
663#if wxUSE_UNICODE_UTF8
664int 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
2523e9b7
VS
675
676#if wxUSE_UNICODE
d1f6e2cf
VS
677
678#if !wxUSE_UTF8_LOCALE_ONLY
679int wxDoSprintfWchar(wchar_t *str, const wxChar *format, ...)
2523e9b7
VS
680{
681 va_list argptr;
682 va_start(argptr, format);
dd0ef332 683
2523e9b7
VS
684 int rv = wxVsprintf(str, format, argptr);
685
686 va_end(argptr);
687 return rv;
dd0ef332 688}
d1f6e2cf
VS
689#endif // !wxUSE_UTF8_LOCALE_ONLY
690
691#if wxUSE_UNICODE_UTF8
692int 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
707int wxDoSnprintfWchar(char *str, size_t size, const wxChar *format, ...)
708{
709 va_list argptr;
710 va_start(argptr, format);
dd0ef332 711
d1f6e2cf
VS
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
720int wxDoSnprintfUtf8(char *str, size_t size, const char *format, ...)
dd0ef332
VS
721{
722 va_list argptr;
2523e9b7 723 va_start(argptr, format);
dd0ef332 724
2523e9b7 725 int rv = wxVsnprintf(str, size, format, argptr);
dd0ef332
VS
726
727 va_end(argptr);
2523e9b7
VS
728 return rv;
729}
d1f6e2cf 730#endif // wxUSE_UNICODE_UTF8
dd0ef332 731
2523e9b7 732#if wxUSE_UNICODE
d1f6e2cf
VS
733
734#if !wxUSE_UTF8_LOCALE_ONLY
735int wxDoSnprintfWchar(wchar_t *str, size_t size, const wxChar *format, ...)
2523e9b7
VS
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;
dd0ef332 744}
d1f6e2cf
VS
745#endif // !wxUSE_UTF8_LOCALE_ONLY
746
747#if wxUSE_UNICODE_UTF8
748int 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
dd0ef332 761
2523e9b7
VS
762
763#ifdef HAVE_BROKEN_VSNPRINTF_DECL
764 #define vsnprintf wx_fixed_vsnprintf
765#endif
766
767#if wxUSE_UNICODE
d1f6e2cf
VS
768
769#if !wxUSE_UTF8_LOCALE_ONLY
2523e9b7 770static int ConvertStringToBuf(const wxString& s, char *out, size_t outsize)
dd0ef332 771{
2523e9b7
VS
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);
dd0ef332 779}
d1f6e2cf 780#endif // !wxUSE_UTF8_LOCALE_ONLY
dd0ef332 781
2523e9b7
VS
782#if wxUSE_UNICODE_UTF8
783static int ConvertStringToBuf(const wxString& s, wchar_t *out, size_t outsize)
dd0ef332 784{
2523e9b7
VS
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;
dd0ef332 791}
d1f6e2cf 792#endif // wxUSE_UNICODE_UTF8
dd0ef332 793
2523e9b7
VS
794template<typename T>
795static size_t PrintfViaString(T *out, size_t outsize,
796 const wxString& format, va_list argptr)
dd0ef332 797{
2523e9b7 798 wxString s;
c6255a6e 799 s.PrintfV(format, argptr);
2523e9b7
VS
800
801 return ConvertStringToBuf(s, out, outsize);
dd0ef332 802}
2523e9b7 803#endif // wxUSE_UNICODE
dd0ef332 804
2523e9b7 805int wxVsprintf(char *str, const wxString& format, va_list argptr)
dd0ef332 806{
2523e9b7 807#if wxUSE_UTF8_LOCALE_ONLY
c6255a6e 808 return vsprintf(str, format.wx_str(), argptr);
2523e9b7
VS
809#else
810 #if wxUSE_UNICODE_UTF8
811 if ( wxLocaleIsUtf8 )
c6255a6e 812 return vsprintf(str, format.wx_str(), argptr);
2523e9b7
VS
813 else
814 #endif
815 #if wxUSE_UNICODE
c6255a6e 816 return PrintfViaString(str, wxNO_LEN, format, argptr);
2523e9b7 817 #else
52de37c7 818 return wxCRT_VsprintfA(str, format.mb_str(), argptr);
2523e9b7
VS
819 #endif
820#endif
dd0ef332 821}
dd0ef332 822
2523e9b7
VS
823#if wxUSE_UNICODE
824int wxVsprintf(wchar_t *str, const wxString& format, va_list argptr)
dd0ef332 825{
2523e9b7 826#if wxUSE_UNICODE_WCHAR
52de37c7 827 return wxCRT_VsprintfW(str, format.wc_str(), argptr);
2523e9b7
VS
828#else // wxUSE_UNICODE_UTF8
829 #if !wxUSE_UTF8_LOCALE_ONLY
830 if ( !wxLocaleIsUtf8 )
52de37c7 831 return wxCRT_VsprintfW(str, format.wc_str(), argptr);
2523e9b7
VS
832 else
833 #endif
c6255a6e 834 return PrintfViaString(str, wxNO_LEN, format, argptr);
2523e9b7 835#endif // wxUSE_UNICODE_UTF8
dd0ef332 836}
2523e9b7 837#endif // wxUSE_UNICODE
dd0ef332 838
2523e9b7
VS
839int wxVsnprintf(char *str, size_t size, const wxString& format, va_list argptr)
840{
841 int rv;
2523e9b7 842#if wxUSE_UTF8_LOCALE_ONLY
52de37c7 843 rv = wxCRT_VsnprintfA(str, size, format.wx_str(), argptr);
2523e9b7
VS
844#else
845 #if wxUSE_UNICODE_UTF8
846 if ( wxLocaleIsUtf8 )
52de37c7 847 rv = wxCRT_VsnprintfA(str, size, format.wx_str(), argptr);
2523e9b7
VS
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
c6255a6e 855 rv = PrintfViaString(str, size, format, argptr);
2523e9b7
VS
856 }
857 #else
52de37c7 858 rv = wxCRT_VsnprintfA(str, size, format.mb_str(), argptr);
2523e9b7
VS
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
870int wxVsnprintf(wchar_t *str, size_t size, const wxString& format, va_list argptr)
871{
872 int rv;
2523e9b7
VS
873
874#if wxUSE_UNICODE_WCHAR
52de37c7 875 rv = wxCRT_VsnprintfW(str, size, format.wc_str(), argptr);
2523e9b7
VS
876#else // wxUSE_UNICODE_UTF8
877 #if !wxUSE_UTF8_LOCALE_ONLY
878 if ( !wxLocaleIsUtf8 )
52de37c7 879 rv = wxCRT_VsnprintfW(str, size, format.wc_str(), argptr);
2523e9b7
VS
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
c6255a6e 886 rv = PrintfViaString(str, size, format, argptr);
2523e9b7
VS
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
dd0ef332
VS
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)
52de37c7 905static inline WORD wxMSW_ctype(wchar_t ch)
dd0ef332
VS
906{
907 WORD ret;
908 GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, &ch, 1, &ret);
909 return ret;
910}
911
52de37c7
VS
912int wxCRT_IsalnumW(wchar_t ch) { return IsCharAlphaNumeric(ch); }
913int wxCRT_IsalphaW(wchar_t ch) { return IsCharAlpha(ch); }
914int wxCRT_IscntrlW(wchar_t ch) { return wxMSW_ctype(ch) & C1_CNTRL; }
915int wxCRT_IsdigitW(wchar_t ch) { return wxMSW_ctype(ch) & C1_DIGIT; }
916int wxCRT_IsgraphW(wchar_t ch) { return wxMSW_ctype(ch) & (C1_DIGIT|C1_PUNCT|C1_ALPHA); }
917int wxCRT_IslowerW(wchar_t ch) { return IsCharLower(ch); }
918int wxCRT_IsprintW(wchar_t ch) { return wxMSW_ctype(ch) & (C1_DIGIT|C1_SPACE|C1_PUNCT|C1_ALPHA); }
919int wxCRT_IspunctW(wchar_t ch) { return wxMSW_ctype(ch) & C1_PUNCT; }
920int wxCRT_IsspaceW(wchar_t ch) { return wxMSW_ctype(ch) & C1_SPACE; }
921int wxCRT_IsupperW(wchar_t ch) { return IsCharUpper(ch); }
922int wxCRT_IsxdigitW(wchar_t ch) { return wxMSW_ctype(ch) & C1_XDIGIT; }
923int wxCRT_Tolower(wchar_t ch) { return (wchar_t)CharLower((LPTSTR)(ch)); }
924int wxCRT_Toupper(wchar_t ch) { return (wchar_t)CharUpper((LPTSTR)(ch)); }
dd0ef332
VS
925#endif
926
927#ifdef wxNEED_WX_MBSTOWCS
928
929WXDLLEXPORT 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
951WXDLLEXPORT 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
52de37c7
VS
990int wxCRT_IsalnumW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cfalnumset, ch); }
991int wxCRT_IsalphaW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cfalphaset, ch); }
992int wxCRT_IscntrlW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cfcntrlset, ch); }
993int wxCRT_IsdigitW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cfdigitset, ch); }
994int wxCRT_IsgraphW(wchar_t ch) { return !CFCharacterSetIsCharacterMember(cfcntrlset, ch) && ch != ' '; }
995int wxCRT_IslowerW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cflowerset, ch); }
996int wxCRT_IsprintW(wchar_t ch) { return !CFCharacterSetIsCharacterMember(cfcntrlset, ch); }
997int wxCRT_IspunctW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cfpunctset, ch); }
998int wxCRT_IsspaceW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cfspaceset, ch); }
999int wxCRT_IsupperW(wchar_t ch) { return CFCharacterSetIsCharacterMember(cfupperset, ch); }
1000int wxCRT_IsxdigitW(wchar_t ch) { return wxCRT_IsdigitW(ch) || (ch>='a' && ch<='f') || (ch>='A' && ch<='F'); }
1001
1002// FIXME: these are broken!
1003extern "C" int wxCRT_TolowerW(wchar_t ch) { return (wchar_t)tolower((char)(ch)); }
1004extern "C" int wxCRT_ToupperW(wchar_t ch) { return (wchar_t)toupper((char)(ch)); }
dd0ef332
VS
1005
1006#endif // wxNEED_WX_CTYPE_H
1007
52de37c7
VS
1008#ifndef wxCRT_StrdupA
1009WXDLLEXPORT char *wxCRT_StrdupA(const char *s)
dd0ef332
VS
1010{
1011 return strcpy((char *)malloc(strlen(s) + 1), s);
1012}
52de37c7 1013#endif // wxCRT_StrdupA
dd0ef332 1014
52de37c7
VS
1015#ifndef wxCRT_StrdupW
1016WXDLLEXPORT wchar_t * wxCRT_StrdupW(const wchar_t *pwz)
dd0ef332
VS
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}
52de37c7 1023#endif // wxCRT_StrdupW
dd0ef332 1024
52de37c7
VS
1025#ifndef wxCRT_StricmpA
1026int 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)
dd0ef332 1036
52de37c7
VS
1037#ifndef wxCRT_StricmpW
1038int WXDLLEXPORT wxCRT_StricmpW(const wchar_t *psz1, const wchar_t *psz2)
dd0ef332 1039{
52de37c7 1040 register wchar_t c1, c2;
dd0ef332
VS
1041 do {
1042 c1 = wxTolower(*psz1++);
1043 c2 = wxTolower(*psz2++);
1044 } while ( c1 && (c1 == c2) );
1045 return c1 - c2;
1046}
52de37c7 1047#endif // !defined(wxCRT_StricmpW)
dd0ef332 1048
52de37c7
VS
1049#ifndef wxCRT_StrnicmpA
1050int WXDLLEXPORT wxCRT_StrnicmpA(const char *s1, const char *s2, size_t n)
dd0ef332
VS
1051{
1052 // initialize the variables just to suppress stupid gcc warning
52de37c7 1053 register char c1 = 0, c2 = 0;
dd0ef332
VS
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}
52de37c7 1061#endif // !defined(wxCRT_StrnicmpA)
cb352236 1062
52de37c7
VS
1063#ifndef wxCRT_StrnicmpW
1064int WXDLLEXPORT wxCRT_StrnicmpW(const wchar_t *s1, const wchar_t *s2, size_t n)
cb352236 1065{
52de37c7
VS
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;
dd0ef332 1074}
52de37c7 1075#endif // !defined(wxCRT_StrnicmpW)
dd0ef332
VS
1076
1077// ----------------------------------------------------------------------------
1078// string.h functions
1079// ----------------------------------------------------------------------------
1080
52de37c7
VS
1081#ifndef wxCRT_StrcatW
1082WXDLLEXPORT wchar_t *wxCRT_StrcatW(wchar_t *dest, const wchar_t *src)
dd0ef332 1083{
52de37c7 1084 wchar_t *ret = dest;
dd0ef332
VS
1085 while (*dest) dest++;
1086 while ((*dest++ = *src++));
1087 return ret;
1088}
52de37c7 1089#endif
dd0ef332 1090
52de37c7
VS
1091#ifndef wxCRT_StrchrW
1092WXDLLEXPORT const wchar_t *wxCRT_StrchrW(const wchar_t *s, wchar_t c)
dd0ef332
VS
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}
52de37c7 1103#endif
dd0ef332 1104
52de37c7
VS
1105#ifndef wxCRT_StrcmpW
1106WXDLLEXPORT int wxCRT_StrcmpW(const wchar_t *s1, const wchar_t *s2)
dd0ef332
VS
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}
52de37c7 1113#endif
dd0ef332 1114
52de37c7
VS
1115#ifndef wxCRT_StrcpyW
1116WXDLLEXPORT wchar_t * wxCRT_StrcpyW(wchar_t *dest, const wchar_t *src)
dd0ef332 1117{
52de37c7 1118 wchar_t *ret = dest;
dd0ef332
VS
1119 while ((*dest++ = *src++));
1120 return ret;
1121}
52de37c7 1122#endif
dd0ef332 1123
52de37c7
VS
1124template<typename T>
1125static inline size_t wxCRT_DoStrlen(const T *s)
dd0ef332
VS
1126{
1127 size_t n = 0;
1128 while ( *s++ )
1129 n++;
1130
1131 return n;
1132}
1133
52de37c7
VS
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
1137WXDLLEXPORT size_t wxCRT_StrlenA(const char *s)
1138 { return wxCRT_DoStrlen(s); }
1139#endif
1140#ifndef wxCRT_StrlenW
1141extern "C" WXDLLEXPORT size_t wxCRT_StrlenW(const wchar_t *s)
1142 { return wxCRT_DoStrlen(s); }
1143#endif
dd0ef332 1144
52de37c7
VS
1145#ifndef wxCRT_StrncatW
1146WXDLLEXPORT wchar_t * wxCRT_StrncatW(wchar_t *dest, const wchar_t *src, size_t n)
dd0ef332 1147{
52de37c7 1148 wchar_t *ret = dest;
dd0ef332
VS
1149 while (*dest) dest++;
1150 while (n && (*dest++ = *src++)) n--;
1151 return ret;
1152}
52de37c7 1153#endif
dd0ef332 1154
52de37c7
VS
1155#ifndef wxCRT_StrncmpW
1156extern "C"
1157WXDLLEXPORT int wxCRT_StrncmpW(const wchar_t *s1, const wchar_t *s2, size_t n)
dd0ef332
VS
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}
52de37c7 1166#endif
dd0ef332 1167
52de37c7
VS
1168#ifndef wxCRT_StrncpyW
1169WXDLLEXPORT wchar_t * wxCRT_StrncpyW(wchar_t *dest, const wchar_t *src, size_t n)
dd0ef332 1170{
52de37c7 1171 wchar_t *ret = dest;
dd0ef332
VS
1172 while (n && (*dest++ = *src++)) n--;
1173 while (n) *dest++=0, n--; // the docs specify padding with zeroes
1174 return ret;
1175}
52de37c7 1176#endif
dd0ef332 1177
52de37c7
VS
1178#ifndef wxCRT_StrpbrkW
1179WXDLLEXPORT const wchar_t * wxCRT_StrpbrkW(const wchar_t *s, const wchar_t *accept)
dd0ef332 1180{
52de37c7 1181 while (*s && !wxCRT_Strchr(accept, *s))
dd0ef332
VS
1182 s++;
1183
1184 return *s ? s : NULL;
1185}
52de37c7 1186#endif
dd0ef332 1187
52de37c7
VS
1188#ifndef wxCRT_StrrchrW
1189WXDLLEXPORT const wchar_t * wxCRT_StrrchrW(const wchar_t *s, wchar_t c)
dd0ef332 1190{
52de37c7 1191 const wchar_t *ret = NULL;
dd0ef332
VS
1192 do
1193 {
1194 if ( *s == c )
1195 ret = s;
1196 s++;
1197 }
1198 while ( *s );
1199
1200 return ret;
1201}
52de37c7 1202#endif
dd0ef332 1203
52de37c7
VS
1204#ifndef wxCRT_StrspnW
1205WXDLLEXPORT size_t wxCRT_StrspnW(const wchar_t *s, const wchar_t *accept)
dd0ef332
VS
1206{
1207 size_t len = 0;
52de37c7 1208 while (wxCRT_Strchr(accept, *s++)) len++;
dd0ef332
VS
1209 return len;
1210}
52de37c7 1211#endif
dd0ef332 1212
52de37c7
VS
1213#ifndef wxCRT_StrstrW
1214WXDLLEXPORT const wchar_t *wxCRT_StrstrW(const wchar_t *haystack, const wchar_t *needle)
dd0ef332 1215{
52de37c7 1216 wxASSERT_MSG( needle != NULL, _T("NULL argument in wxCRT_Strstr") );
dd0ef332
VS
1217
1218 // VZ: this is not exactly the most efficient string search algorithm...
1219
1220 const size_t len = wxStrlen(needle);
1221
52de37c7 1222 while ( const wchar_t *fnd = wxCRT_Strchr(haystack, *needle) )
dd0ef332 1223 {
52de37c7 1224 if ( !wxCRT_Strncmp(fnd, needle, len) )
dd0ef332
VS
1225 return fnd;
1226
1227 haystack = fnd + 1;
1228 }
1229
1230 return NULL;
1231}
dd0ef332
VS
1232#endif
1233
52de37c7
VS
1234#ifndef wxCRT_StrtodW
1235WXDLLEXPORT double wxCRT_StrtodW(const wchar_t *nptr, wchar_t **endptr)
dd0ef332 1236{
52de37c7 1237 const wchar_t *start = nptr;
dd0ef332
VS
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
52de37c7 1258 if (endptr) *endptr = (wchar_t *)(start + (rdat - (const char *)dat));
dd0ef332
VS
1259
1260 return ret;
1261}
52de37c7 1262#endif // !wxCRT_StrtodW
dd0ef332 1263
52de37c7
VS
1264#ifndef wxCRT_StrtolW
1265WXDLLEXPORT long int wxCRT_StrtolW(const wchar_t *nptr, wchar_t **endptr, int base)
dd0ef332 1266{
52de37c7 1267 const wchar_t *start = nptr;
dd0ef332
VS
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
52de37c7 1288 if (endptr) *endptr = (wchar_t *)(start + (rdat - (const char *)dat));
dd0ef332
VS
1289
1290 return ret;
1291}
52de37c7 1292#endif // !wxCRT_StrtolW
dd0ef332 1293
52de37c7
VS
1294#ifndef wxCRT_StrtoulW
1295WXDLLEXPORT unsigned long int wxCRT_StrtoulW(const wchar_t *nptr, wchar_t **endptr, int base)
dd0ef332 1296{
52de37c7 1297 return (unsigned long int) wxCRT_StrtolW(nptr, endptr, base);
dd0ef332
VS
1298}
1299#endif
1300
dd0ef332 1301
dd0ef332 1302
52de37c7
VS
1303#ifndef wxCRT_GetenvW
1304wchar_t* WXDLLEXPORT wxCRT_GetenvW(const wchar_t *name)
dd0ef332 1305{
dd0ef332
VS
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();
dd0ef332 1312}
52de37c7 1313#endif // !wxCRT_GetenvW
dd0ef332 1314
52de37c7 1315#ifndef wxCRT_StrftimeW
dd0ef332 1316WXDLLEXPORT size_t
52de37c7 1317wxCRT_StrftimeW(wchar_t *s, size_t maxsize, const wchar_t *fmt, const struct tm *tm)
dd0ef332
VS
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
52de37c7
VS
1336 wxCRT_StrncpyW(s, wbuf, maxsize);
1337 return wxCRT_StrlenW(s);
dd0ef332 1338}
52de37c7 1339#endif // !wxCRT_StrftimeW
dd0ef332
VS
1340
1341#endif // wxUSE_WCHAR_T
1342
52de37c7
VS
1343template<typename T>
1344static wxULongLong_t
1345wxCRT_StrtoullBase(const T* nptr, T** endptr, int base, T* sign)
17482893
VZ
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 {
52de37c7 1359 T c = *i;
17482893
VZ
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 )
52de37c7 1381 *endptr = (T*) nptr;
17482893
VZ
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
52de37c7 1397 T c = *i;
17482893
VZ
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 {
52de37c7 1424 *endptr = (T*)(nptr + (i - wxstr.begin()));
17482893
VZ
1425 }
1426
1427 return sum;
1428}
1429
52de37c7
VS
1430template<typename T>
1431static wxULongLong_t wxCRT_DoStrtoull(const T* nptr, T** endptr, int base)
17482893 1432{
52de37c7
VS
1433 T sign;
1434 wxULongLong_t uval = wxCRT_StrtoullBase(nptr, endptr, base, &sign);
17482893
VZ
1435
1436 if ( sign == wxT('-') )
1437 {
1438 wxSET_ERRNO(ERANGE);
1439 uval = 0;
1440 }
1441
1442 return uval;
1443}
1444
52de37c7
VS
1445template<typename T>
1446static wxLongLong_t wxCRT_DoStrtoll(const T* nptr, T** endptr, int base)
17482893 1447{
52de37c7
VS
1448 T sign;
1449 wxULongLong_t uval = wxCRT_StrtoullBase(nptr, endptr, base, &sign);
17482893
VZ
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}
52de37c7
VS
1477
1478#ifndef wxCRT_StrtollA
1479wxLongLong_t wxCRT_StrtollA(const char* nptr, char** endptr, int base)
1480 { return wxCRT_DoStrtoll(nptr, endptr, base); }
1481#endif
1482#ifndef wxCRT_StrtollW
1483wxLongLong_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
1488wxULongLong_t wxCRT_StrtoullA(const char* nptr, char** endptr, int base)
1489 { return wxCRT_DoStrtoull(nptr, endptr, base); }
1490#endif
1491#ifndef wxCRT_StrtoullW
1492wxULongLong_t wxCRT_StrtoullW(const wchar_t* nptr, wchar_t** endptr, int base)
1493 { return wxCRT_DoStrtoull(nptr, endptr, base); }
1494#endif
17482893 1495
dd0ef332
VS
1496// ----------------------------------------------------------------------------
1497// functions which we may need even if !wxUSE_WCHAR_T
1498// ----------------------------------------------------------------------------
1499
52de37c7
VS
1500template<typename T>
1501static T *wxCRT_DoStrtok(T *psz, const T *delim, T **save_ptr)
dd0ef332
VS
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 {
52de37c7
VS
1513 *save_ptr = (T *)NULL;
1514 return (T *)NULL;
dd0ef332
VS
1515 }
1516
52de37c7 1517 T *ret = psz;
dd0ef332
VS
1518 psz = wxStrpbrk(psz, delim);
1519 if (!psz)
1520 {
52de37c7 1521 *save_ptr = (T*)NULL;
dd0ef332
VS
1522 }
1523 else
1524 {
1525 *psz = wxT('\0');
1526 *save_ptr = psz + 1;
1527 }
1528
1529 return ret;
1530}
1531
52de37c7
VS
1532#ifndef wxCRT_StrtokA
1533char *wxCRT_StrtokA(char *psz, const char *delim, char **save_ptr)
1534 { return wxCRT_DoStrtok(psz, delim, save_ptr); }
1535#endif
1536#ifndef wxCRT_StrtokW
1537wchar_t *wxCRT_StrtokW(wchar_t *psz, const wchar_t *delim, wchar_t **save_ptr)
1538 { return wxCRT_DoStrtok(psz, delim, save_ptr); }
1539#endif
dd0ef332
VS
1540
1541// ----------------------------------------------------------------------------
1542// missing C RTL functions
1543// ----------------------------------------------------------------------------
1544
1545#ifdef wxNEED_STRDUP
1546
1547char *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
1558void *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__
52de37c7 1568int wxCRT_RemoveW(const wchar_t *path)
dd0ef332
VS
1569{
1570 return ::DeleteFile(path) == 0;
1571}
52de37c7
VS
1572#endif
1573
1574#ifndef wxCRT_TmpnamW
1575wchar_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" );
dd0ef332 1579
52de37c7
VS
1580#ifndef L_tmpnam
1581 #define L_tmpnam 1024
dd0ef332 1582#endif
52de37c7
VS
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
cb352236
VS
1590
1591
52de37c7 1592// ============================================================================
cb352236 1593// wxLocaleIsUtf8
52de37c7 1594// ============================================================================
cb352236
VS
1595
1596#if wxUSE_UNICODE_UTF8
1597
1598#if !wxUSE_UTF8_LOCALE_ONLY
1599bool wxLocaleIsUtf8 = false; // the safer setting if not known
1600#endif
1601
1602static 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:
e40dfb3a
VS
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 }
cb352236 1623 }
cb352236 1624#endif
e40dfb3a
VS
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) )
cb352236 1631 {
e40dfb3a 1632 return true;
cb352236 1633 }
e40dfb3a
VS
1634
1635 // we don't know what charset libc is using, so assume the worst
1636 // to be safe:
1637 return false;
cb352236
VS
1638}
1639
1640void 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
c49f8879
VS
1652#endif // wxUSE_UNICODE_UTF8
1653
1654// ============================================================================
1655// wx wrappers for CRT functions
1656// ============================================================================
1657
52de37c7
VS
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
1667int wxPuts(const wxString& s)
1668{
1669 CALL_ANSI_OR_UNICODE(wxCRT_PutsA(s.mb_str()),
1670 wxCRT_PutsW(s.wc_str()));
1671}
1672
1673int 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
1679int 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
1689void 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
1698wchar_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}
c49f8879
VS
1714
1715// ----------------------------------------------------------------------------
1716// wxScanf() and friends
1717// ----------------------------------------------------------------------------
1718
eb6cb207 1719#ifndef __VISUALC__
c49f8879
VS
1720int wxVsscanf(const char *str, const char *format, va_list ap)
1721 { return wxCRT_VsscanfA(str, format, ap); }
1722int wxVsscanf(const wchar_t *str, const wchar_t *format, va_list ap)
eb6cb207 1723 { return wxCRT_VsscanfW(str, format, ap); }
c49f8879
VS
1724int wxVsscanf(const wxCharBuffer& str, const char *format, va_list ap)
1725 { return wxCRT_VsscanfA(str, format, ap); }
1726int wxVsscanf(const wxWCharBuffer& str, const wchar_t *format, va_list ap)
eb6cb207 1727 { return wxCRT_VsscanfW(str, format, ap); }
c49f8879
VS
1728int wxVsscanf(const wxString& str, const char *format, va_list ap)
1729 { return wxCRT_VsscanfA(str.mb_str(), format, ap); }
1730int wxVsscanf(const wxString& str, const wchar_t *format, va_list ap)
eb6cb207 1731 { return wxCRT_VsscanfW(str.wc_str(), format, ap); }
c49f8879
VS
1732int wxVsscanf(const wxCStrData& str, const char *format, va_list ap)
1733 { return wxCRT_VsscanfA(str.AsCharBuf(), format, ap); }
1734int wxVsscanf(const wxCStrData& str, const wchar_t *format, va_list ap)
eb6cb207
VS
1735 { return wxCRT_VsscanfW(str.AsWCharBuf(), format, ap); }
1736#endif // !__VISUALC__