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