i18n.c 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740
  1. /* Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
  2. *
  3. * This library is free software; you can redistribute it and/or
  4. * modify it under the terms of the GNU Lesser General Public License
  5. * as published by the Free Software Foundation; either version 3 of
  6. * the License, or (at your option) any later version.
  7. *
  8. * This library is distributed in the hope that it will be useful, but
  9. * WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. * Lesser General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Lesser General Public
  14. * License along with this library; if not, write to the Free Software
  15. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  16. * 02110-1301 USA
  17. */
  18. #ifdef HAVE_CONFIG_H
  19. # include <config.h>
  20. #endif
  21. #include <alloca.h>
  22. #include "libguile/_scm.h"
  23. #include "libguile/feature.h"
  24. #include "libguile/i18n.h"
  25. #include "libguile/strings.h"
  26. #include "libguile/chars.h"
  27. #include "libguile/dynwind.h"
  28. #include "libguile/validate.h"
  29. #include "libguile/values.h"
  30. #include "libguile/threads.h"
  31. #include <locale.h>
  32. #include <string.h> /* `strcoll ()' */
  33. #include <ctype.h> /* `toupper ()' et al. */
  34. #include <errno.h>
  35. #if (defined HAVE_NEWLOCALE) && (defined HAVE_STRCOLL_L)
  36. /* The GNU thread-aware locale API is documented in ``Thread-Aware Locale
  37. Model, a Proposal'', by Ulrich Drepper:
  38. http://people.redhat.com/drepper/tllocale.ps.gz
  39. It is now also implemented by Darwin:
  40. http://developer.apple.com/documentation/Darwin/Reference/ManPages/man3/newlocale.3.html
  41. The whole API was eventually standardized in the ``Open Group Base
  42. Specifications Issue 7'' (aka. "POSIX 2008"):
  43. http://www.opengroup.org/onlinepubs/9699919799/basedefs/locale.h.html */
  44. # define USE_GNU_LOCALE_API
  45. #endif
  46. #if (defined USE_GNU_LOCALE_API) && (defined HAVE_XLOCALE_H)
  47. # include <xlocale.h>
  48. #endif
  49. #include "libguile/posix.h" /* for `scm_i_locale_mutex' */
  50. #if (defined HAVE_LANGINFO_H) && (defined HAVE_NL_TYPES_H)
  51. # include <langinfo.h>
  52. # include <nl_types.h>
  53. #endif
  54. #ifndef HAVE_SETLOCALE
  55. static inline char *
  56. setlocale (int category, const char *name)
  57. {
  58. errno = ENOSYS;
  59. return NULL;
  60. }
  61. #endif
  62. /* Helper stringification macro. */
  63. #define SCM_I18N_STRINGIFY(_name) # _name
  64. /* Locale objects, string and character collation, and other locale-dependent
  65. string operations.
  66. A large part of the code here deals with emulating glibc's reentrant
  67. locale API on non-GNU systems. The emulation is a bit "brute-force":
  68. Whenever a `-locale<?' procedure is passed a locale object, then:
  69. 1. The `scm_i_locale_mutex' is locked.
  70. 2. A series of `setlocale ()' call is performed to store the current
  71. locale for each category in an `scm_t_locale' object.
  72. 3. A series of `setlocale ()' call is made to install each of the locale
  73. categories of each of the base locales of each locale object,
  74. recursively, starting from the last locale object of the chain.
  75. 4. The settings captured in step (2) are restored.
  76. 5. The `scm_i_locale_mutex' is released.
  77. Hopefully, the X/Open standard will eventually make this hack useless.
  78. Note: We don't wrap glibc's `uselocale ()' call because it sets the locale
  79. of the current _thread_ (unlike `setlocale ()') and doing so would require
  80. maintaining per-thread locale information on non-GNU systems and always
  81. re-installing this locale upon locale-dependent calls. */
  82. /* Return the category mask corresponding to CAT. */
  83. #define SCM_LOCALE_CATEGORY_MASK(_cat) LC_ ## _cat ## _MASK
  84. #ifndef USE_GNU_LOCALE_API
  85. /* Provide the locale category masks as found in glibc. This must be kept in
  86. sync with `locale-categories.h'. */
  87. # define LC_CTYPE_MASK 1
  88. # define LC_COLLATE_MASK 2
  89. # define LC_MESSAGES_MASK 4
  90. # define LC_MONETARY_MASK 8
  91. # define LC_NUMERIC_MASK 16
  92. # define LC_TIME_MASK 32
  93. # ifdef LC_PAPER
  94. # define LC_PAPER_MASK 64
  95. # else
  96. # define LC_PAPER_MASK 0
  97. # endif
  98. # ifdef LC_NAME
  99. # define LC_NAME_MASK 128
  100. # else
  101. # define LC_NAME_MASK 0
  102. # endif
  103. # ifdef LC_ADDRESS
  104. # define LC_ADDRESS_MASK 256
  105. # else
  106. # define LC_ADDRESS_MASK 0
  107. # endif
  108. # ifdef LC_TELEPHONE
  109. # define LC_TELEPHONE_MASK 512
  110. # else
  111. # define LC_TELEPHONE_MASK 0
  112. # endif
  113. # ifdef LC_MEASUREMENT
  114. # define LC_MEASUREMENT_MASK 1024
  115. # else
  116. # define LC_MEASUREMENT_MASK 0
  117. # endif
  118. # ifdef LC_IDENTIFICATION
  119. # define LC_IDENTIFICATION_MASK 2048
  120. # else
  121. # define LC_IDENTIFICATION_MASK 0
  122. # endif
  123. # define LC_ALL_MASK (LC_CTYPE_MASK \
  124. | LC_NUMERIC_MASK \
  125. | LC_TIME_MASK \
  126. | LC_COLLATE_MASK \
  127. | LC_MONETARY_MASK \
  128. | LC_MESSAGES_MASK \
  129. | LC_PAPER_MASK \
  130. | LC_NAME_MASK \
  131. | LC_ADDRESS_MASK \
  132. | LC_TELEPHONE_MASK \
  133. | LC_MEASUREMENT_MASK \
  134. | LC_IDENTIFICATION_MASK \
  135. )
  136. /* Locale objects as returned by `make-locale' on non-GNU systems. */
  137. typedef struct scm_locale
  138. {
  139. SCM base_locale; /* a `locale' object */
  140. char *locale_name;
  141. int category_mask;
  142. } *scm_t_locale;
  143. /* Free the resources used by LOCALE. */
  144. static inline void
  145. scm_i_locale_free (scm_t_locale locale)
  146. {
  147. free (locale->locale_name);
  148. locale->locale_name = NULL;
  149. }
  150. #else /* USE_GNU_LOCALE_API */
  151. /* Alias for glibc's locale type. */
  152. typedef locale_t scm_t_locale;
  153. #define scm_i_locale_free freelocale
  154. #endif /* USE_GNU_LOCALE_API */
  155. /* A locale object denoting the global locale. */
  156. SCM_GLOBAL_VARIABLE (scm_global_locale, "%global-locale");
  157. /* Validate parameter ARG as a locale object and set C_LOCALE to the
  158. corresponding C locale object. */
  159. #define SCM_VALIDATE_LOCALE_COPY(_pos, _arg, _c_locale) \
  160. do \
  161. { \
  162. SCM_VALIDATE_SMOB ((_pos), (_arg), locale_smob_type); \
  163. (_c_locale) = (scm_t_locale)SCM_SMOB_DATA (_arg); \
  164. } \
  165. while (0)
  166. /* Validate optional parameter ARG as either undefined or bound to a locale
  167. object. Set C_LOCALE to the corresponding C locale object or NULL. */
  168. #define SCM_VALIDATE_OPTIONAL_LOCALE_COPY(_pos, _arg, _c_locale) \
  169. do \
  170. { \
  171. if ((_arg) != SCM_UNDEFINED) \
  172. SCM_VALIDATE_LOCALE_COPY (_pos, _arg, _c_locale); \
  173. else \
  174. (_c_locale) = NULL; \
  175. } \
  176. while (0)
  177. SCM_SMOB (scm_tc16_locale_smob_type, "locale", 0);
  178. SCM_SMOB_FREE (scm_tc16_locale_smob_type, smob_locale_free, locale)
  179. {
  180. scm_t_locale c_locale;
  181. c_locale = (scm_t_locale) SCM_SMOB_DATA (locale);
  182. scm_i_locale_free (c_locale);
  183. return 0;
  184. }
  185. #ifndef USE_GNU_LOCALE_API
  186. static SCM
  187. smob_locale_mark (SCM locale)
  188. {
  189. register SCM dependency;
  190. if (!scm_is_eq (locale, SCM_VARIABLE_REF (scm_global_locale)))
  191. {
  192. scm_t_locale c_locale;
  193. c_locale = (scm_t_locale) SCM_SMOB_DATA (locale);
  194. dependency = (c_locale->base_locale);
  195. }
  196. else
  197. dependency = SCM_BOOL_F;
  198. return dependency;
  199. }
  200. #endif
  201. static void inline scm_locale_error (const char *, int) SCM_NORETURN;
  202. /* Throw an exception corresponding to error ERR. */
  203. static void inline
  204. scm_locale_error (const char *func_name, int err)
  205. {
  206. scm_syserror_msg (func_name,
  207. "Failed to install locale",
  208. SCM_EOL, err);
  209. }
  210. /* Emulating GNU's reentrant locale API. */
  211. #ifndef USE_GNU_LOCALE_API
  212. /* Maximum number of chained locales (via `base_locale'). */
  213. #define LOCALE_STACK_SIZE_MAX 256
  214. typedef struct
  215. {
  216. #define SCM_DEFINE_LOCALE_CATEGORY(_name) char * _name;
  217. #include "locale-categories.h"
  218. #undef SCM_DEFINE_LOCALE_CATEGORY
  219. } scm_t_locale_settings;
  220. /* Fill out SETTINGS according to the current locale settings. On success
  221. zero is returned and SETTINGS is properly initialized. */
  222. static int
  223. get_current_locale_settings (scm_t_locale_settings *settings)
  224. {
  225. const char *locale_name;
  226. #define SCM_DEFINE_LOCALE_CATEGORY(_name) \
  227. { \
  228. SCM_SYSCALL (locale_name = setlocale (LC_ ## _name, NULL)); \
  229. if (locale_name == NULL) \
  230. goto handle_error; \
  231. \
  232. settings-> _name = strdup (locale_name); \
  233. if (settings-> _name == NULL) \
  234. goto handle_oom; \
  235. }
  236. #include "locale-categories.h"
  237. #undef SCM_DEFINE_LOCALE_CATEGORY
  238. return 0;
  239. handle_error:
  240. return EINVAL;
  241. handle_oom:
  242. return ENOMEM;
  243. }
  244. /* Restore locale settings SETTINGS. On success, return zero. */
  245. static int
  246. restore_locale_settings (const scm_t_locale_settings *settings)
  247. {
  248. const char *result;
  249. #define SCM_DEFINE_LOCALE_CATEGORY(_name) \
  250. SCM_SYSCALL (result = setlocale (LC_ ## _name, settings-> _name)); \
  251. if (result == NULL) \
  252. goto handle_error;
  253. #include "locale-categories.h"
  254. #undef SCM_DEFINE_LOCALE_CATEGORY
  255. return 0;
  256. handle_error:
  257. return EINVAL;
  258. }
  259. /* Free memory associated with SETTINGS. */
  260. static void
  261. free_locale_settings (scm_t_locale_settings *settings)
  262. {
  263. #define SCM_DEFINE_LOCALE_CATEGORY(_name) \
  264. free (settings-> _name); \
  265. settings->_name = NULL;
  266. #include "locale-categories.h"
  267. #undef SCM_DEFINE_LOCALE_CATEGORY
  268. }
  269. /* Install the locale named LOCALE_NAME for all the categories listed in
  270. CATEGORY_MASK. */
  271. static int
  272. install_locale_categories (const char *locale_name, int category_mask)
  273. {
  274. const char *result;
  275. if (category_mask == LC_ALL_MASK)
  276. {
  277. SCM_SYSCALL (result = setlocale (LC_ALL, locale_name));
  278. if (result == NULL)
  279. goto handle_error;
  280. }
  281. else
  282. {
  283. #define SCM_DEFINE_LOCALE_CATEGORY(_name) \
  284. if (category_mask & SCM_LOCALE_CATEGORY_MASK (_name)) \
  285. { \
  286. SCM_SYSCALL (result = setlocale (LC_ ## _name, locale_name)); \
  287. if (result == NULL) \
  288. goto handle_error; \
  289. }
  290. #include "locale-categories.h"
  291. #undef SCM_DEFINE_LOCALE_CATEGORY
  292. }
  293. return 0;
  294. handle_error:
  295. return EINVAL;
  296. }
  297. /* Install LOCALE, recursively installing its base locales first. On
  298. success, zero is returned. */
  299. static int
  300. install_locale (scm_t_locale locale)
  301. {
  302. scm_t_locale stack[LOCALE_STACK_SIZE_MAX];
  303. int category_mask = 0;
  304. size_t stack_size = 0;
  305. int stack_offset = 0;
  306. const char *result = NULL;
  307. /* Build up a locale stack by traversing the `base_locale' link. */
  308. do
  309. {
  310. if (stack_size >= LOCALE_STACK_SIZE_MAX)
  311. /* We cannot use `scm_error ()' here because otherwise the locale
  312. mutex may remain locked. */
  313. return EINVAL;
  314. stack[stack_size++] = locale;
  315. /* Keep track of which categories have already been taken into
  316. account. */
  317. category_mask |= locale->category_mask;
  318. if (locale->base_locale != SCM_UNDEFINED)
  319. locale = (scm_t_locale) SCM_SMOB_DATA (locale->base_locale);
  320. else
  321. locale = NULL;
  322. }
  323. while ((locale != NULL) && (category_mask != LC_ALL_MASK));
  324. /* Install the C locale to start from a pristine state. */
  325. SCM_SYSCALL (result = setlocale (LC_ALL, "C"));
  326. if (result == NULL)
  327. goto handle_error;
  328. /* Install the locales in reverse order. */
  329. for (stack_offset = stack_size - 1;
  330. stack_offset >= 0;
  331. stack_offset--)
  332. {
  333. int err;
  334. scm_t_locale locale;
  335. locale = stack[stack_offset];
  336. err = install_locale_categories (locale->locale_name,
  337. locale->category_mask);
  338. if (err)
  339. goto handle_error;
  340. }
  341. return 0;
  342. handle_error:
  343. return EINVAL;
  344. }
  345. /* Leave the locked locale section. */
  346. static inline void
  347. leave_locale_section (const scm_t_locale_settings *settings)
  348. {
  349. /* Restore the previous locale settings. */
  350. (void)restore_locale_settings (settings);
  351. scm_i_pthread_mutex_unlock (&scm_i_locale_mutex);
  352. }
  353. /* Enter a locked locale section. */
  354. static inline int
  355. enter_locale_section (scm_t_locale locale,
  356. scm_t_locale_settings *prev_locale)
  357. {
  358. int err;
  359. scm_i_pthread_mutex_lock (&scm_i_locale_mutex);
  360. err = get_current_locale_settings (prev_locale);
  361. if (err)
  362. {
  363. scm_i_pthread_mutex_unlock (&scm_i_locale_mutex);
  364. return err;
  365. }
  366. err = install_locale (locale);
  367. if (err)
  368. {
  369. leave_locale_section (prev_locale);
  370. free_locale_settings (prev_locale);
  371. }
  372. return err;
  373. }
  374. /* Convenient macro to run STATEMENT in the locale context of C_LOCALE. */
  375. #define RUN_IN_LOCALE_SECTION(_c_locale, _statement) \
  376. do \
  377. { \
  378. int lsec_err; \
  379. scm_t_locale_settings lsec_prev_locale; \
  380. \
  381. lsec_err = enter_locale_section ((_c_locale), &lsec_prev_locale); \
  382. if (lsec_err) \
  383. scm_locale_error (FUNC_NAME, lsec_err); \
  384. else \
  385. { \
  386. _statement ; \
  387. \
  388. leave_locale_section (&lsec_prev_locale); \
  389. free_locale_settings (&lsec_prev_locale); \
  390. } \
  391. } \
  392. while (0)
  393. /* Convert the current locale settings into a locale SMOB. On success, zero
  394. is returned and RESULT points to the new SMOB. Otherwise, an error is
  395. returned. */
  396. static int
  397. get_current_locale (SCM *result)
  398. {
  399. int err = 0;
  400. scm_t_locale c_locale;
  401. const char *current_locale;
  402. c_locale = scm_gc_malloc (sizeof (* c_locale), "locale");
  403. scm_i_pthread_mutex_lock (&scm_i_locale_mutex);
  404. c_locale->category_mask = LC_ALL_MASK;
  405. c_locale->base_locale = SCM_UNDEFINED;
  406. current_locale = setlocale (LC_ALL, NULL);
  407. if (current_locale != NULL)
  408. {
  409. c_locale->locale_name = strdup (current_locale);
  410. if (c_locale->locale_name == NULL)
  411. err = ENOMEM;
  412. }
  413. else
  414. err = EINVAL;
  415. scm_i_pthread_mutex_unlock (&scm_i_locale_mutex);
  416. if (err)
  417. scm_gc_free (c_locale, sizeof (* c_locale), "locale");
  418. else
  419. SCM_NEWSMOB (*result, scm_tc16_locale_smob_type, c_locale);
  420. return err;
  421. }
  422. #endif /* !USE_GNU_LOCALE_API */
  423. /* `make-locale' can take either category lists or single categories (the
  424. `LC_*' integer constants). */
  425. #define SCM_LIST_OR_INTEGER_P(arg) \
  426. (scm_is_integer (arg) || scm_is_true (scm_list_p (arg)))
  427. /* Return the category mask corresponding to CATEGORY (an `LC_' integer
  428. constant). */
  429. static inline int
  430. category_to_category_mask (SCM category,
  431. const char *func_name, int pos)
  432. {
  433. int c_category;
  434. int c_category_mask;
  435. c_category = scm_to_int (category);
  436. #define SCM_DEFINE_LOCALE_CATEGORY(_name) \
  437. case LC_ ## _name: \
  438. c_category_mask = SCM_LOCALE_CATEGORY_MASK (_name); \
  439. break;
  440. switch (c_category)
  441. {
  442. #include "locale-categories.h"
  443. case LC_ALL:
  444. c_category_mask = LC_ALL_MASK;
  445. break;
  446. default:
  447. scm_wrong_type_arg_msg (func_name, pos, category,
  448. "locale category");
  449. }
  450. #undef SCM_DEFINE_LOCALE_CATEGORY
  451. return c_category_mask;
  452. }
  453. /* Convert CATEGORIES, a list of locale categories or a single category (an
  454. integer), into a category mask. */
  455. static int
  456. category_list_to_category_mask (SCM categories,
  457. const char *func_name, int pos)
  458. {
  459. int c_category_mask = 0;
  460. if (scm_is_integer (categories))
  461. c_category_mask = category_to_category_mask (categories,
  462. func_name, pos);
  463. else
  464. for (; !scm_is_null (categories); categories = SCM_CDR (categories))
  465. {
  466. SCM category = SCM_CAR (categories);
  467. c_category_mask |=
  468. category_to_category_mask (category, func_name, pos);
  469. }
  470. return c_category_mask;
  471. }
  472. SCM_DEFINE (scm_make_locale, "make-locale", 2, 1, 0,
  473. (SCM category_list, SCM locale_name, SCM base_locale),
  474. "Return a reference to a data structure representing a set of "
  475. "locale datasets. @var{category_list} should be either a list "
  476. "of locale categories or a single category as used with "
  477. "@code{setlocale} (@pxref{Locales, @code{setlocale}}) and "
  478. "@var{locale_name} should be the name of the locale considered "
  479. "(e.g., @code{\"sl_SI\"}). Optionally, if @code{base_locale} is "
  480. "passed, it should be a locale object denoting settings for "
  481. "categories not listed in @var{category_list}.")
  482. #define FUNC_NAME s_scm_make_locale
  483. {
  484. SCM locale = SCM_BOOL_F;
  485. int err = 0;
  486. int c_category_mask;
  487. char *c_locale_name;
  488. scm_t_locale c_base_locale, c_locale;
  489. SCM_MAKE_VALIDATE (1, category_list, LIST_OR_INTEGER_P);
  490. SCM_VALIDATE_STRING (2, locale_name);
  491. SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, base_locale, c_base_locale);
  492. c_category_mask = category_list_to_category_mask (category_list,
  493. FUNC_NAME, 1);
  494. c_locale_name = scm_to_locale_string (locale_name);
  495. #ifdef USE_GNU_LOCALE_API
  496. if (scm_is_eq (base_locale, SCM_VARIABLE_REF (scm_global_locale)))
  497. {
  498. /* Fetch the current locale and turn in into a `locale_t'. Don't
  499. duplicate the resulting `locale_t' because we want it to be consumed
  500. by `newlocale ()'. */
  501. char *current_locale;
  502. scm_i_pthread_mutex_lock (&scm_i_locale_mutex);
  503. current_locale = setlocale (LC_ALL, NULL);
  504. c_base_locale = newlocale (LC_ALL_MASK, current_locale, NULL);
  505. scm_i_pthread_mutex_unlock (&scm_i_locale_mutex);
  506. if (c_base_locale == (locale_t) 0)
  507. scm_locale_error (FUNC_NAME, errno);
  508. }
  509. else if (c_base_locale != (locale_t) 0)
  510. {
  511. /* C_BASE_LOCALE is to be consumed by `newlocale ()' so it needs to be
  512. duplicated before. */
  513. c_base_locale = duplocale (c_base_locale);
  514. if (c_base_locale == (locale_t) 0)
  515. {
  516. err = errno;
  517. goto fail;
  518. }
  519. }
  520. c_locale = newlocale (c_category_mask, c_locale_name, c_base_locale);
  521. free (c_locale_name);
  522. if (c_locale == (locale_t) 0)
  523. {
  524. if (scm_is_eq (base_locale, SCM_VARIABLE_REF (scm_global_locale)))
  525. /* The base locale object was created lazily and must be freed. */
  526. freelocale (c_base_locale);
  527. scm_locale_error (FUNC_NAME, errno);
  528. }
  529. else
  530. SCM_NEWSMOB (locale, scm_tc16_locale_smob_type, c_locale);
  531. #else
  532. c_locale = scm_gc_malloc (sizeof (* c_locale), "locale");
  533. c_locale->category_mask = c_category_mask;
  534. c_locale->locale_name = c_locale_name;
  535. if (scm_is_eq (base_locale, SCM_VARIABLE_REF (scm_global_locale)))
  536. {
  537. /* Get the current locale settings and turn them into a locale
  538. object. */
  539. err = get_current_locale (&base_locale);
  540. if (err)
  541. goto fail;
  542. }
  543. c_locale->base_locale = base_locale;
  544. {
  545. /* Try out the new locale and raise an exception if it doesn't work. */
  546. int err;
  547. scm_t_locale_settings prev_locale;
  548. err = enter_locale_section (c_locale, &prev_locale);
  549. if (err)
  550. goto fail;
  551. else
  552. {
  553. leave_locale_section (&prev_locale);
  554. SCM_NEWSMOB (locale, scm_tc16_locale_smob_type, c_locale);
  555. }
  556. }
  557. #endif
  558. return locale;
  559. fail:
  560. #ifndef USE_GNU_LOCALE_API
  561. scm_gc_free (c_locale, sizeof (* c_locale), "locale");
  562. #endif
  563. free (c_locale_name);
  564. scm_locale_error (FUNC_NAME, err);
  565. return SCM_BOOL_F;
  566. }
  567. #undef FUNC_NAME
  568. SCM_DEFINE (scm_locale_p, "locale?", 1, 0, 0,
  569. (SCM obj),
  570. "Return true if @var{obj} is a locale object.")
  571. #define FUNC_NAME s_scm_locale_p
  572. {
  573. return scm_from_bool (SCM_SMOB_PREDICATE (scm_tc16_locale_smob_type, obj));
  574. }
  575. #undef FUNC_NAME
  576. /* Locale-dependent string comparison.
  577. A similar API can be found in MzScheme starting from version 200:
  578. http://download.plt-scheme.org/chronology/mzmr200alpha14.html . */
  579. /* Compare null-terminated strings C_S1 and C_S2 according to LOCALE. Return
  580. an integer whose sign is the same as the difference between C_S1 and
  581. C_S2. */
  582. static inline int
  583. compare_strings (const char *c_s1, const char *c_s2, SCM locale,
  584. const char *func_name)
  585. #define FUNC_NAME func_name
  586. {
  587. int result;
  588. scm_t_locale c_locale;
  589. SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, locale, c_locale);
  590. if (c_locale)
  591. {
  592. #ifdef USE_GNU_LOCALE_API
  593. result = strcoll_l (c_s1, c_s2, c_locale);
  594. #else
  595. #ifdef HAVE_STRCOLL
  596. RUN_IN_LOCALE_SECTION (c_locale, result = strcoll (c_s1, c_s2));
  597. #else
  598. result = strcmp (c_s1, c_s2);
  599. #endif
  600. #endif /* !USE_GNU_LOCALE_API */
  601. }
  602. else
  603. #ifdef HAVE_STRCOLL
  604. result = strcoll (c_s1, c_s2);
  605. #else
  606. result = strcmp (c_s1, c_s2);
  607. #endif
  608. return result;
  609. }
  610. #undef FUNC_NAME
  611. /* Store into DST an upper-case version of SRC. */
  612. static inline void
  613. str_upcase (register char *dst, register const char *src)
  614. {
  615. for (; *src != '\0'; src++, dst++)
  616. *dst = toupper ((int) *src);
  617. *dst = '\0';
  618. }
  619. static inline void
  620. str_downcase (register char *dst, register const char *src)
  621. {
  622. for (; *src != '\0'; src++, dst++)
  623. *dst = tolower ((int) *src);
  624. *dst = '\0';
  625. }
  626. #ifdef USE_GNU_LOCALE_API
  627. static inline void
  628. str_upcase_l (register char *dst, register const char *src,
  629. scm_t_locale locale)
  630. {
  631. for (; *src != '\0'; src++, dst++)
  632. *dst = toupper_l (*src, locale);
  633. *dst = '\0';
  634. }
  635. static inline void
  636. str_downcase_l (register char *dst, register const char *src,
  637. scm_t_locale locale)
  638. {
  639. for (; *src != '\0'; src++, dst++)
  640. *dst = tolower_l (*src, locale);
  641. *dst = '\0';
  642. }
  643. #endif
  644. /* Compare null-terminated strings C_S1 and C_S2 in a case-independent way
  645. according to LOCALE. Return an integer whose sign is the same as the
  646. difference between C_S1 and C_S2. */
  647. static inline int
  648. compare_strings_ci (const char *c_s1, const char *c_s2, SCM locale,
  649. const char *func_name)
  650. #define FUNC_NAME func_name
  651. {
  652. int result;
  653. scm_t_locale c_locale;
  654. char *c_us1, *c_us2;
  655. SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, locale, c_locale);
  656. c_us1 = (char *) alloca (strlen (c_s1) + 1);
  657. c_us2 = (char *) alloca (strlen (c_s2) + 1);
  658. if (c_locale)
  659. {
  660. #ifdef USE_GNU_LOCALE_API
  661. str_upcase_l (c_us1, c_s1, c_locale);
  662. str_upcase_l (c_us2, c_s2, c_locale);
  663. result = strcoll_l (c_us1, c_us2, c_locale);
  664. #else
  665. int err;
  666. scm_t_locale_settings prev_locale;
  667. err = enter_locale_section (c_locale, &prev_locale);
  668. if (err)
  669. {
  670. scm_locale_error (func_name, err);
  671. return 0;
  672. }
  673. str_upcase (c_us1, c_s1);
  674. str_upcase (c_us2, c_s2);
  675. #ifdef HAVE_STRCOLL
  676. result = strcoll (c_us1, c_us2);
  677. #else
  678. result = strcmp (c_us1, c_us2);
  679. #endif /* !HAVE_STRCOLL */
  680. leave_locale_section (&prev_locale);
  681. free_locale_settings (&prev_locale);
  682. #endif /* !USE_GNU_LOCALE_API */
  683. }
  684. else
  685. {
  686. str_upcase (c_us1, c_s1);
  687. str_upcase (c_us2, c_s2);
  688. #ifdef HAVE_STRCOLL
  689. result = strcoll (c_us1, c_us2);
  690. #else
  691. result = strcmp (c_us1, c_us2);
  692. #endif
  693. }
  694. return result;
  695. }
  696. #undef FUNC_NAME
  697. SCM_DEFINE (scm_string_locale_lt, "string-locale<?", 2, 1, 0,
  698. (SCM s1, SCM s2, SCM locale),
  699. "Compare strings @var{s1} and @var{s2} in a locale-dependent way."
  700. "If @var{locale} is provided, it should be locale object (as "
  701. "returned by @code{make-locale}) and will be used to perform the "
  702. "comparison; otherwise, the current system locale is used.")
  703. #define FUNC_NAME s_scm_string_locale_lt
  704. {
  705. int result;
  706. const char *c_s1, *c_s2;
  707. SCM_VALIDATE_STRING (1, s1);
  708. SCM_VALIDATE_STRING (2, s2);
  709. c_s1 = scm_i_string_chars (s1);
  710. c_s2 = scm_i_string_chars (s2);
  711. result = compare_strings (c_s1, c_s2, locale, FUNC_NAME);
  712. scm_remember_upto_here_2 (s1, s2);
  713. return scm_from_bool (result < 0);
  714. }
  715. #undef FUNC_NAME
  716. SCM_DEFINE (scm_string_locale_gt, "string-locale>?", 2, 1, 0,
  717. (SCM s1, SCM s2, SCM locale),
  718. "Compare strings @var{s1} and @var{s2} in a locale-dependent way."
  719. "If @var{locale} is provided, it should be locale object (as "
  720. "returned by @code{make-locale}) and will be used to perform the "
  721. "comparison; otherwise, the current system locale is used.")
  722. #define FUNC_NAME s_scm_string_locale_gt
  723. {
  724. int result;
  725. const char *c_s1, *c_s2;
  726. SCM_VALIDATE_STRING (1, s1);
  727. SCM_VALIDATE_STRING (2, s2);
  728. c_s1 = scm_i_string_chars (s1);
  729. c_s2 = scm_i_string_chars (s2);
  730. result = compare_strings (c_s1, c_s2, locale, FUNC_NAME);
  731. scm_remember_upto_here_2 (s1, s2);
  732. return scm_from_bool (result > 0);
  733. }
  734. #undef FUNC_NAME
  735. SCM_DEFINE (scm_string_locale_ci_lt, "string-locale-ci<?", 2, 1, 0,
  736. (SCM s1, SCM s2, SCM locale),
  737. "Compare strings @var{s1} and @var{s2} in a case-insensitive, "
  738. "and locale-dependent way. If @var{locale} is provided, it "
  739. "should be locale object (as returned by @code{make-locale}) "
  740. "and will be used to perform the comparison; otherwise, the "
  741. "current system locale is used.")
  742. #define FUNC_NAME s_scm_string_locale_ci_lt
  743. {
  744. int result;
  745. const char *c_s1, *c_s2;
  746. SCM_VALIDATE_STRING (1, s1);
  747. SCM_VALIDATE_STRING (2, s2);
  748. c_s1 = scm_i_string_chars (s1);
  749. c_s2 = scm_i_string_chars (s2);
  750. result = compare_strings_ci (c_s1, c_s2, locale, FUNC_NAME);
  751. scm_remember_upto_here_2 (s1, s2);
  752. return scm_from_bool (result < 0);
  753. }
  754. #undef FUNC_NAME
  755. SCM_DEFINE (scm_string_locale_ci_gt, "string-locale-ci>?", 2, 1, 0,
  756. (SCM s1, SCM s2, SCM locale),
  757. "Compare strings @var{s1} and @var{s2} in a case-insensitive, "
  758. "and locale-dependent way. If @var{locale} is provided, it "
  759. "should be locale object (as returned by @code{make-locale}) "
  760. "and will be used to perform the comparison; otherwise, the "
  761. "current system locale is used.")
  762. #define FUNC_NAME s_scm_string_locale_ci_gt
  763. {
  764. int result;
  765. const char *c_s1, *c_s2;
  766. SCM_VALIDATE_STRING (1, s1);
  767. SCM_VALIDATE_STRING (2, s2);
  768. c_s1 = scm_i_string_chars (s1);
  769. c_s2 = scm_i_string_chars (s2);
  770. result = compare_strings_ci (c_s1, c_s2, locale, FUNC_NAME);
  771. scm_remember_upto_here_2 (s1, s2);
  772. return scm_from_bool (result > 0);
  773. }
  774. #undef FUNC_NAME
  775. SCM_DEFINE (scm_string_locale_ci_eq, "string-locale-ci=?", 2, 1, 0,
  776. (SCM s1, SCM s2, SCM locale),
  777. "Compare strings @var{s1} and @var{s2} in a case-insensitive, "
  778. "and locale-dependent way. If @var{locale} is provided, it "
  779. "should be locale object (as returned by @code{make-locale}) "
  780. "and will be used to perform the comparison; otherwise, the "
  781. "current system locale is used.")
  782. #define FUNC_NAME s_scm_string_locale_ci_eq
  783. {
  784. int result;
  785. const char *c_s1, *c_s2;
  786. SCM_VALIDATE_STRING (1, s1);
  787. SCM_VALIDATE_STRING (2, s2);
  788. c_s1 = scm_i_string_chars (s1);
  789. c_s2 = scm_i_string_chars (s2);
  790. result = compare_strings_ci (c_s1, c_s2, locale, FUNC_NAME);
  791. scm_remember_upto_here_2 (s1, s2);
  792. return scm_from_bool (result == 0);
  793. }
  794. #undef FUNC_NAME
  795. SCM_DEFINE (scm_char_locale_lt, "char-locale<?", 2, 1, 0,
  796. (SCM c1, SCM c2, SCM locale),
  797. "Return true if character @var{c1} is lower than @var{c2} "
  798. "according to @var{locale} or to the current locale.")
  799. #define FUNC_NAME s_scm_char_locale_lt
  800. {
  801. char c_c1[2], c_c2[2];
  802. SCM_VALIDATE_CHAR (1, c1);
  803. SCM_VALIDATE_CHAR (2, c2);
  804. c_c1[0] = (char)SCM_CHAR (c1); c_c1[1] = '\0';
  805. c_c2[0] = (char)SCM_CHAR (c2); c_c2[1] = '\0';
  806. return scm_from_bool (compare_strings (c_c1, c_c2, locale, FUNC_NAME) < 0);
  807. }
  808. #undef FUNC_NAME
  809. SCM_DEFINE (scm_char_locale_gt, "char-locale>?", 2, 1, 0,
  810. (SCM c1, SCM c2, SCM locale),
  811. "Return true if character @var{c1} is greater than @var{c2} "
  812. "according to @var{locale} or to the current locale.")
  813. #define FUNC_NAME s_scm_char_locale_gt
  814. {
  815. char c_c1[2], c_c2[2];
  816. SCM_VALIDATE_CHAR (1, c1);
  817. SCM_VALIDATE_CHAR (2, c2);
  818. c_c1[0] = (char)SCM_CHAR (c1); c_c1[1] = '\0';
  819. c_c2[0] = (char)SCM_CHAR (c2); c_c2[1] = '\0';
  820. return scm_from_bool (compare_strings (c_c1, c_c2, locale, FUNC_NAME) > 0);
  821. }
  822. #undef FUNC_NAME
  823. SCM_DEFINE (scm_char_locale_ci_lt, "char-locale-ci<?", 2, 1, 0,
  824. (SCM c1, SCM c2, SCM locale),
  825. "Return true if character @var{c1} is lower than @var{c2}, "
  826. "in a case insensitive way according to @var{locale} or to "
  827. "the current locale.")
  828. #define FUNC_NAME s_scm_char_locale_ci_lt
  829. {
  830. int result;
  831. char c_c1[2], c_c2[2];
  832. SCM_VALIDATE_CHAR (1, c1);
  833. SCM_VALIDATE_CHAR (2, c2);
  834. c_c1[0] = (char)SCM_CHAR (c1); c_c1[1] = '\0';
  835. c_c2[0] = (char)SCM_CHAR (c2); c_c2[1] = '\0';
  836. result = compare_strings_ci (c_c1, c_c2, locale, FUNC_NAME);
  837. return scm_from_bool (result < 0);
  838. }
  839. #undef FUNC_NAME
  840. SCM_DEFINE (scm_char_locale_ci_gt, "char-locale-ci>?", 2, 1, 0,
  841. (SCM c1, SCM c2, SCM locale),
  842. "Return true if character @var{c1} is greater than @var{c2}, "
  843. "in a case insensitive way according to @var{locale} or to "
  844. "the current locale.")
  845. #define FUNC_NAME s_scm_char_locale_ci_gt
  846. {
  847. int result;
  848. char c_c1[2], c_c2[2];
  849. SCM_VALIDATE_CHAR (1, c1);
  850. SCM_VALIDATE_CHAR (2, c2);
  851. c_c1[0] = (char)SCM_CHAR (c1); c_c1[1] = '\0';
  852. c_c2[0] = (char)SCM_CHAR (c2); c_c2[1] = '\0';
  853. result = compare_strings_ci (c_c1, c_c2, locale, FUNC_NAME);
  854. return scm_from_bool (result > 0);
  855. }
  856. #undef FUNC_NAME
  857. SCM_DEFINE (scm_char_locale_ci_eq, "char-locale-ci=?", 2, 1, 0,
  858. (SCM c1, SCM c2, SCM locale),
  859. "Return true if character @var{c1} is equal to @var{c2}, "
  860. "in a case insensitive way according to @var{locale} or to "
  861. "the current locale.")
  862. #define FUNC_NAME s_scm_char_locale_ci_eq
  863. {
  864. int result;
  865. char c_c1[2], c_c2[2];
  866. SCM_VALIDATE_CHAR (1, c1);
  867. SCM_VALIDATE_CHAR (2, c2);
  868. c_c1[0] = (char)SCM_CHAR (c1); c_c1[1] = '\0';
  869. c_c2[0] = (char)SCM_CHAR (c2); c_c2[1] = '\0';
  870. result = compare_strings_ci (c_c1, c_c2, locale, FUNC_NAME);
  871. return scm_from_bool (result == 0);
  872. }
  873. #undef FUNC_NAME
  874. /* Locale-dependent alphabetic character mapping. */
  875. SCM_DEFINE (scm_char_locale_downcase, "char-locale-downcase", 1, 1, 0,
  876. (SCM chr, SCM locale),
  877. "Return the lowercase character that corresponds to @var{chr} "
  878. "according to either @var{locale} or the current locale.")
  879. #define FUNC_NAME s_scm_char_locale_downcase
  880. {
  881. char c_chr;
  882. int c_result;
  883. scm_t_locale c_locale;
  884. SCM_VALIDATE_CHAR (1, chr);
  885. c_chr = SCM_CHAR (chr);
  886. SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
  887. if (c_locale != NULL)
  888. {
  889. #ifdef USE_GNU_LOCALE_API
  890. c_result = tolower_l ((int) c_chr, c_locale);
  891. #else
  892. RUN_IN_LOCALE_SECTION (c_locale, c_result = tolower ((int) c_chr));
  893. #endif
  894. }
  895. else
  896. c_result = tolower ((int) c_chr);
  897. return (SCM_MAKE_CHAR (c_result));
  898. }
  899. #undef FUNC_NAME
  900. SCM_DEFINE (scm_char_locale_upcase, "char-locale-upcase", 1, 1, 0,
  901. (SCM chr, SCM locale),
  902. "Return the uppercase character that corresponds to @var{chr} "
  903. "according to either @var{locale} or the current locale.")
  904. #define FUNC_NAME s_scm_char_locale_upcase
  905. {
  906. char c_chr;
  907. int c_result;
  908. scm_t_locale c_locale;
  909. SCM_VALIDATE_CHAR (1, chr);
  910. c_chr = SCM_CHAR (chr);
  911. SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
  912. if (c_locale != NULL)
  913. {
  914. #ifdef USE_GNU_LOCALE_API
  915. c_result = toupper_l ((int) c_chr, c_locale);
  916. #else
  917. RUN_IN_LOCALE_SECTION (c_locale, c_result = toupper ((int) c_chr));
  918. #endif
  919. }
  920. else
  921. c_result = toupper ((int) c_chr);
  922. return (SCM_MAKE_CHAR (c_result));
  923. }
  924. #undef FUNC_NAME
  925. SCM_DEFINE (scm_string_locale_upcase, "string-locale-upcase", 1, 1, 0,
  926. (SCM str, SCM locale),
  927. "Return a new string that is the uppercase version of "
  928. "@var{str} according to either @var{locale} or the current "
  929. "locale.")
  930. #define FUNC_NAME s_scm_string_locale_upcase
  931. {
  932. const char *c_str;
  933. char *c_ustr;
  934. scm_t_locale c_locale;
  935. SCM_VALIDATE_STRING (1, str);
  936. SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
  937. c_str = scm_i_string_chars (str);
  938. c_ustr = (char *) alloca (strlen (c_str) + 1);
  939. if (c_locale)
  940. {
  941. #ifdef USE_GNU_LOCALE_API
  942. str_upcase_l (c_ustr, c_str, c_locale);
  943. #else
  944. RUN_IN_LOCALE_SECTION (c_locale, str_upcase (c_ustr, c_str));
  945. #endif
  946. }
  947. else
  948. str_upcase (c_ustr, c_str);
  949. scm_remember_upto_here (str);
  950. return (scm_from_locale_string (c_ustr));
  951. }
  952. #undef FUNC_NAME
  953. SCM_DEFINE (scm_string_locale_downcase, "string-locale-downcase", 1, 1, 0,
  954. (SCM str, SCM locale),
  955. "Return a new string that is the down-case version of "
  956. "@var{str} according to either @var{locale} or the current "
  957. "locale.")
  958. #define FUNC_NAME s_scm_string_locale_downcase
  959. {
  960. const char *c_str;
  961. char *c_lstr;
  962. scm_t_locale c_locale;
  963. SCM_VALIDATE_STRING (1, str);
  964. SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
  965. c_str = scm_i_string_chars (str);
  966. c_lstr = (char *) alloca (strlen (c_str) + 1);
  967. if (c_locale)
  968. {
  969. #ifdef USE_GNU_LOCALE_API
  970. str_downcase_l (c_lstr, c_str, c_locale);
  971. #else
  972. RUN_IN_LOCALE_SECTION (c_locale, str_downcase (c_lstr, c_str));
  973. #endif
  974. }
  975. else
  976. str_downcase (c_lstr, c_str);
  977. scm_remember_upto_here (str);
  978. return (scm_from_locale_string (c_lstr));
  979. }
  980. #undef FUNC_NAME
  981. /* Note: We don't provide mutative versions of `string-locale-(up|down)case'
  982. because, in some languages, a single downcase character maps to a couple
  983. of uppercase characters. Read the SRFI-13 document for a detailed
  984. discussion about this. */
  985. /* Locale-dependent number parsing. */
  986. SCM_DEFINE (scm_locale_string_to_integer, "locale-string->integer",
  987. 1, 2, 0, (SCM str, SCM base, SCM locale),
  988. "Convert string @var{str} into an integer according to either "
  989. "@var{locale} (a locale object as returned by @code{make-locale}) "
  990. "or the current process locale. Return two values: an integer "
  991. "(on success) or @code{#f}, and the number of characters read "
  992. "from @var{str} (@code{0} on failure).")
  993. #define FUNC_NAME s_scm_locale_string_to_integer
  994. {
  995. SCM result;
  996. long c_result;
  997. int c_base;
  998. const char *c_str;
  999. char *c_endptr;
  1000. scm_t_locale c_locale;
  1001. SCM_VALIDATE_STRING (1, str);
  1002. c_str = scm_i_string_chars (str);
  1003. if (base != SCM_UNDEFINED)
  1004. SCM_VALIDATE_INT_COPY (2, base, c_base);
  1005. else
  1006. c_base = 10;
  1007. SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, locale, c_locale);
  1008. if (c_locale != NULL)
  1009. {
  1010. #ifdef USE_GNU_LOCALE_API
  1011. c_result = strtol_l (c_str, &c_endptr, c_base, c_locale);
  1012. #else
  1013. RUN_IN_LOCALE_SECTION (c_locale,
  1014. c_result = strtol (c_str, &c_endptr, c_base));
  1015. #endif
  1016. }
  1017. else
  1018. c_result = strtol (c_str, &c_endptr, c_base);
  1019. scm_remember_upto_here (str);
  1020. if (c_endptr == c_str)
  1021. result = SCM_BOOL_F;
  1022. else
  1023. result = scm_from_long (c_result);
  1024. return (scm_values (scm_list_2 (result, scm_from_long (c_endptr - c_str))));
  1025. }
  1026. #undef FUNC_NAME
  1027. SCM_DEFINE (scm_locale_string_to_inexact, "locale-string->inexact",
  1028. 1, 1, 0, (SCM str, SCM locale),
  1029. "Convert string @var{str} into an inexact number according to "
  1030. "either @var{locale} (a locale object as returned by "
  1031. "@code{make-locale}) or the current process locale. Return "
  1032. "two values: an inexact number (on success) or @code{#f}, and "
  1033. "the number of characters read from @var{str} (@code{0} on "
  1034. "failure).")
  1035. #define FUNC_NAME s_scm_locale_string_to_inexact
  1036. {
  1037. SCM result;
  1038. double c_result;
  1039. const char *c_str;
  1040. char *c_endptr;
  1041. scm_t_locale c_locale;
  1042. SCM_VALIDATE_STRING (1, str);
  1043. c_str = scm_i_string_chars (str);
  1044. SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
  1045. if (c_locale != NULL)
  1046. {
  1047. #ifdef USE_GNU_LOCALE_API
  1048. c_result = strtod_l (c_str, &c_endptr, c_locale);
  1049. #else
  1050. RUN_IN_LOCALE_SECTION (c_locale,
  1051. c_result = strtod (c_str, &c_endptr));
  1052. #endif
  1053. }
  1054. else
  1055. c_result = strtod (c_str, &c_endptr);
  1056. scm_remember_upto_here (str);
  1057. if (c_endptr == c_str)
  1058. result = SCM_BOOL_F;
  1059. else
  1060. result = scm_from_double (c_result);
  1061. return (scm_values (scm_list_2 (result, scm_from_long (c_endptr - c_str))));
  1062. }
  1063. #undef FUNC_NAME
  1064. /* Language information, aka. `nl_langinfo ()'. */
  1065. /* FIXME: Issues related to `nl-langinfo'.
  1066. 1. The `CODESET' value is not normalized. This is a secondary issue, but
  1067. still a practical issue. See
  1068. http://www.cl.cam.ac.uk/~mgk25/ucs/norm_charmap.c for codeset
  1069. normalization.
  1070. 2. `nl_langinfo ()' is not available on Windows.
  1071. 3. `nl_langinfo ()' may return strings encoded in a locale different from
  1072. the current one, thereby defeating `scm_from_locale_string ()'.
  1073. Example: support the current locale is "Latin-1" and one asks:
  1074. (nl-langinfo DAY_1 (make-locale LC_ALL "eo_EO.UTF-8"))
  1075. The result will be a UTF-8 string. However, `scm_from_locale_string',
  1076. which expects a Latin-1 string, won't be able to make much sense of the
  1077. returned string. Thus, we'd need an `scm_from_string ()' variant where
  1078. the locale (or charset) is explicitly passed. */
  1079. SCM_DEFINE (scm_nl_langinfo, "nl-langinfo", 1, 1, 0,
  1080. (SCM item, SCM locale),
  1081. "Return a string denoting locale information for @var{item} "
  1082. "in the current locale or that specified by @var{locale}. "
  1083. "The semantics and arguments are the same as those of the "
  1084. "X/Open @code{nl_langinfo} function (@pxref{The Elegant and "
  1085. "Fast Way, @code{nl_langinfo},, libc, The GNU C Library "
  1086. "Reference Manual}).")
  1087. #define FUNC_NAME s_scm_nl_langinfo
  1088. {
  1089. #ifdef HAVE_NL_LANGINFO
  1090. SCM result;
  1091. nl_item c_item;
  1092. char *c_result;
  1093. scm_t_locale c_locale;
  1094. SCM_VALIDATE_INT_COPY (2, item, c_item);
  1095. SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
  1096. /* Sadly, `nl_langinfo ()' returns a pointer to a static string. According
  1097. to SuS v2, that static string may be modified by subsequent calls to
  1098. `nl_langinfo ()' as well as by calls to `setlocale ()'. Thus, we must
  1099. acquire the locale mutex before doing invoking `nl_langinfo ()'. See
  1100. http://opengroup.org/onlinepubs/007908799/xsh/nl_langinfo.html for
  1101. details. */
  1102. scm_i_pthread_mutex_lock (&scm_i_locale_mutex);
  1103. if (c_locale != NULL)
  1104. {
  1105. #ifdef USE_GNU_LOCALE_API
  1106. c_result = nl_langinfo_l (c_item, c_locale);
  1107. #else
  1108. /* We can't use `RUN_IN_LOCALE_SECTION ()' here because the locale
  1109. mutex is already taken. */
  1110. int lsec_err;
  1111. scm_t_locale_settings lsec_prev_locale;
  1112. lsec_err = get_current_locale_settings (&lsec_prev_locale);
  1113. if (lsec_err)
  1114. scm_i_pthread_mutex_unlock (&scm_i_locale_mutex);
  1115. else
  1116. {
  1117. lsec_err = install_locale (c_locale);
  1118. if (lsec_err)
  1119. {
  1120. leave_locale_section (&lsec_prev_locale);
  1121. free_locale_settings (&lsec_prev_locale);
  1122. }
  1123. }
  1124. if (lsec_err)
  1125. scm_locale_error (FUNC_NAME, lsec_err);
  1126. else
  1127. {
  1128. c_result = nl_langinfo (c_item);
  1129. restore_locale_settings (&lsec_prev_locale);
  1130. free_locale_settings (&lsec_prev_locale);
  1131. }
  1132. #endif
  1133. }
  1134. else
  1135. c_result = nl_langinfo (c_item);
  1136. c_result = strdup (c_result);
  1137. scm_i_pthread_mutex_unlock (&scm_i_locale_mutex);
  1138. if (c_result == NULL)
  1139. result = SCM_BOOL_F;
  1140. else
  1141. {
  1142. switch (c_item)
  1143. {
  1144. #if (defined GROUPING) && (defined MON_GROUPING)
  1145. case GROUPING:
  1146. case MON_GROUPING:
  1147. {
  1148. char *p;
  1149. /* In this cases, the result is to be interpreted as a list of
  1150. numbers. If the last item is `CHARS_MAX', it has the special
  1151. meaning "no more grouping". */
  1152. result = SCM_EOL;
  1153. for (p = c_result; (*p != '\0') && (*p != CHAR_MAX); p++)
  1154. result = scm_cons (SCM_I_MAKINUM ((int) *p), result);
  1155. {
  1156. SCM last_pair = result;
  1157. result = scm_reverse_x (result, SCM_EOL);
  1158. if (*p != CHAR_MAX)
  1159. {
  1160. /* Cyclic grouping information. */
  1161. if (last_pair != SCM_EOL)
  1162. SCM_SETCDR (last_pair, result);
  1163. }
  1164. }
  1165. free (c_result);
  1166. break;
  1167. }
  1168. #endif
  1169. #if (defined FRAC_DIGITS) && (defined INT_FRAC_DIGITS)
  1170. case FRAC_DIGITS:
  1171. case INT_FRAC_DIGITS:
  1172. /* This is to be interpreted as a single integer. */
  1173. if (*c_result == CHAR_MAX)
  1174. /* Unspecified. */
  1175. result = SCM_BOOL_F;
  1176. else
  1177. result = SCM_I_MAKINUM (*c_result);
  1178. free (c_result);
  1179. break;
  1180. #endif
  1181. #if (defined P_CS_PRECEDES) && (defined INT_N_CS_PRECEDES)
  1182. case P_CS_PRECEDES:
  1183. case N_CS_PRECEDES:
  1184. case INT_P_CS_PRECEDES:
  1185. case INT_N_CS_PRECEDES:
  1186. #if (defined P_SEP_BY_SPACE) && (defined N_SEP_BY_SPACE)
  1187. case P_SEP_BY_SPACE:
  1188. case N_SEP_BY_SPACE:
  1189. #endif
  1190. /* This is to be interpreted as a boolean. */
  1191. result = scm_from_bool (*c_result);
  1192. free (c_result);
  1193. break;
  1194. #endif
  1195. #if (defined P_SIGN_POSN) && (defined INT_N_SIGN_POSN)
  1196. case P_SIGN_POSN:
  1197. case N_SIGN_POSN:
  1198. case INT_P_SIGN_POSN:
  1199. case INT_N_SIGN_POSN:
  1200. /* See `(libc) Sign of Money Amount' for the interpretation of the
  1201. return value here. */
  1202. switch (*c_result)
  1203. {
  1204. case 0:
  1205. result = scm_from_locale_symbol ("parenthesize");
  1206. break;
  1207. case 1:
  1208. result = scm_from_locale_symbol ("sign-before");
  1209. break;
  1210. case 2:
  1211. result = scm_from_locale_symbol ("sign-after");
  1212. break;
  1213. case 3:
  1214. result = scm_from_locale_symbol ("sign-before-currency-symbol");
  1215. break;
  1216. case 4:
  1217. result = scm_from_locale_symbol ("sign-after-currency-symbol");
  1218. break;
  1219. default:
  1220. result = scm_from_locale_symbol ("unspecified");
  1221. }
  1222. break;
  1223. #endif
  1224. default:
  1225. /* FIXME: `locale_string ()' is not appropriate here because of
  1226. encoding issues (see comment above). */
  1227. result = scm_take_locale_string (c_result);
  1228. }
  1229. }
  1230. return result;
  1231. #else
  1232. scm_syserror_msg (FUNC_NAME, "`nl-langinfo' not supported on your system",
  1233. SCM_EOL, ENOSYS);
  1234. return SCM_BOOL_F;
  1235. #endif
  1236. }
  1237. #undef FUNC_NAME
  1238. /* Define the `nl_item' constants. */
  1239. static inline void
  1240. define_langinfo_items (void)
  1241. {
  1242. #if (defined HAVE_NL_TYPES_H) && (defined HAVE_LANGINFO_H)
  1243. #define DEFINE_NLITEM_CONSTANT(_item) \
  1244. scm_c_define (# _item, scm_from_int (_item))
  1245. DEFINE_NLITEM_CONSTANT (CODESET);
  1246. /* Abbreviated days of the week. */
  1247. DEFINE_NLITEM_CONSTANT (ABDAY_1);
  1248. DEFINE_NLITEM_CONSTANT (ABDAY_2);
  1249. DEFINE_NLITEM_CONSTANT (ABDAY_3);
  1250. DEFINE_NLITEM_CONSTANT (ABDAY_4);
  1251. DEFINE_NLITEM_CONSTANT (ABDAY_5);
  1252. DEFINE_NLITEM_CONSTANT (ABDAY_6);
  1253. DEFINE_NLITEM_CONSTANT (ABDAY_7);
  1254. /* Long-named days of the week. */
  1255. DEFINE_NLITEM_CONSTANT (DAY_1); /* Sunday */
  1256. DEFINE_NLITEM_CONSTANT (DAY_2); /* Monday */
  1257. DEFINE_NLITEM_CONSTANT (DAY_3); /* Tuesday */
  1258. DEFINE_NLITEM_CONSTANT (DAY_4); /* Wednesday */
  1259. DEFINE_NLITEM_CONSTANT (DAY_5); /* Thursday */
  1260. DEFINE_NLITEM_CONSTANT (DAY_6); /* Friday */
  1261. DEFINE_NLITEM_CONSTANT (DAY_7); /* Saturday */
  1262. /* Abbreviated month names. */
  1263. DEFINE_NLITEM_CONSTANT (ABMON_1); /* Jan */
  1264. DEFINE_NLITEM_CONSTANT (ABMON_2);
  1265. DEFINE_NLITEM_CONSTANT (ABMON_3);
  1266. DEFINE_NLITEM_CONSTANT (ABMON_4);
  1267. DEFINE_NLITEM_CONSTANT (ABMON_5);
  1268. DEFINE_NLITEM_CONSTANT (ABMON_6);
  1269. DEFINE_NLITEM_CONSTANT (ABMON_7);
  1270. DEFINE_NLITEM_CONSTANT (ABMON_8);
  1271. DEFINE_NLITEM_CONSTANT (ABMON_9);
  1272. DEFINE_NLITEM_CONSTANT (ABMON_10);
  1273. DEFINE_NLITEM_CONSTANT (ABMON_11);
  1274. DEFINE_NLITEM_CONSTANT (ABMON_12);
  1275. /* Long month names. */
  1276. DEFINE_NLITEM_CONSTANT (MON_1); /* January */
  1277. DEFINE_NLITEM_CONSTANT (MON_2);
  1278. DEFINE_NLITEM_CONSTANT (MON_3);
  1279. DEFINE_NLITEM_CONSTANT (MON_4);
  1280. DEFINE_NLITEM_CONSTANT (MON_5);
  1281. DEFINE_NLITEM_CONSTANT (MON_6);
  1282. DEFINE_NLITEM_CONSTANT (MON_7);
  1283. DEFINE_NLITEM_CONSTANT (MON_8);
  1284. DEFINE_NLITEM_CONSTANT (MON_9);
  1285. DEFINE_NLITEM_CONSTANT (MON_10);
  1286. DEFINE_NLITEM_CONSTANT (MON_11);
  1287. DEFINE_NLITEM_CONSTANT (MON_12);
  1288. DEFINE_NLITEM_CONSTANT (AM_STR); /* Ante meridiem string. */
  1289. DEFINE_NLITEM_CONSTANT (PM_STR); /* Post meridiem string. */
  1290. DEFINE_NLITEM_CONSTANT (D_T_FMT); /* Date and time format for strftime. */
  1291. DEFINE_NLITEM_CONSTANT (D_FMT); /* Date format for strftime. */
  1292. DEFINE_NLITEM_CONSTANT (T_FMT); /* Time format for strftime. */
  1293. DEFINE_NLITEM_CONSTANT (T_FMT_AMPM);/* 12-hour time format for strftime. */
  1294. DEFINE_NLITEM_CONSTANT (ERA); /* Alternate era. */
  1295. DEFINE_NLITEM_CONSTANT (ERA_D_FMT); /* Date in alternate era format. */
  1296. DEFINE_NLITEM_CONSTANT (ERA_D_T_FMT); /* Date and time in alternate era
  1297. format. */
  1298. DEFINE_NLITEM_CONSTANT (ERA_T_FMT); /* Time in alternate era format. */
  1299. DEFINE_NLITEM_CONSTANT (ALT_DIGITS); /* Alternate symbols for digits. */
  1300. DEFINE_NLITEM_CONSTANT (RADIXCHAR);
  1301. DEFINE_NLITEM_CONSTANT (THOUSEP);
  1302. #ifdef YESEXPR
  1303. DEFINE_NLITEM_CONSTANT (YESEXPR);
  1304. #endif
  1305. #ifdef NOEXPR
  1306. DEFINE_NLITEM_CONSTANT (NOEXPR);
  1307. #endif
  1308. #ifdef CRNCYSTR /* currency symbol */
  1309. DEFINE_NLITEM_CONSTANT (CRNCYSTR);
  1310. #endif
  1311. /* GNU extensions. */
  1312. #ifdef ERA_YEAR
  1313. DEFINE_NLITEM_CONSTANT (ERA_YEAR); /* Year in alternate era format. */
  1314. #endif
  1315. /* LC_MONETARY category: formatting of monetary quantities.
  1316. These items each correspond to a member of `struct lconv',
  1317. defined in <locale.h>. */
  1318. #ifdef INT_CURR_SYMBOL
  1319. DEFINE_NLITEM_CONSTANT (INT_CURR_SYMBOL);
  1320. #endif
  1321. #ifdef MON_DECIMAL_POINT
  1322. DEFINE_NLITEM_CONSTANT (MON_DECIMAL_POINT);
  1323. #endif
  1324. #ifdef MON_THOUSANDS_SEP
  1325. DEFINE_NLITEM_CONSTANT (MON_THOUSANDS_SEP);
  1326. #endif
  1327. #ifdef MON_GROUPING
  1328. DEFINE_NLITEM_CONSTANT (MON_GROUPING);
  1329. #endif
  1330. #ifdef POSITIVE_SIGN
  1331. DEFINE_NLITEM_CONSTANT (POSITIVE_SIGN);
  1332. #endif
  1333. #ifdef NEGATIVE_SIGN
  1334. DEFINE_NLITEM_CONSTANT (NEGATIVE_SIGN);
  1335. #endif
  1336. #ifdef GROUPING
  1337. DEFINE_NLITEM_CONSTANT (GROUPING);
  1338. #endif
  1339. #ifdef INT_FRAC_DIGITS
  1340. DEFINE_NLITEM_CONSTANT (INT_FRAC_DIGITS);
  1341. #endif
  1342. #ifdef FRAC_DIGITS
  1343. DEFINE_NLITEM_CONSTANT (FRAC_DIGITS);
  1344. #endif
  1345. #ifdef P_CS_PRECEDES
  1346. DEFINE_NLITEM_CONSTANT (P_CS_PRECEDES);
  1347. #endif
  1348. #ifdef P_SEP_BY_SPACE
  1349. DEFINE_NLITEM_CONSTANT (P_SEP_BY_SPACE);
  1350. #endif
  1351. #ifdef N_CS_PRECEDES
  1352. DEFINE_NLITEM_CONSTANT (N_CS_PRECEDES);
  1353. #endif
  1354. #ifdef N_SEP_BY_SPACE
  1355. DEFINE_NLITEM_CONSTANT (N_SEP_BY_SPACE);
  1356. #endif
  1357. #ifdef P_SIGN_POSN
  1358. DEFINE_NLITEM_CONSTANT (P_SIGN_POSN);
  1359. #endif
  1360. #ifdef N_SIGN_POSN
  1361. DEFINE_NLITEM_CONSTANT (N_SIGN_POSN);
  1362. #endif
  1363. #ifdef INT_P_CS_PRECEDES
  1364. DEFINE_NLITEM_CONSTANT (INT_P_CS_PRECEDES);
  1365. #endif
  1366. #ifdef INT_P_SEP_BY_SPACE
  1367. DEFINE_NLITEM_CONSTANT (INT_P_SEP_BY_SPACE);
  1368. #endif
  1369. #ifdef INT_N_CS_PRECEDES
  1370. DEFINE_NLITEM_CONSTANT (INT_N_CS_PRECEDES);
  1371. #endif
  1372. #ifdef INT_N_SEP_BY_SPACE
  1373. DEFINE_NLITEM_CONSTANT (INT_N_SEP_BY_SPACE);
  1374. #endif
  1375. #ifdef INT_P_SIGN_POSN
  1376. DEFINE_NLITEM_CONSTANT (INT_P_SIGN_POSN);
  1377. #endif
  1378. #ifdef INT_N_SIGN_POSN
  1379. DEFINE_NLITEM_CONSTANT (INT_N_SIGN_POSN);
  1380. #endif
  1381. #undef DEFINE_NLITEM_CONSTANT
  1382. #endif /* HAVE_NL_TYPES_H */
  1383. }
  1384. void
  1385. scm_init_i18n ()
  1386. {
  1387. SCM global_locale_smob;
  1388. #ifdef HAVE_NL_LANGINFO
  1389. scm_add_feature ("nl-langinfo");
  1390. define_langinfo_items ();
  1391. #endif
  1392. #include "libguile/i18n.x"
  1393. #ifndef USE_GNU_LOCALE_API
  1394. scm_set_smob_mark (scm_tc16_locale_smob_type, smob_locale_mark);
  1395. #endif
  1396. /* Initialize the global locale object with a special `locale' SMOB. */
  1397. SCM_NEWSMOB (global_locale_smob, scm_tc16_locale_smob_type, NULL);
  1398. SCM_VARIABLE_SET (scm_global_locale, global_locale_smob);
  1399. }
  1400. /*
  1401. Local Variables:
  1402. c-file-style: "gnu"
  1403. End:
  1404. */