diff --git a/src/internal/stdio_impl.h b/src/internal/stdio_impl.h index e1325fe..72c5519 100644 --- a/src/internal/stdio_impl.h +++ b/src/internal/stdio_impl.h @@ -47,6 +47,7 @@ struct _IO_FILE { unsigned char *shend; off_t shlim, shcnt; FILE *prev_locked, *next_locked; + struct __locale_struct *locale; }; size_t __stdio_read(FILE *, unsigned char *, size_t); diff --git a/src/locale/iconv.c b/src/locale/iconv.c index e6121ae..1eeea94 100644 --- a/src/locale/iconv.c +++ b/src/locale/iconv.c @@ -5,6 +5,7 @@ #include #include #include +#include "locale_impl.h" #define UTF_32BE 0300 #define UTF_16LE 0301 @@ -165,9 +166,12 @@ size_t iconv(iconv_t cd0, char **restrict in, size_t *restrict inb, char **restr int err; unsigned char type = map[-1]; unsigned char totype = tomap[-1]; + locale_t *ploc = &CURRENT_LOCALE, loc = *ploc; if (!in || !*in || !*inb) return 0; + *ploc = UTF8_LOCALE; + for (; *inb; *in+=l, *inb-=l) { c = *(unsigned char *)*in; l = 1; @@ -431,6 +435,7 @@ size_t iconv(iconv_t cd0, char **restrict in, size_t *restrict inb, char **restr break; } } + *ploc = loc; return x; ilseq: err = EILSEQ; @@ -445,5 +450,6 @@ starved: x = -1; end: errno = err; + *ploc = loc; return x; } diff --git a/src/stdio/fgetwc.c b/src/stdio/fgetwc.c index b261b44..e455cfe 100644 --- a/src/stdio/fgetwc.c +++ b/src/stdio/fgetwc.c @@ -1,8 +1,9 @@ #include "stdio_impl.h" +#include "locale_impl.h" #include #include -wint_t __fgetwc_unlocked(FILE *f) +static wint_t __fgetwc_unlocked_internal(FILE *f) { mbstate_t st = { 0 }; wchar_t wc; @@ -10,8 +11,6 @@ wint_t __fgetwc_unlocked(FILE *f) unsigned char b; size_t l; - if (f->mode <= 0) fwide(f, 1); - /* Convert character from buffer if possible */ if (f->rpos < f->rend) { l = mbrtowc(&wc, (void *)f->rpos, f->rend - f->rpos, &st); @@ -39,6 +38,16 @@ wint_t __fgetwc_unlocked(FILE *f) return wc; } +wint_t __fgetwc_unlocked(FILE *f) +{ + locale_t *ploc = &CURRENT_LOCALE, loc = *ploc; + if (f->mode <= 0) fwide(f, 1); + *ploc = f->locale; + wchar_t wc = __fgetwc_unlocked_internal(f); + *ploc = loc; + return wc; +} + wint_t fgetwc(FILE *f) { wint_t c; diff --git a/src/stdio/fputwc.c b/src/stdio/fputwc.c index 1bf165b..0be5666 100644 --- a/src/stdio/fputwc.c +++ b/src/stdio/fputwc.c @@ -1,4 +1,5 @@ #include "stdio_impl.h" +#include "locale_impl.h" #include #include #include @@ -7,8 +8,10 @@ wint_t __fputwc_unlocked(wchar_t c, FILE *f) { char mbc[MB_LEN_MAX]; int l; + locale_t *ploc = &CURRENT_LOCALE, loc = *ploc; if (f->mode <= 0) fwide(f, 1); + *ploc = f->locale; if (isascii(c)) { c = putc_unlocked(c, f); @@ -18,8 +21,11 @@ wint_t __fputwc_unlocked(wchar_t c, FILE *f) else f->wpos += l; } else { l = wctomb(mbc, c); - if (l < 0 || __fwritex((void *)mbc, l, f) < l) c = WEOF; + if (l < 0 || __fwritex((void *)mbc, l, f) < l) + c = WEOF; } + if (c==WEOF) f->flags |= F_ERR; + *ploc = loc; return c; } diff --git a/src/stdio/fputws.c b/src/stdio/fputws.c index 317d65f..0ed02f1 100644 --- a/src/stdio/fputws.c +++ b/src/stdio/fputws.c @@ -1,23 +1,28 @@ #include "stdio_impl.h" +#include "locale_impl.h" #include int fputws(const wchar_t *restrict ws, FILE *restrict f) { unsigned char buf[BUFSIZ]; size_t l=0; + locale_t *ploc = &CURRENT_LOCALE, loc = *ploc; FLOCK(f); fwide(f, 1); + *ploc = f->locale; while (ws && (l = wcsrtombs((void *)buf, (void*)&ws, sizeof buf, 0))+1 > 1) if (__fwritex(buf, l, f) < l) { FUNLOCK(f); + *ploc = loc; return -1; } FUNLOCK(f); + *ploc = loc; return l; /* 0 or -1 */ } diff --git a/src/stdio/fwide.c b/src/stdio/fwide.c index 8088e7a..8410b15 100644 --- a/src/stdio/fwide.c +++ b/src/stdio/fwide.c @@ -1,13 +1,14 @@ -#include #include "stdio_impl.h" - -#define SH (8*sizeof(int)-1) -#define NORMALIZE(x) ((x)>>SH | -((-(x))>>SH)) +#include "locale_impl.h" int fwide(FILE *f, int mode) { FLOCK(f); - if (!f->mode) f->mode = NORMALIZE(mode); + if (mode) { + if (!f->locale) f->locale = MB_CUR_MAX==1 + ? C_LOCALE : UTF8_LOCALE; + if (!f->mode) f->mode = mode>0 ? 1 : -1; + } mode = f->mode; FUNLOCK(f); return mode; diff --git a/src/stdio/ungetwc.c b/src/stdio/ungetwc.c index d4c7de3..80d6e20 100644 --- a/src/stdio/ungetwc.c +++ b/src/stdio/ungetwc.c @@ -1,4 +1,5 @@ #include "stdio_impl.h" +#include "locale_impl.h" #include #include #include @@ -8,15 +9,18 @@ wint_t ungetwc(wint_t c, FILE *f) { unsigned char mbc[MB_LEN_MAX]; int l=1; + locale_t *ploc = &CURRENT_LOCALE, loc = *ploc; FLOCK(f); if (f->mode <= 0) fwide(f, 1); + *ploc = f->locale; if (!f->rpos) __toread(f); if (!f->rpos || f->rpos < f->buf - UNGET + l || c == WEOF || (!isascii(c) && (l = wctomb((void *)mbc, c)) < 0)) { FUNLOCK(f); + *ploc = loc; return WEOF; } @@ -26,5 +30,6 @@ wint_t ungetwc(wint_t c, FILE *f) f->flags &= ~F_EOF; FUNLOCK(f); + *ploc = loc; return c; }