Blame lib/nl_langinfo.c

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