Leaked source code of windows server 2003
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.

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