"Fossies" - the Fresh Open Source Software Archive

Member "wine-6.0.1/dlls/msvcrt/wcs.c" (7 Jun 2021, 77055 Bytes) of package /linux/misc/wine-6.0.1.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "wcs.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 6.0_vs_6.0.1.

    1 /*
    2  * msvcrt.dll wide-char functions
    3  *
    4  * Copyright 1999 Alexandre Julliard
    5  * Copyright 2000 Jon Griffiths
    6  *
    7  * This library is free software; you can redistribute it and/or
    8  * modify it under the terms of the GNU Lesser General Public
    9  * License as published by the Free Software Foundation; either
   10  * version 2.1 of the License, or (at your option) any later version.
   11  *
   12  * This library is distributed in the hope that it will be useful,
   13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   15  * Lesser General Public License for more details.
   16  *
   17  * You should have received a copy of the GNU Lesser General Public
   18  * License along with this library; if not, write to the Free Software
   19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
   20  */
   21 
   22 #define _NO_CRT_STDIO_INLINE
   23 #include <limits.h>
   24 #include <locale.h>
   25 #include <math.h>
   26 #include <assert.h>
   27 #include <wchar.h>
   28 #include <wctype.h>
   29 #include "msvcrt.h"
   30 #include "winnls.h"
   31 #include "wtypes.h"
   32 #include "wine/debug.h"
   33 
   34 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
   35 
   36 typedef struct
   37 {
   38     enum { LEN_DEFAULT, LEN_SHORT, LEN_LONG } IntegerLength;
   39     BOOLEAN IntegerDouble, IntegerNative, LeftAlign, Alternate, PadZero;
   40     BOOLEAN WideString, NaturalString;
   41     int FieldLength, Precision;
   42     char Sign, Format;
   43 } pf_flags;
   44 
   45 static BOOL n_format_enabled = TRUE;
   46 
   47 #include "printf.h"
   48 #define PRINTF_WIDE
   49 #include "printf.h"
   50 #undef PRINTF_WIDE
   51 
   52 #if _MSVCR_VER>=80
   53 
   54 /*********************************************************************
   55  *      _get_printf_count_output (MSVCR80.@)
   56  */
   57 int CDECL _get_printf_count_output( void )
   58 {
   59     return n_format_enabled ? 1 : 0;
   60 }
   61 
   62 /*********************************************************************
   63  *      _set_printf_count_output (MSVCR80.@)
   64  */
   65 int CDECL _set_printf_count_output( int enable )
   66 {
   67     BOOL old = n_format_enabled;
   68     n_format_enabled = enable != 0;
   69     return old ? 1 : 0;
   70 }
   71 
   72 #endif /* _MSVCR_VER>=80 */
   73 
   74 /*********************************************************************
   75  *      _wcsdup (MSVCRT.@)
   76  */
   77 wchar_t* CDECL _wcsdup( const wchar_t* str )
   78 {
   79   wchar_t* ret = NULL;
   80   if (str)
   81   {
   82     int size = (wcslen(str) + 1) * sizeof(wchar_t);
   83     ret = malloc( size );
   84     if (ret) memcpy( ret, str, size );
   85   }
   86   return ret;
   87 }
   88 
   89 /*********************************************************************
   90  *              _towlower_l (MSVCRT.@)
   91  */
   92 wint_t CDECL _towlower_l(wint_t c, _locale_t locale)
   93 {
   94     pthreadlocinfo locinfo;
   95     wchar_t ret;
   96 
   97     if(!locale)
   98         locinfo = get_locinfo();
   99     else
  100         locinfo = locale->locinfo;
  101 
  102     if(!locinfo->lc_handle[LC_CTYPE]) {
  103         if(c >= 'A' && c <= 'Z')
  104             return c + 'a' - 'A';
  105         return c;
  106     }
  107 
  108     if(!LCMapStringW(locinfo->lc_handle[LC_CTYPE], LCMAP_LOWERCASE, &c, 1, &ret, 1))
  109         return c;
  110     return ret;
  111 }
  112 
  113 /*********************************************************************
  114  *              towlower (MSVCRT.@)
  115  */
  116 wint_t CDECL towlower(wint_t c)
  117 {
  118     return _towlower_l(c, NULL);
  119 }
  120 
  121 INT CDECL _wcsicmp_l(const wchar_t *str1, const wchar_t *str2, _locale_t locale)
  122 {
  123     _locale_tstruct tmp = {0};
  124     wchar_t c1, c2;
  125 
  126     if(!MSVCRT_CHECK_PMT(str1 != NULL) || !MSVCRT_CHECK_PMT(str2 != NULL))
  127         return _NLSCMPERROR;
  128 
  129     if(!locale)
  130         locale = get_current_locale_noalloc(&tmp);
  131 
  132     do
  133     {
  134         c1 = _towlower_l(*str1++, locale);
  135         c2 = _towlower_l(*str2++, locale);
  136     } while(c1 && (c1 == c2));
  137 
  138     free_locale_noalloc(&tmp);
  139     return c1 - c2;
  140 }
  141 
  142 /*********************************************************************
  143  *      towctrans (MSVCR120.@)
  144  */
  145 wint_t CDECL towctrans(wint_t c, wctrans_t category)
  146 {
  147     if(category == 1)
  148         return _towupper_l(c, NULL);
  149     return _towlower_l(c, NULL);
  150 }
  151 
  152 /*********************************************************************
  153  *      _wcsicmp (MSVCRT.@)
  154  */
  155 INT CDECL _wcsicmp( const wchar_t* str1, const wchar_t* str2 )
  156 {
  157     return _wcsicmp_l(str1, str2, NULL);
  158 }
  159 
  160 /*********************************************************************
  161  *              _wcsnicmp_l (MSVCRT.@)
  162  */
  163 INT CDECL _wcsnicmp_l(const wchar_t *str1, const wchar_t *str2,
  164         size_t n, _locale_t locale)
  165 {
  166     _locale_tstruct tmp = {0};
  167     wchar_t c1, c2;
  168 
  169     if (!n)
  170         return 0;
  171 
  172     if(!MSVCRT_CHECK_PMT(str1 != NULL) || !MSVCRT_CHECK_PMT(str2 != NULL))
  173         return _NLSCMPERROR;
  174 
  175     if(!locale)
  176         locale = get_current_locale_noalloc(&tmp);
  177 
  178     do
  179     {
  180         c1 = _towlower_l(*str1++, locale);
  181         c2 = _towlower_l(*str2++, locale);
  182     } while(--n && c1 && (c1 == c2));
  183 
  184     free_locale_noalloc(&tmp);
  185     return c1 - c2;
  186 }
  187 
  188 /*********************************************************************
  189  *              _wcsnicmp (MSVCRT.@)
  190  */
  191 INT CDECL _wcsnicmp(const wchar_t *str1, const wchar_t *str2, size_t n)
  192 {
  193     return _wcsnicmp_l(str1, str2, n, NULL);
  194 }
  195 
  196 /*********************************************************************
  197  *              _wcsicoll_l (MSVCRT.@)
  198  */
  199 int CDECL _wcsicoll_l(const wchar_t* str1, const wchar_t* str2, _locale_t locale)
  200 {
  201     pthreadlocinfo locinfo;
  202 
  203     if(!locale)
  204         locinfo = get_locinfo();
  205     else
  206         locinfo = locale->locinfo;
  207 
  208     if(!locinfo->lc_handle[LC_COLLATE])
  209     {
  210         wchar_t c1, c2;
  211 
  212         do
  213         {
  214             c1 = *str1++;
  215             if (c1 >= 'A' && c1 <= 'Z')
  216                 c1 += 'a' - 'A';
  217 
  218             c2 = *str2++;
  219             if (c2 >= 'A' && c2 <= 'Z')
  220                 c2 += 'a' - 'A';
  221         } while(c1 && (c1 == c2));
  222         return c1 - c2;
  223     }
  224 
  225     return CompareStringW(locinfo->lc_handle[LC_COLLATE], NORM_IGNORECASE,
  226               str1, -1, str2, -1)-CSTR_EQUAL;
  227 }
  228 
  229 /*********************************************************************
  230  *      _wcsicoll (MSVCRT.@)
  231  */
  232 INT CDECL _wcsicoll( const wchar_t* str1, const wchar_t* str2 )
  233 {
  234     return _wcsicoll_l(str1, str2, NULL);
  235 }
  236 
  237 /*********************************************************************
  238  *              _wcsnicoll_l (MSVCRT.@)
  239  */
  240 int CDECL _wcsnicoll_l(const wchar_t* str1, const wchar_t* str2,
  241                   size_t count, _locale_t locale)
  242 {
  243     pthreadlocinfo locinfo;
  244 
  245     if(!locale)
  246         locinfo = get_locinfo();
  247     else
  248         locinfo = locale->locinfo;
  249 
  250     if(!locinfo->lc_handle[LC_COLLATE])
  251     {
  252         wchar_t c1, c2;
  253 
  254         if (!count)
  255             return 0;
  256 
  257         do
  258         {
  259             c1 = *str1++;
  260             if (c1 >= 'A' && c1 <= 'Z')
  261                 c1 += 'a' - 'A';
  262 
  263             c2 = *str2++;
  264             if (c2 >= 'A' && c2 <= 'Z')
  265                 c2 += 'a' - 'A';
  266         } while(--count && c1 && (c1 == c2));
  267         return c1 - c2;
  268     }
  269 
  270     return CompareStringW(locinfo->lc_handle[LC_COLLATE], NORM_IGNORECASE,
  271               str1, wcsnlen(str1, count),
  272                           str2, wcsnlen(str2, count))-CSTR_EQUAL;
  273 }
  274 
  275 /*********************************************************************
  276  *      _wcsnicoll (MSVCRT.@)
  277  */
  278 INT CDECL _wcsnicoll( const wchar_t* str1, const wchar_t* str2, size_t count )
  279 {
  280     return _wcsnicoll_l(str1, str2, count, NULL);
  281 }
  282 
  283 /*********************************************************************
  284  *      _wcsnset (MSVCRT.@)
  285  */
  286 wchar_t* CDECL _wcsnset( wchar_t* str, wchar_t c, size_t n )
  287 {
  288   wchar_t* ret = str;
  289   while ((n-- > 0) && *str) *str++ = c;
  290   return ret;
  291 }
  292 
  293 /*********************************************************************
  294  *              _wcsnset_s (MSVCRT.@)
  295  */
  296 int CDECL _wcsnset_s( wchar_t *str, size_t size, wchar_t c, size_t count )
  297 {
  298     size_t i;
  299 
  300     if(!str && !size && !count) return 0;
  301     if(!MSVCRT_CHECK_PMT(str != NULL)) return EINVAL;
  302     if(!MSVCRT_CHECK_PMT(size > 0)) return EINVAL;
  303 
  304     for(i=0; i<size-1 && i<count; i++) {
  305         if(!str[i]) return 0;
  306         str[i] = c;
  307     }
  308     for(; i<size; i++)
  309         if(!str[i]) return 0;
  310 
  311     str[0] = 0;
  312     _invalid_parameter(NULL, NULL, NULL, 0, 0);
  313     *_errno() = EINVAL;
  314     return EINVAL;
  315 }
  316 
  317 /*********************************************************************
  318  *      _wcsrev (MSVCRT.@)
  319  */
  320 wchar_t* CDECL _wcsrev( wchar_t* str )
  321 {
  322   wchar_t* ret = str;
  323   wchar_t* end = str + wcslen(str) - 1;
  324   while (end > str)
  325   {
  326     wchar_t t = *end;
  327     *end--  = *str;
  328     *str++  = t;
  329   }
  330   return ret;
  331 }
  332 
  333 /*********************************************************************
  334  *              _wcsset_s (MSVCRT.@)
  335  */
  336 int CDECL _wcsset_s( wchar_t *str, size_t n, wchar_t c )
  337 {
  338     wchar_t *p = str;
  339 
  340     if(!MSVCRT_CHECK_PMT(str != NULL)) return EINVAL;
  341     if(!MSVCRT_CHECK_PMT(n)) return EINVAL;
  342 
  343     while(*p && --n) *p++ = c;
  344     if(!n) {
  345         str[0] = 0;
  346         _invalid_parameter(NULL, NULL, NULL, 0, 0);
  347         *_errno() = EINVAL;
  348         return EINVAL;
  349     }
  350     return 0;
  351 }
  352 
  353 /*********************************************************************
  354  *      _wcsset (MSVCRT.@)
  355  */
  356 wchar_t* CDECL _wcsset( wchar_t* str, wchar_t c )
  357 {
  358   wchar_t* ret = str;
  359   while (*str) *str++ = c;
  360   return ret;
  361 }
  362 
  363 /******************************************************************
  364  *      _wcsupr_s_l (MSVCRT.@)
  365  */
  366 int CDECL _wcsupr_s_l( wchar_t* str, size_t n, _locale_t locale )
  367 {
  368   _locale_tstruct tmp = {0};
  369   wchar_t* ptr = str;
  370 
  371   if (!str || !n)
  372   {
  373     if (str) *str = '\0';
  374     *_errno() = EINVAL;
  375     return EINVAL;
  376   }
  377 
  378   if(!locale)
  379     locale = get_current_locale_noalloc(&tmp);
  380 
  381   while (n--)
  382   {
  383     if (!*ptr)
  384     {
  385       free_locale_noalloc(&tmp);
  386       return 0;
  387     }
  388     *ptr = _towupper_l(*ptr, locale);
  389     ptr++;
  390   }
  391 
  392   free_locale_noalloc(&tmp);
  393 
  394   /* MSDN claims that the function should return and set errno to
  395    * ERANGE, which doesn't seem to be true based on the tests. */
  396   *str = '\0';
  397   *_errno() = EINVAL;
  398   return EINVAL;
  399 }
  400 
  401 /******************************************************************
  402  *      _wcsupr_s (MSVCRT.@)
  403  *
  404  */
  405 INT CDECL _wcsupr_s( wchar_t* str, size_t n )
  406 {
  407   return _wcsupr_s_l( str, n, NULL );
  408 }
  409 
  410 /******************************************************************
  411  *              _wcsupr_l (MSVCRT.@)
  412  */
  413 wchar_t* CDECL _wcsupr_l( wchar_t *str, _locale_t locale )
  414 {
  415     _wcsupr_s_l( str, -1, locale);
  416     return str;
  417 }
  418 
  419 /******************************************************************
  420  *              _wcsupr (MSVCRT.@)
  421  */
  422 wchar_t* CDECL _wcsupr( wchar_t *str )
  423 {
  424     return _wcsupr_l(str, NULL);
  425 }
  426 
  427 /******************************************************************
  428  *      _wcslwr_s_l (MSVCRT.@)
  429  */
  430 int CDECL _wcslwr_s_l( wchar_t* str, size_t n, _locale_t locale )
  431 {
  432   _locale_tstruct tmp = {0};
  433   wchar_t* ptr = str;
  434 
  435   if (!str || !n)
  436   {
  437     if (str) *str = '\0';
  438     *_errno() = EINVAL;
  439     return EINVAL;
  440   }
  441 
  442   if(!locale)
  443     locale = get_current_locale_noalloc(&tmp);
  444 
  445   while (n--)
  446   {
  447     if (!*ptr)
  448     {
  449       free_locale_noalloc(&tmp);
  450       return 0;
  451     }
  452     *ptr = _towlower_l(*ptr, locale);
  453     ptr++;
  454   }
  455 
  456   free_locale_noalloc(&tmp);
  457 
  458   /* MSDN claims that the function should return and set errno to
  459    * ERANGE, which doesn't seem to be true based on the tests. */
  460   *str = '\0';
  461   *_errno() = EINVAL;
  462   return EINVAL;
  463 }
  464 
  465 /******************************************************************
  466  *      _wcslwr_s (MSVCRT.@)
  467  */
  468 int CDECL _wcslwr_s( wchar_t* str, size_t n )
  469 {
  470     return _wcslwr_s_l(str, n, NULL);
  471 }
  472 
  473 /******************************************************************
  474  *      _wcslwr_l (MSVCRT.@)
  475  */
  476 wchar_t* CDECL _wcslwr_l( wchar_t* str, _locale_t locale )
  477 {
  478     _wcslwr_s_l(str, -1, locale);
  479     return str;
  480 }
  481 
  482 /******************************************************************
  483  *      _wcslwr (MSVCRT.@)
  484  */
  485 wchar_t* CDECL _wcslwr( wchar_t* str )
  486 {
  487     _wcslwr_s_l(str, -1, NULL);
  488     return str;
  489 }
  490 
  491 /*********************************************************************
  492  *           wcsncmp    (MSVCRT.@)
  493  */
  494 int CDECL wcsncmp(const wchar_t *str1, const wchar_t *str2, size_t n)
  495 {
  496     if (!n)
  497         return 0;
  498     while(--n && *str1 && (*str1 == *str2))
  499     {
  500         str1++;
  501         str2++;
  502     }
  503     return *str1 - *str2;
  504 }
  505 
  506 /*********************************************************************
  507  *              _wcsncoll_l (MSVCRT.@)
  508  */
  509 int CDECL _wcsncoll_l(const wchar_t* str1, const wchar_t* str2,
  510                   size_t count, _locale_t locale)
  511 {
  512     pthreadlocinfo locinfo;
  513 
  514     if(!locale)
  515         locinfo = get_locinfo();
  516     else
  517         locinfo = locale->locinfo;
  518 
  519     if(!locinfo->lc_handle[LC_COLLATE])
  520         return wcsncmp(str1, str2, count);
  521     return CompareStringW(locinfo->lc_handle[LC_COLLATE], 0,
  522               str1, wcsnlen(str1, count),
  523               str2, wcsnlen(str2, count))-CSTR_EQUAL;
  524 }
  525 
  526 /*********************************************************************
  527  *              _wcsncoll (MSVCRT.@)
  528  */
  529 int CDECL _wcsncoll(const wchar_t* str1, const wchar_t* str2, size_t count)
  530 {
  531     return _wcsncoll_l(str1, str2, count, NULL);
  532 }
  533 
  534 static wchar_t strtod_wstr_get(void *ctx)
  535 {
  536     const wchar_t **p = ctx;
  537     if (!**p) return WEOF;
  538     return *(*p)++;
  539 }
  540 
  541 static void strtod_wstr_unget(void *ctx)
  542 {
  543     const wchar_t **p = ctx;
  544     (*p)--;
  545 }
  546 
  547 /*********************************************************************
  548  *      _wcstod_l (MSVCRT.@)
  549  */
  550 double CDECL _wcstod_l(const wchar_t* str, wchar_t** end,
  551         _locale_t locale)
  552 {
  553     pthreadlocinfo locinfo;
  554     const wchar_t *beg, *p;
  555     struct fpnum fp;
  556     double ret;
  557     int err;
  558 
  559     if (!MSVCRT_CHECK_PMT(str != NULL)) {
  560         if (end) *end = NULL;
  561         return 0;
  562     }
  563 
  564     if (!locale)
  565         locinfo = get_locinfo();
  566     else
  567         locinfo = locale->locinfo;
  568 
  569     p = str;
  570     while(_iswspace_l(*p, locale))
  571         p++;
  572     beg = p;
  573 
  574     fp = fpnum_parse(strtod_wstr_get, strtod_wstr_unget, &p, locinfo, FALSE);
  575     if (end) *end = (p == beg ? (wchar_t*)str : (wchar_t*)p);
  576 
  577     err = fpnum_double(&fp, &ret);
  578     if(err) *_errno() = err;
  579     return ret;
  580 }
  581 
  582 /*********************************************************************
  583  * wcsrtombs_l (INTERNAL)
  584  */
  585 static size_t wcsrtombs_l(char *mbstr, const wchar_t **wcstr,
  586         size_t count, _locale_t locale)
  587 {
  588     pthreadlocinfo locinfo;
  589     size_t tmp = 0;
  590     BOOL used_default = FALSE;
  591     BOOL *pused_default;
  592 
  593     if(!locale)
  594         locinfo = get_locinfo();
  595     else
  596         locinfo = locale->locinfo;
  597 
  598     if(!locinfo->lc_codepage) {
  599         size_t i;
  600 
  601         if(!mbstr)
  602             return wcslen(*wcstr);
  603 
  604         for(i=0; i<count; i++) {
  605             if((*wcstr)[i] > 255) {
  606                 *_errno() = EILSEQ;
  607                 return -1;
  608             }
  609 
  610             mbstr[i] = (*wcstr)[i];
  611             if(!(*wcstr)[i]) break;
  612         }
  613 
  614         if(i < count) *wcstr = NULL;
  615         else *wcstr += i;
  616         return i;
  617     }
  618 
  619     pused_default = (locinfo->lc_codepage != CP_UTF8 ? &used_default : NULL);
  620 
  621     if(!mbstr) {
  622         tmp = WideCharToMultiByte(locinfo->lc_codepage, WC_NO_BEST_FIT_CHARS,
  623                 *wcstr, -1, NULL, 0, NULL, pused_default);
  624         if(!tmp || used_default) {
  625             *_errno() = EILSEQ;
  626             return -1;
  627         }
  628         return tmp-1;
  629     }
  630 
  631     while(**wcstr) {
  632         char buf[3];
  633         size_t i, size;
  634 
  635         size = WideCharToMultiByte(locinfo->lc_codepage, WC_NO_BEST_FIT_CHARS,
  636                 *wcstr, 1, buf, 3, NULL, pused_default);
  637         if(!size || used_default) {
  638             *_errno() = EILSEQ;
  639             return -1;
  640         }
  641         if(tmp+size > count)
  642             return tmp;
  643 
  644         for(i=0; i<size; i++)
  645             mbstr[tmp++] = buf[i];
  646         (*wcstr)++;
  647     }
  648 
  649     if(tmp < count) {
  650         mbstr[tmp] = '\0';
  651         *wcstr = NULL;
  652     }
  653     return tmp;
  654 }
  655 
  656 /*********************************************************************
  657  *      _wcstombs_l (MSVCRT.@)
  658  */
  659 size_t CDECL _wcstombs_l(char *mbstr, const wchar_t *wcstr,
  660         size_t count, _locale_t locale)
  661 {
  662     return wcsrtombs_l(mbstr, &wcstr, count, locale);
  663 }
  664 
  665 /*********************************************************************
  666  *      wcstombs (MSVCRT.@)
  667  */
  668 size_t CDECL wcstombs(char *mbstr, const wchar_t *wcstr,
  669         size_t count)
  670 {
  671     return wcsrtombs_l(mbstr, &wcstr, count, NULL);
  672 }
  673 
  674 /*********************************************************************
  675  *      wcsrtombs (MSVCRT.@)
  676  */
  677 size_t CDECL wcsrtombs(char *mbstr, const wchar_t **wcstr,
  678         size_t count, mbstate_t *mbstate)
  679 {
  680     if(mbstate)
  681         *mbstate = 0;
  682 
  683     return wcsrtombs_l(mbstr, wcstr, count, NULL);
  684 }
  685 
  686 /*********************************************************************
  687  * wcsrtombs_s_l (INTERNAL)
  688  */
  689 static int wcsrtombs_s_l(size_t *ret, char *mbstr, size_t size,
  690         const wchar_t **wcstr, size_t count, _locale_t locale)
  691 {
  692     size_t conv;
  693     int err;
  694 
  695     if(!mbstr && !size && wcstr) {
  696         conv = wcsrtombs_l(NULL, wcstr, 0, locale);
  697         if(ret)
  698             *ret = conv+1;
  699         if(conv == -1)
  700             return *_errno();
  701         return 0;
  702     }
  703 
  704     if (!MSVCRT_CHECK_PMT(mbstr != NULL)) return EINVAL;
  705     if (size) mbstr[0] = '\0';
  706     if (!MSVCRT_CHECK_PMT(wcstr != NULL)) return EINVAL;
  707     if (!MSVCRT_CHECK_PMT(*wcstr != NULL)) return EINVAL;
  708 
  709     if(count==_TRUNCATE || size<count)
  710         conv = size;
  711     else
  712         conv = count;
  713 
  714     err = 0;
  715     conv = wcsrtombs_l(mbstr, wcstr, conv, locale);
  716     if(conv == -1) {
  717         conv = 0;
  718         if(size)
  719             mbstr[0] = '\0';
  720         err = *_errno();
  721     }else if(conv < size)
  722         mbstr[conv++] = '\0';
  723     else if(conv==size && (count==_TRUNCATE || mbstr[conv-1]=='\0')) {
  724         mbstr[conv-1] = '\0';
  725         if(count==_TRUNCATE)
  726             err = STRUNCATE;
  727     }else {
  728         MSVCRT_INVALID_PMT("mbstr[size] is too small", ERANGE);
  729         conv = 0;
  730         if(size)
  731             mbstr[0] = '\0';
  732         err = ERANGE;
  733     }
  734 
  735     if(ret)
  736         *ret = conv;
  737     return err;
  738 }
  739 
  740 /*********************************************************************
  741  *      _wcstombs_s_l (MSVCRT.@)
  742  */
  743 int CDECL _wcstombs_s_l(size_t *ret, char *mbstr, size_t size,
  744         const wchar_t *wcstr, size_t count, _locale_t locale)
  745 {
  746     return wcsrtombs_s_l(ret, mbstr, size, &wcstr,count, locale);
  747 }
  748 
  749 /*********************************************************************
  750  *      wcstombs_s (MSVCRT.@)
  751  */
  752 int CDECL wcstombs_s(size_t *ret, char *mbstr, size_t size,
  753         const wchar_t *wcstr, size_t count)
  754 {
  755     return wcsrtombs_s_l(ret, mbstr, size, &wcstr, count, NULL);
  756 }
  757 
  758 /*********************************************************************
  759  *      wcsrtombs_s (MSVCRT.@)
  760  */
  761 int CDECL wcsrtombs_s(size_t *ret, char *mbstr, size_t size,
  762         const wchar_t **wcstr, size_t count, mbstate_t *mbstate)
  763 {
  764     if(mbstate)
  765         *mbstate = 0;
  766 
  767     return wcsrtombs_s_l(ret, mbstr, size, wcstr, count, NULL);
  768 }
  769 
  770 /*********************************************************************
  771  *      wcstod (MSVCRT.@)
  772  */
  773 double CDECL wcstod(const wchar_t* lpszStr, wchar_t** end)
  774 {
  775     return _wcstod_l(lpszStr, end, NULL);
  776 }
  777 
  778 /*********************************************************************
  779  *      _wtof (MSVCRT.@)
  780  */
  781 double CDECL _wtof(const wchar_t *str)
  782 {
  783     return _wcstod_l(str, NULL, NULL);
  784 }
  785 
  786 /*********************************************************************
  787  *      _wtof_l (MSVCRT.@)
  788  */
  789 double CDECL _wtof_l(const wchar_t *str, _locale_t locale)
  790 {
  791     return _wcstod_l(str, NULL, locale);
  792 }
  793 
  794 #if _MSVCR_VER>=120
  795 
  796 /*********************************************************************
  797  *              _wcstof_l  (MSVCR120.@)
  798  */
  799 float CDECL _wcstof_l( const wchar_t *str, wchar_t **end, _locale_t locale )
  800 {
  801     return _wcstod_l(str, end, locale);
  802 }
  803 
  804 /*********************************************************************
  805  *              wcstof  (MSVCR120.@)
  806  */
  807 float CDECL wcstof( const wchar_t *str, wchar_t **end )
  808 {
  809     return _wcstof_l(str, end, NULL);
  810 }
  811 
  812 #endif /* _MSVCR_VER>=120 */
  813 
  814 /*********************************************************************
  815  * arg_clbk_valist (INTERNAL)
  816  */
  817 printf_arg arg_clbk_valist(void *ctx, int arg_pos, int type, __ms_va_list *valist)
  818 {
  819     printf_arg ret;
  820 
  821     if(type == VT_I8)
  822         ret.get_longlong = va_arg(*valist, LONGLONG);
  823     else if(type == VT_INT)
  824         ret.get_int = va_arg(*valist, int);
  825     else if(type == VT_R8)
  826         ret.get_double = va_arg(*valist, double);
  827     else if(type == VT_PTR)
  828         ret.get_ptr = va_arg(*valist, void*);
  829     else {
  830         ERR("Incorrect type\n");
  831         ret.get_int = 0;
  832     }
  833 
  834     return ret;
  835 }
  836 
  837 /*********************************************************************
  838  * arg_clbk_positional (INTERNAL)
  839  */
  840 printf_arg arg_clbk_positional(void *ctx, int pos, int type, __ms_va_list *valist)
  841 {
  842     printf_arg *args = ctx;
  843     return args[pos];
  844 }
  845 
  846 #if _MSVCR_VER < 140
  847 
  848 /*********************************************************************
  849  *              _vsnprintf (MSVCRT.@)
  850  */
  851 int CDECL _vsnprintf( char *str, size_t len, const char *format, __ms_va_list valist )
  852 {
  853     static const char nullbyte = '\0';
  854     struct _str_ctx_a ctx = {len, str};
  855     int ret;
  856 
  857     ret = pf_printf_a(puts_clbk_str_a, &ctx, format, NULL, 0,
  858             arg_clbk_valist, NULL, &valist);
  859     puts_clbk_str_a(&ctx, 1, &nullbyte);
  860     return ret;
  861 }
  862 
  863 #else
  864 
  865 static int puts_clbk_str_c99_a(void *ctx, int len, const char *str)
  866 {
  867     struct _str_ctx_a *out = ctx;
  868 
  869     if(!out->buf)
  870         return len;
  871 
  872     if(out->len < len) {
  873         memmove(out->buf, str, out->len);
  874         out->buf += out->len;
  875         out->len = 0;
  876         return len;
  877     }
  878 
  879     memmove(out->buf, str, len);
  880     out->buf += len;
  881     out->len -= len;
  882     return len;
  883 }
  884 
  885 /*********************************************************************
  886  *              __stdio_common_vsprintf (UCRTBASE.@)
  887  */
  888 int CDECL __stdio_common_vsprintf( unsigned __int64 options, char *str, size_t len, const char *format,
  889                                    _locale_t locale, __ms_va_list valist )
  890 {
  891     static const char nullbyte = '\0';
  892     struct _str_ctx_a ctx = {len, str};
  893     int ret;
  894 
  895     if (options & ~UCRTBASE_PRINTF_MASK)
  896         FIXME("options %s not handled\n", wine_dbgstr_longlong(options));
  897     ret = pf_printf_a(puts_clbk_str_c99_a,
  898             &ctx, format, (_locale_t)locale, options & UCRTBASE_PRINTF_MASK, arg_clbk_valist, NULL, &valist);
  899     puts_clbk_str_a(&ctx, 1, &nullbyte);
  900 
  901     if(!str)
  902         return ret;
  903     if(options & _CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION)
  904         return ret>len ? -1 : ret;
  905     if(ret>=len) {
  906         if(len) str[len-1] = 0;
  907         if(options & _CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR)
  908             return ret;
  909         return len > 0 ? -2 : -1;
  910     }
  911     return ret;
  912 }
  913 
  914 #endif /* _MSVCR_VER>=140 */
  915 
  916 /*********************************************************************
  917  *      _vsnprintf_l (MSVCRT.@)
  918  */
  919 int CDECL _vsnprintf_l( char *str, size_t len, const char *format,
  920                             _locale_t locale, __ms_va_list valist )
  921 {
  922     static const char nullbyte = '\0';
  923     struct _str_ctx_a ctx = {len, str};
  924     int ret;
  925 
  926     ret = pf_printf_a(puts_clbk_str_a, &ctx, format, locale, 0,
  927             arg_clbk_valist, NULL, &valist);
  928     puts_clbk_str_a(&ctx, 1, &nullbyte);
  929     return ret;
  930 }
  931 
  932 /*********************************************************************
  933  *      _vsprintf_l (MSVCRT.@)
  934  */
  935 int CDECL _vsprintf_l( char *str, const char *format,
  936                             _locale_t locale, __ms_va_list valist )
  937 {
  938     return _vsnprintf_l(str, INT_MAX, format, locale, valist);
  939 }
  940 
  941 /*********************************************************************
  942  *      _sprintf_l (MSVCRT.@)
  943  */
  944 int WINAPIV _sprintf_l(char *str, const char *format,
  945                            _locale_t locale, ...)
  946 {
  947     int retval;
  948     __ms_va_list valist;
  949     __ms_va_start(valist, locale);
  950     retval = _vsnprintf_l(str, INT_MAX, format, locale, valist);
  951     __ms_va_end(valist);
  952     return retval;
  953 }
  954 
  955 static int CDECL vsnprintf_s_l_opt( char *str, size_t sizeOfBuffer,
  956         size_t count, const char *format, DWORD options,
  957         _locale_t locale, __ms_va_list valist )
  958 {
  959     static const char nullbyte = '\0';
  960     struct _str_ctx_a ctx;
  961     int len, ret;
  962 
  963     if(sizeOfBuffer<count+1 || count==-1)
  964         len = sizeOfBuffer;
  965     else
  966         len = count+1;
  967 
  968     ctx.len = len;
  969     ctx.buf = str;
  970     ret = pf_printf_a(puts_clbk_str_a, &ctx, format, locale, MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER | options,
  971             arg_clbk_valist, NULL, &valist);
  972     puts_clbk_str_a(&ctx, 1, &nullbyte);
  973 
  974     if(ret<0 || ret==len) {
  975         if(count!=_TRUNCATE && count>sizeOfBuffer) {
  976             MSVCRT_INVALID_PMT("str[sizeOfBuffer] is too small", ERANGE);
  977             memset(str, 0, sizeOfBuffer);
  978         } else
  979             str[len-1] = '\0';
  980 
  981         return -1;
  982     }
  983 
  984     return ret;
  985 }
  986 
  987 static int vsnwprintf_s_l_opt( wchar_t *str, size_t sizeOfBuffer,
  988         size_t count, const wchar_t *format, DWORD options,
  989         _locale_t locale, __ms_va_list valist)
  990 {
  991     struct _str_ctx_w ctx;
  992     int len, ret;
  993 
  994     len = sizeOfBuffer;
  995     if(count!=-1 && len>count+1)
  996         len = count+1;
  997 
  998     ctx.len = len;
  999     ctx.buf = str;
 1000     ret = pf_printf_w(puts_clbk_str_w, &ctx, format, locale, MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER | options,
 1001             arg_clbk_valist, NULL, &valist);
 1002     puts_clbk_str_w(&ctx, 1, L"");
 1003 
 1004     if(ret<0 || ret==len) {
 1005         if(count!=_TRUNCATE && count>sizeOfBuffer) {
 1006             MSVCRT_INVALID_PMT("str[sizeOfBuffer] is too small", ERANGE);
 1007             memset(str, 0, sizeOfBuffer*sizeof(wchar_t));
 1008         } else
 1009             str[len-1] = '\0';
 1010 
 1011         return -1;
 1012     }
 1013 
 1014     return ret;
 1015 }
 1016 
 1017 /*********************************************************************
 1018  *      _vsnprintf_s_l (MSVCRT.@)
 1019  */
 1020 int CDECL _vsnprintf_s_l( char *str, size_t sizeOfBuffer,
 1021         size_t count, const char *format,
 1022         _locale_t locale, __ms_va_list valist )
 1023 {
 1024     return vsnprintf_s_l_opt(str, sizeOfBuffer, count, format, 0, locale, valist);
 1025 }
 1026 
 1027 /*********************************************************************
 1028  *      _vsprintf_s_l (MSVCRT.@)
 1029  */
 1030 int CDECL _vsprintf_s_l( char *str, size_t count, const char *format,
 1031                                _locale_t locale, __ms_va_list valist )
 1032 {
 1033     return _vsnprintf_s_l(str, INT_MAX, count, format, locale, valist);
 1034 }
 1035 
 1036 /*********************************************************************
 1037  *      _sprintf_s_l (MSVCRT.@)
 1038  */
 1039 int WINAPIV _sprintf_s_l( char *str, size_t count, const char *format,
 1040                                 _locale_t locale, ...)
 1041 {
 1042     int retval;
 1043     __ms_va_list valist;
 1044     __ms_va_start(valist, locale);
 1045     retval = _vsnprintf_s_l(str, INT_MAX, count, format, locale, valist);
 1046     __ms_va_end(valist);
 1047     return retval;
 1048 }
 1049 
 1050 /*********************************************************************
 1051  *              _vsnprintf_s (MSVCRT.@)
 1052  */
 1053 int CDECL _vsnprintf_s( char *str, size_t sizeOfBuffer,
 1054         size_t count, const char *format, __ms_va_list valist )
 1055 {
 1056     return _vsnprintf_s_l(str,sizeOfBuffer, count, format, NULL, valist);
 1057 }
 1058 
 1059 /*********************************************************************
 1060  *              _vsnprintf_c_l (MSVCRT.@)
 1061  */
 1062 int CDECL _vsnprintf_c_l(char *str, size_t len, const char *format,
 1063         _locale_t locale, __ms_va_list valist)
 1064 {
 1065     return vsnprintf_s_l_opt(str, len, len, format, 0, locale, valist);
 1066 }
 1067 
 1068 /*********************************************************************
 1069  *              _vsnprintf_c (MSVCRT.@)
 1070  */
 1071 int CDECL _vsnprintf_c(char *str, size_t len,
 1072         const char *format, __ms_va_list valist)
 1073 {
 1074     return _vsnprintf_c_l(str, len, format, NULL, valist);
 1075 }
 1076 
 1077 #if _MSVCR_VER>=140
 1078 
 1079 /*********************************************************************
 1080  *              __stdio_common_vsnprintf_s (UCRTBASE.@)
 1081  */
 1082 int CDECL __stdio_common_vsnprintf_s( unsigned __int64 options,
 1083         char *str, size_t sizeOfBuffer, size_t count,
 1084         const char *format, _locale_t locale, __ms_va_list valist )
 1085 {
 1086     if (options & ~UCRTBASE_PRINTF_MASK)
 1087         FIXME("options %s not handled\n", wine_dbgstr_longlong(options));
 1088     return vsnprintf_s_l_opt(str, sizeOfBuffer, count, format, options & UCRTBASE_PRINTF_MASK, locale, valist);
 1089 }
 1090 
 1091 /*********************************************************************
 1092  *              __stdio_common_vsnwprintf_s (UCRTBASE.@)
 1093  */
 1094 int CDECL __stdio_common_vsnwprintf_s( unsigned __int64 options,
 1095         wchar_t *str, size_t sizeOfBuffer, size_t count,
 1096         const wchar_t *format, _locale_t locale, __ms_va_list valist )
 1097 {
 1098     if (options & ~UCRTBASE_PRINTF_MASK)
 1099         FIXME("options %s not handled\n", wine_dbgstr_longlong(options));
 1100     return vsnwprintf_s_l_opt(str, sizeOfBuffer, count, format, options & UCRTBASE_PRINTF_MASK, locale, valist);
 1101 }
 1102 
 1103 /*********************************************************************
 1104  *              __stdio_common_vswprintf_s (UCRTBASE.@)
 1105  */
 1106 int CDECL __stdio_common_vswprintf_s( unsigned __int64 options,
 1107         wchar_t *str, size_t count, const wchar_t *format,
 1108         _locale_t locale, __ms_va_list valist )
 1109 {
 1110     return __stdio_common_vsnwprintf_s(options, str, INT_MAX, count, format, locale, valist);
 1111 }
 1112 
 1113 /*********************************************************************
 1114  *              __stdio_common_vsprintf_s (UCRTBASE.@)
 1115  */
 1116 int CDECL __stdio_common_vsprintf_s( unsigned __int64 options,
 1117         char *str, size_t count, const char *format,
 1118         _locale_t locale, __ms_va_list valist )
 1119 {
 1120     if (options & ~UCRTBASE_PRINTF_MASK)
 1121         FIXME("options %s not handled\n", wine_dbgstr_longlong(options));
 1122     return vsnprintf_s_l_opt(str, INT_MAX, count, format, options & UCRTBASE_PRINTF_MASK, locale, valist);
 1123 }
 1124 
 1125 #endif /* _MSVCR_VER>=140 */
 1126 
 1127 /*********************************************************************
 1128  *      vsprintf (MSVCRT.@)
 1129  */
 1130 int CDECL vsprintf( char *str, const char *format, __ms_va_list valist)
 1131 {
 1132     return vsnprintf(str, INT_MAX, format, valist);
 1133 }
 1134 
 1135 /*********************************************************************
 1136  *      vsprintf_s (MSVCRT.@)
 1137  */
 1138 int CDECL vsprintf_s( char *str, size_t num, const char *format, __ms_va_list valist)
 1139 {
 1140     return vsnprintf(str, num, format, valist);
 1141 }
 1142 
 1143 /*********************************************************************
 1144  *      _vscprintf (MSVCRT.@)
 1145  */
 1146 int CDECL _vscprintf( const char *format, __ms_va_list valist )
 1147 {
 1148     return _vsnprintf_l( NULL, INT_MAX, format, NULL, valist );
 1149 }
 1150 
 1151 /*********************************************************************
 1152  *              _vscprintf_l (MSVCRT.@)
 1153  */
 1154 int CDECL _vscprintf_l(const char *format,
 1155         _locale_t locale, __ms_va_list valist)
 1156 {
 1157     return _vsnprintf_l(NULL, INT_MAX, format, locale, valist);
 1158 }
 1159 
 1160 /*********************************************************************
 1161  *      _vscprintf_p_l (MSVCRT.@)
 1162  */
 1163 int CDECL _vscprintf_p_l(const char *format,
 1164         _locale_t locale, __ms_va_list args)
 1165 {
 1166     printf_arg args_ctx[_ARGMAX+1];
 1167     struct _str_ctx_a puts_ctx = {INT_MAX, NULL};
 1168     int ret;
 1169 
 1170     memset(args_ctx, 0, sizeof(args_ctx));
 1171 
 1172     ret = create_positional_ctx_a(args_ctx, format, args);
 1173     if(ret < 0)  {
 1174         _invalid_parameter(NULL, NULL, NULL, 0, 0);
 1175         *_errno() = EINVAL;
 1176         return ret;
 1177     } else if(ret == 0) {
 1178         ret = pf_printf_a(puts_clbk_str_a, &puts_ctx, format, locale,
 1179                 MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER,
 1180                 arg_clbk_valist, NULL, &args);
 1181     } else {
 1182         ret = pf_printf_a(puts_clbk_str_a, &puts_ctx, format, locale,
 1183                 MSVCRT_PRINTF_POSITIONAL_PARAMS | MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER,
 1184                 arg_clbk_positional, args_ctx, NULL);
 1185     }
 1186 
 1187     return ret;
 1188 }
 1189 
 1190 /*********************************************************************
 1191  *      _vscprintf_p (MSVCR80.@)
 1192  */
 1193 int CDECL _vscprintf_p(const char *format, __ms_va_list argptr)
 1194 {
 1195     return _vscprintf_p_l(format, NULL, argptr);
 1196 }
 1197 
 1198 /*********************************************************************
 1199  *      _snprintf (MSVCRT.@)
 1200  */
 1201 int WINAPIV _snprintf(char *str, size_t len, const char *format, ...)
 1202 {
 1203     int retval;
 1204     __ms_va_list valist;
 1205     __ms_va_start(valist, format);
 1206     retval = vsnprintf(str, len, format, valist);
 1207     __ms_va_end(valist);
 1208     return retval;
 1209 }
 1210 
 1211 /*********************************************************************
 1212  *      _snprintf_l (MSVCRT.@)
 1213  */
 1214 int WINAPIV _snprintf_l(char *str, size_t count, const char *format,
 1215         _locale_t locale, ...)
 1216 {
 1217     int retval;
 1218     __ms_va_list valist;
 1219     __ms_va_start(valist, locale);
 1220     retval = _vsnprintf_l(str, count, format, locale, valist);
 1221     __ms_va_end(valist);
 1222     return retval;
 1223 }
 1224 
 1225 /*********************************************************************
 1226  *              _snprintf_c_l (MSVCRT.@)
 1227  */
 1228 int WINAPIV _snprintf_c_l(char *str, size_t count, const char *format,
 1229         _locale_t locale, ...)
 1230 {
 1231     int retval;
 1232     __ms_va_list valist;
 1233     __ms_va_start(valist, locale);
 1234     retval = _vsnprintf_c_l(str, count, format, locale, valist);
 1235     __ms_va_end(valist);
 1236     return retval;
 1237 }
 1238 
 1239 /*********************************************************************
 1240  *              _snprintf_c (MSVCRT.@)
 1241  */
 1242 int WINAPIV _snprintf_c(char *str, size_t count, const char *format, ...)
 1243 {
 1244     int retval;
 1245     __ms_va_list valist;
 1246     __ms_va_start(valist, format);
 1247     retval = _vsnprintf_c(str, count, format, valist);
 1248     __ms_va_end(valist);
 1249     return retval;
 1250 }
 1251 
 1252 /*********************************************************************
 1253  *              _snprintf_s_l (MSVCRT.@)
 1254  */
 1255 int WINAPIV _snprintf_s_l(char *str, size_t len, size_t count,
 1256         const char *format, _locale_t locale, ...)
 1257 {
 1258     int retval;
 1259     __ms_va_list valist;
 1260     __ms_va_start(valist, locale);
 1261     retval = _vsnprintf_s_l(str, len, count, format, locale, valist);
 1262     __ms_va_end(valist);
 1263     return retval;
 1264 }
 1265 
 1266 /*********************************************************************
 1267  *      _snprintf_s (MSVCRT.@)
 1268  */
 1269 int WINAPIV _snprintf_s(char *str, size_t len, size_t count,
 1270     const char *format, ...)
 1271 {
 1272     int retval;
 1273     __ms_va_list valist;
 1274     __ms_va_start(valist, format);
 1275     retval = _vsnprintf_s_l(str, len, count, format, NULL, valist);
 1276     __ms_va_end(valist);
 1277     return retval;
 1278 }
 1279 
 1280 /*********************************************************************
 1281  *              _scprintf (MSVCRT.@)
 1282  */
 1283 int WINAPIV _scprintf(const char *format, ...)
 1284 {
 1285     int retval;
 1286     __ms_va_list valist;
 1287     __ms_va_start(valist, format);
 1288     retval = _vscprintf(format, valist);
 1289     __ms_va_end(valist);
 1290     return retval;
 1291 }
 1292 
 1293 /*********************************************************************
 1294  *              _vsnwprintf (MSVCRT.@)
 1295  */
 1296 int CDECL _vsnwprintf(wchar_t *str, size_t len,
 1297         const wchar_t *format, __ms_va_list valist)
 1298 {
 1299     struct _str_ctx_w ctx = {len, str};
 1300     int ret;
 1301 
 1302     ret = pf_printf_w(puts_clbk_str_w, &ctx, format, NULL, 0,
 1303             arg_clbk_valist, NULL, &valist);
 1304     puts_clbk_str_w(&ctx, 1, L"");
 1305     return ret;
 1306 }
 1307 
 1308 /*********************************************************************
 1309  *              _vsnwprintf_l (MSVCRT.@)
 1310  */
 1311 int CDECL _vsnwprintf_l(wchar_t *str, size_t len, const wchar_t *format,
 1312         _locale_t locale, __ms_va_list valist)
 1313 {
 1314     struct _str_ctx_w ctx = {len, str};
 1315     int ret;
 1316 
 1317     ret = pf_printf_w(puts_clbk_str_w, &ctx, format, locale, 0,
 1318             arg_clbk_valist, NULL, &valist);
 1319     puts_clbk_str_w(&ctx, 1, L"");
 1320     return ret;
 1321 }
 1322 
 1323 /*********************************************************************
 1324  *              _vswprintf_c_l (MSVCRT.@)
 1325  */
 1326 int CDECL _vswprintf_c_l(wchar_t *str, size_t len, const wchar_t *format,
 1327         _locale_t locale, __ms_va_list valist)
 1328 {
 1329     return vsnwprintf_s_l_opt(str, len, len, format, 0, locale, valist);
 1330 }
 1331 
 1332 /*********************************************************************
 1333  *              _vswprintf_c (MSVCRT.@)
 1334  */
 1335 int CDECL _vswprintf_c(wchar_t *str, size_t len,
 1336         const wchar_t *format, __ms_va_list valist)
 1337 {
 1338     return _vswprintf_c_l(str, len, format, NULL, valist);
 1339 }
 1340 
 1341 static int vswprintf_p_l_opt(wchar_t *buffer, size_t length,
 1342         const wchar_t *format, DWORD options, _locale_t locale, __ms_va_list args)
 1343 {
 1344     printf_arg args_ctx[_ARGMAX+1];
 1345     struct _str_ctx_w puts_ctx = {length, buffer};
 1346     int ret;
 1347 
 1348     memset(args_ctx, 0, sizeof(args_ctx));
 1349 
 1350     ret = create_positional_ctx_w(args_ctx, format, args);
 1351     if(ret < 0)  {
 1352         _invalid_parameter(NULL, NULL, NULL, 0, 0);
 1353         *_errno() = EINVAL;
 1354         return ret;
 1355     } else if(ret == 0)
 1356         ret = pf_printf_w(puts_clbk_str_w, &puts_ctx, format, locale, MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER | options,
 1357                 arg_clbk_valist, NULL, &args);
 1358     else
 1359         ret = pf_printf_w(puts_clbk_str_w, &puts_ctx, format, locale,
 1360                 MSVCRT_PRINTF_POSITIONAL_PARAMS | MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER | options,
 1361                 arg_clbk_positional, args_ctx, NULL);
 1362 
 1363     puts_clbk_str_w(&puts_ctx, 1, L"");
 1364     return ret;
 1365 }
 1366 
 1367 /*********************************************************************
 1368  *      _vswprintf_p_l (MSVCRT.@)
 1369  */
 1370 int CDECL _vswprintf_p_l(wchar_t *buffer, size_t length,
 1371         const wchar_t *format, _locale_t locale, __ms_va_list args)
 1372 {
 1373     return vswprintf_p_l_opt(buffer, length, format, 0, locale, args);
 1374 }
 1375 
 1376 #if _MSVCR_VER>=80
 1377 /*********************************************************************
 1378  * _vswprintf_p (MSVCR80.@)
 1379  */
 1380 int CDECL _vswprintf_p(wchar_t *buffer, size_t length,
 1381         const wchar_t *format, __ms_va_list args)
 1382 {
 1383     return vswprintf_p_l_opt(buffer, length, format, 0, NULL, args);
 1384 }
 1385 #endif
 1386 
 1387 #if _MSVCR_VER>=140
 1388 /*********************************************************************
 1389  *              __stdio_common_vswprintf_p (UCRTBASE.@)
 1390  */
 1391 int CDECL __stdio_common_vswprintf_p( unsigned __int64 options,
 1392         wchar_t *str, size_t count, const wchar_t *format,
 1393         _locale_t locale, __ms_va_list valist )
 1394 {
 1395     if (options & ~UCRTBASE_PRINTF_MASK)
 1396         FIXME("options %s not handled\n", wine_dbgstr_longlong(options));
 1397     return vswprintf_p_l_opt(str, count, format, options & UCRTBASE_PRINTF_MASK, locale, valist);
 1398 }
 1399 #endif
 1400 
 1401 /*********************************************************************
 1402  *              _vsnwprintf_s_l (MSVCRT.@)
 1403  */
 1404 int CDECL _vsnwprintf_s_l( wchar_t *str, size_t sizeOfBuffer,
 1405         size_t count, const wchar_t *format,
 1406         _locale_t locale, __ms_va_list valist)
 1407 {
 1408     return vsnwprintf_s_l_opt(str, sizeOfBuffer, count, format, 0, locale, valist);
 1409 }
 1410 
 1411 /*********************************************************************
 1412  *              _vsnwprintf_s (MSVCRT.@)
 1413  */
 1414 int CDECL _vsnwprintf_s(wchar_t *str, size_t sizeOfBuffer,
 1415         size_t count, const wchar_t *format, __ms_va_list valist)
 1416 {
 1417     return _vsnwprintf_s_l(str, sizeOfBuffer, count,
 1418             format, NULL, valist);
 1419 }
 1420 
 1421 /*********************************************************************
 1422  *      _snwprintf (MSVCRT.@)
 1423  */
 1424 int WINAPIV _snwprintf( wchar_t *str, size_t len, const wchar_t *format, ...)
 1425 {
 1426     int retval;
 1427     __ms_va_list valist;
 1428     __ms_va_start(valist, format);
 1429     retval = _vsnwprintf(str, len, format, valist);
 1430     __ms_va_end(valist);
 1431     return retval;
 1432 }
 1433 
 1434 /*********************************************************************
 1435  *      _snwprintf_l (MSVCRT.@)
 1436  */
 1437 int WINAPIV _snwprintf_l( wchar_t *str, size_t len, const wchar_t *format,
 1438         _locale_t locale, ...)
 1439 {
 1440     int retval;
 1441     __ms_va_list valist;
 1442     __ms_va_start(valist, locale);
 1443     retval = _vsnwprintf_l(str, len, format, locale, valist);
 1444     __ms_va_end(valist);
 1445     return retval;
 1446 }
 1447 
 1448 /*********************************************************************
 1449  *      _snwprintf_s (MSVCRT.@)
 1450  */
 1451 int WINAPIV _snwprintf_s( wchar_t *str, size_t len, size_t count,
 1452     const wchar_t *format, ...)
 1453 {
 1454     int retval;
 1455     __ms_va_list valist;
 1456     __ms_va_start(valist, format);
 1457     retval = _vsnwprintf_s_l(str, len, count, format, NULL, valist);
 1458     __ms_va_end(valist);
 1459     return retval;
 1460 }
 1461 
 1462 /*********************************************************************
 1463  *              _snwprintf_s_l (MSVCRT.@)
 1464  */
 1465 int WINAPIV _snwprintf_s_l( wchar_t *str, size_t len, size_t count,
 1466         const wchar_t *format, _locale_t locale, ... )
 1467 {
 1468     int retval;
 1469     __ms_va_list valist;
 1470     __ms_va_start(valist, locale);
 1471     retval = _vsnwprintf_s_l(str, len, count, format, locale, valist);
 1472     __ms_va_end(valist);
 1473     return retval;
 1474 }
 1475 
 1476 #if _MSVCR_VER>=140
 1477 
 1478 static int puts_clbk_str_c99_w(void *ctx, int len, const wchar_t *str)
 1479 {
 1480     struct _str_ctx_w *out = ctx;
 1481 
 1482     if(!out->buf)
 1483         return len;
 1484 
 1485     if(out->len < len) {
 1486         memcpy(out->buf, str, out->len*sizeof(wchar_t));
 1487         out->buf += out->len;
 1488         out->len = 0;
 1489         return len;
 1490     }
 1491 
 1492     memcpy(out->buf, str, len*sizeof(wchar_t));
 1493     out->buf += len;
 1494     out->len -= len;
 1495     return len;
 1496 }
 1497 
 1498 /*********************************************************************
 1499  *              __stdio_common_vswprintf (UCRTBASE.@)
 1500  */
 1501 int CDECL __stdio_common_vswprintf( unsigned __int64 options,
 1502         wchar_t *str, size_t len, const wchar_t *format,
 1503         _locale_t locale, __ms_va_list valist )
 1504 {
 1505     struct _str_ctx_w ctx = {len, str};
 1506     int ret;
 1507 
 1508     if (options & ~UCRTBASE_PRINTF_MASK)
 1509         FIXME("options %s not handled\n", wine_dbgstr_longlong(options));
 1510     ret = pf_printf_w(puts_clbk_str_c99_w,
 1511             &ctx, format, locale, options & UCRTBASE_PRINTF_MASK, arg_clbk_valist, NULL, &valist);
 1512     puts_clbk_str_w(&ctx, 1, L"");
 1513 
 1514     if(!str)
 1515         return ret;
 1516     if(options & _CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION)
 1517         return ret>len ? -1 : ret;
 1518     if(ret>=len) {
 1519         if(len) str[len-1] = 0;
 1520         if(options & _CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR)
 1521             return ret;
 1522         return len > 0 ? -2 : -1;
 1523     }
 1524     return ret;
 1525 }
 1526 
 1527 #endif /* _MSVCR_VER>=140 */
 1528 
 1529 /*********************************************************************
 1530  *      sprintf (MSVCRT.@)
 1531  */
 1532 int WINAPIV sprintf( char *str, const char *format, ... )
 1533 {
 1534     __ms_va_list ap;
 1535     int r;
 1536 
 1537     __ms_va_start( ap, format );
 1538     r = vsnprintf( str, INT_MAX, format, ap );
 1539     __ms_va_end( ap );
 1540     return r;
 1541 }
 1542 
 1543 /*********************************************************************
 1544  *      sprintf_s (MSVCRT.@)
 1545  */
 1546 int WINAPIV sprintf_s( char *str, size_t num, const char *format, ... )
 1547 {
 1548     __ms_va_list ap;
 1549     int r;
 1550 
 1551     __ms_va_start( ap, format );
 1552     r = vsnprintf( str, num, format, ap );
 1553     __ms_va_end( ap );
 1554     return r;
 1555 }
 1556 
 1557 /*********************************************************************
 1558  *      _scwprintf (MSVCRT.@)
 1559  */
 1560 int WINAPIV _scwprintf( const wchar_t *format, ... )
 1561 {
 1562     __ms_va_list ap;
 1563     int r;
 1564 
 1565     __ms_va_start( ap, format );
 1566     r = _vsnwprintf( NULL, INT_MAX, format, ap );
 1567     __ms_va_end( ap );
 1568     return r;
 1569 }
 1570 
 1571 /*********************************************************************
 1572  *      swprintf (MSVCRT.@)
 1573  */
 1574 int WINAPIV _swprintf( wchar_t *str, const wchar_t *format, ... )
 1575 {
 1576     __ms_va_list ap;
 1577     int r;
 1578 
 1579     __ms_va_start( ap, format );
 1580     r = _vsnwprintf( str, INT_MAX, format, ap );
 1581     __ms_va_end( ap );
 1582     return r;
 1583 }
 1584 
 1585 /*********************************************************************
 1586  *      swprintf_s (MSVCRT.@)
 1587  */
 1588 int WINAPIV swprintf_s(wchar_t *str, size_t numberOfElements,
 1589         const wchar_t *format, ... )
 1590 {
 1591     __ms_va_list ap;
 1592     int r;
 1593 
 1594     __ms_va_start(ap, format);
 1595     r = _vsnwprintf_s(str, numberOfElements, INT_MAX, format, ap);
 1596     __ms_va_end(ap);
 1597 
 1598     return r;
 1599 }
 1600 
 1601 /*********************************************************************
 1602  *              _swprintf_s_l (MSVCRT.@)
 1603  */
 1604 int WINAPIV _swprintf_s_l(wchar_t *str, size_t numberOfElements,
 1605         const wchar_t *format, _locale_t locale, ... )
 1606 {
 1607     __ms_va_list ap;
 1608     int r;
 1609 
 1610     __ms_va_start(ap, locale);
 1611     r = _vsnwprintf_s_l(str, numberOfElements, INT_MAX, format, locale, ap);
 1612     __ms_va_end(ap);
 1613 
 1614     return r;
 1615 }
 1616 
 1617 /*********************************************************************
 1618  *              _swprintf_c_l (MSVCRT.@)
 1619  */
 1620 int WINAPIV _swprintf_c_l(wchar_t *str, size_t len,
 1621         const wchar_t *format, _locale_t locale, ... )
 1622 {
 1623     __ms_va_list ap;
 1624     int r;
 1625 
 1626     __ms_va_start(ap, locale);
 1627     r = _vswprintf_c_l(str, len, format, locale, ap);
 1628     __ms_va_end(ap);
 1629 
 1630     return r;
 1631 }
 1632 
 1633 /*********************************************************************
 1634  *              _swprintf_c (MSVCRT.@)
 1635  */
 1636 int WINAPIV _swprintf_c(wchar_t *str, size_t len,
 1637         const wchar_t *format, ... )
 1638 {
 1639     __ms_va_list ap;
 1640     int r;
 1641 
 1642     __ms_va_start(ap, format);
 1643     r = _vswprintf_c(str, len, format, ap);
 1644     __ms_va_end(ap);
 1645 
 1646     return r;
 1647 }
 1648 
 1649 /*********************************************************************
 1650  *      _vswprintf (MSVCRT.@)
 1651  */
 1652 int CDECL _vswprintf( wchar_t* str, const wchar_t* format, __ms_va_list args )
 1653 {
 1654     return _vsnwprintf( str, INT_MAX, format, args );
 1655 }
 1656 
 1657 /*********************************************************************
 1658  *      _vswprintf (MSVCRT.@)
 1659  */
 1660 int CDECL _vswprintf_l( wchar_t* str, const wchar_t* format,
 1661         _locale_t locale, __ms_va_list args )
 1662 {
 1663     return _vsnwprintf_l( str, INT_MAX, format, locale, args );
 1664 }
 1665 
 1666 /*********************************************************************
 1667  *      _vscwprintf (MSVCRT.@)
 1668  */
 1669 int CDECL _vscwprintf( const wchar_t *format, __ms_va_list args )
 1670 {
 1671     return _vsnwprintf( NULL, INT_MAX, format, args );
 1672 }
 1673 
 1674 /*********************************************************************
 1675  *      _vscwprintf_l (MSVCRT.@)
 1676  */
 1677 int CDECL _vscwprintf_l( const wchar_t *format, _locale_t locale, __ms_va_list args )
 1678 {
 1679     return _vsnwprintf_l( NULL, INT_MAX, format, locale, args );
 1680 }
 1681 
 1682 /*********************************************************************
 1683  *      _vscwprintf_p_l (MSVCRT.@)
 1684  */
 1685 int CDECL _vscwprintf_p_l( const wchar_t *format, _locale_t locale, __ms_va_list args )
 1686 {
 1687     return vswprintf_p_l_opt( NULL, INT_MAX, format, 0, locale, args );
 1688 }
 1689 
 1690 #if _MSVCR_VER>=80
 1691 /*********************************************************************
 1692  * _vscwprintf_p (MSVCR80.@)
 1693  */
 1694 int CDECL _vscwprintf_p(const wchar_t *format, __ms_va_list args)
 1695 {
 1696     return vswprintf_p_l_opt(NULL, INT_MAX, format, 0, NULL, args);
 1697 }
 1698 #endif
 1699 
 1700 /*********************************************************************
 1701  *      vswprintf_s (MSVCRT.@)
 1702  */
 1703 int CDECL vswprintf_s(wchar_t* str, size_t numberOfElements,
 1704         const wchar_t* format, __ms_va_list args)
 1705 {
 1706     return _vsnwprintf_s(str, numberOfElements, INT_MAX, format, args );
 1707 }
 1708 
 1709 /*********************************************************************
 1710  *              _vswprintf_s_l (MSVCRT.@)
 1711  */
 1712 int CDECL _vswprintf_s_l(wchar_t* str, size_t numberOfElements,
 1713         const wchar_t* format, _locale_t locale, __ms_va_list args)
 1714 {
 1715     return _vsnwprintf_s_l(str, numberOfElements, INT_MAX,
 1716             format, locale, args );
 1717 }
 1718 
 1719 static int vsprintf_p_l_opt(char *buffer, size_t length, const char *format,
 1720         DWORD options, _locale_t locale, __ms_va_list args)
 1721 {
 1722     static const char nullbyte = '\0';
 1723     printf_arg args_ctx[_ARGMAX+1];
 1724     struct _str_ctx_a puts_ctx = {length, buffer};
 1725     int ret;
 1726 
 1727     memset(args_ctx, 0, sizeof(args_ctx));
 1728 
 1729     ret = create_positional_ctx_a(args_ctx, format, args);
 1730     if(ret < 0) {
 1731         _invalid_parameter(NULL, NULL, NULL, 0, 0);
 1732         *_errno() = EINVAL;
 1733         return ret;
 1734     } else if(ret == 0)
 1735         ret = pf_printf_a(puts_clbk_str_a, &puts_ctx, format, locale,
 1736                 MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER | options, arg_clbk_valist, NULL, &args);
 1737     else
 1738         ret = pf_printf_a(puts_clbk_str_a, &puts_ctx, format, locale,
 1739                 MSVCRT_PRINTF_POSITIONAL_PARAMS | MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER | options,
 1740                 arg_clbk_positional, args_ctx, NULL);
 1741 
 1742     puts_clbk_str_a(&puts_ctx, 1, &nullbyte);
 1743     return ret;
 1744 }
 1745 
 1746 /*********************************************************************
 1747  *              _vsprintf_p_l (MSVCRT.@)
 1748  */
 1749 int CDECL _vsprintf_p_l(char *buffer, size_t length, const char *format,
 1750         _locale_t locale, __ms_va_list args)
 1751 {
 1752     return vsprintf_p_l_opt(buffer, length, format, 0, locale, args);
 1753 }
 1754 
 1755 /*********************************************************************
 1756  *      _vsprintf_p (MSVCRT.@)
 1757  */
 1758 int CDECL _vsprintf_p(char *buffer, size_t length,
 1759         const char *format, __ms_va_list args)
 1760 {
 1761     return _vsprintf_p_l(buffer, length, format, NULL, args);
 1762 }
 1763 
 1764 #if _MSVCR_VER>=140
 1765 /*********************************************************************
 1766  *              __stdio_common_vsprintf_p (UCRTBASE.@)
 1767  */
 1768 int CDECL __stdio_common_vsprintf_p(unsigned __int64 options, char *buffer, size_t length,
 1769         const char *format, _locale_t locale, __ms_va_list args)
 1770 {
 1771     if (options & ~UCRTBASE_PRINTF_MASK)
 1772         FIXME("options %s not handled\n", wine_dbgstr_longlong(options));
 1773     return vsprintf_p_l_opt(buffer, length, format, options & UCRTBASE_PRINTF_MASK, locale, args);
 1774 }
 1775 #endif
 1776 
 1777 /*********************************************************************
 1778  *      _sprintf_p_l (MSVCRT.@)
 1779  */
 1780 int WINAPIV _sprintf_p_l(char *buffer, size_t length,
 1781         const char *format, _locale_t locale, ...)
 1782 {
 1783     __ms_va_list valist;
 1784     int r;
 1785 
 1786     __ms_va_start(valist, locale);
 1787     r = _vsprintf_p_l(buffer, length, format, locale, valist);
 1788     __ms_va_end(valist);
 1789 
 1790     return r;
 1791 }
 1792 
 1793 /*********************************************************************
 1794  *      __swprintf_l (MSVCRT.@)
 1795  */
 1796 int WINAPIV __swprintf_l( wchar_t *str, const wchar_t *format,
 1797         _locale_t locale, ...)
 1798 {
 1799     int retval;
 1800     __ms_va_list valist;
 1801     __ms_va_start(valist, locale);
 1802     retval = _vswprintf_l(str, format, locale, valist);
 1803     __ms_va_end(valist);
 1804     return retval;
 1805 }
 1806 
 1807 #if _MSVCR_VER>=80
 1808 /*********************************************************************
 1809  * _sprintf_p (MSVCR80.@)
 1810  */
 1811 int WINAPIV _sprintf_p(char *buffer, size_t length, const char *format, ...)
 1812 {
 1813     __ms_va_list valist;
 1814     int r;
 1815 
 1816     __ms_va_start(valist, format);
 1817     r = _vsprintf_p_l(buffer, length, format, NULL, valist);
 1818     __ms_va_end(valist);
 1819 
 1820     return r;
 1821 }
 1822 #endif
 1823 
 1824 /*********************************************************************
 1825  *      _swprintf_p_l (MSVCRT.@)
 1826  */
 1827 int WINAPIV _swprintf_p_l(wchar_t *buffer, size_t length,
 1828         const wchar_t *format, _locale_t locale, ...)
 1829 {
 1830     __ms_va_list valist;
 1831     int r;
 1832 
 1833     __ms_va_start(valist, locale);
 1834     r = vswprintf_p_l_opt(buffer, length, format, 0, locale, valist);
 1835     __ms_va_end(valist);
 1836 
 1837     return r;
 1838 }
 1839 
 1840 /*********************************************************************
 1841  *              wcscmp (MSVCRT.@)
 1842  */
 1843 int CDECL wcscmp(const wchar_t *str1, const wchar_t *str2)
 1844 {
 1845     while (*str1 && (*str1 == *str2))
 1846     {
 1847         str1++;
 1848         str2++;
 1849     }
 1850 
 1851     if (*str1 < *str2)
 1852         return -1;
 1853     if (*str1 > *str2)
 1854         return 1;
 1855     return 0;
 1856 }
 1857 
 1858 /*********************************************************************
 1859  *              _wcscoll_l (MSVCRT.@)
 1860  */
 1861 int CDECL _wcscoll_l(const wchar_t* str1, const wchar_t* str2, _locale_t locale)
 1862 {
 1863     pthreadlocinfo locinfo;
 1864 
 1865     if(!locale)
 1866         locinfo = get_locinfo();
 1867     else
 1868         locinfo = locale->locinfo;
 1869 
 1870     if(!locinfo->lc_handle[LC_COLLATE])
 1871         return wcscmp(str1, str2);
 1872     return CompareStringW(locinfo->lc_handle[LC_COLLATE], 0, str1, -1, str2, -1)-CSTR_EQUAL;
 1873 }
 1874 
 1875 /*********************************************************************
 1876  *      wcscoll (MSVCRT.@)
 1877  */
 1878 int CDECL wcscoll( const wchar_t* str1, const wchar_t* str2 )
 1879 {
 1880     return _wcscoll_l(str1, str2, NULL);
 1881 }
 1882 
 1883 /*********************************************************************
 1884  *      wcspbrk (MSVCRT.@)
 1885  */
 1886 wchar_t* CDECL wcspbrk( const wchar_t* str, const wchar_t* accept )
 1887 {
 1888     const wchar_t* p;
 1889 
 1890     while (*str)
 1891     {
 1892         for (p = accept; *p; p++) if (*p == *str) return (wchar_t*)str;
 1893         str++;
 1894     }
 1895     return NULL;
 1896 }
 1897 
 1898 /*********************************************************************
 1899  *      wcstok_s  (MSVCRT.@)
 1900  */
 1901 wchar_t * CDECL wcstok_s( wchar_t *str, const wchar_t *delim,
 1902                                  wchar_t **next_token )
 1903 {
 1904     wchar_t *ret;
 1905 
 1906     if (!MSVCRT_CHECK_PMT(delim != NULL)) return NULL;
 1907     if (!MSVCRT_CHECK_PMT(next_token != NULL)) return NULL;
 1908     if (!MSVCRT_CHECK_PMT(str != NULL || *next_token != NULL)) return NULL;
 1909 
 1910     if (!str) str = *next_token;
 1911 
 1912     while (*str && wcschr( delim, *str )) str++;
 1913     if (!*str) return NULL;
 1914     ret = str++;
 1915     while (*str && !wcschr( delim, *str )) str++;
 1916     if (*str) *str++ = 0;
 1917     *next_token = str;
 1918     return ret;
 1919 }
 1920 
 1921 /*********************************************************************
 1922  *      wcstok  (MSVCRT.@)
 1923  */
 1924 #if _MSVCR_VER>=140
 1925 wchar_t * CDECL wcstok( wchar_t *str, const wchar_t *delim, wchar_t **ctx )
 1926 {
 1927     if (!ctx)
 1928         ctx = &msvcrt_get_thread_data()->wcstok_next;
 1929     return wcstok_s(str, delim, ctx);
 1930 }
 1931 #else
 1932 wchar_t * CDECL wcstok( wchar_t *str, const wchar_t *delim )
 1933 {
 1934     return wcstok_s(str, delim, &msvcrt_get_thread_data()->wcstok_next);
 1935 }
 1936 #endif
 1937 
 1938 /*********************************************************************
 1939  *      _wctomb_s_l (MSVCRT.@)
 1940  */
 1941 int CDECL _wctomb_s_l(int *len, char *mbchar, size_t size,
 1942         wchar_t wch, _locale_t locale)
 1943 {
 1944     pthreadlocinfo locinfo;
 1945     BOOL error = FALSE;
 1946     BOOL *perror;
 1947     int mblen;
 1948 
 1949     if(!mbchar && size>0) {
 1950         if(len)
 1951             *len = 0;
 1952         return 0;
 1953     }
 1954 
 1955     if(len)
 1956         *len = -1;
 1957 
 1958     if(!MSVCRT_CHECK_PMT(size <= INT_MAX))
 1959         return EINVAL;
 1960 
 1961     if(!locale)
 1962         locinfo = get_locinfo();
 1963     else
 1964         locinfo = locale->locinfo;
 1965 
 1966     if(!locinfo->lc_codepage) {
 1967         if(wch > 0xff) {
 1968             if(mbchar && size>0)
 1969                 memset(mbchar, 0, size);
 1970             *_errno() = EILSEQ;
 1971             return EILSEQ;
 1972         }
 1973 
 1974         if(!MSVCRT_CHECK_PMT_ERR(size >= 1, ERANGE))
 1975             return ERANGE;
 1976 
 1977         *mbchar = wch;
 1978         if(len)
 1979             *len = 1;
 1980         return 0;
 1981     }
 1982 
 1983     perror = (locinfo->lc_codepage != CP_UTF8 ? &error : NULL);
 1984     mblen = WideCharToMultiByte(locinfo->lc_codepage, 0, &wch, 1, mbchar, size, NULL, perror);
 1985     if(!mblen || error) {
 1986         if(!mblen && GetLastError()==ERROR_INSUFFICIENT_BUFFER) {
 1987             if(mbchar && size>0)
 1988                 memset(mbchar, 0, size);
 1989 
 1990             MSVCRT_INVALID_PMT("insufficient buffer size", ERANGE);
 1991             return ERANGE;
 1992         }
 1993 
 1994         *_errno() = EILSEQ;
 1995         return EILSEQ;
 1996     }
 1997 
 1998     if(len)
 1999         *len = mblen;
 2000     return 0;
 2001 }
 2002 
 2003 /*********************************************************************
 2004  *              wctomb_s (MSVCRT.@)
 2005  */
 2006 int CDECL wctomb_s(int *len, char *mbchar, size_t size, wchar_t wch)
 2007 {
 2008     return _wctomb_s_l(len, mbchar, size, wch, NULL);
 2009 }
 2010 
 2011 /*********************************************************************
 2012  *              _wctomb_l (MSVCRT.@)
 2013  */
 2014 int CDECL _wctomb_l(char *dst, wchar_t ch, _locale_t locale)
 2015 {
 2016     int len;
 2017 
 2018     _wctomb_s_l(&len, dst, dst ? MB_LEN_MAX : 0, ch, locale);
 2019     return len;
 2020 }
 2021 
 2022 /*********************************************************************
 2023  *      wctomb (MSVCRT.@)
 2024  */
 2025 INT CDECL wctomb( char *dst, wchar_t ch )
 2026 {
 2027     return _wctomb_l(dst, ch, NULL);
 2028 }
 2029 
 2030 /*********************************************************************
 2031  *      wctob (MSVCRT.@)
 2032  */
 2033 INT CDECL wctob( wint_t wchar )
 2034 {
 2035     char out;
 2036     BOOL error = FALSE;
 2037     BOOL *perror;
 2038     UINT codepage = get_locinfo()->lc_codepage;
 2039 
 2040     perror = (codepage != CP_UTF8 ? &error : NULL);
 2041 
 2042     if(!codepage) {
 2043         if (wchar < 0xff)
 2044             return (signed char)wchar;
 2045         else
 2046             return EOF;
 2047     } else if(WideCharToMultiByte( codepage, 0, &wchar, 1, &out, 1, NULL, perror ) && !error)
 2048         return (INT)out;
 2049     return EOF;
 2050 }
 2051 
 2052 /*********************************************************************
 2053  *              wcrtomb_s (MSVCRT.@)
 2054  */
 2055 INT CDECL wcrtomb_s(size_t *len, char *mbchar,
 2056         size_t size, wchar_t wch, mbstate_t *s)
 2057 {
 2058     int ilen, ret;
 2059 
 2060     if (s) *s = 0;
 2061     ret = wctomb_s(&ilen, mbchar, size, wch);
 2062     if (len) *len = ilen;
 2063     return ret;
 2064 }
 2065 
 2066 /*********************************************************************
 2067  *              wcrtomb (MSVCRT.@)
 2068  */
 2069 size_t CDECL wcrtomb( char *dst, wchar_t ch, mbstate_t *s)
 2070 {
 2071     if(s)
 2072         *s = 0;
 2073     return wctomb(dst, ch);
 2074 }
 2075 
 2076 /*********************************************************************
 2077  *      _iswctype_l (MSVCRT.@)
 2078  */
 2079 INT CDECL _iswctype_l( wchar_t wc, wctype_t type, _locale_t locale )
 2080 {
 2081     WORD ct;
 2082 
 2083     if (wc == WEOF) return 0;
 2084     if (wc < 256) return MSVCRT__pwctype[wc] & type;
 2085 
 2086     if (!GetStringTypeW(CT_CTYPE1, &wc, 1, &ct))
 2087     {
 2088         ERR("GetStringTypeW failed for %x\n", wc);
 2089         return 0;
 2090     }
 2091     return ct & type;
 2092 }
 2093 
 2094 /*********************************************************************
 2095  *      iswctype    (MSVCRT.@)
 2096  */
 2097 INT CDECL iswctype( wchar_t wc, wctype_t type )
 2098 {
 2099     return _iswctype_l( wc, type, NULL );
 2100 }
 2101 
 2102 /*********************************************************************
 2103  *      _iswalnum_l (MSVCRT.@)
 2104  */
 2105 int CDECL _iswalnum_l( wchar_t wc, _locale_t locale )
 2106 {
 2107     return _iswctype_l( wc, _ALPHA | _DIGIT, locale );
 2108 }
 2109 
 2110 /*********************************************************************
 2111  *      iswalnum (MSVCRT.@)
 2112  */
 2113 INT CDECL iswalnum( wchar_t wc )
 2114 {
 2115     return _iswalnum_l( wc, NULL );
 2116 }
 2117 
 2118 /*********************************************************************
 2119  *              iswalpha_l (MSVCRT.@)
 2120  */
 2121 INT CDECL _iswalpha_l( wchar_t wc, _locale_t locale )
 2122 {
 2123     return _iswctype_l( wc, _ALPHA, locale );
 2124 }
 2125 
 2126 /*********************************************************************
 2127  *      iswalpha (MSVCRT.@)
 2128  */
 2129 INT CDECL iswalpha( wchar_t wc )
 2130 {
 2131     return _iswalpha_l( wc, NULL );
 2132 }
 2133 
 2134 /*********************************************************************
 2135  *      _iswcntrl_l (MSVCRT.@)
 2136  */
 2137 int CDECL _iswcntrl_l( wchar_t wc, _locale_t locale )
 2138 {
 2139     return _iswctype_l( wc, _CONTROL, locale );
 2140 }
 2141 
 2142 /*********************************************************************
 2143  *      iswcntrl (MSVCRT.@)
 2144  */
 2145 INT CDECL iswcntrl( wchar_t wc )
 2146 {
 2147     return _iswcntrl_l( wc, NULL );
 2148 }
 2149 
 2150 /*********************************************************************
 2151  *      _iswdigit_l (MSVCRT.@)
 2152  */
 2153 INT CDECL _iswdigit_l( wchar_t wc, _locale_t locale )
 2154 {
 2155     return _iswctype_l( wc, _DIGIT, locale );
 2156 }
 2157 
 2158 /*********************************************************************
 2159  *      iswdigit (MSVCRT.@)
 2160  */
 2161 INT CDECL iswdigit( wchar_t wc )
 2162 {
 2163     return _iswdigit_l( wc, NULL );
 2164 }
 2165 
 2166 /*********************************************************************
 2167  *      _iswgraph_l (MSVCRT.@)
 2168  */
 2169 int CDECL _iswgraph_l( wchar_t wc, _locale_t locale )
 2170 {
 2171     return _iswctype_l( wc, _ALPHA | _DIGIT | _PUNCT, locale );
 2172 }
 2173 
 2174 /*********************************************************************
 2175  *      iswgraph (MSVCRT.@)
 2176  */
 2177 INT CDECL iswgraph( wchar_t wc )
 2178 {
 2179     return _iswgraph_l( wc, NULL );
 2180 }
 2181 
 2182 /*********************************************************************
 2183  *      _iswlower_l (MSVCRT.@)
 2184  */
 2185 int CDECL _iswlower_l( wchar_t wc, _locale_t locale )
 2186 {
 2187     return _iswctype_l( wc, _LOWER, locale );
 2188 }
 2189 
 2190 /*********************************************************************
 2191  *      iswlower (MSVCRT.@)
 2192  */
 2193 INT CDECL iswlower( wchar_t wc )
 2194 {
 2195     return _iswlower_l( wc, NULL );
 2196 }
 2197 
 2198 /*********************************************************************
 2199  *      _iswprint_l (MSVCRT.@)
 2200  */
 2201 int CDECL _iswprint_l( wchar_t wc, _locale_t locale )
 2202 {
 2203     return _iswctype_l( wc, _ALPHA | _BLANK | _DIGIT | _PUNCT, locale );
 2204 }
 2205 
 2206 /*********************************************************************
 2207  *      iswprint (MSVCRT.@)
 2208  */
 2209 INT CDECL iswprint( wchar_t wc )
 2210 {
 2211     return _iswprint_l( wc, NULL );
 2212 }
 2213 
 2214 /*********************************************************************
 2215  *      _iswpunct_l (MSVCRT.@)
 2216  */
 2217 INT CDECL _iswpunct_l( wchar_t wc, _locale_t locale )
 2218 {
 2219     return _iswctype_l( wc, _PUNCT, locale );
 2220 }
 2221 
 2222 /*********************************************************************
 2223  *      iswpunct (MSVCRT.@)
 2224  */
 2225 INT CDECL iswpunct( wchar_t wc )
 2226 {
 2227     return _iswpunct_l( wc, NULL );
 2228 }
 2229 
 2230 /*********************************************************************
 2231  *      _iswspace_l (MSVCRT.@)
 2232  */
 2233 INT CDECL _iswspace_l( wchar_t wc, _locale_t locale )
 2234 {
 2235     return _iswctype_l( wc, _SPACE, locale );
 2236 }
 2237 
 2238 /*********************************************************************
 2239  *      iswspace (MSVCRT.@)
 2240  */
 2241 INT CDECL iswspace( wchar_t wc )
 2242 {
 2243     return _iswspace_l( wc, NULL );
 2244 }
 2245 
 2246 /*********************************************************************
 2247  *      _iswupper_l (MSVCRT.@)
 2248  */
 2249 int CDECL _iswupper_l( wchar_t wc, _locale_t locale )
 2250 {
 2251     return _iswctype_l( wc, _UPPER, locale );
 2252 }
 2253 
 2254 /*********************************************************************
 2255  *      iswupper (MSVCRT.@)
 2256  */
 2257 INT CDECL iswupper( wchar_t wc )
 2258 {
 2259     return _iswupper_l( wc, NULL );
 2260 }
 2261 
 2262 /*********************************************************************
 2263  *      _iswxdigit_l (MSVCRT.@)
 2264  */
 2265 int CDECL _iswxdigit_l( wchar_t wc, _locale_t locale )
 2266 {
 2267     return _iswctype_l( wc, _HEX, locale );
 2268 }
 2269 
 2270 /*********************************************************************
 2271  *      iswxdigit (MSVCRT.@)
 2272  */
 2273 INT CDECL iswxdigit( wchar_t wc )
 2274 {
 2275     return _iswxdigit_l( wc, NULL );
 2276 }
 2277 
 2278 /*********************************************************************
 2279  *      _iswblank_l (MSVCRT.@)
 2280  */
 2281 INT CDECL _iswblank_l( wchar_t wc, _locale_t locale )
 2282 {
 2283     return wc == '\t' || _iswctype_l( wc, _BLANK, locale );
 2284 }
 2285 
 2286 /*********************************************************************
 2287  *      iswblank (MSVCRT.@)
 2288  */
 2289 INT CDECL iswblank( wchar_t wc )
 2290 {
 2291     return wc == '\t' || _iswctype_l( wc, _BLANK, NULL );
 2292 }
 2293 
 2294 /*********************************************************************
 2295  *      wcscpy_s (MSVCRT.@)
 2296  */
 2297 INT CDECL wcscpy_s( wchar_t* wcDest, size_t numElement, const  wchar_t *wcSrc)
 2298 {
 2299     size_t size = 0;
 2300 
 2301     if(!MSVCRT_CHECK_PMT(wcDest)) return EINVAL;
 2302     if(!MSVCRT_CHECK_PMT(numElement)) return EINVAL;
 2303 
 2304     if(!MSVCRT_CHECK_PMT(wcSrc))
 2305     {
 2306         wcDest[0] = 0;
 2307         return EINVAL;
 2308     }
 2309 
 2310     size = wcslen(wcSrc) + 1;
 2311 
 2312     if(!MSVCRT_CHECK_PMT_ERR(size <= numElement, ERANGE))
 2313     {
 2314         wcDest[0] = 0;
 2315         return ERANGE;
 2316     }
 2317 
 2318     memmove( wcDest, wcSrc, size*sizeof(WCHAR) );
 2319 
 2320     return 0;
 2321 }
 2322 
 2323 /***********************************************************************
 2324  *             wcscpy (MSVCRT.@)
 2325  */
 2326 wchar_t* __cdecl wcscpy( wchar_t *dst, const wchar_t *src )
 2327 {
 2328     WCHAR *p = dst;
 2329     while ((*p++ = *src++));
 2330     return dst;
 2331 }
 2332 
 2333 /******************************************************************
 2334  *      wcsncpy (MSVCRT.@)
 2335  */
 2336 wchar_t* __cdecl wcsncpy( wchar_t* s1, const wchar_t *s2, size_t n )
 2337 {
 2338     size_t i;
 2339 
 2340     for(i=0; i<n; i++)
 2341         if(!(s1[i] = s2[i])) break;
 2342     for(; i<n; i++)
 2343         s1[i] = 0;
 2344     return s1;
 2345 }
 2346 
 2347 /******************************************************************
 2348  *      wcsncpy_s (MSVCRT.@)
 2349  */
 2350 INT CDECL wcsncpy_s( wchar_t* wcDest, size_t numElement, const wchar_t *wcSrc,
 2351                             size_t count )
 2352 {
 2353     WCHAR *p = wcDest;
 2354     BOOL truncate = (count == _TRUNCATE);
 2355 
 2356     if(!wcDest && !numElement && !count)
 2357         return 0;
 2358 
 2359     if (!wcDest || !numElement)
 2360         return EINVAL;
 2361 
 2362     if (!wcSrc)
 2363     {
 2364         *wcDest = 0;
 2365         return count ? EINVAL : 0;
 2366     }
 2367 
 2368     while (numElement && count && *wcSrc)
 2369     {
 2370         *p++ = *wcSrc++;
 2371         numElement--;
 2372         count--;
 2373     }
 2374     if (!numElement && truncate)
 2375     {
 2376         *(p-1) = 0;
 2377         return STRUNCATE;
 2378     }
 2379     else if (!numElement)
 2380     {
 2381         *wcDest = 0;
 2382         return ERANGE;
 2383     }
 2384 
 2385     *p = 0;
 2386     return 0;
 2387 }
 2388 
 2389 /******************************************************************
 2390  *      wcscat_s (MSVCRT.@)
 2391  *
 2392  */
 2393 INT CDECL wcscat_s(wchar_t* dst, size_t elem, const wchar_t* src)
 2394 {
 2395     wchar_t* ptr = dst;
 2396 
 2397     if (!dst || elem == 0) return EINVAL;
 2398     if (!src)
 2399     {
 2400         dst[0] = '\0';
 2401         return EINVAL;
 2402     }
 2403 
 2404     /* seek to end of dst string (or elem if no end of string is found */
 2405     while (ptr < dst + elem && *ptr != '\0') ptr++;
 2406     while (ptr < dst + elem)
 2407     {
 2408         if ((*ptr++ = *src++) == '\0') return 0;
 2409     }
 2410     /* not enough space */
 2411     dst[0] = '\0';
 2412     return ERANGE;
 2413 }
 2414 
 2415 /***********************************************************************
 2416  *           wcscat (MSVCRT.@)
 2417  */
 2418 wchar_t* __cdecl wcscat( wchar_t *dst, const wchar_t *src )
 2419 {
 2420     wcscpy( dst + wcslen(dst), src );
 2421     return dst;
 2422 }
 2423 
 2424 /*********************************************************************
 2425  *  wcsncat_s (MSVCRT.@)
 2426  *
 2427  */
 2428 INT CDECL wcsncat_s(wchar_t *dst, size_t elem,
 2429         const wchar_t *src, size_t count)
 2430 {
 2431     size_t srclen;
 2432     wchar_t dststart;
 2433     INT ret = 0;
 2434 
 2435     if (!MSVCRT_CHECK_PMT(dst != NULL)) return EINVAL;
 2436     if (!MSVCRT_CHECK_PMT(elem > 0)) return EINVAL;
 2437     if (!MSVCRT_CHECK_PMT(src != NULL || count == 0)) return EINVAL;
 2438 
 2439     if (count == 0)
 2440         return 0;
 2441 
 2442     for (dststart = 0; dststart < elem; dststart++)
 2443     {
 2444         if (dst[dststart] == '\0')
 2445             break;
 2446     }
 2447     if (dststart == elem)
 2448     {
 2449         MSVCRT_INVALID_PMT("dst[elem] is not NULL terminated\n", EINVAL);
 2450         return EINVAL;
 2451     }
 2452 
 2453     if (count == _TRUNCATE)
 2454     {
 2455         srclen = wcslen(src);
 2456         if (srclen >= (elem - dststart))
 2457         {
 2458             srclen = elem - dststart - 1;
 2459             ret = STRUNCATE;
 2460         }
 2461     }
 2462     else
 2463         srclen = min(wcslen(src), count);
 2464     if (srclen < (elem - dststart))
 2465     {
 2466         memcpy(&dst[dststart], src, srclen*sizeof(wchar_t));
 2467         dst[dststart+srclen] = '\0';
 2468         return ret;
 2469     }
 2470     MSVCRT_INVALID_PMT("dst[elem] is too small", ERANGE);
 2471     dst[0] = '\0';
 2472     return ERANGE;
 2473 }
 2474 
 2475 /*********************************************************************
 2476  * wctoint (INTERNAL)
 2477  */
 2478 static int wctoint(WCHAR c, int base)
 2479 {
 2480     int v = -1;
 2481     if ('0' <= c && c <= '9')
 2482         v = c - '0';
 2483     else if ('A' <= c && c <= 'Z')
 2484         v = c - 'A' + 10;
 2485     else if ('a' <= c && c <= 'z')
 2486         v = c - 'a' + 10;
 2487     else {
 2488         /* NOTE: wine_fold_string(MAP_FOLDDIGITS) supports too many things. */
 2489         /* Unicode points that contain digits 0-9; keep this sorted! */
 2490         static const WCHAR zeros[] = {
 2491             0x660, 0x6f0, 0x966, 0x9e6, 0xa66, 0xae6, 0xb66, 0xc66, 0xce6,
 2492             0xd66, 0xe50, 0xed0, 0xf20, 0x1040, 0x17e0, 0x1810, 0xff10
 2493         };
 2494         int i;
 2495         for (i = 0; i < ARRAY_SIZE(zeros) && c >= zeros[i]; ++i) {
 2496             if (zeros[i] <= c && c <= zeros[i] + 9) {
 2497                 v = c - zeros[i];
 2498                 break;
 2499             }
 2500         }
 2501     }
 2502     return v < base ? v : -1;
 2503 }
 2504 
 2505 /*********************************************************************
 2506  *  _wcstoi64_l (MSVCRT.@)
 2507  */
 2508 __int64 CDECL _wcstoi64_l(const wchar_t *nptr,
 2509         wchar_t **endptr, int base, _locale_t locale)
 2510 {
 2511     BOOL negative = FALSE, empty = TRUE;
 2512     __int64 ret = 0;
 2513 
 2514     TRACE("(%s %p %d %p)\n", debugstr_w(nptr), endptr, base, locale);
 2515 
 2516     if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
 2517     if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
 2518     if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
 2519 
 2520     if(endptr)
 2521         *endptr = (wchar_t*)nptr;
 2522 
 2523     while(_iswspace_l(*nptr, locale)) nptr++;
 2524 
 2525     if(*nptr == '-') {
 2526         negative = TRUE;
 2527         nptr++;
 2528     } else if(*nptr == '+')
 2529         nptr++;
 2530 
 2531     if((base==0 || base==16) && wctoint(*nptr, 1)==0 && (nptr[1]=='x' || nptr[1]=='X')) {
 2532         base = 16;
 2533         nptr += 2;
 2534     }
 2535 
 2536     if(base == 0) {
 2537         if(wctoint(*nptr, 1)==0)
 2538             base = 8;
 2539         else
 2540             base = 10;
 2541     }
 2542 
 2543     while(*nptr) {
 2544         int v = wctoint(*nptr, base);
 2545         if(v<0)
 2546             break;
 2547 
 2548         if(negative)
 2549             v = -v;
 2550 
 2551         nptr++;
 2552         empty = FALSE;
 2553 
 2554         if(!negative && (ret>I64_MAX/base || ret*base>I64_MAX-v)) {
 2555             ret = I64_MAX;
 2556             *_errno() = ERANGE;
 2557         } else if(negative && (ret<I64_MIN/base || ret*base<I64_MIN-v)) {
 2558             ret = I64_MIN;
 2559             *_errno() = ERANGE;
 2560         } else
 2561             ret = ret*base + v;
 2562     }
 2563 
 2564     if(endptr && !empty)
 2565         *endptr = (wchar_t*)nptr;
 2566 
 2567     return ret;
 2568 }
 2569 
 2570 /*********************************************************************
 2571  *  _wcstoi64 (MSVCRT.@)
 2572  */
 2573 __int64 CDECL _wcstoi64(const wchar_t *nptr,
 2574         wchar_t **endptr, int base)
 2575 {
 2576     return _wcstoi64_l(nptr, endptr, base, NULL);
 2577 }
 2578 
 2579 /*********************************************************************
 2580  *  _wcstol_l (MSVCRT.@)
 2581  */
 2582 __msvcrt_long CDECL _wcstol_l(const wchar_t *s,
 2583         wchar_t **end, int base, _locale_t locale)
 2584 {
 2585     __int64 ret = _wcstoi64_l(s, end, base, locale);
 2586 
 2587     if(ret > LONG_MAX) {
 2588         ret = LONG_MAX;
 2589         *_errno() = ERANGE;
 2590     }else if(ret < LONG_MIN) {
 2591         ret = LONG_MIN;
 2592         *_errno() = ERANGE;
 2593     }
 2594     return ret;
 2595 }
 2596 
 2597 /*********************************************************************
 2598  *  wcstol (MSVCRT.@)
 2599  */
 2600 __msvcrt_long CDECL wcstol(const wchar_t *s,
 2601         wchar_t **end, int base)
 2602 {
 2603     return _wcstol_l(s, end, base, NULL);
 2604 }
 2605 
 2606 /*********************************************************************
 2607  *  _wtoi_l (MSVCRT.@)
 2608  */
 2609 int __cdecl _wtoi_l(const wchar_t *str, _locale_t locale)
 2610 {
 2611     __int64 ret = _wcstoi64_l(str, NULL, 10, locale);
 2612 
 2613     if(ret > INT_MAX) {
 2614         ret = INT_MAX;
 2615         *_errno() = ERANGE;
 2616     } else if(ret < INT_MIN) {
 2617         ret = INT_MIN;
 2618         *_errno() = ERANGE;
 2619     }
 2620     return ret;
 2621 }
 2622 
 2623 /*********************************************************************
 2624  *  _wtoi (MSVCRT.@)
 2625  */
 2626 int __cdecl _wtoi(const wchar_t *str)
 2627 {
 2628     return _wtoi_l(str, NULL);
 2629 }
 2630 
 2631 /*********************************************************************
 2632  *  _wtol_l (MSVCRT.@)
 2633  */
 2634 __msvcrt_long __cdecl _wtol_l(const wchar_t *str, _locale_t locale)
 2635 {
 2636     __int64 ret = _wcstoi64_l(str, NULL, 10, locale);
 2637 
 2638     if(ret > LONG_MAX) {
 2639         ret = LONG_MAX;
 2640         *_errno() = ERANGE;
 2641     } else if(ret < LONG_MIN) {
 2642         ret = LONG_MIN;
 2643         *_errno() = ERANGE;
 2644     }
 2645     return ret;
 2646 }
 2647 
 2648 /*********************************************************************
 2649  *  _wtol (MSVCRT.@)
 2650  */
 2651 __msvcrt_long __cdecl _wtol(const wchar_t *str)
 2652 {
 2653     return _wtol_l(str, NULL);
 2654 }
 2655 
 2656 #if _MSVCR_VER>=120
 2657 
 2658 /*********************************************************************
 2659  *  _wtoll_l (MSVCR120.@)
 2660  */
 2661 __int64 __cdecl _wtoll_l(const wchar_t *str, _locale_t locale)
 2662 {
 2663     return _wcstoi64_l(str, NULL, 10, locale);
 2664 }
 2665 
 2666 /*********************************************************************
 2667  *  _wtoll (MSVCR120.@)
 2668  */
 2669 __int64 __cdecl _wtoll(const wchar_t *str)
 2670 {
 2671     return _wtoll_l(str, NULL);
 2672 }
 2673 
 2674 #endif /* _MSVCR_VER>=120 */
 2675 
 2676 /*********************************************************************
 2677  *  _wcstoui64_l (MSVCRT.@)
 2678  */
 2679 unsigned __int64 CDECL _wcstoui64_l(const wchar_t *nptr,
 2680         wchar_t **endptr, int base, _locale_t locale)
 2681 {
 2682     BOOL negative = FALSE, empty = TRUE;
 2683     unsigned __int64 ret = 0;
 2684 
 2685     TRACE("(%s %p %d %p)\n", debugstr_w(nptr), endptr, base, locale);
 2686 
 2687     if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
 2688     if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
 2689     if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
 2690 
 2691     if(endptr)
 2692         *endptr = (wchar_t*)nptr;
 2693 
 2694     while(_iswspace_l(*nptr, locale)) nptr++;
 2695 
 2696     if(*nptr == '-') {
 2697         negative = TRUE;
 2698         nptr++;
 2699     } else if(*nptr == '+')
 2700         nptr++;
 2701 
 2702     if((base==0 || base==16) && wctoint(*nptr, 1)==0 && (nptr[1]=='x' || nptr[1]=='X')) {
 2703         base = 16;
 2704         nptr += 2;
 2705     }
 2706 
 2707     if(base == 0) {
 2708         if(wctoint(*nptr, 1)==0)
 2709             base = 8;
 2710         else
 2711             base = 10;
 2712     }
 2713 
 2714     while(*nptr) {
 2715         int v = wctoint(*nptr, base);
 2716         if(v<0)
 2717             break;
 2718 
 2719         nptr++;
 2720         empty = FALSE;
 2721 
 2722         if(ret>UI64_MAX/base || ret*base>UI64_MAX-v) {
 2723             ret = UI64_MAX;
 2724             *_errno() = ERANGE;
 2725         } else
 2726             ret = ret*base + v;
 2727     }
 2728 
 2729     if(endptr && !empty)
 2730         *endptr = (wchar_t*)nptr;
 2731 
 2732     return negative ? -ret : ret;
 2733 }
 2734 
 2735 /*********************************************************************
 2736  *  _wcstoui64 (MSVCRT.@)
 2737  */
 2738 unsigned __int64 CDECL _wcstoui64(const wchar_t *nptr,
 2739         wchar_t **endptr, int base)
 2740 {
 2741     return _wcstoui64_l(nptr, endptr, base, NULL);
 2742 }
 2743 
 2744 /*********************************************************************
 2745  *  _wcstoul_l (MSVCRT.@)
 2746  */
 2747 __msvcrt_ulong __cdecl _wcstoul_l(const wchar_t *s,
 2748         wchar_t **end, int base, _locale_t locale)
 2749 {
 2750     __int64 ret = _wcstoi64_l(s, end, base, locale);
 2751 
 2752     if(ret > ULONG_MAX) {
 2753         ret = ULONG_MAX;
 2754         *_errno() = ERANGE;
 2755     }else if(ret < -(__int64)ULONG_MAX) {
 2756         ret = 1;
 2757         *_errno() = ERANGE;
 2758     }
 2759     return ret;
 2760 }
 2761 
 2762 /*********************************************************************
 2763    *  wcstoul (MSVCRT.@)
 2764     */
 2765 __msvcrt_ulong __cdecl wcstoul(const wchar_t *s, wchar_t **end, int base)
 2766 {
 2767     return _wcstoul_l(s, end, base, NULL);
 2768 }
 2769 
 2770 /******************************************************************
 2771  *  wcsnlen (MSVCRT.@)
 2772  */
 2773 size_t CDECL wcsnlen(const wchar_t *s, size_t maxlen)
 2774 {
 2775     size_t i;
 2776 
 2777     for (i = 0; i < maxlen; i++)
 2778         if (!s[i]) break;
 2779     return i;
 2780 }
 2781 
 2782 /*********************************************************************
 2783  *              _towupper_l (MSVCRT.@)
 2784  */
 2785 wint_t CDECL _towupper_l(wint_t c, _locale_t locale)
 2786 {
 2787     pthreadlocinfo locinfo;
 2788     wchar_t ret;
 2789 
 2790     if(!locale)
 2791         locinfo = get_locinfo();
 2792     else
 2793         locinfo = locale->locinfo;
 2794 
 2795     if(!locinfo->lc_handle[LC_CTYPE]) {
 2796         if(c >= 'a' && c <= 'z')
 2797             return c + 'A' - 'a';
 2798         return c;
 2799     }
 2800 
 2801     if(!LCMapStringW(locinfo->lc_handle[LC_CTYPE], LCMAP_UPPERCASE, &c, 1, &ret, 1))
 2802         return c;
 2803     return ret;
 2804 }
 2805 
 2806 /*********************************************************************
 2807  *              towupper (MSVCRT.@)
 2808  */
 2809 wint_t CDECL towupper(wint_t c)
 2810 {
 2811     return _towupper_l(c, NULL);
 2812 }
 2813 
 2814 /*********************************************************************
 2815  *              wcschr (MSVCRT.@)
 2816  */
 2817 wchar_t* CDECL wcschr(const wchar_t *str, wchar_t ch)
 2818 {
 2819     do { if (*str == ch) return (WCHAR *)(ULONG_PTR)str; } while (*str++);
 2820     return NULL;
 2821 }
 2822 
 2823 /*********************************************************************
 2824  *              wcsrchr (MSVCRT.@)
 2825  */
 2826 wchar_t* CDECL wcsrchr(const wchar_t *str, wchar_t ch)
 2827 {
 2828     WCHAR *ret = NULL;
 2829     do { if (*str == ch) ret = (WCHAR *)(ULONG_PTR)str; } while (*str++);
 2830     return ret;
 2831 }
 2832 
 2833 /***********************************************************************
 2834  *              wcslen (MSVCRT.@)
 2835  */
 2836 size_t CDECL wcslen(const wchar_t *str)
 2837 {
 2838     const wchar_t *s = str;
 2839     while (*s) s++;
 2840     return s - str;
 2841 }
 2842 
 2843 /*********************************************************************
 2844  *              wcsstr (MSVCRT.@)
 2845  */
 2846 wchar_t* CDECL wcsstr(const wchar_t *str, const wchar_t *sub)
 2847 {
 2848     while(*str)
 2849     {
 2850         const wchar_t *p1 = str, *p2 = sub;
 2851         while(*p1 && *p2 && *p1 == *p2)
 2852         {
 2853             p1++;
 2854             p2++;
 2855         }
 2856         if(!*p2)
 2857             return (wchar_t*)str;
 2858         str++;
 2859     }
 2860     return NULL;
 2861 }
 2862 
 2863 /*********************************************************************
 2864  *              _wtoi64_l (MSVCRT.@)
 2865  */
 2866 __int64 CDECL _wtoi64_l(const wchar_t *str, _locale_t locale)
 2867 {
 2868     ULONGLONG RunningTotal = 0;
 2869     BOOL bMinus = FALSE;
 2870 
 2871     while (_iswspace_l(*str, locale)) {
 2872         str++;
 2873     } /* while */
 2874 
 2875     if (*str == '+') {
 2876         str++;
 2877     } else if (*str == '-') {
 2878         bMinus = TRUE;
 2879         str++;
 2880     } /* if */
 2881 
 2882     while (*str >= '0' && *str <= '9') {
 2883         RunningTotal = RunningTotal * 10 + *str - '0';
 2884         str++;
 2885     } /* while */
 2886 
 2887     return bMinus ? -RunningTotal : RunningTotal;
 2888 }
 2889 
 2890 /*********************************************************************
 2891  *              _wtoi64 (MSVCRT.@)
 2892  */
 2893 __int64 CDECL _wtoi64(const wchar_t *str)
 2894 {
 2895     return _wtoi64_l(str, NULL);
 2896 }
 2897 
 2898 /*********************************************************************
 2899  *              _wcsxfrm_l (MSVCRT.@)
 2900  */
 2901 size_t CDECL _wcsxfrm_l(wchar_t *dest, const wchar_t *src,
 2902         size_t len, _locale_t locale)
 2903 {
 2904     pthreadlocinfo locinfo;
 2905     int i, ret;
 2906 
 2907     if(!MSVCRT_CHECK_PMT(src)) return INT_MAX;
 2908     if(!MSVCRT_CHECK_PMT(dest || !len)) return INT_MAX;
 2909 
 2910     if(len > INT_MAX) {
 2911         FIXME("len > INT_MAX not supported\n");
 2912         len = INT_MAX;
 2913     }
 2914 
 2915     if(!locale)
 2916         locinfo = get_locinfo();
 2917     else
 2918         locinfo = locale->locinfo;
 2919 
 2920     if(!locinfo->lc_handle[LC_COLLATE]) {
 2921         wcsncpy(dest, src, len);
 2922         return wcslen(src);
 2923     }
 2924 
 2925     ret = LCMapStringW(locinfo->lc_handle[LC_COLLATE],
 2926             LCMAP_SORTKEY, src, -1, NULL, 0);
 2927     if(!ret) {
 2928         if(len) dest[0] = 0;
 2929         *_errno() = EILSEQ;
 2930         return INT_MAX;
 2931     }
 2932     if(!len) return ret-1;
 2933 
 2934     if(ret > len) {
 2935         dest[0] = 0;
 2936         *_errno() = ERANGE;
 2937         return ret-1;
 2938     }
 2939 
 2940     ret = LCMapStringW(locinfo->lc_handle[LC_COLLATE],
 2941             LCMAP_SORTKEY, src, -1, dest, len) - 1;
 2942     for(i=ret; i>=0; i--)
 2943         dest[i] = ((unsigned char*)dest)[i];
 2944     return ret;
 2945 }
 2946 
 2947 /*********************************************************************
 2948  *              wcsxfrm (MSVCRT.@)
 2949  */
 2950 size_t CDECL wcsxfrm(wchar_t *dest, const wchar_t *src, size_t len)
 2951 {
 2952     return _wcsxfrm_l(dest, src, len, NULL);
 2953 }