1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/wxchar.cpp
3 // Purpose: wxChar implementation
4 // Author: Ove Kaven
5 // Modified by: Ron Lee, Francesco Montorsi
6 // Created: 09/04/99
7 // RCS-ID: $Id: wxchar.cpp 58994 2009-02-18 15:49:09Z FM $
8 // Copyright: (c) wxWidgets copyright
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ===========================================================================
13 // headers, declarations, constants
14 // ===========================================================================
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #include "wx/wxchar.h"
24
25 #define _ISOC9X_SOURCE 1 // to get vsscanf()
26 #define _BSD_SOURCE 1 // to still get strdup()
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #ifndef __WXWINCE__
33 #include <time.h>
34 #include <locale.h>
35 #else
36 #include "wx/msw/wince/time.h"
37 #endif
38
39 #ifndef WX_PRECOMP
40 #include "wx/string.h"
41 #include "wx/hash.h"
42 #include "wx/utils.h" // for wxMin and wxMax
43 #include "wx/log.h"
44 #endif
45
46 #if defined(__WIN32__) && defined(wxNEED_WX_CTYPE_H)
47 #include <windef.h>
48 #include <winbase.h>
49 #include <winnls.h>
50 #include <winnt.h>
51 #endif
52
53 #if defined(__MWERKS__) && __MSL__ >= 0x6000
54 namespace std {}
55 using namespace std ;
56 #endif
57
58 #if wxUSE_WCHAR_T
wxMB2WC(wchar_t * buf,const char * psz,size_t n)59 size_t WXDLLEXPORT wxMB2WC(wchar_t *buf, const char *psz, size_t n)
60 {
61 // assume that we have mbsrtowcs() too if we have wcsrtombs()
62 #ifdef HAVE_WCSRTOMBS
63 mbstate_t mbstate;
64 memset(&mbstate, 0, sizeof(mbstate_t));
65 #endif
66
67 if (buf) {
68 if (!n || !*psz) {
69 if (n) *buf = wxT('\0');
70 return 0;
71 }
72 #ifdef HAVE_WCSRTOMBS
73 return mbsrtowcs(buf, &psz, n, &mbstate);
74 #else
75 return wxMbstowcs(buf, psz, n);
76 #endif
77 }
78
79 // note that we rely on common (and required by Unix98 but unfortunately not
80 // C99) extension which allows to call mbs(r)towcs() with NULL output pointer
81 // to just get the size of the needed buffer -- this is needed as otherwise
82 // we have no idea about how much space we need and if the CRT doesn't
83 // support it (the only currently known example being Metrowerks, see
84 // wx/wxchar.h) we don't use its mbstowcs() at all
85 #ifdef HAVE_WCSRTOMBS
86 return mbsrtowcs((wchar_t *) NULL, &psz, 0, &mbstate);
87 #else
88 return wxMbstowcs((wchar_t *) NULL, psz, 0);
89 #endif
90 }
91
wxWC2MB(char * buf,const wchar_t * pwz,size_t n)92 size_t WXDLLEXPORT wxWC2MB(char *buf, const wchar_t *pwz, size_t n)
93 {
94 #ifdef HAVE_WCSRTOMBS
95 mbstate_t mbstate;
96 memset(&mbstate, 0, sizeof(mbstate_t));
97 #endif
98
99 if (buf) {
100 if (!n || !*pwz) {
101 // glibc2.1 chokes on null input
102 if (n) *buf = '\0';
103 return 0;
104 }
105 #ifdef HAVE_WCSRTOMBS
106 return wcsrtombs(buf, &pwz, n, &mbstate);
107 #else
108 return wxWcstombs(buf, pwz, n);
109 #endif
110 }
111
112 #ifdef HAVE_WCSRTOMBS
113 return wcsrtombs((char *) NULL, &pwz, 0, &mbstate);
114 #else
115 return wxWcstombs((char *) NULL, pwz, 0);
116 #endif
117 }
118 #endif // wxUSE_WCHAR_T
119
wxOKlibc()120 bool WXDLLEXPORT wxOKlibc()
121 {
122 #if wxUSE_WCHAR_T && defined(__UNIX__) && defined(__GLIBC__) && !defined(__WINE__)
123 // glibc 2.0 uses UTF-8 even when it shouldn't
124 wchar_t res = 0;
125 if ((MB_CUR_MAX == 2) &&
126 (wxMB2WC(&res, "\xdd\xa5", 1) == 1) &&
127 (res==0x765)) {
128 // this is UTF-8 allright, check whether that's what we want
129 char *cur_locale = setlocale(LC_CTYPE, NULL);
130 if ((strlen(cur_locale) < 4) ||
131 (strcasecmp(cur_locale + strlen(cur_locale) - 4, "utf8")) ||
132 (strcasecmp(cur_locale + strlen(cur_locale) - 5, "utf-8"))) {
133 // nope, don't use libc conversion
134 return false;
135 }
136 }
137 #endif
138 return true;
139 }
140
141 // ============================================================================
142 // printf() functions business
143 // ============================================================================
144
145 // special test mode: define all functions below even if we don't really need
146 // them to be able to test them
147 #ifdef wxTEST_PRINTF
148 #undef wxFprintf
149 #undef wxPrintf
150 #undef wxSprintf
151 #undef wxVfprintf
152 #undef wxVsprintf
153 #undef wxVprintf
154 #undef wxVsnprintf_
155 #undef wxSnprintf_
156
157 #define wxNEED_WPRINTF
158
159 int wxVfprintf( FILE *stream, const wxChar *format, va_list argptr );
160 #endif
161
162 // ----------------------------------------------------------------------------
163 // implement [v]snprintf() if the system doesn't provide a safe one
164 // or if the system's one does not support positional parameters
165 // (very useful for i18n purposes)
166 // ----------------------------------------------------------------------------
167
168 #if !defined(wxVsnprintf_)
169
170 #if !wxUSE_WXVSNPRINTF
171 #error wxUSE_WXVSNPRINTF must be 1 if our wxVsnprintf_ is used
172 #endif
173
174 // wxUSE_STRUTILS says our wxVsnprintf_ implementation to use or not to
175 // use wxStrlen and wxStrncpy functions over one-char processing loops.
176 //
177 // Some benchmarking revealed that wxUSE_STRUTILS == 1 has the following
178 // effects:
179 // -> on Windows:
180 // when in ANSI mode, this setting does not change almost anything
181 // when in Unicode mode, it gives ~ 50% of slowdown !
182 // -> on Linux:
183 // both in ANSI and Unicode mode it gives ~ 60% of speedup !
184 //
185 #if defined(WIN32) && wxUSE_UNICODE
186 #define wxUSE_STRUTILS 0
187 #else
188 #define wxUSE_STRUTILS 1
189 #endif
190
191 // some limits of our implementation
192 #define wxMAX_SVNPRINTF_ARGUMENTS 64
193 #define wxMAX_SVNPRINTF_FLAGBUFFER_LEN 32
194 #define wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN 512
195
196 // prefer snprintf over sprintf
197 #if defined(__VISUALC__) || \
198 (defined(__BORLANDC__) && __BORLANDC__ >= 0x540)
199 #define system_sprintf(buff, max, flags, data) \
200 ::_snprintf(buff, max, flags, data)
201 #elif defined(HAVE_SNPRINTF)
202 #define system_sprintf(buff, max, flags, data) \
203 ::snprintf(buff, max, flags, data)
204 #else // NB: at least sprintf() should always be available
205 // since 'max' is not used in this case, wxVsnprintf() should always
206 // ensure that 'buff' is big enough for all common needs
207 // (see wxMAX_SVNPRINTF_FLAGBUFFER_LEN and wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN)
208 #define system_sprintf(buff, max, flags, data) \
209 ::sprintf(buff, flags, data)
210
211 #define SYSTEM_SPRINTF_IS_UNSAFE
212 #endif
213
214 // the conversion specifiers accepted by wxVsnprintf_
215 enum wxPrintfArgType {
216 wxPAT_INVALID = -1,
217
218 wxPAT_INT, // %d, %i, %o, %u, %x, %X
219 wxPAT_LONGINT, // %ld, etc
220 #ifdef wxLongLong_t
221 wxPAT_LONGLONGINT, // %Ld, etc
222 #endif
223 wxPAT_SIZET, // %Zd, etc
224
225 wxPAT_DOUBLE, // %e, %E, %f, %g, %G
226 wxPAT_LONGDOUBLE, // %le, etc
227
228 wxPAT_POINTER, // %p
229
230 wxPAT_CHAR, // %hc (in ANSI mode: %c, too)
231 wxPAT_WCHAR, // %lc (in Unicode mode: %c, too)
232
233 wxPAT_PCHAR, // %s (related to a char *)
234 wxPAT_PWCHAR, // %s (related to a wchar_t *)
235
236 wxPAT_NINT, // %n
237 wxPAT_NSHORTINT, // %hn
238 wxPAT_NLONGINT // %ln
239 };
240
241 // an argument passed to wxVsnprintf_
242 typedef union {
243 int pad_int; // %d, %i, %o, %u, %x, %X
244 long int pad_longint; // %ld, etc
245 #ifdef wxLongLong_t
246 wxLongLong_t pad_longlongint; // %Ld, etc
247 #endif
248 size_t pad_sizet; // %Zd, etc
249
250 double pad_double; // %e, %E, %f, %g, %G
251 long double pad_longdouble; // %le, etc
252
253 void *pad_pointer; // %p
254
255 char pad_char; // %hc (in ANSI mode: %c, too)
256 wchar_t pad_wchar; // %lc (in Unicode mode: %c, too)
257
258 char *pad_pchar; // %s (related to a char *)
259 wchar_t *pad_pwchar; // %s (related to a wchar_t *)
260
261 int *pad_nint; // %n
262 short int *pad_nshortint; // %hn
263 long int *pad_nlongint; // %ln
264 } wxPrintfArg;
265
266
267 // Contains parsed data relative to a conversion specifier given to
268 // wxVsnprintf_ and parsed from the format string
269 // NOTE: in C++ there is almost no difference between struct & classes thus
270 // there is no performance gain by using a struct here...
271 class wxPrintfConvSpec
272 {
273 public:
274
275 // the position of the argument relative to this conversion specifier
276 size_t m_pos;
277
278 // the type of this conversion specifier
279 wxPrintfArgType m_type;
280
281 // the minimum and maximum width
282 // when one of this var is set to -1 it means: use the following argument
283 // in the stack as minimum/maximum width for this conversion specifier
284 int m_nMinWidth, m_nMaxWidth;
285
286 // does the argument need to the be aligned to left ?
287 bool m_bAlignLeft;
288
289 // pointer to the '%' of this conversion specifier in the format string
290 // NOTE: this points somewhere in the string given to the Parse() function -
291 // it's task of the caller ensure that memory is still valid !
292 const wxChar *m_pArgPos;
293
294 // pointer to the last character of this conversion specifier in the
295 // format string
296 // NOTE: this points somewhere in the string given to the Parse() function -
297 // it's task of the caller ensure that memory is still valid !
298 const wxChar *m_pArgEnd;
299
300 // a little buffer where formatting flags like #+\.hlqLZ are stored by Parse()
301 // for use in Process()
302 // NB: even if this buffer is used only for numeric conversion specifiers and
303 // thus could be safely declared as a char[] buffer, we want it to be wxChar
304 // so that in Unicode builds we can avoid to convert its contents to Unicode
305 // chars when copying it in user's buffer.
306 char m_szFlags[wxMAX_SVNPRINTF_FLAGBUFFER_LEN];
307
308
309 public:
310
311 // we don't declare this as a constructor otherwise it would be called
312 // automatically and we don't want this: to be optimized, wxVsnprintf_
313 // calls this function only on really-used instances of this class.
314 void Init();
315
316 // Parses the first conversion specifier in the given string, which must
317 // begin with a '%'. Returns false if the first '%' does not introduce a
318 // (valid) conversion specifier and thus should be ignored.
319 bool Parse(const wxChar *format);
320
321 // Process this conversion specifier and puts the result in the given
322 // buffer. Returns the number of characters written in 'buf' or -1 if
323 // there's not enough space.
324 int Process(wxChar *buf, size_t lenMax, wxPrintfArg *p, size_t written);
325
326 // Loads the argument of this conversion specifier from given va_list.
327 bool LoadArg(wxPrintfArg *p, va_list &argptr);
328
329 private:
330 // An helper function of LoadArg() which is used to handle the '*' flag
331 void ReplaceAsteriskWith(int w);
332 };
333
Init()334 void wxPrintfConvSpec::Init()
335 {
336 m_nMinWidth = 0;
337 m_nMaxWidth = 0xFFFF;
338 m_pos = 0;
339 m_bAlignLeft = false;
340 m_pArgPos = m_pArgEnd = NULL;
341 m_type = wxPAT_INVALID;
342
343 // this character will never be removed from m_szFlags array and
344 // is important when calling sprintf() in wxPrintfConvSpec::Process() !
345 m_szFlags[0] = '%';
346 }
347
Parse(const wxChar * format)348 bool wxPrintfConvSpec::Parse(const wxChar *format)
349 {
350 bool done = false;
351
352 // temporary parse data
353 size_t flagofs = 1;
354 bool in_prec, // true if we found the dot in some previous iteration
355 prec_dot; // true if the dot has been already added to m_szFlags
356 int ilen = 0;
357
358 m_bAlignLeft = in_prec = prec_dot = false;
359 m_pArgPos = m_pArgEnd = format;
360 do
361 {
362 #define CHECK_PREC \
363 if (in_prec && !prec_dot) \
364 { \
365 m_szFlags[flagofs++] = '.'; \
366 prec_dot = true; \
367 }
368
369 // what follows '%'?
370 const wxChar ch = *(++m_pArgEnd);
371 switch ( ch )
372 {
373 case wxT('\0'):
374 return false; // not really an argument
375
376 case wxT('%'):
377 return false; // not really an argument
378
379 case wxT('#'):
380 case wxT('0'):
381 case wxT(' '):
382 case wxT('+'):
383 case wxT('\''):
384 CHECK_PREC
385 m_szFlags[flagofs++] = char(ch);
386 break;
387
388 case wxT('-'):
389 CHECK_PREC
390 m_bAlignLeft = true;
391 m_szFlags[flagofs++] = char(ch);
392 break;
393
394 case wxT('.'):
395 CHECK_PREC
396 in_prec = true;
397 prec_dot = false;
398 m_nMaxWidth = 0;
399 // dot will be auto-added to m_szFlags if non-negative
400 // number follows
401 break;
402
403 case wxT('h'):
404 ilen = -1;
405 CHECK_PREC
406 m_szFlags[flagofs++] = char(ch);
407 break;
408
409 case wxT('l'):
410 // NB: it's safe to use flagofs-1 as flagofs always start from 1
411 if (m_szFlags[flagofs-1] == 'l') // 'll' modifier is the same as 'L' or 'q'
412 ilen = 2;
413 else
414 ilen = 1;
415 CHECK_PREC
416 m_szFlags[flagofs++] = char(ch);
417 break;
418
419 case wxT('q'):
420 case wxT('L'):
421 ilen = 2;
422 CHECK_PREC
423 m_szFlags[flagofs++] = char(ch);
424 break;
425 #ifdef __WXMSW__
426 // under Windows we support the special '%I64' notation as longlong
427 // integer conversion specifier for MSVC compatibility
428 // (it behaves exactly as '%lli' or '%Li' or '%qi')
429 case wxT('I'):
430 if (*(m_pArgEnd+1) != wxT('6') ||
431 *(m_pArgEnd+2) != wxT('4'))
432 return false; // bad format
433
434 m_pArgEnd++;
435 m_pArgEnd++;
436
437 ilen = 2;
438 CHECK_PREC
439 m_szFlags[flagofs++] = char(ch);
440 m_szFlags[flagofs++] = '6';
441 m_szFlags[flagofs++] = '4';
442 break;
443 #endif // __WXMSW__
444
445 case wxT('Z'):
446 ilen = 3;
447 CHECK_PREC
448 m_szFlags[flagofs++] = char(ch);
449 break;
450
451 case wxT('*'):
452 if (in_prec)
453 {
454 CHECK_PREC
455
456 // tell Process() to use the next argument
457 // in the stack as maxwidth...
458 m_nMaxWidth = -1;
459 }
460 else
461 {
462 // tell Process() to use the next argument
463 // in the stack as minwidth...
464 m_nMinWidth = -1;
465 }
466
467 // save the * in our formatting buffer...
468 // will be replaced later by Process()
469 m_szFlags[flagofs++] = char(ch);
470 break;
471
472 case wxT('1'): case wxT('2'): case wxT('3'):
473 case wxT('4'): case wxT('5'): case wxT('6'):
474 case wxT('7'): case wxT('8'): case wxT('9'):
475 {
476 int len = 0;
477 CHECK_PREC
478 while ( (*m_pArgEnd >= wxT('0')) &&
479 (*m_pArgEnd <= wxT('9')) )
480 {
481 m_szFlags[flagofs++] = char(*m_pArgEnd);
482 len = len*10 + (*m_pArgEnd - wxT('0'));
483 m_pArgEnd++;
484 }
485
486 if (in_prec)
487 m_nMaxWidth = len;
488 else
489 m_nMinWidth = len;
490
491 m_pArgEnd--; // the main loop pre-increments n again
492 }
493 break;
494
495 case wxT('$'): // a positional parameter (e.g. %2$s) ?
496 {
497 if (m_nMinWidth <= 0)
498 break; // ignore this formatting flag as no
499 // numbers are preceding it
500
501 // remove from m_szFlags all digits previously added
502 do {
503 flagofs--;
504 } while (m_szFlags[flagofs] >= '1' &&
505 m_szFlags[flagofs] <= '9');
506
507 // re-adjust the offset making it point to the
508 // next free char of m_szFlags
509 flagofs++;
510
511 m_pos = m_nMinWidth;
512 m_nMinWidth = 0;
513 }
514 break;
515
516 case wxT('d'):
517 case wxT('i'):
518 case wxT('o'):
519 case wxT('u'):
520 case wxT('x'):
521 case wxT('X'):
522 CHECK_PREC
523 m_szFlags[flagofs++] = char(ch);
524 m_szFlags[flagofs] = '\0';
525 if (ilen == 0)
526 m_type = wxPAT_INT;
527 else if (ilen == -1)
528 // NB: 'short int' value passed through '...'
529 // is promoted to 'int', so we have to get
530 // an int from stack even if we need a short
531 m_type = wxPAT_INT;
532 else if (ilen == 1)
533 m_type = wxPAT_LONGINT;
534 else if (ilen == 2)
535 #ifdef wxLongLong_t
536 m_type = wxPAT_LONGLONGINT;
537 #else // !wxLongLong_t
538 m_type = wxPAT_LONGINT;
539 #endif // wxLongLong_t/!wxLongLong_t
540 else if (ilen == 3)
541 m_type = wxPAT_SIZET;
542 done = true;
543 break;
544
545 case wxT('e'):
546 case wxT('E'):
547 case wxT('f'):
548 case wxT('g'):
549 case wxT('G'):
550 CHECK_PREC
551 m_szFlags[flagofs++] = char(ch);
552 m_szFlags[flagofs] = '\0';
553 if (ilen == 2)
554 m_type = wxPAT_LONGDOUBLE;
555 else
556 m_type = wxPAT_DOUBLE;
557 done = true;
558 break;
559
560 case wxT('p'):
561 m_type = wxPAT_POINTER;
562 m_szFlags[flagofs++] = char(ch);
563 m_szFlags[flagofs] = '\0';
564 done = true;
565 break;
566
567 case wxT('c'):
568 m_szFlags[flagofs++] = char(ch);
569 m_szFlags[flagofs] = '\0';
570 if (ilen == -1)
571 {
572 // in Unicode mode %hc == ANSI character
573 // and in ANSI mode, %hc == %c == ANSI...
574 m_type = wxPAT_CHAR;
575 }
576 else if (ilen == 1)
577 {
578 // in ANSI mode %lc == Unicode character
579 // and in Unicode mode, %lc == %c == Unicode...
580 m_type = wxPAT_WCHAR;
581 }
582 else
583 {
584 #if wxUSE_UNICODE
585 // in Unicode mode, %c == Unicode character
586 m_type = wxPAT_WCHAR;
587 #else
588 // in ANSI mode, %c == ANSI character
589 m_type = wxPAT_CHAR;
590 #endif
591 }
592 done = true;
593 break;
594
595 case wxT('s'):
596 m_szFlags[flagofs++] = char(ch);
597 m_szFlags[flagofs] = '\0';
598 if (ilen == -1)
599 {
600 // Unicode mode wx extension: we'll let %hs mean non-Unicode
601 // strings (when in ANSI mode, %s == %hs == ANSI string)
602 m_type = wxPAT_PCHAR;
603 }
604 else if (ilen == 1)
605 {
606 // in Unicode mode, %ls == %s == Unicode string
607 // in ANSI mode, %ls == Unicode string
608 m_type = wxPAT_PWCHAR;
609 }
610 else
611 {
612 #if wxUSE_UNICODE
613 m_type = wxPAT_PWCHAR;
614 #else
615 m_type = wxPAT_PCHAR;
616 #endif
617 }
618 done = true;
619 break;
620
621 case wxT('n'):
622 m_szFlags[flagofs++] = char(ch);
623 m_szFlags[flagofs] = '\0';
624 if (ilen == 0)
625 m_type = wxPAT_NINT;
626 else if (ilen == -1)
627 m_type = wxPAT_NSHORTINT;
628 else if (ilen >= 1)
629 m_type = wxPAT_NLONGINT;
630 done = true;
631 break;
632
633 default:
634 // bad format, don't consider this an argument;
635 // leave it unchanged
636 return false;
637 }
638
639 if (flagofs == wxMAX_SVNPRINTF_FLAGBUFFER_LEN)
640 {
641 wxLogDebug(wxT("Too many flags specified for a single conversion specifier!"));
642 return false;
643 }
644 }
645 while (!done);
646
647 return true; // parsing was successful
648 }
649
650
ReplaceAsteriskWith(int width)651 void wxPrintfConvSpec::ReplaceAsteriskWith(int width)
652 {
653 char temp[wxMAX_SVNPRINTF_FLAGBUFFER_LEN];
654
655 // find the first * in our flag buffer
656 char *pwidth = strchr(m_szFlags, '*');
657 wxCHECK_RET(pwidth, _T("field width must be specified"));
658
659 // save what follows the * (the +1 is to skip the asterisk itself!)
660 strcpy(temp, pwidth+1);
661 if (width < 0)
662 {
663 pwidth[0] = wxT('-');
664 pwidth++;
665 }
666
667 // replace * with the actual integer given as width
668 #ifndef SYSTEM_SPRINTF_IS_UNSAFE
669 int maxlen = (m_szFlags + wxMAX_SVNPRINTF_FLAGBUFFER_LEN - pwidth) /
670 sizeof(*m_szFlags);
671 #endif
672 int offset = system_sprintf(pwidth, maxlen, "%d", abs(width));
673
674 // restore after the expanded * what was following it
675 strcpy(pwidth+offset, temp);
676 }
677
LoadArg(wxPrintfArg * p,va_list & argptr)678 bool wxPrintfConvSpec::LoadArg(wxPrintfArg *p, va_list &argptr)
679 {
680 // was the '*' width/precision specifier used ?
681 if (m_nMaxWidth == -1)
682 {
683 // take the maxwidth specifier from the stack
684 m_nMaxWidth = va_arg(argptr, int);
685 if (m_nMaxWidth < 0)
686 m_nMaxWidth = 0;
687 else
688 ReplaceAsteriskWith(m_nMaxWidth);
689 }
690
691 if (m_nMinWidth == -1)
692 {
693 // take the minwidth specifier from the stack
694 m_nMinWidth = va_arg(argptr, int);
695
696 ReplaceAsteriskWith(m_nMinWidth);
697 if (m_nMinWidth < 0)
698 {
699 m_bAlignLeft = !m_bAlignLeft;
700 m_nMinWidth = -m_nMinWidth;
701 }
702 }
703
704 switch (m_type) {
705 case wxPAT_INT:
706 p->pad_int = va_arg(argptr, int);
707 break;
708 case wxPAT_LONGINT:
709 p->pad_longint = va_arg(argptr, long int);
710 break;
711 #ifdef wxLongLong_t
712 case wxPAT_LONGLONGINT:
713 p->pad_longlongint = va_arg(argptr, wxLongLong_t);
714 break;
715 #endif // wxLongLong_t
716 case wxPAT_SIZET:
717 p->pad_sizet = va_arg(argptr, size_t);
718 break;
719 case wxPAT_DOUBLE:
720 p->pad_double = va_arg(argptr, double);
721 break;
722 case wxPAT_LONGDOUBLE:
723 p->pad_longdouble = va_arg(argptr, long double);
724 break;
725 case wxPAT_POINTER:
726 p->pad_pointer = va_arg(argptr, void *);
727 break;
728
729 case wxPAT_CHAR:
730 p->pad_char = (char)va_arg(argptr, int); // char is promoted to int when passed through '...'
731 break;
732 case wxPAT_WCHAR:
733 p->pad_wchar = (wchar_t)va_arg(argptr, int); // char is promoted to int when passed through '...'
734 break;
735
736 case wxPAT_PCHAR:
737 p->pad_pchar = va_arg(argptr, char *);
738 break;
739 case wxPAT_PWCHAR:
740 p->pad_pwchar = va_arg(argptr, wchar_t *);
741 break;
742
743 case wxPAT_NINT:
744 p->pad_nint = va_arg(argptr, int *);
745 break;
746 case wxPAT_NSHORTINT:
747 p->pad_nshortint = va_arg(argptr, short int *);
748 break;
749 case wxPAT_NLONGINT:
750 p->pad_nlongint = va_arg(argptr, long int *);
751 break;
752
753 case wxPAT_INVALID:
754 default:
755 return false;
756 }
757
758 return true; // loading was successful
759 }
760
Process(wxChar * buf,size_t lenMax,wxPrintfArg * p,size_t written)761 int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p, size_t written)
762 {
763 // buffer to avoid dynamic memory allocation each time for small strings;
764 // note that this buffer is used only to hold results of number formatting,
765 // %s directly writes user's string in buf, without using szScratch
766 char szScratch[wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN];
767 size_t lenScratch = 0, lenCur = 0;
768
769 #define APPEND_CH(ch) \
770 { \
771 if ( lenCur == lenMax ) \
772 return -1; \
773 \
774 buf[lenCur++] = ch; \
775 }
776
777 #define APPEND_STR(s) \
778 { \
779 for ( const wxChar *p = s; *p; p++ ) \
780 { \
781 APPEND_CH(*p); \
782 } \
783 }
784
785 switch ( m_type )
786 {
787 case wxPAT_INT:
788 lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_int);
789 break;
790
791 case wxPAT_LONGINT:
792 lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_longint);
793 break;
794
795 #ifdef wxLongLong_t
796 case wxPAT_LONGLONGINT:
797 lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_longlongint);
798 break;
799 #endif // SIZEOF_LONG_LONG
800
801 case wxPAT_SIZET:
802 lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_sizet);
803 break;
804
805 case wxPAT_LONGDOUBLE:
806 lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_longdouble);
807 break;
808
809 case wxPAT_DOUBLE:
810 lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_double);
811 break;
812
813 case wxPAT_POINTER:
814 lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_pointer);
815 break;
816
817 case wxPAT_CHAR:
818 case wxPAT_WCHAR:
819 {
820 wxChar val =
821 #if wxUSE_UNICODE
822 p->pad_wchar;
823
824 if (m_type == wxPAT_CHAR)
825 {
826 // user passed a character explicitely indicated as ANSI...
827 const char buf[2] = { p->pad_char, 0 };
828 val = wxString(buf, wxConvLibc)[0u];
829
830 //wprintf(L"converting ANSI=>Unicode"); // for debug
831 }
832 #else
833 p->pad_char;
834
835 #if wxUSE_WCHAR_T
836 if (m_type == wxPAT_WCHAR)
837 {
838 // user passed a character explicitely indicated as Unicode...
839 const wchar_t buf[2] = { p->pad_wchar, 0 };
840 val = wxString(buf, wxConvLibc)[0u];
841
842 //printf("converting Unicode=>ANSI"); // for debug
843 }
844 #endif
845 #endif
846
847 size_t i;
848
849 if (!m_bAlignLeft)
850 for (i = 1; i < (size_t)m_nMinWidth; i++)
851 APPEND_CH(_T(' '));
852
853 APPEND_CH(val);
854
855 if (m_bAlignLeft)
856 for (i = 1; i < (size_t)m_nMinWidth; i++)
857 APPEND_CH(_T(' '));
858 }
859 break;
860
861 case wxPAT_PCHAR:
862 case wxPAT_PWCHAR:
863 {
864 wxString s;
865 const wxChar *val =
866 #if wxUSE_UNICODE
867 p->pad_pwchar;
868
869 if (m_type == wxPAT_PCHAR)
870 {
871 // user passed a string explicitely indicated as ANSI...
872 val = s = wxString(p->pad_pchar, wxConvLibc);
873
874 //wprintf(L"converting ANSI=>Unicode"); // for debug
875 }
876 #else
877 p->pad_pchar;
878
879 #if wxUSE_WCHAR_T
880 if (m_type == wxPAT_PWCHAR)
881 {
882 // user passed a string explicitely indicated as Unicode...
883 val = s = wxString(p->pad_pwchar, wxConvLibc);
884
885 //printf("converting Unicode=>ANSI"); // for debug
886 }
887 #endif
888 #endif
889 int len;
890
891 if (val)
892 {
893 #if wxUSE_STRUTILS
894 // at this point we are sure that m_nMaxWidth is positive or null
895 // (see top of wxPrintfConvSpec::LoadArg)
896 len = wxMin((unsigned int)m_nMaxWidth, wxStrlen(val));
897 #else
898 for ( len = 0; val[len] && (len < m_nMaxWidth); len++ )
899 ;
900 #endif
901 }
902 else if (m_nMaxWidth >= 6)
903 {
904 val = wxT("(null)");
905 len = 6;
906 }
907 else
908 {
909 val = wxEmptyString;
910 len = 0;
911 }
912
913 int i;
914
915 if (!m_bAlignLeft)
916 {
917 for (i = len; i < m_nMinWidth; i++)
918 APPEND_CH(_T(' '));
919 }
920
921 #if wxUSE_STRUTILS
922 len = wxMin((unsigned int)len, lenMax-lenCur);
923 wxStrncpy(buf+lenCur, val, len);
924 lenCur += len;
925 #else
926 for (i = 0; i < len; i++)
927 APPEND_CH(val[i]);
928 #endif
929
930 if (m_bAlignLeft)
931 {
932 for (i = len; i < m_nMinWidth; i++)
933 APPEND_CH(_T(' '));
934 }
935 }
936 break;
937
938 case wxPAT_NINT:
939 *p->pad_nint = written;
940 break;
941
942 case wxPAT_NSHORTINT:
943 *p->pad_nshortint = (short int)written;
944 break;
945
946 case wxPAT_NLONGINT:
947 *p->pad_nlongint = written;
948 break;
949
950 case wxPAT_INVALID:
951 default:
952 return -1;
953 }
954
955 // if we used system's sprintf() then we now need to append the s_szScratch
956 // buffer to the given one...
957 switch (m_type)
958 {
959 case wxPAT_INT:
960 case wxPAT_LONGINT:
961 #ifdef wxLongLong_t
962 case wxPAT_LONGLONGINT:
963 #endif
964 case wxPAT_SIZET:
965 case wxPAT_LONGDOUBLE:
966 case wxPAT_DOUBLE:
967 case wxPAT_POINTER:
968 wxASSERT(lenScratch < wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN);
969 #if !wxUSE_UNICODE
970 {
971 if (lenMax < lenScratch)
972 {
973 // fill output buffer and then return -1
974 wxStrncpy(buf, szScratch, lenMax);
975 return -1;
976 }
977 wxStrncpy(buf, szScratch, lenScratch);
978 lenCur += lenScratch;
979 }
980 #else
981 {
982 // Copy the char scratch to the wide output. This requires
983 // conversion, but we can optimise by making use of the fact
984 // that we are formatting numbers, this should mean only 7-bit
985 // ascii characters are involved.
986 wxChar *bufptr = buf;
987 const wxChar *bufend = buf + lenMax;
988 const char *scratchptr = szScratch;
989
990 // Simply copy each char to a wxChar, stopping on the first
991 // null or non-ascii byte. Checking '(signed char)*scratchptr
992 // > 0' is an extra optimisation over '*scratchptr != 0 &&
993 // isascii(*scratchptr)', though it assumes signed char is
994 // 8-bit 2 complement.
995 while ((signed char)*scratchptr > 0 && bufptr != bufend)
996 *bufptr++ = *scratchptr++;
997
998 if (bufptr == bufend)
999 return -1;
1000
1001 lenCur += bufptr - buf;
1002
1003 // check if the loop stopped on a non-ascii char, if yes then
1004 // fall back to wxMB2WX
1005 if (*scratchptr)
1006 {
1007 size_t len = wxMB2WX(bufptr, scratchptr, bufend - bufptr);
1008
1009 if (len && len != (size_t)(-1))
1010 if (bufptr[len - 1])
1011 return -1;
1012 else
1013 lenCur += len;
1014 }
1015 }
1016 #endif
1017 break;
1018
1019 default:
1020 break; // all other cases were completed previously
1021 }
1022
1023 return lenCur;
1024 }
1025
1026 // Copy chars from source to dest converting '%%' to '%'. Takes at most maxIn
1027 // chars from source and write at most outMax chars to dest, returns the
1028 // number of chars actually written. Does not treat null specially.
1029 //
wxCopyStrWithPercents(size_t maxOut,wxChar * dest,size_t maxIn,const wxChar * source)1030 static int wxCopyStrWithPercents(
1031 size_t maxOut,
1032 wxChar *dest,
1033 size_t maxIn,
1034 const wxChar *source)
1035 {
1036 size_t written = 0;
1037
1038 if (maxIn == 0)
1039 return 0;
1040
1041 size_t i;
1042 for ( i = 0; i < maxIn-1 && written < maxOut; source++, i++)
1043 {
1044 dest[written++] = *source;
1045 if (*(source+1) == wxT('%'))
1046 {
1047 // skip this additional '%' character
1048 source++;
1049 i++;
1050 }
1051 }
1052
1053 if (i < maxIn && written < maxOut)
1054 // copy last character inconditionally
1055 dest[written++] = *source;
1056
1057 return written;
1058 }
1059
wxVsnprintf_(wxChar * buf,size_t lenMax,const wxChar * format,va_list argptr)1060 int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax,
1061 const wxChar *format, va_list argptr)
1062 {
1063 // useful for debugging, to understand if we are really using this function
1064 // rather than the system implementation
1065 #if 0
1066 wprintf(L"Using wxVsnprintf_\n");
1067 #endif
1068
1069 // required memory:
1070 wxPrintfConvSpec arg[wxMAX_SVNPRINTF_ARGUMENTS];
1071 wxPrintfArg argdata[wxMAX_SVNPRINTF_ARGUMENTS];
1072 wxPrintfConvSpec *pspec[wxMAX_SVNPRINTF_ARGUMENTS] = { NULL };
1073
1074 size_t i;
1075
1076 // number of characters in the buffer so far, must be less than lenMax
1077 size_t lenCur = 0;
1078
1079 size_t nargs = 0;
1080 const wxChar *toparse = format;
1081
1082 // parse the format string
1083 bool posarg_present = false, nonposarg_present = false;
1084 for (; *toparse != wxT('\0'); toparse++)
1085 {
1086 if (*toparse == wxT('%') )
1087 {
1088 arg[nargs].Init();
1089
1090 // let's see if this is a (valid) conversion specifier...
1091 if (arg[nargs].Parse(toparse))
1092 {
1093 // ...yes it is
1094 wxPrintfConvSpec *current = &arg[nargs];
1095
1096 // make toparse point to the end of this specifier
1097 toparse = current->m_pArgEnd;
1098
1099 if (current->m_pos > 0)
1100 {
1101 // the positionals start from number 1... adjust the index
1102 current->m_pos--;
1103 posarg_present = true;
1104 }
1105 else
1106 {
1107 // not a positional argument...
1108 current->m_pos = nargs;
1109 nonposarg_present = true;
1110 }
1111
1112 // this conversion specifier is tied to the pos-th argument...
1113 pspec[current->m_pos] = current;
1114 nargs++;
1115
1116 if (nargs == wxMAX_SVNPRINTF_ARGUMENTS)
1117 {
1118 wxLogDebug(wxT("A single call to wxVsnprintf() has more than %d arguments; ")
1119 wxT("ignoring all remaining arguments."), wxMAX_SVNPRINTF_ARGUMENTS);
1120 break; // cannot handle any additional conv spec
1121 }
1122 }
1123 else
1124 {
1125 // it's safe to look in the next character of toparse as at worst
1126 // we'll hit its \0
1127 if (*(toparse+1) == wxT('%'))
1128 toparse++; // the Parse() returned false because we've found a %%
1129 }
1130 }
1131 }
1132
1133 if (posarg_present && nonposarg_present)
1134 {
1135 buf[0] = 0;
1136 return -1; // format strings with both positional and
1137 } // non-positional conversion specifier are unsupported !!
1138
1139 // on platforms where va_list is an array type, it is necessary to make a
1140 // copy to be able to pass it to LoadArg as a reference.
1141 bool ok = true;
1142 va_list ap;
1143 wxVaCopy(ap, argptr);
1144
1145 // now load arguments from stack
1146 for (i=0; i < nargs && ok; i++)
1147 {
1148 // !pspec[i] means that the user forgot a positional parameter (e.g. %$1s %$3s);
1149 // LoadArg == false means that wxPrintfConvSpec::Parse failed to set the
1150 // conversion specifier 'type' to a valid value...
1151 ok = pspec[i] && pspec[i]->LoadArg(&argdata[i], ap);
1152 }
1153
1154 va_end(ap);
1155
1156 // something failed while loading arguments from the variable list...
1157 // (e.g. the user repeated twice the same positional argument)
1158 if (!ok)
1159 {
1160 buf[0] = 0;
1161 return -1;
1162 }
1163
1164 // finally, process each conversion specifier with its own argument
1165 toparse = format;
1166 for (i=0; i < nargs; i++)
1167 {
1168 // copy in the output buffer the portion of the format string between
1169 // last specifier and the current one
1170 size_t tocopy = ( arg[i].m_pArgPos - toparse );
1171
1172 lenCur += wxCopyStrWithPercents(lenMax - lenCur, buf + lenCur,
1173 tocopy, toparse);
1174 if (lenCur == lenMax)
1175 {
1176 buf[lenMax - 1] = 0;
1177 return lenMax+1; // not enough space in the output buffer !
1178 }
1179
1180 // process this specifier directly in the output buffer
1181 int n = arg[i].Process(buf+lenCur, lenMax - lenCur, &argdata[arg[i].m_pos], lenCur);
1182 if (n == -1)
1183 {
1184 buf[lenMax-1] = wxT('\0'); // be sure to always NUL-terminate the string
1185 return lenMax+1; // not enough space in the output buffer !
1186 }
1187 lenCur += n;
1188
1189 // the +1 is because wxPrintfConvSpec::m_pArgEnd points to the last character
1190 // of the format specifier, but we are not interested to it...
1191 toparse = arg[i].m_pArgEnd + 1;
1192 }
1193
1194 // copy portion of the format string after last specifier
1195 // NOTE: toparse is pointing to the character just after the last processed
1196 // conversion specifier
1197 // NOTE2: the +1 is because we want to copy also the '\0'
1198 size_t tocopy = wxStrlen(format) + 1 - ( toparse - format ) ;
1199
1200 lenCur += wxCopyStrWithPercents(lenMax - lenCur, buf + lenCur,
1201 tocopy, toparse) - 1;
1202 if (buf[lenCur])
1203 {
1204 buf[lenCur] = 0;
1205 return lenMax+1; // not enough space in the output buffer !
1206 }
1207
1208 // Don't do:
1209 // wxASSERT(lenCur == wxStrlen(buf));
1210 // in fact if we embedded NULLs in the output buffer (using %c with a '\0')
1211 // such check would fail
1212
1213 return lenCur;
1214 }
1215
1216 #undef APPEND_CH
1217 #undef APPEND_STR
1218 #undef CHECK_PREC
1219
1220 #else // wxVsnprintf_ is defined
1221
1222 #if wxUSE_WXVSNPRINTF
1223 #error wxUSE_WXVSNPRINTF must be 0 if our wxVsnprintf_ is not used
1224 #endif
1225
1226 #endif // !wxVsnprintf_
1227
1228 #if !defined(wxSnprintf_)
wxSnprintf_(wxChar * buf,size_t len,const wxChar * format,...)1229 int WXDLLEXPORT wxSnprintf_(wxChar *buf, size_t len, const wxChar *format, ...)
1230 {
1231 va_list argptr;
1232 va_start(argptr, format);
1233
1234 int iLen = wxVsnprintf_(buf, len, format, argptr);
1235
1236 va_end(argptr);
1237
1238 return iLen;
1239 }
1240 #endif // wxSnprintf_
1241
1242 #if defined(__DMC__)
1243 /* Digital Mars adds count to _stprintf (C99) so convert */
1244 #if wxUSE_UNICODE
wxSprintf(wchar_t * __RESTRICT s,const wchar_t * __RESTRICT format,...)1245 int wxSprintf (wchar_t * __RESTRICT s, const wchar_t * __RESTRICT format, ... )
1246 {
1247 va_list arglist;
1248
1249 va_start( arglist, format );
1250 int iLen = swprintf ( s, -1, format, arglist );
1251 va_end( arglist );
1252 return iLen ;
1253 }
1254
1255 #endif // wxUSE_UNICODE
1256
1257 #endif //__DMC__
1258
1259 #if defined(__MINGW32__) && ( defined(_STLPORT_VERSION) && _STLPORT_VERSION >= 0x510 )
1260 /* MinGW with STLPort 5.1 has clashing defines for _stprintf so use swprintf */
1261 /* STLPort 5.1 defines standard (C99) vswprintf() and swprintf() that takes count. */
wxSprintf(wchar_t * s,const wchar_t * format,...)1262 int wxSprintf (wchar_t * s, const wchar_t * format, ... )
1263 {
1264 va_list arglist;
1265
1266 va_start( arglist, format );
1267 int iLen = swprintf ( s, -1, format, arglist );
1268 va_end( arglist );
1269 return iLen ;
1270 }
1271 #endif // MINGW32 _STLPORT_VERSION >= 0x510
1272
1273 // ----------------------------------------------------------------------------
1274 // implement the standard IO functions for wide char if libc doesn't have them
1275 // ----------------------------------------------------------------------------
1276
1277 #ifdef wxNEED_FPUTS
wxFputs(const wchar_t * ws,FILE * stream)1278 int wxFputs(const wchar_t *ws, FILE *stream)
1279 {
1280 wxCharBuffer buf(wxConvLibc.cWC2MB(ws));
1281 if ( !buf )
1282 return -1;
1283
1284 // counting the number of wide characters written isn't worth the trouble,
1285 // simply distinguish between ok and error
1286 return fputs(buf, stream) == -1 ? -1 : 0;
1287 }
1288 #endif // wxNEED_FPUTS
1289
1290 #ifdef wxNEED_PUTS
wxPuts(const wxChar * ws)1291 int wxPuts(const wxChar *ws)
1292 {
1293 int rc = wxFputs(ws, stdout);
1294 if ( rc != -1 )
1295 {
1296 if ( wxFputs(L"\n", stdout) == -1 )
1297 return -1;
1298
1299 rc++;
1300 }
1301
1302 return rc;
1303 }
1304 #endif // wxNEED_PUTS
1305
1306 #ifdef wxNEED_PUTC
wxPutc(wchar_t wc,FILE * stream)1307 int /* not wint_t */ wxPutc(wchar_t wc, FILE *stream)
1308 {
1309 wchar_t ws[2] = { wc, L'\0' };
1310
1311 return wxFputs(ws, stream);
1312 }
1313 #endif // wxNEED_PUTC
1314
1315 // NB: we only implement va_list functions here, the ones taking ... are
1316 // defined below for wxNEED_PRINTF_CONVERSION case anyhow and we reuse
1317 // the definitions there to avoid duplicating them here
1318 #ifdef wxNEED_WPRINTF
1319
1320 // TODO: implement the scanf() functions
vwscanf(const wxChar * format,va_list argptr)1321 int vwscanf(const wxChar *format, va_list argptr)
1322 {
1323 wxFAIL_MSG( _T("TODO") );
1324
1325 return -1;
1326 }
1327
vswscanf(const wxChar * ws,const wxChar * format,va_list argptr)1328 int vswscanf(const wxChar *ws, const wxChar *format, va_list argptr)
1329 {
1330 // The best we can do without proper Unicode support in glibc is to
1331 // convert the strings into MB representation and run ANSI version
1332 // of the function. This doesn't work with %c and %s because of difference
1333 // in size of char and wchar_t, though.
1334
1335 wxCHECK_MSG( wxStrstr(format, _T("%s")) == NULL, -1,
1336 _T("incomplete vswscanf implementation doesn't allow %s") );
1337 wxCHECK_MSG( wxStrstr(format, _T("%c")) == NULL, -1,
1338 _T("incomplete vswscanf implementation doesn't allow %c") );
1339
1340 va_list argcopy;
1341 wxVaCopy(argcopy, argptr);
1342 return vsscanf(wxConvLibc.cWX2MB(ws), wxConvLibc.cWX2MB(format), argcopy);
1343 }
1344
vfwscanf(FILE * stream,const wxChar * format,va_list argptr)1345 int vfwscanf(FILE *stream, const wxChar *format, va_list argptr)
1346 {
1347 wxFAIL_MSG( _T("TODO") );
1348
1349 return -1;
1350 }
1351
1352 #define vswprintf wxVsnprintf_
1353
vfwprintf(FILE * stream,const wxChar * format,va_list argptr)1354 int vfwprintf(FILE *stream, const wxChar *format, va_list argptr)
1355 {
1356 wxString s;
1357 int rc = s.PrintfV(format, argptr);
1358
1359 if ( rc != -1 )
1360 {
1361 // we can't do much better without Unicode support in libc...
1362 if ( fprintf(stream, "%s", (const char*)s.mb_str() ) == -1 )
1363 return -1;
1364 }
1365
1366 return rc;
1367 }
1368
vwprintf(const wxChar * format,va_list argptr)1369 int vwprintf(const wxChar *format, va_list argptr)
1370 {
1371 return wxVfprintf(stdout, format, argptr);
1372 }
1373
1374 #endif // wxNEED_WPRINTF
1375
1376 #ifdef wxNEED_PRINTF_CONVERSION
1377
1378 // ----------------------------------------------------------------------------
1379 // wxFormatConverter: class doing the "%s" -> "%ls" conversion
1380 // ----------------------------------------------------------------------------
1381
1382 /*
1383 Here are the gory details. We want to follow the Windows/MS conventions,
1384 that is to have
1385
1386 In ANSI mode:
1387
1388 format specifier results in
1389 -----------------------------------
1390 %c, %hc, %hC char
1391 %lc, %C, %lC wchar_t
1392
1393 In Unicode mode:
1394
1395 format specifier results in
1396 -----------------------------------
1397 %hc, %C, %hC char
1398 %c, %lc, %lC wchar_t
1399
1400
1401 while on POSIX systems we have %C identical to %lc and %c always means char
1402 (in any mode) while %lc always means wchar_t,
1403
1404 So to use native functions in order to get our semantics we must do the
1405 following translations in Unicode mode (nothing to do in ANSI mode):
1406
1407 wxWidgets specifier POSIX specifier
1408 ----------------------------------------
1409
1410 %hc, %C, %hC %c
1411 %c %lc
1412
1413
1414 And, of course, the same should be done for %s as well.
1415 */
1416
1417 class wxFormatConverter
1418 {
1419 public:
1420 wxFormatConverter(const wxChar *format);
1421
1422 // notice that we only translated the string if m_fmtOrig == NULL (as set
1423 // by CopyAllBefore()), otherwise we should simply use the original format
operator const wxChar*() const1424 operator const wxChar *() const
1425 { return m_fmtOrig ? m_fmtOrig : m_fmt.c_str(); }
1426
1427 private:
1428 // copy another character to the translated format: this function does the
1429 // copy if we are translating but doesn't do anything at all if we don't,
1430 // so we don't create the translated format string at all unless we really
1431 // need to (i.e. InsertFmtChar() is called)
CopyFmtChar(wxChar ch)1432 wxChar CopyFmtChar(wxChar ch)
1433 {
1434 if ( !m_fmtOrig )
1435 {
1436 // we're translating, do copy
1437 m_fmt += ch;
1438 }
1439 else
1440 {
1441 // simply increase the count which should be copied by
1442 // CopyAllBefore() later if needed
1443 m_nCopied++;
1444 }
1445
1446 return ch;
1447 }
1448
1449 // insert an extra character
InsertFmtChar(wxChar ch)1450 void InsertFmtChar(wxChar ch)
1451 {
1452 if ( m_fmtOrig )
1453 {
1454 // so far we haven't translated anything yet
1455 CopyAllBefore();
1456 }
1457
1458 m_fmt += ch;
1459 }
1460
CopyAllBefore()1461 void CopyAllBefore()
1462 {
1463 wxASSERT_MSG( m_fmtOrig && m_fmt.empty(), _T("logic error") );
1464
1465 m_fmt = wxString(m_fmtOrig, m_nCopied);
1466
1467 // we won't need it any longer
1468 m_fmtOrig = NULL;
1469 }
1470
IsFlagChar(wxChar ch)1471 static bool IsFlagChar(wxChar ch)
1472 {
1473 return ch == _T('-') || ch == _T('+') ||
1474 ch == _T('0') || ch == _T(' ') || ch == _T('#');
1475 }
1476
SkipDigits(const wxChar ** ptpc)1477 void SkipDigits(const wxChar **ptpc)
1478 {
1479 while ( **ptpc >= _T('0') && **ptpc <= _T('9') )
1480 CopyFmtChar(*(*ptpc)++);
1481 }
1482
1483 // the translated format
1484 wxString m_fmt;
1485
1486 // the original format
1487 const wxChar *m_fmtOrig;
1488
1489 // the number of characters already copied
1490 size_t m_nCopied;
1491 };
1492
wxFormatConverter(const wxChar * format)1493 wxFormatConverter::wxFormatConverter(const wxChar *format)
1494 {
1495 m_fmtOrig = format;
1496 m_nCopied = 0;
1497
1498 while ( *format )
1499 {
1500 if ( CopyFmtChar(*format++) == _T('%') )
1501 {
1502 // skip any flags
1503 while ( IsFlagChar(*format) )
1504 CopyFmtChar(*format++);
1505
1506 // and possible width
1507 if ( *format == _T('*') )
1508 CopyFmtChar(*format++);
1509 else
1510 SkipDigits(&format);
1511
1512 // precision?
1513 if ( *format == _T('.') )
1514 {
1515 CopyFmtChar(*format++);
1516 if ( *format == _T('*') )
1517 CopyFmtChar(*format++);
1518 else
1519 SkipDigits(&format);
1520 }
1521
1522 // next we can have a size modifier
1523 enum
1524 {
1525 Default,
1526 Short,
1527 Long
1528 } size;
1529
1530 switch ( *format )
1531 {
1532 case _T('h'):
1533 size = Short;
1534 format++;
1535 break;
1536
1537 case _T('l'):
1538 // "ll" has a different meaning!
1539 if ( format[1] != _T('l') )
1540 {
1541 size = Long;
1542 format++;
1543 break;
1544 }
1545 //else: fall through
1546
1547 default:
1548 size = Default;
1549 }
1550
1551 // and finally we should have the type
1552 switch ( *format )
1553 {
1554 case _T('C'):
1555 case _T('S'):
1556 // %C and %hC -> %c and %lC -> %lc
1557 if ( size == Long )
1558 CopyFmtChar(_T('l'));
1559
1560 InsertFmtChar(*format++ == _T('C') ? _T('c') : _T('s'));
1561 break;
1562
1563 case _T('c'):
1564 case _T('s'):
1565 // %c -> %lc but %hc stays %hc and %lc is still %lc
1566 if ( size == Default)
1567 InsertFmtChar(_T('l'));
1568 // fall through
1569
1570 default:
1571 // nothing special to do
1572 if ( size != Default )
1573 CopyFmtChar(*(format - 1));
1574 CopyFmtChar(*format++);
1575 }
1576 }
1577 }
1578 }
1579
1580 #else // !wxNEED_PRINTF_CONVERSION
1581 // no conversion necessary
1582 #define wxFormatConverter(x) (x)
1583 #endif // wxNEED_PRINTF_CONVERSION/!wxNEED_PRINTF_CONVERSION
1584
1585 #ifdef __WXDEBUG__
1586 // For testing the format converter
wxConvertFormat(const wxChar * format)1587 wxString wxConvertFormat(const wxChar *format)
1588 {
1589 return wxString(wxFormatConverter(format));
1590 }
1591 #endif
1592
1593 // ----------------------------------------------------------------------------
1594 // wxPrintf(), wxScanf() and relatives
1595 // ----------------------------------------------------------------------------
1596
1597 #if defined(wxNEED_PRINTF_CONVERSION) || defined(wxNEED_WPRINTF)
1598
wxScanf(const wxChar * format,...)1599 int wxScanf( const wxChar *format, ... )
1600 {
1601 va_list argptr;
1602 va_start(argptr, format);
1603
1604 int ret = vwscanf(wxFormatConverter(format), argptr );
1605
1606 va_end(argptr);
1607
1608 return ret;
1609 }
1610
wxSscanf(const wxChar * str,const wxChar * format,...)1611 int wxSscanf( const wxChar *str, const wxChar *format, ... )
1612 {
1613 va_list argptr;
1614 va_start(argptr, format);
1615
1616 int ret = vswscanf( str, wxFormatConverter(format), argptr );
1617
1618 va_end(argptr);
1619
1620 return ret;
1621 }
1622
wxFscanf(FILE * stream,const wxChar * format,...)1623 int wxFscanf( FILE *stream, const wxChar *format, ... )
1624 {
1625 va_list argptr;
1626 va_start(argptr, format);
1627 int ret = vfwscanf(stream, wxFormatConverter(format), argptr);
1628
1629 va_end(argptr);
1630
1631 return ret;
1632 }
1633
wxPrintf(const wxChar * format,...)1634 int wxPrintf( const wxChar *format, ... )
1635 {
1636 va_list argptr;
1637 va_start(argptr, format);
1638
1639 int ret = vwprintf( wxFormatConverter(format), argptr );
1640
1641 va_end(argptr);
1642
1643 return ret;
1644 }
1645
1646 #ifndef wxSnprintf
wxSnprintf(wxChar * str,size_t size,const wxChar * format,...)1647 int wxSnprintf( wxChar *str, size_t size, const wxChar *format, ... )
1648 {
1649 va_list argptr;
1650 va_start(argptr, format);
1651
1652 int ret = vswprintf( str, size, wxFormatConverter(format), argptr );
1653
1654 // VsnprintfTestCase reveals that glibc's implementation of vswprintf
1655 // doesn't nul terminate on truncation.
1656 str[size - 1] = 0;
1657
1658 va_end(argptr);
1659
1660 return ret;
1661 }
1662 #endif // wxSnprintf
1663
wxSprintf(wxChar * str,const wxChar * format,...)1664 int wxSprintf( wxChar *str, const wxChar *format, ... )
1665 {
1666 va_list argptr;
1667 va_start(argptr, format);
1668
1669 // note that wxString::FormatV() uses wxVsnprintf(), not wxSprintf(), so
1670 // it's safe to implement this one in terms of it
1671 wxString s(wxString::FormatV(format, argptr));
1672 wxStrcpy(str, s);
1673
1674 va_end(argptr);
1675
1676 return s.length();
1677 }
1678
wxFprintf(FILE * stream,const wxChar * format,...)1679 int wxFprintf( FILE *stream, const wxChar *format, ... )
1680 {
1681 va_list argptr;
1682 va_start( argptr, format );
1683
1684 int ret = vfwprintf( stream, wxFormatConverter(format), argptr );
1685
1686 va_end(argptr);
1687
1688 return ret;
1689 }
1690
wxVsscanf(const wxChar * str,const wxChar * format,va_list argptr)1691 int wxVsscanf( const wxChar *str, const wxChar *format, va_list argptr )
1692 {
1693 return vswscanf( str, wxFormatConverter(format), argptr );
1694 }
1695
wxVfprintf(FILE * stream,const wxChar * format,va_list argptr)1696 int wxVfprintf( FILE *stream, const wxChar *format, va_list argptr )
1697 {
1698 return vfwprintf( stream, wxFormatConverter(format), argptr );
1699 }
1700
wxVprintf(const wxChar * format,va_list argptr)1701 int wxVprintf( const wxChar *format, va_list argptr )
1702 {
1703 return vwprintf( wxFormatConverter(format), argptr );
1704 }
1705
1706 #ifndef wxVsnprintf
wxVsnprintf(wxChar * str,size_t size,const wxChar * format,va_list argptr)1707 int wxVsnprintf( wxChar *str, size_t size, const wxChar *format, va_list argptr )
1708 {
1709 return vswprintf( str, size, wxFormatConverter(format), argptr );
1710 }
1711 #endif // wxVsnprintf
1712
wxVsprintf(wxChar * str,const wxChar * format,va_list argptr)1713 int wxVsprintf( wxChar *str, const wxChar *format, va_list argptr )
1714 {
1715 // same as for wxSprintf()
1716 return vswprintf(str, INT_MAX / 4, wxFormatConverter(format), argptr);
1717 }
1718
1719 #endif // wxNEED_PRINTF_CONVERSION
1720
1721 #if wxUSE_WCHAR_T
1722
1723 // ----------------------------------------------------------------------------
1724 // ctype.h stuff (currently unused)
1725 // ----------------------------------------------------------------------------
1726
1727 #if defined(__WIN32__) && defined(wxNEED_WX_CTYPE_H)
wxMSW_ctype(wxChar ch)1728 inline WORD wxMSW_ctype(wxChar ch)
1729 {
1730 WORD ret;
1731 GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, &ch, 1, &ret);
1732 return ret;
1733 }
1734
wxIsalnum(wxChar ch)1735 WXDLLEXPORT int wxIsalnum(wxChar ch) { return IsCharAlphaNumeric(ch); }
wxIsalpha(wxChar ch)1736 WXDLLEXPORT int wxIsalpha(wxChar ch) { return IsCharAlpha(ch); }
wxIscntrl(wxChar ch)1737 WXDLLEXPORT int wxIscntrl(wxChar ch) { return wxMSW_ctype(ch) & C1_CNTRL; }
wxIsdigit(wxChar ch)1738 WXDLLEXPORT int wxIsdigit(wxChar ch) { return wxMSW_ctype(ch) & C1_DIGIT; }
wxIsgraph(wxChar ch)1739 WXDLLEXPORT int wxIsgraph(wxChar ch) { return wxMSW_ctype(ch) & (C1_DIGIT|C1_PUNCT|C1_ALPHA); }
wxIslower(wxChar ch)1740 WXDLLEXPORT int wxIslower(wxChar ch) { return IsCharLower(ch); }
wxIsprint(wxChar ch)1741 WXDLLEXPORT int wxIsprint(wxChar ch) { return wxMSW_ctype(ch) & (C1_DIGIT|C1_SPACE|C1_PUNCT|C1_ALPHA); }
wxIspunct(wxChar ch)1742 WXDLLEXPORT int wxIspunct(wxChar ch) { return wxMSW_ctype(ch) & C1_PUNCT; }
wxIsspace(wxChar ch)1743 WXDLLEXPORT int wxIsspace(wxChar ch) { return wxMSW_ctype(ch) & C1_SPACE; }
wxIsupper(wxChar ch)1744 WXDLLEXPORT int wxIsupper(wxChar ch) { return IsCharUpper(ch); }
wxIsxdigit(wxChar ch)1745 WXDLLEXPORT int wxIsxdigit(wxChar ch) { return wxMSW_ctype(ch) & C1_XDIGIT; }
wxTolower(wxChar ch)1746 WXDLLEXPORT int wxTolower(wxChar ch) { return (wxChar)CharLower((LPTSTR)(ch)); }
wxToupper(wxChar ch)1747 WXDLLEXPORT int wxToupper(wxChar ch) { return (wxChar)CharUpper((LPTSTR)(ch)); }
1748 #endif
1749
1750 #ifdef wxNEED_WX_MBSTOWCS
1751
wxMbstowcs(wchar_t * out,const char * in,size_t outlen)1752 WXDLLEXPORT size_t wxMbstowcs (wchar_t * out, const char * in, size_t outlen)
1753 {
1754 if (!out)
1755 {
1756 size_t outsize = 0;
1757 while(*in++)
1758 outsize++;
1759 return outsize;
1760 }
1761
1762 const char* origin = in;
1763
1764 while (outlen-- && *in)
1765 {
1766 *out++ = (wchar_t) *in++;
1767 }
1768
1769 *out = '\0';
1770
1771 return in - origin;
1772 }
1773
wxWcstombs(char * out,const wchar_t * in,size_t outlen)1774 WXDLLEXPORT size_t wxWcstombs (char * out, const wchar_t * in, size_t outlen)
1775 {
1776 if (!out)
1777 {
1778 size_t outsize = 0;
1779 while(*in++)
1780 outsize++;
1781 return outsize;
1782 }
1783
1784 const wchar_t* origin = in;
1785
1786 while (outlen-- && *in)
1787 {
1788 *out++ = (char) *in++;
1789 }
1790
1791 *out = '\0';
1792
1793 return in - origin;
1794 }
1795
1796 #endif // wxNEED_WX_MBSTOWCS
1797
1798 #if defined(wxNEED_WX_CTYPE_H)
1799
1800 #include <CoreFoundation/CoreFoundation.h>
1801
1802 #define cfalnumset CFCharacterSetGetPredefined(kCFCharacterSetAlphaNumeric)
1803 #define cfalphaset CFCharacterSetGetPredefined(kCFCharacterSetLetter)
1804 #define cfcntrlset CFCharacterSetGetPredefined(kCFCharacterSetControl)
1805 #define cfdigitset CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit)
1806 //CFCharacterSetRef cfgraphset = kCFCharacterSetControl && !' '
1807 #define cflowerset CFCharacterSetGetPredefined(kCFCharacterSetLowercaseLetter)
1808 //CFCharacterSetRef cfprintset = !kCFCharacterSetControl
1809 #define cfpunctset CFCharacterSetGetPredefined(kCFCharacterSetPunctuation)
1810 #define cfspaceset CFCharacterSetGetPredefined(kCFCharacterSetWhitespaceAndNewline)
1811 #define cfupperset CFCharacterSetGetPredefined(kCFCharacterSetUppercaseLetter)
1812
wxIsalnum(wxChar ch)1813 WXDLLEXPORT int wxIsalnum(wxChar ch) { return CFCharacterSetIsCharacterMember(cfalnumset, ch); }
wxIsalpha(wxChar ch)1814 WXDLLEXPORT int wxIsalpha(wxChar ch) { return CFCharacterSetIsCharacterMember(cfalphaset, ch); }
wxIscntrl(wxChar ch)1815 WXDLLEXPORT int wxIscntrl(wxChar ch) { return CFCharacterSetIsCharacterMember(cfcntrlset, ch); }
wxIsdigit(wxChar ch)1816 WXDLLEXPORT int wxIsdigit(wxChar ch) { return CFCharacterSetIsCharacterMember(cfdigitset, ch); }
wxIsgraph(wxChar ch)1817 WXDLLEXPORT int wxIsgraph(wxChar ch) { return !CFCharacterSetIsCharacterMember(cfcntrlset, ch) && ch != ' '; }
wxIslower(wxChar ch)1818 WXDLLEXPORT int wxIslower(wxChar ch) { return CFCharacterSetIsCharacterMember(cflowerset, ch); }
wxIsprint(wxChar ch)1819 WXDLLEXPORT int wxIsprint(wxChar ch) { return !CFCharacterSetIsCharacterMember(cfcntrlset, ch); }
wxIspunct(wxChar ch)1820 WXDLLEXPORT int wxIspunct(wxChar ch) { return CFCharacterSetIsCharacterMember(cfpunctset, ch); }
wxIsspace(wxChar ch)1821 WXDLLEXPORT int wxIsspace(wxChar ch) { return CFCharacterSetIsCharacterMember(cfspaceset, ch); }
wxIsupper(wxChar ch)1822 WXDLLEXPORT int wxIsupper(wxChar ch) { return CFCharacterSetIsCharacterMember(cfupperset, ch); }
wxIsxdigit(wxChar ch)1823 WXDLLEXPORT int wxIsxdigit(wxChar ch) { return wxIsdigit(ch) || (ch>='a' && ch<='f') || (ch>='A' && ch<='F'); }
wxTolower(wxChar ch)1824 WXDLLEXPORT int wxTolower(wxChar ch) { return (wxChar)tolower((char)(ch)); }
wxToupper(wxChar ch)1825 WXDLLEXPORT int wxToupper(wxChar ch) { return (wxChar)toupper((char)(ch)); }
1826
1827 #endif // wxNEED_WX_CTYPE_H
1828
1829 #ifndef wxStrdupA
1830
wxStrdupA(const char * s)1831 WXDLLEXPORT char *wxStrdupA(const char *s)
1832 {
1833 return strcpy((char *)malloc(strlen(s) + 1), s);
1834 }
1835
1836 #endif // wxStrdupA
1837
1838 #ifndef wxStrdupW
1839
wxStrdupW(const wchar_t * pwz)1840 WXDLLEXPORT wchar_t * wxStrdupW(const wchar_t *pwz)
1841 {
1842 size_t size = (wxWcslen(pwz) + 1) * sizeof(wchar_t);
1843 wchar_t *ret = (wchar_t *) malloc(size);
1844 memcpy(ret, pwz, size);
1845 return ret;
1846 }
1847
1848 #endif // wxStrdupW
1849
1850 #ifndef wxStricmp
wxStricmp(const wxChar * psz1,const wxChar * psz2)1851 int WXDLLEXPORT wxStricmp(const wxChar *psz1, const wxChar *psz2)
1852 {
1853 register wxChar c1, c2;
1854 do {
1855 c1 = wxTolower(*psz1++);
1856 c2 = wxTolower(*psz2++);
1857 } while ( c1 && (c1 == c2) );
1858 return c1 - c2;
1859 }
1860 #endif
1861
1862 #ifndef wxStricmp
wxStrnicmp(const wxChar * s1,const wxChar * s2,size_t n)1863 int WXDLLEXPORT wxStrnicmp(const wxChar *s1, const wxChar *s2, size_t n)
1864 {
1865 // initialize the variables just to suppress stupid gcc warning
1866 register wxChar c1 = 0, c2 = 0;
1867 while (n && ((c1 = wxTolower(*s1)) == (c2 = wxTolower(*s2)) ) && c1) n--, s1++, s2++;
1868 if (n) {
1869 if (c1 < c2) return -1;
1870 if (c1 > c2) return 1;
1871 }
1872 return 0;
1873 }
1874 #endif
1875
1876 #ifndef wxSetlocale
wxSetlocale(int category,const wxChar * locale)1877 WXDLLEXPORT wxWCharBuffer wxSetlocale(int category, const wxChar *locale)
1878 {
1879 char *localeOld = setlocale(category, wxConvLibc.cWX2MB(locale));
1880
1881 return wxWCharBuffer(wxConvLibc.cMB2WC(localeOld));
1882 }
1883 #endif
1884
1885 #if wxUSE_WCHAR_T && !defined(HAVE_WCSLEN)
wxWcslen(const wchar_t * s)1886 WXDLLEXPORT size_t wxWcslen(const wchar_t *s)
1887 {
1888 size_t n = 0;
1889 while ( *s++ )
1890 n++;
1891
1892 return n;
1893 }
1894 #endif
1895
1896 // ----------------------------------------------------------------------------
1897 // string.h functions
1898 // ----------------------------------------------------------------------------
1899
1900 #ifdef wxNEED_WX_STRING_H
1901
1902 // RN: These need to be c externed for the regex lib
1903 #ifdef __cplusplus
1904 extern "C" {
1905 #endif
1906
wxStrcat(wxChar * dest,const wxChar * src)1907 WXDLLEXPORT wxChar * wxStrcat(wxChar *dest, const wxChar *src)
1908 {
1909 wxChar *ret = dest;
1910 while (*dest) dest++;
1911 while ((*dest++ = *src++));
1912 return ret;
1913 }
1914
wxStrchr(const wxChar * s,wxChar c)1915 WXDLLEXPORT const wxChar * wxStrchr(const wxChar *s, wxChar c)
1916 {
1917 // be careful here as the terminating NUL makes part of the string
1918 while ( *s != c )
1919 {
1920 if ( !*s++ )
1921 return NULL;
1922 }
1923
1924 return s;
1925 }
1926
wxStrcmp(const wxChar * s1,const wxChar * s2)1927 WXDLLEXPORT int wxStrcmp(const wxChar *s1, const wxChar *s2)
1928 {
1929 while ((*s1 == *s2) && *s1) s1++, s2++;
1930 if ((wxUChar)*s1 < (wxUChar)*s2) return -1;
1931 if ((wxUChar)*s1 > (wxUChar)*s2) return 1;
1932 return 0;
1933 }
1934
wxStrcpy(wxChar * dest,const wxChar * src)1935 WXDLLEXPORT wxChar * wxStrcpy(wxChar *dest, const wxChar *src)
1936 {
1937 wxChar *ret = dest;
1938 while ((*dest++ = *src++));
1939 return ret;
1940 }
1941
wxStrlen_(const wxChar * s)1942 WXDLLEXPORT size_t wxStrlen_(const wxChar *s)
1943 {
1944 size_t n = 0;
1945 while ( *s++ )
1946 n++;
1947
1948 return n;
1949 }
1950
1951
wxStrncat(wxChar * dest,const wxChar * src,size_t n)1952 WXDLLEXPORT wxChar * wxStrncat(wxChar *dest, const wxChar *src, size_t n)
1953 {
1954 wxChar *ret = dest;
1955 while (*dest) dest++;
1956 while (n && (*dest++ = *src++)) n--;
1957 return ret;
1958 }
1959
wxStrncmp(const wxChar * s1,const wxChar * s2,size_t n)1960 WXDLLEXPORT int wxStrncmp(const wxChar *s1, const wxChar *s2, size_t n)
1961 {
1962 while (n && (*s1 == *s2) && *s1) n--, s1++, s2++;
1963 if (n) {
1964 if ((wxUChar)*s1 < (wxUChar)*s2) return -1;
1965 if ((wxUChar)*s1 > (wxUChar)*s2) return 1;
1966 }
1967 return 0;
1968 }
1969
wxStrncpy(wxChar * dest,const wxChar * src,size_t n)1970 WXDLLEXPORT wxChar * wxStrncpy(wxChar *dest, const wxChar *src, size_t n)
1971 {
1972 wxChar *ret = dest;
1973 while (n && (*dest++ = *src++)) n--;
1974 while (n) *dest++=0, n--; // the docs specify padding with zeroes
1975 return ret;
1976 }
1977
wxStrpbrk(const wxChar * s,const wxChar * accept)1978 WXDLLEXPORT const wxChar * wxStrpbrk(const wxChar *s, const wxChar *accept)
1979 {
1980 while (*s && !wxStrchr(accept, *s))
1981 s++;
1982
1983 return *s ? s : NULL;
1984 }
1985
wxStrrchr(const wxChar * s,wxChar c)1986 WXDLLEXPORT const wxChar * wxStrrchr(const wxChar *s, wxChar c)
1987 {
1988 const wxChar *ret = NULL;
1989 do
1990 {
1991 if ( *s == c )
1992 ret = s;
1993 s++;
1994 }
1995 while ( *s );
1996
1997 return ret;
1998 }
1999
wxStrspn(const wxChar * s,const wxChar * accept)2000 WXDLLEXPORT size_t wxStrspn(const wxChar *s, const wxChar *accept)
2001 {
2002 size_t len = 0;
2003 while (wxStrchr(accept, *s++)) len++;
2004 return len;
2005 }
2006
wxStrstr(const wxChar * haystack,const wxChar * needle)2007 WXDLLEXPORT const wxChar *wxStrstr(const wxChar *haystack, const wxChar *needle)
2008 {
2009 wxASSERT_MSG( needle != NULL, _T("NULL argument in wxStrstr") );
2010
2011 // VZ: this is not exactly the most efficient string search algorithm...
2012
2013 const size_t len = wxStrlen(needle);
2014
2015 while ( const wxChar *fnd = wxStrchr(haystack, *needle) )
2016 {
2017 if ( !wxStrncmp(fnd, needle, len) )
2018 return fnd;
2019
2020 haystack = fnd + 1;
2021 }
2022
2023 return NULL;
2024 }
2025
2026 #ifdef __cplusplus
2027 }
2028 #endif
2029
wxStrtod(const wxChar * nptr,wxChar ** endptr)2030 WXDLLEXPORT double wxStrtod(const wxChar *nptr, wxChar **endptr)
2031 {
2032 const wxChar decSep(
2033 #if wxUSE_INTL
2034 wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER)[0]
2035 #else
2036 _T('.')
2037 #endif
2038 );
2039 const wxChar *start = nptr;
2040
2041 while (wxIsspace(*nptr)) nptr++;
2042 if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++;
2043 while (wxIsdigit(*nptr)) nptr++;
2044 if (*nptr == decSep) {
2045 nptr++;
2046 while (wxIsdigit(*nptr)) nptr++;
2047 }
2048 if (*nptr == wxT('E') || *nptr == wxT('e')) {
2049 nptr++;
2050 if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++;
2051 while (wxIsdigit(*nptr)) nptr++;
2052 }
2053
2054 wxString data(start, nptr-start);
2055 const wxWX2MBbuf dat = data.mb_str(wxConvLibc);
2056 char *rdat = wxMBSTRINGCAST dat;
2057 double ret = strtod(dat, &rdat);
2058
2059 if (endptr) *endptr = (wxChar *)(start + (rdat - (const char *)dat));
2060
2061 return ret;
2062 }
2063
wxStrtol(const wxChar * nptr,wxChar ** endptr,int base)2064 WXDLLEXPORT long int wxStrtol(const wxChar *nptr, wxChar **endptr, int base)
2065 {
2066 const wxChar *start = nptr;
2067
2068 while (wxIsspace(*nptr)) nptr++;
2069 if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++;
2070 if (((base == 0) || (base == 16)) &&
2071 (nptr[0] == wxT('0') && nptr[1] == wxT('x'))) {
2072 nptr += 2;
2073 base = 16;
2074 }
2075 else if ((base == 0) && (nptr[0] == wxT('0'))) base = 8;
2076 else if (base == 0) base = 10;
2077
2078 while ((wxIsdigit(*nptr) && (*nptr - wxT('0') < base)) ||
2079 (wxIsalpha(*nptr) && (wxToupper(*nptr) - wxT('A') + 10 < base))) nptr++;
2080
2081 wxString data(start, nptr-start);
2082 wxWX2MBbuf dat = data.mb_str(wxConvLibc);
2083 char *rdat = wxMBSTRINGCAST dat;
2084 long int ret = strtol(dat, &rdat, base);
2085
2086 if (endptr) *endptr = (wxChar *)(start + (rdat - (const char *)dat));
2087
2088 return ret;
2089 }
2090
wxStrtoul(const wxChar * nptr,wxChar ** endptr,int base)2091 WXDLLEXPORT unsigned long int wxStrtoul(const wxChar *nptr, wxChar **endptr, int base)
2092 {
2093 return (unsigned long int) wxStrtol(nptr, endptr, base);
2094 }
2095
2096 #endif // wxNEED_WX_STRING_H
2097
2098 #ifdef wxNEED_WX_STDIO_H
wxFopen(const wxChar * path,const wxChar * mode)2099 WXDLLEXPORT FILE * wxFopen(const wxChar *path, const wxChar *mode)
2100 {
2101 char mode_buffer[10];
2102 for (size_t i = 0; i < wxStrlen(mode)+1; i++)
2103 mode_buffer[i] = (char) mode[i];
2104
2105 return fopen( wxConvFile.cWX2MB(path), mode_buffer );
2106 }
2107
wxFreopen(const wxChar * path,const wxChar * mode,FILE * stream)2108 WXDLLEXPORT FILE * wxFreopen(const wxChar *path, const wxChar *mode, FILE *stream)
2109 {
2110 char mode_buffer[10];
2111 for (size_t i = 0; i < wxStrlen(mode)+1; i++)
2112 mode_buffer[i] = (char) mode[i];
2113
2114 return freopen( wxConvFile.cWX2MB(path), mode_buffer, stream );
2115 }
2116
wxRemove(const wxChar * path)2117 WXDLLEXPORT int wxRemove(const wxChar *path)
2118 {
2119 return remove( wxConvFile.cWX2MB(path) );
2120 }
2121
wxRename(const wxChar * oldpath,const wxChar * newpath)2122 WXDLLEXPORT int wxRename(const wxChar *oldpath, const wxChar *newpath)
2123 {
2124 return rename( wxConvFile.cWX2MB(oldpath), wxConvFile.cWX2MB(newpath) );
2125 }
2126 #endif
2127
2128 #ifndef wxAtof
wxAtof(const wxChar * psz)2129 double WXDLLEXPORT wxAtof(const wxChar *psz)
2130 {
2131 #ifdef __WXWINCE__
2132 double d;
2133 wxString str(psz);
2134 if (str.ToDouble(& d))
2135 return d;
2136
2137 return 0.0;
2138 #else
2139 return atof(wxConvLibc.cWX2MB(psz));
2140 #endif
2141 }
2142 #endif
2143
2144 #ifdef wxNEED_WX_STDLIB_H
wxAtoi(const wxChar * psz)2145 int WXDLLEXPORT wxAtoi(const wxChar *psz)
2146 {
2147 return atoi(wxConvLibc.cWX2MB(psz));
2148 }
2149
wxAtol(const wxChar * psz)2150 long WXDLLEXPORT wxAtol(const wxChar *psz)
2151 {
2152 return atol(wxConvLibc.cWX2MB(psz));
2153 }
2154
wxGetenv(const wxChar * name)2155 wxChar * WXDLLEXPORT wxGetenv(const wxChar *name)
2156 {
2157 #if wxUSE_UNICODE
2158 // NB: buffer returned by getenv() is allowed to be overwritten next
2159 // time getenv() is called, so it is OK to use static string
2160 // buffer to hold the data.
2161 static wxWCharBuffer value((wxChar*)NULL);
2162 value = wxConvLibc.cMB2WX(getenv(wxConvLibc.cWX2MB(name)));
2163 return value.data();
2164 #else
2165 return getenv(name);
2166 #endif
2167 }
2168 #endif // wxNEED_WX_STDLIB_H
2169
2170 #ifdef wxNEED_WXSYSTEM
wxSystem(const wxChar * psz)2171 int WXDLLEXPORT wxSystem(const wxChar *psz)
2172 {
2173 return system(wxConvLibc.cWX2MB(psz));
2174 }
2175 #endif // wxNEED_WXSYSTEM
2176
2177 #ifdef wxNEED_WX_TIME_H
2178 WXDLLEXPORT size_t
wxStrftime(wxChar * s,size_t maxsize,const wxChar * fmt,const struct tm * tm)2179 wxStrftime(wxChar *s, size_t maxsize, const wxChar *fmt, const struct tm *tm)
2180 {
2181 if ( !maxsize )
2182 return 0;
2183
2184 wxCharBuffer buf(maxsize);
2185
2186 wxCharBuffer bufFmt(wxConvLibc.cWX2MB(fmt));
2187 if ( !bufFmt )
2188 return 0;
2189
2190 size_t ret = strftime(buf.data(), maxsize, bufFmt, tm);
2191 if ( !ret )
2192 return 0;
2193
2194 wxWCharBuffer wbuf = wxConvLibc.cMB2WX(buf);
2195 if ( !wbuf )
2196 return 0;
2197
2198 wxStrncpy(s, wbuf, maxsize);
2199 return wxStrlen(s);
2200 }
2201 #endif // wxNEED_WX_TIME_H
2202
2203 #ifndef wxCtime
wxCtime(const time_t * timep)2204 WXDLLEXPORT wxChar *wxCtime(const time_t *timep)
2205 {
2206 // normally the string is 26 chars but give one more in case some broken
2207 // DOS compiler decides to use "\r\n" instead of "\n" at the end
2208 static wxChar buf[27];
2209
2210 // ctime() is guaranteed to return a string containing only ASCII
2211 // characters, as its format is always the same for any locale
2212 wxStrncpy(buf, wxString::FromAscii(ctime(timep)), WXSIZEOF(buf));
2213 buf[WXSIZEOF(buf) - 1] = _T('\0');
2214
2215 return buf;
2216 }
2217 #endif // wxCtime
2218
2219 #endif // wxUSE_WCHAR_T
2220
2221 // ----------------------------------------------------------------------------
2222 // functions which we may need even if !wxUSE_WCHAR_T
2223 // ----------------------------------------------------------------------------
2224
2225 #ifndef wxStrtok
2226
wxStrtok(wxChar * psz,const wxChar * delim,wxChar ** save_ptr)2227 WXDLLEXPORT wxChar * wxStrtok(wxChar *psz, const wxChar *delim, wxChar **save_ptr)
2228 {
2229 if (!psz)
2230 {
2231 psz = *save_ptr;
2232 if ( !psz )
2233 return NULL;
2234 }
2235
2236 psz += wxStrspn(psz, delim);
2237 if (!*psz)
2238 {
2239 *save_ptr = (wxChar *)NULL;
2240 return (wxChar *)NULL;
2241 }
2242
2243 wxChar *ret = psz;
2244 psz = wxStrpbrk(psz, delim);
2245 if (!psz)
2246 {
2247 *save_ptr = (wxChar*)NULL;
2248 }
2249 else
2250 {
2251 *psz = wxT('\0');
2252 *save_ptr = psz + 1;
2253 }
2254
2255 return ret;
2256 }
2257
2258 #endif // wxStrtok
2259
2260 // ----------------------------------------------------------------------------
2261 // missing C RTL functions
2262 // ----------------------------------------------------------------------------
2263
2264 #ifdef wxNEED_STRDUP
2265
strdup(const char * s)2266 char *strdup(const char *s)
2267 {
2268 char *dest = (char*) malloc( strlen( s ) + 1 ) ;
2269 if ( dest )
2270 strcpy( dest , s ) ;
2271 return dest ;
2272 }
2273 #endif // wxNEED_STRDUP
2274
2275 #if defined(__WXWINCE__) && (_WIN32_WCE <= 211)
2276
calloc(size_t num,size_t size)2277 void *calloc( size_t num, size_t size )
2278 {
2279 void** ptr = (void **)malloc(num * size);
2280 memset( ptr, 0, num * size);
2281 return ptr;
2282 }
2283
2284 #endif // __WXWINCE__ <= 211
2285
2286 #ifdef __WXWINCE__
2287
wxRemove(const wxChar * path)2288 int wxRemove(const wxChar *path)
2289 {
2290 return ::DeleteFile(path) == 0;
2291 }
2292
2293 #endif
2294