"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.

    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 }