Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1159 lines
36 KiB

  1. /***
  2. *setlocal.c - Contains the setlocale function
  3. *
  4. * Copyright (c) 1988-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Contains the setlocale() function.
  8. *
  9. *Revision History:
  10. * 03-21-89 JCR Module created.
  11. * 09-25-89 GJF Fixed copyright. Checked for compatibility with Win 3.0
  12. * 09-25-90 KRS Major rewrite--support more than "C" locale if _INTL.
  13. * 11-05-91 ETC Get 09-25-90 working for C and "" locales; separate
  14. * setlocal.h; add Init functions.
  15. * 12-05-91 ETC Separate nlsdata.c; add mt support; remove calls to
  16. * itself.
  17. * 12-20-91 ETC Added _getlocaleinfo api interface function.
  18. * 09-25-92 KRS Fix for latest NLSAPI changes, etc.
  19. * 01-25-93 KRS Fix for latest changes, clean up code, etc.
  20. * 02-02-93 CFW Many modifications and bug fixes (all under _INTL).
  21. * 02-08-93 CFW Bug fixes and casts to avoid warnings (all under _INTL).
  22. * 02-17-93 CFW Removed re-call of init() functions in case of failure.
  23. * 03-01-93 CFW Check GetQualifiedLocale return value.
  24. * 03-02-93 CFW Added POSIX conformance, check environment variables.
  25. * 03-09-93 CFW Set CP to CP_ACP when changing to C locale.
  26. * 03-17-93 CFW Change expand to expandlocale, prepend _ to internal
  27. * functions, lots of POSIX fixup.
  28. * 03-23-93 CFW Add _ to GetQualifiedLocale call.
  29. * 03-24-93 CFW Change to _get_qualified_locale, support ".codepage".
  30. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  31. * 05-10-93 CFW Disallow setlocale(LC_*, ".").
  32. * 05-24-93 CFW Clean up file (brief is evil).
  33. * 09-15-93 CFW Use ANSI conformant "__" names.
  34. * 02-04-94 CFW Remove unused param.
  35. * 04-15-94 GJF Moved prototypes for locale category initialization
  36. * functions to setlocal.h. Made definitions for
  37. * __lc_category, cacheid, cachecp, cachein and cacheout
  38. * conditional on DLL_FOR_WIN32S. Made _clocalestr into
  39. * a global for DLL_FOR_WIN32S so that crtlib.c may use
  40. * it.
  41. * 09-06-94 CFW Remove _INTL switch.
  42. * 09-06-94 CFW Merge non-Win32.
  43. * 01-10-95 CFW Debug CRT allocs.
  44. * 09-25-95 GJF New locking scheme for functions which set or
  45. * reference locale information.
  46. * 05-02-96 SKS Variables _setlc_active and __unguarded_readlc_active
  47. * are used by MSVCP42*.DLL and so must be _CRTIMP.
  48. * 07-09-97 GJF Made __lc_category selectany. Also, removed obsolete
  49. * DLL_FOR_WIN32S support.
  50. * 01-12-98 GJF Use _lc_collate_cp codepage.
  51. * 02-27-98 RKP Add 64 bit support.
  52. * 09-10-98 GJF Revised multithread support based on threadlocinfo
  53. * struct.
  54. * 09-21-98 GJF No need to lock or update threadlocinfo for setlocale
  55. * calls which only read info.
  56. * 11-06-98 GJF In __lc_strtolc, make sure you don't overflow
  57. * names->szCodePage.
  58. * 12-08-98 GJF Fixed __updatetlocinfo (several errors).
  59. * 01-04-99 GJF Changes for 64-bit size_t.
  60. * 01-18-99 GJF In MT models, setlocale needs to check if the old
  61. * __ptlocinfo needs to be freed up. Also, unrelated,
  62. * have _setlocale_get_all return NULL if malloc fails.
  63. * 03-02-99 KRS Partially back out previous fix for now. (per BryanT)
  64. * 03-20-99 GJF Added more reference counters (restoring fix)
  65. * 04-24-99 PML Added __lconv_intl_refcount
  66. * 01-26-00 GB Modified _setlocale_cat. Added _first_127char,
  67. * _ctype_loc_style and __lc_clike
  68. * 08-18-00 GB Fixed problems with __lc_clike stuff.
  69. * 09-06-00 GB Made pwctype independent of locale.
  70. * 10-12-00 GB Compared requested locale to current locale for
  71. * requested category in setlocale-set_cat. Performance
  72. * enhancement.
  73. * 11-05-00 PML Fixed double-free of __lconv_mon_refcount and
  74. * lconv_num_refcount (vs7#181380)
  75. * 01-29-01 GB Added _func function version of data variable used in msvcprt.lib
  76. * to work with STATIC_CPPLIB
  77. *
  78. *******************************************************************************/
  79. #include <locale.h>
  80. #if !defined(_WIN32) && !defined(_POSIX_)
  81. static char _clocalestr[] = "C";
  82. #else /* _WIN32/_POSIX_ */
  83. #include <cruntime.h>
  84. #include <mtdll.h>
  85. #include <malloc.h>
  86. #include <string.h>
  87. #include <stdarg.h>
  88. #include <stdlib.h> /* for strtol */
  89. #include <setlocal.h>
  90. #include <dbgint.h>
  91. #include <ctype.h>
  92. #include <awint.h>
  93. /* C locale */
  94. static char _clocalestr[] = "C";
  95. #ifdef _POSIX_
  96. static char _posixlocalestr[] = "POSIX";
  97. #endif
  98. #define _LOC_CCACHE 5 // Cache of last 5 locale changed and if they are clike.
  99. __declspec(selectany) struct {
  100. const char * catname;
  101. char * locale;
  102. int (* init)(void);
  103. } __lc_category[LC_MAX-LC_MIN+1] = {
  104. /* code assumes locale initialization is "_clocalestr" */
  105. { "LC_ALL", NULL, __init_dummy /* never called */ },
  106. { "LC_COLLATE", _clocalestr, __init_collate },
  107. { "LC_CTYPE", _clocalestr, __init_ctype },
  108. { "LC_MONETARY",_clocalestr, __init_monetary },
  109. { "LC_NUMERIC", _clocalestr, __init_numeric },
  110. { "LC_TIME", _clocalestr, __init_time }
  111. };
  112. struct _is_ctype_compatible {
  113. unsigned long id;
  114. int is_clike;
  115. };
  116. /* First 127 character type for CLOCALE */
  117. static const short _ctype_loc_style[] = {
  118. _CONTROL,
  119. _CONTROL,
  120. _CONTROL,
  121. _CONTROL,
  122. _CONTROL,
  123. _CONTROL,
  124. _CONTROL,
  125. _CONTROL,
  126. _SPACE | _CONTROL | _BLANK,
  127. _SPACE | _CONTROL,
  128. _SPACE | _CONTROL,
  129. _SPACE | _CONTROL,
  130. _SPACE | _CONTROL,
  131. _CONTROL,
  132. _CONTROL,
  133. _CONTROL,
  134. _CONTROL,
  135. _CONTROL,
  136. _CONTROL,
  137. _CONTROL,
  138. _CONTROL,
  139. _CONTROL,
  140. _CONTROL,
  141. _CONTROL,
  142. _CONTROL,
  143. _CONTROL,
  144. _CONTROL,
  145. _CONTROL,
  146. _CONTROL,
  147. _CONTROL,
  148. _CONTROL,
  149. _SPACE | _BLANK,
  150. _PUNCT,
  151. _PUNCT,
  152. _PUNCT,
  153. _PUNCT,
  154. _PUNCT,
  155. _PUNCT,
  156. _PUNCT,
  157. _PUNCT,
  158. _PUNCT,
  159. _PUNCT,
  160. _PUNCT,
  161. _PUNCT,
  162. _PUNCT,
  163. _PUNCT,
  164. _PUNCT,
  165. _DIGIT | _HEX,
  166. _DIGIT | _HEX,
  167. _DIGIT | _HEX,
  168. _DIGIT | _HEX,
  169. _DIGIT | _HEX,
  170. _DIGIT | _HEX,
  171. _DIGIT | _HEX,
  172. _DIGIT | _HEX,
  173. _DIGIT | _HEX,
  174. _DIGIT | _HEX,
  175. _PUNCT,
  176. _PUNCT,
  177. _PUNCT,
  178. _PUNCT,
  179. _PUNCT,
  180. _PUNCT,
  181. _PUNCT,
  182. _UPPER | _HEX | C1_ALPHA,
  183. _UPPER | _HEX | C1_ALPHA,
  184. _UPPER | _HEX | C1_ALPHA,
  185. _UPPER | _HEX | C1_ALPHA,
  186. _UPPER | _HEX | C1_ALPHA,
  187. _UPPER | _HEX | C1_ALPHA,
  188. _UPPER | C1_ALPHA,
  189. _UPPER | C1_ALPHA,
  190. _UPPER | C1_ALPHA,
  191. _UPPER | C1_ALPHA,
  192. _UPPER | C1_ALPHA,
  193. _UPPER | C1_ALPHA,
  194. _UPPER | C1_ALPHA,
  195. _UPPER | C1_ALPHA,
  196. _UPPER | C1_ALPHA,
  197. _UPPER | C1_ALPHA,
  198. _UPPER | C1_ALPHA,
  199. _UPPER | C1_ALPHA,
  200. _UPPER | C1_ALPHA,
  201. _UPPER | C1_ALPHA,
  202. _UPPER | C1_ALPHA,
  203. _UPPER | C1_ALPHA,
  204. _UPPER | C1_ALPHA,
  205. _UPPER | C1_ALPHA,
  206. _UPPER | C1_ALPHA,
  207. _UPPER | C1_ALPHA,
  208. _PUNCT,
  209. _PUNCT,
  210. _PUNCT,
  211. _PUNCT,
  212. _PUNCT,
  213. _PUNCT,
  214. _LOWER | _HEX | C1_ALPHA,
  215. _LOWER | _HEX | C1_ALPHA,
  216. _LOWER | _HEX | C1_ALPHA,
  217. _LOWER | _HEX | C1_ALPHA,
  218. _LOWER | _HEX | C1_ALPHA,
  219. _LOWER | _HEX | C1_ALPHA,
  220. _LOWER | C1_ALPHA,
  221. _LOWER | C1_ALPHA,
  222. _LOWER | C1_ALPHA,
  223. _LOWER | C1_ALPHA,
  224. _LOWER | C1_ALPHA,
  225. _LOWER | C1_ALPHA,
  226. _LOWER | C1_ALPHA,
  227. _LOWER | C1_ALPHA,
  228. _LOWER | C1_ALPHA,
  229. _LOWER | C1_ALPHA,
  230. _LOWER | C1_ALPHA,
  231. _LOWER | C1_ALPHA,
  232. _LOWER | C1_ALPHA,
  233. _LOWER | C1_ALPHA,
  234. _LOWER | C1_ALPHA,
  235. _LOWER | C1_ALPHA,
  236. _LOWER | C1_ALPHA,
  237. _LOWER | C1_ALPHA,
  238. _LOWER | C1_ALPHA,
  239. _LOWER | C1_ALPHA,
  240. _PUNCT,
  241. _PUNCT,
  242. _PUNCT,
  243. _PUNCT,
  244. _CONTROL
  245. };
  246. static const char _first_127char[] = {
  247. 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
  248. 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
  249. 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
  250. 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
  251. 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
  252. 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100,101,102,
  253. 103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,
  254. 120,121,122,123,124,125,126,127
  255. };
  256. #ifdef _MT
  257. extern unsigned short *__ctype1; /* defined in initctyp.c */
  258. extern struct __lc_time_data __lc_time_c; /* defined in strftime.c */
  259. extern struct __lc_time_data *__lc_time_curr; /* defined in strftime.c */
  260. extern struct __lc_time_data *__lc_time_intl; /* defined in inittime.c */
  261. /*
  262. * initial locale information struct, set to the C locale. Used only until the
  263. * first call to setlocale()
  264. */
  265. threadlocinfo __initiallocinfo = {
  266. 1, /* refcount */
  267. _CLOCALECP, /* lc_codepage */
  268. _CLOCALECP, /* lc_collate_cp */
  269. { _CLOCALEHANDLE, /* lc_handle[6] */
  270. _CLOCALEHANDLE,
  271. _CLOCALEHANDLE,
  272. _CLOCALEHANDLE,
  273. _CLOCALEHANDLE,
  274. _CLOCALEHANDLE },
  275. 1, /* lc_clike */
  276. 1, /* mb_cur_max */
  277. NULL, /* lconv_intl_refcount */
  278. NULL, /* lconv_num_refcount */
  279. NULL, /* lconv_mon_refcount */
  280. &__lconv_c, /* lconv */
  281. NULL, /* lconv_intl */
  282. NULL, /* ctype1_refcount */
  283. NULL, /* ctype1 */
  284. _ctype + 1, /* pctype */
  285. &__lc_time_c, /* lc_time_curr */
  286. NULL /* lc_time_intl */
  287. };
  288. /*
  289. * global pointer to the current per-thread locale information structure.
  290. */
  291. pthreadlocinfo __ptlocinfo = &__initiallocinfo;
  292. /*
  293. * Flag indicating whether or not setlocale() is active. Its value is the
  294. * number of setlocale() calls currently active.
  295. */
  296. _CRTIMP int __setlc_active;
  297. /* These functions are for enabling STATIC_CPPLIB functionality */
  298. _CRTIMP int __cdecl ___setlc_active_func(void)
  299. {
  300. return __setlc_active;
  301. }
  302. /*
  303. * Flag indicating whether or not a function which references the locale
  304. * without having locked it is active. Its value is the number of such
  305. * functions.
  306. */
  307. _CRTIMP int __unguarded_readlc_active;
  308. /* These functions are for enabling STATIC_CPPLIB functionality */
  309. _CRTIMP int * __cdecl ___unguarded_readlc_active_add_func(void)
  310. {
  311. return &__unguarded_readlc_active;
  312. }
  313. #endif /* _MT */
  314. /* helper function prototypes */
  315. char * _expandlocale(char *, char *, LC_ID *, UINT *, int);
  316. void _strcats(char *, int, ...);
  317. void __lc_lctostr(char *, const LC_STRINGS *);
  318. int __lc_strtolc(LC_STRINGS *, const char *);
  319. static char * __cdecl _setlocale_set_cat(int, const char *);
  320. static char * __cdecl _setlocale_get_all(void);
  321. #ifdef _MT
  322. extern int * __lconv_intl_refcount;
  323. extern int * __lconv_num_refcount;
  324. extern int * __lconv_mon_refcount;
  325. extern int * __ctype1_refcount;
  326. static pthreadlocinfo __cdecl __updatetlocinfo_lk(void);
  327. static char * __cdecl _setlocale_lk(int, const char *);
  328. void __cdecl __free_lconv_mon(struct lconv *);
  329. void __cdecl __free_lconv_num(struct lconv *);
  330. void __cdecl __free_lc_time(struct __lc_time_data *);
  331. #endif
  332. #endif /* _WIN32/_POSIX_ */
  333. #ifdef _MT
  334. /***
  335. *__freetlocinfo() - free threadlocinfo
  336. *
  337. *Purpose:
  338. * Free up the per-thread locale info structure specified by the passed
  339. * pointer.
  340. *
  341. *Entry:
  342. * pthreadlocinfo ptloci
  343. *
  344. *Exit:
  345. *
  346. *Exceptions:
  347. *
  348. *******************************************************************************/
  349. void __cdecl __freetlocinfo (
  350. pthreadlocinfo ptloci
  351. )
  352. {
  353. /*
  354. * Free up lconv struct
  355. */
  356. if ( (ptloci->lconv_intl != __lconv_intl) &&
  357. (ptloci->lconv_intl != NULL) &&
  358. (*(ptloci->lconv_intl_refcount) == 0))
  359. {
  360. if ( (ptloci->lconv_mon_refcount != NULL) &&
  361. (*(ptloci->lconv_mon_refcount) == 0) &&
  362. (ptloci->lconv_mon_refcount != __lconv_mon_refcount) )
  363. {
  364. _free_crt(ptloci->lconv_mon_refcount);
  365. __free_lconv_mon(ptloci->lconv_intl);
  366. }
  367. if ( (ptloci->lconv_num_refcount != NULL) &&
  368. (*(ptloci->lconv_num_refcount) == 0) &&
  369. (ptloci->lconv_num_refcount != __lconv_num_refcount) )
  370. {
  371. _free_crt(ptloci->lconv_num_refcount);
  372. __free_lconv_num(ptloci->lconv_intl);
  373. }
  374. _free_crt(ptloci->lconv_intl_refcount);
  375. _free_crt(ptloci->lconv_intl);
  376. }
  377. /*
  378. * Free up ctype tables
  379. */
  380. if ( (ptloci->ctype1_refcount != __ctype1_refcount) &&
  381. (ptloci->ctype1_refcount != NULL) &&
  382. (*(ptloci->ctype1_refcount) == 0) )
  383. {
  384. _free_crt(ptloci->ctype1_refcount);
  385. _free_crt(ptloci->ctype1);
  386. }
  387. /*
  388. * Free up the __lc_time_data struct
  389. */
  390. if ( (ptloci->lc_time_intl != __lc_time_intl) &&
  391. (ptloci->lc_time_intl != NULL) &&
  392. ((ptloci->lc_time_intl->refcount) == 0) )
  393. {
  394. __free_lc_time(ptloci->lc_time_intl);
  395. _free_crt(ptloci->lc_time_intl);
  396. }
  397. /*
  398. * Free up the threadlocinfo struct
  399. */
  400. _free_crt(ptloci);
  401. }
  402. /***
  403. *__updatetlocinfo() - refresh the thread's locale info
  404. *
  405. *Purpose:
  406. * Update the current thread's reference to the locale information to
  407. * match the current global locale info. Decrement the reference on the
  408. * old locale information struct and if this count is now zero (so that no
  409. * threads are using it), free it.
  410. *
  411. *Entry:
  412. *
  413. *Exit:
  414. * _getptd()->ptlocinfo == __ptlocinfo
  415. *
  416. *Exceptions:
  417. *
  418. *******************************************************************************/
  419. pthreadlocinfo __cdecl __updatetlocinfo(void)
  420. {
  421. pthreadlocinfo ptloci;
  422. _mlock(_SETLOCALE_LOCK);
  423. __try
  424. {
  425. ptloci = __updatetlocinfo_lk();
  426. }
  427. __finally
  428. {
  429. _munlock(_SETLOCALE_LOCK);
  430. }
  431. return ptloci;
  432. }
  433. static pthreadlocinfo __cdecl __updatetlocinfo_lk(void)
  434. {
  435. pthreadlocinfo ptloci;
  436. _ptiddata ptd = _getptd();
  437. if ( (ptloci = ptd->ptlocinfo) != __ptlocinfo )
  438. {
  439. /*
  440. * Decrement the reference counts in the old locale info
  441. * structure.
  442. */
  443. if ( ptloci != NULL )
  444. {
  445. (ptloci->refcount)--;
  446. if ( ptloci->lconv_intl_refcount != NULL )
  447. (*(ptloci->lconv_intl_refcount))--;
  448. if ( ptloci->lconv_mon_refcount != NULL )
  449. (*(ptloci->lconv_mon_refcount))--;
  450. if ( ptloci->lconv_num_refcount != NULL )
  451. (*(ptloci->lconv_num_refcount))--;
  452. if ( ptloci->ctype1_refcount != NULL )
  453. (*(ptloci->ctype1_refcount))--;
  454. (ptloci->lc_time_curr->refcount)--;
  455. }
  456. /*
  457. * Update to the current locale info structure and increment the
  458. * reference counts.
  459. */
  460. ptd->ptlocinfo = __ptlocinfo;
  461. (__ptlocinfo->refcount)++;
  462. if ( __ptlocinfo->lconv_intl_refcount != NULL )
  463. (*(__ptlocinfo->lconv_intl_refcount))++;
  464. if ( __ptlocinfo->lconv_mon_refcount != NULL )
  465. (*(__ptlocinfo->lconv_mon_refcount))++;
  466. if ( __ptlocinfo->lconv_num_refcount != NULL )
  467. (*(__ptlocinfo->lconv_num_refcount))++;
  468. if ( __ptlocinfo->ctype1_refcount != NULL )
  469. (*(__ptlocinfo->ctype1_refcount))++;
  470. (__ptlocinfo->lc_time_curr->refcount)++;
  471. /*
  472. * Free the old locale info structure, if necessary. Must be done
  473. * after incrementing reference counts in current locale in case
  474. * any refcounts are shared with the old locale.
  475. */
  476. if ( (ptloci != NULL) &&
  477. (ptloci->refcount == 0) &&
  478. (ptloci != &__initiallocinfo) )
  479. __freetlocinfo(ptloci);
  480. }
  481. return ptd->ptlocinfo;
  482. }
  483. #endif
  484. /***
  485. *char * setlocale(int category, char *locale) - Set one or all locale categories
  486. *
  487. *Purpose:
  488. * The setlocale() routine allows the user to set one or more of
  489. * the locale categories to the specific locale selected by the
  490. * user. [ANSI]
  491. *
  492. * NOTE: Under !_INTL, the C libraries only support the "C" locale.
  493. * Attempts to change the locale will fail.
  494. *
  495. *Entry:
  496. * int category = One of the locale categories defined in locale.h
  497. * char *locale = String identifying a specific locale or NULL to
  498. * query the current locale.
  499. *
  500. *Exit:
  501. * If supplied locale pointer == NULL:
  502. *
  503. * Return pointer to current locale string and do NOT change
  504. * the current locale.
  505. *
  506. * If supplied locale pointer != NULL:
  507. *
  508. * If locale string is '\0', set locale to default.
  509. *
  510. * If desired setting can be honored, return a pointer to the
  511. * locale string for the appropriate category.
  512. *
  513. * If desired setting can NOT be honored, return NULL.
  514. *
  515. *Exceptions:
  516. * Compound locale strings of the form "LC_COLLATE=xxx;LC_CTYPE=xxx;..."
  517. * are allowed for the LC_ALL category. This is to support the ability
  518. * to restore locales with the returned string, as specified by ANSI.
  519. * Setting the locale with a compound locale string will succeed unless
  520. * *all* categories failed. The returned string will reflect the current
  521. * locale. For example, if LC_CTYPE fails in the above string, setlocale
  522. * will return "LC_COLLATE=xxx;LC_CTYPE=yyy;..." where yyy is the
  523. * previous locale (or the C locale if restoring the previous locale
  524. * also failed). Unrecognized LC_* categories are ignored.
  525. *
  526. *******************************************************************************/
  527. #if !defined(_WIN32) && !defined(_POSIX_) /* trivial ANSI support */
  528. char * __cdecl setlocale (
  529. int _category,
  530. const char *_locale
  531. )
  532. {
  533. if ( (_locale == NULL) ||
  534. (_locale[0] == '\0') ||
  535. ( (_locale[0]=='C') && (_locale[1]=='\0')) )
  536. return(_clocalestr);
  537. else
  538. return(NULL);
  539. }
  540. #else /* _WIN32/_POSIX_ */
  541. char * __cdecl setlocale (
  542. int _category,
  543. const char *_locale
  544. )
  545. {
  546. char * retval;
  547. #ifdef _MT
  548. pthreadlocinfo ptloci;
  549. int i;
  550. /* Validate category */
  551. if ( (_category < LC_MIN) || (_category > LC_MAX) )
  552. return NULL;
  553. if ( _locale == NULL )
  554. return _setlocale_lk(_category, NULL);
  555. _mlock(_SETLOCALE_LOCK);
  556. __try {
  557. if ( (ptloci = _malloc_crt( sizeof(threadlocinfo) )) == NULL )
  558. retval = NULL;
  559. if ( (ptloci != NULL) && (retval = _setlocale_lk(_category, _locale)) )
  560. {
  561. ptloci->refcount = 0;
  562. ptloci->lc_codepage = __lc_codepage;
  563. ptloci->lc_collate_cp = __lc_collate_cp;
  564. for ( i = 0 ; i <= LC_MAX - LC_MIN ; i++ )
  565. ptloci->lc_handle[i] = __lc_handle[i];
  566. ptloci->lc_clike = __lc_clike;
  567. ptloci->mb_cur_max = __mb_cur_max;
  568. ptloci->lconv_intl_refcount = __lconv_intl_refcount;
  569. ptloci->lconv_num_refcount = __lconv_num_refcount;
  570. ptloci->lconv_mon_refcount = __lconv_mon_refcount;
  571. ptloci->lconv = __lconv;
  572. ptloci->lconv_intl = __lconv_intl;
  573. ptloci->ctype1_refcount = __ctype1_refcount;
  574. ptloci->ctype1 = __ctype1;
  575. ptloci->pctype = _pctype;
  576. ptloci->lc_time_curr = __lc_time_curr;
  577. ptloci->lc_time_intl = __lc_time_intl;
  578. if ( (__ptlocinfo->refcount == 0) &&
  579. (__ptlocinfo != &__initiallocinfo) )
  580. __freetlocinfo(__ptlocinfo);
  581. __ptlocinfo = ptloci;
  582. (void)__updatetlocinfo_lk();
  583. }
  584. if ( (retval == NULL) && (ptloci != NULL) )
  585. _free_crt(ptloci);
  586. }
  587. __finally {
  588. _munlock(_SETLOCALE_LOCK);
  589. }
  590. return retval;
  591. }
  592. static char * __cdecl _setlocale_lk(
  593. int _category,
  594. const char *_locale
  595. )
  596. {
  597. char * retval;
  598. #else
  599. /* Validate category */
  600. if ((_category < LC_MIN) || (_category > LC_MAX))
  601. return NULL;
  602. #endif
  603. /* Interpret locale */
  604. if (_category != LC_ALL)
  605. {
  606. retval = (_locale) ? _setlocale_set_cat(_category,_locale) :
  607. __lc_category[_category].locale;
  608. } else { /* LC_ALL */
  609. char lctemp[MAX_LC_LEN];
  610. int i;
  611. int same = 1;
  612. int fLocaleSet = 0; /* flag to indicate if anything successfully set */
  613. if (_locale != NULL)
  614. {
  615. if ( (_locale[0]=='L') && (_locale[1]=='C') && (_locale[2]=='_') )
  616. {
  617. /* parse compound locale string */
  618. size_t len;
  619. const char * p = _locale; /* start of string to parse */
  620. const char * s;
  621. do {
  622. s = strpbrk(p,"=;");
  623. if ((s==(char *)NULL) || (!(len=(size_t)(s-p))) || (*s==';'))
  624. return NULL; /* syntax error */
  625. /* match with known LC_ strings, if possible, else ignore */
  626. for (i=LC_ALL+1; i<=LC_MAX; i++)
  627. {
  628. if ((!strncmp(__lc_category[i].catname,p,len))
  629. && (len==strlen(__lc_category[i].catname)))
  630. {
  631. break; /* matched i */
  632. }
  633. } /* no match if (i>LC_MAX) -- just ignore */
  634. if ((!(len = strcspn(++s,";"))) && (*s!=';'))
  635. return NULL; /* syntax error */
  636. if (i<=LC_MAX)
  637. {
  638. strncpy(lctemp, s, len);
  639. lctemp[len]='\0'; /* null terminate string */
  640. /* don't fail unless all categories fail */
  641. if (_setlocale_set_cat(i,lctemp))
  642. fLocaleSet++; /* record a success */
  643. }
  644. if (*(p = s+len)!='\0')
  645. p++; /* skip ';', if present */
  646. } while (*p);
  647. retval = (fLocaleSet) ? _setlocale_get_all() : NULL;
  648. } else { /* simple LC_ALL locale string */
  649. /* confirm locale is supported, get expanded locale */
  650. if (retval = _expandlocale((char *)_locale, lctemp, NULL, NULL, _category))
  651. {
  652. for (i=LC_MIN; i<=LC_MAX; i++)
  653. {
  654. if (i!=LC_ALL)
  655. {
  656. if (strcmp(lctemp, __lc_category[i].locale))
  657. {
  658. if (_setlocale_set_cat(i, lctemp))
  659. {
  660. fLocaleSet++; /* record a success */
  661. }
  662. else
  663. {
  664. same = 0; /* record a failure */
  665. }
  666. }
  667. else
  668. fLocaleSet++; /* trivial succcess */
  669. }
  670. }
  671. #ifdef _POSIX_
  672. /* special case for POSIX - since LC_ALL expands,
  673. one LC_ALL call may set many different categories,
  674. must assume not same, get full string */
  675. same = 0;
  676. #endif
  677. if (same) /* needn't call setlocale_get_all() if all the same */
  678. {
  679. retval = _setlocale_get_all();
  680. /* retval set above */
  681. _free_crt(__lc_category[LC_ALL].locale);
  682. __lc_category[LC_ALL].locale = NULL;
  683. }
  684. else
  685. retval = (fLocaleSet) ? _setlocale_get_all() : NULL;
  686. }
  687. }
  688. } else { /* LC_ALL & NULL */
  689. retval = _setlocale_get_all ();
  690. }
  691. }
  692. /* common exit point */
  693. return retval;
  694. } /* setlocale */
  695. static char * __cdecl _setlocale_set_cat (
  696. int category,
  697. const char * locale
  698. )
  699. {
  700. char * oldlocale;
  701. LCID oldhandle;
  702. UINT oldcodepage;
  703. LC_ID oldid;
  704. LC_ID idtemp;
  705. UINT cptemp;
  706. char lctemp[MAX_LC_LEN];
  707. char * pch;
  708. static struct _is_ctype_compatible _Lcid_c[_LOC_CCACHE] = {{0,1}};
  709. struct _is_ctype_compatible buf1, buf2;
  710. int i;
  711. short out[sizeof(_first_127char)];
  712. if (!_expandlocale((char *)locale, lctemp, &idtemp, &cptemp, category))
  713. {
  714. return NULL; /* unrecognized locale */
  715. }
  716. if (!strcmp(lctemp, __lc_category[category].locale))
  717. {
  718. return __lc_category[category].locale;
  719. }
  720. if (!(pch = (char *)_malloc_crt(strlen(lctemp)+1)))
  721. {
  722. return NULL; /* error if malloc fails */
  723. }
  724. oldlocale = __lc_category[category].locale; /* save for possible restore*/
  725. oldhandle = __lc_handle[category];
  726. memcpy((void *)&oldid, (void *)&__lc_id[category], sizeof(oldid));
  727. oldcodepage = __lc_codepage;
  728. /* update locale string */
  729. __lc_category[category].locale = strcpy(pch,lctemp);
  730. __lc_handle[category] = MAKELCID(idtemp.wLanguage, SORT_DEFAULT);
  731. memcpy((void *)&__lc_id[category], (void *)&idtemp, sizeof(idtemp));
  732. /* To speedup locale based comparisions, we identify if the current
  733. * local has first 127 character set same as CLOCALE. If yes then
  734. * __lc_clike = TRUE. Also we keep this info. in a cache of cache
  735. * size = _LOC_CCACHE, so that every time the locale is switched, we
  736. * don't have to call time consuming GetStringTypeA.
  737. */
  738. if (category==LC_CTYPE)
  739. {
  740. __lc_codepage = cptemp;
  741. buf1 = _Lcid_c[_LOC_CCACHE -1];
  742. /* brings the recently used codepage to the top. or else shifts
  743. * every thing down by one so that new _Lcid_c can be placed at
  744. * the top.
  745. */
  746. for ( i = 0; i < _LOC_CCACHE; i++)
  747. {
  748. if (__lc_codepage == _Lcid_c[i].id)
  749. {
  750. _Lcid_c[0] = _Lcid_c[i];
  751. _Lcid_c[i] = buf1;
  752. break;
  753. }
  754. else
  755. {
  756. buf2 = _Lcid_c[i];
  757. _Lcid_c[i] = buf1;
  758. buf1 = buf2;
  759. }
  760. }
  761. if ( i == _LOC_CCACHE)
  762. {
  763. if ( __crtGetStringTypeA(CT_CTYPE1,
  764. _first_127char,
  765. sizeof(_first_127char),
  766. out,
  767. __lc_codepage,
  768. __lc_handle[LC_CTYPE],
  769. TRUE ))
  770. {
  771. if ( !memcmp(out, _ctype_loc_style, sizeof(_ctype_loc_style)))
  772. _Lcid_c[0].is_clike = TRUE;
  773. else
  774. _Lcid_c[0].is_clike = FALSE;
  775. }
  776. else
  777. _Lcid_c[0].is_clike = FALSE;
  778. _Lcid_c[0].id = __lc_codepage;
  779. }
  780. __lc_clike = _Lcid_c[0].is_clike;
  781. }
  782. if ( category == LC_COLLATE )
  783. __lc_collate_cp = cptemp;
  784. if (__lc_category[category].init())
  785. {
  786. /* restore previous state! */
  787. __lc_category[category].locale = oldlocale;
  788. _free_crt(pch);
  789. __lc_handle[category] = oldhandle;
  790. __lc_codepage = oldcodepage;
  791. return NULL; /* error if non-zero return */
  792. }
  793. /* locale set up successfully */
  794. /* Cleanup */
  795. if ((oldlocale != _clocalestr)
  796. #ifdef _POSIX_
  797. && (oldlocale!=_posixlocalestr)
  798. #endif
  799. )
  800. _free_crt(oldlocale);
  801. return __lc_category[category].locale;
  802. } /* _setlocale_set_cat */
  803. static char * __cdecl _setlocale_get_all (
  804. void
  805. )
  806. {
  807. int i;
  808. int same = 1;
  809. /* allocate memory if necessary */
  810. if ( (__lc_category[LC_ALL].locale == NULL) &&
  811. ((__lc_category[LC_ALL].locale =
  812. _malloc_crt((MAX_LC_LEN+1) * (LC_MAX-LC_MIN+1) + CATNAMES_LEN))
  813. == NULL) )
  814. return NULL;
  815. __lc_category[LC_ALL].locale[0] = '\0';
  816. for (i=LC_MIN+1; ; i++)
  817. {
  818. _strcats(__lc_category[LC_ALL].locale, 3, __lc_category[i].catname,"=",__lc_category[i].locale);
  819. if (i<LC_MAX)
  820. {
  821. strcat(__lc_category[LC_ALL].locale,";");
  822. if (strcmp(__lc_category[i].locale, __lc_category[i+1].locale))
  823. same=0;
  824. }
  825. else
  826. {
  827. if (!same)
  828. return __lc_category[LC_ALL].locale;
  829. else
  830. {
  831. _free_crt(__lc_category[LC_ALL].locale);
  832. __lc_category[LC_ALL].locale = (char *)NULL;
  833. return __lc_category[LC_CTYPE].locale;
  834. }
  835. }
  836. }
  837. } /* _setlocale_get_all */
  838. char * _expandlocale (
  839. char *expr,
  840. char * output,
  841. LC_ID * id,
  842. UINT * cp,
  843. int category
  844. )
  845. {
  846. static LC_ID cacheid = {0, 0, 0};
  847. static UINT cachecp = 0;
  848. static char cachein[MAX_LC_LEN] = "C";
  849. static char cacheout[MAX_LC_LEN] = "C";
  850. if (!expr)
  851. return NULL; /* error if no input */
  852. #ifdef _POSIX_
  853. if (!*expr)
  854. {
  855. /* POSIX: when locale=="", look first at the environment variables:
  856. 1) use LC_ALL EV if defined and not null (LC_ALL expands to LC_*)
  857. 2) use EV that matches category and is not null
  858. 3) use LANG EV if defined and not null
  859. otherwise, we fall through to get system default */
  860. char *envar;
  861. if (category == LC_ALL && (envar = getenv("LC_ALL")))
  862. {
  863. if (!*envar)
  864. {
  865. /* LC_ALL expands to LC_*, set output to "", each category will be
  866. expanded individually */
  867. *output = '\0';
  868. return output;
  869. }
  870. else {
  871. expr = envar;
  872. }
  873. }
  874. else {
  875. if ((envar = getenv(__lc_category[category].catname)) && *envar ||
  876. (envar = getenv("LANG")) && *envar)
  877. {
  878. expr = envar;
  879. }
  880. }
  881. }
  882. #endif /* _POSIX_ */
  883. if (((*expr=='C') && (!expr[1]))
  884. #ifdef _POSIX_
  885. || (!strcmp(expr, _posixlocalestr))
  886. #endif
  887. ) /* for "C" locale, just return */
  888. {
  889. #ifdef _POSIX_
  890. strcpy(output, _posixlocalestr);
  891. #else
  892. *output = 'C';
  893. output[1] = '\0';
  894. #endif
  895. if (id)
  896. {
  897. id->wLanguage = 0;
  898. id->wCountry = 0;
  899. id->wCodePage = 0;
  900. }
  901. if (cp)
  902. {
  903. *cp = CP_ACP; /* return to ANSI code page */
  904. }
  905. return output; /* "C" */
  906. }
  907. /* first, make sure we didn't just do this one */
  908. if (strcmp(cacheout,expr) && strcmp(cachein,expr))
  909. {
  910. /* do some real work */
  911. LC_STRINGS names;
  912. if (__lc_strtolc((LC_STRINGS *)&names, (const char *)expr))
  913. return NULL; /* syntax error */
  914. if (!__get_qualified_locale((LPLC_STRINGS)&names,
  915. (LPLC_ID)&cacheid, (LPLC_STRINGS)&names))
  916. return NULL; /* locale not recognized/supported */
  917. /* begin: cache atomic section */
  918. cachecp = cacheid.wCodePage;
  919. __lc_lctostr((char *)cacheout, &names);
  920. /* Don't cache "" empty string */
  921. if (*expr)
  922. strcpy(cachein, expr);
  923. else
  924. strcpy(cachein, cacheout);
  925. /* end: cache atomic section */
  926. }
  927. if (id)
  928. memcpy((void *)id, (void *)&cacheid, sizeof(cacheid)); /* possibly return LC_ID */
  929. if (cp)
  930. memcpy((void *)cp, (void *)&cachecp, sizeof(cachecp)); /* possibly return cp */
  931. strcpy(output,cacheout);
  932. return cacheout; /* return fully expanded locale string */
  933. }
  934. /* helpers */
  935. int __cdecl __init_dummy(void) /* default routine for locale initializer */
  936. {
  937. return 0;
  938. }
  939. void _strcats
  940. (
  941. char *outstr,
  942. int n,
  943. ...
  944. )
  945. {
  946. int i;
  947. va_list substr;
  948. va_start (substr, n);
  949. for (i =0; i<n; i++)
  950. {
  951. strcat(outstr, va_arg(substr, char *));
  952. }
  953. va_end(substr);
  954. }
  955. int __lc_strtolc
  956. (
  957. LC_STRINGS *names,
  958. const char *locale
  959. )
  960. {
  961. int i;
  962. size_t len;
  963. char ch;
  964. memset((void *)names, '\0', sizeof(LC_STRINGS)); /* clear out result */
  965. if (*locale=='\0')
  966. return 0; /* trivial case */
  967. /* only code page is given */
  968. if (locale[0] == '.' && locale[1] != '\0')
  969. {
  970. strcpy((char *)names->szCodePage, &locale[1]);
  971. return 0;
  972. }
  973. for (i=0; ; i++)
  974. {
  975. if (!(len=strcspn(locale,"_.,")))
  976. return -1; /* syntax error */
  977. ch = locale[len];
  978. if ((i==0) && (len<MAX_LANG_LEN) && (ch!='.'))
  979. strncpy((char *)names->szLanguage, locale, len);
  980. else if ((i==1) && (len<MAX_CTRY_LEN) && (ch!='_'))
  981. strncpy((char *)names->szCountry, locale, len);
  982. else if ((i==2) && (len<MAX_CP_LEN) && (ch=='\0' || ch==','))
  983. strncpy((char *)names->szCodePage, locale, len);
  984. else
  985. return -1; /* error parsing locale string */
  986. if (ch==',')
  987. {
  988. /* modifier not used in current implementation, but it
  989. must be parsed to for POSIX/XOpen conformance */
  990. /* strncpy(names->szModifier, locale, MAX_MODIFIER_LEN-1); */
  991. break;
  992. }
  993. if (!ch)
  994. break;
  995. locale+=(len+1);
  996. }
  997. return 0;
  998. }
  999. void __lc_lctostr
  1000. (
  1001. char *locale,
  1002. const LC_STRINGS *names
  1003. )
  1004. {
  1005. strcpy(locale, (char *)names->szLanguage);
  1006. if (*(names->szCountry))
  1007. _strcats(locale, 2, "_", names->szCountry);
  1008. if (*(names->szCodePage))
  1009. _strcats(locale, 2, ".", names->szCodePage);
  1010. /* if (names->szModifier)
  1011. _strcats(locale, 2, ",", names->szModifier); */
  1012. }
  1013. #endif /* _WIN32/_POSIX_ */