home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / wcstombs.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  9KB  |  283 lines

  1. /***
  2. *wcstombs.c - Convert wide char string to multibyte char string.
  3. *
  4. *       Copyright (c) 1990-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       Convert a wide char string into the equivalent multibyte char string.
  8. *
  9. *******************************************************************************/
  10.  
  11.  
  12. #include <cruntime.h>
  13. #include <stdlib.h>
  14. #include <limits.h>
  15. #include <internal.h>
  16. #include <mtdll.h>
  17. #include <dbgint.h>
  18. #include <errno.h>
  19.  
  20. #ifndef _MAC
  21. #include <locale.h>
  22. #include <setlocal.h>
  23. #endif  /* _MAC */
  24.  
  25. /***
  26. *int __cdecl wcsncnt - count wide characters in a string, up to n.
  27. *
  28. *Purpose:
  29. *       Internal local support function. Counts characters in string including NULL.
  30. *       If NULL not found in n chars, then return n.
  31. *
  32. *Entry:
  33. *       const wchar_t *string   - start of string
  34. *       int n                   - character count
  35. *
  36. *Exit:
  37. *       returns number of wide characters from start of string to
  38. *       NULL (inclusive), up to n.
  39. *
  40. *Exceptions:
  41. *
  42. *******************************************************************************/
  43.  
  44. static int __cdecl wcsncnt (
  45.         const wchar_t *string,
  46.         int cnt
  47.         )
  48. {
  49.         int n = cnt+1;
  50.         wchar_t *cp = (wchar_t *)string;
  51.  
  52.         while (--n && *cp)
  53.             cp++;
  54.  
  55.         if (n && !*cp)
  56.             return cp - string + 1;
  57.         return cnt;
  58. }
  59.  
  60. /***
  61. *size_t wcstombs() - Convert wide char string to multibyte char string.
  62. *
  63. *Purpose:
  64. *       Convert a wide char string into the equivalent multibyte char string,
  65. *       according to the LC_CTYPE category of the current locale.
  66. *       [ANSI].
  67. *
  68. *       NOTE:  Currently, the C libraries support the "C" locale only.
  69. *              Non-C locale support now available under _INTL switch.
  70. *Entry:
  71. *       char *s            = pointer to destination multibyte char string
  72. *       const wchar_t *pwc = pointer to source wide character string
  73. *       size_t           n = maximum number of bytes to store in s
  74. *
  75. *Exit:
  76. *       If s != NULL, returns    (size_t)-1 (if a wchar cannot be converted)
  77. *       Otherwise:       Number of bytes modified (<=n), not including
  78. *                    the terminating NUL, if any.
  79. *
  80. *Exceptions:
  81. *       Returns (size_t)-1 if s is NULL or invalid mb character encountered.
  82. *
  83. *******************************************************************************/
  84.  
  85. #ifdef _MT
  86.  
  87. size_t __cdecl wcstombs
  88.         (
  89.         char * s,
  90.         const wchar_t * pwcs,
  91.         size_t n
  92.         )
  93. {
  94.         int retval;
  95.         int local_lock_flag;
  96.  
  97.         _lock_locale( local_lock_flag )
  98.         retval = _wcstombs_lk(s, pwcs, n);
  99.         _unlock_locale( local_lock_flag );
  100.         return retval;
  101. }
  102.  
  103. #endif  /* _MT */
  104.  
  105. #ifdef _MT
  106. size_t __cdecl _wcstombs_lk
  107. #else  /* _MT */
  108. size_t __cdecl wcstombs
  109. #endif  /* _MT */
  110.         (
  111.         char * s,
  112.         const wchar_t * pwcs,
  113.         size_t n
  114.         )
  115. {
  116.         size_t count = 0;
  117. #ifndef _MAC
  118.         int i, retval;
  119.         char buffer[MB_LEN_MAX];
  120.         BOOL defused = 0;
  121. #endif  /* _MAC */
  122.         if (s && n == 0)
  123.             /* dest string exists, but 0 bytes converted */
  124.             return (size_t) 0;
  125.  
  126.         _ASSERTE(pwcs != NULL);
  127.  
  128. #ifndef _MAC
  129.  
  130.  
  131.         /* if destination string exists, fill it in */
  132.         if (s)
  133.         {
  134.             if (__lc_handle[LC_CTYPE] == _CLOCALEHANDLE)
  135.             {
  136.                 /* C locale: easy and fast */
  137.                 while(count < n)
  138.                 {
  139.                     if (*pwcs > 255)  /* validate high byte */
  140.                     {
  141.                         errno = EILSEQ;
  142.                         return (size_t)-1;  /* error */
  143.                     }
  144.                     s[count] = (char) *pwcs;
  145.                     if (*pwcs++ == L'\0')
  146.                         return count;
  147.                     count++;
  148.                 }
  149.                 return count;
  150.             } else {
  151.  
  152.                 if (1 == MB_CUR_MAX)
  153.                 {
  154.                     /* If SBCS, one wchar_t maps to one char */
  155.  
  156.                     /* WideCharToMultiByte will compare past NULL - reset n */
  157.                     if (n > 0)
  158.                         n = wcsncnt(pwcs, n);
  159.  
  160.                     if ( ((count = WideCharToMultiByte( __lc_codepage,
  161.                                                         WC_COMPOSITECHECK |
  162.                                                             WC_SEPCHARS,
  163.                                                         pwcs,
  164.                                                         n,
  165.                                                         s,
  166.                                                         n,
  167.                                                         NULL,
  168.                                                         &defused )) != 0) &&
  169.                          (!defused) )
  170.                     {
  171.                         if (*(s + count - 1) == '\0')
  172.                             count--; /* don't count NUL */
  173.  
  174.                         return count;
  175.                     }
  176.  
  177.                     errno = EILSEQ;
  178.                     return (size_t)-1;
  179.                 }
  180.                 else {
  181.  
  182.                     /* If MBCS, wchar_t to char mapping unknown */
  183.  
  184.                     /* Assume that usually the buffer is large enough */
  185.                     if ( ((count = WideCharToMultiByte( __lc_codepage,
  186.                                                         WC_COMPOSITECHECK |
  187.                                                             WC_SEPCHARS,
  188.                                                         pwcs,
  189.                                                         -1,
  190.                                                         s,
  191.                                                         n,
  192.                                                         NULL,
  193.                                                         &defused )) != 0) &&
  194.                          (!defused) )
  195.                     {
  196.                         return count - 1; /* don't count NUL */
  197.                     }
  198.  
  199.                     if (defused || GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  200.                     {
  201.                         errno = EILSEQ;
  202.                         return (size_t)-1;
  203.                     }
  204.  
  205.                     /* buffer not large enough, must do char by char */
  206.                     while (count < n)
  207.                     {
  208.                         if ( ((retval = WideCharToMultiByte( __lc_codepage,
  209.                                                              0,
  210.                                                              pwcs,
  211.                                                              1,
  212.                                                              buffer,
  213.                                                              MB_CUR_MAX,
  214.                                                              NULL,
  215.                                                              &defused )) == 0)
  216.                              || defused )
  217.                         {
  218.                             errno = EILSEQ;
  219.                             return (size_t)-1;
  220.                         }
  221.  
  222.                         if (count + retval > n)
  223.                             return count;
  224.  
  225.                         for (i = 0; i < retval; i++, count++) /* store character */
  226.                             if((s[count] = buffer[i])=='\0')
  227.                                 return count;
  228.  
  229.                         pwcs++;
  230.                     }
  231.  
  232.                     return count;
  233.                 }
  234.             }
  235.         }
  236.         else { /* s == NULL, get size only, pwcs must be NUL-terminated */
  237.  
  238.             if (__lc_handle[LC_CTYPE] == _CLOCALEHANDLE)
  239.                 return wcslen(pwcs);
  240.             else {
  241.                 if (((count=WideCharToMultiByte(__lc_codepage,
  242.                 WC_COMPOSITECHECK | WC_SEPCHARS,
  243.                 pwcs, -1, NULL, 0, NULL, &defused)) == 0) || (defused))
  244.                 {
  245.                     errno = EILSEQ;
  246.                     return (size_t)-1;
  247.                 }
  248.  
  249.                 return count - 1;
  250.             }
  251.         }
  252.  
  253. #else  /* _MAC */
  254.  
  255.         /* if destination string exists, fill it in */
  256.         if (s)
  257.         {
  258.             /* C locale: easy and fast */
  259.             while(count < n)
  260.             {
  261.                 if (*pwcs > 255)  /* validate high byte */
  262.                 {
  263.                     errno = EILSEQ;
  264.                     return (size_t)-1;  /* error */
  265.                 }
  266.                 s[count] = (char) *pwcs;
  267.                 if (*pwcs++ == L'\0')
  268.                     return count;
  269.                 count++;
  270.             }
  271.             return count;
  272.  
  273.         } else { /* s == NULL, get size only, pwcs must be NUL-terminated */
  274.             const wchar_t *eos = pwcs;
  275.  
  276.             while( *eos++ ) ;
  277.  
  278.             return( (size_t)(eos - pwcs - 1) );
  279.         }
  280.  
  281. #endif  /* _MAC */
  282. }
  283.