1 #ifndef PLAN9
2 #include	<sys/types.h>
3 #include	<stdio.h>
4 #include	<unistd.h>
5 #include	<stdlib.h>
6 #include	<fcntl.h>
7 #include	<string.h>
8 #include	<errno.h>
9 #include	"plan9.h"
10 #else /* PLAN9 */
11 #include	<u.h>
12 #include	<libc.h>
13 #include	<bio.h>
14 #endif /* PLAN9 */
15 #include	"cyrillic.h"
16 #include	"misc.h"
17 #include	"ms.h"
18 #include	"8859.h"
19 #include	"big5.h"
20 #include	"gb.h"
21 #include	"hdr.h"
22 #include	"conv.h"
23 
24 void usage(void);
25 void list(void);
26 int squawk = 1;
27 int clean = 0;
28 int verbose = 0;
29 long ninput, noutput, nrunes, nerrors;
30 char *file = "stdin";
31 char *argv0;
32 Rune runes[N];
33 char obuf[UTFmax*N];	/* maximum bloat from N runes */
34 long tab[NRUNE];
35 #ifndef	PLAN9
36 extern char version[];
37 #endif
38 
39 void intable(int, long *, struct convert *);
40 void unicode_in(int, long *, struct convert *);
41 void unicode_out(Rune *, int, long *);
42 
43 int
main(int argc,char ** argv)44 main(int argc, char **argv)
45 {
46 	char *from = "utf";
47 	char *to = "utf";
48 	int fd;
49 	int listem = 0;
50 	struct convert *t, *f;
51 
52 	ARGBEGIN {
53 	case 'c':
54 		clean = 1;
55 		break;
56 	case 'f':
57 		from = EARGF(usage());
58 		break;
59 	case 'l':
60 		listem = 1;
61 		break;
62 	case 's':
63 		squawk = 0;
64 		break;
65 	case 't':
66 		to = EARGF(usage());
67 		break;
68 	case 'v':
69 		verbose = 1;
70 		break;
71 	default:
72 		usage();
73 		break;
74 	} ARGEND
75 
76 	USED(argc);
77 	if(verbose)
78 		squawk = 1;
79 	if(listem){
80 		list();
81 		EXIT(0, 0);
82 	}
83 	if(!from || !to)
84 		usage();
85 	f = conv(from, 1);
86 	t = conv(to, 0);
87 #define	PROC	{if(f->flags&Table)\
88 			intable(fd, (long *)f->data, t);\
89 		else\
90 			((Infn)(f->fn))(fd, (long *)0, t);}
91 	if(*argv){
92 		while(*argv){
93 			file = *argv;
94 #ifndef PLAN9
95 			if((fd = open(*argv, 0)) < 0){
96 				EPR "%s: %s: %s\n", argv0, *argv, strerror(errno));
97 #else /* PLAN9 */
98 			if((fd = open(*argv, OREAD)) < 0){
99 				EPR "%s: %s: %r\n", argv0, *argv);
100 #endif /* PLAN9 */
101 				EXIT(1, "open failure");
102 			}
103 			PROC
104 			close(fd);
105 			argv++;
106 		}
107 	} else {
108 		fd = 0;
109 		PROC
110 	}
111 	if(verbose)
112 		EPR "%s: %ld input bytes, %ld runes, %ld output bytes (%ld errors)\n", argv0,
113 			ninput, nrunes, noutput, nerrors);
114 	EXIT(((nerrors && squawk)? 1:0), ((nerrors && squawk)? "conversion error":0));
115 	return(0);	/* shut up compiler */
116 }
117 
118 void
119 usage(void)
120 {
121 	EPR "Usage: %s [-slv] [-f cs] [-t cs] [file ...]\n", argv0);
122 	verbose = 1;
123 	list();
124 	EXIT(1, "usage");
125 }
126 
127 void
128 list(void)
129 {
130 	struct convert *c;
131 	char ch = verbose?'\t':' ';
132 
133 #ifndef	PLAN9
134 	EPR "%s version = '%s'\n", argv0, version);
135 #endif
136 	if(verbose)
137 		EPR "character sets:\n");
138 	else
139 		EPR "cs:");
140 	for(c = convert; c->name; c++){
141 		if((c->flags&From) && c[1].name && (strcmp(c[1].name, c->name) == 0)){
142 			EPR "%c%s", ch, c->name);
143 			c++;
144 		} else if(c->flags&Table)
145 			EPR "%c%s", ch, c->name);
146 		else if(c->flags&From)
147 			EPR "%c%s(from)", ch, c->name);
148 		else
149 			EPR "%c%s(to)", ch, c->name);
150 		if(verbose)
151 			EPR "\t%s\n", c->chatter);
152 	}
153 	if(!verbose)
154 		EPR "\n");
155 }
156 
157 struct convert *
158 conv(char *name, int from)
159 {
160 	struct convert *c;
161 
162 	for(c = convert; c->name; c++){
163 		if(cistrcmp(c->name, name) != 0)
164 			continue;
165 		if(c->flags&Table)
166 			return(c);
167 		if(((c->flags&From) == 0) == (from == 0))
168 			return(c);
169 	}
170 	EPR "%s: charset `%s' unknown\n", argv0, name);
171 	EXIT(1, "unknown character set");
172 	return(0);	/* just shut the compiler up */
173 }
174 
175 void
176 swab2(char *b, int n)
177 {
178 	char *e, p;
179 
180 	for(e = b+n; b < e; b++){
181 		p = *b;
182 		*b = b[1];
183 		*++b = p;
184 	}
185 }
186 
187 void
188 unicode_in(int fd, long *notused, struct convert *out)
189 {
190 	u16int ubuf[N];
191 	Rune buf[N];
192 	int i, n;
193 	int swabme;
194 
195 	USED(notused);
196 	if(read(fd, (char *)ubuf, 2) != 2)
197 		return;
198 	ninput += 2;
199 	switch(ubuf[0])
200 	{
201 	default:
202 		buf[0] = ubuf[0];
203 		OUT(out, buf, 1);
204 	case 0xFEFF:
205 		swabme = 0;
206 		break;
207 	case 0xFFFE:
208 		swabme = 1;
209 		break;
210 	}
211 	while((n = read(fd, (char *)ubuf, 2*N)) > 0){
212 		ninput += n;
213 		if(swabme)
214 			swab2((char *)ubuf, n);
215 		for(i=0; i<n/2; i++)
216 			buf[i] = ubuf[i];
217 		if(n&1){
218 			if(squawk)
219 				EPR "%s: odd byte count in %s\n", argv0, file);
220 			nerrors++;
221 			if(clean)
222 				n--;
223 			else
224 				buf[n++/2] = Runeerror;
225 		}
226 		OUT(out, buf, n/2);
227 	}
228 }
229 
230 void
231 unicode_in_be(int fd, long *notused, struct convert *out)
232 {
233 	int i, n;
234 	u16int ubuf[N];
235 	Rune buf[N], r;
236 	uchar *p;
237 
238 	USED(notused);
239 	while((n = read(fd, (char *)ubuf, 2*N)) > 0){
240 		ninput += n;
241 		p = (uchar*)ubuf;
242 		for(i=0; i<n/2; i++){
243 			r = *p++<<8;
244 			r |= *p++;
245 			buf[i] = r;
246 		}
247 		if(n&1){
248 			if(squawk)
249 				EPR "%s: odd byte count in %s\n", argv0, file);
250 			nerrors++;
251 			if(clean)
252 				n--;
253 			else
254 				buf[n++/2] = Runeerror;
255 		}
256 		OUT(out, buf, n/2);
257 	}
258 	OUT(out, buf, 0);
259 }
260 
261 void
262 unicode_in_le(int fd, long *notused, struct convert *out)
263 {
264 	int i, n;
265 	u16int ubuf[N];
266 	Rune buf[N], r;
267 	uchar *p;
268 
269 	USED(notused);
270 	while((n = read(fd, (char *)ubuf, 2*N)) > 0){
271 		ninput += n;
272 		p = (uchar*)ubuf;
273 		for(i=0; i<n/2; i++){
274 			r = *p++;
275 			r |= *p++<<8;
276 			buf[i] = r;
277 		}
278 		if(n&1){
279 			if(squawk)
280 				EPR "%s: odd byte count in %s\n", argv0, file);
281 			nerrors++;
282 			if(clean)
283 				n--;
284 			else
285 				buf[n++/2] = Runeerror;
286 		}
287 		OUT(out, buf, n/2);
288 	}
289 	OUT(out, buf, 0);
290 }
291 
292 void
293 unicode_out(Rune *base, int n, long *notused)
294 {
295 	static int first = 1;
296 	u16int buf[N];
297 	int i;
298 
299 	USED(notused);
300 	nrunes += n;
301 	if(first){
302 		u16int x = 0xFEFF;
303 		noutput += 2;
304 		write(1, (char *)&x, 2);
305 		first = 0;
306 	}
307 	noutput += 2*n;
308 	for(i=0; i<n; i++)
309 		buf[i] = base[i];
310 	write(1, (char *)buf, 2*n);
311 }
312 
313 void
314 unicode_out_be(Rune *base, int n, long *notused)
315 {
316 	int i;
317 	uchar *p;
318 	Rune r;
319 
320 	USED(notused);
321 	p = (uchar*)base;
322 	for(i=0; i<n; i++){
323 		r = base[i];
324 		*p++ = r>>8;
325 		*p++ = r;
326 	}
327 	nrunes += n;
328 	noutput += 2*n;
329 	write(1, (char *)base, 2*n);
330 }
331 
332 void
333 unicode_out_le(Rune *base, int n, long *notused)
334 {
335 	int i;
336 	uchar *p;
337 	Rune r;
338 
339 	USED(notused);
340 	p = (uchar*)base;
341 	for(i=0; i<n; i++){
342 		r = base[i];
343 		*p++ = r;
344 		*p++ = r>>8;
345 	}
346 	nrunes += n;
347 	noutput += 2*n;
348 	write(1, (char *)base, 2*n);
349 }
350 
351 void
352 intable(int fd, long *table, struct convert *out)
353 {
354 	uchar buf[N];
355 	uchar *p, *e;
356 	Rune *r;
357 	int n;
358 	long c;
359 
360 	while((n = read(fd, (char *)buf, N)) > 0){
361 		ninput += n;
362 		r = runes;
363 		for(p = buf, e = buf+n; p < e; p++){
364 			c = table[*p];
365 			if(c < 0){
366 				if(squawk)
367 					EPR "%s: bad char 0x%x near byte %ld in %s\n", argv0, *p, ninput+(p-e), file);
368 				nerrors++;
369 				if(clean)
370 					continue;
371 				c = BADMAP;
372 			}
373 			*r++ = c;
374 		}
375 		OUT(out, runes, r-runes);
376 	}
377 	OUT(out, runes, 0);
378 	if(n < 0){
379 #ifdef	PLAN9
380 		EPR "%s: input read: %r\n", argv0);
381 #else
382 		EPR "%s: input read: %s\n", argv0, strerror(errno));
383 #endif
384 		EXIT(1, "input read error");
385 	}
386 }
387 
388 void
389 outtable(Rune *base, int n, long *map)
390 {
391 	long c;
392 	char *p;
393 	int i;
394 
395 	nrunes += n;
396 	for(i = 0; i < NRUNE; i++)
397 		tab[i] = -1;
398 	for(i = 0; i < 256; i++)
399 		if(map[i] >= 0)
400 			tab[map[i]] = i;
401 	for(i = 0, p = obuf; i < n; i++){
402 		c = tab[base[i]];
403 		if(c < 0){
404 			if(squawk)
405 				EPR "%s: rune 0x%x not in output cs\n", argv0, base[i]);
406 			nerrors++;
407 			if(clean)
408 				continue;
409 			c = BADMAP;
410 		}
411 		*p++ = c;
412 	}
413 	noutput += p-obuf;
414 	write(1, obuf, p-obuf);
415 }
416 
417 long tabascii[256] =
418 {
419 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
420 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
421 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
422 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
423 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
424 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
425 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
426 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
427   -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
428   -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
429   -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
430   -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
431   -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
432   -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
433   -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
434   -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1
435 };
436 
437 long tabmsdos[256] =	/* from jhelling@cs.ruu.nl (Jeroen Hellingman) */
438 {
439 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
440 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
441 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
442 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
443 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
444 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
445 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
446 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
447 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, /* latin */
448 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
449 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
450 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
451 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
452 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
453 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, /* forms */
454 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
455 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
456 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
457 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
458 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
459 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, /* greek */
460 0x03a6, 0x0398, 0x2126, 0x03b4, 0x221e, 0x2205, 0x2208, 0x2229,
461 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, /* math */
462 0x00b0, 0x2022, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x220e, 0x00a0
463 };
464 long tabmsdos2[256] =	/* from jhelling@cs.ruu.nl (Jeroen Hellingman) */
465 {
466 0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
467 0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
468 0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x2043, 0x21a8,
469 0x2191, 0x2193, 0x2192, 0x2190, 0x2319, 0x2194, 0x25b2, 0x25bc,
470 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
471 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
472 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
473 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
474 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
475 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
476 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, /* latin */
477 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
478 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
479 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
480 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
481 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
482 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, /* forms */
483 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
484 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
485 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
486 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
487 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
488 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, /* greek */
489 0x03a6, 0x0398, 0x2126, 0x03b4, 0x221e, 0x2205, 0x2208, 0x2229,
490 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, /* math */
491 0x00b0, 0x2022, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x220e, 0x00a0
492 };
493 struct convert convert[] =
494 {	/* if two entries have the same name, put the from one first */
495 	{ "8859-1", "Latin-1 (Western and Northern Europe including Italian)", Table, (void *)tab8859_1 },
496 	{ "8859-2", "Latin-2 (Eastern Europe except Turkey and the Baltic countries)", Table, (void *)tab8859_2 },
497 	{ "8859-3", "Latin-3 (Mediterranean, South Africa, Esperanto)", Table, (void *)tab8859_3 },
498 	{ "8859-4", "Latin-4 (Scandinavia and the Baltic countries; obsolete)", Table, (void *)tab8859_4 },
499 	{ "8859-5", "Part 5 (Cyrillic)", Table, (void *)tab8859_5 },
500 	{ "8859-6", "Part 6 (Arabic)", Table, (void *)tab8859_6 },
501 	{ "8859-7", "Part 7 (Greek)", Table, (void *)tab8859_7 },
502 	{ "8859-8", "Part 8 (Hebrew)", Table, (void *)tab8859_8 },
503 	{ "8859-9", "Latin-5 (Turkey, Western Europe except Icelandic and Faroese)", Table, (void *)tab8859_9 },
504 	{ "8859-10", "Latin-6 (Northern Europe)", Table, (void *)tab8859_10 },
505 	{ "8859-15", "Latin-9 (Western Europe)", Table, (void *)tab8859_15 },
506 	{ "ascii", "7-bit ASCII", Table, (void *)tabascii },
507 	{ "atari", "ATARI-ST character set", Table, (void *)tabatari },
508 	{ "av", "Alternativnyj Variant", Table, (void *)tabav },
509 	{ "big5", "Big 5 (HKU)", From|Func, 0, (Fnptr)big5_in },
510 	{ "big5", "Big 5 (HKU)", Func, 0, (Fnptr)big5_out },
511 	{ "ebcdic", "EBCDIC", Table, (void *)tabebcdic },	/* 6f is recommended bad map */
512 	{ "euc-k", "Korean EUC: ASCII+KS C 5601 1987", From|Func, 0, (Fnptr)uksc_in },
513 	{ "euc-k", "Korean EUC: ASCII+KS C 5601 1987", Func, 0, (Fnptr)uksc_out },
514 	{ "gb2312", "GB2312-80 (Chinese)", From|Func, 0, (Fnptr)gb_in },
515 	{ "gb2312", "GB2312-80 (Chinese)", Func, 0, (Fnptr)gb_out },
516 	{ "html", "HTML", From|Func, 0, (Fnptr)html_in },
517 	{ "html", "HTML", Func, 0, (Fnptr)html_out },
518 	{ "ibm437", "IBM Code Page 437 (US)", Table, (void*)tabcp437 },
519 	{ "ibm720", "IBM Code Page 720 (Arabic)", Table, (void*)tabcp720 },
520 	{ "ibm737", "IBM Code Page 737 (Greek)", Table, (void*)tabcp737 },
521 	{ "ibm775", "IBM Code Page 775 (Baltic)", Table, (void*)tabcp775 },
522 	{ "ibm850", "IBM Code Page 850 (Multilingual Latin I)", Table, (void*)tabcp850 },
523 	{ "ibm852", "IBM Code Page 852 (Latin II)", Table, (void*)tabcp852 },
524 	{ "ibm855", "IBM Code Page 855 (Cyrillic)", Table, (void*)tabcp855 },
525 	{ "ibm857", "IBM Code Page 857 (Turkish)", Table, (void*)tabcp857 },
526 	{ "ibm858", "IBM Code Page 858 (Multilingual Latin I+Euro)", Table, (void*)tabcp858 },
527 	{ "ibm862", "IBM Code Page 862 (Hebrew)", Table, (void*)tabcp862 },
528 	{ "ibm866", "IBM Code Page 866 (Russian)", Table, (void*)tabcp866 },
529 	{ "ibm874", "IBM Code Page 874 (Thai)", Table, (void*)tabcp874 },
530 	{ "iso-2022-jp", "alias for jis-kanji (MIME)", From|Func, 0, (Fnptr)jisjis_in },
531 	{ "iso-2022-jp", "alias for jis-kanji (MIME)", Func, 0, (Fnptr)jisjis_out },
532 	{ "iso-8859-1", "alias for 8859-1 (MIME)", Table, (void *)tab8859_1 },
533 	{ "iso-8859-2", "alias for 8859-2 (MIME)", Table, (void *)tab8859_2 },
534 	{ "iso-8859-3", "alias for 8859-3 (MIME)", Table, (void *)tab8859_3 },
535 	{ "iso-8859-4", "alias for 8859-4 (MIME)", Table, (void *)tab8859_4 },
536 	{ "iso-8859-5", "alias for 8859-5 (MIME)", Table, (void *)tab8859_5 },
537 	{ "iso-8859-6", "alias for 8859-6 (MIME)", Table, (void *)tab8859_6 },
538 	{ "iso-8859-7", "alias for 8859-7 (MIME)", Table, (void *)tab8859_7 },
539 	{ "iso-8859-8", "alias for 8859-8 (MIME)", Table, (void *)tab8859_8 },
540 	{ "iso-8859-9", "alias for 8859-9 (MIME)", Table, (void *)tab8859_9 },
541 	{ "iso-8859-10", "alias for 8859-10 (MIME)", Table, (void *)tab8859_10 },
542 	{ "iso-8859-15", "alias for 8859-15 (MIME)", Table, (void *)tab8859_15 },
543 	{ "jis", "guesses at the JIS encoding", From|Func, 0, (Fnptr)jis_in },
544 	{ "jis-kanji", "ISO 2022-JP (Japanese)", From|Func, 0, (Fnptr)jisjis_in },
545 	{ "jis-kanji", "ISO 2022-JP (Japanese)", Func, 0, (Fnptr)jisjis_out },
546 	{ "koi8", "KOI-8 (GOST 19769-74)", Table, (void *)tabkoi8 },
547 	{ "koi8-r", "alias for koi8 (MIME)", Table, (void *)tabkoi8 },
548 	{ "latin1", "alias for 8859-1", Table, (void *)tab8859_1 },
549 	{ "macrom", "Macintosh Standard Roman character set", Table, (void *)tabmacroman },
550 	{ "microsoft", "alias for windows1252", Table, (void *)tabcp1252 },
551 	{ "ms-kanji", "Microsoft, or Shift-JIS", From|Func, 0, (Fnptr)msjis_in },
552 	{ "ms-kanji", "Microsoft, or Shift-JIS", Func, 0, (Fnptr)msjis_out },
553 	{ "msdos", "IBM PC (alias for ibm437)", Table, (void *)tabcp437 },
554 	{ "msdos2", "IBM PC (ibm437 with graphics in C0)", Table, (void *)tabmsdos2 },
555 	{ "next", "NEXTSTEP character set", Table, (void *)tabnextstep },
556 	{ "ov", "Osnovnoj Variant", Table, (void *)tabov },
557 	{ "ps2", "IBM PS/2: (alias for ibm850)", Table, (void *)tabcp850 },
558 	{ "sf1", "ISO-646: Finnish/Swedish SF-1 variant", Table, (void *)tabsf1 },
559 	{ "sf2", "ISO-646: Finnish/Swedish SF-2 variant (recommended)", Table, (void *)tabsf2 },
560 	{ "tis-620", "Thai+ASCII (TIS 620-1986)", Table, (void *)tabtis620 },
561 	{ "tune", "TUNE (Tamil)", From|Func, 0, (Fnptr)tune_in },
562 	{ "tune", "TUNE (Tamil)", Func, 0, (Fnptr)tune_out },
563 	{ "ucode", "Russian U-code", Table, (void *)tabucode },
564 	{ "ujis", "EUC-JX: JIS 0208", From|Func, 0, (Fnptr)ujis_in },
565 	{ "ujis", "EUC-JX: JIS 0208", Func, 0, (Fnptr)ujis_out },
566 	{ "unicode", "Unicode 1.1", From|Func, 0, (Fnptr)unicode_in },
567 	{ "unicode", "Unicode 1.1", Func, 0, (Fnptr)unicode_out },
568 	{ "unicode-be", "Unicode 1.1 big-endian", From|Func, 0, (Fnptr)unicode_in_be },
569 	{ "unicode-be", "Unicode 1.1 big-endian", Func, 0, (Fnptr)unicode_out_be },
570 	{ "unicode-le", "Unicode 1.1 little-endian", From|Func, 0, (Fnptr)unicode_in_le },
571 	{ "unicode-le", "Unicode 1.1 little-endian", Func, 0, (Fnptr)unicode_out_le },
572 	{ "us-ascii", "alias for ascii (MIME)", Table, (void *)tabascii },
573 	{ "utf", "FSS-UTF a.k.a. UTF-8", From|Func, 0, (Fnptr)utf_in },
574 	{ "utf", "FSS-UTF a.k.a. UTF-8", Func, 0, (Fnptr)utf_out },
575 	{ "utf1", "UTF-1 (ISO 10646 Annex A)", From|Func, 0, (Fnptr)isoutf_in },
576 	{ "utf1", "UTF-1 (ISO 10646 Annex A)", Func, 0, (Fnptr)isoutf_out },
577 	{ "utf-8", "alias for utf (MIME)", From|Func, 0, (Fnptr)utf_in },
578 	{ "utf-8", "alias for utf (MIME)", Func, 0, (Fnptr)utf_out },
579 	{ "utf-16", "alias for unicode (MIME)", From|Func, 0, (Fnptr)unicode_in },
580 	{ "utf-16", "alias for unicode (MIME)", Func, 0, (Fnptr)unicode_out },
581 	{ "utf-16be", "alias for unicode-be (MIME)", From|Func, 0, (Fnptr)unicode_in_be },
582 	{ "utf-16be", "alias for unicode-be (MIME)", Func, 0, (Fnptr)unicode_out_be },
583 	{ "utf-16le", "alias for unicode-le (MIME)", From|Func, 0, (Fnptr)unicode_in_le },
584 	{ "utf-16le", "alias for unicode-le (MIME)", Func, 0, (Fnptr)unicode_out_le },
585 	{ "viet1", "Vietnamese VSCII-1 (1993)", Table, (void *)tabviet1 },
586 	{ "viet2", "Vietnamese VSCII-2 (1993)", Table, (void *)tabviet2 },
587 	{ "vscii", "Vietnamese VISCII 1.1 (1992)", Table, (void *)tabviscii },
588 	{ "windows-1250", "Windows Code Page 1250 (Central Europe)", Table, (void *)tabcp1250 },
589 	{ "windows-1251", "Windows Code Page 1251 (Cyrillic)", Table, (void *)tabcp1251 },
590 	{ "windows-1252", "Windows Code Page 1252 (Latin I)", Table, (void *)tabcp1252 },
591 	{ "windows-1253", "Windows Code Page 1253 (Greek)", Table, (void *)tabcp1253 },
592 	{ "windows-1254", "Windows Code Page 1254 (Turkish)", Table, (void *)tabcp1254 },
593 	{ "windows-1255", "Windows Code Page 1255 (Hebrew)", Table, (void *)tabcp1255 },
594 	{ "windows-1256", "Windows Code Page 1256 (Arabic)", Table, (void *)tabcp1256 },
595 	{ "windows-1257", "Windows Code Page 1257 (Baltic)", Table, (void *)tabcp1257 },
596 	{ "windows-1258", "Windows Code Page 1258 (Vietnam)", Table, (void *)tabcp1258 },
597 	{ 0 }
598 };
599