#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rune.h"
static void
freegl(char **oldgl)
{
int ic;
if (oldgl == NULL)
return;
for (ic = LC_ALL; ic < _LC_LAST; ic++)
free(oldgl[ic]);
free(oldgl);
}
static char **
dupgl(char **oldgl)
{
char **newgl;
int ic;
if ((newgl = calloc(_LC_LAST, sizeof(*newgl))) == NULL)
return NULL;
for (ic = LC_ALL; ic < _LC_LAST; ic++) {
if ((newgl[ic] = strdup(ic == LC_ALL ? "" :
oldgl == NULL ? "C" : oldgl[ic])) == NULL) {
freegl(newgl);
return NULL;
}
}
return newgl;
}
static int
changegl(int category, const char *locname, char **gl)
{
char *cp;
if ((locname = _get_locname(category, locname)) == NULL ||
(cp = strdup(locname)) == NULL)
return -1;
free(gl[category]);
gl[category] = cp;
return 0;
}
char *
setlocale(int category, const char *locname)
{
static char global_locname[256];
static char **global_locale;
char **newgl, *firstname, *nextname;
int ic;
if (category < LC_ALL || category >= _LC_LAST)
return NULL;
if (locname != NULL) {
if ((newgl = dupgl(global_locale)) == NULL)
return NULL;
if (category == LC_ALL && strchr(locname, '/') != NULL) {
if ((firstname = strdup(locname)) == NULL) {
freegl(newgl);
return NULL;
}
nextname = firstname;
for (ic = 1; ic < _LC_LAST; ic++)
if (nextname == NULL || changegl(ic,
strsep(&nextname, "/"), newgl) == -1)
break;
free(firstname);
if (ic < _LC_LAST || nextname != NULL) {
freegl(newgl);
return NULL;
}
} else {
if (changegl(category, locname, newgl) == -1) {
freegl(newgl);
return NULL;
}
if (category == LC_ALL) {
for (ic = 1; ic < _LC_LAST; ic++) {
if (changegl(ic, locname,
newgl) == -1) {
freegl(newgl);
return NULL;
}
}
}
}
} else
newgl = global_locale;
if (newgl == NULL) {
(void)strlcpy(global_locname, "C", sizeof(global_locname));
goto done;
}
if (category > LC_ALL || newgl[LC_ALL][0] != '\0') {
if (strlcpy(global_locname, newgl[category],
sizeof(global_locname)) >= sizeof(global_locname))
global_locname[0] = '\0';
goto done;
}
for (ic = 2; ic < _LC_LAST; ic++)
if (strcmp(newgl[ic], newgl[1]) != 0)
break;
if (ic == _LC_LAST) {
if (strlcpy(global_locname, newgl[1],
sizeof(global_locname)) >= sizeof(global_locname))
global_locname[0] = '\0';
} else {
ic = snprintf(global_locname, sizeof(global_locname),
"%s/%s/%s/%s/%s/%s", newgl[1], newgl[2], newgl[3],
newgl[4], newgl[5], newgl[6]);
if (ic < 0 || ic >= sizeof(global_locname))
global_locname[0] = '\0';
}
done:
if (locname != NULL) {
if (global_locname[0] != '\0') {
freegl(global_locale);
global_locale = newgl;
if (category == LC_ALL || category == LC_CTYPE)
_GlobalRuneLocale =
strchr(newgl[LC_CTYPE], '.') == NULL ?
&_DefaultRuneLocale : _Utf8RuneLocale;
} else {
freegl(newgl);
return NULL;
}
}
return global_locname;
}
DEF_STRONG(setlocale);