i18n.c 51 KB

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