~jamesodhunt/ubuntu/raring/upstart/1.6

« back to all changes in this revision

Viewing changes to intl/dcigettext.c

  • Committer: Scott James Remnant
  • Date: 2010-02-04 23:39:59 UTC
  • mfrom: (1182.1.45 upstart)
  • mto: This revision was merged to the branch mainline in revision 1250.
  • Revision ID: scott@netsplit.com-20100204233959-7kajqjnaoh7208ob
Tags: upstream-0.6.5
ImportĀ upstreamĀ versionĀ 0.6.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* Implementation of the internal dcigettext function.
2
 
   Copyright (C) 1995-1999, 2000-2006 Free Software Foundation, Inc.
 
2
   Copyright (C) 1995-1999, 2000-2007 Free Software Foundation, Inc.
3
3
 
4
4
   This program is free software; you can redistribute it and/or modify it
5
5
   under the terms of the GNU Library General Public License as published
90
90
# include <sys/param.h>
91
91
#endif
92
92
 
93
 
#if !defined _LIBC && HAVE_NL_LOCALE_NAME
94
 
# include <langinfo.h>
 
93
#if !defined _LIBC
 
94
# if HAVE_NL_LOCALE_NAME
 
95
#  include <langinfo.h>
 
96
# endif
 
97
# include "localcharset.h"
95
98
#endif
96
99
 
97
100
#include "gettextP.h"
125
128
    ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
126
129
#endif
127
130
 
128
 
/* The internal variables in the standalone libintl.a must have different
129
 
   names than the internal variables in GNU libc, otherwise programs
130
 
   using libintl.a cannot be linked statically.  */
131
 
#if !defined _LIBC
132
 
# define _nl_default_default_domain libintl_nl_default_default_domain
133
 
# define _nl_current_default_domain libintl_nl_current_default_domain
134
 
# define _nl_default_dirname libintl_nl_default_dirname
135
 
# define _nl_domain_bindings libintl_nl_domain_bindings
136
 
#endif
137
 
 
138
131
/* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>.  */
139
132
#ifndef offsetof
140
133
# define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
170
163
# endif
171
164
#endif
172
165
 
 
166
/* Use a replacement if the system does not provide the `tsearch' function
 
167
   family.  */
 
168
#if HAVE_TSEARCH || defined _LIBC
 
169
# include <search.h>
 
170
#else
 
171
# define tsearch libintl_tsearch
 
172
# define tfind libintl_tfind
 
173
# define tdelete libintl_tdelete
 
174
# define twalk libintl_twalk
 
175
# include "tsearch.h"
 
176
#endif
 
177
 
 
178
#ifdef _LIBC
 
179
# define tsearch __tsearch
 
180
#endif
 
181
 
173
182
/* Amount to increase buffer size by in each try.  */
174
183
#define PATH_INCR 32
175
184
 
263
272
  char msgid[ZERO];
264
273
};
265
274
 
266
 
/* Root of the search tree with known translations.  We can use this
267
 
   only if the system provides the `tsearch' function family.  */
268
 
#if defined HAVE_TSEARCH || defined _LIBC
269
 
# include <search.h>
270
 
 
271
275
gl_rwlock_define_initialized (static, tree_lock)
272
276
 
 
277
/* Root of the search tree with known translations.  */
273
278
static void *root;
274
279
 
275
 
# ifdef _LIBC
276
 
#  define tsearch __tsearch
277
 
# endif
278
 
 
279
280
/* Function to compare two entries in the table of known translations.  */
280
281
static int
281
282
transcmp (const void *p1, const void *p2)
312
313
 
313
314
  return result;
314
315
}
315
 
#endif
316
316
 
317
317
/* Name of the default domain used for gettext(3) prior any call to
318
318
   textdomain(3).  The default value for this is "messages".  */
501
501
  char *retval;
502
502
  size_t retlen;
503
503
  int saved_errno;
504
 
#if defined HAVE_TSEARCH || defined _LIBC
505
504
  struct known_translation_t *search;
506
505
  struct known_translation_t **foundp = NULL;
507
506
  size_t msgid_len;
508
 
# if defined HAVE_PER_THREAD_LOCALE && !defined IN_LIBGLOCALE
 
507
#if defined HAVE_PER_THREAD_LOCALE && !defined IN_LIBGLOCALE
509
508
  const char *localename;
510
 
# endif
511
509
#endif
512
510
  size_t domainname_len;
513
511
 
524
522
            : n == 1 ? (char *) msgid1 : (char *) msgid2);
525
523
#endif
526
524
 
 
525
  /* Preserve the `errno' value.  */
 
526
  saved_errno = errno;
 
527
 
527
528
  gl_rwlock_rdlock (_nl_state_lock);
528
529
 
529
530
  /* If DOMAINNAME is NULL, we are interested in the default domain.  If
538
539
    category = LC_MESSAGES;
539
540
#endif
540
541
 
541
 
#if defined HAVE_TSEARCH || defined _LIBC
542
542
  msgid_len = strlen (msgid1) + 1;
543
543
 
544
544
  /* Try to find the translation among those which we found at
548
548
  memcpy (search->msgid, msgid1, msgid_len);
549
549
  search->domainname = domainname;
550
550
  search->category = category;
551
 
# ifdef HAVE_PER_THREAD_LOCALE
552
 
#  ifndef IN_LIBGLOCALE
553
 
#   ifdef _LIBC
 
551
#ifdef HAVE_PER_THREAD_LOCALE
 
552
# ifndef IN_LIBGLOCALE
 
553
#  ifdef _LIBC
554
554
  localename = __current_locale_name (category);
555
 
#   else
556
 
#    if HAVE_NL_LOCALE_NAME
 
555
#  else
 
556
#   if HAVE_NL_LOCALE_NAME
557
557
  /* NL_LOCALE_NAME is public glibc API introduced in glibc-2.4.  */
558
558
  localename = nl_langinfo (NL_LOCALE_NAME (category));
559
 
#    else
560
 
#     if HAVE_STRUCT___LOCALE_STRUCT___NAMES && defined USE_IN_GETTEXT_TESTS
 
559
#   else
 
560
#    if HAVE_STRUCT___LOCALE_STRUCT___NAMES && defined USE_IN_GETTEXT_TESTS
561
561
  /* The __names field is not public glibc API and must therefore not be used
562
562
     in code that is installed in public locations.  */
563
563
  {
567
567
    else
568
568
      localename = "";
569
569
  }
570
 
#     endif
571
570
#    endif
572
571
#   endif
573
572
#  endif
 
573
# endif
574
574
  search->localename = localename;
575
 
#  ifdef IN_LIBGLOCALE
 
575
# ifdef IN_LIBGLOCALE
576
576
  search->encoding = encoding;
577
 
#  endif
578
577
# endif
579
578
 
580
579
  /* Since tfind/tsearch manage a balanced tree, concurrent tfind and
596
595
        retval = (char *) (*foundp)->translation;
597
596
 
598
597
      gl_rwlock_unlock (_nl_state_lock);
 
598
      __set_errno (saved_errno);
599
599
      return retval;
600
600
    }
601
601
#endif
602
602
 
603
 
  /* Preserve the `errno' value.  */
604
 
  saved_errno = errno;
605
 
 
606
603
  /* See whether this is a SUID binary or not.  */
607
604
  DETERMINE_SECURE;
608
605
 
683
680
                                 + domainname_len + 5);
684
681
  ADD_BLOCK (block_list, xdomainname);
685
682
 
686
 
  stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
687
 
                  domainname, domainname_len),
 
683
  stpcpy ((char *) mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
 
684
                            domainname, domainname_len),
688
685
          ".mo");
689
686
 
690
687
  /* Creating working area.  */
773
770
              /* Found the translation of MSGID1 in domain DOMAIN:
774
771
                 starting at RETVAL, RETLEN bytes.  */
775
772
              FREE_BLOCKS (block_list);
776
 
#if defined HAVE_TSEARCH || defined _LIBC
777
773
              if (foundp == NULL)
778
774
                {
779
775
                  /* Create a new entry and add it to the search tree.  */
782
778
 
783
779
                  size = offsetof (struct known_translation_t, msgid)
784
780
                         + msgid_len + domainname_len + 1;
785
 
# ifdef HAVE_PER_THREAD_LOCALE
 
781
#ifdef HAVE_PER_THREAD_LOCALE
786
782
                  size += strlen (localename) + 1;
787
 
# endif
 
783
#endif
788
784
                  newp = (struct known_translation_t *) malloc (size);
789
785
                  if (newp != NULL)
790
786
                    {
791
787
                      char *new_domainname;
792
 
# ifdef HAVE_PER_THREAD_LOCALE
 
788
#ifdef HAVE_PER_THREAD_LOCALE
793
789
                      char *new_localename;
794
 
# endif
 
790
#endif
795
791
 
796
 
                      new_domainname = mempcpy (newp->msgid, msgid1, msgid_len);
 
792
                      new_domainname =
 
793
                        (char *) mempcpy (newp->msgid, msgid1, msgid_len);
797
794
                      memcpy (new_domainname, domainname, domainname_len + 1);
798
 
# ifdef HAVE_PER_THREAD_LOCALE
 
795
#ifdef HAVE_PER_THREAD_LOCALE
799
796
                      new_localename = new_domainname + domainname_len + 1;
800
797
                      strcpy (new_localename, localename);
801
 
# endif
 
798
#endif
802
799
                      newp->domainname = new_domainname;
803
800
                      newp->category = category;
804
 
# ifdef HAVE_PER_THREAD_LOCALE
 
801
#ifdef HAVE_PER_THREAD_LOCALE
805
802
                      newp->localename = new_localename;
806
 
# endif
807
 
# ifdef IN_LIBGLOCALE
 
803
#endif
 
804
#ifdef IN_LIBGLOCALE
808
805
                      newp->encoding = encoding;
809
 
# endif
 
806
#endif
810
807
                      newp->counter = _nl_msg_cat_cntr;
811
808
                      newp->domain = domain;
812
809
                      newp->translation = retval;
834
831
                  (*foundp)->translation = retval;
835
832
                  (*foundp)->translation_length = retlen;
836
833
                }
837
 
#endif
 
834
 
838
835
              __set_errno (saved_errno);
839
836
 
840
837
              /* Now deal with plural.  */
1005
1002
# ifndef IN_LIBGLOCALE
1006
1003
      const char *encoding = get_output_charset (domainbinding);
1007
1004
# endif
 
1005
      size_t nconversions;
 
1006
      struct converted_domain *convd;
 
1007
      size_t i;
 
1008
 
 
1009
      /* Protect against reallocation of the table.  */
 
1010
      gl_rwlock_rdlock (domain->conversions_lock);
1008
1011
 
1009
1012
      /* Search whether a table with converted translations for this
1010
1013
         encoding has already been allocated.  */
1011
 
      size_t nconversions = domain->nconversions;
1012
 
      struct converted_domain *convd = NULL;
1013
 
      size_t i;
 
1014
      nconversions = domain->nconversions;
 
1015
      convd = NULL;
1014
1016
 
1015
1017
      for (i = nconversions; i > 0; )
1016
1018
        {
1022
1024
            }
1023
1025
        }
1024
1026
 
 
1027
      gl_rwlock_unlock (domain->conversions_lock);
 
1028
 
1025
1029
      if (convd == NULL)
1026
1030
        {
1027
 
          /* Allocate a table for the converted translations for this
1028
 
             encoding.  */
1029
 
          struct converted_domain *new_conversions =
1030
 
            (struct converted_domain *)
1031
 
            (domain->conversions != NULL
1032
 
             ? realloc (domain->conversions,
1033
 
                        (nconversions + 1) * sizeof (struct converted_domain))
1034
 
             : malloc ((nconversions + 1) * sizeof (struct converted_domain)));
1035
 
 
1036
 
          if (__builtin_expect (new_conversions == NULL, 0))
1037
 
            /* Nothing we can do, no more memory.  We cannot use the
1038
 
               translation because it might be encoded incorrectly.  */
1039
 
            return (char *) -1;
1040
 
 
1041
 
          domain->conversions = new_conversions;
1042
 
 
1043
 
          /* Copy the 'encoding' string to permanent storage.  */
1044
 
          encoding = strdup (encoding);
1045
 
          if (__builtin_expect (encoding == NULL, 0))
1046
 
            /* Nothing we can do, no more memory.  We cannot use the
1047
 
               translation because it might be encoded incorrectly.  */
1048
 
            return (char *) -1;
1049
 
 
1050
 
          convd = &new_conversions[nconversions];
1051
 
          convd->encoding = encoding;
1052
 
 
1053
 
          /* Find out about the character set the file is encoded with.
1054
 
             This can be found (in textual form) in the entry "".  If this
1055
 
             entry does not exist or if this does not contain the 'charset='
1056
 
             information, we will assume the charset matches the one the
1057
 
             current locale and we don't have to perform any conversion.  */
1058
 
# ifdef _LIBC
1059
 
          convd->conv = (__gconv_t) -1;
1060
 
# else
1061
 
#  if HAVE_ICONV
1062
 
          convd->conv = (iconv_t) -1;
1063
 
#  endif
1064
 
# endif
 
1031
          /* We have to allocate a new conversions table.  */
 
1032
          gl_rwlock_wrlock (domain->conversions_lock);
 
1033
 
 
1034
          /* Maybe in the meantime somebody added the translation.
 
1035
             Recheck.  */
 
1036
          for (i = nconversions; i > 0; )
 
1037
            {
 
1038
              i--;
 
1039
              if (strcmp (domain->conversions[i].encoding, encoding) == 0)
 
1040
                {
 
1041
                  convd = &domain->conversions[i];
 
1042
                  goto found_convd;
 
1043
                }
 
1044
            }
 
1045
 
1065
1046
          {
1066
 
            char *nullentry;
1067
 
            size_t nullentrylen;
1068
 
 
1069
 
            /* Get the header entry.  This is a recursion, but it doesn't
1070
 
               reallocate domain->conversions because we pass
1071
 
               encoding = NULL or convert = 0, respectively.  */
1072
 
            nullentry =
1073
 
# ifdef IN_LIBGLOCALE
1074
 
              _nl_find_msg (domain_file, domainbinding, NULL, "",
1075
 
                            &nullentrylen);
1076
 
# else
1077
 
              _nl_find_msg (domain_file, domainbinding, "", 0, &nullentrylen);
1078
 
# endif
1079
 
 
1080
 
            if (nullentry != NULL)
 
1047
            /* Allocate a table for the converted translations for this
 
1048
               encoding.  */
 
1049
            struct converted_domain *new_conversions =
 
1050
              (struct converted_domain *)
 
1051
              (domain->conversions != NULL
 
1052
               ? realloc (domain->conversions,
 
1053
                          (nconversions + 1) * sizeof (struct converted_domain))
 
1054
               : malloc ((nconversions + 1) * sizeof (struct converted_domain)));
 
1055
 
 
1056
            if (__builtin_expect (new_conversions == NULL, 0))
1081
1057
              {
1082
 
                const char *charsetstr;
1083
 
 
1084
 
                charsetstr = strstr (nullentry, "charset=");
1085
 
                if (charsetstr != NULL)
1086
 
                  {
1087
 
                    size_t len;
1088
 
                    char *charset;
1089
 
                    const char *outcharset;
1090
 
 
1091
 
                    charsetstr += strlen ("charset=");
1092
 
                    len = strcspn (charsetstr, " \t\n");
1093
 
 
1094
 
                    charset = (char *) alloca (len + 1);
 
1058
                /* Nothing we can do, no more memory.  We cannot use the
 
1059
                   translation because it might be encoded incorrectly.  */
 
1060
              unlock_fail:
 
1061
                gl_rwlock_unlock (domain->conversions_lock);
 
1062
                return (char *) -1;
 
1063
              }
 
1064
 
 
1065
            domain->conversions = new_conversions;
 
1066
 
 
1067
            /* Copy the 'encoding' string to permanent storage.  */
 
1068
            encoding = strdup (encoding);
 
1069
            if (__builtin_expect (encoding == NULL, 0))
 
1070
              /* Nothing we can do, no more memory.  We cannot use the
 
1071
                 translation because it might be encoded incorrectly.  */
 
1072
              goto unlock_fail;
 
1073
 
 
1074
            convd = &new_conversions[nconversions];
 
1075
            convd->encoding = encoding;
 
1076
 
 
1077
            /* Find out about the character set the file is encoded with.
 
1078
               This can be found (in textual form) in the entry "".  If this
 
1079
               entry does not exist or if this does not contain the 'charset='
 
1080
               information, we will assume the charset matches the one the
 
1081
               current locale and we don't have to perform any conversion.  */
 
1082
# ifdef _LIBC
 
1083
            convd->conv = (__gconv_t) -1;
 
1084
# else
 
1085
#  if HAVE_ICONV
 
1086
            convd->conv = (iconv_t) -1;
 
1087
#  endif
 
1088
# endif
 
1089
            {
 
1090
              char *nullentry;
 
1091
              size_t nullentrylen;
 
1092
 
 
1093
              /* Get the header entry.  This is a recursion, but it doesn't
 
1094
                 reallocate domain->conversions because we pass
 
1095
                 encoding = NULL or convert = 0, respectively.  */
 
1096
              nullentry =
 
1097
# ifdef IN_LIBGLOCALE
 
1098
                _nl_find_msg (domain_file, domainbinding, NULL, "",
 
1099
                              &nullentrylen);
 
1100
# else
 
1101
                _nl_find_msg (domain_file, domainbinding, "", 0, &nullentrylen);
 
1102
# endif
 
1103
 
 
1104
              if (nullentry != NULL)
 
1105
                {
 
1106
                  const char *charsetstr;
 
1107
 
 
1108
                  charsetstr = strstr (nullentry, "charset=");
 
1109
                  if (charsetstr != NULL)
 
1110
                    {
 
1111
                      size_t len;
 
1112
                      char *charset;
 
1113
                      const char *outcharset;
 
1114
 
 
1115
                      charsetstr += strlen ("charset=");
 
1116
                      len = strcspn (charsetstr, " \t\n");
 
1117
 
 
1118
                      charset = (char *) alloca (len + 1);
1095
1119
# if defined _LIBC || HAVE_MEMPCPY
1096
 
                    *((char *) mempcpy (charset, charsetstr, len)) = '\0';
 
1120
                      *((char *) mempcpy (charset, charsetstr, len)) = '\0';
1097
1121
# else
1098
 
                    memcpy (charset, charsetstr, len);
1099
 
                    charset[len] = '\0';
 
1122
                      memcpy (charset, charsetstr, len);
 
1123
                      charset[len] = '\0';
1100
1124
# endif
1101
1125
 
1102
 
                    outcharset = encoding;
 
1126
                      outcharset = encoding;
1103
1127
 
1104
1128
# ifdef _LIBC
1105
 
                    /* We always want to use transliteration.  */
1106
 
                    outcharset = norm_add_slashes (outcharset, "TRANSLIT");
1107
 
                    charset = norm_add_slashes (charset, "");
1108
 
                    int r = __gconv_open (outcharset, charset, &convd->conv,
1109
 
                                          GCONV_AVOID_NOCONV);
1110
 
                    if (__builtin_expect (r != __GCONV_OK, 0))
1111
 
                      {
1112
 
                        /* If the output encoding is the same there is
1113
 
                           nothing to do.  Otherwise do not use the
1114
 
                           translation at all.  */
1115
 
                        if (__builtin_expect (r != __GCONV_NOCONV, 1))
1116
 
                          return NULL;
 
1129
                      /* We always want to use transliteration.  */
 
1130
                      outcharset = norm_add_slashes (outcharset, "TRANSLIT");
 
1131
                      charset = norm_add_slashes (charset, "");
 
1132
                      int r = __gconv_open (outcharset, charset, &convd->conv,
 
1133
                                            GCONV_AVOID_NOCONV);
 
1134
                      if (__builtin_expect (r != __GCONV_OK, 0))
 
1135
                        {
 
1136
                          /* If the output encoding is the same there is
 
1137
                             nothing to do.  Otherwise do not use the
 
1138
                             translation at all.  */
 
1139
                          if (__builtin_expect (r != __GCONV_NULCONV, 1))
 
1140
                            {
 
1141
                              gl_rwlock_unlock (domain->conversions_lock);
 
1142
                              free ((char *) encoding);
 
1143
                              return NULL;
 
1144
                            }
1117
1145
 
1118
 
                        convd->conv = (__gconv_t) -1;
1119
 
                      }
 
1146
                          convd->conv = (__gconv_t) -1;
 
1147
                        }
1120
1148
# else
1121
1149
#  if HAVE_ICONV
1122
 
                    /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5,
1123
 
                       we want to use transliteration.  */
 
1150
                      /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5,
 
1151
                         we want to use transliteration.  */
1124
1152
#   if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \
1125
1153
       || _LIBICONV_VERSION >= 0x0105
1126
 
                    if (strchr (outcharset, '/') == NULL)
1127
 
                      {
1128
 
                        char *tmp;
1129
 
 
1130
 
                        len = strlen (outcharset);
1131
 
                        tmp = (char *) alloca (len + 10 + 1);
1132
 
                        memcpy (tmp, outcharset, len);
1133
 
                        memcpy (tmp + len, "//TRANSLIT", 10 + 1);
1134
 
                        outcharset = tmp;
1135
 
 
 
1154
                      if (strchr (outcharset, '/') == NULL)
 
1155
                        {
 
1156
                          char *tmp;
 
1157
 
 
1158
                          len = strlen (outcharset);
 
1159
                          tmp = (char *) alloca (len + 10 + 1);
 
1160
                          memcpy (tmp, outcharset, len);
 
1161
                          memcpy (tmp + len, "//TRANSLIT", 10 + 1);
 
1162
                          outcharset = tmp;
 
1163
 
 
1164
                          convd->conv = iconv_open (outcharset, charset);
 
1165
 
 
1166
                          freea (outcharset);
 
1167
                        }
 
1168
                      else
 
1169
#   endif
1136
1170
                        convd->conv = iconv_open (outcharset, charset);
1137
 
 
1138
 
                        freea (outcharset);
1139
 
                      }
1140
 
                    else
1141
 
#   endif
1142
 
                      convd->conv = iconv_open (outcharset, charset);
1143
1171
#  endif
1144
1172
# endif
1145
1173
 
1146
 
                    freea (charset);
1147
 
                  }
1148
 
              }
 
1174
                      freea (charset);
 
1175
                    }
 
1176
                }
 
1177
            }
 
1178
            convd->conv_tab = NULL;
 
1179
            /* Here domain->conversions is still == new_conversions.  */
 
1180
            domain->nconversions++;
1149
1181
          }
1150
 
          convd->conv_tab = NULL;
1151
 
          /* Here domain->conversions is still == new_conversions.  */
1152
 
          domain->nconversions++;
 
1182
 
 
1183
        found_convd:
 
1184
          gl_rwlock_unlock (domain->conversions_lock);
1153
1185
        }
1154
1186
 
1155
1187
      if (
1584
1616
          return _NL_CURRENT (LC_CTYPE, CODESET);
1585
1617
# else
1586
1618
#  if HAVE_ICONV
1587
 
          extern const char *locale_charset (void);
1588
1619
          return locale_charset ();
1589
1620
#  endif
1590
1621
# endif
1617
1648
}
1618
1649
#endif
1619
1650
 
 
1651
#if !_LIBC && !HAVE_TSEARCH
 
1652
# include "tsearch.c"
 
1653
#endif
 
1654
 
1620
1655
 
1621
1656
#ifdef _LIBC
1622
1657
/* If we want to free all resources we have to do some work at