home *** CD-ROM | disk | FTP | other *** search
/ Beijing Paradise BBS Backup / PARADISE.ISO / software / BBSDOORW / SNWS191S.ZIP / PCCHARST.C < prev    next >
Text File  |  1993-08-17  |  19KB  |  518 lines

  1. /*
  2.     SNEWS 1.91
  3.  
  4.     pccharst - routines to handle multiple character sets for IBM PCs
  5.  
  6.  
  7.     Copyright (C) 1993  Daniel Fandrich
  8.                         <dan@fch.wimsey.bc.ca> or CompuServe 72365,306
  9.  
  10.     This program is free software; you can redistribute it and/or modify
  11.     it under the terms of the GNU General Public License, version 1, as
  12.     published by the Free Software Foundation.
  13.  
  14.     This program is distributed in the hope that it will be useful,
  15.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.     GNU General Public License for more details.
  18.  
  19.     See the file COPYING, which contains a copy of the GNU General
  20.     Public License.
  21.  
  22.  
  23.     Source is formatted with a tab size of 4.
  24.  
  25.  */
  26.  
  27.  
  28. #include "defs.h"
  29. #include "pccharst.h"
  30. #include <dos.h>
  31. #include <ctype.h>
  32. #include <string.h>
  33.  
  34.  
  35. #define DEFAULT_CP 437    /* mapping to use if active CP isn't supported */
  36.  
  37. #define NOCH '?'        /* character to show for those invalid in current code page */
  38.  
  39.  
  40. enum code_pages code_page_table;
  41.  
  42. /* these names must match enum code_pages */
  43. struct {int code_page_num; enum code_pages cptable;} code_page_list[] = {
  44.     437, CP437,        /* US */
  45.     850, CP850,        /* Multilingual/Latin I */
  46.  
  47. #if 0    /* these aren't in the table yet */
  48.     852, CP852,        /* Slavic/Latin II */
  49.     857, CP857,        /* Turkish/Latin V */
  50.     860, CP860,        /* Portugal */
  51.     861, CP861,        /* Iceland */
  52.     862, CP862,        /* Hebrew */
  53.     863, CP863,        /* Canadian - French */
  54.     865, CP865,        /* Norway/Denmark */
  55.     866, CP866,        /* Cyrillic */
  56.     869, CP869,        /* Greek */
  57. #endif
  58.     0, CP_NOT_SUPP    /* end of list */
  59. };
  60.  
  61. /* these names must match enum char_sets */
  62. char *char_set_names[/*enum char_sets*/] = {
  63.     "X-IBM437",        /* IBM code page 437     code page 437 is best */
  64.     "ISO-8859-1",    /* Latin 1                code page 850 is best */
  65.     "ISO-8859-2",   /* Latin 2                code page 852 is best */
  66.     "ISO-8859-3",    /* Latin 3                code page 850 is best? */
  67.     "ISO-8859-4",    /* Latin 4                code page 850 is best? */
  68.     "ISO-8859-9",    /* Latin 5                code page 857 is best */
  69. #if 0    /* these aren't in the mapping table yet */
  70.     "ISO-8859-5",    /* Latin/Cyrillic        code page 866 is best */
  71.     "ISO-8859-6",    /* Latin/Arabic */
  72.     "ISO-8859-7",    /* Latin/Greek          code page 869 is best */
  73.     "ISO-8859-8",    /* Latin/Hebrew */
  74.     "ISO-8859-10",    /* Latin 6                code page 852 is best? */
  75. #endif
  76.     "US-ASCII",        /* (must be last in table) equivalent to ISO-8859-1 */
  77.     NULL
  78. };
  79.  
  80.  
  81. /* cptable[code_pages][char_sets][character code] */
  82. char cptable[2 /*8*/][6/*12*/][0x80] = {
  83.  
  84. { /* code page 437 mappings */
  85.  
  86. /* Map from code page 437 to code page 437 */
  87. {
  88. 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
  89. 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
  90. 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
  91. 0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
  92. 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
  93. 0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
  94. 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
  95. 0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
  96. 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
  97. 0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
  98. 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,
  99. 0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
  100. 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,
  101. 0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
  102. 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
  103. 0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
  104. },
  105.  
  106. /* Map from ISO 8859-1 to code page 437 */
  107. {
  108. /* 128 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  109. /* 136 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  110. /* 144 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  111. /* 152 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  112. /* 160 */    0xFF,0xAD,0x9B,0x9C,0x0F,0x9D,0x7C,0x15,
  113. /* 168 */    '"', '@', 0xA6,0xAE,0xAA,0xC4,NOCH,'-',
  114. /* 176 */    0xF8,0xF1,0xFD,'3', 0x27,0xE6,0x14,0xFA,
  115. /* 184 */    ',', '1', 0xA7,0xAF,0xAC,0xAB,NOCH,0xA8,
  116. /* 192 */    'A', 'A', 'A', 'A', 0x8E,0x8F,0x92,0x80,
  117. /* 200 */   'E', 0x90,'E', 'E', 'I', 'I', 'I', 'I',
  118. /* 208 */    'D', 0xA5,'O', 'O', 'O', 'O', 0x99,'X',
  119. /* 216 */    0xE9,'U', 'U', 'U', 0x9A,'Y', NOCH,0xE1,
  120. /* 224 */    0x85,0xA0,0x83,'a', 0x84,0x86,0x91,0x87,
  121. /* 232 */    0x8A,0x82,0x88,0x89,0x8D,0xA1,0x8C,0x8B,
  122. /* 240 */    NOCH,0xA4,0x95,0xA2,0x93,'o', 0x94,0xF6,
  123. /* 248 */    0xED,0x97,0xA3,0x96,0x81,'y', NOCH,0x98
  124. },
  125.  
  126. /* Map from ISO 8859-2 to code page 437 */
  127. {
  128. /* 128 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  129. /* 136 */   NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  130. /* 144 */   NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  131. /* 152 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  132. /* 160 */    0xFF,'A', NOCH,'L', 0x0F,'L', 'S', 0x15,
  133. /* 168 */    '"', 'S', 'S', 'T', 'Z', 0xC4,'Z', 'Z',
  134. /* 176 */    0xF8,'a', NOCH,'l', 0x27,'l', 's', NOCH,
  135. /* 184 */    ',', 's', 's', 't', 'z', '"', 'z', 'z',
  136. /* 192 */    'R', 'A', 'A', 'A', 0x8E,'L', 'C', 0x80,
  137. /* 200 */   'C', 0x90,'E', 'E', 'E', 'I', 'I', 'D',
  138. /* 208 */    'D', 'N', 'N', 'O', 'O', 'O', 0x99,'X',
  139. /* 216 */    'R', 'U', 'U', 'U', 0x9A,'Y', 'T', 0xE1,
  140. /* 224 */    'r', 0xA0,0x83,'a', 0x84,'l', 'c', 0x87,
  141. /* 232 */    'c', 0x82,'e', 0x89,'e', 0xA1,0x8C,'d',
  142. /* 240 */    0xEB,'n', 'n', 0xA2,0x93,'o', 0x94,0xF6,
  143. /* 248 */    'r', 'u', 0xA3,'u', 0x81,'y', 't', 0xF9
  144. },
  145.  
  146. /* Map from ISO 8859-3 to code page 437 */
  147. {
  148. /* 128 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  149. /* 136 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  150. /* 144 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  151. /* 152 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  152. /* 160 */    0xFF,'H', NOCH,0x9C,0x0F,NOCH,'H', 0x15,
  153. /* 168 */    '"', 'I', 'S', 'G', 'J', 0xC4,NOCH,'Z',
  154. /* 176 */    0xF8,'h', 0xFD,'3', 0x27,0xE6,'h', 0xFA,
  155. /* 184 */    ',', 'i', 'd', 'g', 'j', 0xAB,NOCH,'z',
  156. /* 192 */    'A', 'A', 'A', NOCH,0x8E,'C', 'C', 0x80,
  157. /* 200 */   'E', 0x90,'E', 'E', 'I', 'I', 'I', 'I',
  158. /* 208 */    NOCH,0xA5,'O', 'O', 'O', 'G', 0x99,'X',
  159. /* 216 */    'G', 'U', 'U', 'U', 0x9A,'U', 'S', 0xE1,
  160. /* 224 */    0x85,0xA0,0x83,NOCH,0x84,'c', 'c', 0x87,
  161. /* 232 */    0x8A,0x82,0x88,0x89,0x8D,0xA1,0x8C,0x8B,
  162. /* 240 */    NOCH,0xA4,0x95,0xA2,0x93,'g', 0x94,0xF6,
  163. /* 248 */    'g', 0x97,0xA3,0x96,0x81,'u', 's', 0xF9
  164. },
  165.  
  166. /* WHAT IS GREENLANDIC K (162) AND LAPPISH ENG (189,191)? */
  167. /* Map from ISO 8859-4 to code page 437 */
  168. {
  169. /* 128 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  170. /* 136 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  171. /* 144 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  172. /* 152 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  173. /* 160 */    0xFF,'A', 'k', 'R', 0x0F,'I', 'L', 0x15,
  174. /* 168 */    '"', 'S', 'E', 'G', 'T', 0xC4,'Z', '-',
  175. /* 176 */    0xF8,'a', NOCH,'r', 0x27,'i', 'l', NOCH,
  176. /* 184 */    ',', 's', 'e', 'g', 't', NOCH,'z', NOCH,
  177. /* 192 */    'A', 'A', 'A', 'A', 0x8E,0x8F,0x92,'I',
  178. /* 200 */   'C', 0x90,'E', 'E', 'E', 'I', 'I', 'I',
  179. /* 208 */    'D', 'N', 'O', 'K', 'O', 'O', 0x99,'X',
  180. /* 216 */    0xE9,'U', 'U', 'U', 0x9A,'U', 'U', 0xE1,
  181. /* 224 */    'a', 0xA0,0x83,'a', 0x84,0x86,0x91,'i',
  182. /* 232 */    'c', 0x82,'e', 0x89,'e', 0xA1,0x8C,'i',
  183. /* 240 */    0xEB,'n', 'o', 'k', 0x93,'o', 0x94,0xF6,
  184. /* 248 */    0xED,'u', 0xA3,0x96,0x81,'u', 'u', 0xF9
  185. },
  186.  
  187. /* Map from ISO 8859-9 to code page 437 */
  188. {
  189. /* 128 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  190. /* 136 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  191. /* 144 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  192. /* 152 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  193. /* 160 */    0xFF,0xAD,0x9B,0x9C,0x0F,0x9D,0x7C,0x15,
  194. /* 168 */    '"', '@', 0xA6,0xAE,0xAA,0xC4,NOCH,'-',
  195. /* 176 */    0xF8,0xF1,0xFD,'3', 0x27,0xE6,0x14,0xFA,
  196. /* 184 */    ',', '1', 0xA7,0xAF,0xAC,0xAB,NOCH,0xA8,
  197. /* 192 */    'A', 'A', 'A', 'A', 0x8E,0x8F,0x92,0x80,
  198. /* 200 */   'E', 0x90,'E', 'E', 'I', 'I', 'I', 'I',
  199. /* 208 */    'G', 0xA5,'O', 'O', 'O', 'O', 0x99,'X',
  200. /* 216 */    0xE9,'U', 'U', 'U', 0x9A,'I', 'S', 0xE1,
  201. /* 224 */    0x85,0xA0,0x83,'a', 0x84,0x86,0x91,0x87,
  202. /* 232 */    0x8A,0x82,0x88,0x89,0x8D,0xA1,0x8C,0x8B,
  203. /* 240 */    'g', 0xA4,0x95,0xA2,0x93,'o', 0x94,0xF6,
  204. /* 248 */    0xED,0x97,0xA3,0x96,0x81,'i', 's', 0x98
  205. }
  206. },
  207.  
  208.  
  209. { /* code page 850 mappings */
  210.  
  211. /* Map from code page 437 to code page 850 */
  212. {
  213. 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
  214. 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
  215. 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
  216. 0x98,0x99,0x9A,0xBD,0x9C,0xBE,NOCH,0x9F,
  217. 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
  218. 0xA8,0xDA,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
  219. 0xB0,0xB1,0xB2,0xB3,0xB4,0xB4,0xB9,0xBB,
  220. 0xBF,0xB9,0xBA,0xBB,0xBC,0xD9,0xBC,0xBF,
  221. 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC3,0xCC,
  222. 0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCA,
  223. 0xC1,0xCB,0xC2,0xC8,0xC0,0xDA,0xC9,0xC3,
  224. 0xC5,0xD9,0xDA,0xDB,0xDC,0xDB,0xDB,0xDF,
  225. NOCH,0xE1,NOCH,NOCH,NOCH,NOCH,0xE6,NOCH,
  226. NOCH,NOCH,NOCH,NOCH,0x1D,NOCH,NOCH,NOCH,
  227. NOCH,0xF1,0x10,0x11,'?', 0xA8,0xF6,0x7E,
  228. 0xF8,0xFA,0xFA,0x1F,'n' ,0xFD,0xFE,0xFF
  229. },
  230.  
  231. /* Map from ISO 8859-1 to code page 850 */
  232. {
  233. /* 128 */   NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  234. /* 136 */   NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  235. /* 144 */   NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  236. /* 152 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  237. /* 160 */    0xFF,0xAD,0xBD,0x9C,0xCF,0xBE,0xDD,0xF5,
  238. /* 168 */    0xF9,0xB8,0xA6,0xAE,0xAA,0xC4,0xA9,0xEE,
  239. /* 176 */    0xF8,0xF1,0xFD,0xFC,0xEF,0xE6,0xF4,0xFA,
  240. /* 184 */    0xF7,0xFB,0xA7,0xAF,0xAC,0xAB,0xF3,0xA8,
  241. /* 192 */    0xB7,0xB5,0xB6,0xC7,0x8E,0x8F,0x92,0x80,
  242. /* 200 */   0xD4,0x90,0xD2,0xD3,0xDE,0xD6,0xD7,0xD8,
  243. /* 208 */    0xD1,0xA5,0xE3,0xE0,0xE2,0xE5,0x99,0x9E,
  244. /* 216 */    0x9D,0xEB,0xE9,0xEA,0x9A,0xED,0xE8,0xE1,
  245. /* 224 */    0x85,0xA0,0x83,0xC6,0x84,0x86,0x91,0x87,
  246. /* 232 */    0x8A,0x82,0x88,0x89,0x8D,0xA1,0x8C,0x8B,
  247. /* 240 */    0xD0,0xA4,0x95,0xA2,0x93,0xE4,0x94,0xF6,
  248. /* 248 */    0x9B,0x97,0xA3,0x96,0x81,0xEC,0xE7,0x98
  249. },
  250.  
  251. /* IS CARON (183) 0xF7? */
  252. /* Map from ISO 8859-2 to code page 850 */
  253. {
  254. /* 128 */   NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  255. /* 136 */   NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  256. /* 144 */   NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  257. /* 152 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  258. /* 160 */    0xFF,'A', NOCH,'L', 0xCF,'L', 'S', 0xF5,
  259. /* 168 */    0xF9,'S', 'S', 'T', 'Z', 0xC4,'Z', 'Z',
  260. /* 176 */    0xF8,'a', NOCH,'l', 0xEF,'l', 's', NOCH,
  261. /* 184 */    0xF7,'s', 's', 't', 'z', '"', 'z', 'z',
  262. /* 192 */    'R', 0xB5,0xB6,'A', 0x8E,'L', 'C', 0x80,
  263. /* 200 */   'C', 0x90,'E', 0xD3,'E', 0xD6,0xD7,'D',
  264. /* 208 */    0xD1,'N', 'N', 0xE0,0xE2,'O', 0x99,0x9E,
  265. /* 216 */    'R', 'U', 0xE9,'U', 0x9A,0xED,'T', 0xE1,
  266. /* 224 */    'r', 0xA0,0x83,'a', 0x84,'l', 'c', 0x87,
  267. /* 232 */    'c', 0x82,'e', 0x89,'e', 0xA1,0x8C,'d',
  268. /* 240 */    0xD0,'n', 'n', 0xA2,0x93,'o', 0x94,0xF6,
  269. /* 248 */    'r', 'u', 0xA3,'u', 0x81,0xEC,'t', 0xFA
  270. },
  271.  
  272. /* Map from ISO 8859-3 to code page 850 */
  273. {
  274. /* 128 */   NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  275. /* 136 */   NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  276. /* 144 */   NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  277. /* 152 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  278. /* 160 */    0xFF,'H', NOCH,0x9C,0xCF,NOCH,'H', 0xF5,
  279. /* 168 */    0xF9,'I', 'S', 'G', 'J', 0xC4,NOCH,'Z',
  280. /* 176 */    0xF8,'h', 0xFD,0xFC,0xEF,0xE6,'h', 0xFA,
  281. /* 184 */    0xF7,'i', 's', 'g', 'j', 0xAB,NOCH,'z',
  282. /* 192 */    0xB7,0xB5,0xB6,NOCH,0x8E,'C', 'C', 0x80,
  283. /* 200 */   0xD4,0x90,0xD2,0xD3,0xDE,0xD6,0xD7,0xD8,
  284. /* 208 */    NOCH,0xA5,0xE3,0xE0,0xE2,'G', 0x99,0x9E,
  285. /* 216 */    'G', 0xEB,0xE9,0xEA,0x9A,'U', 'S', 0xE1,
  286. /* 224 */    0x85,0xA0,0x83,NOCH,0x84,'c', 'c', 0x87,
  287. /* 232 */    0x8A,0x82,0x88,0x89,0x8D,0xA1,0x8C,0x8B,
  288. /* 240 */    NOCH,0xA4,0x95,0xA2,0x93,'g', 0x94,0xF6,
  289. /* 248 */    'g', 0x97,0xA3,0x96,0x81,'u', 's', 0xFA
  290. },
  291.  
  292. /* Map from ISO 8859-4 to code page 850 */
  293. {
  294. /* 128 */   NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  295. /* 136 */   NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  296. /* 144 */   NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  297. /* 152 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  298. /* 160 */    0xFF,'A', 'k', 'R', 0xCF,'I', 'L', 0xF5,
  299. /* 168 */    0xF9,'S', 'E', 'G', 'T', 0xC4,'Z', 0xEE,
  300. /* 176 */    0xF8,'a', NOCH,'r', 0xEF,'i', 'l', NOCH,
  301. /* 184 */    0xF7,'s', 'e', 'g', 't', NOCH,'z', NOCH,
  302. /* 192 */    'A', 0xB5,0xB6,0xC7,0x8E,0x8F,0x92,'I',
  303. /* 200 */   'C', 0x90,'E', 0xD3,'E', 0xD6,0xD7,'I',
  304. /* 208 */    0xD1,'N', 'O', 'K', 0xE2,0xE5,0x99,0x9E,
  305. /* 216 */    0x9D,'U', 0xE9,0xEA,0x9A,'U', 'U', 0xE1,
  306. /* 224 */    'a', 0xA0,0x83,0xC6,0x84,0x86,0x91,'i',
  307. /* 232 */    'c', 0x82,'e', 0x89,'e', 0xA1,0x8C,'i',
  308. /* 240 */    0xD0,'n', 'o', 'k', 0x93,0xE4,0x94,0xF6,
  309. /* 248 */    0x9B,'u', 0xA3,0x96,0x81,'u', 'u', 0xFA
  310. },
  311.  
  312. /* Map from ISO 8859-9 to code page 850 */
  313. {
  314. /* 128 */   NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  315. /* 136 */   NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  316. /* 144 */   NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  317. /* 152 */    NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,NOCH,
  318. /* 160 */    0xFF,0xAD,0xBD,0x9C,0xCF,0xBE,0xDD,0xF5,
  319. /* 168 */    0xF9,0xB8,0xA6,0xAE,0xAA,0xC4,0xA9,0xEE,
  320. /* 176 */    0xF8,0xF1,0xFD,0xFC,0xEF,0xE6,0xF4,0xFA,
  321. /* 184 */    0xF7,0xFB,0xA7,0xAF,0xAC,0xAB,0xF3,0xA8,
  322. /* 192 */    0xB7,0xB5,0xB6,0xC7,0x8E,0x8F,0x92,0x80,
  323. /* 200 */   0xD4,0x90,0xD2,0xD3,0xDE,0xD6,0xD7,0xD8,
  324. /* 208 */    'G', 0xA5,0xE3,0xE0,0xE2,0xE5,0x99,0x9E,
  325. /* 216 */    0x9D,0xEB,0xE9,0xEA,0x9A,'I', 'S', 0xE1,
  326. /* 224 */    0x85,0xA0,0x83,0xC6,0x84,0x86,0x91,0x87,
  327. /* 232 */    0x8A,0x82,0x88,0x89,0x8D,0xA1,0x8C,0x8B,
  328. /* 240 */    'g', 0xA4,0x95,0xA2,0x93,0xE4,0x94,0xF6,
  329. /* 248 */    0x9B,0x97,0xA3,0x96,0x81,'i', 's', 0x98
  330. }
  331. }
  332. };
  333.  
  334. char base64[0x80] = {
  335. /* 0x00 */    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
  336. /* 0x08 */    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
  337. /* 0x10 */    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
  338. /* 0x18 */    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
  339. /* 0x20 */    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
  340. /* 0x28 */    -1,   -1,   -1,   0x3E, -1,   -1,   -1,   0x3F,
  341. /* 0x30 */    0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
  342. /* 0x38 */    0x3C, 0x3D, -1,   -1,   -1,   -1,   -1,   -1,
  343. /* 0x40 */    -1,   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
  344. /* 0x48 */    0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
  345. /* 0x50 */    0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
  346. /* 0x58 */    0x17, 0x18, 0x19, -1,   -1,   -1,   -1,   -1,
  347. /* 0x60 */    -1,   0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
  348. /* 0x68 */    0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
  349. /* 0x70 */    0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
  350. /* 0x78 */    0x31, 0x32, 0x33, -1,   -1,   -1,   -1,   -1
  351. };
  352.  
  353. /*------------------------- get current code page --------------------------*/
  354. int get_code_page(void)
  355. {
  356. #ifdef __OS2__
  357.     ULONG CpList[1];
  358.     ULONG CpSize;
  359.  
  360.     if (DosQueryCp(sizeof(CpList), CpList, &CpSize))
  361.         return DEFAULT_CP;
  362.  
  363.     return (int) CpList[0];
  364.  
  365. #else /* __MSDOS__ */
  366.  
  367.     union REGS inregs, outregs;
  368.  
  369.     inregs.x.ax = 0x6601;
  370.     intdos(&inregs, &outregs);
  371.     if (outregs.x.cflag)
  372.         return DEFAULT_CP;    /* no code page support -- use default */
  373.  
  374.     return outregs.x.bx;
  375.  
  376. #endif
  377. }
  378.  
  379. /*----------------- return code page enum based on page --------------------*/
  380. enum code_pages select_cp_table(int code_page_num)
  381. {
  382.     int index;
  383.  
  384.     for (index = 0; code_page_list[index].code_page_num; ++index)
  385.         if (code_page_list[index].code_page_num == code_page_num)
  386.             break;
  387.     return index;
  388. }
  389.  
  390. /*---------------- return character set enum based on name -----------------*/
  391. enum char_sets select_char_set(char *name)
  392. {
  393.     int index;
  394.  
  395.     for (index = 0; char_set_names[index]; ++index)
  396.         if (stricmp(char_set_names[index], name) == 0)
  397.             return index;
  398.     return DEFAULT_CHAR_SET;        /* default character set */
  399. }
  400.  
  401. /*---------- translate MIME character to the code page character -----------*/
  402. unsigned char translate_char(unsigned char inchar, enum char_sets cset)
  403. {
  404. /* US_ASCII isn't in the tables, so choose ISO-8859-1 which will do the job */
  405.     if (cset == US_ASCII)
  406.         cset = ISO_8859_1;
  407.     return (inchar < 0x80) ? inchar :
  408.         ((code_page_table == CP_NOT_SUPP) ? inchar : cptable[code_page_table][cset][inchar & 0x7F]);
  409. }
  410.  
  411. /*------- translate line of MIME characters to code page characters --------*/
  412. char *translate_line(char *origline, enum char_sets cset)
  413. {
  414.     static char out_line[81];
  415.     int out_index;
  416.  
  417.     for (out_index = 0; (out_index < sizeof(out_line) - 1) &&
  418.          ((out_line[out_index++] = translate_char(*origline++, cset)) != 0) ;)
  419.         ;
  420.     out_line[out_index] = 0;
  421.     return out_line;
  422. }
  423.  
  424. /*------------ Translate 4 bytes of base64 to 3 bytes of binary ------------*/
  425. static int decode_base64(char *base, char *bin)
  426. {
  427.     bin[0] = (base64[base[0]] << 2) | (base64[base[1]] >> 4);
  428.     bin[1] = (base64[base[1]] << 4) | (base64[base[2]] >> 2);
  429.     bin[2] = (base64[base[2]] << 6) | (base64[base[3]]);
  430.     return    (base64[base[0]] < 0) ? 0            /* only with a bad line */
  431.             : (base64[base[1]] < 0) ? 0            /* only with a bad line */
  432.             : (base64[base[2]] < 0) ? 1
  433.             : (base64[base[3]] < 0) ? 2
  434.             : 3;
  435. }
  436.  
  437. /*--------- translate RFC 1342 header line to code page characters ----------*/
  438. /* e.g.  From: =?ISO-8859-1?Q?Patrik_F=E4ltstr=F6m?= <paf@nada.kth.se> */
  439. /* e.g.  Subject: =?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?= */
  440. char *translate_header(char *origline, enum char_sets cset)
  441. {
  442.     static char out_line[81];
  443.     char *outp = out_line;
  444.     char char_set_name[80];
  445.     enum char_sets line_char_set;
  446.     char *hex_code = "12";
  447.     char hex_value;
  448.     char encoding;
  449.     int num_conv, i;
  450.  
  451.     while (*origline) {
  452.         if ((*origline == '=') && (*(origline+1) == '?') && strstr(origline+2, "?=")) {
  453.  
  454.             /* detected RFC 1342 header line -- parse it */
  455.             strtok(strcpy(char_set_name, origline += 2), "?\n\r");
  456.             line_char_set = select_char_set(char_set_name);
  457.  
  458.             /* point to encoding method character */
  459.             origline = 1 + strchr(origline, '?');
  460.             encoding = tolower(*origline);
  461.  
  462.             /* point to first character of encoded text */
  463.             origline = 1 + strchr(origline, '?');
  464.  
  465.             if (encoding == 'q')                /* quoted-printable encoding */
  466.                 while (*origline) {        /* scan quoted-printable characters */
  467.  
  468.                     /* end of special portion of header? */
  469.                     if ((*origline == '?') && (*(origline+1) == '=')) {
  470.                         if (*(origline += 2) == ' ')
  471.                             ++origline;
  472.                         break;
  473.                     }
  474.  
  475.                     /* special character */
  476.                     if (*origline == '=') {
  477.                         hex_code[0] = *++origline;
  478.                         hex_code[1] = *++origline;
  479.                         ++origline;
  480.                         sscanf(hex_code, "%x", &hex_value);
  481.                         *outp++ = translate_char(hex_value, line_char_set);
  482.  
  483.                     /* encoded space */
  484.                     } else if (*origline == '_') {
  485.                         *outp++ = ' ';
  486.                         ++origline;
  487.  
  488.                     /* normal text */
  489.                     } else
  490.                         *outp++ = translate_char(*origline++, cset);
  491.  
  492.                 } /* while */
  493.  
  494.  
  495.             else if (encoding == 'b')            /* base64 encoding */
  496.                 while (*origline) {
  497.                     /* end of special portion of header? */
  498.                     if ((*origline == '?') && (*(origline+1) == '=')) {
  499.                         if (*(origline += 2) == ' ')
  500.                             ++origline;
  501.                         break;
  502.                     }
  503.                     num_conv = decode_base64(origline, outp);
  504.                     for (i = 0; i < num_conv; ++i)
  505.                         outp[i] = translate_char(outp[i], line_char_set);
  506.                     outp += num_conv;
  507.                     origline += 4;
  508.                 } /* while */
  509.  
  510.         } else
  511.             *outp++ = translate_char(*origline++, cset);
  512.  
  513.     } /* while */
  514.     *outp = '\0';
  515.  
  516.     return out_line;
  517. }
  518.