i18n.c 49 KB

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