Blame lib/nl_langinfo.c

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