localcharset.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. /* Determine a canonical name for the current locale's character encoding.
  2. Copyright (C) 2000-2006, 2008-2009 Free Software Foundation, Inc.
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 3, or (at your option)
  6. any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License along
  12. with this program; if not, write to the Free Software Foundation,
  13. Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
  14. /* Written by Bruno Haible <bruno@clisp.org>. */
  15. #include <config.h>
  16. /* Specification. */
  17. #include "localcharset.h"
  18. #include <stddef.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <stdlib.h>
  22. #if defined __APPLE__ && defined __MACH__ && HAVE_LANGINFO_CODESET
  23. # define DARWIN7 /* Darwin 7 or newer, i.e. MacOS X 10.3 or newer */
  24. #endif
  25. #if defined _WIN32 || defined __WIN32__
  26. # define WIN32_NATIVE
  27. #endif
  28. #if defined __EMX__
  29. /* Assume EMX program runs on OS/2, even if compiled under DOS. */
  30. # ifndef OS2
  31. # define OS2
  32. # endif
  33. #endif
  34. #if !defined WIN32_NATIVE
  35. # if HAVE_LANGINFO_CODESET
  36. # include <langinfo.h>
  37. # else
  38. # if 0 /* see comment below */
  39. # include <locale.h>
  40. # endif
  41. # endif
  42. # ifdef __CYGWIN__
  43. # define WIN32_LEAN_AND_MEAN
  44. # include <windows.h>
  45. # endif
  46. #elif defined WIN32_NATIVE
  47. # define WIN32_LEAN_AND_MEAN
  48. # include <windows.h>
  49. #endif
  50. #if defined OS2
  51. # define INCL_DOS
  52. # include <os2.h>
  53. #endif
  54. #if ENABLE_RELOCATABLE
  55. # include "relocatable.h"
  56. #else
  57. # define relocate(pathname) (pathname)
  58. #endif
  59. /* Get LIBDIR. */
  60. #ifndef LIBDIR
  61. # include "configmake.h"
  62. #endif
  63. #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
  64. /* Win32, Cygwin, OS/2, DOS */
  65. # define ISSLASH(C) ((C) == '/' || (C) == '\\')
  66. #endif
  67. #ifndef DIRECTORY_SEPARATOR
  68. # define DIRECTORY_SEPARATOR '/'
  69. #endif
  70. #ifndef ISSLASH
  71. # define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR)
  72. #endif
  73. #if HAVE_DECL_GETC_UNLOCKED
  74. # undef getc
  75. # define getc getc_unlocked
  76. #endif
  77. /* The following static variable is declared 'volatile' to avoid a
  78. possible multithread problem in the function get_charset_aliases. If we
  79. are running in a threaded environment, and if two threads initialize
  80. 'charset_aliases' simultaneously, both will produce the same value,
  81. and everything will be ok if the two assignments to 'charset_aliases'
  82. are atomic. But I don't know what will happen if the two assignments mix. */
  83. #if __STDC__ != 1
  84. # define volatile /* empty */
  85. #endif
  86. /* Pointer to the contents of the charset.alias file, if it has already been
  87. read, else NULL. Its format is:
  88. ALIAS_1 '\0' CANONICAL_1 '\0' ... ALIAS_n '\0' CANONICAL_n '\0' '\0' */
  89. static const char * volatile charset_aliases;
  90. /* Return a pointer to the contents of the charset.alias file. */
  91. static const char *
  92. get_charset_aliases (void)
  93. {
  94. const char *cp;
  95. cp = charset_aliases;
  96. if (cp == NULL)
  97. {
  98. #if !(defined DARWIN7 || defined VMS || defined WIN32_NATIVE || defined __CYGWIN__)
  99. FILE *fp;
  100. const char *dir;
  101. const char *base = "charset.alias";
  102. char *file_name;
  103. /* Make it possible to override the charset.alias location. This is
  104. necessary for running the testsuite before "make install". */
  105. dir = getenv ("CHARSETALIASDIR");
  106. if (dir == NULL || dir[0] == '\0')
  107. dir = relocate (LIBDIR);
  108. /* Concatenate dir and base into freshly allocated file_name. */
  109. {
  110. size_t dir_len = strlen (dir);
  111. size_t base_len = strlen (base);
  112. int add_slash = (dir_len > 0 && !ISSLASH (dir[dir_len - 1]));
  113. file_name = (char *) malloc (dir_len + add_slash + base_len + 1);
  114. if (file_name != NULL)
  115. {
  116. memcpy (file_name, dir, dir_len);
  117. if (add_slash)
  118. file_name[dir_len] = DIRECTORY_SEPARATOR;
  119. memcpy (file_name + dir_len + add_slash, base, base_len + 1);
  120. }
  121. }
  122. if (file_name == NULL || (fp = fopen (file_name, "r")) == NULL)
  123. /* Out of memory or file not found, treat it as empty. */
  124. cp = "";
  125. else
  126. {
  127. /* Parse the file's contents. */
  128. char *res_ptr = NULL;
  129. size_t res_size = 0;
  130. for (;;)
  131. {
  132. int c;
  133. char buf1[50+1];
  134. char buf2[50+1];
  135. size_t l1, l2;
  136. char *old_res_ptr;
  137. c = getc (fp);
  138. if (c == EOF)
  139. break;
  140. if (c == '\n' || c == ' ' || c == '\t')
  141. continue;
  142. if (c == '#')
  143. {
  144. /* Skip comment, to end of line. */
  145. do
  146. c = getc (fp);
  147. while (!(c == EOF || c == '\n'));
  148. if (c == EOF)
  149. break;
  150. continue;
  151. }
  152. ungetc (c, fp);
  153. if (fscanf (fp, "%50s %50s", buf1, buf2) < 2)
  154. break;
  155. l1 = strlen (buf1);
  156. l2 = strlen (buf2);
  157. old_res_ptr = res_ptr;
  158. if (res_size == 0)
  159. {
  160. res_size = l1 + 1 + l2 + 1;
  161. res_ptr = (char *) malloc (res_size + 1);
  162. }
  163. else
  164. {
  165. res_size += l1 + 1 + l2 + 1;
  166. res_ptr = (char *) realloc (res_ptr, res_size + 1);
  167. }
  168. if (res_ptr == NULL)
  169. {
  170. /* Out of memory. */
  171. res_size = 0;
  172. if (old_res_ptr != NULL)
  173. free (old_res_ptr);
  174. break;
  175. }
  176. strcpy (res_ptr + res_size - (l2 + 1) - (l1 + 1), buf1);
  177. strcpy (res_ptr + res_size - (l2 + 1), buf2);
  178. }
  179. fclose (fp);
  180. if (res_size == 0)
  181. cp = "";
  182. else
  183. {
  184. *(res_ptr + res_size) = '\0';
  185. cp = res_ptr;
  186. }
  187. }
  188. if (file_name != NULL)
  189. free (file_name);
  190. #else
  191. # if defined DARWIN7
  192. /* To avoid the trouble of installing a file that is shared by many
  193. GNU packages -- many packaging systems have problems with this --,
  194. simply inline the aliases here. */
  195. cp = "ISO8859-1" "\0" "ISO-8859-1" "\0"
  196. "ISO8859-2" "\0" "ISO-8859-2" "\0"
  197. "ISO8859-4" "\0" "ISO-8859-4" "\0"
  198. "ISO8859-5" "\0" "ISO-8859-5" "\0"
  199. "ISO8859-7" "\0" "ISO-8859-7" "\0"
  200. "ISO8859-9" "\0" "ISO-8859-9" "\0"
  201. "ISO8859-13" "\0" "ISO-8859-13" "\0"
  202. "ISO8859-15" "\0" "ISO-8859-15" "\0"
  203. "KOI8-R" "\0" "KOI8-R" "\0"
  204. "KOI8-U" "\0" "KOI8-U" "\0"
  205. "CP866" "\0" "CP866" "\0"
  206. "CP949" "\0" "CP949" "\0"
  207. "CP1131" "\0" "CP1131" "\0"
  208. "CP1251" "\0" "CP1251" "\0"
  209. "eucCN" "\0" "GB2312" "\0"
  210. "GB2312" "\0" "GB2312" "\0"
  211. "eucJP" "\0" "EUC-JP" "\0"
  212. "eucKR" "\0" "EUC-KR" "\0"
  213. "Big5" "\0" "BIG5" "\0"
  214. "Big5HKSCS" "\0" "BIG5-HKSCS" "\0"
  215. "GBK" "\0" "GBK" "\0"
  216. "GB18030" "\0" "GB18030" "\0"
  217. "SJIS" "\0" "SHIFT_JIS" "\0"
  218. "ARMSCII-8" "\0" "ARMSCII-8" "\0"
  219. "PT154" "\0" "PT154" "\0"
  220. /*"ISCII-DEV" "\0" "?" "\0"*/
  221. "*" "\0" "UTF-8" "\0";
  222. # endif
  223. # if defined VMS
  224. /* To avoid the troubles of an extra file charset.alias_vms in the
  225. sources of many GNU packages, simply inline the aliases here. */
  226. /* The list of encodings is taken from the OpenVMS 7.3-1 documentation
  227. "Compaq C Run-Time Library Reference Manual for OpenVMS systems"
  228. section 10.7 "Handling Different Character Sets". */
  229. cp = "ISO8859-1" "\0" "ISO-8859-1" "\0"
  230. "ISO8859-2" "\0" "ISO-8859-2" "\0"
  231. "ISO8859-5" "\0" "ISO-8859-5" "\0"
  232. "ISO8859-7" "\0" "ISO-8859-7" "\0"
  233. "ISO8859-8" "\0" "ISO-8859-8" "\0"
  234. "ISO8859-9" "\0" "ISO-8859-9" "\0"
  235. /* Japanese */
  236. "eucJP" "\0" "EUC-JP" "\0"
  237. "SJIS" "\0" "SHIFT_JIS" "\0"
  238. "DECKANJI" "\0" "DEC-KANJI" "\0"
  239. "SDECKANJI" "\0" "EUC-JP" "\0"
  240. /* Chinese */
  241. "eucTW" "\0" "EUC-TW" "\0"
  242. "DECHANYU" "\0" "DEC-HANYU" "\0"
  243. "DECHANZI" "\0" "GB2312" "\0"
  244. /* Korean */
  245. "DECKOREAN" "\0" "EUC-KR" "\0";
  246. # endif
  247. # if defined WIN32_NATIVE || defined __CYGWIN__
  248. /* To avoid the troubles of installing a separate file in the same
  249. directory as the DLL and of retrieving the DLL's directory at
  250. runtime, simply inline the aliases here. */
  251. cp = "CP936" "\0" "GBK" "\0"
  252. "CP1361" "\0" "JOHAB" "\0"
  253. "CP20127" "\0" "ASCII" "\0"
  254. "CP20866" "\0" "KOI8-R" "\0"
  255. "CP20936" "\0" "GB2312" "\0"
  256. "CP21866" "\0" "KOI8-RU" "\0"
  257. "CP28591" "\0" "ISO-8859-1" "\0"
  258. "CP28592" "\0" "ISO-8859-2" "\0"
  259. "CP28593" "\0" "ISO-8859-3" "\0"
  260. "CP28594" "\0" "ISO-8859-4" "\0"
  261. "CP28595" "\0" "ISO-8859-5" "\0"
  262. "CP28596" "\0" "ISO-8859-6" "\0"
  263. "CP28597" "\0" "ISO-8859-7" "\0"
  264. "CP28598" "\0" "ISO-8859-8" "\0"
  265. "CP28599" "\0" "ISO-8859-9" "\0"
  266. "CP28605" "\0" "ISO-8859-15" "\0"
  267. "CP38598" "\0" "ISO-8859-8" "\0"
  268. "CP51932" "\0" "EUC-JP" "\0"
  269. "CP51936" "\0" "GB2312" "\0"
  270. "CP51949" "\0" "EUC-KR" "\0"
  271. "CP51950" "\0" "EUC-TW" "\0"
  272. "CP54936" "\0" "GB18030" "\0"
  273. "CP65001" "\0" "UTF-8" "\0";
  274. # endif
  275. #endif
  276. charset_aliases = cp;
  277. }
  278. return cp;
  279. }
  280. /* Determine the current locale's character encoding, and canonicalize it
  281. into one of the canonical names listed in config.charset.
  282. The result must not be freed; it is statically allocated.
  283. If the canonical name cannot be determined, the result is a non-canonical
  284. name. */
  285. #ifdef STATIC
  286. STATIC
  287. #endif
  288. const char *
  289. locale_charset (void)
  290. {
  291. const char *codeset;
  292. const char *aliases;
  293. #if !(defined WIN32_NATIVE || defined OS2)
  294. # if HAVE_LANGINFO_CODESET
  295. /* Most systems support nl_langinfo (CODESET) nowadays. */
  296. codeset = nl_langinfo (CODESET);
  297. # ifdef __CYGWIN__
  298. /* Cygwin 2006 does not have locales. nl_langinfo (CODESET) always
  299. returns "US-ASCII". As long as this is not fixed, return the suffix
  300. of the locale name from the environment variables (if present) or
  301. the codepage as a number. */
  302. if (codeset != NULL && strcmp (codeset, "US-ASCII") == 0)
  303. {
  304. const char *locale;
  305. static char buf[2 + 10 + 1];
  306. locale = getenv ("LC_ALL");
  307. if (locale == NULL || locale[0] == '\0')
  308. {
  309. locale = getenv ("LC_CTYPE");
  310. if (locale == NULL || locale[0] == '\0')
  311. locale = getenv ("LANG");
  312. }
  313. if (locale != NULL && locale[0] != '\0')
  314. {
  315. /* If the locale name contains an encoding after the dot, return
  316. it. */
  317. const char *dot = strchr (locale, '.');
  318. if (dot != NULL)
  319. {
  320. const char *modifier;
  321. dot++;
  322. /* Look for the possible @... trailer and remove it, if any. */
  323. modifier = strchr (dot, '@');
  324. if (modifier == NULL)
  325. return dot;
  326. if (modifier - dot < sizeof (buf))
  327. {
  328. memcpy (buf, dot, modifier - dot);
  329. buf [modifier - dot] = '\0';
  330. return buf;
  331. }
  332. }
  333. }
  334. /* Woe32 has a function returning the locale's codepage as a number. */
  335. sprintf (buf, "CP%u", GetACP ());
  336. codeset = buf;
  337. }
  338. # endif
  339. # else
  340. /* On old systems which lack it, use setlocale or getenv. */
  341. const char *locale = NULL;
  342. /* But most old systems don't have a complete set of locales. Some
  343. (like SunOS 4 or DJGPP) have only the C locale. Therefore we don't
  344. use setlocale here; it would return "C" when it doesn't support the
  345. locale name the user has set. */
  346. # if 0
  347. locale = setlocale (LC_CTYPE, NULL);
  348. # endif
  349. if (locale == NULL || locale[0] == '\0')
  350. {
  351. locale = getenv ("LC_ALL");
  352. if (locale == NULL || locale[0] == '\0')
  353. {
  354. locale = getenv ("LC_CTYPE");
  355. if (locale == NULL || locale[0] == '\0')
  356. locale = getenv ("LANG");
  357. }
  358. }
  359. /* On some old systems, one used to set locale = "iso8859_1". On others,
  360. you set it to "language_COUNTRY.charset". In any case, we resolve it
  361. through the charset.alias file. */
  362. codeset = locale;
  363. # endif
  364. #elif defined WIN32_NATIVE
  365. static char buf[2 + 10 + 1];
  366. /* Woe32 has a function returning the locale's codepage as a number. */
  367. sprintf (buf, "CP%u", GetACP ());
  368. codeset = buf;
  369. #elif defined OS2
  370. const char *locale;
  371. static char buf[2 + 10 + 1];
  372. ULONG cp[3];
  373. ULONG cplen;
  374. /* Allow user to override the codeset, as set in the operating system,
  375. with standard language environment variables. */
  376. locale = getenv ("LC_ALL");
  377. if (locale == NULL || locale[0] == '\0')
  378. {
  379. locale = getenv ("LC_CTYPE");
  380. if (locale == NULL || locale[0] == '\0')
  381. locale = getenv ("LANG");
  382. }
  383. if (locale != NULL && locale[0] != '\0')
  384. {
  385. /* If the locale name contains an encoding after the dot, return it. */
  386. const char *dot = strchr (locale, '.');
  387. if (dot != NULL)
  388. {
  389. const char *modifier;
  390. dot++;
  391. /* Look for the possible @... trailer and remove it, if any. */
  392. modifier = strchr (dot, '@');
  393. if (modifier == NULL)
  394. return dot;
  395. if (modifier - dot < sizeof (buf))
  396. {
  397. memcpy (buf, dot, modifier - dot);
  398. buf [modifier - dot] = '\0';
  399. return buf;
  400. }
  401. }
  402. /* Resolve through the charset.alias file. */
  403. codeset = locale;
  404. }
  405. else
  406. {
  407. /* OS/2 has a function returning the locale's codepage as a number. */
  408. if (DosQueryCp (sizeof (cp), cp, &cplen))
  409. codeset = "";
  410. else
  411. {
  412. sprintf (buf, "CP%u", cp[0]);
  413. codeset = buf;
  414. }
  415. }
  416. #endif
  417. if (codeset == NULL)
  418. /* The canonical name cannot be determined. */
  419. codeset = "";
  420. /* Resolve alias. */
  421. for (aliases = get_charset_aliases ();
  422. *aliases != '\0';
  423. aliases += strlen (aliases) + 1, aliases += strlen (aliases) + 1)
  424. if (strcmp (codeset, aliases) == 0
  425. || (aliases[0] == '*' && aliases[1] == '\0'))
  426. {
  427. codeset = aliases + strlen (aliases) + 1;
  428. break;
  429. }
  430. /* Don't return an empty string. GNU libc and GNU libiconv interpret
  431. the empty string as denoting "the locale's character encoding",
  432. thus GNU libiconv would call this function a second time. */
  433. if (codeset[0] == '\0')
  434. codeset = "ASCII";
  435. return codeset;
  436. }