]> git.saurik.com Git - wxWidgets.git/blob - src/common/wxchar.cpp
don't mention GUI-only changes in the base section
[wxWidgets.git] / src / common / wxchar.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: wxchar.cpp
3 // Purpose: wxChar implementation
4 // Author: Ove Kåven
5 // Modified by:
6 // Created: 09/04/99
7 // RCS-ID: $Id$
8 // Copyright: (c) wxWindows copyright
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "wxchar.h"
14 #endif
15
16 // ===========================================================================
17 // headers, declarations, constants
18 // ===========================================================================
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #define _ISOC9X_SOURCE 1 // to get vsscanf()
28 #define _BSD_SOURCE 1 // to still get strdup()
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <locale.h>
34 #include <time.h>
35
36 #ifndef WX_PRECOMP
37 #include "wx/defs.h"
38 #include "wx/wxchar.h"
39 #include "wx/string.h"
40 #include "wx/hash.h"
41 #endif
42
43 #if defined(__WIN32__) && defined(wxNEED_WX_CTYPE_H)
44 #include <windef.h>
45 #include <winbase.h>
46 #include <winnls.h>
47 #include <winnt.h>
48 #endif
49
50 #if wxUSE_WCHAR_T
51 size_t WXDLLEXPORT wxMB2WC(wchar_t *buf, const char *psz, size_t n)
52 {
53 if (buf) {
54 if (!n || !*psz) {
55 if (n) *buf = wxT('\0');
56 return 0;
57 }
58 return mbstowcs(buf, psz, n);
59 }
60
61 // assume that we have mbsrtowcs() too if we have wcsrtombs()
62 #ifdef HAVE_WCSRTOMBS
63 mbstate_t mbstate;
64 return mbsrtowcs((wchar_t *) NULL, &psz, 0, &mbstate);
65 #else // !GNU libc
66 return mbstowcs((wchar_t *) NULL, psz, 0);
67 #endif // GNU
68 }
69
70 size_t WXDLLEXPORT wxWC2MB(char *buf, const wchar_t *pwz, size_t n)
71 {
72 if (buf) {
73 if (!n || !*pwz) {
74 // glibc2.1 chokes on null input
75 if (n) *buf = '\0';
76 return 0;
77 }
78 return wcstombs(buf, pwz, n);
79 }
80
81 #if HAVE_WCSRTOMBS
82 mbstate_t mbstate;
83 return wcsrtombs((char *) NULL, &pwz, 0, &mbstate);
84 #else // !GNU libc
85 return wcstombs((char *) NULL, pwz, 0);
86 #endif // GNU
87 }
88 #endif // wxUSE_WCHAR_T
89
90 bool WXDLLEXPORT wxOKlibc()
91 {
92 #if wxUSE_WCHAR_T && defined(__UNIX__) && defined(__GLIBC__)
93 // glibc 2.0 uses UTF-8 even when it shouldn't
94 wchar_t res = 0;
95 if ((MB_CUR_MAX == 2) &&
96 (wxMB2WC(&res, "\xdd\xa5", 1) == 1) &&
97 (res==0x765)) {
98 // this is UTF-8 allright, check whether that's what we want
99 char *cur_locale = setlocale(LC_CTYPE, NULL);
100 if ((strlen(cur_locale) < 4) ||
101 (strcasecmp(cur_locale + strlen(cur_locale) - 4, "utf8")) ||
102 (strcasecmp(cur_locale + strlen(cur_locale) - 5, "utf-8"))) {
103 // nope, don't use libc conversion
104 return FALSE;
105 }
106 }
107 #endif
108 return TRUE;
109 }
110
111 // ============================================================================
112 // printf() functions business
113 // ============================================================================
114
115 // special test mode: define all functions below even if we don't really need
116 // them to be able to test them
117 #ifdef wxTEST_PRINTF
118 #undef wxFprintf
119 #undef wxPrintf
120 #undef wxSprintf
121 #undef wxVfprintf
122 #undef wxVsprintf
123 #undef wxVprintf
124 #undef wxVsnprintf_
125 #undef wxSnprintf_
126
127 #define wxNEED_WPRINTF
128
129 int wxVfprintf( FILE *stream, const wxChar *format, va_list argptr );
130 #endif
131
132 // ----------------------------------------------------------------------------
133 // implement [v]snprintf() if the system doesn't provide a safe one
134 // ----------------------------------------------------------------------------
135
136 #if !defined(wxVsnprintf_)
137 int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax,
138 const wxChar *format, va_list argptr)
139 {
140 // buffer to avoid dynamic memory allocation each time for small strings
141 char szScratch[1024];
142
143 // number of characters in the buffer so far, must be less than lenMax
144 size_t lenCur = 0;
145
146 for ( size_t n = 0; ; n++ )
147 {
148 const wxChar chCur = format[n];
149
150 if ( chCur == wxT('%') )
151 {
152 static char s_szFlags[256] = "%";
153 size_t flagofs = 1;
154 bool adj_left = FALSE,
155 in_prec = FALSE,
156 prec_dot = FALSE,
157 done = FALSE;
158 int ilen = 0;
159 size_t min_width = 0,
160 max_width = wxSTRING_MAXLEN;
161 do
162 {
163
164 #define CHECK_PREC \
165 if (in_prec && !prec_dot) \
166 { \
167 s_szFlags[flagofs++] = '.'; \
168 prec_dot = TRUE; \
169 }
170
171 #define APPEND_CH(ch) \
172 if ( lenCur == lenMax ) \
173 return -1; \
174 \
175 buf[lenCur++] = ch
176
177 #define APPEND_STR(s) \
178 { \
179 for ( const wxChar *p = s; *p; p++ ) \
180 { \
181 APPEND_CH(*p); \
182 } \
183 }
184
185 // what follows '%'?
186 const wxChar ch = format[++n];
187 switch ( ch )
188 {
189 case wxT('\0'):
190 APPEND_CH(_T('\0'));
191
192 done = TRUE;
193 break;
194
195 case wxT('%'):
196 APPEND_CH(_T('%'));
197 done = TRUE;
198 break;
199
200 case wxT('#'):
201 case wxT('0'):
202 case wxT(' '):
203 case wxT('+'):
204 case wxT('\''):
205 CHECK_PREC
206 s_szFlags[flagofs++] = ch;
207 break;
208
209 case wxT('-'):
210 CHECK_PREC
211 adj_left = TRUE;
212 s_szFlags[flagofs++] = ch;
213 break;
214
215 case wxT('.'):
216 CHECK_PREC
217 in_prec = TRUE;
218 prec_dot = FALSE;
219 max_width = 0;
220 // dot will be auto-added to s_szFlags if non-negative
221 // number follows
222 break;
223
224 case wxT('h'):
225 ilen = -1;
226 CHECK_PREC
227 s_szFlags[flagofs++] = ch;
228 break;
229
230 case wxT('l'):
231 ilen = 1;
232 CHECK_PREC
233 s_szFlags[flagofs++] = ch;
234 break;
235
236 case wxT('q'):
237 case wxT('L'):
238 ilen = 2;
239 CHECK_PREC
240 s_szFlags[flagofs++] = ch;
241 break;
242
243 case wxT('Z'):
244 ilen = 3;
245 CHECK_PREC
246 s_szFlags[flagofs++] = ch;
247 break;
248
249 case wxT('*'):
250 {
251 int len = va_arg(argptr, int);
252 if (in_prec)
253 {
254 if (len<0) break;
255 CHECK_PREC
256 max_width = len;
257 }
258 else
259 {
260 if (len<0)
261 {
262 adj_left = !adj_left;
263 s_szFlags[flagofs++] = '-';
264 len = -len;
265 }
266 min_width = len;
267 }
268 flagofs += ::sprintf(s_szFlags+flagofs,"%d",len);
269 }
270 break;
271
272 case wxT('1'): case wxT('2'): case wxT('3'):
273 case wxT('4'): case wxT('5'): case wxT('6'):
274 case wxT('7'): case wxT('8'): case wxT('9'):
275 {
276 int len = 0;
277 CHECK_PREC
278 while ( (format[n] >= wxT('0')) &&
279 (format[n] <= wxT('9')) )
280 {
281 s_szFlags[flagofs++] = format[n];
282 len = len*10 + (format[n] - wxT('0'));
283 n++;
284 }
285
286 if (in_prec)
287 max_width = len;
288 else
289 min_width = len;
290
291 n--; // the main loop pre-increments n again
292 }
293 break;
294
295 case wxT('d'):
296 case wxT('i'):
297 case wxT('o'):
298 case wxT('u'):
299 case wxT('x'):
300 case wxT('X'):
301 CHECK_PREC
302 s_szFlags[flagofs++] = ch;
303 s_szFlags[flagofs] = '\0';
304 if (ilen == 0 )
305 {
306 int val = va_arg(argptr, int);
307 ::sprintf(szScratch, s_szFlags, val);
308 }
309 else if (ilen == -1)
310 {
311 // NB: 'short int' value passed through '...'
312 // is promoted to 'int', so we have to get
313 // an int from stack even if we need a short
314 short int val = (short int) va_arg(argptr, int);
315 ::sprintf(szScratch, s_szFlags, val);
316 }
317 else if (ilen == 1)
318 {
319 long int val = va_arg(argptr, long int);
320 ::sprintf(szScratch, s_szFlags, val);
321 }
322 else if (ilen == 2)
323 {
324 #if SIZEOF_LONG_LONG
325 long long int val = va_arg(argptr, long long int);
326 ::sprintf(szScratch, s_szFlags, val);
327 #else // !long long
328 long int val = va_arg(argptr, long int);
329 ::sprintf(szScratch, s_szFlags, val);
330 #endif // long long/!long long
331 }
332 else if (ilen == 3)
333 {
334 size_t val = va_arg(argptr, size_t);
335 ::sprintf(szScratch, s_szFlags, val);
336 }
337
338 {
339 const wxMB2WXbuf tmp =
340 wxConvLibc.cMB2WX(szScratch);
341 APPEND_STR(tmp);
342 }
343
344 done = TRUE;
345 break;
346
347 case wxT('e'):
348 case wxT('E'):
349 case wxT('f'):
350 case wxT('g'):
351 case wxT('G'):
352 CHECK_PREC
353 s_szFlags[flagofs++] = ch;
354 s_szFlags[flagofs] = '\0';
355 if (ilen == 2)
356 {
357 long double val = va_arg(argptr, long double);
358 ::sprintf(szScratch, s_szFlags, val);
359 }
360 else
361 {
362 double val = va_arg(argptr, double);
363 ::sprintf(szScratch, s_szFlags, val);
364 }
365
366 {
367 const wxMB2WXbuf tmp =
368 wxConvLibc.cMB2WX(szScratch);
369 APPEND_STR(tmp);
370 }
371
372 done = TRUE;
373 break;
374
375 case wxT('p'):
376 {
377 void *val = va_arg(argptr, void *);
378 CHECK_PREC
379 s_szFlags[flagofs++] = ch;
380 s_szFlags[flagofs] = '\0';
381 ::sprintf(szScratch, s_szFlags, val);
382
383 const wxMB2WXbuf tmp =
384 wxConvLibc.cMB2WX(szScratch);
385 APPEND_STR(tmp);
386
387 done = TRUE;
388 }
389 break;
390
391 case wxT('c'):
392 {
393 wxChar val = va_arg(argptr, int);
394 // we don't need to honor padding here, do we?
395 APPEND_CH(val);
396
397 done = TRUE;
398 }
399 break;
400
401 case wxT('s'):
402 if (ilen == -1)
403 {
404 // wx extension: we'll let %hs mean non-Unicode
405 // strings
406 char *val = va_arg(argptr, char *);
407 #if wxUSE_UNICODE
408 // ASCII->Unicode constructor handles max_width
409 // right
410 wxString s(val, wxConvLibc, max_width);
411 #else
412 size_t len = wxSTRING_MAXLEN;
413 if (val)
414 {
415 for ( len = 0;
416 val[len] && (len < max_width);
417 len++ )
418 ;
419 }
420 else
421 val = wxT("(null)");
422 wxString s(val, len);
423 #endif
424 if (s.Len() < min_width)
425 s.Pad(min_width - s.Len(), wxT(' '), adj_left);
426
427 APPEND_STR(s);
428 }
429 else
430 {
431 wxChar *val = va_arg(argptr, wxChar *);
432 size_t len = wxSTRING_MAXLEN;
433 if (val)
434 {
435 for ( len = 0;
436 val[len] && (len < max_width);
437 len++ )
438 ;
439 }
440 else
441 val = wxT("(null)");
442
443 wxString s(val, len);
444 if (s.Len() < min_width)
445 s.Pad(min_width - s.Len(), wxT(' '), adj_left);
446
447 APPEND_STR(s);
448 }
449 done = TRUE;
450 break;
451
452 case wxT('n'):
453 if (ilen == 0)
454 {
455 int *val = va_arg(argptr, int *);
456 *val = lenCur;
457 }
458 else if (ilen == -1)
459 {
460 short int *val = va_arg(argptr, short int *);
461 *val = lenCur;
462 }
463 else if (ilen >= 1)
464 {
465 long int *val = va_arg(argptr, long int *);
466 *val = lenCur;
467 }
468 done = TRUE;
469 break;
470
471 default:
472 // bad format, leave unchanged
473 APPEND_CH(_T('%'));
474 APPEND_CH(ch);
475 done = TRUE;
476 break;
477 }
478 }
479 while (!done);
480 }
481 else
482 {
483 APPEND_CH(chCur);
484 }
485
486 // terminating NUL?
487 if ( !chCur )
488 break;
489 }
490
491 return lenCur;
492 }
493
494 #undef APPEND_CH
495 #undef APPEND_STR
496 #undef CHECK_PREC
497
498 #endif // !wxVsnprintfA
499
500 #if !defined(wxSnprintf_)
501 int WXDLLEXPORT wxSnprintf_(wxChar *buf, size_t len, const wxChar *format, ...)
502 {
503 va_list argptr;
504 va_start(argptr, format);
505
506 int iLen = wxVsnprintf_(buf, len, format, argptr);
507
508 va_end(argptr);
509
510 return iLen;
511 }
512 #endif // wxSnprintf_
513
514 // ----------------------------------------------------------------------------
515 // implement the standard IO functions for wide char if libc doesn't have them
516 // ----------------------------------------------------------------------------
517
518 #ifdef wxNEED_FPUTWC
519
520 int wxFputs(const wchar_t *ws, FILE *stream)
521 {
522 // counting the number of wide characters written isn't worth the trouble,
523 // simply distinguish between ok and error
524 return fputs(wxConvLibc.cWC2MB(ws), stream) == -1 ? -1 : 0;
525 }
526
527 int /* not wint_t */ wxPutc(wchar_t wc, FILE *stream)
528 {
529 wchar_t ws[2] = { wc, L'\0' };
530
531 return wxFputs(ws, stream);
532 }
533
534 #endif // wxNEED_FPUTWC
535
536 // NB: we only implement va_list functions here, the ones taking ... are
537 // defined below for wxNEED_PRINTF_CONVERSION case anyhow and we reuse
538 // the definitions there to avoid duplicating them here
539 #ifdef wxNEED_WPRINTF
540
541 // TODO: implement the scanf() functions
542 int vwscanf(const wxChar *format, va_list argptr)
543 {
544 wxFAIL_MSG( _T("TODO") );
545
546 return -1;
547 }
548
549 int vswscanf(const wxChar *ws, const wxChar *format, va_list argptr)
550 {
551 wxFAIL_MSG( _T("TODO") );
552
553 return -1;
554 }
555
556 int vfwscanf(FILE *stream, const wxChar *format, va_list argptr)
557 {
558 wxFAIL_MSG( _T("TODO") );
559
560 return -1;
561 }
562
563 #define vswprintf wxVsnprintf_
564
565 int vfwprintf(FILE *stream, const wxChar *format, va_list argptr)
566 {
567 wxString s;
568 int rc = s.PrintfV(format, argptr);
569
570 if ( rc != -1 )
571 {
572 // we can't do much better without Unicode support in libc...
573 if ( fprintf(stream, "%s", s.mb_str()) == -1 )
574 return -1;
575 }
576
577 return rc;
578 }
579
580 int vwprintf(const wxChar *format, va_list argptr)
581 {
582 return wxVfprintf(stdout, format, argptr);
583 }
584
585 #endif // wxNEED_WPRINTF
586
587 #ifdef wxNEED_PRINTF_CONVERSION
588
589 // ----------------------------------------------------------------------------
590 // wxFormatConverter: class doing the "%s" -> "%ls" conversion
591 // ----------------------------------------------------------------------------
592
593 /*
594 Here are the gory details. We want to follow the Windows/MS conventions,
595 that is to have
596
597 In ANSI mode:
598
599 format specifier results in
600 -----------------------------------
601 %c, %hc, %hC char
602 %lc, %C, %lC wchar_t
603
604 In Unicode mode:
605
606 format specifier results in
607 -----------------------------------
608 %hc, %C, %hC char
609 %c, %lc, %lC wchar_t
610
611
612 while on POSIX systems we have %C identical to %lc and %c always means char
613 (in any mode) while %lc always means wchar_t,
614
615 So to use native functions in order to get our semantics we must do the
616 following translations in Unicode mode (nothing to do in ANSI mode):
617
618 wxWindows specifier POSIX specifier
619 ----------------------------------------
620
621 %hc, %C, %hC %c
622 %c %lc
623
624
625 And, of course, the same should be done for %s as well.
626 */
627
628 class wxFormatConverter
629 {
630 public:
631 wxFormatConverter(const wxChar *format);
632
633 // notice that we only translated the string if m_fmtOrig == NULL (as set
634 // by CopyAllBefore()), otherwise we should simply use the original format
635 operator const wxChar *() const
636 { return m_fmtOrig ? m_fmtOrig : m_fmt.c_str(); }
637
638 private:
639 // copy another character to the translated format: this function does the
640 // copy if we are translating but doesn't do anything at all if we don't,
641 // so we don't create the translated format string at all unless we really
642 // need to (i.e. InsertFmtChar() is called)
643 wxChar CopyFmtChar(wxChar ch)
644 {
645 if ( !m_fmtOrig )
646 {
647 // we're translating, do copy
648 m_fmt += ch;
649 }
650 else
651 {
652 // simply increase the count which should be copied by
653 // CopyAllBefore() later if needed
654 m_nCopied++;
655 }
656
657 return ch;
658 }
659
660 // insert an extra character
661 void InsertFmtChar(wxChar ch)
662 {
663 if ( m_fmtOrig )
664 {
665 // so far we haven't translated anything yet
666 CopyAllBefore();
667 }
668
669 m_fmt += ch;
670 }
671
672 void CopyAllBefore()
673 {
674 wxASSERT_MSG( m_fmtOrig && m_fmt.empty(), _T("logic error") );
675
676 m_fmt = wxString(m_fmtOrig, m_nCopied);
677
678 // we won't need it any longer
679 m_fmtOrig = NULL;
680 }
681
682 static bool IsFlagChar(wxChar ch)
683 {
684 return ch == _T('-') || ch == _T('+') ||
685 ch == _T('0') || ch == _T(' ') || ch == _T('#');
686 }
687
688 void SkipDigits(const wxChar **ppc)
689 {
690 while ( **ppc >= _T('0') && **ppc <= _T('9') )
691 CopyFmtChar(*(*ppc)++);
692 }
693
694 // the translated format
695 wxString m_fmt;
696
697 // the original format
698 const wxChar *m_fmtOrig;
699
700 // the number of characters already copied
701 size_t m_nCopied;
702 };
703
704 wxFormatConverter::wxFormatConverter(const wxChar *format)
705 {
706 m_fmtOrig = format;
707 m_nCopied = 0;
708
709 while ( *format )
710 {
711 if ( CopyFmtChar(*format++) == _T('%') )
712 {
713 // skip any flags
714 while ( IsFlagChar(*format) )
715 CopyFmtChar(*format++);
716
717 // and possible width
718 if ( *format == _T('*') )
719 CopyFmtChar(*format++);
720 else
721 SkipDigits(&format);
722
723 // precision?
724 if ( *format == _T('.') )
725 {
726 SkipDigits(&format);
727 }
728
729 // next we can have a size modifier
730 enum
731 {
732 Default,
733 Short,
734 Long
735 } size;
736
737 switch ( *format )
738 {
739 case _T('h'):
740 size = Short;
741 format++;
742 break;
743
744 case _T('l'):
745 // "ll" has a different meaning!
746 if ( format[1] != _T('l') )
747 {
748 size = Long;
749 format++;
750 break;
751 }
752 //else: fall through
753
754 default:
755 size = Default;
756 }
757
758 // and finally we should have the type
759 switch ( *format )
760 {
761 case _T('C'):
762 case _T('S'):
763 // %C and %hC -> %c and %lC -> %lc
764 if ( size == Long )
765 CopyFmtChar(_T('l'));
766
767 InsertFmtChar(*format++ == _T('C') ? _T('c') : _T('s'));
768 break;
769
770 case _T('c'):
771 case _T('s'):
772 // %c -> %lc but %hc stays %hc and %lc is still %lc
773 switch ( size )
774 {
775 case Default:
776 InsertFmtChar(_T('l'));
777 break;
778
779 case Short:
780 CopyFmtChar(_T('h'));
781 break;
782
783 case Long:
784 ;
785 }
786 // fall through
787
788 default:
789 // nothing special to do
790 CopyFmtChar(*format++);
791 }
792 }
793 }
794 }
795
796 #else // !wxNEED_PRINTF_CONVERSION
797 // no conversion necessary
798 #define wxFormatConverter(x) (x)
799 #endif // wxNEED_PRINTF_CONVERSION/!wxNEED_PRINTF_CONVERSION
800
801 // ----------------------------------------------------------------------------
802 // wxPrintf(), wxScanf() and relatives
803 // ----------------------------------------------------------------------------
804
805 #if defined(wxNEED_PRINTF_CONVERSION) || defined(wxNEED_WPRINTF)
806
807 int wxScanf( const wxChar *format, ... )
808 {
809 va_list argptr;
810 va_start(argptr, format);
811
812 int ret = vwscanf(wxFormatConverter(format), argptr );
813
814 va_end(argptr);
815
816 return ret;
817 }
818
819 int wxSscanf( const wxChar *str, const wxChar *format, ... )
820 {
821 va_list argptr;
822 va_start(argptr, format);
823
824 int ret = vswscanf( str, wxFormatConverter(format), argptr );
825
826 va_end(argptr);
827
828 return ret;
829 }
830
831 int wxFscanf( FILE *stream, const wxChar *format, ... )
832 {
833 va_list argptr;
834 va_start(argptr, format);
835
836 int ret = vfwscanf(stream, wxFormatConverter(format), argptr);
837
838 va_end(argptr);
839
840 return ret;
841 }
842
843 int wxPrintf( const wxChar *format, ... )
844 {
845 va_list argptr;
846 va_start(argptr, format);
847
848 int ret = vwprintf( wxFormatConverter(format), argptr );
849
850 va_end(argptr);
851
852 return ret;
853 }
854
855 #ifndef wxSnprintf
856 int wxSnprintf( wxChar *str, size_t size, const wxChar *format, ... )
857 {
858 va_list argptr;
859 va_start(argptr, format);
860
861 int ret = vswprintf( str, size, wxFormatConverter(format), argptr );
862
863 va_end(argptr);
864
865 return ret;
866 }
867 #endif // wxSnprintf
868
869 int wxSprintf( wxChar *str, const wxChar *format, ... )
870 {
871 va_list argptr;
872 va_start(argptr, format);
873
874 // callers of wxSprintf() deserve what they get
875 int ret = vswprintf( str, UINT_MAX, wxFormatConverter(format), argptr );
876
877 va_end(argptr);
878
879 return ret;
880 }
881
882 int wxFprintf( FILE *stream, const wxChar *format, ... )
883 {
884 va_list argptr;
885 va_start( argptr, format );
886
887 int ret = vfwprintf( stream, wxFormatConverter(format), argptr );
888
889 va_end(argptr);
890
891 return ret;
892 }
893
894 int wxVsscanf( const wxChar *str, const wxChar *format, va_list argptr )
895 {
896 return vswscanf( str, wxFormatConverter(format), argptr );
897 }
898
899 int wxVfprintf( FILE *stream, const wxChar *format, va_list argptr )
900 {
901 return vfwprintf( stream, wxFormatConverter(format), argptr );
902 }
903
904 int wxVprintf( const wxChar *format, va_list argptr )
905 {
906 return vwprintf( wxFormatConverter(format), argptr );
907 }
908
909 #ifndef wxVsnprintf
910 int wxVsnprintf( wxChar *str, size_t size, const wxChar *format, va_list argptr )
911 {
912 return vswprintf( str, size, wxFormatConverter(format), argptr );
913 }
914 #endif // wxVsnprintf
915
916 int wxVsprintf( wxChar *str, const wxChar *format, va_list argptr )
917 {
918 // same as for wxSprintf()
919 return vswprintf(str, UINT_MAX, wxFormatConverter(format), argptr);
920 }
921
922 #endif // wxNEED_PRINTF_CONVERSION
923
924 // ----------------------------------------------------------------------------
925 // ctype.h stuff (currently unused)
926 // ----------------------------------------------------------------------------
927
928 #if defined(__WIN32__) && defined(wxNEED_WX_CTYPE_H)
929 inline WORD wxMSW_ctype(wxChar ch)
930 {
931 WORD ret;
932 GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, &ch, 1, &ret);
933 return ret;
934 }
935
936 WXDLLEXPORT int wxIsalnum(wxChar ch) { return IsCharAlphaNumeric(ch); }
937 WXDLLEXPORT int wxIsalpha(wxChar ch) { return IsCharAlpha(ch); }
938 WXDLLEXPORT int wxIsctrl(wxChar ch) { return wxMSW_ctype(ch) & C1_CNTRL; }
939 WXDLLEXPORT int wxIsdigit(wxChar ch) { return wxMSW_ctype(ch) & C1_DIGIT; }
940 WXDLLEXPORT int wxIsgraph(wxChar ch) { return wxMSW_ctype(ch) & (C1_DIGIT|C1_PUNCT|C1_ALPHA); }
941 WXDLLEXPORT int wxIslower(wxChar ch) { return IsCharLower(ch); }
942 WXDLLEXPORT int wxIsprint(wxChar ch) { return wxMSW_ctype(ch) & (C1_DIGIT|C1_SPACE|C1_PUNCT|C1_ALPHA); }
943 WXDLLEXPORT int wxIspunct(wxChar ch) { return wxMSW_ctype(ch) & C1_PUNCT; }
944 WXDLLEXPORT int wxIsspace(wxChar ch) { return wxMSW_ctype(ch) & C1_SPACE; }
945 WXDLLEXPORT int wxIsupper(wxChar ch) { return IsCharUpper(ch); }
946 WXDLLEXPORT int wxIsxdigit(wxChar ch) { return wxMSW_ctype(ch) & C1_XDIGIT; }
947 WXDLLEXPORT int wxTolower(wxChar ch) { return (wxChar)CharLower((LPTSTR)(ch)); }
948 WXDLLEXPORT int wxToupper(wxChar ch) { return (wxChar)CharUpper((LPTSTR)(ch)); }
949 #endif
950
951 #ifndef wxStrdup
952 WXDLLEXPORT wxChar * wxStrdup(const wxChar *psz)
953 {
954 size_t size = (wxStrlen(psz) + 1) * sizeof(wxChar);
955 wxChar *ret = (wxChar *) malloc(size);
956 memcpy(ret, psz, size);
957 return ret;
958 }
959 #endif
960
961 #ifndef wxStricmp
962 int WXDLLEXPORT wxStricmp(const wxChar *psz1, const wxChar *psz2)
963 {
964 register wxChar c1, c2;
965 do {
966 c1 = wxTolower(*psz1++);
967 c2 = wxTolower(*psz2++);
968 } while ( c1 && (c1 == c2) );
969 return c1 - c2;
970 }
971 #endif
972
973 #ifndef wxStricmp
974 int WXDLLEXPORT wxStrnicmp(const wxChar *s1, const wxChar *s2, size_t n)
975 {
976 register wxChar c1, c2;
977 while (n && ((c1 = wxTolower(*s1)) == (c2 = wxTolower(*s2)) ) && c1) n--, s1++, s2++;
978 if (n) {
979 if (c1 < c2) return -1;
980 if (c1 > c2) return 1;
981 }
982 return 0;
983 }
984 #endif
985
986 #ifndef wxStrtok
987 WXDLLEXPORT wxChar * wxStrtok(wxChar *psz, const wxChar *delim, wxChar **save_ptr)
988 {
989 if (!psz)
990 {
991 psz = *save_ptr;
992 if ( !psz )
993 return NULL;
994 }
995
996 psz += wxStrspn(psz, delim);
997 if (!*psz)
998 {
999 *save_ptr = (wxChar *)NULL;
1000 return (wxChar *)NULL;
1001 }
1002
1003 wxChar *ret = psz;
1004 psz = wxStrpbrk(psz, delim);
1005 if (!psz)
1006 {
1007 *save_ptr = (wxChar*)NULL;
1008 }
1009 else
1010 {
1011 *psz = wxT('\0');
1012 *save_ptr = psz + 1;
1013 }
1014
1015 return ret;
1016 }
1017 #endif // wxStrtok
1018
1019 #ifndef wxSetlocale
1020 WXDLLEXPORT wxWCharBuffer wxSetlocale(int category, const wxChar *locale)
1021 {
1022 char *localeOld = setlocale(category, wxConvLocal.cWX2MB(locale));
1023
1024 return wxWCharBuffer(wxConvLocal.cMB2WC(localeOld));
1025 }
1026 #endif
1027
1028 // ----------------------------------------------------------------------------
1029 // string.h functions
1030 // ----------------------------------------------------------------------------
1031
1032 #ifdef wxNEED_WX_STRING_H
1033 WXDLLEXPORT wxChar * wxStrcat(wxChar *dest, const wxChar *src)
1034 {
1035 wxChar *ret = dest;
1036 while (*dest) dest++;
1037 while ((*dest++ = *src++));
1038 return ret;
1039 }
1040
1041 WXDLLEXPORT const wxChar * wxStrchr(const wxChar *s, wxChar c)
1042 {
1043 // be careful here as the terminating NUL makes part of the string
1044 while ( *s != c )
1045 {
1046 if ( !*s++ )
1047 return NULL;
1048 }
1049
1050 return s;
1051 }
1052
1053 WXDLLEXPORT int wxStrcmp(const wxChar *s1, const wxChar *s2)
1054 {
1055 while ((*s1 == *s2) && *s1) s1++, s2++;
1056 if ((wxUChar)*s1 < (wxUChar)*s2) return -1;
1057 if ((wxUChar)*s1 > (wxUChar)*s2) return 1;
1058 return 0;
1059 }
1060
1061 WXDLLEXPORT wxChar * wxStrcpy(wxChar *dest, const wxChar *src)
1062 {
1063 wxChar *ret = dest;
1064 while ((*dest++ = *src++));
1065 return ret;
1066 }
1067
1068 WXDLLEXPORT wxChar * wxStrncat(wxChar *dest, const wxChar *src, size_t n)
1069 {
1070 wxChar *ret = dest;
1071 while (*dest) dest++;
1072 while (n && (*dest++ = *src++)) n--;
1073 return ret;
1074 }
1075
1076 WXDLLEXPORT int wxStrncmp(const wxChar *s1, const wxChar *s2, size_t n)
1077 {
1078 while (n && (*s1 == *s2) && *s1) n--, s1++, s2++;
1079 if (n) {
1080 if ((wxUChar)*s1 < (wxUChar)*s2) return -1;
1081 if ((wxUChar)*s1 > (wxUChar)*s2) return 1;
1082 }
1083 return 0;
1084 }
1085
1086 WXDLLEXPORT wxChar * wxStrncpy(wxChar *dest, const wxChar *src, size_t n)
1087 {
1088 wxChar *ret = dest;
1089 while (n && (*dest++ = *src++)) n--;
1090 while (n) *dest++=0, n--; // the docs specify padding with zeroes
1091 return ret;
1092 }
1093
1094 WXDLLEXPORT const wxChar * wxStrpbrk(const wxChar *s, const wxChar *accept)
1095 {
1096 while (*s && !wxStrchr(accept, *s))
1097 s++;
1098
1099 return *s ? s : NULL;
1100 }
1101
1102 WXDLLEXPORT const wxChar * wxStrrchr(const wxChar *s, wxChar c)
1103 {
1104 const wxChar *ret = NULL;
1105 do
1106 {
1107 if ( *s == c )
1108 ret = s;
1109 s++;
1110 }
1111 while ( *s );
1112
1113 return ret;
1114 }
1115
1116 WXDLLEXPORT size_t wxStrspn(const wxChar *s, const wxChar *accept)
1117 {
1118 size_t len = 0;
1119 while (wxStrchr(accept, *s++)) len++;
1120 return len;
1121 }
1122
1123 WXDLLEXPORT const wxChar *wxStrstr(const wxChar *haystack, const wxChar *needle)
1124 {
1125 wxCHECK_RET( needle, NULL, _T("NULL argument in wxStrstr") );
1126
1127 // VZ: this is not exactly the most efficient string search algorithm...
1128
1129 const size_t len = wxStrlen(needle);
1130
1131 while ( const wxChar *fnd = wxStrchr(haystack, *needle) )
1132 {
1133 if ( !wxStrncmp(fnd, needle, len) )
1134 return fnd;
1135
1136 haystack = fnd + 1;
1137 }
1138
1139 return NULL;
1140 }
1141
1142 WXDLLEXPORT double wxStrtod(const wxChar *nptr, wxChar **endptr)
1143 {
1144 const wxChar *start = nptr;
1145
1146 // FIXME: only correct for C locale
1147 while (wxIsspace(*nptr)) nptr++;
1148 if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++;
1149 while (wxIsdigit(*nptr)) nptr++;
1150 if (*nptr == wxT('.')) {
1151 nptr++;
1152 while (wxIsdigit(*nptr)) nptr++;
1153 }
1154 if (*nptr == wxT('E') || *nptr == wxT('e')) {
1155 nptr++;
1156 if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++;
1157 while (wxIsdigit(*nptr)) nptr++;
1158 }
1159
1160 wxString data(nptr, nptr-start);
1161 wxWX2MBbuf dat = data.mb_str(wxConvLocal);
1162 char *rdat = wxMBSTRINGCAST dat;
1163 double ret = strtod(dat, &rdat);
1164
1165 if (endptr) *endptr = (wxChar *)(start + (rdat - (const char *)dat));
1166
1167 return ret;
1168 }
1169
1170 WXDLLEXPORT long int wxStrtol(const wxChar *nptr, wxChar **endptr, int base)
1171 {
1172 const wxChar *start = nptr;
1173
1174 // FIXME: only correct for C locale
1175 while (wxIsspace(*nptr)) nptr++;
1176 if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++;
1177 if (((base == 0) || (base == 16)) &&
1178 (nptr[0] == wxT('0') && nptr[1] == wxT('x'))) {
1179 nptr += 2;
1180 base = 16;
1181 }
1182 else if ((base == 0) && (nptr[0] == wxT('0'))) base = 8;
1183 else if (base == 0) base = 10;
1184
1185 while ((wxIsdigit(*nptr) && (*nptr - wxT('0') < base)) ||
1186 (wxIsalpha(*nptr) && (wxToupper(*nptr) - wxT('A') + 10 < base))) nptr++;
1187
1188 wxString data(nptr, nptr-start);
1189 wxWX2MBbuf dat = data.mb_str(wxConvLocal);
1190 char *rdat = wxMBSTRINGCAST dat;
1191 long int ret = strtol(dat, &rdat, base);
1192
1193 if (endptr) *endptr = (wxChar *)(start + (rdat - (const char *)dat));
1194
1195 return ret;
1196 }
1197 #endif // wxNEED_WX_STRING_H
1198
1199 #ifdef wxNEED_WX_STDIO_H
1200 WXDLLEXPORT FILE * wxFopen(const wxChar *path, const wxChar *mode)
1201 {
1202 char mode_buffer[10];
1203 for (size_t i = 0; i < wxStrlen(mode)+1; i++)
1204 mode_buffer[i] = (char) mode[i];
1205
1206 return fopen( wxConvFile.cWX2MB(path), mode_buffer );
1207 }
1208
1209 WXDLLEXPORT FILE * wxFreopen(const wxChar *path, const wxChar *mode, FILE *stream)
1210 {
1211 char mode_buffer[10];
1212 for (size_t i = 0; i < wxStrlen(mode)+1; i++)
1213 mode_buffer[i] = (char) mode[i];
1214
1215 return freopen( wxConvFile.cWX2MB(path), mode_buffer, stream );
1216 }
1217
1218 WXDLLEXPORT int wxRemove(const wxChar *path)
1219 {
1220 return remove( wxConvFile.cWX2MB(path) );
1221 }
1222
1223 WXDLLEXPORT int wxRename(const wxChar *oldpath, const wxChar *newpath)
1224 {
1225 return rename( wxConvFile.cWX2MB(oldpath), wxConvFile.cWX2MB(newpath) );
1226 }
1227 #endif
1228
1229 #ifndef wxAtof
1230 double WXDLLEXPORT wxAtof(const wxChar *psz)
1231 {
1232 return atof(wxConvLocal.cWX2MB(psz));
1233 }
1234 #endif
1235
1236 #ifdef wxNEED_WX_STDLIB_H
1237 int WXDLLEXPORT wxAtoi(const wxChar *psz)
1238 {
1239 return atoi(wxConvLocal.cWX2MB(psz));
1240 }
1241
1242 long WXDLLEXPORT wxAtol(const wxChar *psz)
1243 {
1244 return atol(wxConvLocal.cWX2MB(psz));
1245 }
1246
1247 wxChar * WXDLLEXPORT wxGetenv(const wxChar *name)
1248 {
1249 static wxHashTable env;
1250
1251 // check if we already have stored the converted env var
1252 wxObject *data = env.Get(name);
1253 if (!data)
1254 {
1255 // nope, retrieve it,
1256 #if wxUSE_UNICODE
1257 wxCharBuffer buffer = wxConvLocal.cWX2MB(name);
1258 // printf( "buffer %s\n", (const char*) buffer );
1259 const char *val = getenv( (const char *)buffer );
1260 #else
1261 const char *val = getenv( name );
1262 #endif
1263
1264 if (!val) return (wxChar *)NULL;
1265 // printf( "home %s\n", val );
1266
1267 // convert it,
1268 #ifdef wxUSE_UNICODE
1269 data = (wxObject *)new wxString(val, wxConvLocal);
1270 #else
1271 data = (wxObject *)new wxString(val);
1272 #endif
1273
1274 // and store it
1275 env.Put(name, data);
1276 }
1277 // return converted env var
1278 return (wxChar *)((wxString *)data)->c_str();
1279 }
1280
1281 int WXDLLEXPORT wxSystem(const wxChar *psz)
1282 {
1283 return system(wxConvLocal.cWX2MB(psz));
1284 }
1285
1286 #endif
1287
1288 #ifdef wxNEED_WX_TIME_H
1289 WXDLLEXPORT size_t wxStrftime(wxChar *s, size_t max, const wxChar *fmt, const struct tm *tm)
1290 {
1291 if (!max) return 0;
1292
1293 char *buf = (char *)malloc(max);
1294 size_t ret = strftime(buf, max, wxConvLocal.cWX2MB(fmt), tm);
1295 if (ret)
1296 {
1297 wxStrcpy(s, wxConvLocal.cMB2WX(buf));
1298 free(buf);
1299 return wxStrlen(s);
1300 }
1301 else
1302 {
1303 free(buf);
1304 *s = 0;
1305 return 0;
1306 }
1307 }
1308 #endif