summaryrefslogtreecommitdiffstats
path: root/intl
diff options
context:
space:
mode:
Diffstat (limited to 'intl')
-rw-r--r--intl/explodename.c167
-rw-r--r--intl/l10nflist.c381
-rw-r--r--intl/loadinfo.h58
3 files changed, 606 insertions, 0 deletions
diff --git a/intl/explodename.c b/intl/explodename.c
new file mode 100644
index 0000000..2fd8be0
--- /dev/null
+++ b/intl/explodename.c
@@ -0,0 +1,167 @@
+/* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "loadinfo.h"
+
+int
+_nl_explode_name (name, language, modifier, territory, codeset,
+ normalized_codeset, special, sponsor, revision)
+ char *name;
+ const char **language;
+ const char **modifier;
+ const char **territory;
+ const char **codeset;
+ const char **normalized_codeset;
+ const char **special;
+ const char **sponsor;
+ const char **revision;
+{
+ enum { undecided, xpg, cen } syntax;
+ char *cp;
+ int mask;
+
+ *modifier = NULL;
+ *territory = NULL;
+ *codeset = NULL;
+ *normalized_codeset = NULL;
+ *special = NULL;
+ *sponsor = NULL;
+ *revision = NULL;
+
+ /* Now we determine the single parts of the locale name. First
+ look for the language. Termination symbols are `_' and `@' if
+ we use XPG4 style, and `_', `+', and `,' if we use CEN syntax. */
+ mask = 0;
+ syntax = undecided;
+ *language = cp = name;
+ while (cp[0] != '\0' && cp[0] != '_' && cp[0] != '@'
+ && cp[0] != '+' && cp[0] != ',')
+ ++cp;
+
+ if (*language == cp)
+ /* This does not make sense: language has to be specified. Use
+ this entry as it is without exploding. Perhaps it is an alias. */
+ cp = strchr (*language, '\0');
+ else if (cp[0] == '_')
+ {
+ /* Next is the territory. */
+ cp[0] = '\0';
+ *territory = ++cp;
+
+ while (cp[0] != '\0' && cp[0] != '.' && cp[0] != '@'
+ && cp[0] != '+' && cp[0] != ',' && cp[0] != '_')
+ ++cp;
+
+ mask |= TERRITORY;
+
+ if (cp[0] == '.')
+ {
+ /* Next is the codeset. */
+ syntax = xpg;
+ cp[0] = '\0';
+ *codeset = ++cp;
+
+ while (cp[0] != '\0' && cp[0] != '@')
+ ++cp;
+
+ mask |= XPG_CODESET;
+
+ if (*codeset != cp && (*codeset)[0] != '\0')
+ {
+ *normalized_codeset = _nl_normalize_codeset (*codeset,
+ cp - *codeset);
+ if (strcmp (*codeset, *normalized_codeset) == 0)
+ free ((char *) *normalized_codeset);
+ else
+ mask |= XPG_NORM_CODESET;
+ }
+ }
+ }
+
+ if (cp[0] == '@' || (syntax != xpg && cp[0] == '+'))
+ {
+ /* Next is the modifier. */
+ syntax = cp[0] == '@' ? xpg : cen;
+ cp[0] = '\0';
+ *modifier = ++cp;
+
+ while (syntax == cen && cp[0] != '\0' && cp[0] != '+'
+ && cp[0] != ',' && cp[0] != '_')
+ ++cp;
+
+ mask |= XPG_MODIFIER | CEN_AUDIENCE;
+ }
+
+ if (syntax != xpg && (cp[0] == '+' || cp[0] == ',' || cp[0] == '_'))
+ {
+ syntax = cen;
+
+ if (cp[0] == '+')
+ {
+ /* Next is special application (CEN syntax). */
+ cp[0] = '\0';
+ *special = ++cp;
+
+ while (cp[0] != '\0' && cp[0] != ',' && cp[0] != '_')
+ ++cp;
+
+ mask |= CEN_SPECIAL;
+ }
+
+ if (cp[0] == ',')
+ {
+ /* Next is sponsor (CEN syntax). */
+ cp[0] = '\0';
+ *sponsor = ++cp;
+
+ while (cp[0] != '\0' && cp[0] != '_')
+ ++cp;
+
+ mask |= CEN_SPONSOR;
+ }
+
+ if (cp[0] == '_')
+ {
+ /* Next is revision (CEN syntax). */
+ cp[0] = '\0';
+ *revision = ++cp;
+
+ mask |= CEN_REVISION;
+ }
+ }
+
+ /* For CEN sytnax values it might be important to have the
+ separator character in the file name, not for XPG syntax. */
+ if (syntax == xpg)
+ {
+ if (*territory != NULL && (*territory)[0] == '\0')
+ mask &= ~TERRITORY;
+
+ if (*codeset != NULL && (*codeset)[0] == '\0')
+ mask &= ~XPG_CODESET;
+
+ if (*modifier != NULL && (*modifier)[0] == '\0')
+ mask &= ~XPG_MODIFIER;
+ }
+
+ return mask;
+}
diff --git a/intl/l10nflist.c b/intl/l10nflist.c
new file mode 100644
index 0000000..4f955a9
--- /dev/null
+++ b/intl/l10nflist.c
@@ -0,0 +1,381 @@
+/* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined _LIBC && (defined __ARGZ_COUNT || defined __ARGZ_STRINGIFY)
+# include <argz.h>
+#endif
+#include <ctype.h>
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#endif
+
+#if defined HAVE_STRING_H || defined _LIBC
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+#if !HAVE_STRCHR && !defined _LIBC
+# ifndef strchr
+# define strchr index
+# endif
+#endif
+
+#include "loadinfo.h"
+
+/* @@ end of prolog @@ */
+
+#ifdef _LIBC
+/* Rename the non ANSI C functions. This is required by the standard
+ because some ANSI C functions will require linking with this object
+ file and the name space must not be polluted. */
+# define stpcpy(dest, src) __stpcpy(dest, src)
+#else
+# ifndef HAVE_STPCPY
+static char *stpcpy PARAMS ((char *dest, const char *src));
+# endif
+#endif
+
+/* Define function which are usually not available. */
+
+#if !defined _LIBC && !defined __ARGZ_COUNT
+/* Returns the number of strings in ARGZ. */
+static size_t __argz_count PARAMS ((const char *argz, size_t len));
+
+static size_t
+__argz_count (argz, len)
+ const char *argz;
+ size_t len;
+{
+ size_t count = 0;
+ while (len > 0)
+ {
+ size_t part_len = strlen (argz);
+ argz += part_len + 1;
+ len -= part_len + 1;
+ count++;
+ }
+ return count;
+}
+#endif /* !_LIBC && !__ARGZ_COUNT */
+
+#if !defined _LIBC && !defined __ARGZ_STRINGIFY
+/* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
+ except the last into the character SEP. */
+static void __argz_stringify PARAMS ((char *argz, size_t len, int sep));
+
+static void
+__argz_stringify (argz, len, sep)
+ char *argz;
+ size_t len;
+ int sep;
+{
+ while (len > 0)
+ {
+ size_t part_len = strlen (argz);
+ argz += part_len;
+ len -= part_len + 1;
+ if (len > 0)
+ *argz++ = sep;
+ }
+}
+#endif /* !_LIBC && !__ARGZ_COUNT */
+
+#if !defined _LIBC && !defined __ARGZ_NEXT
+static char *
+__argz_next (argz, argz_len, entry)
+ char *argz;
+ size_t argz_len;
+ const char *entry;
+{
+ if (entry)
+ {
+ if (entry < argz + argz_len)
+ entry = strchr (entry, '\0') + 1;
+
+ return entry >= argz + argz_len ? NULL : (char *) entry;
+ }
+ else
+ if (argz_len > 0)
+ return argz;
+ else
+ return 0;
+}
+#endif
+
+
+/* Return number of bits set in X. */
+static int pop PARAMS ((int x));
+
+static inline int
+pop (x)
+ int x;
+{
+ /* We assume that no more than 16 bits are used. */
+ x = ((x & ~0x5555) >> 1) + (x & 0x5555);
+ x = ((x & ~0x3333) >> 2) + (x & 0x3333);
+ x = ((x >> 4) + x) & 0x0f0f;
+ x = ((x >> 8) + x) & 0xff;
+
+ return x;
+}
+
+
+struct loaded_l10nfile *
+_nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
+ territory, codeset, normalized_codeset, modifier, special,
+ sponsor, revision, filename, do_allocate)
+ struct loaded_l10nfile **l10nfile_list;
+ const char *dirlist;
+ size_t dirlist_len;
+ int mask;
+ const char *language;
+ const char *territory;
+ const char *codeset;
+ const char *normalized_codeset;
+ const char *modifier;
+ const char *special;
+ const char *sponsor;
+ const char *revision;
+ const char *filename;
+ int do_allocate;
+{
+ char *abs_filename;
+ struct loaded_l10nfile *last = NULL;
+ struct loaded_l10nfile *retval;
+ char *cp;
+ size_t entries;
+ int cnt;
+
+ /* Allocate room for the full file name. */
+ abs_filename = (char *) malloc (dirlist_len
+ + strlen (language)
+ + ((mask & TERRITORY) != 0
+ ? strlen (territory) + 1 : 0)
+ + ((mask & XPG_CODESET) != 0
+ ? strlen (codeset) + 1 : 0)
+ + ((mask & XPG_NORM_CODESET) != 0
+ ? strlen (normalized_codeset) + 1 : 0)
+ + (((mask & XPG_MODIFIER) != 0
+ || (mask & CEN_AUDIENCE) != 0) ?
+ strlen (modifier) + 1 : 0)
+ + ((mask & CEN_SPECIAL) != 0
+ ? strlen (special) + 1 : 0)
+ + ((mask & CEN_SPONSOR) != 0
+ ? strlen (sponsor) + 1 : 0)
+ + ((mask & CEN_REVISION) != 0
+ ? strlen (revision) + 1 : 0)
+ + 1 + strlen (filename) + 1);
+
+ if (abs_filename == NULL)
+ return NULL;
+
+ retval = NULL;
+ last = NULL;
+
+ /* Construct file name. */
+ memcpy (abs_filename, dirlist, dirlist_len);
+ __argz_stringify (abs_filename, dirlist_len, ':');
+ cp = abs_filename + (dirlist_len - 1);
+ *cp++ = '/';
+ cp = stpcpy (cp, language);
+
+ if ((mask & TERRITORY) != 0)
+ {
+ *cp++ = '_';
+ cp = stpcpy (cp, territory);
+ }
+ if ((mask & XPG_CODESET) != 0)
+ {
+ *cp++ = '.';
+ cp = stpcpy (cp, codeset);
+ }
+ if ((mask & XPG_NORM_CODESET) != 0)
+ {
+ *cp++ = '.';
+ cp = stpcpy (cp, normalized_codeset);
+ }
+ if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0)
+ {
+ /* This component can be part of both syntaces but has different
+ leading characters. For CEN we use `+', else `@'. */
+ *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@';
+ cp = stpcpy (cp, modifier);
+ }
+ if ((mask & CEN_SPECIAL) != 0)
+ {
+ *cp++ = '+';
+ cp = stpcpy (cp, special);
+ }
+ if ((mask & CEN_SPONSOR) != 0)
+ {
+ *cp++ = ',';
+ cp = stpcpy (cp, sponsor);
+ }
+ if ((mask & CEN_REVISION) != 0)
+ {
+ *cp++ = '_';
+ cp = stpcpy (cp, revision);
+ }
+
+ *cp++ = '/';
+ stpcpy (cp, filename);
+
+ /* Look in list of already loaded domains whether it is already
+ available. */
+ last = NULL;
+ for (retval = *l10nfile_list; retval != NULL; retval = retval->next)
+ if (retval->filename != NULL)
+ {
+ int compare = strcmp (retval->filename, abs_filename);
+ if (compare == 0)
+ /* We found it! */
+ break;
+ if (compare < 0)
+ {
+ /* It's not in the list. */
+ retval = NULL;
+ break;
+ }
+
+ last = retval;
+ }
+
+ if (retval != NULL || do_allocate == 0)
+ {
+ free (abs_filename);
+ return retval;
+ }
+
+ retval = (struct loaded_l10nfile *)
+ malloc (sizeof (*retval) + (__argz_count (dirlist, dirlist_len)
+ * (1 << pop (mask))
+ * sizeof (struct loaded_l10nfile *)));
+ if (retval == NULL)
+ return NULL;
+
+ retval->filename = abs_filename;
+ retval->decided = (__argz_count (dirlist, dirlist_len) != 1
+ || ((mask & XPG_CODESET) != 0
+ && (mask & XPG_NORM_CODESET) != 0));
+ retval->data = NULL;
+
+ if (last == NULL)
+ {
+ retval->next = *l10nfile_list;
+ *l10nfile_list = retval;
+ }
+ else
+ {
+ retval->next = last->next;
+ last->next = retval;
+ }
+
+ entries = 0;
+ /* If the DIRLIST is a real list the RETVAL entry correcponds not to
+ a real file. So we have to use the DIRLIST separation machanism
+ of the inner loop. */
+ cnt = __argz_count (dirlist, dirlist_len) == 1 ? mask - 1 : mask;
+ for (; cnt >= 0; --cnt)
+ if ((cnt & ~mask) == 0
+ && ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0)
+ && ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0))
+ {
+ /* Iterate over all elements of the DIRLIST. */
+ char *dir = NULL;
+
+ while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir))
+ != NULL)
+ retval->successor[entries++]
+ = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, cnt,
+ language, territory, codeset,
+ normalized_codeset, modifier, special,
+ sponsor, revision, filename, 1);
+ }
+ retval->successor[entries] = NULL;
+
+ return retval;
+}
+
+/* Normalize codeset name. There is no standard for the codeset
+ names. Normalization allows the user to use any of the common
+ names. */
+const char *
+_nl_normalize_codeset (codeset, name_len)
+ const char *codeset;
+ size_t name_len;
+{
+ int len = 0;
+ int only_digit = 1;
+ char *retval;
+ char *wp;
+ size_t cnt;
+
+ for (cnt = 0; cnt < name_len; ++cnt)
+ if (isalnum (codeset[cnt]))
+ {
+ ++len;
+
+ if (isalpha (codeset[cnt]))
+ only_digit = 0;
+ }
+
+ retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
+
+ if (retval != NULL)
+ {
+ if (only_digit)
+ wp = stpcpy (retval, "ISO");
+ else
+ wp = retval;
+
+ for (cnt = 0; cnt < name_len; ++cnt)
+ if (isalpha (codeset[cnt]))
+ *wp++ = tolower (codeset[cnt]);
+ else if (isdigit (codeset[cnt]))
+ *wp++ = codeset[cnt];
+
+ *wp = '\0';
+ }
+
+ return (const char *) retval;
+}
+
+
+/* @@ begin of epilog @@ */
+
+/* We don't want libintl.a to depend on any other library. So we
+ avoid the non-standard function stpcpy. In GNU C Library this
+ function is available, though. Also allow the symbol HAVE_STPCPY
+ to be defined. */
+#if !_LIBC && !HAVE_STPCPY
+static char *
+stpcpy (dest, src)
+ char *dest;
+ const char *src;
+{
+ while ((*dest++ = *src++) != '\0')
+ /* Do nothing. */ ;
+ return dest - 1;
+}
+#endif
diff --git a/intl/loadinfo.h b/intl/loadinfo.h
new file mode 100644
index 0000000..c67c2eb
--- /dev/null
+++ b/intl/loadinfo.h
@@ -0,0 +1,58 @@
+#ifndef PARAMS
+# if __STDC__
+# define PARAMS(args) args
+# else
+# define PARAMS(args) ()
+# endif
+#endif
+
+/* Encoding of locale name parts. */
+#define CEN_REVISION 1
+#define CEN_SPONSOR 2
+#define CEN_SPECIAL 4
+#define XPG_NORM_CODESET 8
+#define XPG_CODESET 16
+#define TERRITORY 32
+#define CEN_AUDIENCE 64
+#define XPG_MODIFIER 128
+
+#define CEN_SPECIFIC (CEN_REVISION|CEN_SPONSOR|CEN_SPECIAL|CEN_AUDIENCE)
+#define XPG_SPECIFIC (XPG_CODESET|XPG_NORM_CODESET|XPG_MODIFIER)
+
+
+struct loaded_l10nfile
+{
+ const char *filename;
+ int decided;
+
+ const void *data;
+
+ struct loaded_l10nfile *next;
+ struct loaded_l10nfile *successor[1];
+};
+
+
+extern const char *_nl_normalize_codeset PARAMS ((const char *codeset,
+ size_t name_len));
+
+extern struct loaded_l10nfile *
+_nl_make_l10nflist PARAMS ((struct loaded_l10nfile **l10nfile_list,
+ const char *dirlist, size_t dirlist_len, int mask,
+ const char *language, const char *territory,
+ const char *codeset,
+ const char *normalized_codeset,
+ const char *modifier, const char *special,
+ const char *sponsor, const char *revision,
+ const char *filename, int do_allocate));
+
+
+extern const char *_nl_expand_alias PARAMS ((const char *name));
+
+extern int _nl_explode_name PARAMS ((char *name, const char **language,
+ const char **modifier,
+ const char **territory,
+ const char **codeset,
+ const char **normalized_codeset,
+ const char **special,
+ const char **sponsor,
+ const char **revision));