use restrict everywhere it's required by c99 and/or posix 2008
[musl] / src / locale / iconv.c
index 4e46c7e..7b341fe 100644 (file)
@@ -6,25 +6,20 @@
 #include <limits.h>
 #include <stdint.h>
 
-#define UTF_32BE    000
-#define UTF_16LE    001
-#define UTF_16BE    002
-#define UTF_32LE    003
-#define UCS2BE      004
-#define UCS2LE      005
-#define WCHAR_T     007
-
-#define US_ASCII    021
-#define UTF_8       022
-#define LATIN_9     024
-#define TIS_620     025
-#define JIS_0201    026
-
-#define EUC         031
-#define EUC_TW      032
-#define SHIFT_JIS   033
-#define BIG5        034
-#define GBK         035
+#define UTF_32BE    0300
+#define UTF_16LE    0301
+#define UTF_16BE    0302
+#define UTF_32LE    0303
+#define UCS2BE      0304
+#define UCS2LE      0305
+#define WCHAR_T     0306
+#define US_ASCII    0307
+#define UTF_8       0310
+#define EUC_JP      0320
+#define SHIFT_JIS   0321
+#define GB18030     0330
+#define GBK         0331
+#define GB2312      0332
 
 /* FIXME: these are not implemented yet
  * EUC:   A1-FE A1-FE
 
 /* Definitions of charmaps. Each charmap consists of:
  * 1. Empty-string-terminated list of null-terminated aliases.
- * 2. Special type code or bits per character.
- * 3. Number of elided entries (128 for specials).
- * 4. Character table (size determined by fields 2 and 3). */
+ * 2. Special type code or number of elided entries.
+ * 3. Character table (size determined by field 2). */
 
 static const unsigned char charmaps[] =
-"utf8\0\0\022\x80"
-"wchart\0\0\007\x80"
-
-"ucs2\0ucs2be\0\0\004\x80"
-"ucs2le\0\0\005\x80"
-
-"utf16\0utf16be\0\0\002\x80"
-"utf16le\0\0\001\x80"
-
-"ucs4\0ucs4be\0utf32\0utf32be\0\0\000\x80"
-"ucs4le\0utf32le\0\0\003\x80"
-
-"ascii\0iso646\0usascii\0\0\021\x80"
-"latin1\0iso88591\0\0\x09\x80"
-"latin9\0iso885915\0\0\024\x80"
-"tis620\0iso885911\0\0\025\x80"
-"jis0201\0\0\026\x80"
-
-"iso88592\0\0\x0a\x21"
-"\x04\x61\x1b\x14\x29\x3d\x69\x75\x0a\x2a"
-"\x60\x79\x45\x56\x5e\xad\xf4\xb5\x17\x2c"
-"\x05\x6d\x2b\x14\x2d\x3e\x6d\x75\x2c\x2e"
-"\x61\x7d\x55\x96\x5e\xdd\xfa\xc5\x17\x55"
-"\xc1\x08\x23\x10\x31\x39\x19\x74\x0c\x43"
-"\xc9\x60\xb4\x8c\x46\xcd\x38\xe3\x10\x44"
-"\x43\x1d\x35\x0d\x35\x50\x59\x73\x0d\x56"
-"\x6e\x69\x03\x17\x37\xdd\x88\xf5\x4d\x55"
-"\xe1\x88\x33\x10\x39\x3a\x1d\x74\x4e\x43"
-"\xe9\x64\xb4\xce\x46\xed\xb8\xf3\x50\x44"
-"\x44\x21\x35\x0f\x3d\x51\xd9\x73\x4f\x56"
-"\x6f\xe9\x13\x17\x3f\xfd\x8c\x95\x2d"
-
-"iso88593\0\0\x0a\x21"
-"\x26\x61\x3b\x0a\x29\x00\x90\x74\x0a\x2a"
-"\x30\x79\xe5\x11\x4d\xad\x00\xb0\x17\x2c"
-"\x27\xc9\x32\x0b\x2d\xb5\x94\x74\x0b\x2e"
-"\x31\x7d\xf5\x51\x4d\xbd\x00\xc0\x17\x30"
-"\xc1\x08\x03\x00\x31\x0a\x21\x74\x0c\x32"
-"\xc9\x28\xb3\x0c\x33\xcd\x38\xf3\x0c\x00"
-"\xd1\x48\x33\x0d\x35\x20\x59\x73\x0d\x47"
-"\xd9\x68\xb3\x0d\x37\x6c\x71\xf5\x0d\x38"
-"\xe1\x88\x03\x00\x39\x0b\x25\x74\x0e\x3a"
-"\xe9\xa8\xb3\x0e\x3b\xed\xb8\xf3\x0e\x00"
-"\xf1\xc8\x33\x0f\x3d\x21\xd9\x73\x4f\x47"
-"\xf9\xe8\xb3\x0f\x3f\x6d\x75\x95\x2d"
-
-"iso88594\0\0\x0a\x21"
-"\x04\xe1\x64\x15\x29\x28\xed\x74\x0a\x2a"
-"\x60\x49\x24\x92\x59\xad\xf4\xf5\x0a\x2c"
-"\x05\x6d\x7b\x15\x2d\x29\xf1\x74\x2c\x2e"
-"\x61\x4d\x34\xd2\x59\x4a\xf9\xb5\x14\x40"
-"\xc1\x08\x33\x0c\x31\xc5\x18\xe3\x12\x43"
-"\xc9\x60\xb4\x8c\x45\xcd\x38\xa3\x12\x44"
-"\x45\x31\x65\x13\x35\xd5\x58\x73\x0d\x36"
-"\x72\x69\xb3\x0d\x37\x68\xa9\xf5\x4d\x40"
-"\xe1\x88\x33\x0e\x39\xe5\x98\xf3\x52\x43"
-"\xe9\x64\xb4\xce\x45\xed\xb8\xb3\x52\x44"
-"\x46\x35\x75\x13\x3d\xf5\xd8\x73\x0f\x3e"
-"\x73\xe9\xb3\x0f\x3f\x69\xad\x95\x2d"
-
-"iso88595\0\0\x0e\x21"
-"\x01\x84\x00\x31\x40\x10\x10\x05\x84\x01"
-"\x71\x40\x20\x10\x09\x84\x02\xb1\x40\x30"
-"\x10\xad\x80\x03\xf1\x40\x40\x10\x11\x84"
-"\x04\x31\x41\x50\x10\x15\x84\x05\x71\x41"
-"\x60\x10\x19\x84\x06\xb1\x41\x70\x10\x1d"
-"\x84\x07\xf1\x41\x80\x10\x21\x84\x08\x31"
-"\x42\x90\x10\x25\x84\x09\x71\x42\xa0\x10"
-"\x29\x84\x0a\xb1\x42\xb0\x10\x2d\x84\x0b"
-"\xf1\x42\xc0\x10\x31\x84\x0c\x31\x43\xd0"
-"\x10\x35\x84\x0d\x71\x43\xe0\x10\x39\x84"
-"\x0e\xb1\x43\xf0\x10\x3d\x84\x0f\xf1\x43"
-"\x00\x11\x41\x84\x10\x31\x44\x10\x11\x45"
-"\x84\x11\x71\x44\x20\x11\x49\x84\x12\xb1"
-"\x44\x30\x11\x4d\x84\x13\xf1\x44\x58\x84"
-"\x51\x84\x14\x31\x45\x50\x11\x55\x84\x15"
-"\x71\x45\x60\x11\x59\x84\x16\xb1\x45\x70"
-"\x11\xa7\x80\x17\xf1\x45\x00"
-
-"iso88596\0\0\x0b\x21"
-"\x00\x00\x00\x00\x48\x01\x00\x00\x00\x00"
-"\x00\x00\x00\x00\x00\x18\xdc\x0a\x00\x00"
-"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-"\x00\x00\x00\x00\x00\xc0\x86\x01\x00\x00"
-"\x00\x7c\x18\x00\x21\x16\xf1\x88\x49\x5c"
-"\x62\x13\x9f\x18\xc5\x29\x56\xf1\x8a\x59"
-"\xdc\x62\x17\xbf\x18\xc6\x31\x96\xf1\x8c"
-"\x69\x5c\x63\x1b\xdf\x18\xc7\x39\xd6\x31"
-"\x00\x00\x00\x00\x00\x00\x00\xc8\x41\x16"
-"\xf2\x90\x89\x5c\x64\x23\x1f\x19\xc9\x49"
-"\x56\xf2\x92\x99\xdc\x64\x27\x3f\x19\xca"
-"\x51\x96\x32\x00\x00\x00\x00\x00\x00\x00"
-"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-"\x00"
-
-"iso88597\0\0\x0e\x21"
-"\x18\x60\x06\x38\x0a\xb0\x82\xaf\xa0\x29"
-"\x70\x0a\xa0\x02\xa9\x80\xde\xb0\x0a\xb0"
-"\x02\xad\x00\x00\x50\x01\xc2\x02\xb1\x80"
-"\x2c\x30\x0b\x10\x0e\x85\x83\xe1\x70\x0b"
-"\x20\x0e\x89\x83\xe2\xb0\x0b\x30\x0e\xbd"
-"\x80\xe3\xf0\x38\x40\x0e\x91\x83\xe4\x30"
-"\x39\x50\x0e\x95\x83\xe5\x70\x39\x60\x0e"
-"\x99\x83\xe6\xb0\x39\x70\x0e\x9d\x83\xe7"
-"\xf0\x39\x80\x0e\xa1\x03\x00\x30\x3a\x90"
-"\x0e\xa5\x83\xe9\x70\x3a\xa0\x0e\xa9\x83"
-"\xea\xb0\x3a\xb0\x0e\xad\x83\xeb\xf0\x3a"
-"\xc0\x0e\xb1\x83\xec\x30\x3b\xd0\x0e\xb5"
-"\x83\xed\x70\x3b\xe0\x0e\xb9\x83\xee\xb0"
-"\x3b\xf0\x0e\xbd\x83\xef\xf0\x3b\x00\x0f"
-"\xc1\x83\xf0\x30\x3c\x10\x0f\xc5\x83\xf1"
-"\x70\x3c\x20\x0f\xc9\x83\xf2\xb0\x3c\x30"
-"\x0f\xcd\x83\xf3\x00\x00\x00"
-
-"iso88598\0\0\x0e\x21"
-"\x00\x80\x28\x30\x0a\x90\x02\xa5\x80\x29"
-"\x70\x0a\xa0\x02\xa9\xc0\x35\xb0\x0a\xb0"
-"\x02\xad\x80\x2b\xf0\x0a\xc0\x02\xb1\x80"
-"\x2c\x30\x0b\xd0\x02\xb5\x80\x2d\x70\x0b"
-"\xe0\x02\xb9\xc0\x3d\xb0\x0b\xf0\x02\xbd"
-"\x80\x2f\x00\x00\x00\x00\x00\x00\x00\x00"
-"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-"\x00\x00\x00\x00\x00\x00\x00\x00\x70\x01"
-"\x42\x17\xd1\x85\x74\x31\x5d\x50\x17\xd5"
-"\x85\x75\x71\x5d\x60\x17\xd9\x85\x76\xb1"
-"\x5d\x70\x17\xdd\x85\x77\xf1\x5d\x80\x17"
-"\xe1\x85\x78\x31\x5e\x90\x17\xe5\x85\x79"
-"\x71\x5e\xa0\x17\xe9\x85\x7a\x01\x00\x00"
-"\x00\x0e\xe0\x03\x08\x00\x00"
-
-"iso88599\0\0\x09\x50"
-"\x1e\xa3\x49\x9b\x46\xad\x9a\xb5\x6b\xd8"
-"\xb2\x69\xdb\xc6\x0d\xa6\xd7\x6f\xe0\xc2"
-"\x89\x1b\x47\xae\x9c\xb9\x73\xe8\xd2\xa9"
-"\x5b\xc7\xae\x9d\xbb\x77\x1f\xe3\xc9\x9b"
-"\x47\xaf\x9e\xbd\x7b\xf8\xf2\xe9\xdb\xc7"
-"\x2f\xe6\xd7\x7f"
-
-"iso885910\0\0\x0e\x21"
-"\x04\x81\x44\x20\x12\xa8\x04\x28\x81\x4d"
-"\x70\x0a\xec\x04\x10\x01\x58\x60\x16\xf4"
-"\x05\xad\x80\x5a\xa0\x14\xc0\x02\x05\xc1"
-"\x44\x30\x12\xac\x04\x29\xc1\x4d\x70\x0b"
-"\xf0\x04\x11\x41\x58\x70\x16\xf8\x05\x15"
-"\xe0\x5a\xb0\x14\x00\x04\xc1\x80\x30\x30"
-"\x0c\x10\x03\xc5\x80\x31\xe0\x12\x30\x04"
-"\xc9\x00\x46\xb0\x0c\x58\x04\xcd\x80\x33"
-"\xf0\x0c\x40\x03\x45\x01\x53\x30\x0d\x50"
-"\x03\xd5\x80\x35\x80\x16\x60\x03\x72\x81"
-"\x36\xb0\x0d\x70\x03\xdd\x80\x37\xf0\x0d"
-"\x04\x04\xe1\x80\x38\x30\x0e\x90\x03\xe5"
-"\x80\x39\xf0\x12\x34\x04\xe9\x40\x46\xb0"
-"\x0e\x5c\x04\xed\x80\x3b\xf0\x0e\xc0\x03"
-"\x46\x41\x53\x30\x0f\xd0\x03\xf5\x80\x3d"
-"\x90\x16\xe0\x03\x73\x81\x3e\xb0\x0f\xf0"
-"\x03\xfd\x80\x3f\x80\x13\x00"
-
-"iso885913\0\0\x0e\x21"
-"\x1d\xa0\x28\x30\x0a\x90\x02\x1e\xa0\x29"
-"\x70\x0a\x60\x03\xa9\x80\x55\xb0\x0a\xb0"
-"\x02\xad\x80\x2b\x60\x0c\xc0\x02\xb1\x80"
-"\x2c\x30\x0b\x70\x80\xb5\x80\x2d\x70\x0b"
-"\xe0\x03\xb9\xc0\x55\xb0\x0b\xf0\x02\xbd"
-"\x80\x2f\x60\x0e\x10\x04\x2e\x01\x40\x60"
-"\x10\x10\x03\xc5\x00\x46\x20\x11\x30\x04"
-"\xc9\x40\x5e\x60\x11\x88\x04\x36\x81\x4a"
-"\xb0\x13\x80\x05\x43\x41\x51\x30\x0d\x30"
-"\x05\xd5\x80\x35\x70\x0d\xc8\x05\x41\x81"
-"\x56\xa0\x16\x70\x03\x7b\x41\x5f\xf0\x0d"
-"\x14\x04\x2f\x41\x40\x70\x10\x90\x03\xe5"
-"\x40\x46\x30\x11\x34\x04\xe9\x80\x5e\x70"
-"\x11\x8c\x04\x37\xc1\x4a\xc0\x13\x84\x05"
-"\x44\x81\x51\x30\x0f\x34\x05\xf5\x80\x3d"
-"\x70\x0f\xcc\x05\x42\xc1\x56\xb0\x16\xf0"
-"\x03\x7c\x81\x5f\x90\x01\x02"
-
-"iso885914\0\0\x0d\x21"
-"\x02\x7e\xc0\x8f\x02\x85\xb0\x10\x14\xfc"
-"\x29\x00\xf4\xa9\x40\xd0\x2f\x78\x79\xdf"
-"\x0a\x5c\x01\x5e\xf0\xf0\x1f\x1e\x24\x84"
-"\x04\x20\x1f\xe4\x6d\x81\x95\x0f\xf4\x57"
-"\x7e\xd0\x83\xf9\x79\x4f\xe8\x0b\x7d\x98"
-"\x07\x06\xc1\x40\x18\x0c\x03\x62\x50\x0c"
-"\x8c\xc1\x31\x40\x06\xc9\x40\x19\x2c\x03"
-"\x66\xd0\x0c\x9c\xc1\x33\xa0\x0b\xd1\x40"
-"\x1a\x4c\x03\x6a\x50\x0d\xac\x81\x9a\xc7"
-"\x06\xd9\x40\x1b\x6c\x03\x6e\xd0\x0d\xec"
-"\xc2\x37\x00\x07\xe1\x40\x1c\x8c\x03\x72"
-"\x50\x0e\xcc\xc1\x39\x40\x07\xe9\x40\x1d"
-"\xac\x03\x76\xd0\x0e\xdc\xc1\x3b\xa8\x0b"
-"\xf1\x40\x1e\xcc\x03\x7a\x50\x0f\xec\xc1"
-"\x9a\xc7\x07\xf9\x40\x1f\xec\x03\x7e\xd0"
-"\x0f\xee\xc2\x3f\x00"
-
-"iso885916\0\0\x0e\x21"
-"\x04\x41\x41\x10\x14\xb0\x82\x1e\x20\x58"
-"\x70\x0a\x84\x05\xa9\x00\x86\xb0\x0a\xe4"
-"\x05\xad\x80\x5e\xb0\x17\xc0\x02\xb1\x00"
-"\x43\x20\x14\xf4\x05\x1d\xa0\x2d\x70\x0b"
-"\xf8\x05\x0d\x41\x86\xb0\x0b\x48\x05\x53"
-"\x01\x5e\xc0\x17\x00\x03\xc1\x80\x30\x20"
-"\x10\x10\x03\x06\x81\x31\x70\x0c\x20\x03"
-"\xc9\x80\x32\xb0\x0c\x30\x03\xcd\x80\x33"
-"\xf0\x0c\x40\x04\x43\x81\x34\x30\x0d\x50"
-"\x03\x50\x81\x35\xa0\x15\xc0\x05\xd9\x80"
-"\x36\xb0\x0d\x70\x03\x18\x81\x86\xf0\x0d"
-"\x80\x03\xe1\x80\x38\x30\x10\x90\x03\x07"
-"\x81\x39\x70\x0e\xa0\x03\xe9\x80\x3a\xb0"
-"\x0e\xb0\x03\xed\x80\x3b\xf0\x0e\x44\x04"
-"\x44\x81\x3c\x30\x0f\xd0\x03\x51\x81\x3d"
-"\xb0\x15\xc4\x05\xf9\x80\x3e\xb0\x0f\xf0"
-"\x03\x19\xc1\x86\xf0\x0f\x00"
-
-"windows1252\0\0\x0e\x00"
-"\xac\x20\x00\xa0\x01\x4a\x06\x1e\xa0\x09"
-"\x08\x02\x86\x80\xc6\x02\x0c\x08\x16\xe4"
-"\x80\x52\x01\x00\xd0\x17\x00\x00\x00\x00"
-"\x06\x98\x01\x72\x80\x1d\xa0\x08\x38\x01"
-"\x52\x80\xdc\x82\x48\x18\x16\xe8\x80\x53"
-"\x01\x00\xe0\x17\xe0\x05\xa0\x40\x28\x20"
-"\x0a\x8c\x02\xa4\x40\x29\x60\x0a\x9c\x02"
-"\xa8\x40\x2a\xa0\x0a\xac\x02\xac\x40\x2b"
-"\xe0\x0a\xbc\x02\xb0\x40\x2c\x20\x0b\xcc"
-"\x02\xb4\x40\x2d\x60\x0b\xdc\x02\xb8\x40"
-"\x2e\xa0\x0b\xec\x02\xbc\x40\x2f\xe0\x0b"
-"\xfc\x02\xc0\x40\x30\x20\x0c\x0c\x03\xc4"
-"\x40\x31\x60\x0c\x1c\x03\xc8\x40\x32\xa0"
-"\x0c\x2c\x03\xcc\x40\x33\xe0\x0c\x3c\x03"
-"\xd0\x40\x34\x20\x0d\x4c\x03\xd4\x40\x35"
-"\x60\x0d\x5c\x03\xd8\x40\x36\xa0\x0d\x6c"
-"\x03\xdc\x40\x37\xe0\x0d\x7c\x03\xe0\x40"
-"\x38\x20\x0e\x8c\x03\xe4\x40\x39\x60\x0e"
-"\x9c\x03\xe8\x40\x3a\xa0\x0e\xac\x03\xec"
-"\x40\x3b\xe0\x0e\xbc\x03\xf0\x40\x3c\x20"
-"\x0f\xcc\x03\xf4\x40\x3d\x60\x0f\xdc\x03"
-"\xf8\x40\x3e\xa0\x0f\xec\x03\xfc\x40\x3f"
-"\xe0\x0f\xfc\x03"
+"utf8\0\0\310"
+"wchart\0\0\306"
+"ucs2\0ucs2be\0\0\304"
+"ucs2le\0\0\305"
+"utf16\0utf16be\0\0\302"
+"utf16le\0\0\301"
+"ucs4\0ucs4be\0utf32\0utf32be\0\0\300"
+"ucs4le\0utf32le\0\0\303"
+"ascii\0usascii\0iso646\0iso646us\0\0\307"
+"eucjp\0\0\320"
+"shiftjis\0sjis\0\0\321"
+"gb18030\0\0\330"
+"gbk\0\0\331"
+"gb2312\0\0\332"
+#include "codepages.h"
 ;
 
+static const unsigned short legacy_chars[] = {
+#include "legacychars.h"
+};
 
+static const unsigned short jis0208[84][94] = {
+#include "jis0208.h"
+};
 
-static int fuzzycmp(const char *a, const char *b)
+static const unsigned short gb18030[126][190] = {
+#include "gb18030.h"
+};
+
+static int fuzzycmp(const unsigned char *a, const unsigned char *b)
 {
        for (; *a && *b; a++, b++) {
                while (*a && (*a|32U)-'a'>26 && *a-'0'>10U) a++;
@@ -292,25 +71,30 @@ static int fuzzycmp(const char *a, const char *b)
        return *a != *b;
 }
 
-static int find_charmap(const char *name)
+static size_t find_charmap(const void *name)
 {
        const unsigned char *s;
        for (s=charmaps; *s; ) {
                if (!fuzzycmp(name, s)) {
-                       for (; *s; s+=strlen(s)+1);
+                       for (; *s; s+=strlen((void *)s)+1);
                        return s+1-charmaps;
                }
-               s += strlen(s)+1;
-               if (!*s) s += ((128-s[2])*s[1]+7)/8 + 3;
+               s += strlen((void *)s)+1;
+               if (!*s) {
+                       if (s[1] > 0200) s+=2;
+                       else s+=2+(128U-s[1])/4*5;
+               }
        }
        return -1;
 }
 
 iconv_t iconv_open(const char *to, const char *from)
 {
-       int f, t;
+       size_t f, t;
 
-       if ((t = find_charmap(to)) < 0 || (f = find_charmap(from)) < 0) {
+       if ((t = find_charmap(to))==-1
+        || (f = find_charmap(from))==-1
+        || (charmaps[t] >= 0320)) {
                errno = EINVAL;
                return (iconv_t)-1;
        }
@@ -338,65 +122,46 @@ static void put_16(unsigned char *s, unsigned c, int e)
 
 static unsigned get_32(const unsigned char *s, int e)
 {
+       e &= 3;
        return s[e]+0U<<24 | s[e^1]<<16 | s[e^2]<<8 | s[e^3];
 }
 
 static void put_32(unsigned char *s, unsigned c, int e)
 {
+       e &= 3;
        s[e^0] = c>>24;
        s[e^1] = c>>16;
        s[e^2] = c>>8;
        s[e^3] = c;
 }
 
-
-
-#define GET_MAPPING(m, i, n) ( (1<<(n))-1 & ( \
-       (m)[(i)*(n)/8] >> ((n)%8*(i)%8) | \
-       (m)[(i)*(n)/8+1] << 8-((n)%8*(i)%8) | \
-       (m)[(i)*(n)/8+2] << 16-((n)%8*(i)%8)     ) )
-
-static unsigned get_mapping(const unsigned char *m, unsigned c, unsigned n)
-{
-       switch (n) {
-       default:
-       case 9:  return m[c*9/8]>>c%8 | m[c*9/8+1]<<8-c%8 & (1<<n)-1;
-       case 10: return m[c*10/8]>>2*c%8 | m[c*10/8+1]<<8-2*c%8 & (1<<n)-1;
-       case 11: return GET_MAPPING(m, c, 11);
-       case 13: return GET_MAPPING(m, c, 13);
-       case 14: return GET_MAPPING(m, c, 14);
-       }
-}
-
 /* Adapt as needed */
 #define mbrtowc_utf8 mbrtowc
 #define wctomb_utf8 wctomb
 
-#include <stdio.h>
-size_t iconv(iconv_t cd0, char **in, size_t *inb, char **out, size_t *outb)
+size_t iconv(iconv_t cd0, char **restrict in, size_t *restrict inb, char **restrict out, size_t *restrict outb)
 {
        size_t x=0;
        unsigned long cd = (unsigned long)cd0;
        unsigned to = cd & 0xffff;
        unsigned from = cd >> 16;
-       const unsigned char *map = charmaps+from+2;
-       const unsigned char *tomap = charmaps+to+2;
+       const unsigned char *map = charmaps+from+1;
+       const unsigned char *tomap = charmaps+to+1;
        mbstate_t st = {0};
        wchar_t wc;
        unsigned c, d;
        size_t k, l;
        int err;
-       unsigned elide = map[-1] + 128;
-       unsigned toelide = tomap[-1] + 128;
-       unsigned char type = map[-2];
-       unsigned char totype = tomap[-2];
+       unsigned char type = map[-1];
+       unsigned char totype = tomap[-1];
 
        if (!in || !*in || !*inb) return 0;
 
        for (; *inb; *in+=l, *inb-=l) {
                c = *(unsigned char *)*in;
                l = 1;
-               if (type < 8 || c >= 0x80) switch (type) {
+
+               if (c >= 128 || type-UTF_32BE < 7U) switch (type) {
                case UTF_8:
                        l = mbrtowc_utf8(&wc, *in, *inb, &st);
                        if (!l) l++;
@@ -404,33 +169,8 @@ size_t iconv(iconv_t cd0, char **in, size_t *inb, char **out, size_t *outb)
                        else if (l == (size_t)-2) goto starved;
                        c = wc;
                        break;
-               case LATIN_9:
-                       if ((unsigned)c - 0xa4 <= 0xbe - 0xa4) {
-                               static const unsigned char map[] = {
-                                       0, 0x60, 0, 0x61, 0, 0, 0, 0, 0, 0, 0,
-                                       0, 0, 0, 0, 0x7d, 0, 0, 0, 0x7e, 0, 0, 0,
-                                       0x52, 0x53, 0x78
-                               };
-                               if (c == 0xa4) c = 0x20ac;
-                               else if (map[c-0xa5]) c = 0x100 | map[c-0xa5];
-                       }
-                       break;
-               case TIS_620:
-                       if (c >= 0xa1) c += 0x0e01-0xa1;
-                       break;
-               case JIS_0201:
-                       if (c >= 0xa1)
-                               if (c <= 0xdf) c += 0xff61-0xa1;
-                               else goto ilseq;
-                       break;
-               case 9: case 10: case 11: case 13: case 14:
-                       if (c < elide) break;
-                       c = get_mapping(map, c-elide, type);
-                       if (!c) {
                case US_ASCII:
-                               goto ilseq;
-                       }
-                       break;
+                       goto ilseq;
                case WCHAR_T:
                        l = sizeof(wchar_t);
                        if (*inb < l) goto starved;
@@ -440,7 +180,7 @@ size_t iconv(iconv_t cd0, char **in, size_t *inb, char **out, size_t *outb)
                case UTF_32LE:
                        l = 4;
                        if (*inb < 4) goto starved;
-                       c = get_32(*in, type);
+                       c = get_32((void *)*in, type);
                        }
                        if (c-0xd800u < 0x800u || c >= 0x110000u) goto ilseq;
                        break;
@@ -450,17 +190,101 @@ size_t iconv(iconv_t cd0, char **in, size_t *inb, char **out, size_t *outb)
                case UTF_16LE:
                        l = 2;
                        if (*inb < 2) goto starved;
-                       c = get_16(*in, type);
+                       c = get_16((void *)*in, type);
                        if ((unsigned)(c-0xdc00) < 0x400) goto ilseq;
                        if ((unsigned)(c-0xd800) < 0x400) {
                                if (type-UCS2BE < 2U) goto ilseq;
                                l = 4;
                                if (*inb < 4) goto starved;
-                               d = get_16(*in + 2, from);
-                               if ((unsigned)(c-0xdc00) >= 0x400) goto ilseq;
-                               c = ((c-0xd800)<<10) | (d-0xdc00);
+                               d = get_16((void *)(*in + 2), type);
+                               if ((unsigned)(d-0xdc00) >= 0x400) goto ilseq;
+                               c = ((c-0xd7c0)<<10) + (d-0xdc00);
+                       }
+                       break;
+               case SHIFT_JIS:
+                       if (c-0xa1 <= 0xdf-0xa1) {
+                               c += 0xff61-0xa1;
+                               break;
+                       }
+                       l = 2;
+                       if (*inb < 2) goto starved;
+                       d = *((unsigned char *)*in + 1);
+                       if (c-129 <= 159-129) c -= 129;
+                       else if (c-224 <= 239-224) c -= 193;
+                       else goto ilseq;
+                       c *= 2;
+                       if (d-64 <= 158-64) {
+                               if (d==127) goto ilseq;
+                               if (d>127) d--;
+                               d -= 64;
+                       } else if (d-159 <= 252-159) {
+                               c++;
+                               d -= 159;
+                       }
+                       c = jis0208[c][d];
+                       if (!c) goto ilseq;
+                       break;
+               case EUC_JP:
+                       l = 2;
+                       if (*inb < 2) goto starved;
+                       d = *((unsigned char *)*in + 1);
+                       if (c==0x8e) {
+                               c = d;
+                               if (c-0xa1 > 0xdf-0xa1) goto ilseq;
+                               c += 0xff61 - 0xa1;
+                               break;
+                       }
+                       c -= 0xa1;
+                       d -= 0xa1;
+                       if (c >= 84 || d >= 94) goto ilseq;
+                       c = jis0208[c][d];
+                       if (!c) goto ilseq;
+                       break;
+               case GB2312:
+                       if (c < 0xa1) goto ilseq;
+               case GBK:
+               case GB18030:
+                       c -= 0x81;
+                       if (c >= 126) goto ilseq;
+                       l = 2;
+                       if (*inb < 2) goto starved;
+                       d = *((unsigned char *)*in + 1);
+                       if (d < 0xa1 && type == GB2312) goto ilseq;
+                       if (d-0x40>=191 || d==127) {
+                               if (d-'0'>9 || type != GB18030)
+                                       goto ilseq;
+                               l = 4;
+                               if (*inb < 4) goto starved;
+                               c = (10*c + d-'0') * 1260;
+                               d = *((unsigned char *)*in + 2);
+                               if (d-0x81>126) goto ilseq;
+                               c += 10*(d-0x81);
+                               d = *((unsigned char *)*in + 3);
+                               if (d-'0'>9) goto ilseq;
+                               c += d-'0';
+                               c += 128;
+                               for (d=0; d<=c; ) {
+                                       k = 0;
+                                       for (int i=0; i<126; i++)
+                                               for (int j=0; j<190; j++)
+                                                       if (gb18030[i][j]-d <= c-d)
+                                                               k++;
+                                       d = c+1;
+                                       c += k;
+                               }
+                               break;
                        }
+                       d -= 0x40;
+                       if (d>63) d--;
+                       c = gb18030[c][d];
                        break;
+               default:
+                       if (c < 128+type) break;
+                       c -= 128+type;
+                       c = legacy_chars[ map[c*5/4]>>2*c%8 |
+                               map[c*5/4+1]<<8-2*c%8 & 1023 ];
+                       if (!c) c = *(unsigned char *)*in;
+                       if (c==1) goto ilseq;
                }
 
                switch (totype) {
@@ -480,73 +304,48 @@ size_t iconv(iconv_t cd0, char **in, size_t *inb, char **out, size_t *outb)
                        *out += k;
                        *outb -= k;
                        break;
-               case TIS_620:
-                       if (c-0xe01u <= 0xff-0xa1)
-                               c -= 0xe01-0xa1;
-                       else if (c >= 0xa1)
-                               goto ascii;
-                       goto revout;
-               case JIS_0201:
-                       if (c-0xff61u <= 0xdf-0xa1)
-                               c -= 0xff61-0xa1;
-                       else if (c >= 0xa1)
-                               goto ascii;
-                       goto revout;
-               case LATIN_9:
-                       if (c == 0x20ac) {
-                               c=0xa4;
-                       } else if (c-0x150u<=0x12 && (1<<c-0x150 & 0x3000c)) {
-                               static const unsigned char map[] =
-                                       { 0xa6,0xa8,0xbc,0xbd };
-                               c = map[c&3];
-                       } else if (c-0x178u<=0x7 && (1<<c-0x178 & 0x61)) {
-                               static const unsigned char map[] =
-                                       { 0xbe,0,0,0,0,0xb4,0xb8 };
-                               c = map[c&7];
-                       } else if (c>0x100 ||
-                               c-0xa5u<=0xbeu-0xa5
-                               && (1<<c-0xa5 & 0x388800a))
-               case US_ASCII: ascii:
-                       if (c > 0x7f) x++, c='*';
-               case 9: case 10: case 11: case 13: case 14:
+               case US_ASCII:
+                       if (c > 0x7f) subst: x++, c='*';
+               default:
                        if (*outb < 1) goto toobig;
-                       if (c < toelide) {
+                       if (c < 128+totype) {
                        revout:
                                *(*out)++ = c;
                                *outb -= 1;
                                break;
                        }
-                       for (d=0; d<256-toelide; d++) {
-                               if (c == get_mapping(tomap, d, totype)) {
-                                       c = d + toelide;
+                       d = c;
+                       for (c=0; c<128-totype; c++) {
+                               if (d == legacy_chars[ map[c*5/4]>>2*c%8 |
+                                       map[c*5/4+1]<<8-2*c%8 & 1023 ]) {
+                                       c += 128;
                                        goto revout;
                                }
                        }
-                       x++;
-                       c = '*';
-                       goto revout;
+                       goto subst;
                case UCS2BE:
                case UCS2LE:
                case UTF_16BE:
                case UTF_16LE:
-                       if (c < 0x10000) {
+                       if (c < 0x10000 || type-UCS2BE < 2U) {
+                               if (c >= 0x10000) c = 0xFFFD;
                                if (*outb < 2) goto toobig;
-                               put_16(*out, c, totype);
+                               put_16((void *)*out, c, totype);
                                *out += 2;
                                *outb -= 2;
                                break;
                        }
-                       if (type-UCS2BE < 2U) goto ilseq;
                        if (*outb < 4) goto toobig;
-                       put_16(*out, (c>>10)|0xd800, totype);
-                       put_16(*out + 2, (c&0x3ff)|0xdc00, totype);
+                       c -= 0x10000;
+                       put_16((void *)*out, (c>>10)|0xd800, totype);
+                       put_16((void *)(*out + 2), (c&0x3ff)|0xdc00, totype);
                        *out += 4;
                        *outb -= 4;
                        break;
                case UTF_32BE:
                case UTF_32LE:
                        if (*outb < 4) goto toobig;
-                       put_32(*out, c, totype);
+                       put_32((void *)*out, c, totype);
                        *out += 4;
                        *outb -= 4;
                        break;
@@ -559,9 +358,11 @@ ilseq:
        goto end;
 toobig:
        err = E2BIG;
+       x = -1;
        goto end;
 starved:
        err = EINVAL;
+       x = -1;
 end:
        errno = err;
        return x;