Blame lib/nl_langinfo.c

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