Rewrite locale loading procedures, so any load failure will not affect

currently cached data.  It allows a number of nice things, like: removing
fallback code from single locale loading, remove memory leak when LC_CTYPE
data loaded again and again, efficient cache use, not only for
setlocale(locale1); setlocale(locale1), but for setlocale(locale1);
setlocale("C"); setlocale(locale1) too (i.e.  data file loaded only once).
This commit is contained in:
Andrey A. Chernov 2002-08-08 05:51:54 +00:00
parent af8c0bce98
commit 76692b8025
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=101498
11 changed files with 260 additions and 193 deletions

View File

@ -40,68 +40,115 @@ __FBSDID("$FreeBSD$");
#include "collate.h" #include "collate.h"
#include "setlocale.h" #include "setlocale.h"
#include "ldpart.h"
#include "libc_private.h" #include "libc_private.h"
int __collate_load_error = 1; int __collate_load_error = 1;
int __collate_substitute_nontrivial; int __collate_substitute_nontrivial;
char __collate_version[STR_LEN];
u_char __collate_substitute_table[UCHAR_MAX + 1][STR_LEN]; u_char __collate_substitute_table[UCHAR_MAX + 1][STR_LEN];
struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1]; struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1];
struct __collate_st_chain_pri __collate_chain_pri_table[TABLE_SIZE]; struct __collate_st_chain_pri __collate_chain_pri_table[TABLE_SIZE];
#define FREAD(a, b, c, d) \
do { \
if (fread(a, b, c, d) != c) { \
(void)fclose(d); \
return -1; \
} \
} while(0)
void __collate_err(int ex, const char *f) __dead2; void __collate_err(int ex, const char *f) __dead2;
int int
__collate_load_tables(encoding) __collate_load_tables(const char *encoding)
char *encoding;
{ {
char buf[PATH_MAX];
FILE *fp; FILE *fp;
int i, save_load_error; int i, saverr;
char collate_version[STR_LEN];
char buf[PATH_MAX];
char *TMP_substitute_table, *TMP_char_pri_table, *TMP_chain_pri_table;
static char collate_encoding[ENCODING_LEN + 1];
save_load_error = __collate_load_error; /* 'encoding' must be already checked. */
__collate_load_error = 1; if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
if (!encoding) { __collate_load_error = 1;
__collate_load_error = save_load_error; return (_LDP_CACHE);
return -1;
} }
if (!strcmp(encoding, "C") || !strcmp(encoding, "POSIX"))
return 0; /*
if (!_PathLocale) { * If the locale name is the same as our cache, use the cache.
__collate_load_error = save_load_error; */
return -1; if (strcmp(encoding, collate_encoding) == 0) {
__collate_load_error = 0;
return (_LDP_CACHE);
} }
/*
* Slurp the locale file into the cache.
*/
/* 'PathLocale' must be already set & checked. */
/* Range checking not needed, encoding has fixed size */ /* Range checking not needed, encoding has fixed size */
(void)strcpy(buf, _PathLocale); (void)strcpy(buf, _PathLocale);
(void)strcat(buf, "/"); (void)strcat(buf, "/");
(void)strcat(buf, encoding); (void)strcat(buf, encoding);
(void)strcat(buf, "/LC_COLLATE"); (void)strcat(buf, "/LC_COLLATE");
if ((fp = fopen(buf, "r")) == NULL) { if ((fp = fopen(buf, "r")) == NULL)
__collate_load_error = save_load_error; return (_LDP_ERROR);
return -1;
} if ((TMP_substitute_table =
FREAD(__collate_version, sizeof(__collate_version), 1, fp); malloc(sizeof(__collate_substitute_table))) == NULL) {
if (strcmp(__collate_version, COLLATE_VERSION) != 0) {
(void)fclose(fp); (void)fclose(fp);
return -1; errno = ENOMEM;
return (_LDP_ERROR);
} }
FREAD(__collate_substitute_table, sizeof(__collate_substitute_table), if ((TMP_char_pri_table =
1, fp); malloc(sizeof(__collate_char_pri_table))) == NULL) {
FREAD(__collate_char_pri_table, sizeof(__collate_char_pri_table), 1, free(TMP_substitute_table);
fp); (void)fclose(fp);
FREAD(__collate_chain_pri_table, sizeof(__collate_chain_pri_table), 1, errno = ENOMEM;
fp); return (_LDP_ERROR);
}
if ((TMP_chain_pri_table =
malloc(sizeof(__collate_chain_pri_table))) == NULL) {
free(TMP_substitute_table);
free(TMP_char_pri_table);
(void)fclose(fp);
errno = ENOMEM;
return (_LDP_ERROR);
}
#define FREAD(a, b, c, d) \
{ \
if (fread(a, b, c, d) != c) { \
saverr = errno; \
free(TMP_substitute_table); \
free(TMP_char_pri_table); \
free(TMP_chain_pri_table); \
(void)fclose(d); \
errno = saverr; \
return (_LDP_ERROR); \
} \
}
FREAD(collate_version, sizeof(collate_version), 1, fp);
if (strcmp(collate_version, COLLATE_VERSION) != 0) {
free(TMP_substitute_table);
free(TMP_char_pri_table);
free(TMP_chain_pri_table);
(void)fclose(fp);
errno = EFTYPE;
return (_LDP_ERROR);
}
FREAD(TMP_substitute_table, sizeof(__collate_substitute_table), 1, fp);
FREAD(TMP_char_pri_table, sizeof(__collate_char_pri_table), 1, fp);
FREAD(TMP_chain_pri_table, sizeof(__collate_chain_pri_table), 1, fp);
(void)fclose(fp); (void)fclose(fp);
__collate_load_error = 0;
(void)strcpy(collate_encoding, encoding);
(void)memcpy(__collate_substitute_table, TMP_substitute_table,
sizeof(__collate_substitute_table));
(void)memcpy(__collate_char_pri_table, TMP_char_pri_table,
sizeof(__collate_char_pri_table));
(void)memcpy(__collate_chain_pri_table, TMP_chain_pri_table,
sizeof(__collate_chain_pri_table));
free(TMP_substitute_table);
free(TMP_char_pri_table);
free(TMP_chain_pri_table);
__collate_substitute_nontrivial = 0; __collate_substitute_nontrivial = 0;
for (i = 0; i < UCHAR_MAX + 1; i++) { for (i = 0; i < UCHAR_MAX + 1; i++) {
@ -111,8 +158,9 @@ __collate_load_tables(encoding)
break; break;
} }
} }
__collate_load_error = 0;
return 0; return (_LDP_LOADED);
} }
u_char * u_char *
@ -152,8 +200,8 @@ __collate_lookup(t, len, prim, sec)
*len = 1; *len = 1;
*prim = *sec = 0; *prim = *sec = 0;
for(p2 = __collate_chain_pri_table; p2->str[0]; p2++) { for (p2 = __collate_chain_pri_table; p2->str[0]; p2++) {
if(strncmp(t, p2->str, strlen(p2->str)) == 0) { if (strncmp(t, p2->str, strlen(p2->str)) == 0) {
*len = strlen(p2->str); *len = strlen(p2->str);
*prim = p2->prim; *prim = p2->prim;
*sec = p2->sec; *sec = p2->sec;

View File

@ -48,7 +48,6 @@ struct __collate_st_chain_pri {
extern int __collate_load_error; extern int __collate_load_error;
extern int __collate_substitute_nontrivial; extern int __collate_substitute_nontrivial;
extern char __collate_version[STR_LEN];
extern u_char __collate_substitute_table[UCHAR_MAX + 1][STR_LEN]; extern u_char __collate_substitute_table[UCHAR_MAX + 1][STR_LEN];
extern struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1]; extern struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1];
extern struct __collate_st_chain_pri __collate_chain_pri_table[TABLE_SIZE]; extern struct __collate_st_chain_pri __collate_chain_pri_table[TABLE_SIZE];
@ -56,7 +55,7 @@ extern struct __collate_st_chain_pri __collate_chain_pri_table[TABLE_SIZE];
__BEGIN_DECLS __BEGIN_DECLS
u_char *__collate_strdup(u_char *); u_char *__collate_strdup(u_char *);
u_char *__collate_substitute(const u_char *); u_char *__collate_substitute(const u_char *);
int __collate_load_tables(char *); int __collate_load_tables(const char *);
void __collate_lookup(const u_char *, int *, int *, int *); void __collate_lookup(const u_char *, int *, int *, int *);
int __collate_range_cmp(int, int); int __collate_range_cmp(int, int);
#ifdef COLLATE_DEBUG #ifdef COLLATE_DEBUG

View File

@ -63,40 +63,36 @@ _EUC_init(rl)
_RuneLocale *rl; _RuneLocale *rl;
{ {
_EucInfo *ei; _EucInfo *ei;
int x; int x, new__mb_cur_max;
char *v, *e; char *v, *e;
rl->sgetrune = _EUC_sgetrune; rl->sgetrune = _EUC_sgetrune;
rl->sputrune = _EUC_sputrune; rl->sputrune = _EUC_sputrune;
if (!rl->variable) { if (rl->variable == NULL)
free(rl);
return (EFTYPE); return (EFTYPE);
}
v = (char *) rl->variable; v = (char *)rl->variable;
while (*v == ' ' || *v == '\t') while (*v == ' ' || *v == '\t')
++v; ++v;
if ((ei = malloc(sizeof(_EucInfo))) == NULL) { if ((ei = malloc(sizeof(_EucInfo))) == NULL)
free(rl);
return (ENOMEM); return (ENOMEM);
}
__mb_cur_max = 0; new__mb_cur_max = 0;
for (x = 0; x < 4; ++x) { for (x = 0; x < 4; ++x) {
ei->count[x] = (int) strtol(v, &e, 0); ei->count[x] = (int)strtol(v, &e, 0);
if (v == e || !(v = e)) { if (v == e || !(v = e)) {
free(rl);
free(ei); free(ei);
return (EFTYPE); return (EFTYPE);
} }
if (__mb_cur_max < ei->count[x]) if (new__mb_cur_max < ei->count[x])
__mb_cur_max = ei->count[x]; new__mb_cur_max = ei->count[x];
while (*v == ' ' || *v == '\t') while (*v == ' ' || *v == '\t')
++v; ++v;
ei->bits[x] = (int) strtol(v, &e, 0); ei->bits[x] = (int)strtol(v, &e, 0);
if (v == e || !(v = e)) { if (v == e || !(v = e)) {
free(rl);
free(ei); free(ei);
return (EFTYPE); return (EFTYPE);
} }
@ -105,18 +101,13 @@ _EUC_init(rl)
} }
ei->mask = (int)strtol(v, &e, 0); ei->mask = (int)strtol(v, &e, 0);
if (v == e || !(v = e)) { if (v == e || !(v = e)) {
free(rl);
free(ei); free(ei);
return (EFTYPE); return (EFTYPE);
} }
if (sizeof(_EucInfo) <= rl->variable_len) { rl->variable = ei;
memcpy(rl->variable, ei, sizeof(_EucInfo));
free(ei);
} else {
rl->variable = ei;
}
rl->variable_len = sizeof(_EucInfo); rl->variable_len = sizeof(_EucInfo);
_CurrentRuneLocale = rl; _CurrentRuneLocale = rl;
__mb_cur_max = new__mb_cur_max;
return (0); return (0);
} }

View File

@ -42,7 +42,6 @@ __FBSDID("$FreeBSD$");
#include "ldpart.h" #include "ldpart.h"
static int split_lines(char *, const char *); static int split_lines(char *, const char *);
static void set_from_buf(const char *, int, const char **);
int int
__part_load_locale(const char *name, __part_load_locale(const char *name,
@ -53,35 +52,25 @@ __part_load_locale(const char *name,
int locale_buf_size_min, int locale_buf_size_min,
const char **dst_localebuf) const char **dst_localebuf)
{ {
static char locale_buf_C[] = "C"; int saverr, fd, i, num_lines;
static int num_lines; char *lbuf, *p;
int saverr; const char *plim;
int fd; char filename[PATH_MAX];
char *lbuf;
char *p;
const char *plim;
char filename[PATH_MAX];
struct stat st; struct stat st;
size_t namesize; size_t namesize, bufsize;
size_t bufsize;
int save_using_locale;
save_using_locale = *using_locale;
*using_locale = 0;
/* 'name' must be already checked. */ /* 'name' must be already checked. */
if (strcmp(name, "C") == 0 || strcmp(name, "POSIX") == 0) {
if (!strcmp(name, "C") || !strcmp(name, "POSIX")) *using_locale = 0;
return 0; return (_LDP_CACHE);
}
/* /*
* If the locale name is the same as our cache, use the cache. * If the locale name is the same as our cache, use the cache.
*/ */
lbuf = locale_buf; if (locale_buf != NULL && strcmp(name, locale_buf) == 0) {
if (lbuf != NULL && strcmp(name, lbuf) == 0) {
set_from_buf(lbuf, num_lines, dst_localebuf);
*using_locale = 1; *using_locale = 1;
return 0; return (_LDP_CACHE);
} }
/* /*
@ -90,16 +79,14 @@ __part_load_locale(const char *name,
namesize = strlen(name) + 1; namesize = strlen(name) + 1;
/* 'PathLocale' must be already set & checked. */ /* 'PathLocale' must be already set & checked. */
/* Range checking not needed, 'name' size is limited */ /* Range checking not needed, 'name' size is limited */
strcpy(filename, _PathLocale); strcpy(filename, _PathLocale);
strcat(filename, "/"); strcat(filename, "/");
strcat(filename, name); strcat(filename, name);
strcat(filename, "/"); strcat(filename, "/");
strcat(filename, category_filename); strcat(filename, category_filename);
fd = _open(filename, O_RDONLY); if ((fd = _open(filename, O_RDONLY)) < 0)
if (fd < 0) return (_LDP_ERROR);
goto no_locale;
if (_fstat(fd, &st) != 0) if (_fstat(fd, &st) != 0)
goto bad_locale; goto bad_locale;
if (st.st_size <= 0) { if (st.st_size <= 0) {
@ -107,18 +94,15 @@ __part_load_locale(const char *name,
goto bad_locale; goto bad_locale;
} }
bufsize = namesize + st.st_size; bufsize = namesize + st.st_size;
locale_buf = NULL; if ((lbuf = malloc(bufsize)) == NULL) {
lbuf = (lbuf == NULL || lbuf == locale_buf_C) ? errno = ENOMEM;
malloc(bufsize) : reallocf(lbuf, bufsize);
if (lbuf == NULL)
goto bad_locale; goto bad_locale;
}
(void)strcpy(lbuf, name); (void)strcpy(lbuf, name);
p = lbuf + namesize; p = lbuf + namesize;
plim = p + st.st_size; plim = p + st.st_size;
if (_read(fd, p, (size_t) st.st_size) != st.st_size) if (_read(fd, p, (size_t) st.st_size) != st.st_size)
goto bad_lbuf; goto bad_lbuf;
if (_close(fd) != 0)
goto bad_lbuf;
/* /*
* Parse the locale file into localebuf. * Parse the locale file into localebuf.
*/ */
@ -133,37 +117,37 @@ __part_load_locale(const char *name,
num_lines = locale_buf_size_min; num_lines = locale_buf_size_min;
else { else {
errno = EFTYPE; errno = EFTYPE;
goto reset_locale; goto bad_lbuf;
} }
set_from_buf(lbuf, num_lines, dst_localebuf); (void)_close(fd);
/* /*
* Record the successful parse in the cache. * Record the successful parse in the cache.
*/ */
if (locale_buf != NULL)
free(locale_buf);
locale_buf = lbuf; locale_buf = lbuf;
for (p = locale_buf, i = 0; i < num_lines; i++)
dst_localebuf[i] = (p += strlen(p) + 1);
for (i = num_lines; i < locale_buf_size_max; i++)
dst_localebuf[i] = NULL;
*using_locale = 1; *using_locale = 1;
return 0; return (_LDP_LOADED);
reset_locale:
locale_buf = locale_buf_C;
save_using_locale = 0;
bad_lbuf: bad_lbuf:
saverr = errno; saverr = errno;
free(lbuf); free(lbuf);
errno = saverr; errno = saverr;
bad_locale: bad_locale:
saverr = errno; saverr = errno;
(void)_close(fd); (void)_close(fd);
errno = saverr; errno = saverr;
no_locale:
*using_locale = save_using_locale;
return -1; return (_LDP_ERROR);
} }
static int static int
split_lines(char *p, const char *plim) split_lines(char *p, const char *plim)
{ {
int i; int i;
@ -174,13 +158,3 @@ split_lines(char *p, const char *plim)
return (i); return (i);
} }
static void
set_from_buf(const char *p, int num_lines, const char **dst_localebuf) {
const char **ap;
int i;
for (ap = dst_localebuf, i = 0; i < num_lines; ++ap, ++i)
*ap = p += strlen(p) + 1;
}

View File

@ -29,6 +29,10 @@
#ifndef _LDPART_H_ #ifndef _LDPART_H_
#define _LDPART_H_ #define _LDPART_H_
#define _LDP_LOADED 0
#define _LDP_ERROR (-1)
#define _LDP_CACHE 1
int __part_load_locale(const char *, int*, char *, const char *, int __part_load_locale(const char *, int*, char *, const char *,
int, int, const char **); int, int, const char **);

View File

@ -52,18 +52,19 @@ static char *_messages_locale_buf;
int int
__messages_load_locale(const char *name) __messages_load_locale(const char *name)
{ {
/* int ret;
* Propose that we can have incomplete locale file (w/o "{yes,no}str").
* Initialize them before loading. In case of complete locale, they'll
* be initialized to loaded value, otherwise they'll not be touched.
*/
_messages_locale.yesstr = empty;
_messages_locale.nostr = empty;
return __part_load_locale(name, &_messages_using_locale, ret = __part_load_locale(name, &_messages_using_locale,
_messages_locale_buf, "LC_MESSAGES", _messages_locale_buf, "LC_MESSAGES",
LCMESSAGES_SIZE_FULL, LCMESSAGES_SIZE_MIN, LCMESSAGES_SIZE_FULL, LCMESSAGES_SIZE_MIN,
(const char **)&_messages_locale); (const char **)&_messages_locale);
if (ret == _LDP_LOADED) {
if (_messages_locale.yesstr == NULL)
_messages_locale.yesstr = empty;
if (_messages_locale.nostr == NULL)
_messages_locale.nostr = empty;
}
return (ret);
} }
struct lc_messages_T * struct lc_messages_T *

View File

@ -63,7 +63,7 @@ static int _monetary_using_locale;
static char *_monetary_locale_buf; static char *_monetary_locale_buf;
static char static char
cnv(const char *str) cnv(const char *str)
{ {
int i = strtol(str, NULL, 10); int i = strtol(str, NULL, 10);
@ -77,12 +77,13 @@ __monetary_load_locale(const char *name)
{ {
int ret; int ret;
__mlocale_changed = 1;
ret = __part_load_locale(name, &_monetary_using_locale, ret = __part_load_locale(name, &_monetary_using_locale,
_monetary_locale_buf, "LC_MONETARY", _monetary_locale_buf, "LC_MONETARY",
LCMONETARY_SIZE, LCMONETARY_SIZE, LCMONETARY_SIZE, LCMONETARY_SIZE,
(const char **)&_monetary_locale); (const char **)&_monetary_locale);
if (ret == 0 && _monetary_using_locale) { if (ret != _LDP_ERROR)
__mlocale_changed = 1;
if (ret == _LDP_LOADED) {
_monetary_locale.mon_grouping = _monetary_locale.mon_grouping =
__fix_locale_grouping_str(_monetary_locale.mon_grouping); __fix_locale_grouping_str(_monetary_locale.mon_grouping);
@ -102,7 +103,7 @@ __monetary_load_locale(const char *name)
} }
struct lc_monetary_T * struct lc_monetary_T *
__get_current_monetary_locale(void) __get_current_monetary_locale(void)
{ {
return (_monetary_using_locale return (_monetary_using_locale
? &_monetary_locale ? &_monetary_locale

View File

@ -53,14 +53,15 @@ __numeric_load_locale(const char *name)
{ {
int ret; int ret;
__nlocale_changed = 1;
ret = __part_load_locale(name, &_numeric_using_locale, ret = __part_load_locale(name, &_numeric_using_locale,
_numeric_locale_buf, "LC_NUMERIC", _numeric_locale_buf, "LC_NUMERIC",
LCNUMERIC_SIZE, LCNUMERIC_SIZE, LCNUMERIC_SIZE, LCNUMERIC_SIZE,
(const char **)&_numeric_locale); (const char **)&_numeric_locale);
if (ret == 0 && _numeric_using_locale) if (ret != _LDP_ERROR)
__nlocale_changed = 1;
if (ret == _LDP_LOADED)
_numeric_locale.grouping = _numeric_locale.grouping =
__fix_locale_grouping_str(_numeric_locale.grouping); __fix_locale_grouping_str(_numeric_locale.grouping);
return (ret); return (ret);
} }

View File

@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
#include "namespace.h" #include "namespace.h"
#include <arpa/inet.h> #include <arpa/inet.h>
#include <errno.h>
#include <rune.h> #include <rune.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -59,22 +60,35 @@ _Read_RuneMagi(fp)
_RuneLocale *rl; _RuneLocale *rl;
_RuneEntry *rr; _RuneEntry *rr;
struct stat sb; struct stat sb;
int x; int x, saverr;
if (_fstat(fileno(fp), &sb) < 0) if (_fstat(fileno(fp), &sb) < 0)
return(0); return (NULL);
if (sb.st_size < sizeof(_RuneLocale)) if (sb.st_size < sizeof(_RuneLocale)) {
return(0); errno = EFTYPE;
return (NULL);
}
if ((data = malloc(sb.st_size)) == NULL) if ((data = malloc(sb.st_size)) == NULL) {
return(0); errno = ENOMEM;
return (NULL);
}
errno = 0;
rewind(fp); /* Someone might have read the magic number once already */ rewind(fp); /* Someone might have read the magic number once already */
if (errno) {
saverr = errno;
free(data);
errno = saverr;
return (NULL);
}
if (fread(data, sb.st_size, 1, fp) != 1) { if (fread(data, sb.st_size, 1, fp) != 1) {
saverr = errno;
free(data); free(data);
return(0); errno = saverr;
return (NULL);
} }
rl = (_RuneLocale *)data; rl = (_RuneLocale *)data;
@ -84,7 +98,8 @@ _Read_RuneMagi(fp)
if (memcmp(rl->magic, _RUNE_MAGIC_1, sizeof(rl->magic))) { if (memcmp(rl->magic, _RUNE_MAGIC_1, sizeof(rl->magic))) {
free(data); free(data);
return(0); errno = EFTYPE;
return (NULL);
} }
rl->invalid_rune = ntohl(rl->invalid_rune); rl->invalid_rune = ntohl(rl->invalid_rune);
@ -103,21 +118,24 @@ _Read_RuneMagi(fp)
rl->variable = rl->runetype_ext.ranges + rl->runetype_ext.nranges; rl->variable = rl->runetype_ext.ranges + rl->runetype_ext.nranges;
if (rl->variable > lastp) { if (rl->variable > lastp) {
free(data); free(data);
return(0); errno = EFTYPE;
return (NULL);
} }
rl->maplower_ext.ranges = (_RuneEntry *)rl->variable; rl->maplower_ext.ranges = (_RuneEntry *)rl->variable;
rl->variable = rl->maplower_ext.ranges + rl->maplower_ext.nranges; rl->variable = rl->maplower_ext.ranges + rl->maplower_ext.nranges;
if (rl->variable > lastp) { if (rl->variable > lastp) {
free(data); free(data);
return(0); errno = EFTYPE;
return (NULL);
} }
rl->mapupper_ext.ranges = (_RuneEntry *)rl->variable; rl->mapupper_ext.ranges = (_RuneEntry *)rl->variable;
rl->variable = rl->mapupper_ext.ranges + rl->mapupper_ext.nranges; rl->variable = rl->mapupper_ext.ranges + rl->mapupper_ext.nranges;
if (rl->variable > lastp) { if (rl->variable > lastp) {
free(data); free(data);
return(0); errno = EFTYPE;
return (NULL);
} }
for (x = 0; x < rl->runetype_ext.nranges; ++x) { for (x = 0; x < rl->runetype_ext.nranges; ++x) {
@ -131,7 +149,8 @@ _Read_RuneMagi(fp)
rl->variable = rr[x].types + len; rl->variable = rr[x].types + len;
if (rl->variable > lastp) { if (rl->variable > lastp) {
free(data); free(data);
return(0); errno = EFTYPE;
return (NULL);
} }
while (len-- > 0) while (len-- > 0)
rr[x].types[len] = ntohl(rr[x].types[len]); rr[x].types[len] = ntohl(rr[x].types[len]);
@ -156,7 +175,8 @@ _Read_RuneMagi(fp)
} }
if (((char *)rl->variable) + rl->variable_len > (char *)lastp) { if (((char *)rl->variable) + rl->variable_len > (char *)lastp) {
free(data); free(data);
return(0); errno = EFTYPE;
return (NULL);
} }
/* /*
@ -174,5 +194,5 @@ _Read_RuneMagi(fp)
if (!rl->mapupper_ext.nranges) if (!rl->mapupper_ext.nranges)
rl->mapupper_ext.ranges = 0; rl->mapupper_ext.ranges = 0;
return(rl); return (rl);
} }

View File

@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
#include "lnumeric.h" /* for __numeric_load_locale() */ #include "lnumeric.h" /* for __numeric_load_locale() */
#include "lmessages.h" /* for __messages_load_locale() */ #include "lmessages.h" /* for __messages_load_locale() */
#include "setlocale.h" #include "setlocale.h"
#include "ldpart.h"
#include "../stdtime/timelocal.h" /* for __time_load_locale() */ #include "../stdtime/timelocal.h" /* for __time_load_locale() */
/* /*
@ -92,7 +93,7 @@ static char saved_categories[_LC_LAST][ENCODING_LEN + 1];
static char current_locale_string[_LC_LAST * (ENCODING_LEN + 1/*"/"*/ + 1)]; static char current_locale_string[_LC_LAST * (ENCODING_LEN + 1/*"/"*/ + 1)];
static char *currentlocale(void); static char *currentlocale(void);
static int wrap_setrunelocale(char *); static int wrap_setrunelocale(const char *);
static char *loadlocale(int); static char *loadlocale(int);
char * char *
@ -206,7 +207,10 @@ setlocale(category, locale)
for (j = 1; j < i; j++) { for (j = 1; j < i; j++) {
(void)strcpy(new_categories[j], (void)strcpy(new_categories[j],
saved_categories[j]); saved_categories[j]);
(void)loadlocale(j); if (loadlocale(j) == NULL) {
(void)strcpy(new_categories[j], "C");
(void)loadlocale(j);
}
} }
errno = saverr; errno = saverr;
return (NULL); return (NULL);
@ -235,27 +239,24 @@ currentlocale()
} }
static int static int
wrap_setrunelocale(locale) wrap_setrunelocale(const char *locale)
char *locale;
{ {
int ret = setrunelocale(locale); int ret = setrunelocale((char *)locale);
if (ret != 0) { if (ret != 0) {
errno = ret; errno = ret;
return (-1); return (_LDP_ERROR);
} }
return (0); return (_LDP_LOADED);
} }
static char * static char *
loadlocale(category) loadlocale(category)
int category; int category;
{ {
char *ret;
char *new = new_categories[category]; char *new = new_categories[category];
char *old = current_categories[category]; char *old = current_categories[category];
int (*func)(); int (*func)(const char *);
int saverr;
if ((new[0] == '.' && if ((new[0] == '.' &&
(new[1] == '\0' || (new[1] == '.' && new[2] == '\0'))) || (new[1] == '\0' || (new[1] == '.' && new[2] == '\0'))) ||
@ -278,8 +279,10 @@ loadlocale(category)
return (NULL); return (NULL);
} }
_PathLocale = strdup(p); _PathLocale = strdup(p);
if (_PathLocale == NULL) if (_PathLocale == NULL) {
errno = ENOMEM;
return (NULL); return (NULL);
}
} else } else
_PathLocale = _PATH_LOCALE; _PathLocale = _PATH_LOCALE;
} }
@ -311,15 +314,11 @@ loadlocale(category)
if (strcmp(new, old) == 0) if (strcmp(new, old) == 0)
return (old); return (old);
ret = func(new) != 0 ? NULL : new; if (func(new) != _LDP_ERROR) {
if (ret == NULL) {
saverr = errno;
if (func(old) != 0 && func("C") == 0)
(void)strcpy(old, "C");
errno = saverr;
} else
(void)strcpy(old, new); (void)strcpy(old, new);
return (old);
}
return (ret); return (NULL);
} }

View File

@ -54,12 +54,15 @@ extern int _MSKanji_init(_RuneLocale *);
extern _RuneLocale *_Read_RuneMagi(FILE *); extern _RuneLocale *_Read_RuneMagi(FILE *);
int int
setrunelocale(encoding) setrunelocale(char *encoding)
char *encoding;
{ {
FILE *fp; FILE *fp;
char name[PATH_MAX]; char name[PATH_MAX];
_RuneLocale *rl; _RuneLocale *rl;
int saverr, ret;
static char ctype_encoding[ENCODING_LEN + 1];
static _RuneLocale *CachedRuneLocale;
static int Cached__mb_cur_max;
if (!encoding || !*encoding || strlen(encoding) > ENCODING_LEN || if (!encoding || !*encoding || strlen(encoding) > ENCODING_LEN ||
(encoding[0] == '.' && (encoding[0] == '.' &&
@ -71,12 +74,25 @@ setrunelocale(encoding)
/* /*
* The "C" and "POSIX" locale are always here. * The "C" and "POSIX" locale are always here.
*/ */
if (!strcmp(encoding, "C") || !strcmp(encoding, "POSIX")) { if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
_CurrentRuneLocale = &_DefaultRuneLocale; _CurrentRuneLocale = &_DefaultRuneLocale;
__mb_cur_max = 1; __mb_cur_max = 1;
return (0); return (0);
} }
/*
* If the locale name is the same as our cache, use the cache.
*/
if (CachedRuneLocale != NULL &&
strcmp(encoding, ctype_encoding) == 0) {
_CurrentRuneLocale = CachedRuneLocale;
__mb_cur_max = Cached__mb_cur_max;
return (0);
}
/*
* Slurp the locale file into the cache.
*/
if (_PathLocale == NULL) { if (_PathLocale == NULL) {
char *p = getenv("PATH_LOCALE"); char *p = getenv("PATH_LOCALE");
@ -90,7 +106,7 @@ setrunelocale(encoding)
return (ENAMETOOLONG); return (ENAMETOOLONG);
_PathLocale = strdup(p); _PathLocale = strdup(p);
if (_PathLocale == NULL) if (_PathLocale == NULL)
return (errno); return (ENOMEM);
} else } else
_PathLocale = _PATH_LOCALE; _PathLocale = _PATH_LOCALE;
} }
@ -103,25 +119,38 @@ setrunelocale(encoding)
if ((fp = fopen(name, "r")) == NULL) if ((fp = fopen(name, "r")) == NULL)
return (errno); return (errno);
if ((rl = _Read_RuneMagi(fp)) == 0) { if ((rl = _Read_RuneMagi(fp)) == NULL) {
fclose(fp); saverr = errno;
return (EFTYPE); (void)fclose(fp);
return (saverr);
} }
fclose(fp); (void)fclose(fp);
if (!rl->encoding[0]) if (strcmp(rl->encoding, "NONE") == 0)
return (EFTYPE); ret = _none_init(rl);
else if (!strcmp(rl->encoding, "NONE")) else if (strcmp(rl->encoding, "UTF2") == 0)
return (_none_init(rl)); ret = _UTF2_init(rl);
else if (!strcmp(rl->encoding, "UTF2")) else if (strcmp(rl->encoding, "EUC") == 0)
return (_UTF2_init(rl)); ret = _EUC_init(rl);
else if (!strcmp(rl->encoding, "EUC")) else if (strcmp(rl->encoding, "BIG5") == 0)
return (_EUC_init(rl)); ret = _BIG5_init(rl);
else if (!strcmp(rl->encoding, "BIG5")) else if (strcmp(rl->encoding, "MSKanji") == 0)
return (_BIG5_init(rl)); ret = _MSKanji_init(rl);
else if (!strcmp(rl->encoding, "MSKanji"))
return (_MSKanji_init(rl));
else else
return (EFTYPE); ret = EFTYPE;
if (ret == 0) {
if (CachedRuneLocale != NULL) {
/* See euc.c */
if (strcmp(CachedRuneLocale->encoding, "EUC") == 0)
free(CachedRuneLocale->variable);
free(CachedRuneLocale);
}
CachedRuneLocale = _CurrentRuneLocale;
Cached__mb_cur_max = __mb_cur_max;
(void)strcpy(ctype_encoding, encoding);
} else
free(rl);
return (ret);
} }