home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / src / common / wxchar.cpp < prev    next >
C/C++ Source or Header  |  2002-09-08  |  36KB  |  1,243 lines

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