diff options
-rw-r--r-- | lib/libc/locale/collate.c | 126 | ||||
-rw-r--r-- | lib/libc/locale/collate.h | 3 | ||||
-rw-r--r-- | lib/libc/locale/euc.c | 35 | ||||
-rw-r--r-- | lib/libc/locale/ldpart.c | 88 | ||||
-rw-r--r-- | lib/libc/locale/ldpart.h | 4 | ||||
-rw-r--r-- | lib/libc/locale/lmessages.c | 23 | ||||
-rw-r--r-- | lib/libc/locale/lmonetary.c | 9 | ||||
-rw-r--r-- | lib/libc/locale/lnumeric.c | 7 | ||||
-rw-r--r-- | lib/libc/locale/rune.c | 48 | ||||
-rw-r--r-- | lib/libc/locale/setlocale.c | 37 | ||||
-rw-r--r-- | lib/libc/locale/setrunelocale.c | 71 |
11 files changed, 259 insertions, 192 deletions
diff --git a/lib/libc/locale/collate.c b/lib/libc/locale/collate.c index 83684d1..c7e6c12 100644 --- a/lib/libc/locale/collate.c +++ b/lib/libc/locale/collate.c @@ -40,68 +40,115 @@ __FBSDID("$FreeBSD$"); #include "collate.h" #include "setlocale.h" +#include "ldpart.h" #include "libc_private.h" int __collate_load_error = 1; int __collate_substitute_nontrivial; -char __collate_version[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_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; int -__collate_load_tables(encoding) - char *encoding; +__collate_load_tables(const char *encoding) { - char buf[PATH_MAX]; 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; - __collate_load_error = 1; - if (!encoding) { - __collate_load_error = save_load_error; - return -1; + /* 'encoding' must be already checked. */ + if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) { + __collate_load_error = 1; + return (_LDP_CACHE); } - if (!strcmp(encoding, "C") || !strcmp(encoding, "POSIX")) - return 0; - if (!_PathLocale) { - __collate_load_error = save_load_error; - return -1; + + /* + * If the locale name is the same as our cache, use the cache. + */ + 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 */ (void)strcpy(buf, _PathLocale); (void)strcat(buf, "/"); (void)strcat(buf, encoding); (void)strcat(buf, "/LC_COLLATE"); - if ((fp = fopen(buf, "r")) == NULL) { - __collate_load_error = save_load_error; - return -1; + if ((fp = fopen(buf, "r")) == NULL) + return (_LDP_ERROR); + + if ((TMP_substitute_table = + malloc(sizeof(__collate_substitute_table))) == NULL) { + (void)fclose(fp); + errno = ENOMEM; + return (_LDP_ERROR); } - FREAD(__collate_version, sizeof(__collate_version), 1, fp); - if (strcmp(__collate_version, COLLATE_VERSION) != 0) { + if ((TMP_char_pri_table = + malloc(sizeof(__collate_char_pri_table))) == NULL) { + free(TMP_substitute_table); (void)fclose(fp); - return -1; + errno = ENOMEM; + return (_LDP_ERROR); } - FREAD(__collate_substitute_table, sizeof(__collate_substitute_table), - 1, fp); - FREAD(__collate_char_pri_table, sizeof(__collate_char_pri_table), 1, - fp); - FREAD(__collate_chain_pri_table, sizeof(__collate_chain_pri_table), 1, - fp); + 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); - __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; for (i = 0; i < UCHAR_MAX + 1; i++) { @@ -111,8 +158,9 @@ __collate_load_tables(encoding) break; } } + __collate_load_error = 0; - return 0; + return (_LDP_LOADED); } u_char * @@ -152,8 +200,8 @@ __collate_lookup(t, len, prim, sec) *len = 1; *prim = *sec = 0; - for(p2 = __collate_chain_pri_table; p2->str[0]; p2++) { - if(strncmp(t, p2->str, strlen(p2->str)) == 0) { + for (p2 = __collate_chain_pri_table; p2->str[0]; p2++) { + if (strncmp(t, p2->str, strlen(p2->str)) == 0) { *len = strlen(p2->str); *prim = p2->prim; *sec = p2->sec; diff --git a/lib/libc/locale/collate.h b/lib/libc/locale/collate.h index d8dd045..4a0eefb 100644 --- a/lib/libc/locale/collate.h +++ b/lib/libc/locale/collate.h @@ -48,7 +48,6 @@ struct __collate_st_chain_pri { extern int __collate_load_error; extern int __collate_substitute_nontrivial; -extern char __collate_version[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_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 u_char *__collate_strdup(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 *); int __collate_range_cmp(int, int); #ifdef COLLATE_DEBUG diff --git a/lib/libc/locale/euc.c b/lib/libc/locale/euc.c index 9008a91..43194fa 100644 --- a/lib/libc/locale/euc.c +++ b/lib/libc/locale/euc.c @@ -63,40 +63,36 @@ _EUC_init(rl) _RuneLocale *rl; { _EucInfo *ei; - int x; + int x, new__mb_cur_max; char *v, *e; rl->sgetrune = _EUC_sgetrune; rl->sputrune = _EUC_sputrune; - if (!rl->variable) { - free(rl); + if (rl->variable == NULL) return (EFTYPE); - } - v = (char *) rl->variable; + + v = (char *)rl->variable; while (*v == ' ' || *v == '\t') ++v; - if ((ei = malloc(sizeof(_EucInfo))) == NULL) { - free(rl); + if ((ei = malloc(sizeof(_EucInfo))) == NULL) return (ENOMEM); - } - __mb_cur_max = 0; + + new__mb_cur_max = 0; 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)) { - free(rl); free(ei); return (EFTYPE); } - if (__mb_cur_max < ei->count[x]) - __mb_cur_max = ei->count[x]; + if (new__mb_cur_max < ei->count[x]) + new__mb_cur_max = ei->count[x]; while (*v == ' ' || *v == '\t') ++v; - ei->bits[x] = (int) strtol(v, &e, 0); + ei->bits[x] = (int)strtol(v, &e, 0); if (v == e || !(v = e)) { - free(rl); free(ei); return (EFTYPE); } @@ -105,18 +101,13 @@ _EUC_init(rl) } ei->mask = (int)strtol(v, &e, 0); if (v == e || !(v = e)) { - free(rl); free(ei); return (EFTYPE); } - if (sizeof(_EucInfo) <= rl->variable_len) { - memcpy(rl->variable, ei, sizeof(_EucInfo)); - free(ei); - } else { - rl->variable = ei; - } + rl->variable = ei; rl->variable_len = sizeof(_EucInfo); _CurrentRuneLocale = rl; + __mb_cur_max = new__mb_cur_max; return (0); } diff --git a/lib/libc/locale/ldpart.c b/lib/libc/locale/ldpart.c index 0e276cf..1933312 100644 --- a/lib/libc/locale/ldpart.c +++ b/lib/libc/locale/ldpart.c @@ -42,7 +42,6 @@ __FBSDID("$FreeBSD$"); #include "ldpart.h" static int split_lines(char *, const char *); -static void set_from_buf(const char *, int, const char **); int __part_load_locale(const char *name, @@ -53,35 +52,25 @@ __part_load_locale(const char *name, int locale_buf_size_min, const char **dst_localebuf) { - static char locale_buf_C[] = "C"; - static int num_lines; - int saverr; - int fd; - char *lbuf; - char *p; - const char *plim; - char filename[PATH_MAX]; + int saverr, fd, i, num_lines; + char *lbuf, *p; + const char *plim; + char filename[PATH_MAX]; struct stat st; - size_t namesize; - size_t bufsize; - int save_using_locale; - - save_using_locale = *using_locale; - *using_locale = 0; + size_t namesize, bufsize; /* 'name' must be already checked. */ - - if (!strcmp(name, "C") || !strcmp(name, "POSIX")) - return 0; + if (strcmp(name, "C") == 0 || strcmp(name, "POSIX") == 0) { + *using_locale = 0; + return (_LDP_CACHE); + } /* * If the locale name is the same as our cache, use the cache. */ - lbuf = locale_buf; - if (lbuf != NULL && strcmp(name, lbuf) == 0) { - set_from_buf(lbuf, num_lines, dst_localebuf); + if (locale_buf != NULL && strcmp(name, locale_buf) == 0) { *using_locale = 1; - return 0; + return (_LDP_CACHE); } /* @@ -90,16 +79,14 @@ __part_load_locale(const char *name, namesize = strlen(name) + 1; /* 'PathLocale' must be already set & checked. */ - /* Range checking not needed, 'name' size is limited */ strcpy(filename, _PathLocale); strcat(filename, "/"); strcat(filename, name); strcat(filename, "/"); strcat(filename, category_filename); - fd = _open(filename, O_RDONLY); - if (fd < 0) - goto no_locale; + if ((fd = _open(filename, O_RDONLY)) < 0) + return (_LDP_ERROR); if (_fstat(fd, &st) != 0) goto bad_locale; if (st.st_size <= 0) { @@ -107,18 +94,15 @@ __part_load_locale(const char *name, goto bad_locale; } bufsize = namesize + st.st_size; - locale_buf = NULL; - lbuf = (lbuf == NULL || lbuf == locale_buf_C) ? - malloc(bufsize) : reallocf(lbuf, bufsize); - if (lbuf == NULL) + if ((lbuf = malloc(bufsize)) == NULL) { + errno = ENOMEM; goto bad_locale; + } (void)strcpy(lbuf, name); p = lbuf + namesize; plim = p + st.st_size; if (_read(fd, p, (size_t) st.st_size) != st.st_size) goto bad_lbuf; - if (_close(fd) != 0) - goto bad_lbuf; /* * Parse the locale file into localebuf. */ @@ -133,37 +117,37 @@ __part_load_locale(const char *name, num_lines = locale_buf_size_min; else { 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. */ + if (locale_buf != NULL) + free(locale_buf); 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; - return 0; + return (_LDP_LOADED); -reset_locale: - locale_buf = locale_buf_C; - save_using_locale = 0; bad_lbuf: - saverr = errno; - free(lbuf); + saverr = errno; + free(lbuf); errno = saverr; bad_locale: - saverr = errno; - (void)_close(fd); + saverr = errno; + (void)_close(fd); errno = saverr; -no_locale: - *using_locale = save_using_locale; - return -1; + return (_LDP_ERROR); } static int -split_lines(char *p, const char *plim) +split_lines(char *p, const char *plim) { int i; @@ -174,13 +158,3 @@ split_lines(char *p, const char *plim) 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; -} - diff --git a/lib/libc/locale/ldpart.h b/lib/libc/locale/ldpart.h index 049ab56..becca06 100644 --- a/lib/libc/locale/ldpart.h +++ b/lib/libc/locale/ldpart.h @@ -29,6 +29,10 @@ #ifndef _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, int, const char **); diff --git a/lib/libc/locale/lmessages.c b/lib/libc/locale/lmessages.c index dd1239e..ed58c99 100644 --- a/lib/libc/locale/lmessages.c +++ b/lib/libc/locale/lmessages.c @@ -52,18 +52,19 @@ static char *_messages_locale_buf; int __messages_load_locale(const char *name) { - /* - * 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; + int ret; - return __part_load_locale(name, &_messages_using_locale, - _messages_locale_buf, "LC_MESSAGES", - LCMESSAGES_SIZE_FULL, LCMESSAGES_SIZE_MIN, - (const char **)&_messages_locale); + ret = __part_load_locale(name, &_messages_using_locale, + _messages_locale_buf, "LC_MESSAGES", + LCMESSAGES_SIZE_FULL, LCMESSAGES_SIZE_MIN, + (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 * diff --git a/lib/libc/locale/lmonetary.c b/lib/libc/locale/lmonetary.c index eddd1ce..3dc6df0 100644 --- a/lib/libc/locale/lmonetary.c +++ b/lib/libc/locale/lmonetary.c @@ -63,7 +63,7 @@ static int _monetary_using_locale; static char *_monetary_locale_buf; static char -cnv(const char *str) +cnv(const char *str) { int i = strtol(str, NULL, 10); @@ -77,12 +77,13 @@ __monetary_load_locale(const char *name) { int ret; - __mlocale_changed = 1; ret = __part_load_locale(name, &_monetary_using_locale, _monetary_locale_buf, "LC_MONETARY", LCMONETARY_SIZE, LCMONETARY_SIZE, (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 = __fix_locale_grouping_str(_monetary_locale.mon_grouping); @@ -102,7 +103,7 @@ __monetary_load_locale(const char *name) } struct lc_monetary_T * -__get_current_monetary_locale(void) +__get_current_monetary_locale(void) { return (_monetary_using_locale ? &_monetary_locale diff --git a/lib/libc/locale/lnumeric.c b/lib/libc/locale/lnumeric.c index 0fb0aab..b1b975e 100644 --- a/lib/libc/locale/lnumeric.c +++ b/lib/libc/locale/lnumeric.c @@ -53,14 +53,15 @@ __numeric_load_locale(const char *name) { int ret; - __nlocale_changed = 1; ret = __part_load_locale(name, &_numeric_using_locale, _numeric_locale_buf, "LC_NUMERIC", LCNUMERIC_SIZE, LCNUMERIC_SIZE, (const char **)&_numeric_locale); - if (ret == 0 && _numeric_using_locale) + if (ret != _LDP_ERROR) + __nlocale_changed = 1; + if (ret == _LDP_LOADED) _numeric_locale.grouping = - __fix_locale_grouping_str(_numeric_locale.grouping); + __fix_locale_grouping_str(_numeric_locale.grouping); return (ret); } diff --git a/lib/libc/locale/rune.c b/lib/libc/locale/rune.c index c67773c..63a50de 100644 --- a/lib/libc/locale/rune.c +++ b/lib/libc/locale/rune.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include "namespace.h" #include <arpa/inet.h> +#include <errno.h> #include <rune.h> #include <stdio.h> #include <string.h> @@ -59,22 +60,35 @@ _Read_RuneMagi(fp) _RuneLocale *rl; _RuneEntry *rr; struct stat sb; - int x; + int x, saverr; if (_fstat(fileno(fp), &sb) < 0) - return(0); + return (NULL); - if (sb.st_size < sizeof(_RuneLocale)) - return(0); + if (sb.st_size < sizeof(_RuneLocale)) { + errno = EFTYPE; + return (NULL); + } - if ((data = malloc(sb.st_size)) == NULL) - return(0); + if ((data = malloc(sb.st_size)) == NULL) { + errno = ENOMEM; + return (NULL); + } + errno = 0; 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) { + saverr = errno; free(data); - return(0); + errno = saverr; + return (NULL); } rl = (_RuneLocale *)data; @@ -84,7 +98,8 @@ _Read_RuneMagi(fp) if (memcmp(rl->magic, _RUNE_MAGIC_1, sizeof(rl->magic))) { free(data); - return(0); + errno = EFTYPE; + return (NULL); } rl->invalid_rune = ntohl(rl->invalid_rune); @@ -103,21 +118,24 @@ _Read_RuneMagi(fp) rl->variable = rl->runetype_ext.ranges + rl->runetype_ext.nranges; if (rl->variable > lastp) { free(data); - return(0); + errno = EFTYPE; + return (NULL); } rl->maplower_ext.ranges = (_RuneEntry *)rl->variable; rl->variable = rl->maplower_ext.ranges + rl->maplower_ext.nranges; if (rl->variable > lastp) { free(data); - return(0); + errno = EFTYPE; + return (NULL); } rl->mapupper_ext.ranges = (_RuneEntry *)rl->variable; rl->variable = rl->mapupper_ext.ranges + rl->mapupper_ext.nranges; if (rl->variable > lastp) { free(data); - return(0); + errno = EFTYPE; + return (NULL); } for (x = 0; x < rl->runetype_ext.nranges; ++x) { @@ -131,7 +149,8 @@ _Read_RuneMagi(fp) rl->variable = rr[x].types + len; if (rl->variable > lastp) { free(data); - return(0); + errno = EFTYPE; + return (NULL); } while (len-- > 0) 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) { free(data); - return(0); + errno = EFTYPE; + return (NULL); } /* @@ -174,5 +194,5 @@ _Read_RuneMagi(fp) if (!rl->mapupper_ext.nranges) rl->mapupper_ext.ranges = 0; - return(rl); + return (rl); } diff --git a/lib/libc/locale/setlocale.c b/lib/libc/locale/setlocale.c index 6b249a9..525ca8f 100644 --- a/lib/libc/locale/setlocale.c +++ b/lib/libc/locale/setlocale.c @@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$"); #include "lnumeric.h" /* for __numeric_load_locale() */ #include "lmessages.h" /* for __messages_load_locale() */ #include "setlocale.h" +#include "ldpart.h" #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 *currentlocale(void); -static int wrap_setrunelocale(char *); +static int wrap_setrunelocale(const char *); static char *loadlocale(int); char * @@ -206,7 +207,10 @@ setlocale(category, locale) for (j = 1; j < i; j++) { (void)strcpy(new_categories[j], saved_categories[j]); - (void)loadlocale(j); + if (loadlocale(j) == NULL) { + (void)strcpy(new_categories[j], "C"); + (void)loadlocale(j); + } } errno = saverr; return (NULL); @@ -235,27 +239,24 @@ currentlocale() } static int -wrap_setrunelocale(locale) - char *locale; +wrap_setrunelocale(const char *locale) { - int ret = setrunelocale(locale); + int ret = setrunelocale((char *)locale); if (ret != 0) { errno = ret; - return (-1); + return (_LDP_ERROR); } - return (0); + return (_LDP_LOADED); } static char * loadlocale(category) int category; { - char *ret; char *new = new_categories[category]; char *old = current_categories[category]; - int (*func)(); - int saverr; + int (*func)(const char *); if ((new[0] == '.' && (new[1] == '\0' || (new[1] == '.' && new[2] == '\0'))) || @@ -278,8 +279,10 @@ loadlocale(category) return (NULL); } _PathLocale = strdup(p); - if (_PathLocale == NULL) + if (_PathLocale == NULL) { + errno = ENOMEM; return (NULL); + } } else _PathLocale = _PATH_LOCALE; } @@ -311,15 +314,11 @@ loadlocale(category) if (strcmp(new, old) == 0) return (old); - ret = func(new) != 0 ? NULL : new; - if (ret == NULL) { - saverr = errno; - if (func(old) != 0 && func("C") == 0) - (void)strcpy(old, "C"); - errno = saverr; - } else + if (func(new) != _LDP_ERROR) { (void)strcpy(old, new); + return (old); + } - return (ret); + return (NULL); } diff --git a/lib/libc/locale/setrunelocale.c b/lib/libc/locale/setrunelocale.c index 11d97bd..f1a01fc 100644 --- a/lib/libc/locale/setrunelocale.c +++ b/lib/libc/locale/setrunelocale.c @@ -54,12 +54,15 @@ extern int _MSKanji_init(_RuneLocale *); extern _RuneLocale *_Read_RuneMagi(FILE *); int -setrunelocale(encoding) - char *encoding; +setrunelocale(char *encoding) { FILE *fp; char name[PATH_MAX]; _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 || (encoding[0] == '.' && @@ -71,12 +74,25 @@ setrunelocale(encoding) /* * 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; __mb_cur_max = 1; 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) { char *p = getenv("PATH_LOCALE"); @@ -90,7 +106,7 @@ setrunelocale(encoding) return (ENAMETOOLONG); _PathLocale = strdup(p); if (_PathLocale == NULL) - return (errno); + return (ENOMEM); } else _PathLocale = _PATH_LOCALE; } @@ -103,25 +119,38 @@ setrunelocale(encoding) if ((fp = fopen(name, "r")) == NULL) return (errno); - if ((rl = _Read_RuneMagi(fp)) == 0) { - fclose(fp); - return (EFTYPE); + if ((rl = _Read_RuneMagi(fp)) == NULL) { + saverr = errno; + (void)fclose(fp); + return (saverr); } - fclose(fp); + (void)fclose(fp); - if (!rl->encoding[0]) - return (EFTYPE); - else if (!strcmp(rl->encoding, "NONE")) - return (_none_init(rl)); - else if (!strcmp(rl->encoding, "UTF2")) - return (_UTF2_init(rl)); - else if (!strcmp(rl->encoding, "EUC")) - return (_EUC_init(rl)); - else if (!strcmp(rl->encoding, "BIG5")) - return (_BIG5_init(rl)); - else if (!strcmp(rl->encoding, "MSKanji")) - return (_MSKanji_init(rl)); + if (strcmp(rl->encoding, "NONE") == 0) + ret = _none_init(rl); + else if (strcmp(rl->encoding, "UTF2") == 0) + ret = _UTF2_init(rl); + else if (strcmp(rl->encoding, "EUC") == 0) + ret = _EUC_init(rl); + else if (strcmp(rl->encoding, "BIG5") == 0) + ret = _BIG5_init(rl); + else if (strcmp(rl->encoding, "MSKanji") == 0) + ret = _MSKanji_init(rl); 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); } |