blob: e48b38cf2ffaff30a0c28ce6d423adbc85e3960d [file] [log] [blame]
/* Fake setlocale - platform independent, for testing purposes.
Copyright (C) 2001-2002, 2019-2020 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <locale.h>
#include <string.h>
/* Make this override available independently of possible overrides in
libgnuintl.h or locale.h.
Note: On platforms where _nl_locale_name_posix invokes setlocale_null, this
override *must* be called 'setlocale'. */
#undef setlocale
/* Avoid a link error on MSVC. */
#if defined _WIN32 && !defined __CYGWIN__
# define setlocale fake_setlocale
#endif
/* Return string representation of locale CATEGORY. */
static const char *
category_to_name (int category)
{
const char *retval;
switch (category)
{
#ifdef LC_COLLATE
case LC_COLLATE:
retval = "LC_COLLATE";
break;
#endif
#ifdef LC_CTYPE
case LC_CTYPE:
retval = "LC_CTYPE";
break;
#endif
#ifdef LC_MONETARY
case LC_MONETARY:
retval = "LC_MONETARY";
break;
#endif
#ifdef LC_NUMERIC
case LC_NUMERIC:
retval = "LC_NUMERIC";
break;
#endif
#ifdef LC_TIME
case LC_TIME:
retval = "LC_TIME";
break;
#endif
#ifdef LC_MESSAGES
case LC_MESSAGES:
retval = "LC_MESSAGES";
break;
#endif
#ifdef LC_RESPONSE
case LC_RESPONSE:
retval = "LC_RESPONSE";
break;
#endif
#ifdef LC_ALL
case LC_ALL:
/* This might not make sense but is perhaps better than any other
value. */
retval = "LC_ALL";
break;
#endif
default:
/* If you have a better idea for a default value let me know. */
retval = "LC_XXX";
}
return retval;
}
/* An implementation of setlocale that always succeeds, but doesn't
actually change the behaviour of locale dependent functions.
Assumes setenv()/putenv() is not called. */
char *
setlocale (int category, const char *locale)
{
static char C_string[] = "C";
static char *current_locale = C_string;
struct list
{
int category;
char *current_locale;
struct list *next;
};
static struct list *facets = NULL;
struct list *facetp;
char *retval;
if (locale != NULL)
{
char *copy;
copy = (char *) malloc (strlen (locale) + 1);
strcpy (copy, locale);
if (category == LC_ALL)
{
while ((facetp = facets) != NULL)
{
facets = facetp->next;
free (facetp->current_locale);
free (facetp);
}
if (current_locale != C_string)
free (current_locale);
current_locale = copy;
}
else
{
for (facetp = facets; facetp != NULL; facetp = facetp->next)
if (category == facetp->category)
{
free (facetp->current_locale);
facetp->current_locale = copy;
break;
}
if (facetp == NULL)
{
facetp = (struct list *) malloc (sizeof (struct list));
facetp->category = category;
facetp->current_locale = copy;
facetp->next = facets;
facets = facetp;
}
}
}
retval = current_locale;
for (facetp = facets; facetp != NULL; facetp = facetp->next)
if (category == facetp->category)
{
retval = facetp->current_locale;
break;
}
if (retval[0] == '\0')
{
retval = getenv ("LC_ALL");
if (retval == NULL || retval[0] == '\0')
{
retval = getenv (category_to_name (category));
if (retval == NULL || retval[0] == '\0')
{
retval = getenv ("LANG");
if (retval == NULL || retval[0] == '\0')
retval = "C";
}
}
}
return retval;
}