Blame lib/nl_langinfo.c

Packit Service a2489d
/* nl_langinfo() replacement: query locale dependent information.
Packit Service a2489d
Packit Service a2489d
   Copyright (C) 2007-2018 Free Software Foundation, Inc.
Packit Service a2489d
Packit Service a2489d
   This program is free software: you can redistribute it and/or modify
Packit Service a2489d
   it under the terms of the GNU General Public License as published by
Packit Service a2489d
   the Free Software Foundation; either version 3 of the License, or
Packit Service a2489d
   (at your option) any later version.
Packit Service a2489d
Packit Service a2489d
   This program is distributed in the hope that it will be useful,
Packit Service a2489d
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a2489d
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a2489d
   GNU General Public License for more details.
Packit Service a2489d
Packit Service a2489d
   You should have received a copy of the GNU General Public License
Packit Service a2489d
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Packit Service a2489d
Packit Service a2489d
#include <config.h>
Packit Service a2489d
Packit Service a2489d
/* Specification.  */
Packit Service a2489d
#include <langinfo.h>
Packit Service a2489d
Packit Service a2489d
#include <locale.h>
Packit Service a2489d
#include <string.h>
Packit Service a2489d
#if defined _WIN32 && ! defined __CYGWIN__
Packit Service a2489d
# define WIN32_LEAN_AND_MEAN  /* avoid including junk */
Packit Service a2489d
# include <windows.h>
Packit Service a2489d
# include <stdio.h>
Packit Service a2489d
#endif
Packit Service a2489d
Packit Service a2489d
#if !REPLACE_NL_LANGINFO || GNULIB_defined_CODESET
Packit Service a2489d
/* Return the codeset of the current locale, if this is easily deducible.
Packit Service a2489d
   Otherwise, return "".  */
Packit Service a2489d
static char *
Packit Service a2489d
ctype_codeset (void)
Packit Service a2489d
{
Packit Service a2489d
  static char buf[2 + 10 + 1];
Packit Service a2489d
  char const *locale = setlocale (LC_CTYPE, NULL);
Packit Service a2489d
  char *codeset = buf;
Packit Service a2489d
  size_t codesetlen;
Packit Service a2489d
  codeset[0] = '\0';
Packit Service a2489d
Packit Service a2489d
  if (locale && locale[0])
Packit Service a2489d
    {
Packit Service a2489d
      /* If the locale name contains an encoding after the dot, return it.  */
Packit Service a2489d
      char *dot = strchr (locale, '.');
Packit Service a2489d
Packit Service a2489d
      if (dot)
Packit Service a2489d
        {
Packit Service a2489d
          /* Look for the possible @... trailer and remove it, if any.  */
Packit Service a2489d
          char *codeset_start = dot + 1;
Packit Service a2489d
          char const *modifier = strchr (codeset_start, '@');
Packit Service a2489d
Packit Service a2489d
          if (! modifier)
Packit Service a2489d
            codeset = codeset_start;
Packit Service a2489d
          else
Packit Service a2489d
            {
Packit Service a2489d
              codesetlen = modifier - codeset_start;
Packit Service a2489d
              if (codesetlen < sizeof buf)
Packit Service a2489d
                {
Packit Service a2489d
                  codeset = memcpy (buf, codeset_start, codesetlen);
Packit Service a2489d
                  codeset[codesetlen] = '\0';
Packit Service a2489d
                }
Packit Service a2489d
            }
Packit Service a2489d
        }
Packit Service a2489d
    }
Packit Service a2489d
Packit Service a2489d
# if defined _WIN32 && ! defined __CYGWIN__
Packit Service a2489d
  /* If setlocale is successful, it returns the number of the
Packit Service a2489d
     codepage, as a string.  Otherwise, fall back on Windows API
Packit Service a2489d
     GetACP, which returns the locale's codepage as a number (although
Packit Service a2489d
     this doesn't change according to what the 'setlocale' call specified).
Packit Service a2489d
     Either way, prepend "CP" to make it a valid codeset name.  */
Packit Service a2489d
  codesetlen = strlen (codeset);
Packit Service a2489d
  if (0 < codesetlen && codesetlen < sizeof buf - 2)
Packit Service a2489d
    memmove (buf + 2, codeset, codesetlen + 1);
Packit Service a2489d
  else
Packit Service a2489d
    sprintf (buf + 2, "%u", GetACP ());
Packit Service a2489d
  codeset = memcpy (buf, "CP", 2);
Packit Service a2489d
# endif
Packit Service a2489d
  return codeset;
Packit Service a2489d
}
Packit Service a2489d
#endif
Packit Service a2489d
Packit Service a2489d
Packit Service a2489d
#if REPLACE_NL_LANGINFO
Packit Service a2489d
Packit Service a2489d
/* Override nl_langinfo with support for added nl_item values.  */
Packit Service a2489d
Packit Service a2489d
# undef nl_langinfo
Packit Service a2489d
Packit Service a2489d
char *
Packit Service a2489d
rpl_nl_langinfo (nl_item item)
Packit Service a2489d
{
Packit Service a2489d
  switch (item)
Packit Service a2489d
    {
Packit Service a2489d
# if GNULIB_defined_CODESET
Packit Service a2489d
    case CODESET:
Packit Service a2489d
      return ctype_codeset ();
Packit Service a2489d
# endif
Packit Service a2489d
# if GNULIB_defined_T_FMT_AMPM
Packit Service a2489d
    case T_FMT_AMPM:
Packit Service a2489d
      return (char *) "%I:%M:%S %p";
Packit Service a2489d
# endif
Packit Service a2489d
# if GNULIB_defined_ALTMON
Packit Service a2489d
    case ALTMON_1:
Packit Service a2489d
    case ALTMON_2:
Packit Service a2489d
    case ALTMON_3:
Packit Service a2489d
    case ALTMON_4:
Packit Service a2489d
    case ALTMON_5:
Packit Service a2489d
    case ALTMON_6:
Packit Service a2489d
    case ALTMON_7:
Packit Service a2489d
    case ALTMON_8:
Packit Service a2489d
    case ALTMON_9:
Packit Service a2489d
    case ALTMON_10:
Packit Service a2489d
    case ALTMON_11:
Packit Service a2489d
    case ALTMON_12:
Packit Service a2489d
      /* We don't ship the appropriate localizations with gnulib.  Therefore,
Packit Service a2489d
         treat ALTMON_i like MON_i.  */
Packit Service a2489d
      item = item - ALTMON_1 + MON_1;
Packit Service a2489d
      break;
Packit Service a2489d
# endif
Packit Service a2489d
# if GNULIB_defined_ERA
Packit Service a2489d
    case ERA:
Packit Service a2489d
      /* The format is not standardized.  In glibc it is a sequence of strings
Packit Service a2489d
         of the form "direction:offset:start_date:end_date:era_name:era_format"
Packit Service a2489d
         with an empty string at the end.  */
Packit Service a2489d
      return (char *) "";
Packit Service a2489d
    case ERA_D_FMT:
Packit Service a2489d
      /* The %Ex conversion in strftime behaves like %x if the locale does not
Packit Service a2489d
         have an alternative time format.  */
Packit Service a2489d
      item = D_FMT;
Packit Service a2489d
      break;
Packit Service a2489d
    case ERA_D_T_FMT:
Packit Service a2489d
      /* The %Ec conversion in strftime behaves like %c if the locale does not
Packit Service a2489d
         have an alternative time format.  */
Packit Service a2489d
      item = D_T_FMT;
Packit Service a2489d
      break;
Packit Service a2489d
    case ERA_T_FMT:
Packit Service a2489d
      /* The %EX conversion in strftime behaves like %X if the locale does not
Packit Service a2489d
         have an alternative time format.  */
Packit Service a2489d
      item = T_FMT;
Packit Service a2489d
      break;
Packit Service a2489d
    case ALT_DIGITS:
Packit Service a2489d
      /* The format is not standardized.  In glibc it is a sequence of 10
Packit Service a2489d
         strings, appended in memory.  */
Packit Service a2489d
      return (char *) "\0\0\0\0\0\0\0\0\0\0";
Packit Service a2489d
# endif
Packit Service a2489d
# if GNULIB_defined_YESEXPR || !FUNC_NL_LANGINFO_YESEXPR_WORKS
Packit Service a2489d
    case YESEXPR:
Packit Service a2489d
      return (char *) "^[yY]";
Packit Service a2489d
    case NOEXPR:
Packit Service a2489d
      return (char *) "^[nN]";
Packit Service a2489d
# endif
Packit Service a2489d
    default:
Packit Service a2489d
      break;
Packit Service a2489d
    }
Packit Service a2489d
  return nl_langinfo (item);
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
#else
Packit Service a2489d
Packit Service a2489d
/* Provide nl_langinfo from scratch, either for native MS-Windows, or
Packit Service a2489d
   for old Unix platforms without locales, such as Linux libc5 or
Packit Service a2489d
   BeOS.  */
Packit Service a2489d
Packit Service a2489d
# include <time.h>
Packit Service a2489d
Packit Service a2489d
char *
Packit Service a2489d
nl_langinfo (nl_item item)
Packit Service a2489d
{
Packit Service a2489d
  static char nlbuf[100];
Packit Service a2489d
  struct tm tmm = { 0 };
Packit Service a2489d
Packit Service a2489d
  switch (item)
Packit Service a2489d
    {
Packit Service a2489d
    /* nl_langinfo items of the LC_CTYPE category */
Packit Service a2489d
    case CODESET:
Packit Service a2489d
      {
Packit Service a2489d
        char *codeset = ctype_codeset ();
Packit Service a2489d
        if (*codeset)
Packit Service a2489d
          return codeset;
Packit Service a2489d
      }
Packit Service a2489d
# ifdef __BEOS__
Packit Service a2489d
      return (char *) "UTF-8";
Packit Service a2489d
# else
Packit Service a2489d
      return (char *) "ISO-8859-1";
Packit Service a2489d
# endif
Packit Service a2489d
    /* nl_langinfo items of the LC_NUMERIC category */
Packit Service a2489d
    case RADIXCHAR:
Packit Service a2489d
      return localeconv () ->decimal_point;
Packit Service a2489d
    case THOUSEP:
Packit Service a2489d
      return localeconv () ->thousands_sep;
Packit Service a2489d
# ifdef GROUPING
Packit Service a2489d
    case GROUPING:
Packit Service a2489d
      return localeconv () ->grouping;
Packit Service a2489d
# endif
Packit Service a2489d
    /* nl_langinfo items of the LC_TIME category.
Packit Service a2489d
       TODO: Really use the locale.  */
Packit Service a2489d
    case D_T_FMT:
Packit Service a2489d
    case ERA_D_T_FMT:
Packit Service a2489d
      return (char *) "%a %b %e %H:%M:%S %Y";
Packit Service a2489d
    case D_FMT:
Packit Service a2489d
    case ERA_D_FMT:
Packit Service a2489d
      return (char *) "%m/%d/%y";
Packit Service a2489d
    case T_FMT:
Packit Service a2489d
    case ERA_T_FMT:
Packit Service a2489d
      return (char *) "%H:%M:%S";
Packit Service a2489d
    case T_FMT_AMPM:
Packit Service a2489d
      return (char *) "%I:%M:%S %p";
Packit Service a2489d
    case AM_STR:
Packit Service a2489d
      if (!strftime (nlbuf, sizeof nlbuf, "%p", &tmm))
Packit Service a2489d
        return (char *) "AM";
Packit Service a2489d
      return nlbuf;
Packit Service a2489d
    case PM_STR:
Packit Service a2489d
      tmm.tm_hour = 12;
Packit Service a2489d
      if (!strftime (nlbuf, sizeof nlbuf, "%p", &tmm))
Packit Service a2489d
        return (char *) "PM";
Packit Service a2489d
      return nlbuf;
Packit Service a2489d
    case DAY_1:
Packit Service a2489d
    case DAY_2:
Packit Service a2489d
    case DAY_3:
Packit Service a2489d
    case DAY_4:
Packit Service a2489d
    case DAY_5:
Packit Service a2489d
    case DAY_6:
Packit Service a2489d
    case DAY_7:
Packit Service a2489d
      {
Packit Service a2489d
        static char const days[][sizeof "Wednesday"] = {
Packit Service a2489d
          "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
Packit Service a2489d
          "Friday", "Saturday"
Packit Service a2489d
        };
Packit Service a2489d
        tmm.tm_wday = item - DAY_1;
Packit Service a2489d
        if (!strftime (nlbuf, sizeof nlbuf, "%A", &tmm))
Packit Service a2489d
          return (char *) days[item - DAY_1];
Packit Service a2489d
        return nlbuf;
Packit Service a2489d
      }
Packit Service a2489d
    case ABDAY_1:
Packit Service a2489d
    case ABDAY_2:
Packit Service a2489d
    case ABDAY_3:
Packit Service a2489d
    case ABDAY_4:
Packit Service a2489d
    case ABDAY_5:
Packit Service a2489d
    case ABDAY_6:
Packit Service a2489d
    case ABDAY_7:
Packit Service a2489d
      {
Packit Service a2489d
        static char const abdays[][sizeof "Sun"] = {
Packit Service a2489d
          "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
Packit Service a2489d
        };
Packit Service a2489d
        tmm.tm_wday = item - ABDAY_1;
Packit Service a2489d
        if (!strftime (nlbuf, sizeof nlbuf, "%a", &tmm))
Packit Service a2489d
          return (char *) abdays[item - ABDAY_1];
Packit Service a2489d
        return nlbuf;
Packit Service a2489d
      }
Packit Service a2489d
    {
Packit Service a2489d
      static char const months[][sizeof "September"] = {
Packit Service a2489d
        "January", "February", "March", "April", "May", "June", "July",
Packit Service a2489d
        "September", "October", "November", "December"
Packit Service a2489d
      };
Packit Service a2489d
      case MON_1:
Packit Service a2489d
      case MON_2:
Packit Service a2489d
      case MON_3:
Packit Service a2489d
      case MON_4:
Packit Service a2489d
      case MON_5:
Packit Service a2489d
      case MON_6:
Packit Service a2489d
      case MON_7:
Packit Service a2489d
      case MON_8:
Packit Service a2489d
      case MON_9:
Packit Service a2489d
      case MON_10:
Packit Service a2489d
      case MON_11:
Packit Service a2489d
      case MON_12:
Packit Service a2489d
        tmm.tm_mon = item - MON_1;
Packit Service a2489d
        if (!strftime (nlbuf, sizeof nlbuf, "%B", &tmm))
Packit Service a2489d
          return (char *) months[item - MON_1];
Packit Service a2489d
        return nlbuf;
Packit Service a2489d
      case ALTMON_1:
Packit Service a2489d
      case ALTMON_2:
Packit Service a2489d
      case ALTMON_3:
Packit Service a2489d
      case ALTMON_4:
Packit Service a2489d
      case ALTMON_5:
Packit Service a2489d
      case ALTMON_6:
Packit Service a2489d
      case ALTMON_7:
Packit Service a2489d
      case ALTMON_8:
Packit Service a2489d
      case ALTMON_9:
Packit Service a2489d
      case ALTMON_10:
Packit Service a2489d
      case ALTMON_11:
Packit Service a2489d
      case ALTMON_12:
Packit Service a2489d
        tmm.tm_mon = item - ALTMON_1;
Packit Service a2489d
        /* The platforms without nl_langinfo() don't support strftime with %OB.
Packit Service a2489d
           We don't even need to try.  */
Packit Service a2489d
        #if 0
Packit Service a2489d
        if (!strftime (nlbuf, sizeof nlbuf, "%OB", &tmm))
Packit Service a2489d
        #endif
Packit Service a2489d
          if (!strftime (nlbuf, sizeof nlbuf, "%B", &tmm))
Packit Service a2489d
            return (char *) months[item - ALTMON_1];
Packit Service a2489d
        return nlbuf;
Packit Service a2489d
    }
Packit Service a2489d
    case ABMON_1:
Packit Service a2489d
    case ABMON_2:
Packit Service a2489d
    case ABMON_3:
Packit Service a2489d
    case ABMON_4:
Packit Service a2489d
    case ABMON_5:
Packit Service a2489d
    case ABMON_6:
Packit Service a2489d
    case ABMON_7:
Packit Service a2489d
    case ABMON_8:
Packit Service a2489d
    case ABMON_9:
Packit Service a2489d
    case ABMON_10:
Packit Service a2489d
    case ABMON_11:
Packit Service a2489d
    case ABMON_12:
Packit Service a2489d
      {
Packit Service a2489d
        static char const abmonths[][sizeof "Jan"] = {
Packit Service a2489d
          "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
Packit Service a2489d
          "Sep", "Oct", "Nov", "Dec"
Packit Service a2489d
        };
Packit Service a2489d
        tmm.tm_mon = item - ABMON_1;
Packit Service a2489d
        if (!strftime (nlbuf, sizeof nlbuf, "%b", &tmm))
Packit Service a2489d
          return (char *) abmonths[item - ABMON_1];
Packit Service a2489d
        return nlbuf;
Packit Service a2489d
      }
Packit Service a2489d
    case ERA:
Packit Service a2489d
      return (char *) "";
Packit Service a2489d
    case ALT_DIGITS:
Packit Service a2489d
      return (char *) "\0\0\0\0\0\0\0\0\0\0";
Packit Service a2489d
    /* nl_langinfo items of the LC_MONETARY category.  */
Packit Service a2489d
    case CRNCYSTR:
Packit Service a2489d
      return localeconv () ->currency_symbol;
Packit Service a2489d
# ifdef INT_CURR_SYMBOL
Packit Service a2489d
    case INT_CURR_SYMBOL:
Packit Service a2489d
      return localeconv () ->int_curr_symbol;
Packit Service a2489d
    case MON_DECIMAL_POINT:
Packit Service a2489d
      return localeconv () ->mon_decimal_point;
Packit Service a2489d
    case MON_THOUSANDS_SEP:
Packit Service a2489d
      return localeconv () ->mon_thousands_sep;
Packit Service a2489d
    case MON_GROUPING:
Packit Service a2489d
      return localeconv () ->mon_grouping;
Packit Service a2489d
    case POSITIVE_SIGN:
Packit Service a2489d
      return localeconv () ->positive_sign;
Packit Service a2489d
    case NEGATIVE_SIGN:
Packit Service a2489d
      return localeconv () ->negative_sign;
Packit Service a2489d
    case FRAC_DIGITS:
Packit Service a2489d
      return & localeconv () ->frac_digits;
Packit Service a2489d
    case INT_FRAC_DIGITS:
Packit Service a2489d
      return & localeconv () ->int_frac_digits;
Packit Service a2489d
    case P_CS_PRECEDES:
Packit Service a2489d
      return & localeconv () ->p_cs_precedes;
Packit Service a2489d
    case N_CS_PRECEDES:
Packit Service a2489d
      return & localeconv () ->n_cs_precedes;
Packit Service a2489d
    case P_SEP_BY_SPACE:
Packit Service a2489d
      return & localeconv () ->p_sep_by_space;
Packit Service a2489d
    case N_SEP_BY_SPACE:
Packit Service a2489d
      return & localeconv () ->n_sep_by_space;
Packit Service a2489d
    case P_SIGN_POSN:
Packit Service a2489d
      return & localeconv () ->p_sign_posn;
Packit Service a2489d
    case N_SIGN_POSN:
Packit Service a2489d
      return & localeconv () ->n_sign_posn;
Packit Service a2489d
# endif
Packit Service a2489d
    /* nl_langinfo items of the LC_MESSAGES category
Packit Service a2489d
       TODO: Really use the locale. */
Packit Service a2489d
    case YESEXPR:
Packit Service a2489d
      return (char *) "^[yY]";
Packit Service a2489d
    case NOEXPR:
Packit Service a2489d
      return (char *) "^[nN]";
Packit Service a2489d
    default:
Packit Service a2489d
      return (char *) "";
Packit Service a2489d
    }
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
#endif