ReactOS 0.4.16-dev-732-g2d1144a
wsetlocale.cpp
Go to the documentation of this file.
1/***
2*wsetlocale.cpp - Contains the wsetlocale function
3*
4* Copyright (c) Microsoft Corporation. All rights reserved.
5*
6*Purpose:
7* Contains the wsetlocale() function.
8*
9****/
10
11#include <corecrt_internal.h>
12#include <locale.h>
13
14extern "C" {
15
16static const char _first_127char[] = {
17 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
19 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
20 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
21 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
22 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100,101,102,
23 103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,
24 120,121,122,123,124,125,126,127
25};
26
28extern const unsigned short _wctype[];
29static const unsigned short *_ctype_loc_style = _wctype + 2;
30
32
33/* helper function prototypes */
34_Success_(return != 0)
35static wchar_t * _expandlocale(
36 _In_z_ wchar_t const * expr,
37 _Out_writes_z_(sizeInChars) wchar_t * output,
39 _Out_writes_z_(localeNameSizeInChars) wchar_t * localeNameOutput,
42 );
43
44void _wcscats(_Inout_updates_z_(_Param_(2)) wchar_t *, size_t, int, ...);
45void __lc_lctowcs(_Inout_updates_z_(_Param_(2)) wchar_t *, size_t, const __crt_locale_strings *);
47static wchar_t * __cdecl _wsetlocale_set_cat(__crt_locale_data*, int, const wchar_t *);
50static wchar_t * __cdecl _wsetlocale_nolock(__crt_locale_data*, int, const wchar_t *);
53
55{
57}
58
59/***
60* _configthreadlocale(int i)
61*
62* Purpose:
63* To set _own_locale flag on threadinfo sturct. If this flag is set, this thread
64* is going own it's threadlocinfo struct. Setlocale call on other thread will have
65* no effect on this thread's locale. If 0 is passed then nothing is changed, but
66* current status is returned.
67* Exit :
68* Returns the current status - i.e. per thread locale is enabled or not.
69*
70*******************************************************************************/
72{
73 /*
74 * ownlocale flag struct:
75 * bits: 000000000000000000000000 000W 00P1
76 * P is set when _ENABLE_PER_THREAD_LOCALE is called for this thread
77 * or _ENABLE_PER_THREAD_LOCALE_NEW was set when this thread was created.
78 * W is set when _WSETLOCALE_AVOID_SYNC_LOCALE_BIT is set by _wsetlocale.
79 * It is used to disable global-ptd resynchronization during a call to _wsetlocale.
80 *
81 * __globallocalestatus structure:
82 * bits: 111111111111111111111111 1111 1N1G
83 * G is set if _ENABLE_PER_THREAD_LOCALE_GLOBAL is set.
84 * G is 0 if _ENABLE_PER_THREAD_LOCALE_GLOBAL is not set.
85 * N is set if _ENABLE_PER_THREAD_LOCALE_NEW is set.
86 * N is 0 if _ENABLE_PER_THREAD_LOCALE_NEW is not set.
87 */
88 __acrt_ptd* const ptd = __acrt_getptd();
90
91 switch(i)
92 {
94 // same behavior as __acrt_disable_global_locale_sync()
95 ptd->_own_locale = ptd->_own_locale | _PER_THREAD_LOCALE_BIT;
96 break;
97
99 // same behavior as __acrt_enable_global_locale_sync()
100 ptd->_own_locale = ptd->_own_locale & ~_PER_THREAD_LOCALE_BIT;
101 break;
102
103 case 0:
104 break;
105
106 /* used only during dll startup for linkopt */
107 case -1:
109 break;
110
111 default:
112 _VALIDATE_RETURN(("Invalid parameter for _configthreadlocale",0),EINVAL,-1);
113 break;
114 }
115
116 return retval;
117}
118
120{
121 __acrt_lock_and_call(__acrt_locale_lock, [&]
122 {
124 {
126 {
127 return;
128 }
129
131 });
132 });
133}
134
135/***
136*_free_locale() - free threadlocinfo
137*
138*Purpose:
139* Free up the per-thread locale info structure specified by the passed
140* pointer.
141*
142*Entry:
143* __crt_locale_data* ptloci
144*
145*Exit:
146*
147*Exceptions:
148*
149*******************************************************************************/
150
153 )
154{
155 if (plocinfo != nullptr)
156 {
158 __try
159 {
160 if (plocinfo->mbcinfo != nullptr &&
163 {
165 }
166 }
168 {
170 }
172
173 if (plocinfo->locinfo != nullptr)
174 {
175 /*
176 * this portion has to be in locale lock as there may be case when
177 * not this thread but some other thread is still holding to this
178 * locale and is also trying to free this locale. In this case
179 * we may end up leaking memory.
180 */
181
183 __try
184 {
186 if ( (plocinfo->locinfo != nullptr) &&
187 (plocinfo->locinfo->refcount == 0) &&
190 }
192 {
194 }
196 }
197
199 }
200}
201
202/*
203* _locale_t _get_current_locale() -
204* Gets the current locale setting.
205*
206* Purpose:
207* Gets the current locale setting for this thread. Returns locale
208* in form of _locale_t, which then can be used with other locale
209* aware string functions.
210*
211*/
212
214{
215 __acrt_ptd* const ptd = __acrt_getptd();
216
217 auto locale_copy(_calloc_crt_t(__crt_locale_pointers, 1));
218 if (!locale_copy)
219 return nullptr; // calloc will set errno
220
223
224 // No one can free the data pointed to by ptlocinfo while we're copying
225 // it, since we're copying this thread's ptlocinfo, which won't be updated
226 // during the copy. So there are no worries about it being freed from
227 // under us. We still need a lock while adding a reference for the new
228 // copy, though, because of the race condition found in _wsetlocale.
229 locale_copy.get()->locinfo = ptd->_locale_info;
230 locale_copy.get()->mbcinfo = ptd->_multibyte_info;
231 __acrt_lock_and_call(__acrt_locale_lock, [&]
232 {
233 __acrt_add_locale_ref(locale_copy.get()->locinfo);
234 });
235
236 __acrt_lock_and_call(__acrt_multibyte_cp_lock, [&]
237 {
238 InterlockedIncrement(&locale_copy.get()->mbcinfo->refcount);
239 });
240
241 return locale_copy.detach();
242}
243
244// Enclaves do not support dynamic locales, but they support reading the default one.
245#ifndef _UCRT_ENCLAVE_BUILD
246
247// This is used as the initializer if a category does not need initialization.
249{
250 return 0;
251}
252
254
255_CRT_LINKER_FORCE_INCLUDE(__acrt_locale_terminator);
256
257extern __declspec(selectany) struct {
258 const wchar_t * catname;
259 wchar_t * locale;
262 /* code assumes locale initialization is "__wclocalestr" */
263 { L"LC_ALL", nullptr, no_op_initialize },
269};
270
271/***
272*
273* _copytlocinfo_nolock(__crt_locale_data* ptlocid, __crt_locale_data* ptlocis)
274*
275* Purpose:
276* Copy the contents of ptlocis to ptlocid and increase the refcount of all the
277* elements in ptlocid after copy.
278*
279******************************************************************************/
281 __crt_locale_data* ptlocid,
282 __crt_locale_data* ptlocis)
283{
284 if (ptlocis != nullptr && ptlocid != nullptr && ptlocid != ptlocis) {
285 *ptlocid = *ptlocis;
286 ptlocid->refcount = 0;
287 __acrt_add_locale_ref(ptlocid);
288 }
289}
290
291/***
292* void sync_legacy_variables_lk()
293*
294* Purpose:
295* Syncs all the legacy locale specific variables to the global locale.
296*
297*******************************************************************************/
299{
301 _pctype = __acrt_current_locale_data.value()->_public._locale_pctype;
302 __mb_cur_max = __acrt_current_locale_data.value()->_public._locale_mb_cur_max;
303}
304
305/***
306* _locale_t _wcreate_locale(int category, char *wlocale) -
307* Set one or all locale categories of global locale structure
308*
309* Purpose:
310* The _wcreate_locale() routine allows the user to create a _locale_t
311* object that can be used with other locale functions.
312*
313* Entry:
314* int category = One of the locale categories defined in locale.h
315* char *locale = String identifying a specific locale.
316*
317* Exit:
318* If supplied locale pointer != nullptr:
319*
320* If locale string is '\0', set locale to default.
321*
322* If desired setting can be honored, return a pointer to the
323* locale string for the appropriate category.
324*
325* If desired setting can NOT be honored, return nullptr.
326*
327* Exceptions:
328* Compound locale strings of the form "LC_COLLATE=xxx;LC_CTYPE=xxx;..."
329* are allowed for the LC_ALL category. This is to support the ability
330* to restore locales with the returned string, as specified by ANSI.
331* Setting the locale with a compound locale string will succeed unless
332* *all* categories failed. The returned string will reflect the current
333* locale. For example, if LC_CTYPE fails in the above string, setlocale
334* will return "LC_COLLATE=xxx;LC_CTYPE=yyy;..." where yyy is the
335* previous locale (or the C locale if restoring the previous locale
336* also failed). Unrecognized LC_* categories are ignored.
337*
338*******************************************************************************/
339
341 int _category,
342 const wchar_t *locale
343 )
344{
345 if (_category < LC_MIN || _category > LC_MAX || locale == nullptr)
346 return nullptr;
347
348 auto result = _calloc_crt_t(__crt_locale_pointers, 1);
350
351 auto locale_data = _calloc_crt_t(__crt_locale_data, 1);
352 _VALIDATE_RETURN_NOEXC(locale_data, ENOMEM, nullptr);
353
354 auto multibyte_data = _calloc_crt_t(__crt_multibyte_data, 1);
355 _VALIDATE_RETURN_NOEXC(multibyte_data, ENOMEM, nullptr);
356
358
359 if (_wsetlocale_nolock(locale_data.get(), _category, locale) == nullptr ||
360 _setmbcp_nolock(locale_data.get()->_public._locale_lc_codepage, multibyte_data.get()) != 0)
361 {
362 __acrt_release_locale_ref(locale_data.get());
363 __acrt_free_locale(locale_data.detach());
364 return nullptr;
365 }
366
367 multibyte_data.get()->refcount = 1;
368
369 result.get()->locinfo = locale_data.detach();
370 result.get()->mbcinfo = multibyte_data.detach();
371 return result.detach();
372}
373
374/***
375* _locale_t _create_locale(int category, char *locale) -
376* Set one or all locale categories of global locale structure
377****/
379 int _category,
380 const char *_locale
381 )
382{
383 wchar_t _wlocale[MAX_LC_LEN];
384
385 /* Early input validation */
386 if ( (_category < LC_MIN) || (_category > LC_MAX) || _locale == nullptr)
387 return nullptr;
388
389 if ( __acrt_MultiByteToWideChar(CP_ACP, 0, _locale, -1, _wlocale, _countof(_wlocale)) == 0 )
390 { // conversion to wide char failed
391 return nullptr;
392 }
393
394 return _wcreate_locale(_category, _wlocale);
395}
396
397/*
398*char * setlocale(int category, char *locale) - Set one or all locale categories
399*
400*Purpose:
401* The setlocale() routine allows the user to set one or more of
402* the locale categories to the specific locale selected by the
403* user. [ANSI]
404*
405* NOTE: Under !_INTL, the C libraries only support the "C" locale.
406* Attempts to change the locale will fail.
407*
408*Entry:
409* int category = One of the locale categories defined in locale.h
410* char *locale = String identifying a specific locale or nullptr to
411* query the current locale.
412*
413*Exit:
414* If supplied locale pointer == nullptr:
415*
416* Return pointer to current locale string and do NOT change
417* the current locale.
418*
419* If supplied locale pointer != nullptr:
420*
421* If locale string is '\0', set locale to default.
422*
423* If desired setting can be honored, return a pointer to the
424* locale string for the appropriate category.
425*
426* If desired setting can NOT be honored, return nullptr.
427*
428*Exceptions:
429* Compound locale strings of the form "LC_COLLATE=xxx;LC_CTYPE=xxx;..."
430* are allowed for the LC_ALL category. This is to support the ability
431* to restore locales with the returned string, as specified by ANSI.
432* Setting the locale with a compound locale string will succeed unless
433* *all* categories failed. The returned string will reflect the current
434* locale. For example, if LC_CTYPE fails in the above string, setlocale
435* will return "LC_COLLATE=xxx;LC_CTYPE=yyy;..." where yyy is the
436* previous locale (or the C locale if restoring the previous locale
437* also failed). Unrecognized LC_* categories are ignored.
438*
439*/
440
442 int _category,
443 const wchar_t *_wlocale
444 )
445{
446 wchar_t * retval=nullptr;
447 __crt_locale_data* ptloci = nullptr;
448
449 /* Validate category */
450 _VALIDATE_RETURN(LC_MIN <= _category && _category <= LC_MAX, EINVAL, nullptr);
451
452 __acrt_ptd* const ptd = __acrt_getptd();
453
454 // Deadlock Avoidance: When a new thread is created in the process, we
455 // create a new PTD for the thread. The PTD initialization function is
456 // called under the loader lock. This initialization function will also
457 // acquire the locale lock in order to acquire a reference to the current
458 // global locale for the new thread.
459 //
460 // Some of the locale APIs are not available on all supported target OSes.
461 // We dynamically obtain these libraries via LoadLibrary/GetProcAddress.
462 // We must ensure that no call to LoadLibrary is made while we hold the
463 // locale lock, lest we deadlock due to lock order inversion between the
464 // loader lock and the locale lock.
465 //
466 // This function call here will ensure that any required modules are loaded
467 // before we acquire the locale lock.
469
471
472 // Prevent global locale resynchronization - we call things like stricmp() further down
473 // without passing our _locale_t which would trigger a resynchronization.
474 // Use _WSETLOCALE_AVOID_SYNC_LOCALE_BIT to avoid interfering with other locale settings
475 // (see _configthreadlocale() for details).
476
477 // This may not be necessary anymore and may be a hold-over from when _wsetlocale called
478 // setlocale instead of the other way around.
479 // (MSFT:20394962 - Investigate whether _WSETLOCALE_AVOID_SYNC_LOCALE_BIT is needed)
480 __acrt_disable_global_locale_sync(ptd, _WSETLOCALE_AVOID_SYNC_LOCALE_BIT);
481
482 __crt_call_and_cleanup([&]
483 {
484 if ((ptloci = _calloc_crt_t(__crt_locale_data, 1).detach()) != nullptr)
485 {
486 __acrt_lock_and_call(__acrt_locale_lock, [&]
487 {
488 _copytlocinfo_nolock(ptloci, ptd->_locale_info);
489
490 if ((retval = _wsetlocale_nolock(ptloci, _category, _wlocale)) != 0)
491 {
492 // If no call has been made to setlocale to change locale from "C" locale
493 // to some other locale, we keep locale_changed = 0. Other functions that
494 // depend on locale use this variable to optimize performance for C locale
495 // which is normally the case in applications.
496 if (_wlocale != nullptr)
497 {
498 if (wcscmp(_wlocale, __acrt_wide_c_locale_string) != 0)
499 {
501 }
502 // If it is again set to the C locale, could we not retain that state?
503 // else
504 // {
505 // __acrt_set_locale_unchanged();
506 // }
507 }
508
509 (void)_updatetlocinfoEx_nolock(&ptd->_locale_info, ptloci);
511 // Note that after incrementing _own_locale, if this thread doesn't
512 // have its own locale, _own_locale variable should be 1.
513
514 // Do not use __acrt_should_sync_with_global_locale() because
515 // _WSETLOCALE_AVOID_SYNC_LOCALE_BIT will interfere.
516 if (!(ptd->_own_locale & _PER_THREAD_LOCALE_BIT) &&
518 {
521 }
522 }
523 else
524 {
526 __acrt_free_locale(ptloci);
527 }
528 });
529 }
530 },
531 [&]{ __acrt_enable_global_locale_sync(ptd, _WSETLOCALE_AVOID_SYNC_LOCALE_BIT); });
532
533 return retval;
534}
535
537 __crt_locale_data* ploci,
538 int _category,
539 const wchar_t *_wlocale
540 )
541{
542 wchar_t * retval;
543 /* Interpret locale */
544
545 if (_category != LC_ALL)
546 {
547 retval = (_wlocale) ? _wsetlocale_set_cat(ploci, _category,_wlocale) :
548 ploci->lc_category[_category].wlocale;
549
550 } else { /* LC_ALL */
551 wchar_t lctemp[MAX_LC_LEN];
552 int i;
553 int same = 1;
554 int fLocaleSet = 0; /* flag to indicate if anything successfully set */
555
556 if (_wlocale != nullptr)
557 {
558 if ( (_wlocale[0]==L'L') && (_wlocale[1]==L'C') && (_wlocale[2]==L'_') )
559 {
560 /* parse compound locale string */
561 size_t len;
562 const wchar_t * p = _wlocale; /* start of string to parse */
563 const wchar_t * s;
564
565 do {
566 s = wcspbrk(p, L"=;");
567
568 if (s == nullptr || (len=(size_t)(s - p)) == 0 || (*s == L';'))
569 return nullptr; /* syntax error */
570
571 /* match with known LC_ strings, if possible, else ignore */
572 for (i=LC_ALL+1; i<=LC_MAX; i++)
573 {
574 if ((!wcsncmp(__lc_category[i].catname,p,len))
575 && (len==wcslen(__lc_category[i].catname)))
576 {
577 break; /* matched i */
578 }
579 } /* no match if (i>LC_MAX) -- just ignore */
580
581 if ((len = wcscspn(++s, L";")) == 0 && *s != L';')
582 return nullptr; /* syntax error */
583
584 if (i<=LC_MAX)
585 {
586 _ERRCHECK(wcsncpy_s(lctemp, _countof(lctemp), s, len));
587 lctemp[len]=L'\0'; /* null terminate string */
588
589 /* don't fail unless all categories fail */
590 if (_wsetlocale_set_cat(ploci, i,lctemp))
591 fLocaleSet++; /* record a success */
592 }
593 if (*(p = s+len)!=L'\0')
594 p++; /* skip ';', if present */
595
596 } while (*p);
597
598 retval = (fLocaleSet) ? _wsetlocale_get_all(ploci) : nullptr;
599
600 } else { /* simple LC_ALL locale string */
601
603 wchar_t localeNameTemp[LOCALE_NAME_MAX_LENGTH];
604 /* confirm locale is supported, get expanded locale */
605 retval = _expandlocale(_wlocale, lctemp, _countof(lctemp), localeNameTemp, _countof(localeNameTemp), code_page);
606 if (retval != 0)
607 {
608 for (i=LC_MIN; i<=LC_MAX; i++)
609 {
610 if (i!=LC_ALL)
611 {
612 if (wcscmp(lctemp, ploci->lc_category[i].wlocale) != 0)
613 { // does not match the LC_ALL locale
614 if (_wsetlocale_set_cat(ploci, i, lctemp))
615 {
616 fLocaleSet++; /* record a success */
617 }
618 else
619 {
620 same = 0; /* record a failure */
621 }
622 }
623 else
624 fLocaleSet++; /* trivial succcess */
625 }
626 }
627 if (same) /* needn't call setlocale_get_all() if all the same */
628 {
630 /* retval set above */
631 }
632 else
633 retval = (fLocaleSet) ? _wsetlocale_get_all(ploci) : nullptr;
634 }
635 }
636 } else { /* LC_ALL & nullptr */
637 retval = _wsetlocale_get_all (ploci);
638 }
639 }
640
641 /* common exit point */
642 return retval;
643} /* setlocale */
644
645
646static wchar_t * __cdecl _wsetlocale_set_cat (
647 __crt_locale_data* ploci,
648 int category,
649 const wchar_t * wlocale
650 )
651{
652 wchar_t * oldlocale;
653 wchar_t * oldlocalename;
654 UINT oldcodepage;
655
656 UINT cptemp;
657 wchar_t lctemp[MAX_LC_LEN];
658 wchar_t localeNameString[LOCALE_NAME_MAX_LENGTH];
659 wchar_t * pch = nullptr;
660 wchar_t * pch_cat_locale = nullptr;
661 size_t cch = 0;
662 unsigned short out[sizeof(_first_127char)];
663 int i;
664 __acrt_ptd* const ptd = __acrt_getptd();
665 __crt_ctype_compatibility_data* _Loc_c = ptd->_setloc_data._Loc_c; // __setloc_data._Loc_c is array
666 int _LOC_CCACHE = _countof(ptd->_setloc_data._Loc_c);
668
669 if (!_expandlocale(wlocale, lctemp, _countof(lctemp), localeNameString, _countof(localeNameString), cptemp))
670 return nullptr;
671
672 // if this category's locale hadn't changed
673 if (wcscmp(lctemp, ploci->lc_category[category].wlocale) == 0)
674 {
675 return ploci->lc_category[category].wlocale;
676 }
677
678 cch = wcslen(lctemp) + 1;
679 if ((pch = static_cast<wchar_t*>(_malloc_crt(sizeof(int) + (cch * sizeof(wchar_t))))) == nullptr)
680 return nullptr; /* error if malloc fails */
681
682 pch_cat_locale = pch + (sizeof(int) / sizeof(wchar_t));
683
684 /* save for possible restore */
685 oldlocale = ploci->lc_category[category].wlocale;
686 oldlocalename = ploci->locale_name[category];
687 oldcodepage = ploci->_public._locale_lc_codepage;
688
689 /* update locale string */
690 _ERRCHECK(wcscpy_s(pch_cat_locale, cch, lctemp));
691 ploci->lc_category[category].wlocale = pch_cat_locale;
692
693 /* Copy locale name */
694 if (lctemp[0] == L'C' && lctemp[1] == L'\x0') // if "C" locale
695 ploci->locale_name[category] = nullptr;
696 else
697 ploci->locale_name[category] = __acrt_copy_locale_name(localeNameString);
698
699 /* To speedup locale based comparisions, we identify if the current
700 * local has first 127 character set same as CLOCALE. If yes then
701 * ploci->lc_clike = TRUE.
702 */
703
704 if (category==LC_CTYPE)
705 {
706 ploci->_public._locale_lc_codepage = cptemp;
707 buf1 = _Loc_c[_LOC_CCACHE -1];
708 /* brings the recently used codepage to the top. or else shifts
709 * every thing down by one so that new _Loc_c can be placed at
710 * the top.
711 */
712 for ( i = 0; i < _LOC_CCACHE; i++)
713 {
714 if (ploci->_public._locale_lc_codepage == _Loc_c[i].id)
715 {
716 /* We don't really want to swap cache around in case what we are looking
717 * for is the first element of the cache
718 */
719 if (i!=0)
720 {
721 _Loc_c[0] = _Loc_c[i];
722 _Loc_c[i] = buf1;
723 }
724 break;
725 }
726 else
727 {
728 buf2 = _Loc_c[i];
729 _Loc_c[i] = buf1;
730 buf1 = buf2;
731 }
732 }
733 if ( i == _LOC_CCACHE)
734 {
735 if ( __acrt_GetStringTypeA(nullptr, CT_CTYPE1,
737 sizeof(_first_127char),
738 out,
740 TRUE ))
741 {
742 int j;
743 for ( j = 0; j < sizeof(_first_127char); j++)
744 out[j] = out[j]&
746 if ( !memcmp(out, _ctype_loc_style, (sizeof(_first_127char)/sizeof(char))*sizeof(short)))
747 {
748 _Loc_c[0].is_clike = TRUE;
749 }
750 else
751 {
752 _Loc_c[0].is_clike = FALSE;
753 }
754 }
755 else
756 _Loc_c[0].is_clike = FALSE;
757 _Loc_c[0].id = ploci->_public._locale_lc_codepage;
758 }
759 ploci->lc_clike = _Loc_c[0].is_clike;
760 } /* category==LC_CTYPE */
761 else if ( category == LC_COLLATE )
762 ploci->lc_collate_cp = cptemp;
763 else if ( category == LC_TIME )
764 ploci->lc_time_cp = cptemp;
765
766 if (__lc_category[category].init(ploci) != 0)
767 {
768 /* restore previous state */
769 ploci->lc_category[category].wlocale = oldlocale;
771 ploci->locale_name[category] = oldlocalename;
772 _free_crt(pch);
773 ploci->_public._locale_lc_codepage = oldcodepage;
774
775 return nullptr; /* error if non-zero return */
776 }
777
778 /* locale set up successfully */
779 /* Cleanup */
780 if ((oldlocale != __acrt_wide_c_locale_string) &&
782 )
783 {
784 _ASSERT(0);
788 ploci->lc_category[category].wlocale = nullptr;
789 ploci->locale_name[category] = nullptr;
790 }
791 if (pch)
792 {
793 reinterpret_cast<long&>(*pch) = 1;
794 }
795 ploci->lc_category[category].wrefcount = reinterpret_cast<long*>(pch);
796
797 return ploci->lc_category[category].wlocale;
798} /* _wsetlocale_set_cat */
799
800
801
803{
804 int i;
805 int same = 1;
806 wchar_t *pch = nullptr;
807 size_t cch = 0;
808 long *refcount = nullptr;
809 size_t refcountSize = 0;
810
811 /* allocate memory if necessary */
812 refcountSize = sizeof(int) + (sizeof(wchar_t) * (MAX_LC_LEN+1) * (LC_MAX-LC_MIN+1)) + (sizeof(wchar_t) * CATNAMES_LEN);
813 if ( (refcount = static_cast<long*>(_malloc_crt(refcountSize))) == nullptr)
814 return nullptr;
815
816 pch = ((wchar_t*)refcount) + (sizeof(int) / sizeof(wchar_t));
817 cch = (refcountSize - sizeof(int)) / sizeof(wchar_t);
818 *pch = L'\0';
819 *refcount = 1;
820 for (i=LC_MIN+1; ; i++)
821 {
822 _wcscats(pch, cch, 3, __lc_category[i].catname, L"=", ploci->lc_category[i].wlocale);
823 if (i<LC_MAX)
824 {
825 _ERRCHECK(wcscat_s(pch, cch, L";"));
826 if (wcscmp(ploci->lc_category[i].wlocale, ploci->lc_category[i+1].wlocale))
827 same=0;
828 }
829 else
830 {
831 if (!same) {
832 if (ploci->lc_category[LC_ALL].wrefcount != nullptr &&
834 _ASSERT(0);
836 }
837 if (ploci->lc_category[LC_ALL].refcount != nullptr &&
839 _ASSERT(0);
841 }
842 ploci->lc_category[LC_ALL].refcount = nullptr;
843 ploci->lc_category[LC_ALL].locale = nullptr;
844 ploci->lc_category[LC_ALL].wrefcount = refcount;
845 return ploci->lc_category[LC_ALL].wlocale = pch;
846 } else {
847 _free_crt(refcount);
848 if (ploci->lc_category[LC_ALL].wrefcount != nullptr &&
850 _ASSERT(0);
852 }
853 if (ploci->lc_category[LC_ALL].refcount != nullptr &&
855 _ASSERT(0);
857 }
858 ploci->lc_category[LC_ALL].refcount = nullptr;
859 ploci->lc_category[LC_ALL].locale = nullptr;
860 ploci->lc_category[LC_ALL].wrefcount = nullptr;
861 ploci->lc_category[LC_ALL].wlocale = nullptr;
862 return ploci->lc_category[LC_CTYPE].wlocale;
863 }
864 }
865 }
866} /* _wsetlocale_get_all */
867
868// --- BCP-47 tag parsing for _expandlocale() ---
869//
870// Provides parse_bcp47() which parses a given locale expression and updates a __crt_locale_strings structure accordingly.
871// Unsupported:
872// * Extension and private tags
873// * 4-8 character language subtags
874// * Grandfathered tags
875// * Lone code page specifiers (POSIX extension for BCP-47)
876
878{
879 normal,
882};
883
885{
886 wchar_t const * ptr;
887 size_t length;
889};
890
892{
893 switch (wc)
894 {
895 case '-':
896 case '_':
898 case '.':
900 case '\0':
901 default:
903 }
904}
905
906static bool string_is_alpha(wchar_t const * const str, size_t const len)
907{
908 for (size_t i = 0; i < len; ++i)
909 {
910 if (!__ascii_isalpha(str[i]))
911 {
912 return false;
913 }
914 }
915 return true;
916}
917
918static bool string_is_digit(wchar_t const * const str, size_t const len)
919{
920 for (size_t i = 0; i < len; ++i)
921 {
922 if (!__ascii_isdigit(str[i]))
923 {
924 return false;
925 }
926 }
927 return true;
928}
929
931{
933 {
934 return false;
935 }
936
937 if (section.length < 2 || section.length > 3)
938 {
939 return false; // Failure, only 2-3 letter language codes permitted.
940 }
941
942 if (!string_is_alpha(section.ptr, section.length))
943 {
944 return false;
945 }
946
947 _ERRCHECK(wcsncpy_s(names->szLanguage, _countof(names->szLanguage), section.ptr, section.length));
948 _ERRCHECK(wcsncpy_s(names->szLocaleName, _countof(names->szLocaleName), section.ptr, section.length));
949 return true;
950}
951
953{
955 {
956 return false;
957 }
958
959 if (section.length != 4) {
960 return false; // Failure, only 4 letter script codes permitted.
961 }
962
963 if (!string_is_alpha(section.ptr, section.length))
964 {
965 return false;
966 }
967
968 _ERRCHECK(wcsncat_s(names->szLocaleName, _countof(names->szLocaleName), L"-", 1));
969 _ERRCHECK(wcsncat_s(names->szLocaleName, _countof(names->szLocaleName), section.ptr, section.length));
970 return true;
971}
972
974{
976 {
977 return false;
978 }
979
980 if ( !(section.length == 2 && string_is_alpha(section.ptr, section.length)) // if not 2 letters
981 && !(section.length == 3 && string_is_digit(section.ptr, section.length))) // and not 3 digits
982 {
983 return false;
984 }
985
986 _ERRCHECK(wcsncpy_s(names->szCountry, _countof(names->szCountry), section.ptr, section.length));
987 _ERRCHECK(wcsncat_s(names->szLocaleName, _countof(names->szLocaleName), L"-", 1));
988 _ERRCHECK(wcsncat_s(names->szLocaleName, _countof(names->szLocaleName), section.ptr, section.length));
989 return true;
990}
991
993{
995 {
996 return false;
997 }
998
999 _ERRCHECK(wcsncpy_s(names->szCodePage, _countof(names->szCodePage), section.ptr, section.length));
1000 return true; // Success
1001}
1002
1003static bool parse_bcp47(__crt_locale_strings * const names, const wchar_t * const expr)
1004{
1005 wchar_t const * p = expr;
1006 wchar_t const * const delimiters = L"-_.";
1007
1008 memset(names, 0, sizeof(__crt_locale_strings));
1009
1010 size_t const max_sections = 4;
1012 size_t num_sections = 0;
1013
1014 for (auto last_delimiter = _bcp47_section_delimiter::normal;
1016 last_delimiter = categorize_delimiter(*p++)
1017 )
1018 {
1019 if (num_sections >= max_sections)
1020 {
1021 // Didn't reach end of string before running out of sections to parse.
1022 return false;
1023 }
1024
1025 size_t const section_length = (last_delimiter != _bcp47_section_delimiter::code_page)
1026 ? wcscspn(p, delimiters) : wcslen(p);
1027
1028 sections[num_sections].ptr = p;
1029 sections[num_sections].length = section_length;
1030 sections[num_sections].delimiter = last_delimiter;
1031
1032 p += section_length;
1033 ++num_sections;
1034 }
1035
1036 switch (num_sections)
1037 {
1038 case 1:
1039 // en
1041 case 2:
1042 // en-US
1043 // zh-Hans
1044 // en.utf-8
1045 // .utf-8
1050 );
1051 case 3:
1052 // en-US.utf-8
1053 // zh-Hans-HK
1057 );
1058 case 4:
1059 // zh-Hans-HK.utf-8
1064 default:
1065 return false;
1066 }
1067}
1068
1069// Utility functions/structs for _expandlocale().
1070
1071static int get_default_code_page(wchar_t const * const valid_windows_locale_name)
1072{
1073 int code_page{};
1074
1075 int const size_written = __acrt_GetLocaleInfoEx(
1076 valid_windows_locale_name,
1077 LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
1078 reinterpret_cast<LPWSTR>(&code_page),
1079 sizeof(int) / sizeof(wchar_t)
1080 );
1081
1082 if (size_written == 0 || code_page == 0)
1083 { // Default to UTF-8 if could not find or no default code page.
1084 return CP_UTF8;
1085 }
1086
1087 return code_page;
1088}
1089
1091{
1092 // Scope guard to keep invariants in _expandlocale for the localeNameOutput and _cacheLocaleName variables.
1093 // The cacheLocaleName/localeNameOutput is the only cache where work is done progressively in the cache value,
1094 // (inside __acrt_get_qualified_locale and __acrt_get_qualified_locale_downlevel)
1095 // so we must save/restore at function start and invalidate the cache once we have stuff to commit to both.
1096public:
1098 wchar_t * const localeNameOutput,
1099 size_t const localeNameSizeInChars,
1100 __crt_qualified_locale_data * const psetloc_data
1101 ) : _localeNameOutput(localeNameOutput),
1103 _psetloc_data(psetloc_data),
1105 {
1106 _ERRCHECK(wcsncpy_s(localeNameOutput, localeNameSizeInChars, psetloc_data->_cacheLocaleName, _countof(psetloc_data->_cacheLocaleName)));
1107 }
1108
1110 {
1111 if (!_committed)
1112 {
1114 }
1115 }
1116
1119
1120 void commit_locale_name(wchar_t const * const new_locale_name, size_t const new_locale_name_length)
1121 {
1122 _ERRCHECK(wcsncpy_s(_psetloc_data->_cacheLocaleName, _countof(_psetloc_data->_cacheLocaleName), new_locale_name, new_locale_name_length));
1123 commit_locale_name_cache_already_updated(new_locale_name, new_locale_name_length);
1124 }
1125
1126 void commit_locale_name_cache_already_updated(wchar_t const * const new_locale_name, size_t const new_locale_name_length)
1127 {
1128 _ERRCHECK(wcsncpy_s(_localeNameOutput, _localeNameSizeInChars, new_locale_name, new_locale_name_length));
1129 _committed = true;
1130 }
1131
1132private:
1137};
1138
1140 wchar_t const * const expr,
1141 wchar_t * const output,
1142 size_t const sizeInChars,
1143 wchar_t * const localeNameOutput,
1144 size_t const localeNameSizeInChars,
1145 UINT& output_code_page
1146 )
1147{
1148 // Returns: locale name to return to user (lifetime bound to PTD variable _cacheout)
1149 // Out Parameters:
1150 // * output: locale name to return to user (lifetime bound to supplied buffer)
1151 // * localeNameOutput: normalized locale name to be used internally (lifetime bound to supplied buffer)
1152 // * output_code_page: code page used
1153 //
1154 // Effects:
1155 // Parses an input locale string and returns the string that will replicate the effects just taken (output), the string to be used
1156 // for Win32 calls (localeNameOutput), and the code page.
1157 // Note that there are three modes here:
1158 // * Legacy and Windows Locale Names:
1159 // The output locale string and internally used locale string become normalized for Win32 APIs.
1160 // Neither necessarily match the user input locale.
1161 // Uses ACP as default if Windows does not know the code page.
1162 // * Permissive Windows locale names:
1163 // Ask Windows whether full given user string is a known locale name.
1164 // In that case, the output locale string, internally used locale string, and user input locale all match.
1165 // Uses UTF-8 as default if Windows does not know the code page.
1166 // * BCP-47 Locale Names:
1167 // Windows doesn't recognize BCP-47 + code page specifiers, but we must support them for proper UTF-8 support.
1168 // The output locale name must include the code page, but internally we modify the format so Windows understands it.
1169 // Uses UTF-8 as default if Windows does not know the code page.
1170 //
1171 // Also populates _psetloc_data structure from the PTD:
1172 // Caching Internals:
1173 // * _cachein: Caches last successful 'expr'.
1174 // * _cacheout: Caches last successful 'output' (which is also the return value).
1175 // * _cachecp: Caches last successful 'output_code_page'.
1176 // * _cacheLocaleName: Caches last successful 'localeNameOutput'.
1177 // Legacy Internals (used by __acrt_get_qualified_locale and __acrt_get_qualified_locale_downlevel only):
1178 // * pchLanguage: Pointer to start of language name, ex: "English"
1179 // * pchCountry: Pointer to start of country/region name, ex: "United States"
1180 // * iLocState: Used to record the match degree for locales checked (i.e. language and region match vs just language match)
1181 // * bAbbrevLanguage: Whether language name is a three-letter short-form, ex: "ENU"
1182 // * bAbbrevCountry: Whether country/region name is a three letter short-form, ex: "USA"
1183 // * iPrimaryLen: Length of pchLanguage portion of locale string
1184 // Also in _psetloc_data, but not used in _expandlocale: _Loc_c
1185
1186 if (!expr)
1187 {
1188 return nullptr; // error if no input
1189 }
1190
1191 // C locale
1192 // Callers know that LocaleNameOutput has not been updated and check for "C" locale before using it.
1193 if (expr[0] == L'C' && expr[1] == L'\0')
1194 {
1195 _ERRCHECK(wcscpy_s(output, sizeInChars, L"C"));
1196 output_code_page = CP_ACP;
1197 return output;
1198 }
1199
1200 __crt_qualified_locale_data * const _psetloc_data = &__acrt_getptd()->_setloc_data;
1201 UINT * const pcachecp = &_psetloc_data->_cachecp;
1202 wchar_t * const cachein = _psetloc_data->_cachein;
1203 size_t const cacheinLen = _countof(_psetloc_data->_cachein);
1204 wchar_t * const cacheout = _psetloc_data->_cacheout;
1205 size_t const cacheoutLen = _countof(_psetloc_data->_cacheout);
1206 size_t charactersInExpression = 0;
1207 int iCodePage = 0;
1208
1209 // This guard owns access to localeNameOutput. It expresses the invariants that localeNameOutput and _cacheLocaleName have.
1210 _expandlocale_locale_name_cache locale_name_guard(localeNameOutput, localeNameSizeInChars, _psetloc_data);
1211
1212 // First, make sure we didn't just do this one
1213 charactersInExpression = wcslen(expr);
1214 if (charactersInExpression >= MAX_LC_LEN || // we would never have cached this
1215 (wcscmp(cacheout, expr) && wcscmp(cachein, expr)))
1216 {
1218 BOOL getqloc_results = FALSE;
1219 BOOL const isDownlevel = !__acrt_can_use_vista_locale_apis();
1220
1221 // Check if can parse as Legacy/Windows locale name
1222 if (__lc_wcstolc(&names, expr) == 0)
1223 {
1224 if (isDownlevel)
1225 {
1226 getqloc_results = __acrt_get_qualified_locale_downlevel(&names, pcachecp, &names);
1227 }
1228 else
1229 {
1230 getqloc_results = __acrt_get_qualified_locale(&names, pcachecp, &names);
1231 }
1232 }
1233
1234 // If successfully parsed as Legacy/Windows name
1235 if (getqloc_results)
1236 {
1237 // Legacy/Windows name resolution returns applies normalization to both returned and internally used locale names.
1238 __lc_lctowcs(cacheout, cacheoutLen, &names);
1239
1240 // __acrt_get_qualified_locale and __acrt_get_qualified_locale_downlevel update _cacheLocaleName - if successful commit locale changes
1241 locale_name_guard.commit_locale_name_cache_already_updated(names.szLocaleName, wcslen(names.szLocaleName) + 1);
1242 }
1244 {
1245 // Windows recognizes the locale expression - only work is to grab the code page to be used.
1246 iCodePage = get_default_code_page(expr);
1247
1248 // Commit code page
1249 *pcachecp = static_cast<WORD>(iCodePage);
1250
1251 // Commit locale name that we will return to the user (same as input locale string).
1252 _ERRCHECK(wcsncpy_s(cacheout, cacheoutLen, expr, charactersInExpression + 1));
1253
1254 // Commit locale name for internal use (same as input locale string).
1255 locale_name_guard.commit_locale_name(expr, charactersInExpression + 1);
1256 }
1257 else if (parse_bcp47(&names, expr) && __acrt_IsValidLocaleName(names.szLocaleName))
1258 {
1259 // Parsed as Windows-recognized BCP-47 tag
1260 wchar_t const * const normalized_locale_name = names.szLocaleName;
1261
1262 if (names.szCodePage[0])
1263 {
1264 wchar_t const * const cp = names.szCodePage;
1265
1266 // Allow .utf8/.utf-8 for BCP-47 tags.
1267 if ( __ascii_towlower(cp[0]) == L'u'
1268 && __ascii_towlower(cp[1]) == L't'
1269 && __ascii_towlower(cp[2]) == L'f'
1270 && (cp[3] == L'8' && cp[4] == L'\0')
1271 || (cp[3] == L'-' && cp[4] == L'8' && cp[5] == L'\0'))
1272 {
1273 iCodePage = CP_UTF8;
1274 }
1275 else
1276 {
1277 // Other codepage tokens (fr-FR.1252, etc.) aren't supported for BCP-47 tags (eg: Use Unicode!)
1278 return nullptr;
1279 }
1280 }
1281 else
1282 {
1283 iCodePage = get_default_code_page(normalized_locale_name);
1284 }
1285
1286 // Commit code page
1287 *pcachecp = static_cast<WORD>(iCodePage);
1288
1289 // Commit locale name that we will return to the user (same as input locale string).
1290 _ERRCHECK(wcsncpy_s(cacheout, cacheoutLen, expr, charactersInExpression + 1));
1291
1292 // Commit normalized name for internal use.
1293 locale_name_guard.commit_locale_name(normalized_locale_name, wcslen(normalized_locale_name) + 1);
1294 }
1295 else
1296 {
1297 return nullptr; // input unrecognized as locale name
1298 }
1299
1300 // Operation succeeded - commit input cache.
1301 if (*expr && charactersInExpression < MAX_LC_LEN)
1302 {
1303 _ERRCHECK(wcsncpy_s(cachein, cacheinLen, expr, charactersInExpression + 1));
1304 }
1305 else
1306 {
1307 *cachein = L'\x0';
1308 }
1309 }
1310
1311 output_code_page = *pcachecp; // Update code page
1312
1313 _ERRCHECK(wcscpy_s(output, sizeInChars, cacheout));
1314 return cacheout; // Return locale name to be given back to user, with lifetime bound in PTD
1315}
1316
1317/* helpers */
1318
1319void _wcscats ( wchar_t *outstr, size_t numberOfElements, int n, ...)
1320{
1321 int i;
1323
1324 va_start (substr, n);
1325
1326 for (i =0; i<n; i++)
1327 {
1328 _ERRCHECK(wcscat_s(outstr, numberOfElements, va_arg(substr, wchar_t *)));
1329 }
1330 va_end(substr);
1331}
1332
1333// Parse the wlocale string to find the array of language/region/codepage strings (if available)
1334// in the form .CodePage, Language, Language_Region, Language_Region.Codepage, or Language.CodePage
1335// If the input is a BCP-47 tag, then that tag is returned in the names language.
1336int __lc_wcstolc ( __crt_locale_strings *names, const wchar_t *wlocale)
1337{
1338 int i;
1339 size_t len;
1340 wchar_t wch;
1341
1342 memset((void *)names, '\0', sizeof(__crt_locale_strings)); /* clear out result */
1343
1344 if (*wlocale==L'\0')
1345 return 0; /* trivial case */
1346
1347 /* only code page is given */
1348 if (wlocale[0] == L'.' && wlocale[1] != L'\0')
1349 {
1350 _ERRCHECK(wcsncpy_s(names->szCodePage, _countof(names->szCodePage), &wlocale[1], MAX_CP_LEN-1));
1351 /* Make sure to null terminate the string in case wlocale is > MAX_CP_LEN */
1352 names->szCodePage[ MAX_CP_LEN -1] = 0;
1353 return 0;
1354 }
1355
1356 // Looks like Language_Country/Region.Codepage
1357 for (i=0; ; i++)
1358 {
1359 // _ language country/region separator, . is before codepage, either , or \0 are end of string.
1360 len = wcscspn(wlocale, L"_.,");
1361 if (len == 0)
1362 return -1; /* syntax error, can't start with a separator */
1363
1364 wch = wlocale[len];
1365
1366 if ((i == 0) && (len < MAX_LANG_LEN))
1367 {
1368 _ERRCHECK(wcsncpy_s(names->szLanguage, _countof(names->szLanguage), wlocale, len));
1369 if (wch == L'.')
1370 {
1371 // '.' is a delimiter before codepage, so codepage is expected next (skip country/region)
1372 i++;
1373 }
1374 }
1375
1376 else if ((i==1) && (len<MAX_CTRY_LEN) && (wch!=L'_'))
1377 _ERRCHECK(wcsncpy_s(names->szCountry, _countof(names->szCountry), wlocale, len));
1378
1379 else if ((i==2) && (len<MAX_CP_LEN) && (wch==L'\0' || wch==L','))
1380 _ERRCHECK(wcsncpy_s(names->szCodePage, _countof(names->szCodePage), wlocale, len));
1381
1382 else
1383 return -1; /* error parsing wlocale string */
1384
1385 if (wch==L',')
1386 {
1387 /* modifier not used in current implementation, but it
1388 must be parsed to for POSIX/XOpen conformance */
1389 /* wcsncpy(names->szModifier, wlocale, MAX_MODIFIER_LEN-1); */
1390 break;
1391 }
1392
1393 if (!wch)
1394 break;
1395 wlocale+=(len+1);
1396 }
1397 return 0;
1398}
1399// Append locale name pieces together in the form of "Language_country/region.CodePage"
1400// Note that the preferred form is the BCP-47 tag, but we don't want to change legacy names
1402{
1404 if (*(names->szCountry))
1405 _wcscats(locale, numberOfElements, 2, L"_", names->szCountry);
1406 if (*(names->szCodePage))
1407 _wcscats(locale, numberOfElements, 2, L".", names->szCodePage);
1408}
1409
1410// Create a copy of a locale name string
1412{
1413 size_t cch;
1414 wchar_t* localeNameCopy;
1415
1416 if (!localeName) // Input cannot be nullptr
1417 return nullptr;
1418
1419 cch = wcsnlen(localeName, LOCALE_NAME_MAX_LENGTH);
1420 if (cch >= LOCALE_NAME_MAX_LENGTH) // locale name length must be <= LOCALE_NAME_MAX_LENGTH
1421 return nullptr;
1422
1423 if ((localeNameCopy = (wchar_t *) _malloc_crt((cch + 1) * sizeof(wchar_t))) == nullptr)
1424 return nullptr;
1425
1426 _ERRCHECK(wcsncpy_s(localeNameCopy, cch+1, localeName, cch+1));
1427 return localeNameCopy;
1428}
1429
1430#endif /* _UCRT_ENCLAVE_BUILD */
1431
1432} // extern "C"
#define _ASSERT(x)
BOOL __cdecl __acrt_GetStringTypeA(_locale_t const locale, DWORD const info_type, LPCSTR const string, int const string_size_in_bytes, unsigned short *const char_type, int const code_page, BOOL const error)
#define __inline
Definition: _wctype.cpp:15
#define EINVAL
Definition: acclib.h:90
#define ENOMEM
Definition: acclib.h:84
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
#define __cdecl
Definition: accygwin.h:79
char * va_list
Definition: acmsvcex.h:78
#define va_end(ap)
Definition: acmsvcex.h:90
#define va_start(ap, A)
Definition: acmsvcex.h:91
#define va_arg(ap, T)
Definition: acmsvcex.h:89
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedDecrement
Definition: armddk.h:52
#define MAX_LANG_LEN
#define MAX_CP_LEN
#define MAX_CTRY_LEN
#define MAX_LC_LEN
void commit_locale_name_cache_already_updated(wchar_t const *const new_locale_name, size_t const new_locale_name_length)
__crt_qualified_locale_data * _psetloc_data
_expandlocale_locale_name_cache(wchar_t *const localeNameOutput, size_t const localeNameSizeInChars, __crt_qualified_locale_data *const psetloc_data)
void commit_locale_name(wchar_t const *const new_locale_name, size_t const new_locale_name_length)
_expandlocale_locale_name_cache & operator=(_expandlocale_locale_name_cache const &)=delete
_expandlocale_locale_name_cache(_expandlocale_locale_name_cache const &)=delete
Definition: _locale.h:75
__acrt_ptd *__cdecl __acrt_getptd(void)
void __cdecl __acrt_unlock(_In_ __acrt_lock_id lock)
Definition: locks.cpp:57
#define _WSETLOCALE_AVOID_SYNC_LOCALE_BIT
void __cdecl __acrt_release_locale_ref(__crt_locale_data *)
__crt_multibyte_data *__cdecl __acrt_update_thread_multibyte_data(void)
Definition: mbctype.cpp:361
int WINAPI __acrt_GetLocaleInfoEx(_In_opt_ LPCWSTR locale_name, _In_ LCTYPE lc_type, _Out_writes_opt_(data_count) LPWSTR data, _In_ int data_count)
struct lconv * __acrt_lconv
Definition: localeconv.cpp:56
@ __acrt_locale_lock
@ __acrt_multibyte_cp_lock
bool __cdecl __acrt_can_use_vista_locale_apis(void)
#define _CRT_LINKER_FORCE_INCLUDE(name)
wchar_t __acrt_wide_c_locale_string[]
Definition: nlsdata.cpp:28
#define CATNAMES_LEN
#define _PER_THREAD_LOCALE_BIT
void __cdecl __acrt_eagerly_load_locale_apis(void)
__crt_locale_data *__cdecl __acrt_update_thread_locale_data(void)
#define _ERRCHECK(e)
void __cdecl __acrt_add_locale_ref(__crt_locale_data *)
__crt_multibyte_data __acrt_initial_multibyte_data
Definition: mbctype.cpp:42
#define _GLOBAL_LOCALE_BIT
BOOL WINAPI __acrt_IsValidLocaleName(_In_ LPCWSTR locale_name)
#define _VALIDATE_RETURN(expr, errorcode, retexpr)
wcsncat_s
_In_ size_t const _In_ int _In_ bool const _In_ unsigned const _In_ __acrt_rounding_mode const _Inout_ __crt_cached_ptd_host & ptd
Definition: cvt.cpp:355
__acrt_lock(__acrt_heap_lock)
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define CP_ACP
Definition: compat.h:109
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned short WORD
Definition: ntddk_ex.h:93
void __declspec(noinline) __cdecl _free_base(void *const block)
Definition: free_base.cpp:98
BOOL __cdecl __acrt_get_qualified_locale(const __crt_locale_strings *, UINT *, __crt_locale_strings *)
BOOL __cdecl __acrt_get_qualified_locale_downlevel(const __crt_locale_strings *lpInStr, UINT *lpOutCodePage, __crt_locale_strings *lpOutStr)
GLdouble s
Definition: gl.h:2039
GLdouble n
Definition: glext.h:7729
GLuint GLuint * names
Definition: glext.h:11545
GLuint64EXT * result
Definition: glext.h:11304
GLfloat GLfloat p
Definition: glext.h:8902
GLenum GLsizei len
Definition: glext.h:6722
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
#define _BLANK
Definition: ctype.h:72
#define _PUNCT
Definition: ctype.h:70
#define _CONTROL
Definition: ctype.h:71
#define _LOWER
Definition: ctype.h:66
#define _SPACE
Definition: ctype.h:68
#define _ALPHA
Definition: ctype.h:76
#define _UPPER
Definition: ctype.h:65
#define _HEX
Definition: ctype.h:73
#define _DIGIT
Definition: ctype.h:67
#define __mb_cur_max
Definition: ctype.h:629
int __globallocalestatus
Definition: glstatus.cpp:13
#define LC_CTYPE
Definition: locale.h:19
#define LC_MAX
Definition: locale.h:25
#define LC_MIN
Definition: locale.h:24
#define LC_ALL
Definition: locale.h:17
#define LC_TIME
Definition: locale.h:22
#define LC_COLLATE
Definition: locale.h:18
#define _DISABLE_PER_THREAD_LOCALE
Definition: locale.h:55
#define _ENABLE_PER_THREAD_LOCALE
Definition: locale.h:54
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define _pctype
Definition: wctype.h:43
__forceinline int __CRTDECL __ascii_towlower(int const _C)
Definition: ctype.h:180
#define __ascii_isalpha(c)
Definition: ctype.h:141
#define __ascii_isdigit(c)
Definition: ctype.h:142
int __cdecl __acrt_locale_initialize_ctype(__crt_locale_data *ploci)
Definition: initctype.cpp:51
int __cdecl __acrt_locale_initialize_monetary(__crt_locale_data *ploci)
Definition: initmon.cpp:61
int __cdecl __acrt_locale_initialize_numeric(__crt_locale_data *ploci)
Definition: initnum.cpp:76
int __cdecl __acrt_locale_initialize_time(__crt_locale_data *const locale_data)
Definition: inittime.cpp:104
#define _free_crt
#define _malloc_crt
#define _VALIDATE_RETURN_NOEXC(expr, errorcode, retexpr)
static substr_t substr(const WCHAR *str, size_t len)
Definition: internet.h:203
long __cdecl _InterlockedExchange(_Interlocked_operand_ long volatile *_Target, long _Value)
_locale_t plocinfo
Definition: ismbbyte.cpp:75
#define pch(ap)
Definition: match.c:418
#define wcscpy_s(d, l, s)
Definition: utility.h:201
#define wcsncpy_s(d, l, s, n)
Definition: utility.h:202
static DWORD DWORD void LPSTR DWORD cch
Definition: str.c:202
@ max_sections
Definition: resource.c:32
static size_t numberOfElements
Definition: string.c:87
struct section sections[2]
Definition: diskspace.c:792
unsigned int UINT
Definition: ndis.h:50
__crt_state_management::dual_state_global< __crt_locale_data * > __acrt_current_locale_data
Definition: nlsdata.cpp:132
#define _Out_writes_z_(s)
Definition: no_sal2.h:180
#define _Success_(c)
Definition: no_sal2.h:84
#define _In_z_
Definition: no_sal2.h:164
#define _Inout_updates_z_(s)
Definition: no_sal2.h:186
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
#define LOCALE_NAME_MAX_LENGTH
#define L(x)
Definition: ntvdm.h:50
#define __try
Definition: pseh2_64.h:172
#define __endtry
Definition: pseh2_64.h:175
#define __finally
Definition: pseh2_64.h:174
const WCHAR * str
_Check_return_ _CRTIMP _CONST_RETURN wchar_t *__cdecl wcspbrk(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_Control)
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
_Check_return_ _CRTIMP int __cdecl wcsncmp(_In_reads_or_z_(_MaxCount) const wchar_t *_Str1, _In_reads_or_z_(_MaxCount) const wchar_t *_Str2, _In_ size_t _MaxCount)
_Check_return_ _CRTIMP size_t __cdecl wcscspn(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_Control)
#define CP_UTF8
Definition: nls.h:20
#define memset(x, y, z)
Definition: compat.h:39
#define _countof(array)
Definition: sndvol32.h:70
#define false
Definition: stdbool.h:37
size_t __cdecl wcsnlen(wchar_t const *const string, size_t const maximum_count)
Definition: strnlen.cpp:210
__crt_qualified_locale_data _setloc_data
unsigned int _locale_lc_codepage
Definition: corecrt.h:625
__crt_locale_data_public _public
unsigned int lc_collate_cp
__crt_locale_refcount lc_category[6]
wchar_t * locale_name[6]
unsigned int lc_time_cp
wchar_t _cachein[MAX_LC_LEN]
wchar_t _cacheout[MAX_LC_LEN]
wchar_t _cacheLocaleName[LOCALE_NAME_MAX_LENGTH]
_bcp47_section_delimiter delimiter
Definition: wsetlocale.cpp:888
wchar_t const * ptr
Definition: wsetlocale.cpp:886
Definition: query.h:86
pthreadlocinfo locinfo
Definition: corecrt.h:23
pthreadmbcinfo mbcinfo
Definition: corecrt.h:24
Definition: parser.c:56
#define wchar_t
Definition: wchar.h:102
INT CDECL wcscat_s(wchar_t *dst, size_t elem, const wchar_t *src)
Definition: wcs.c:406
wchar_t tm const _CrtWcstime_Writes_and_advances_ptr_ count wchar_t ** out
Definition: wcsftime.cpp:383
int retval
Definition: wcstombs.cpp:91
#define CT_CTYPE1
Definition: winnls.h:239
#define LOCALE_IDEFAULTANSICODEPAGE
Definition: winnls.h:40
static int init
Definition: wintirpc.c:33
int __cdecl _setmbcp_nolock(int, __crt_multibyte_data *)
Definition: mbctype.cpp:692
__crt_locale_data *__cdecl _updatetlocinfoEx_nolock(__crt_locale_data **, __crt_locale_data *)
void _wcscats(_Inout_updates_z_(_Param_(2)) wchar_t *, size_t, int,...)
static wchar_t *__cdecl _wsetlocale_get_all(__crt_locale_data *)
Definition: wsetlocale.cpp:802
static bool string_is_alpha(wchar_t const *const str, size_t const len)
Definition: wsetlocale.cpp:906
static bool parse_bcp47_language(__crt_locale_strings *const names, _bcp47_section const &section)
Definition: wsetlocale.cpp:930
static bool parse_bcp47_script(__crt_locale_strings *const names, _bcp47_section const &section)
Definition: wsetlocale.cpp:952
_In_ size_t sizeInChars
Definition: wsetlocale.cpp:38
void __cdecl __acrt_free_locale(__crt_locale_data *)
const unsigned short _wctype[]
Definition: ctype.c:296
static __crt_locale_data *__cdecl _updatetlocinfo_nolock(void)
static void __cdecl _copytlocinfo_nolock(__crt_locale_data *ptlocid, __crt_locale_data *ptlocis)
Definition: wsetlocale.cpp:280
static bool parse_bcp47_code_page(__crt_locale_strings *const names, _bcp47_section const &section)
Definition: wsetlocale.cpp:992
static bool parse_bcp47_region(__crt_locale_strings *const names, _bcp47_section const &section)
Definition: wsetlocale.cpp:973
LPWSTR __cdecl __acrt_copy_locale_name(LPCWSTR localeName)
_In_ size_t _In_ size_t localeNameSizeInChars
Definition: wsetlocale.cpp:40
static const char _first_127char[]
Definition: wsetlocale.cpp:16
const __lc_category[LC_MAX-LC_MIN+1]
Definition: wsetlocale.cpp:261
_locale_t __cdecl _get_current_locale(void)
Definition: wsetlocale.cpp:213
wchar_t *__cdecl _wsetlocale(int _category, const wchar_t *_wlocale)
Definition: wsetlocale.cpp:441
static __inline void sync_legacy_variables_lk()
Definition: wsetlocale.cpp:298
void __cdecl __acrt_set_locale_changed()
Definition: wsetlocale.cpp:54
static wchar_t *__cdecl _wsetlocale_nolock(__crt_locale_data *, int, const wchar_t *)
Definition: wsetlocale.cpp:536
__crt_locale_data __acrt_initial_locale_data
Definition: nlsdata.cpp:92
static bool string_is_digit(wchar_t const *const str, size_t const len)
Definition: wsetlocale.cpp:918
_locale_t __cdecl _create_locale(int _category, const char *_locale)
Definition: wsetlocale.cpp:378
static wchar_t *__cdecl _wsetlocale_set_cat(__crt_locale_data *, int, const wchar_t *)
Definition: wsetlocale.cpp:646
static int __cdecl no_op_initialize(__crt_locale_data *)
Definition: wsetlocale.cpp:248
static _bcp47_section_delimiter categorize_delimiter(wchar_t const wc)
Definition: wsetlocale.cpp:891
int __lc_wcstolc(__crt_locale_strings *, const wchar_t *)
void __cdecl __acrt_uninitialize_locale()
Definition: wsetlocale.cpp:119
long __acrt_locale_changed_data
Definition: wsetlocale.cpp:31
static int get_default_code_page(wchar_t const *const valid_windows_locale_name)
_In_ size_t _In_ size_t _Out_ UINT & cp
Definition: wsetlocale.cpp:42
static const unsigned short * _ctype_loc_style
Definition: wsetlocale.cpp:29
int __cdecl _configthreadlocale(int i)
Definition: wsetlocale.cpp:71
void __cdecl _free_locale(_locale_t plocinfo)
Definition: wsetlocale.cpp:151
_bcp47_section_delimiter
Definition: wsetlocale.cpp:878
_locale_t __cdecl _wcreate_locale(int _category, const wchar_t *locale)
Definition: wsetlocale.cpp:340
static bool parse_bcp47(__crt_locale_strings *const names, const wchar_t *const expr)
wchar_t * _expandlocale(wchar_t const *const expr, wchar_t *const output, size_t const sizeInChars, wchar_t *const localeNameOutput, size_t const localeNameSizeInChars, UINT &output_code_page)
void __lc_lctowcs(_Inout_updates_z_(_Param_(2)) wchar_t *, size_t, const __crt_locale_strings *)
WCHAR * LPWSTR
Definition: xmlstorage.h:184
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define const
Definition: zconf.h:233