/* * hankaku.c 全角->半角変換 * * Copyright (C) 1997-1998 Masaki Chikama (Wren) * 1998- * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * */ /* $Id: hankaku.c,v 1.7 2001/03/22 11:10:13 chikama Exp $ */ #include #include #include #include "portab.h" #include "hankaku.h" #include "system.h" static const uint8_t hankakutable[3][192] = {{ // 0x8140 - 0x81ff ' ', 0xa4, 0xa1, ',', '.', 0xa5, ':', ';', '?', '!', 0xde, 0xdf, 0, '`', 0, '^', '~', '_', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xb0, 0, 0, '/', 0, 0, 0, '|', 0, 0, 0, '\'', 0, '"', '(', ')', 0, 0, '[', ']', '{', '}', 0, 0, 0, 0, 0xa2, 0xa3, 0, 0, 0, 0, '+', '-', 0, 0, 0, 0, '=', 0, '<', '>', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', '$', 0, 0, '%', '#', '&', '*', '@', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },{ // 0x8240 - 0x82ff 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0, 0, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0, 0, 0, 0, 0, 0, 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },{ // 0x8340 - 0x83ff 0xa7, 0xb1, 0xa8, 0xb2, 0xa9, 0xb3, 0xaa, 0xb4, 0xab, 0xb5, 0xb6, 0, 0xb7, 0, 0xb8, 0, 0xb9, 0, 0xba, 0, 0xbb, 0, 0xbc, 0, 0xbd, 0, 0xbe, 0, 0xbf, 0, 0xc0, 0, 0xc1, 0, 0xaf, 0xc2, 0, 0xc3, 0, 0xc4, 0, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0, 0, 0xcb, 0, 0, 0xcc, 0, 0, 0xcd, 0, 0, 0xce, 0, 0, 0xcf, 0xd0, 0, 0xd1, 0xd2, 0xd3, 0xac, 0xd4, 0xad, 0xd5, 0xae, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0, 0xdc, 0, 0, 0xa6, 0xdd, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }}; static const uint16_t kanatbl[] = { 0x8140, 0x8142, 0x8175, 0x8176, 0x8141, 0x8145, 0x82f0, 0x829f, 0x82a1, 0x82a3, 0x82a5, 0x82a7, 0x82e1, 0x82e3, 0x82e5, 0x82c1, 0x815b, 0x82a0, 0x82a2, 0x82a4, 0x82a6, 0x82a8, 0x82a9, 0x82ab, 0x82ad, 0x82af, 0x82b1, 0x82b3, 0x82b5, 0x82b7, 0x82b9, 0x82bb, 0x82bd, 0x82bf, 0x82c2, 0x82c4, 0x82c6, 0x82c8, 0x82c9, 0x82ca, 0x82cb, 0x82cc, 0x82cd, 0x82d0, 0x82d3, 0x82d6, 0x82d9, 0x82dc, 0x82dd, 0x82de, 0x82df, 0x82e0, 0x82e2, 0x82e4, 0x82e6, 0x82e7, 0x82e8, 0x82e9, 0x82ea, 0x82eb, 0x82ed, 0x82f1, 0x814a, 0x814b }; static const char zenkaku_digits[][3] = { {0x82, 0x4f, 0x00}, /* 0 */ {0x82, 0x50, 0x00}, /* 1 */ {0x82, 0x51, 0x00}, /* 2 */ {0x82, 0x52, 0x00}, /* 3 */ {0x82, 0x53, 0x00}, /* 4 */ {0x82, 0x54, 0x00}, /* 5 */ {0x82, 0x55, 0x00}, /* 6 */ {0x82, 0x56, 0x00}, /* 7 */ {0x82, 0x57, 0x00}, /* 8 */ {0x82, 0x58, 0x00}, /* 9 */ {0x81, 0x40, 0x00}, /* space */ }; static uint8_t *zen2han_sjis(const uint8_t *src) { uint8_t c0, c1; char *dst, *_dst; dst = _dst = malloc(strlen(src) + 1); if (dst == NULL) NOMEMERR(); while(0 != (c0 = *src++)) { if (c0 < 0x81) { *dst++ = c0; } else if (c0 <= 0x83) { c1 = *src++; uint8_t h = hankakutable[c0 - 0x81][c1 - 0x40]; if (h) { *dst++ = h; } else { *dst++ = c0; *dst++ = c1; } } else if (c0 < 0xa0){ *dst++ = c0; *dst++ = *src++; } else if (c0 < 0xe0){ *dst++ = c0; } else { *dst++ = c0; *dst++ = *src++; } } *dst = 0; return _dst; } static char *zen2han_utf8(const char *src) { char *dst, *_dst; dst = _dst = malloc(strlen(src) + 1); if (dst == NULL) NOMEMERR(); const char *p = src; while (*p) { const char *prev = p; switch (utf8_next_codepoint(&p)) { case L'’': *dst++ = '\''; break; case L'”': *dst++ = '"'; break; case L' ': *dst++ = ' '; break; case L'、': strcpy(dst, "、"); dst += 3; break; case L'。': strcpy(dst, "。"); dst += 3; break; case L'「': strcpy(dst, "「"); dst += 3; break; case L'」': strcpy(dst, "」"); dst += 3; break; case L'゛': strcpy(dst, "゙"); dst += 3; break; case L'゜': strcpy(dst, "゚"); dst += 3; break; case L'ァ': strcpy(dst, "ァ"); dst += 3; break; case L'ア': strcpy(dst, "ア"); dst += 3; break; case L'ィ': strcpy(dst, "ィ"); dst += 3; break; case L'イ': strcpy(dst, "イ"); dst += 3; break; case L'ゥ': strcpy(dst, "ゥ"); dst += 3; break; case L'ウ': strcpy(dst, "ウ"); dst += 3; break; case L'ェ': strcpy(dst, "ェ"); dst += 3; break; case L'エ': strcpy(dst, "エ"); dst += 3; break; case L'ォ': strcpy(dst, "ォ"); dst += 3; break; case L'オ': strcpy(dst, "オ"); dst += 3; break; case L'カ': strcpy(dst, "カ"); dst += 3; break; case L'キ': strcpy(dst, "キ"); dst += 3; break; case L'ク': strcpy(dst, "ク"); dst += 3; break; case L'ケ': strcpy(dst, "ケ"); dst += 3; break; case L'コ': strcpy(dst, "コ"); dst += 3; break; case L'サ': strcpy(dst, "サ"); dst += 3; break; case L'シ': strcpy(dst, "シ"); dst += 3; break; case L'ス': strcpy(dst, "ス"); dst += 3; break; case L'セ': strcpy(dst, "セ"); dst += 3; break; case L'ソ': strcpy(dst, "ソ"); dst += 3; break; case L'タ': strcpy(dst, "タ"); dst += 3; break; case L'チ': strcpy(dst, "チ"); dst += 3; break; case L'ッ': strcpy(dst, "ッ"); dst += 3; break; case L'ツ': strcpy(dst, "ツ"); dst += 3; break; case L'テ': strcpy(dst, "テ"); dst += 3; break; case L'ト': strcpy(dst, "ト"); dst += 3; break; case L'ナ': strcpy(dst, "ナ"); dst += 3; break; case L'ニ': strcpy(dst, "ニ"); dst += 3; break; case L'ヌ': strcpy(dst, "ヌ"); dst += 3; break; case L'ネ': strcpy(dst, "ネ"); dst += 3; break; case L'ノ': strcpy(dst, "ノ"); dst += 3; break; case L'ハ': strcpy(dst, "ハ"); dst += 3; break; case L'ヒ': strcpy(dst, "ヒ"); dst += 3; break; case L'フ': strcpy(dst, "フ"); dst += 3; break; case L'ヘ': strcpy(dst, "ヘ"); dst += 3; break; case L'ホ': strcpy(dst, "ホ"); dst += 3; break; case L'マ': strcpy(dst, "マ"); dst += 3; break; case L'ミ': strcpy(dst, "ミ"); dst += 3; break; case L'ム': strcpy(dst, "ム"); dst += 3; break; case L'メ': strcpy(dst, "メ"); dst += 3; break; case L'モ': strcpy(dst, "モ"); dst += 3; break; case L'ャ': strcpy(dst, "ャ"); dst += 3; break; case L'ヤ': strcpy(dst, "ヤ"); dst += 3; break; case L'ュ': strcpy(dst, "ュ"); dst += 3; break; case L'ユ': strcpy(dst, "ユ"); dst += 3; break; case L'ョ': strcpy(dst, "ョ"); dst += 3; break; case L'ヨ': strcpy(dst, "ヨ"); dst += 3; break; case L'ラ': strcpy(dst, "ラ"); dst += 3; break; case L'リ': strcpy(dst, "リ"); dst += 3; break; case L'ル': strcpy(dst, "ル"); dst += 3; break; case L'レ': strcpy(dst, "レ"); dst += 3; break; case L'ロ': strcpy(dst, "ロ"); dst += 3; break; case L'ワ': strcpy(dst, "ワ"); dst += 3; break; case L'ヲ': strcpy(dst, "ヲ"); dst += 3; break; case L'ン': strcpy(dst, "ン"); dst += 3; break; case L'・': strcpy(dst, "・"); dst += 3; break; case L'ー': strcpy(dst, "ー"); dst += 3; break; case L'!': *dst++ = '!'; break; case L'#': *dst++ = '#'; break; case L'$': *dst++ = '$'; break; case L'%': *dst++ = '%'; break; case L'&': *dst++ = '&'; break; case L'(': *dst++ = '('; break; case L')': *dst++ = ')'; break; case L'*': *dst++ = '*'; break; case L'+': *dst++ = '+'; break; case L',': *dst++ = ','; break; case L'-': *dst++ = '-'; break; case L'.': *dst++ = '.'; break; case L'/': *dst++ = '/'; break; case L'0': *dst++ = '0'; break; case L'1': *dst++ = '1'; break; case L'2': *dst++ = '2'; break; case L'3': *dst++ = '3'; break; case L'4': *dst++ = '4'; break; case L'5': *dst++ = '5'; break; case L'6': *dst++ = '6'; break; case L'7': *dst++ = '7'; break; case L'8': *dst++ = '8'; break; case L'9': *dst++ = '9'; break; case L':': *dst++ = ':'; break; case L';': *dst++ = ';'; break; case L'<': *dst++ = '<'; break; case L'=': *dst++ = '='; break; case L'>': *dst++ = '>'; break; case L'?': *dst++ = '?'; break; case L'@': *dst++ = '@'; break; case L'A': *dst++ = 'A'; break; case L'B': *dst++ = 'B'; break; case L'C': *dst++ = 'C'; break; case L'D': *dst++ = 'D'; break; case L'E': *dst++ = 'E'; break; case L'F': *dst++ = 'F'; break; case L'G': *dst++ = 'G'; break; case L'H': *dst++ = 'H'; break; case L'I': *dst++ = 'I'; break; case L'J': *dst++ = 'J'; break; case L'K': *dst++ = 'K'; break; case L'L': *dst++ = 'L'; break; case L'M': *dst++ = 'M'; break; case L'N': *dst++ = 'N'; break; case L'O': *dst++ = 'O'; break; case L'P': *dst++ = 'P'; break; case L'Q': *dst++ = 'Q'; break; case L'R': *dst++ = 'R'; break; case L'S': *dst++ = 'S'; break; case L'T': *dst++ = 'T'; break; case L'U': *dst++ = 'U'; break; case L'V': *dst++ = 'V'; break; case L'W': *dst++ = 'W'; break; case L'X': *dst++ = 'X'; break; case L'Y': *dst++ = 'Y'; break; case L'Z': *dst++ = 'Z'; break; case L'[': *dst++ = '['; break; case L']': *dst++ = ']'; break; case L'^': *dst++ = '^'; break; case L'_': *dst++ = '_'; break; case L'`': *dst++ = '`'; break; case L'a': *dst++ = 'a'; break; case L'b': *dst++ = 'b'; break; case L'c': *dst++ = 'c'; break; case L'd': *dst++ = 'd'; break; case L'e': *dst++ = 'e'; break; case L'f': *dst++ = 'f'; break; case L'g': *dst++ = 'g'; break; case L'h': *dst++ = 'h'; break; case L'i': *dst++ = 'i'; break; case L'j': *dst++ = 'j'; break; case L'k': *dst++ = 'k'; break; case L'l': *dst++ = 'l'; break; case L'm': *dst++ = 'm'; break; case L'n': *dst++ = 'n'; break; case L'o': *dst++ = 'o'; break; case L'p': *dst++ = 'p'; break; case L'q': *dst++ = 'q'; break; case L'r': *dst++ = 'r'; break; case L's': *dst++ = 's'; break; case L't': *dst++ = 't'; break; case L'u': *dst++ = 'u'; break; case L'v': *dst++ = 'v'; break; case L'w': *dst++ = 'w'; break; case L'x': *dst++ = 'x'; break; case L'y': *dst++ = 'y'; break; case L'z': *dst++ = 'z'; break; case L'{': *dst++ = '{'; break; case L'|': *dst++ = '|'; break; case L'}': *dst++ = '}'; break; case L' ̄': *dst++ = '~'; break; case L'¥': *dst++ = '\\'; break; default: while (prev < p) *dst++ = *prev++; break; } } *dst = 0; return _dst; } uint8_t *zen2han(const uint8_t *src, CharacterEncoding enc) { switch (enc) { case SHIFT_JIS: return zen2han_sjis(src); case UTF8: return zen2han_utf8(src); default: return (uint8_t *)src; } } uint8_t *han2zen(const uint8_t *src, CharacterEncoding enc) { if (enc != SHIFT_JIS) return (uint8_t *)src; // Not implemented uint8_t c0; uint8_t *dst, *_dst; dst = _dst = malloc(strlen(src) * 2 + 1); if (dst == NULL) NOMEMERR(); while(0 != (c0 = *src++)) { if (c0 == 0x20) { *dst++ = 0x81; *dst++ = 0x40; } else if (c0 < 0x80) { *dst++ = c0; } else if (c0 >= 0xe0) { *dst++ = (char)c0; *dst++ = *src++; } else if (c0 >= 0xa0) { const uint16_t kana = kanatbl[c0 - 0xa0]; *dst++ = kana >> 8; *dst++ = kana & 0xff; } else { *dst++ = (char)c0; *dst++ = *src++; } } *dst = 0; return _dst; } char *format_number(int n, int width, char *buf) { if (width) { sprintf(buf, "%*d", width, n); return buf + strlen(buf) - width; } sprintf(buf, "%d", n); return buf; } char *format_number_zenkaku(int n, int width, char *buf) { char work[256]; char *dst = buf; for (char *s = format_number(n, width, work); *s; s++) { const char *p = zenkaku_digits[*s == ' ' ? 10 : *s - '0']; while (*p) *dst++ = *p++; } *dst = '\0'; return buf; }