Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  pg_localeconv_r.c

  Sprache: C
 

/*-------------------------------------------------------------------------
 *
 * pg_localeconv_r.c
 *    Thread-safe implementations of localeconv()
 *
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *    src/port/pg_localeconv_r.c
 *
 *-------------------------------------------------------------------------
 */


#include "c.h"

#if !defined(WIN32)
#include <langinfo.h>
#include <pthread.h>
#endif

#include <limits.h>

#ifdef MON_THOUSANDS_SEP
/*
 * One of glibc's extended langinfo items detected.  Assume that the full set
 * is present, which means we can use nl_langinfo_l() instead of localeconv().
 */

#define TRANSLATE_FROM_LANGINFO
#endif

struct lconv_member_info
{
 bool  is_string;
 int   category;
 size_t  offset;
#ifdef TRANSLATE_FROM_LANGINFO
 nl_item  item;
#endif
};

/* Some macros to declare the lconv members compactly. */
#ifdef TRANSLATE_FROM_LANGINFO
#define LCONV_M(is_string, category, name, item)      \
 { is_string, category, offsetof(struct lconv, name), item }
#else
#define LCONV_M(is_string, category, name, item)   \
 { is_string, category, offsetof(struct lconv, name) }
#endif
#define LCONV_S(c, n, i) LCONV_M(true,  c, n, i)
#define LCONV_C(c, n, i) LCONV_M(false, c, n, i)

/*
 * The work of populating lconv objects is driven by this table.  Since we
 * tolerate non-matching encodings in LC_NUMERIC and LC_MONETARY, we have to
 * call the underlying OS routine multiple times, with the correct locales.
 * The first column of this table says which locale category applies to each struct
 * member.  The second column is the name of the struct member.  The third
 * column is the name of the nl_item, if translating from nl_langinfo_l() (it's
 * always the member name, in upper case).
 */

static const struct lconv_member_info table[] = {
 /* String fields. */
 LCONV_S(LC_NUMERIC, decimal_point, DECIMAL_POINT),
 LCONV_S(LC_NUMERIC, thousands_sep, THOUSANDS_SEP),
 LCONV_S(LC_NUMERIC, grouping, GROUPING),
 LCONV_S(LC_MONETARY, int_curr_symbol, INT_CURR_SYMBOL),
 LCONV_S(LC_MONETARY, currency_symbol, CURRENCY_SYMBOL),
 LCONV_S(LC_MONETARY, mon_decimal_point, MON_DECIMAL_POINT),
 LCONV_S(LC_MONETARY, mon_thousands_sep, MON_THOUSANDS_SEP),
 LCONV_S(LC_MONETARY, mon_grouping, MON_GROUPING),
 LCONV_S(LC_MONETARY, positive_sign, POSITIVE_SIGN),
 LCONV_S(LC_MONETARY, negative_sign, NEGATIVE_SIGN),

 /* Character fields. */
 LCONV_C(LC_MONETARY, int_frac_digits, INT_FRAC_DIGITS),
 LCONV_C(LC_MONETARY, frac_digits, FRAC_DIGITS),
 LCONV_C(LC_MONETARY, p_cs_precedes, P_CS_PRECEDES),
 LCONV_C(LC_MONETARY, p_sep_by_space, P_SEP_BY_SPACE),
 LCONV_C(LC_MONETARY, n_cs_precedes, N_CS_PRECEDES),
 LCONV_C(LC_MONETARY, n_sep_by_space, N_SEP_BY_SPACE),
 LCONV_C(LC_MONETARY, p_sign_posn, P_SIGN_POSN),
 LCONV_C(LC_MONETARY, n_sign_posn, N_SIGN_POSN),
};

static inline char **
lconv_string_member(struct lconv *lconv, int i)
{
 return (char **) ((char *) lconv + table[i].offset);
}

static inline char *
lconv_char_member(struct lconv *lconv, int i)
{
 return (char *) lconv + table[i].offset;
}

/*
 * Free the members of a struct lconv populated by pg_localeconv_r().  The
 * struct itself is in storage provided by the caller of pg_localeconv_r().
 */

void
pg_localeconv_free(struct lconv *lconv)
{
 for (int i = 0; i < lengthof(table); ++i)
  if (table[i].is_string)
   free(*lconv_string_member(lconv, i));
}

#ifdef TRANSLATE_FROM_LANGINFO
/*
 * Fill in struct lconv members using the equivalent nl_langinfo_l() items.
 */

static int
pg_localeconv_from_langinfo(struct lconv *dst,
       locale_t monetary_locale,
       locale_t numeric_locale)
{
 for (int i = 0; i < lengthof(table); ++i)
 {
  locale_t locale;

  locale = table[i].category == LC_NUMERIC ?
   numeric_locale : monetary_locale;

  if (table[i].is_string)
  {
   char    *string;

   string = nl_langinfo_l(table[i].item, locale);
   if (!(string = strdup(string)))
   {
    pg_localeconv_free(dst);
    errno = ENOMEM;
    return -1;
   }
   *lconv_string_member(dst, i) = string;
  }
  else
  {
   *lconv_char_member(dst, i) =
    *nl_langinfo_l(table[i].item, locale);
  }
 }

 return 0;
}
#else       /* not TRANSLATE_FROM_LANGINFO */
/*
 * Copy members from a given category.  Note that you have to call this twice
 * to copy the LC_MONETARY and then LC_NUMERIC members.
 */

static int
pg_localeconv_copy_members(struct lconv *dst,
         struct lconv *src,
         int category)
{
 for (int i = 0; i < lengthof(table); ++i)
 {
  if (table[i].category != category)
   continue;

  if (table[i].is_string)
  {
   char    *string;

   string = *lconv_string_member(src, i);
   if (!(string = strdup(string)))
   {
    pg_localeconv_free(dst);
    errno = ENOMEM;
    return -1;
   }
   *lconv_string_member(dst, i) = string;
  }
  else
  {
   *lconv_char_member(dst, i) = *lconv_char_member(src, i);
  }
 }

 return 0;
}
#endif       /* not TRANSLATE_FROM_LANGINFO */

/*
 * A thread-safe routine to get a copy of the lconv struct for a given
 * LC_NUMERIC and LC_MONETARY.  Different approaches are used on different
 * OSes, because the standard interface is so multi-threading unfriendly.
 *
 * 1.  On Windows, there is no uselocale(), but there is a way to put
 * setlocale() into a thread-local mode temporarily.  Its localeconv() is
 * documented as returning a pointer to thread-local storage, so we don't have
 * to worry about concurrent callers.
 *
 * 2.  On Glibc, as an extension, all the information required to populate
 * struct lconv is also available via nl_langpath_l(), which is thread-safe.
 *
 * 3.  On macOS and *BSD, there is localeconv_l(), so we can create a temporary
 * locale_t to pass in, and the result is a pointer to storage associated with
 * the locale_t so we control its lifetime and we don't have to worry about
 * concurrent calls clobbering it.
 *
 * 4.  Otherwise, we wrap plain old localeconv() in uselocale() to avoid
 * touching the global locale, but the output buffer is allowed by the standard
 * to be overwritten by concurrent calls to localeconv().  We protect against
 * _this_ function doing that with a Big Lock, but there isn't much we can do
 * about code outside our tree that might call localeconv(), given such a poor
 * interface.
 *
 * The POSIX standard explicitly says that it is undefined what happens if
 * LC_MONETARY or LC_NUMERIC imply an encoding (codeset) different from that
 * implied by LC_CTYPE.  In practice, all Unix-ish platforms seem to believe
 * that localeconv() should return strings that are encoded in the codeset
 * implied by the LC_MONETARY or LC_NUMERIC locale name.  On Windows, LC_CTYPE
 * has to match to get sane results.
 *
 * To get predictable results on all platforms, we'll call the underlying
 * routines with LC_ALL set to the appropriate locale for each set of members,
 * and merge the results.  Three members of the resulting object are therefore
 * guaranteed to be encoded with LC_NUMERIC's codeset: "decimal_point",
 * "thousands_sep" and "grouping".  All other members are encoded with
 * LC_MONETARY's codeset.
 *
 * Returns 0 on success.  Returns non-zero on failure, and sets errno.  On
 * success, the caller is responsible for calling pg_localeconv_free() on the
 * output struct to free the string members it contains.
 */

int
pg_localeconv_r(const char *lc_monetary,
    const char *lc_numeric,
    struct lconv *output)
{
#ifdef WIN32
 wchar_t    *save_lc_ctype = NULL;
 wchar_t    *save_lc_monetary = NULL;
 wchar_t    *save_lc_numeric = NULL;
 int   save_config_thread_locale;
 int   result = -1;

 /* Put setlocale() into thread-local mode. */
 save_config_thread_locale = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);

 /*
  * Capture the current values as wide strings.  Otherwise, we might not be
  * able to restore them if their names contain non-ASCII characters and
  * the intermediate locale changes the expected encoding.  We don't want
  * to leave the caller in an unexpected state by failing to restore, or
  * crash the runtime library.
 */

 save_lc_ctype = _wsetlocale(LC_CTYPE, NULL);
 if (!save_lc_ctype || !(save_lc_ctype = wcsdup(save_lc_ctype)))
  goto exit;
 save_lc_monetary = _wsetlocale(LC_MONETARY, NULL);
 if (!save_lc_monetary || !(save_lc_monetary = wcsdup(save_lc_monetary)))
  goto exit;
 save_lc_numeric = _wsetlocale(LC_NUMERIC, NULL);
 if (!save_lc_numeric || !(save_lc_numeric = wcsdup(save_lc_numeric)))
  goto exit;

 memset(output, 0sizeof(*output));

 /* Copy the LC_MONETARY members. */
 if (!setlocale(LC_ALL, lc_monetary))
  goto exit;
 result = pg_localeconv_copy_members(output, localeconv(), LC_MONETARY);
 if (result != 0)
  goto exit;

 /* Copy the LC_NUMERIC members. */
 if (!setlocale(LC_ALL, lc_numeric))
  goto exit;
 result = pg_localeconv_copy_members(output, localeconv(), LC_NUMERIC);

exit:
 /* Restore everything we changed. */
 if (save_lc_ctype)
 {
  _wsetlocale(LC_CTYPE, save_lc_ctype);
  free(save_lc_ctype);
 }
 if (save_lc_monetary)
 {
  _wsetlocale(LC_MONETARY, save_lc_monetary);
  free(save_lc_monetary);
 }
 if (save_lc_numeric)
 {
  _wsetlocale(LC_NUMERIC, save_lc_numeric);
  free(save_lc_numeric);
 }
 _configthreadlocale(save_config_thread_locale);

 return result;

#else       /* !WIN32 */
 locale_t monetary_locale;
 locale_t numeric_locale;
 int   result;

 /*
  * All variations on Unix require locale_t objects for LC_MONETARY and
  * LC_NUMERIC.  We'll set all locale categories, so that we can don't have
  * to worry about POSIX's undefined behavior if LC_CTYPE's encoding
  * doesn't match.
 */

 errno = ENOENT;
 monetary_locale = newlocale(LC_ALL_MASK, lc_monetary, 0);
 if (monetary_locale == 0)
  return -1;
 numeric_locale = newlocale(LC_ALL_MASK, lc_numeric, 0);
 if (numeric_locale == 0)
 {
  freelocale(monetary_locale);
  return -1;
 }

 memset(output, 0sizeof(*output));
#if defined(TRANSLATE_FROM_LANGINFO)
 /* Copy from non-standard nl_langinfo_l() extended items. */
 result = pg_localeconv_from_langinfo(output,
           monetary_locale,
           numeric_locale);
#elif defined(HAVE_LOCALECONV_L)
 /* Copy the LC_MONETARY members from a thread-safe lconv object. */
 result = pg_localeconv_copy_members(output,
          localeconv_l(monetary_locale),
          LC_MONETARY);
 if (result == 0)
 {
  /* Copy the LC_NUMERIC members from a thread-safe lconv object. */
  result = pg_localeconv_copy_members(output,
           localeconv_l(numeric_locale),
           LC_NUMERIC);
 }
#else
 /* We have nothing better than standard POSIX facilities. */
 {
  static pthread_mutex_t big_lock = PTHREAD_MUTEX_INITIALIZER;
  locale_t save_locale;

  pthread_mutex_lock(&big_lock);
  /* Copy the LC_MONETARY members. */
  save_locale = uselocale(monetary_locale);
  result = pg_localeconv_copy_members(output,
           localeconv(),
           LC_MONETARY);
  if (result == 0)
  {
   /* Copy the LC_NUMERIC members. */
   uselocale(numeric_locale);
   result = pg_localeconv_copy_members(output,
            localeconv(),
            LC_NUMERIC);
  }
  pthread_mutex_unlock(&big_lock);

  uselocale(save_locale);
 }
#endif

 freelocale(monetary_locale);
 freelocale(numeric_locale);

 return result;
#endif       /* !WIN32 */
}

Messung V0.5 in Prozent
C=94 H=83 G=88

¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=141584
#Domains=752002