diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/locale/iconv.c | 47 |
1 files changed, 45 insertions, 2 deletions
diff --git a/src/locale/iconv.c b/src/locale/iconv.c index 0696b555..2107b055 100644 --- a/src/locale/iconv.c +++ b/src/locale/iconv.c @@ -18,6 +18,7 @@ #define UTF_8 0310 #define EUC_JP 0320 #define SHIFT_JIS 0321 +#define ISO2022_JP 0322 #define GB18030 0330 #define GBK 0331 #define GB2312 0332 @@ -41,6 +42,7 @@ static const unsigned char charmaps[] = "ascii\0usascii\0iso646\0iso646us\0\0\307" "eucjp\0\0\320" "shiftjis\0sjis\0\0\321" +"iso2022jp\0\0\322" "gb18030\0\0\330" "gbk\0\0\331" "gb2312\0\0\332" @@ -123,6 +125,7 @@ static size_t extract_to(iconv_t cd) iconv_t iconv_open(const char *to, const char *from) { size_t f, t; + struct stateful_cd *scd; if ((t = find_charmap(to))==-1 || (f = find_charmap(from))==-1 @@ -132,8 +135,9 @@ iconv_t iconv_open(const char *to, const char *from) } iconv_t cd = combine_to_from(t, f); - if (0) { - struct stateful_cd *scd = malloc(sizeof *scd); + switch (charmaps[f]) { + case ISO2022_JP: + scd = malloc(sizeof *scd); if (!scd) return (iconv_t)-1; scd->base_cd = cd; scd->state = 0; @@ -294,6 +298,45 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri c = jis0208[c][d]; if (!c) goto ilseq; break; + case ISO2022_JP: + if (c >= 128) goto ilseq; + if (c == '\033') { + l = 3; + if (*inb < 3) goto starved; + c = *((unsigned char *)*in + 1); + d = *((unsigned char *)*in + 2); + if (c != '(' && c != '$') goto ilseq; + switch (128*(c=='$') + d) { + case 'B': scd->state=0; continue; + case 'J': scd->state=1; continue; + case 'I': scd->state=4; continue; + case 128+'@': scd->state=2; continue; + case 128+'B': scd->state=3; continue; + } + goto ilseq; + } + switch (scd->state) { + case 1: + if (c=='\\') c = 0xa5; + if (c=='~') c = 0x203e; + break; + case 2: + case 3: + l = 2; + if (*inb < 2) goto starved; + d = *((unsigned char *)*in + 1); + c -= 0x21; + d -= 0x21; + if (c >= 84 || d >= 94) goto ilseq; + c = jis0208[c][d]; + if (!c) goto ilseq; + break; + case 4: + if (c-0x60 < 0x1f) goto ilseq; + if (c-0x21 < 0x5e) c += 0xff61-0x21; + break; + } + break; case GB2312: if (c < 128) break; if (c < 0xa1) goto ilseq; |