/* Determine a canonical name for the current locale's character encoding.
- Copyright (C) 2000 Free Software Foundation, Inc.
+ Copyright (C) 2000-2002 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published
# define WIN32
#endif
-#ifndef WIN32
+#if defined __EMX__
+/* Assume EMX program runs on OS/2, even if compiled under DOS. */
+# define OS2
+#endif
+
+#if !defined WIN32
# if HAVE_LANGINFO_CODESET
# include <langinfo.h>
# else
# include <locale.h>
# endif
# endif
-#else /* WIN32 */
+#elif defined WIN32
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
#endif
+#if defined OS2
+# define INCL_DOS
+# include <os2.h>
+#endif
+
+#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
+ /* Win32, OS/2, DOS */
+# define ISSLASH(C) ((C) == '/' || (C) == '\\')
+#endif
#ifndef DIRECTORY_SEPARATOR
# define DIRECTORY_SEPARATOR '/'
# define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR)
#endif
+#ifdef HAVE_GETC_UNLOCKED
+# undef getc
+# define getc getc_unlocked
+#endif
+
/* The following static variable is declared 'volatile' to avoid a
possible multithread problem in the function get_charset_aliases. If we
are running in a threaded environment, and if two threads initialize
'charset_aliases' simultaneously, both will produce the same value,
and everything will be ok if the two assignments to 'charset_aliases'
are atomic. But I don't know what will happen if the two assignments mix. */
+#if __STDC__ != 1
+# define volatile /* empty */
+#endif
/* Pointer to the contents of the charset.alias file, if it has already been
read, else NULL. Its format is:
ALIAS_1 '\0' CANONICAL_1 '\0' ... ALIAS_n '\0' CANONICAL_n '\0' '\0' */
-static char * volatile charset_aliases;
+static const char * volatile charset_aliases;
/* Return a pointer to the contents of the charset.alias file. */
static const char *
get_charset_aliases ()
{
- char *cp;
+ const char *cp;
cp = charset_aliases;
if (cp == NULL)
{
-#ifndef WIN32
+#if !defined WIN32
FILE *fp;
const char *dir = LIBDIR;
const char *base = "charset.alias";
continue;
}
ungetc (c, fp);
- if (fscanf(fp, "%50s %50s", buf1, buf2) < 2)
+ if (fscanf (fp, "%50s %50s", buf1, buf2) < 2)
break;
l1 = strlen (buf1);
l2 = strlen (buf2);
if (res_size == 0)
{
res_size = l1 + 1 + l2 + 1;
- res_ptr = malloc (res_size + 1);
+ res_ptr = (char *) malloc (res_size + 1);
}
else
{
res_size += l1 + 1 + l2 + 1;
- res_ptr = realloc (res_ptr, res_size + 1);
+ res_ptr = (char *) realloc (res_ptr, res_size + 1);
}
if (res_ptr == NULL)
{
if (file_name != NULL)
free (file_name);
-#else /* WIN32 */
+#else
/* To avoid the troubles of installing a separate file in the same
directory as the DLL and of retrieving the DLL's directory at
runtime, simply inline the aliases here. */
+# if defined WIN32
cp = "CP936" "\0" "GBK" "\0"
"CP1361" "\0" "JOHAB" "\0";
+# endif
#endif
charset_aliases = cp;
into one of the canonical names listed in config.charset.
The result must not be freed; it is statically allocated.
If the canonical name cannot be determined, the result is a non-canonical
- name or NULL. */
+ name. */
#ifdef STATIC
STATIC
const char *codeset;
const char *aliases;
-#ifndef WIN32
+#if !(defined WIN32 || defined OS2)
# if HAVE_LANGINFO_CODESET
# else
- /* On old systems which lack it, use setlocale and getenv. */
+ /* On old systems which lack it, use setlocale or getenv. */
const char *locale = NULL;
-# if HAVE_SETLOCALE
+ /* But most old systems don't have a complete set of locales. Some
+ (like SunOS 4 or DJGPP) have only the C locale. Therefore we don't
+ use setlocale here; it would return "C" when it doesn't support the
+ locale name the user has set. */
+# if HAVE_SETLOCALE && 0
locale = setlocale (LC_CTYPE, NULL);
# endif
if (locale == NULL || locale[0] == '\0')
# endif
-#else /* WIN32 */
+#elif defined WIN32
static char buf[2 + 10 + 1];
sprintf (buf, "CP%u", GetACP ());
codeset = buf;
-#endif
+#elif defined OS2
- if (codeset != NULL && codeset[0] != '\0')
+ const char *locale;
+ static char buf[2 + 10 + 1];
+ ULONG cp[3];
+ ULONG cplen;
+
+ /* Allow user to override the codeset, as set in the operating system,
+ with standard language environment variables. */
+ locale = getenv ("LC_ALL");
+ if (locale == NULL || locale[0] == '\0')
{
- /* Resolve alias. */
- for (aliases = get_charset_aliases ();
- *aliases != '\0';
- aliases += strlen (aliases) + 1, aliases += strlen (aliases) + 1)
- if (!strcmp (codeset, aliases))
- {
- codeset = aliases + strlen (aliases) + 1;
- break;
- }
+ locale = getenv ("LC_CTYPE");
+ if (locale == NULL || locale[0] == '\0')
+ locale = getenv ("LANG");
}
+ if (locale != NULL && locale[0] != '\0')
+ {
+ /* If the locale name contains an encoding after the dot, return it. */
+ const char *dot = strchr (locale, '.');
+
+ if (dot != NULL)
+ {
+ const char *modifier;
+
+ dot++;
+ /* Look for the possible @... trailer and remove it, if any. */
+ modifier = strchr (dot, '@');
+ if (modifier == NULL)
+ return dot;
+ if (modifier - dot < sizeof (buf))
+ {
+ memcpy (buf, dot, modifier - dot);
+ buf [modifier - dot] = '\0';
+ return buf;
+ }
+ }
+
+ /* Resolve through the charset.alias file. */
+ codeset = locale;
+ }
+ else
+ {
+ /* OS/2 has a function returning the locale's codepage as a number. */
+ if (DosQueryCp (sizeof (cp), cp, &cplen))
+ codeset = "";
+ else
+ {
+ sprintf (buf, "CP%u", cp[0]);
+ codeset = buf;
+ }
+ }
+
+#endif
+
+ if (codeset == NULL)
+ /* The canonical name cannot be determined. */
+ codeset = "";
+
+ /* Resolve alias. */
+ for (aliases = get_charset_aliases ();
+ *aliases != '\0';
+ aliases += strlen (aliases) + 1, aliases += strlen (aliases) + 1)
+ if (strcmp (codeset, aliases) == 0
+ || (aliases[0] == '*' && aliases[1] == '\0'))
+ {
+ codeset = aliases + strlen (aliases) + 1;
+ break;
+ }
return codeset;
}