Blame gnulib/lib/nl_langinfo.c

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