OSDN Git Service

* some improvements arround -M
[nkf/nkf.git] / nkf.c
1 /** Network Kanji Filter. (PDS Version)
2 ************************************************************************
3 ** Copyright (C) 1987, Fujitsu LTD. (Itaru ICHIKAWA)
4 ** \e$BO"Mm@h!'\e(B \e$B!J3t!KIY;NDL8&5f=j!!%=%U%H#38&!!;T@n!!;j\e(B 
5 ** \e$B!J\e(BE-Mail Address: ichikawa@flab.fujitsu.co.jp\e$B!K\e(B
6 ** Copyright (C) 1996,1998
7 ** Copyright (C) 2002
8 ** \e$BO"Mm@h!'\e(B \e$BN05eBg3X>pJs9)3X2J\e(B \e$B2OLn\e(B \e$B??<#\e(B  mime/X0208 support
9 ** \e$B!J\e(BE-Mail Address: kono@ie.u-ryukyu.ac.jp\e$B!K\e(B
10 ** \e$BO"Mm@h!'\e(B COW for DOS & Win16 & Win32 & OS/2
11 ** \e$B!J\e(BE-Mail Address: GHG00637@niftyserve.or.p\e$B!K\e(B
12 **
13 **    \e$B$3$N%=!<%9$N$$$+$J$kJ#<L!$2~JQ!$=$@5$b5vBz$7$^$9!#$?$@$7!"\e(B
14 **    \e$B$=$N:]$K$O!"C/$,9W8%$7$?$r<($9$3$NItJ,$r;D$9$3$H!#\e(B
15 **    \e$B:FG[I[$d;(;o$NIUO?$J$I$NLd$$9g$o$;$bI,MW$"$j$^$;$s!#\e(B
16 **    \e$B1DMxMxMQ$b>e5-$KH?$7$J$$HO0O$G5v2D$7$^$9!#\e(B
17 **    \e$B%P%$%J%j$NG[I[$N:]$K$O\e(Bversion message\e$B$rJ]B8$9$k$3$H$r>r7o$H$7$^$9!#\e(B
18 **    \e$B$3$N%W%m%0%i%`$K$D$$$F$OFC$K2?$NJ]>Z$b$7$J$$!"0-$7$+$i$:!#\e(B
19 **
20 **    Everyone is permitted to do anything on this program 
21 **    including copying, modifying, improving,
22 **    as long as you don't try to pretend that you wrote it.
23 **    i.e., the above copyright notice has to appear in all copies.  
24 **    Binary distribution requires original version messages.
25 **    You don't have to ask before copying, redistribution or publishing.
26 **    THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE.
27 ***********************************************************************/
28
29 /***********************************************************************
30 ** UTF-8 \e$B%5%]!<%H$K$D$$$F\e(B
31 **    \e$B=>Mh$N\e(B nkf \e$B$HF~$l$+$($F$=$N$^$^;H$($k$h$&$K$J$C$F$$$^$9\e(B
32 **    nkf -e \e$B$J$I$H$7$F5/F0$9$k$H!"<+F0H=JL$G\e(B UTF-8 \e$B$HH=Dj$5$l$l$P!"\e(B
33 **    \e$B$=$N$^$^\e(B euc-jp \e$B$KJQ49$5$l$^$9\e(B
34 **
35 **    \e$B$^$@%P%0$,$"$k2DG=@-$,9b$$$G$9!#\e(B
36 **    (\e$BFC$K<+F0H=JL!"%3!<%I:.:_!"%(%i!<=hM}7O\e(B)
37 **
38 **    \e$B2?$+LdBj$r8+$D$1$?$i!"\e(B
39 **        E-Mail: furukawa@tcp-ip.or.jp
40 **    \e$B$^$G8fO"Mm$r$*4j$$$7$^$9!#\e(B
41 ***********************************************************************/
42 /* $Id: nkf.c,v 1.54 2005/01/02 05:46:01 naruse Exp $ */
43 #define NKF_VERSION "2.0.4"
44 #define NKF_RELEASE_DATE "2005-01-01"
45 #include "config.h"
46
47 static char *CopyRight =
48       "Copyright (C) 1987, FUJITSU LTD. (I.Ichikawa),2000 S. Kono, COW, 2002-2004 Kono, Furukawa";
49
50
51 /*
52 **
53 **
54 **
55 ** USAGE:       nkf [flags] [file] 
56 **
57 ** Flags:
58 ** b    Output is buffered             (DEFAULT)
59 ** u    Output is unbuffered
60 **
61 ** t    no operation
62 **
63 ** j    Outout code is JIS 7 bit        (DEFAULT SELECT) 
64 ** s    Output code is MS Kanji         (DEFAULT SELECT) 
65 ** e    Output code is AT&T JIS         (DEFAULT SELECT) 
66 ** w    Output code is AT&T JIS         (DEFAULT SELECT) 
67 ** l    Output code is JIS 7bit and ISO8859-1 Latin-1
68 **
69 ** m    MIME conversion for ISO-2022-JP
70 ** I    Convert non ISO-2022-JP charactor to GETA by Pekoe <pekoe@lair.net>
71 ** i_ Output sequence to designate JIS-kanji (DEFAULT_J)
72 ** o_ Output sequence to designate single-byte roman characters (DEFAULT_R)
73 ** M    MIME output conversion 
74 **
75 ** r  {de/en}crypt ROT13/47
76 **
77 ** v  display Version
78 **
79 ** T  Text mode output        (for MS-DOS)
80 **
81 ** x    Do not convert X0201 kana into X0208
82 ** Z    Convert X0208 alphabet to ASCII
83 **
84 ** f60  fold option
85 **
86 ** m    MIME decode
87 ** B    try to fix broken JIS, missing Escape
88 ** B[1-9]  broken level
89 **
90 ** O   Output to 'nkf.out' file or last file name
91 ** d   Delete \r in line feed 
92 ** c   Add \r in line feed 
93 ** -- other long option
94 ** -- ignore following option (don't use with -O )
95 **
96 **/
97
98 #if (defined(__TURBOC__) || defined(_MSC_VER) || defined(LSI_C) || defined(__MINGW32__)) && !defined(MSDOS)
99 #define MSDOS
100 #if (defined(__Win32__) || defined(_WIN32)) && !defined(__WIN32__)
101 #define __WIN32__
102 #endif
103 #endif
104
105 #ifdef PERL_XS
106 #undef OVERWRITE
107 #endif
108
109 #ifndef PERL_XS
110 #include <stdio.h>
111 #endif
112
113 #include <stdlib.h>
114
115 #if defined(MSDOS) || defined(__OS2__) 
116 #include <fcntl.h>
117 #include <io.h>
118 #endif
119
120 #ifdef MSDOS
121 #ifdef LSI_C
122 #define setbinmode(fp) fsetbin(fp)
123 #else /* Microsoft C, Turbo C */
124 #define setbinmode(fp) setmode(fileno(fp), O_BINARY)
125 #endif
126 #else /* UNIX,OS/2 */
127 #define setbinmode(fp)
128 #endif
129
130 #ifdef _IOFBF /* SysV and MSDOS, Windows */
131 #define       setvbuffer(fp, buf, size)       setvbuf(fp, buf, _IOFBF, size)
132 #else /* BSD */
133 #define       setvbuffer(fp, buf, size)       setbuffer(fp, buf, size)
134 #endif
135
136 /*Borland C++ 4.5 EasyWin*/
137 #if defined(__TURBOC__) && defined(_Windows) && !defined(__WIN32__) /*Easy Win */
138 #define         EASYWIN
139 #ifndef __WIN16__
140 #define __WIN16__
141 #endif
142 #include <windows.h>
143 #endif
144
145 #ifdef OVERWRITE
146 /* added by satoru@isoternet.org */
147 #include <string.h>
148 #include <sys/stat.h>
149 #ifndef MSDOS /* UNIX, OS/2 */
150 #include <unistd.h>
151 #include <utime.h>
152 #else
153 #if defined(_MSC_VER) || defined(__MINGW32__) /* VC++, MinGW */
154 #include <sys/utime.h>
155 #elif defined(__TURBOC__) /* BCC */
156 #include <utime.h>
157 #elif defined(LSI_C) /* LSI C */
158 #endif
159 #endif
160 #endif 
161
162 #ifdef INT_IS_SHORT
163 #define int long
164 #endif
165
166 #define         FALSE   0
167 #define         TRUE    1
168
169 /* state of output_mode and input_mode  
170
171    c2           0 means ASCII
172                 X0201
173                 ISO8859_1
174                 X0208
175                 EOF      all termination
176    c1           32bit data
177
178  */
179
180 #define         ASCII           0
181 #define         X0208           1
182 #define         X0201           2
183 #define         ISO8859_1       8
184 #define         NO_X0201        3
185 #define         X0212           16
186
187 /* Input Assumption */
188
189 #define         JIS_INPUT       4
190 #define         SJIS_INPUT      5
191 #define         LATIN1_INPUT    6
192 #define         FIXED_MIME      7
193 #define         STRICT_MIME     8
194
195 /* MIME ENCODE */
196
197 #define         ISO2022JP       9
198 #define         JAPANESE_EUC   10
199 #define         SHIFT_JIS      11
200
201 #define         UTF8           12
202 #define         UTF8_INPUT     13
203 #define         UTF16LE_INPUT  14
204 #define         UTF16BE_INPUT  15
205
206 #define         WISH_TRUE      15
207
208 /* ASCII CODE */
209
210 #define         BS      0x08
211 #define         TAB     0x09
212 #define         NL      0x0a
213 #define         CR      0x0d
214 #define         ESC     0x1b
215 #define         SPACE   0x20
216 #define         AT      0x40
217 #define         SSP     0xa0
218 #define         DEL     0x7f
219 #define         SI      0x0f
220 #define         SO      0x0e
221 #define         SSO     0x8e
222 #define         SS3     0x8f
223
224 #define         is_alnum(c)  \
225             (('a'<=c && c<='z')||('A'<= c && c<='Z')||('0'<=c && c<='9'))
226
227 #define         HOLD_SIZE       1024
228 #define         IOBUF_SIZE      16384
229
230 #define         DEFAULT_J       'B'
231 #define         DEFAULT_R       'B'
232
233 #define         SJ0162  0x00e1          /* 01 - 62 ku offset */
234 #define         SJ6394  0x0161          /* 63 - 94 ku offset */
235
236 #define         RANGE_NUM_MAX   18
237 #define         GETA1   0x22
238 #define         GETA2   0x2e
239
240
241 #if defined( UTF8_OUTPUT_ENABLE ) || defined( UTF8_INPUT_ENABLE )
242 #define sizeof_euc_utf8 94
243 #define sizeof_euc_to_utf8_1byte 94
244 #define sizeof_euc_to_utf8_2bytes 94
245 #define sizeof_utf8_to_euc_C2 64
246 #define sizeof_utf8_to_euc_E5B8 64
247 #define sizeof_utf8_to_euc_2bytes 112
248 #define sizeof_utf8_to_euc_3bytes 112
249 #endif
250
251 /* MIME preprocessor */
252
253
254 #ifdef EASYWIN /*Easy Win */
255 extern POINT _BufferSize;
256 #endif
257
258 /*      function prototype  */
259
260 #ifdef ANSI_C_PROTOTYPE
261 #define PROTO(x)  x 
262 #define STATIC static
263 #else
264 #define PROTO(x)  ()
265 #define STATIC
266 #endif
267
268 struct input_code{
269     char *name;
270     int stat;
271     int score;
272     int index;
273     int buf[3];
274     void (*status_func)PROTO((struct input_code *, int));
275     int (*iconv_func)PROTO((int c2, int c1, int c0));
276     int _file_stat;
277 };
278
279 STATIC char *input_codename = "";
280
281 STATIC  int     noconvert PROTO((FILE *f));
282 STATIC  int     kanji_convert PROTO((FILE *f));
283 STATIC  int     h_conv PROTO((FILE *f,int c2,int c1));
284 STATIC  int     push_hold_buf PROTO((int c2));
285 STATIC  void    set_iconv PROTO((int f, int (*iconv_func)()));
286 STATIC  int     s_iconv PROTO((int c2,int c1,int c0));
287 STATIC  int     s2e_conv PROTO((int c2, int c1, int *p2, int *p1));
288 STATIC  int     e_iconv PROTO((int c2,int c1,int c0));
289 #ifdef UTF8_INPUT_ENABLE
290 STATIC  int     w2e_conv PROTO((int c2,int c1,int c0,int *p2,int *p1));
291 STATIC  int     w_iconv PROTO((int c2,int c1,int c0));
292 STATIC  int     w_iconv16 PROTO((int c2,int c1,int c0));
293 STATIC  int     w_iconv_common PROTO((int c1,int c0,unsigned short **pp,int psize,int *p2,int *p1));
294 STATIC  int     ww16_conv PROTO((int c2, int c1, int c0));
295 #endif
296 #ifdef UTF8_OUTPUT_ENABLE
297 STATIC  int     e2w_conv PROTO((int c2,int c1));
298 STATIC  void    w_oconv PROTO((int c2,int c1));
299 STATIC  void    w_oconv16 PROTO((int c2,int c1));
300 #endif
301 STATIC  void    e_oconv PROTO((int c2,int c1));
302 STATIC  int     e2s_conv PROTO((int c2, int c1, int *p2, int *p1));
303 STATIC  void    s_oconv PROTO((int c2,int c1));
304 STATIC  void    j_oconv PROTO((int c2,int c1));
305 STATIC  void    fold_conv PROTO((int c2,int c1));
306 STATIC  void    cr_conv PROTO((int c2,int c1));
307 STATIC  void    z_conv PROTO((int c2,int c1));
308 STATIC  void    rot_conv PROTO((int c2,int c1));
309 STATIC  void    hira_conv PROTO((int c2,int c1));
310 STATIC  void    base64_conv PROTO((int c2,int c1));
311 STATIC  void    iso2022jp_check_conv PROTO((int c2,int c1));
312 STATIC  void    no_connection PROTO((int c2,int c1));
313 STATIC  int     no_connection2 PROTO((int c2,int c1,int c0));
314
315 STATIC  void    code_score PROTO((struct input_code *ptr));
316 STATIC  void    code_status PROTO((int c));
317
318 STATIC  void    std_putc PROTO((int c));
319 STATIC  int     std_getc PROTO((FILE *f));
320 STATIC  int     std_ungetc PROTO((int c,FILE *f));
321
322 STATIC  int     broken_getc PROTO((FILE *f));
323 STATIC  int     broken_ungetc PROTO((int c,FILE *f));
324
325 STATIC  int     mime_begin PROTO((FILE *f));
326 STATIC  int     mime_getc PROTO((FILE *f));
327 STATIC  int     mime_ungetc PROTO((int c,FILE *f));
328
329 STATIC  int     mime_begin_strict PROTO((FILE *f));
330 STATIC  int     mime_getc_buf PROTO((FILE *f));
331 STATIC  int     mime_ungetc_buf  PROTO((int c,FILE *f));
332 STATIC  int     mime_integrity PROTO((FILE *f,unsigned char *p));
333
334 STATIC  int     base64decode PROTO((int c));
335 STATIC  void    mime_putc PROTO((int c));
336 STATIC  void    open_mime PROTO((int c));
337 STATIC  void    close_mime PROTO(());
338 STATIC  void    usage PROTO(());
339 STATIC  void    version PROTO(());
340 STATIC  void    options PROTO((unsigned char *c));
341 #ifdef PERL_XS
342 STATIC  void    reinit PROTO(());
343 #endif
344
345 /* buffers */
346
347 static unsigned char   stdibuf[IOBUF_SIZE];
348 static unsigned char   stdobuf[IOBUF_SIZE];
349 static unsigned char   hold_buf[HOLD_SIZE*2];
350 static int             hold_count;
351
352 /* MIME preprocessor fifo */
353
354 #define MIME_BUF_SIZE   (1024)    /* 2^n ring buffer */
355 #define MIME_BUF_MASK   (MIME_BUF_SIZE-1)   
356 #define Fifo(n)         mime_buf[(n)&MIME_BUF_MASK]
357 static unsigned char           mime_buf[MIME_BUF_SIZE];
358 static unsigned int            mime_top = 0;
359 static unsigned int            mime_last = 0;  /* decoded */
360 static unsigned int            mime_input = 0; /* undecoded */
361
362 /* flags */
363 static int             unbuf_f = FALSE;
364 static int             estab_f = FALSE;
365 static int             nop_f = FALSE;
366 static int             binmode_f = TRUE;       /* binary mode */
367 static int             rot_f = FALSE;          /* rot14/43 mode */
368 static int             hira_f = FALSE;          /* hira/kata henkan */
369 static int             input_f = FALSE;        /* non fixed input code  */
370 static int             alpha_f = FALSE;        /* convert JIx0208 alphbet to ASCII */
371 static int             mime_f = STRICT_MIME;   /* convert MIME B base64 or Q */
372 static int             mimebuf_f = FALSE;      /* MIME buffered input */
373 static int             broken_f = FALSE;       /* convert ESC-less broken JIS */
374 static int             iso8859_f = FALSE;      /* ISO8859 through */
375 static int             mimeout_f = FALSE;       /* base64 mode */
376 #if defined(MSDOS) || defined(__OS2__) 
377 static int             x0201_f = TRUE;         /* Assume JISX0201 kana */
378 #else
379 static int             x0201_f = NO_X0201;     /* Assume NO JISX0201 */
380 #endif
381 static int             iso2022jp_f = FALSE;    /* convert ISO-2022-JP */
382 #ifdef UTF8_OUTPUT_ENABLE
383 static int             unicode_bom_f= 0;   /* Output Unicode BOM */
384 static int             w_oconv16_LE = 0;   /* utf-16 little endian */
385 static int             ms_ucs_map_f = FALSE;   /* Microsoft UCS Mapping Compatible */
386 #endif
387
388
389 #ifdef NUMCHAR_OPTION
390
391 #define CLASS_MASK  0x0f000000
392 #define CLASS_UTF16 0x01000000
393 #endif
394
395 #ifdef INPUT_OPTION
396 static int cap_f = FALSE;
397 static int (*i_cgetc)PROTO((FILE *)) = std_getc; /* input of cgetc */
398 static int (*i_cungetc)PROTO((int c ,FILE *f)) = std_ungetc;
399 STATIC int cap_getc PROTO((FILE *f));
400 STATIC int cap_ungetc PROTO((int c,FILE *f));
401
402 static int url_f = FALSE;
403 static int (*i_ugetc)PROTO((FILE *)) = std_getc; /* input of ugetc */
404 static int (*i_uungetc)PROTO((int c ,FILE *f)) = std_ungetc;
405 STATIC int url_getc PROTO((FILE *f));
406 STATIC int url_ungetc PROTO((int c,FILE *f));
407
408 static int numchar_f = FALSE;
409 static int (*i_ngetc)PROTO((FILE *)) = std_getc; /* input of ugetc */
410 static int (*i_nungetc)PROTO((int c ,FILE *f)) = std_ungetc;
411 STATIC int numchar_getc PROTO((FILE *f));
412 STATIC int numchar_ungetc PROTO((int c,FILE *f));
413 #endif
414
415 #ifdef CHECK_OPTION
416 static int noout_f = FALSE;
417 STATIC void no_putc PROTO((int c));
418 static int debug_f = FALSE;
419 STATIC void debug PROTO((char *str));
420 #endif
421
422 static int guess_f = FALSE;
423 STATIC  void    print_guessed_code PROTO((char *filename));
424 STATIC  void    set_input_codename PROTO((char *codename));
425 static int is_inputcode_mixed = FALSE;
426 static int is_inputcode_set   = FALSE;
427
428 #ifdef EXEC_IO
429 static int exec_f = 0;
430 #endif
431
432 #ifdef SHIFTJIS_CP932
433 STATIC int cp932_f = TRUE;
434 #define CP932_TABLE_BEGIN (0xfa)
435 #define CP932_TABLE_END   (0xfc)
436
437 STATIC int cp932inv_f = TRUE;
438 #define CP932INV_TABLE_BEGIN (0xed)
439 #define CP932INV_TABLE_END   (0xee)
440
441 /* STATIC int cp932_conv PROTO((int c2, int c1)); */
442 #endif /* SHIFTJIS_CP932 */
443
444 #ifdef X0212_ENABLE
445 STATIC int x0212_f = FALSE;
446 static int x0212_shift PROTO((int c));
447 static int x0212_unshift PROTO((int c));
448 #endif
449
450 STATIC unsigned char prefix_table[256];
451
452 STATIC void e_status PROTO((struct input_code *, int));
453 STATIC void s_status PROTO((struct input_code *, int));
454
455 #ifdef UTF8_INPUT_ENABLE
456 STATIC void w_status PROTO((struct input_code *, int));
457 STATIC void w16_status PROTO((struct input_code *, int));
458 static int             utf16_mode = UTF16LE_INPUT;
459 #endif
460
461 struct input_code input_code_list[] = {
462     {"EUC-JP",    0, 0, 0, {0, 0, 0}, e_status, e_iconv, 0},
463     {"Shift_JIS", 0, 0, 0, {0, 0, 0}, s_status, s_iconv, 0},
464     {"UTF-8",     0, 0, 0, {0, 0, 0}, w_status, w_iconv, 0},
465     {"UTF-16",    0, 0, 0, {0, 0, 0}, w16_status, w_iconv16, 0},
466     {0}
467 };
468
469 static int              mimeout_mode = 0;
470 static int              base64_count = 0;
471
472 /* X0208 -> ASCII converter */
473
474 /* fold parameter */
475 static int             f_line = 0;    /* chars in line */
476 static int             f_prev = 0;
477 static int             fold_preserve_f = FALSE; /* preserve new lines */
478 static int             fold_f  = FALSE;
479 static int             fold_len  = 0;
480
481 /* options */
482 static unsigned char   kanji_intro = DEFAULT_J;
483 static unsigned char   ascii_intro = DEFAULT_R;
484
485 /* Folding */
486
487 #define FOLD_MARGIN  10
488 #define DEFAULT_FOLD 60
489
490 static int             fold_margin  = FOLD_MARGIN;
491
492 /* converters */
493
494 #ifdef DEFAULT_CODE_JIS
495 #   define  DEFAULT_CONV j_oconv
496 #endif
497 #ifdef DEFAULT_CODE_SJIS
498 #   define  DEFAULT_CONV s_oconv
499 #endif
500 #ifdef DEFAULT_CODE_EUC
501 #   define  DEFAULT_CONV e_oconv
502 #endif
503 #ifdef DEFAULT_CODE_UTF8
504 #   define  DEFAULT_CONV w_oconv
505 #endif
506
507 /* process default */
508 static void (*output_conv)PROTO((int c2,int c1)) = DEFAULT_CONV;   
509
510 static void (*oconv)PROTO((int c2,int c1)) = no_connection; 
511 /* s_iconv or oconv */
512 static int (*iconv)PROTO((int c2,int c1,int c0)) = no_connection2;   
513
514 static void (*o_zconv)PROTO((int c2,int c1)) = no_connection; 
515 static void (*o_fconv)PROTO((int c2,int c1)) = no_connection; 
516 static void (*o_crconv)PROTO((int c2,int c1)) = no_connection; 
517 static void (*o_rot_conv)PROTO((int c2,int c1)) = no_connection; 
518 static void (*o_hira_conv)PROTO((int c2,int c1)) = no_connection; 
519 static void (*o_base64conv)PROTO((int c2,int c1)) = no_connection;
520 static void (*o_iso2022jp_check_conv)PROTO((int c2,int c1)) = no_connection;
521
522 /* static redirections */
523
524 static  void   (*o_putc)PROTO((int c)) = std_putc;
525
526 static  int    (*i_getc)PROTO((FILE *f)) = std_getc; /* general input */
527 static  int    (*i_ungetc)PROTO((int c,FILE *f)) =std_ungetc;
528
529 static  int    (*i_bgetc)PROTO((FILE *)) = std_getc; /* input of mgetc */
530 static  int    (*i_bungetc)PROTO((int c ,FILE *f)) = std_ungetc;
531
532 static  void   (*o_mputc)PROTO((int c)) = std_putc ; /* output of mputc */
533
534 static  int    (*i_mgetc)PROTO((FILE *)) = std_getc; /* input of mgetc */
535 static  int    (*i_mungetc)PROTO((int c ,FILE *f)) = std_ungetc;
536
537 /* for strict mime */
538 static  int    (*i_mgetc_buf)PROTO((FILE *)) = std_getc; /* input of mgetc_buf */
539 static  int    (*i_mungetc_buf)PROTO((int c,FILE *f)) = std_ungetc;
540
541 /* Global states */
542 static int output_mode = ASCII,    /* output kanji mode */
543            input_mode =  ASCII,    /* input kanji mode */
544            shift_mode =  FALSE;    /* TRUE shift out, or X0201  */
545 static int mime_decode_mode =   FALSE;    /* MIME mode B base64, Q hex */
546
547 /* X0201 / X0208 conversion tables */
548
549 /* X0201 kana conversion table */
550 /* 90-9F A0-DF */
551 static
552 unsigned char cv[]= {
553     0x21,0x21,0x21,0x23,0x21,0x56,0x21,0x57,
554     0x21,0x22,0x21,0x26,0x25,0x72,0x25,0x21,
555     0x25,0x23,0x25,0x25,0x25,0x27,0x25,0x29,
556     0x25,0x63,0x25,0x65,0x25,0x67,0x25,0x43,
557     0x21,0x3c,0x25,0x22,0x25,0x24,0x25,0x26,
558     0x25,0x28,0x25,0x2a,0x25,0x2b,0x25,0x2d,
559     0x25,0x2f,0x25,0x31,0x25,0x33,0x25,0x35,
560     0x25,0x37,0x25,0x39,0x25,0x3b,0x25,0x3d,
561     0x25,0x3f,0x25,0x41,0x25,0x44,0x25,0x46,
562     0x25,0x48,0x25,0x4a,0x25,0x4b,0x25,0x4c,
563     0x25,0x4d,0x25,0x4e,0x25,0x4f,0x25,0x52,
564     0x25,0x55,0x25,0x58,0x25,0x5b,0x25,0x5e,
565     0x25,0x5f,0x25,0x60,0x25,0x61,0x25,0x62,
566     0x25,0x64,0x25,0x66,0x25,0x68,0x25,0x69,
567     0x25,0x6a,0x25,0x6b,0x25,0x6c,0x25,0x6d,
568     0x25,0x6f,0x25,0x73,0x21,0x2b,0x21,0x2c,
569     0x00,0x00};
570
571
572 /* X0201 kana conversion table for daguten */
573 /* 90-9F A0-DF */
574 static
575 unsigned char dv[]= { 
576     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
577     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
578     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
579     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
580     0x00,0x00,0x00,0x00,0x00,0x00,0x25,0x74,
581     0x00,0x00,0x00,0x00,0x25,0x2c,0x25,0x2e,
582     0x25,0x30,0x25,0x32,0x25,0x34,0x25,0x36,
583     0x25,0x38,0x25,0x3a,0x25,0x3c,0x25,0x3e,
584     0x25,0x40,0x25,0x42,0x25,0x45,0x25,0x47,
585     0x25,0x49,0x00,0x00,0x00,0x00,0x00,0x00,
586     0x00,0x00,0x00,0x00,0x25,0x50,0x25,0x53,
587     0x25,0x56,0x25,0x59,0x25,0x5c,0x00,0x00,
588     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
589     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
590     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
591     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
592     0x00,0x00};
593
594 /* X0201 kana conversion table for han-daguten */
595 /* 90-9F A0-DF */
596 static
597 unsigned char ev[]= { 
598     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
599     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
600     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
601     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
602     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
603     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
604     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
605     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
606     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
607     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
608     0x00,0x00,0x00,0x00,0x25,0x51,0x25,0x54,
609     0x25,0x57,0x25,0x5a,0x25,0x5d,0x00,0x00,
610     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
611     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
612     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
613     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
614     0x00,0x00};
615
616
617 /* X0208 kigou conversion table */
618 /* 0x8140 - 0x819e */
619 static
620 unsigned char fv[] = {
621
622     0x00,0x00,0x00,0x00,0x2c,0x2e,0x00,0x3a,
623     0x3b,0x3f,0x21,0x00,0x00,0x27,0x60,0x00,
624     0x5e,0x00,0x5f,0x00,0x00,0x00,0x00,0x00,
625     0x00,0x00,0x00,0x00,0x00,0x2d,0x00,0x2f,
626     0x5c,0x00,0x00,0x7c,0x00,0x00,0x60,0x27,
627     0x22,0x22,0x28,0x29,0x00,0x00,0x5b,0x5d,
628     0x7b,0x7d,0x3c,0x3e,0x00,0x00,0x00,0x00,
629     0x00,0x00,0x00,0x00,0x2b,0x2d,0x00,0x00,
630     0x00,0x3d,0x00,0x3c,0x3e,0x00,0x00,0x00,
631     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
632     0x24,0x00,0x00,0x25,0x23,0x26,0x2a,0x40,
633     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
634 } ;
635
636
637 #define    CRLF      1
638
639 static int             file_out = FALSE;
640 #ifdef OVERWRITE
641 static int             overwrite = FALSE;
642 #endif
643
644 static int             crmode_f = 0;   /* CR, NL, CRLF */
645 #ifdef EASYWIN /*Easy Win */
646 static int             end_check;
647 #endif /*Easy Win */
648
649 #ifndef PERL_XS
650 int
651 main(argc, argv)
652     int             argc;
653     char          **argv;
654 {
655     FILE  *fin;
656     unsigned char  *cp;
657
658     char *outfname = NULL;
659     char *origfname;
660
661 #ifdef EASYWIN /*Easy Win */
662     _BufferSize.y = 400;/*Set Scroll Buffer Size*/
663 #endif
664
665     for (argc--,argv++; (argc > 0) && **argv == '-'; argc--, argv++) {
666         cp = (unsigned char *)*argv;
667         options(cp);
668 #ifdef EXEC_IO
669         if (exec_f){
670             int fds[2], pid;
671             if (pipe(fds) < 0 || (pid = fork()) < 0){
672                 abort();
673             }
674             if (pid == 0){
675                 if (exec_f > 0){
676                     close(fds[0]);
677                     dup2(fds[1], 1);
678                 }else{
679                     close(fds[1]);
680                     dup2(fds[0], 0);
681                 }
682                 execvp(argv[1], &argv[1]);
683             }
684             if (exec_f > 0){
685                 close(fds[1]);
686                 dup2(fds[0], 0);
687             }else{
688                 close(fds[0]);
689                 dup2(fds[1], 1);
690             }
691             argc = 0;
692             break;
693         }
694 #endif
695     }
696     if(x0201_f == WISH_TRUE)
697          x0201_f = ((!iso2022jp_f)? TRUE : NO_X0201);
698
699     if (binmode_f == TRUE)
700 #ifdef __OS2__
701     if (freopen("","wb",stdout) == NULL) 
702         return (-1);
703 #else
704     setbinmode(stdout);
705 #endif
706
707     if (unbuf_f)
708       setbuf(stdout, (char *) NULL);
709     else
710       setvbuffer(stdout, stdobuf, IOBUF_SIZE);
711
712     if (argc == 0) {
713       if (binmode_f == TRUE)
714 #ifdef __OS2__
715       if (freopen("","rb",stdin) == NULL) return (-1);
716 #else
717       setbinmode(stdin);
718 #endif
719       setvbuffer(stdin, stdibuf, IOBUF_SIZE);
720       if (nop_f)
721           noconvert(stdin);
722       else {
723           kanji_convert(stdin);
724           if (guess_f) print_guessed_code(NULL);
725       }
726     } else {
727       int nfiles = argc;
728       while (argc--) {
729           if ((fin = fopen((origfname = *argv++), "r")) == NULL) {
730               perror(*--argv);
731               return(-1);
732           } else {
733 #ifdef OVERWRITE
734               int fd = 0;
735               int fd_backup = 0;
736 #endif
737
738 /* reopen file for stdout */
739               if (file_out == TRUE) {
740 #ifdef OVERWRITE
741                   if (overwrite){
742                       outfname = malloc(strlen(origfname)
743                                         + strlen(".nkftmpXXXXXX")
744                                         + 1);
745                       if (!outfname){
746                           perror(origfname);
747                           return -1;
748                       }
749                       strcpy(outfname, origfname);
750 #ifdef MSDOS
751                       {
752                           int i;
753                           for (i = strlen(outfname); i; --i){
754                               if (outfname[i - 1] == '/'
755                                   || outfname[i - 1] == '\\'){
756                                   break;
757                               }
758                           }
759                           outfname[i] = '\0';
760                       }
761                       strcat(outfname, "ntXXXXXX");
762                       mktemp(outfname);
763                       fd = open(outfname, O_WRONLY | O_CREAT | O_TRUNC,
764                                 S_IREAD | S_IWRITE);
765 #else
766                       strcat(outfname, ".nkftmpXXXXXX");
767                       fd = mkstemp(outfname);
768 #endif
769                       if (fd < 0
770                           || (fd_backup = dup(fileno(stdout))) < 0
771                           || dup2(fd, fileno(stdout)) < 0
772                           ){
773                           perror(origfname);
774                           return -1;
775                       }
776                   }else
777 #endif
778                   if(argc == 1 ) {
779                       outfname = *argv++;
780                       argc--;
781                   } else {
782                       outfname = "nkf.out";
783                   }
784
785                   if(freopen(outfname, "w", stdout) == NULL) {
786                       perror (outfname);
787                       return (-1);
788                   }
789                   if (binmode_f == TRUE) {
790 #ifdef __OS2__
791                       if (freopen("","wb",stdout) == NULL) 
792                            return (-1);
793 #else
794                       setbinmode(stdout);
795 #endif
796                   }
797               }
798               if (binmode_f == TRUE)
799 #ifdef __OS2__
800                  if (freopen("","rb",fin) == NULL) 
801                     return (-1);
802 #else
803                  setbinmode(fin);
804 #endif 
805               setvbuffer(fin, stdibuf, IOBUF_SIZE);
806               if (nop_f)
807                   noconvert(fin);
808               else {
809                   char *filename = NULL;
810                   kanji_convert(fin);
811                   if (nfiles > 1) filename = origfname;
812                   if (guess_f) print_guessed_code(filename);
813               }
814               fclose(fin);
815 #ifdef OVERWRITE
816               if (overwrite) {
817                   struct stat     sb;
818 #if defined(MSDOS) && !defined(__MINGW32__)
819                   time_t tb[2];
820 #else
821                   struct utimbuf  tb;
822 #endif
823
824                   fflush(stdout);
825                   close(fd);
826                   if (dup2(fd_backup, fileno(stdout)) < 0){
827                       perror("dup2");
828                   }
829                   if (stat(origfname, &sb)) {
830                       fprintf(stderr, "Can't stat %s\n", origfname);
831                   }
832                   /* \e$B%Q!<%_%C%7%g%s$rI|85\e(B */
833                   if (chmod(outfname, sb.st_mode)) {
834                       fprintf(stderr, "Can't set permission %s\n", outfname);
835                   }
836
837                   /* \e$B%?%$%`%9%?%s%W$rI|85\e(B */
838 #if defined(MSDOS) && !defined(__MINGW32__)
839                   tb[0] = tb[1] = sb.st_mtime;
840                   if (utime(outfname, tb)) {
841                       fprintf(stderr, "Can't set timestamp %s\n", outfname);
842                   }
843 #else
844                   tb.actime  = sb.st_atime;
845                   tb.modtime = sb.st_mtime;
846                   if (utime(outfname, &tb)) {
847                       fprintf(stderr, "Can't set timestamp %s\n", outfname);
848                   }
849 #endif
850 #ifdef MSDOS
851                   if (unlink(origfname)){
852                       perror(origfname);
853                   }
854 #endif
855                   if (rename(outfname, origfname)) {
856                       perror(origfname);
857                       fprintf(stderr, "Can't rename %s to %s\n",
858                               outfname, origfname);
859                   }
860                   free(outfname);
861               }
862 #endif
863           }
864       }
865     }
866 #ifdef EASYWIN /*Easy Win */
867     if (file_out == FALSE) 
868         scanf("%d",&end_check);
869     else 
870         fclose(stdout);
871 #else /* for Other OS */
872     if (file_out == TRUE) 
873         fclose(stdout);
874 #endif 
875     return (0);
876 }
877 #endif
878
879 static 
880 struct {
881     char *name;
882     char *alias;
883 } long_option[] = {
884     {"base64","jMB"},
885     {"euc","e"},
886     {"euc-input","E"},
887     {"fj","jm"},
888     {"help","v"},
889     {"jis","j"},
890     {"jis-input","J"},
891     {"mac","sLm"},
892     {"mime","jM"},
893     {"mime-input","m"},
894     {"msdos","sLw"},
895     {"sjis","s"},
896     {"sjis-input","S"},
897     {"unix","eLu"},
898     {"version","V"},
899     {"windows","sLw"},
900     {"hiragana","h1"},
901     {"katakana","h2"},
902     {"katakana-hiragana","h3"},
903     {"guess", "g"},
904     {"cp932", ""},
905     {"no-cp932", ""},
906 #ifdef X0212_ENABLE
907     {"x0212", ""},
908 #endif
909 #ifdef UTF8_OUTPUT_ENABLE
910     {"utf8", "w"},
911     {"utf16", "w16"},
912     {"ms-ucs-map", ""},
913 #endif
914 #ifdef UTF8_INPUT_ENABLE
915     {"utf8-input", "W"},
916     {"utf16-input", "W16"},
917 #endif
918 #ifdef OVERWRITE
919     {"overwrite", ""},
920 #endif
921 #ifdef INPUT_OPTION
922     {"cap-input", ""},
923     {"url-input", ""},
924 #endif
925 #ifdef NUMCHAR_OPTION
926     {"numchar-input", ""},
927 #endif
928 #ifdef CHECK_OPTION
929     {"no-output", ""},
930     {"debug", ""},
931 #endif
932 #ifdef SHIFTJIS_CP932
933     {"cp932inv", ""},
934 #endif
935 #ifdef EXEC_IO
936     {"exec-in", ""},
937     {"exec-out", ""},
938 #endif
939     {"prefix=", ""},
940 };
941
942 static int option_mode = 0;
943
944 void
945 options(cp) 
946      unsigned char *cp;
947 {
948     int i;
949     unsigned char *p = NULL;
950
951     if (option_mode==1)
952         return;
953     if (*cp++ != '-') 
954         return;
955     while (*cp) {
956         if (p && !*cp) {
957             cp = p;
958             p = 0;
959         }
960         switch (*cp++) {
961         case '-':  /* literal options */
962             if (!*cp) {        /* ignore the rest of arguments */
963                 option_mode = 1;
964                 return;
965             }
966             for (i=0;i<sizeof(long_option)/sizeof(long_option[0]);i++) {
967                 int j;
968                 p = (unsigned char *)long_option[i].name;
969                 for (j=0;*p && (*p != '=') && *p == cp[j];p++, j++);
970                 if (*p == cp[j]){
971                     p = &cp[j];
972                     break;
973                 }
974                 p = 0;
975             }
976             if (p == 0) return;
977             cp = (unsigned char *)long_option[i].alias;
978             if (!*cp){
979 #ifdef OVERWRITE
980                 if (strcmp(long_option[i].name, "overwrite") == 0){
981                     file_out = TRUE;
982                     overwrite = TRUE;
983                     continue;
984                 }
985 #endif
986 #ifdef INPUT_OPTION
987                 if (strcmp(long_option[i].name, "cap-input") == 0){
988                     cap_f = TRUE;
989                     continue;
990                 }
991                 if (strcmp(long_option[i].name, "url-input") == 0){
992                     url_f = TRUE;
993                     continue;
994                 }
995 #endif
996 #ifdef NUMCHAR_OPTION
997                 if (strcmp(long_option[i].name, "numchar-input") == 0){
998                     numchar_f = TRUE;
999                     continue;
1000                 }
1001 #endif
1002 #ifdef CHECK_OPTION
1003                 if (strcmp(long_option[i].name, "no-output") == 0){
1004                     noout_f = TRUE;
1005                     continue;
1006                 }
1007                 if (strcmp(long_option[i].name, "debug") == 0){
1008                     debug_f = TRUE;
1009                     continue;
1010                 }
1011 #endif
1012                 if (strcmp(long_option[i].name, "cp932") == 0){
1013 #ifdef SHIFTJIS_CP932
1014                     cp932_f = TRUE;
1015                     cp932inv_f = TRUE;
1016 #endif
1017 #ifdef UTF8_OUTPUT_ENABLE
1018                     ms_ucs_map_f = TRUE;
1019 #endif
1020                     continue;
1021                 }
1022                 if (strcmp(long_option[i].name, "no-cp932") == 0){
1023 #ifdef SHIFTJIS_CP932
1024                     cp932_f = FALSE;
1025                     cp932inv_f = FALSE;
1026 #endif
1027 #ifdef UTF8_OUTPUT_ENABLE
1028                     ms_ucs_map_f = FALSE;
1029 #endif
1030                     continue;
1031                 }
1032 #ifdef SHIFTJIS_CP932
1033                 if (strcmp(long_option[i].name, "cp932inv") == 0){
1034                     cp932inv_f = TRUE;
1035                     continue;
1036                 }
1037 #endif
1038
1039 #ifdef X0212_ENABLE
1040                 if (strcmp(long_option[i].name, "x0212") == 0){
1041                     x0212_f = TRUE;
1042                     continue;
1043                 }
1044 #endif
1045
1046 #ifdef EXEC_IO
1047                   if (strcmp(long_option[i].name, "exec-in") == 0){
1048                       exec_f = 1;
1049                       return;
1050                   }
1051                   if (strcmp(long_option[i].name, "exec-out") == 0){
1052                       exec_f = -1;
1053                       return;
1054                   }
1055 #endif
1056 #ifdef UTF8_OUTPUT_ENABLE
1057                 if (strcmp(long_option[i].name, "ms-ucs-map") == 0){
1058                     ms_ucs_map_f = TRUE;
1059                     continue;
1060                 }
1061 #endif
1062                 if (strcmp(long_option[i].name, "prefix=") == 0){
1063                     if (*p == '=' && ' ' < p[1] && p[1] < 128){
1064                         for (i = 2; ' ' < p[i] && p[i] < 128; i++){
1065                             prefix_table[p[i]] = p[1];
1066                         }
1067                     }
1068                     continue;
1069                 }
1070             }
1071             continue;
1072         case 'b':           /* buffered mode */
1073             unbuf_f = FALSE;
1074             continue;
1075         case 'u':           /* non bufferd mode */
1076             unbuf_f = TRUE;
1077             continue;
1078         case 't':           /* transparent mode */
1079             nop_f = TRUE;
1080             continue;
1081         case 'j':           /* JIS output */
1082         case 'n':
1083             output_conv = j_oconv;
1084             continue;
1085         case 'e':           /* AT&T EUC output */
1086             output_conv = e_oconv;
1087             continue;
1088         case 's':           /* SJIS output */
1089             output_conv = s_oconv;
1090             continue;
1091         case 'l':           /* ISO8859 Latin-1 support, no conversion */
1092             iso8859_f = TRUE;  /* Only compatible with ISO-2022-JP */
1093             input_f = LATIN1_INPUT;
1094             continue;
1095         case 'i':           /* Kanji IN ESC-$-@/B */
1096             if (*cp=='@'||*cp=='B') 
1097                 kanji_intro = *cp++;
1098             continue;
1099         case 'o':           /* ASCII IN ESC-(-J/B */
1100             if (*cp=='J'||*cp=='B'||*cp=='H') 
1101                 ascii_intro = *cp++;
1102             continue;
1103         case 'h':
1104             /*  
1105                 bit:1   hira -> kata
1106                 bit:2   kata -> hira
1107             */
1108             if ('9'>= *cp && *cp>='0') 
1109                 hira_f |= (*cp++ -'0');
1110             else 
1111                 hira_f |= 1;
1112             continue;
1113         case 'r':
1114             rot_f = TRUE;
1115             continue;
1116 #if defined(MSDOS) || defined(__OS2__) 
1117         case 'T':
1118             binmode_f = FALSE;
1119             continue;
1120 #endif
1121 #ifndef PERL_XS
1122         case 'V':
1123             version();
1124             exit(1);
1125             break;
1126         case 'v':
1127             usage();
1128             exit(1);
1129             break;
1130 #endif
1131 #ifdef UTF8_OUTPUT_ENABLE
1132         case 'w':           /* UTF-8 output */
1133             if ('1'== cp[0] && '6'==cp[1]) {
1134                 output_conv = w_oconv16; cp+=2;
1135                 if (cp[0]=='L') {
1136                     unicode_bom_f=2; cp++;
1137                     w_oconv16_LE = 1;
1138                     if (cp[0] == '0'){
1139                         unicode_bom_f=1; cp++;
1140                     }
1141                 } else if (cp[0] == 'B') {
1142                     unicode_bom_f=2; cp++;
1143                     if (cp[0] == '0'){
1144                         unicode_bom_f=1; cp++;
1145                     }
1146                 } 
1147             } else if (cp[0] == '8') {
1148                 output_conv = w_oconv; cp++;
1149                 unicode_bom_f=2;
1150                 if (cp[0] == '0'){
1151                     unicode_bom_f=1; cp++;
1152                 }
1153             } else
1154                 output_conv = w_oconv;
1155             continue;
1156 #endif
1157 #ifdef UTF8_INPUT_ENABLE
1158         case 'W':           /* UTF-8 input */
1159             if ('1'== cp[0] && '6'==cp[1]) {
1160                 input_f = UTF16LE_INPUT;
1161                 if (cp[0]=='L') {
1162                     cp++;
1163                 } else if (cp[0] == 'B') {
1164                     cp++;
1165                     input_f = UTF16BE_INPUT;
1166                 }
1167             } else if (cp[0] == '8') {
1168                 cp++;
1169                 input_f = UTF8_INPUT;
1170             } else
1171                 input_f = UTF8_INPUT;
1172             continue;
1173 #endif
1174         /* Input code assumption */
1175         case 'J':   /* JIS input */
1176         case 'E':   /* AT&T EUC input */
1177             input_f = JIS_INPUT;
1178             continue;
1179         case 'S':   /* MS Kanji input */
1180             input_f = SJIS_INPUT;
1181             if (x0201_f==NO_X0201) x0201_f=TRUE;
1182             continue;
1183         case 'Z':   /* Convert X0208 alphabet to asii */
1184             /*  bit:0   Convert X0208
1185                 bit:1   Convert Kankaku to one space
1186                 bit:2   Convert Kankaku to two spaces
1187                 bit:3   Convert HTML Entity
1188             */
1189             if ('9'>= *cp && *cp>='0') 
1190                 alpha_f |= 1<<(*cp++ -'0');
1191             else 
1192                 alpha_f |= TRUE;
1193             continue;
1194         case 'x':   /* Convert X0201 kana to X0208 or X0201 Conversion */
1195             x0201_f = FALSE;    /* No X0201->X0208 conversion */
1196             /* accept  X0201
1197                     ESC-(-I     in JIS, EUC, MS Kanji
1198                     SI/SO       in JIS, EUC, MS Kanji
1199                     SSO         in EUC, JIS, not in MS Kanji
1200                     MS Kanji (0xa0-0xdf) 
1201                output  X0201
1202                     ESC-(-I     in JIS (0x20-0x5f)
1203                     SSO         in EUC (0xa0-0xdf)
1204                     0xa0-0xd    in MS Kanji (0xa0-0xdf) 
1205             */
1206             continue;
1207         case 'X':   /* Assume X0201 kana */
1208             /* Default value is NO_X0201 for EUC/MS-Kanji mix */
1209             x0201_f = TRUE;
1210             continue;
1211         case 'F':   /* prserve new lines */
1212             fold_preserve_f = TRUE;
1213         case 'f':   /* folding -f60 or -f */
1214             fold_f = TRUE;
1215             fold_len = 0;
1216             while('0'<= *cp && *cp <='9') { /* we don't use atoi here */
1217                 fold_len *= 10;
1218                 fold_len += *cp++ - '0';
1219             }
1220             if (!(0<fold_len && fold_len<BUFSIZ)) 
1221                 fold_len = DEFAULT_FOLD;
1222             if (*cp=='-') {
1223                 fold_margin = 0;
1224                 cp++;
1225                 while('0'<= *cp && *cp <='9') { /* we don't use atoi here */
1226                     fold_margin *= 10;
1227                     fold_margin += *cp++ - '0';
1228                 }
1229             }
1230             continue;
1231         case 'm':   /* MIME support */
1232             if (*cp=='B'||*cp=='Q') {
1233                 mime_decode_mode = *cp++;
1234                 mimebuf_f = FIXED_MIME;
1235             } else if (*cp=='N') {
1236                 mime_f = TRUE; cp++;
1237             } else if (*cp=='S') {
1238                 mime_f = STRICT_MIME; cp++;
1239             } else if (*cp=='0') {
1240                 mime_f = FALSE; cp++;
1241             }
1242             continue;
1243         case 'M':   /* MIME output */
1244             if (*cp=='B') {
1245                 mimeout_mode = 'B';
1246                 mimeout_f = FIXED_MIME; cp++;
1247             } else if (*cp=='Q') {
1248                 mimeout_mode = 'Q';
1249                 mimeout_f = FIXED_MIME; cp++;
1250             } else {
1251                 mimeout_f = TRUE;
1252             }
1253             continue;
1254         case 'B':   /* Broken JIS support */
1255             /*  bit:0   no ESC JIS
1256                 bit:1   allow any x on ESC-(-x or ESC-$-x
1257                 bit:2   reset to ascii on NL
1258             */
1259             if ('9'>= *cp && *cp>='0') 
1260                 broken_f |= 1<<(*cp++ -'0');
1261             else 
1262                 broken_f |= TRUE;
1263             continue;
1264 #ifndef PERL_XS
1265         case 'O':/* for Output file */
1266             file_out = TRUE;
1267             continue;
1268 #endif
1269         case 'c':/* add cr code */
1270             crmode_f = CRLF;
1271             continue;
1272         case 'd':/* delete cr code */
1273             crmode_f = NL;
1274             continue;
1275         case 'I':   /* ISO-2022-JP output */
1276             iso2022jp_f = TRUE;
1277             continue;
1278         case 'L':  /* line mode */
1279             if (*cp=='u') {         /* unix */
1280                 crmode_f = NL; cp++;
1281             } else if (*cp=='m') { /* mac */
1282                 crmode_f = CR; cp++;
1283             } else if (*cp=='w') { /* windows */
1284                 crmode_f = CRLF; cp++;
1285             } else if (*cp=='0') { /* no conversion  */
1286                 crmode_f = 0; cp++;
1287             }
1288             continue;
1289         case 'g':
1290 #ifndef PERL_XS
1291             guess_f = TRUE;
1292 #endif
1293             continue;
1294         case ' ':    
1295         /* module muliple options in a string are allowed for Perl moudle  */
1296             while(*cp && *cp!='-') cp++;
1297             if(*cp=='-') cp++;
1298             continue;
1299         default:
1300             /* bogus option but ignored */
1301             continue;
1302         }
1303     }
1304 }
1305
1306 #ifdef ANSI_C_PROTOTYPE
1307 struct input_code * find_inputcode_byfunc(int (*iconv_func)(int c2,int c1,int c0))
1308 #else
1309 struct input_code * find_inputcode_byfunc(iconv_func)
1310      int (*iconv_func)();
1311 #endif
1312 {
1313     if (iconv_func){
1314         struct input_code *p = input_code_list;
1315         while (p->name){
1316             if (iconv_func == p->iconv_func){
1317                 return p;
1318             }
1319             p++;
1320         }
1321     }
1322     return 0;
1323 }
1324
1325 #ifdef ANSI_C_PROTOTYPE
1326 void set_iconv(int f, int (*iconv_func)(int c2,int c1,int c0))
1327 #else
1328 void set_iconv(f, iconv_func)
1329      int f;
1330      int (*iconv_func)();
1331 #endif
1332 {
1333 #ifdef CHECK_OPTION
1334     static int (*iconv_for_check)() = 0;
1335 #endif
1336 #ifdef INPUT_CODE_FIX
1337     if (f || !input_f)
1338 #endif
1339         if (estab_f != f){
1340             estab_f = f;
1341         }
1342
1343     if (iconv_func
1344 #ifdef INPUT_CODE_FIX
1345         && (f == -TRUE || !input_f) /* -TRUE means "FORCE" */
1346 #endif
1347         ){
1348         iconv = iconv_func;
1349     }
1350 #ifdef CHECK_OPTION
1351     if (estab_f && iconv_for_check != iconv){
1352         struct input_code *p = find_inputcode_byfunc(iconv);
1353         if (p){
1354             set_input_codename(p->name);
1355             debug(input_codename);
1356         }
1357         iconv_for_check = iconv;
1358     }
1359 #endif
1360 }
1361
1362 #define SCORE_L2       (1)                   /* \e$BBh\e(B2\e$B?e=`4A;z\e(B */
1363 #define SCORE_KANA     (SCORE_L2 << 1)       /* \e$B$$$o$f$kH>3Q%+%J\e(B */
1364 #define SCORE_DEPEND   (SCORE_KANA << 1)     /* \e$B5!<o0MB8J8;z\e(B */
1365 #ifdef SHIFTJIS_CP932
1366 #define SCORE_CP932    (SCORE_DEPEND << 1)   /* CP932 \e$B$K$h$kFI$_49$(\e(B */
1367 #define SCORE_NO_EXIST (SCORE_CP932 << 1)    /* \e$BB8:_$7$J$$J8;z\e(B */
1368 #else
1369 #define SCORE_NO_EXIST (SCORE_DEPEND << 1)   /* \e$BB8:_$7$J$$J8;z\e(B */
1370 #endif
1371 #define SCORE_iMIME    (SCORE_NO_EXIST << 1) /* MIME \e$B$K$h$k;XDj\e(B */
1372 #define SCORE_ERROR    (SCORE_iMIME << 1) /* \e$B%(%i!<\e(B */
1373
1374 #define SCORE_INIT (SCORE_iMIME)
1375
1376 int score_table_A0[] = {
1377     0, 0, 0, 0,
1378     0, 0, 0, 0,
1379     0, SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND,
1380     SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND, SCORE_NO_EXIST,
1381 };
1382
1383 int score_table_F0[] = {
1384     SCORE_L2, SCORE_L2, SCORE_L2, SCORE_L2,
1385     SCORE_L2, SCORE_DEPEND, SCORE_NO_EXIST, SCORE_NO_EXIST,
1386     SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND,
1387     SCORE_DEPEND, SCORE_NO_EXIST, SCORE_NO_EXIST, SCORE_ERROR,
1388 };
1389
1390 void set_code_score(ptr, score)
1391      struct input_code *ptr;
1392      int score;
1393 {
1394     if (ptr){
1395         ptr->score |= score;
1396     }
1397 }
1398
1399 void clr_code_score(ptr, score)
1400      struct input_code *ptr;
1401      int score;
1402 {
1403     if (ptr){
1404         ptr->score &= ~score;
1405     }
1406 }
1407
1408 void code_score(ptr)
1409      struct input_code *ptr;
1410 {
1411     int c2 = ptr->buf[0];
1412     int c1 = ptr->buf[1];
1413     if (c2 < 0){
1414         set_code_score(ptr, SCORE_ERROR);
1415     }else if (c2 == SSO){
1416         set_code_score(ptr, SCORE_KANA);
1417 #ifdef UTF8_OUTPUT_ENABLE
1418     }else if (!e2w_conv(c2, c1)){
1419         set_code_score(ptr, SCORE_NO_EXIST);
1420 #endif
1421     }else if ((c2 & 0x70) == 0x20){
1422         set_code_score(ptr, score_table_A0[c2 & 0x0f]);
1423     }else if ((c2 & 0x70) == 0x70){
1424         set_code_score(ptr, score_table_F0[c2 & 0x0f]);
1425     }else if ((c2 & 0x70) >= 0x50){
1426         set_code_score(ptr, SCORE_L2);
1427     }
1428 }
1429
1430 void status_disable(ptr)
1431 struct input_code *ptr;
1432 {
1433     ptr->stat = -1;
1434     ptr->buf[0] = -1;
1435     code_score(ptr);
1436     if (iconv == ptr->iconv_func) set_iconv(FALSE, 0);
1437 }
1438
1439 void status_push_ch(ptr, c)
1440      struct input_code *ptr;
1441      int c;
1442 {
1443     ptr->buf[ptr->index++] = c;
1444 }
1445
1446 void status_clear(ptr)
1447      struct input_code *ptr;
1448 {
1449     ptr->stat = 0;
1450     ptr->index = 0;
1451 }
1452
1453 void status_reset(ptr)
1454      struct input_code *ptr;
1455 {
1456     status_clear(ptr);
1457     ptr->score = SCORE_INIT;
1458 }
1459
1460 void status_reinit(ptr)
1461      struct input_code *ptr;
1462 {
1463     status_reset(ptr);
1464     ptr->_file_stat = 0;
1465 }
1466
1467 void status_check(ptr, c)
1468      struct input_code *ptr;
1469      int c;
1470 {
1471     if (c <= DEL && estab_f){
1472         status_reset(ptr);
1473     }
1474 }
1475
1476 void s_status(ptr, c)
1477      struct input_code *ptr;
1478      int c;
1479 {
1480     switch(ptr->stat){
1481       case -1:
1482           status_check(ptr, c);
1483           break;
1484       case 0:
1485           if (c <= DEL){
1486               break;
1487 #ifdef NUMCHAR_OPTION
1488           }else if ((c & CLASS_MASK) == CLASS_UTF16){
1489               break;
1490 #endif
1491           }else if (0xa1 <= c && c <= 0xdf){
1492               status_push_ch(ptr, SSO);
1493               status_push_ch(ptr, c);
1494               code_score(ptr);
1495               status_clear(ptr);
1496           }else if ((0x81 <= c && c < 0xa0) || (0xe0 <= c && c <= 0xef)){
1497               ptr->stat = 1;
1498               status_push_ch(ptr, c);
1499 #ifdef SHIFTJIS_CP932
1500           }else if (cp932_f
1501                     && CP932_TABLE_BEGIN <= c && c <= CP932_TABLE_END){
1502               ptr->stat = 2;
1503               status_push_ch(ptr, c);
1504 #endif /* SHIFTJIS_CP932 */
1505 #ifdef X0212_ENABLE
1506           }else if (x0212_f && 0xf0 <= c && c <= 0xfc){
1507               ptr->stat = 1;
1508               status_push_ch(ptr, c);
1509 #endif /* X0212_ENABLE */
1510           }else{
1511               status_disable(ptr);
1512           }
1513           break;
1514       case 1:
1515           if ((0x40 <= c && c <= 0x7e) || (0x80 <= c && c <= 0xfc)){
1516               status_push_ch(ptr, c);
1517               s2e_conv(ptr->buf[0], ptr->buf[1], &ptr->buf[0], &ptr->buf[1]);
1518               code_score(ptr);
1519               status_clear(ptr);
1520           }else{
1521               status_disable(ptr);
1522           }
1523           break;
1524       case 2:
1525 #ifdef SHIFTJIS_CP932
1526           if ((0x40 <= c && c <= 0x7e) || (0x80 <= c && c <= 0xfc)){
1527               status_push_ch(ptr, c);
1528               if (s2e_conv(ptr->buf[0], ptr->buf[1], &ptr->buf[0], &ptr->buf[1]) == 0){
1529                   set_code_score(ptr, SCORE_CP932);
1530                   status_clear(ptr);
1531                   break;
1532               }
1533           }
1534 #endif /* SHIFTJIS_CP932 */
1535 #ifndef X0212_ENABLE
1536           status_disable(ptr);
1537           break;
1538 #endif
1539     }
1540 }
1541
1542 void e_status(ptr, c)
1543      struct input_code *ptr;
1544      int c;
1545 {
1546     switch (ptr->stat){
1547       case -1:
1548           status_check(ptr, c);
1549           break;
1550       case 0:
1551           if (c <= DEL){
1552               break;
1553 #ifdef NUMCHAR_OPTION
1554           }else if ((c & CLASS_MASK) == CLASS_UTF16){
1555               break;
1556 #endif
1557           }else if (SSO == c || (0xa1 <= c && c <= 0xfe)){
1558               ptr->stat = 1;
1559               status_push_ch(ptr, c);
1560 #ifdef X0212_ENABLE
1561           }else if (0x8f == c){
1562               ptr->stat = 2;
1563               status_push_ch(ptr, c);
1564 #endif /* X0212_ENABLE */
1565           }else{
1566               status_disable(ptr);
1567           }
1568           break;
1569       case 1:
1570           if (0xa1 <= c && c <= 0xfe){
1571               status_push_ch(ptr, c);
1572               code_score(ptr);
1573               status_clear(ptr);
1574           }else{
1575               status_disable(ptr);
1576           }
1577           break;
1578 #ifdef X0212_ENABLE
1579       case 2:
1580           if (0xa1 <= c && c <= 0xfe){
1581               ptr->stat = 1;
1582               status_push_ch(ptr, c);
1583           }else{
1584               status_disable(ptr);
1585           }
1586 #endif /* X0212_ENABLE */
1587     }
1588 }
1589
1590 #ifdef UTF8_INPUT_ENABLE
1591 void w16_status(ptr, c)
1592      struct input_code *ptr;
1593      int c;
1594 {
1595     switch (ptr->stat){
1596       case -1:
1597           break;
1598       case 0:
1599           if (ptr->_file_stat == 0){
1600               if (c == 0xfe || c == 0xff){
1601                   ptr->stat = c;
1602                   status_push_ch(ptr, c);
1603                   ptr->_file_stat = 1;
1604               }else{
1605                   status_disable(ptr);
1606                   ptr->_file_stat = -1;
1607               }
1608           }else if (ptr->_file_stat > 0){
1609               ptr->stat = 1;
1610               status_push_ch(ptr, c);
1611           }else if (ptr->_file_stat < 0){
1612               status_disable(ptr);
1613           }
1614           break;
1615
1616       case 1:
1617           if (c == EOF){
1618               status_disable(ptr);
1619               ptr->_file_stat = -1;
1620           }else{
1621               status_push_ch(ptr, c);
1622               status_clear(ptr);
1623           }
1624           break;
1625
1626       case 0xfe:
1627       case 0xff:
1628           if (ptr->stat != c && (c == 0xfe || c == 0xff)){
1629               status_push_ch(ptr, c);
1630               status_clear(ptr);
1631           }else{
1632               status_disable(ptr);
1633               ptr->_file_stat = -1;
1634           }
1635           break;
1636     }
1637 }
1638
1639 void w_status(ptr, c)
1640      struct input_code *ptr;
1641      int c;
1642 {
1643     switch (ptr->stat){
1644       case -1:
1645           status_check(ptr, c);
1646           break;
1647       case 0:
1648           if (c <= DEL){
1649               break;
1650 #ifdef NUMCHAR_OPTION
1651           }else if ((c & CLASS_MASK) == CLASS_UTF16){
1652               break;
1653 #endif
1654           }else if (0xc0 <= c && c <= 0xdf){
1655               ptr->stat = 1;
1656               status_push_ch(ptr, c);
1657           }else if (0xe0 <= c && c <= 0xef){
1658               ptr->stat = 2;
1659               status_push_ch(ptr, c);
1660           }else{
1661               status_disable(ptr);
1662           }
1663           break;
1664       case 1:
1665       case 2:
1666           if (0x80 <= c && c <= 0xbf){
1667               status_push_ch(ptr, c);
1668               if (ptr->index > ptr->stat){
1669                   int bom = (ptr->buf[0] == 0xef && ptr->buf[1] == 0xbb
1670                              && ptr->buf[2] == 0xbf);
1671                   w2e_conv(ptr->buf[0], ptr->buf[1], ptr->buf[2],
1672                            &ptr->buf[0], &ptr->buf[1]);
1673                   if (!bom){
1674                       code_score(ptr);
1675                   }
1676                   status_clear(ptr);
1677               }
1678           }else{
1679               status_disable(ptr);
1680           }
1681           break;
1682     }
1683 }
1684 #endif
1685
1686 void
1687 code_status(c)
1688      int c;
1689 {
1690     int action_flag = 1;
1691     struct input_code *result = 0;
1692     struct input_code *p = input_code_list;
1693     while (p->name){
1694         (p->status_func)(p, c);
1695         if (p->stat > 0){
1696             action_flag = 0;
1697         }else if(p->stat == 0){
1698             if (result){
1699                 action_flag = 0;
1700             }else{
1701                 result = p;
1702             }
1703         }
1704         ++p;
1705     }
1706
1707     if (action_flag){
1708         if (result && !estab_f){
1709             set_iconv(TRUE, result->iconv_func);
1710         }else if (c <= DEL){
1711             struct input_code *ptr = input_code_list;
1712             while (ptr->name){
1713                 status_reset(ptr);
1714                 ++ptr;
1715             }
1716         }
1717     }
1718 }
1719
1720 #define STD_GC_BUFSIZE (256)
1721 int std_gc_buf[STD_GC_BUFSIZE];
1722 int std_gc_ndx;
1723
1724 int 
1725 std_getc(f)
1726 FILE *f;
1727 {
1728     if (std_gc_ndx){
1729         return std_gc_buf[--std_gc_ndx];
1730     }
1731     return getc(f);
1732 }
1733
1734 int 
1735 std_ungetc(c,f)
1736 int c;
1737 FILE *f;
1738 {
1739     if (std_gc_ndx == STD_GC_BUFSIZE){
1740         return EOF;
1741     }
1742     std_gc_buf[std_gc_ndx++] = c;
1743     return c;
1744 }
1745
1746 void 
1747 std_putc(c)
1748 int c;
1749 {
1750     if(c!=EOF)
1751       putchar(c);
1752 }
1753
1754 int
1755 noconvert(f)
1756     FILE  *f;
1757 {
1758     int    c;
1759
1760     while ((c = (*i_getc)(f)) != EOF)
1761       (*o_putc)(c);
1762     return 1;
1763 }
1764
1765
1766 void
1767 module_connection()
1768 {
1769     oconv = output_conv; 
1770     o_putc = std_putc;
1771
1772     /* replace continucation module, from output side */
1773
1774     /* output redicrection */
1775 #ifdef CHECK_OPTION
1776     if (noout_f || guess_f){
1777         o_putc = no_putc;
1778     }
1779 #endif
1780     if (mimeout_f) {
1781         o_mputc = o_putc;
1782         o_putc = mime_putc;
1783         if (mimeout_f == TRUE) {
1784             o_base64conv = oconv; oconv = base64_conv;
1785         }
1786         /* base64_count = 0; */
1787     }
1788
1789     if (crmode_f) {
1790         o_crconv = oconv; oconv = cr_conv;
1791     }
1792     if (rot_f) {
1793         o_rot_conv = oconv; oconv = rot_conv;
1794     }
1795     if (iso2022jp_f) {
1796         o_iso2022jp_check_conv = oconv; oconv = iso2022jp_check_conv;
1797     }
1798     if (hira_f) {
1799         o_hira_conv = oconv; oconv = hira_conv;
1800     }
1801     if (fold_f) {
1802         o_fconv = oconv; oconv = fold_conv;
1803         f_line = 0;
1804     }
1805     if (alpha_f || x0201_f) {
1806         o_zconv = oconv; oconv = z_conv;
1807     }
1808
1809     i_getc = std_getc;
1810     i_ungetc = std_ungetc;
1811     /* input redicrection */
1812 #ifdef INPUT_OPTION
1813     if (cap_f){
1814         i_cgetc = i_getc; i_getc = cap_getc;
1815         i_cungetc = i_ungetc; i_ungetc= cap_ungetc;
1816     }
1817     if (url_f){
1818         i_ugetc = i_getc; i_getc = url_getc;
1819         i_uungetc = i_ungetc; i_ungetc= url_ungetc;
1820     }
1821 #endif
1822 #ifdef NUMCHAR_OPTION
1823     if (numchar_f){
1824         i_ngetc = i_getc; i_getc = numchar_getc;
1825         i_nungetc = i_ungetc; i_ungetc= numchar_ungetc;
1826     }
1827 #endif
1828     if (mime_f && mimebuf_f==FIXED_MIME) {
1829         i_mgetc = i_getc; i_getc = mime_getc;
1830         i_mungetc = i_ungetc; i_ungetc = mime_ungetc;
1831     }
1832     if (broken_f & 1) {
1833         i_bgetc = i_getc; i_getc = broken_getc;
1834         i_bungetc = i_ungetc; i_ungetc = broken_ungetc;
1835     }
1836     if (input_f == JIS_INPUT || input_f == LATIN1_INPUT) {
1837         set_iconv(-TRUE, e_iconv);
1838     } else if (input_f == SJIS_INPUT) {
1839         set_iconv(-TRUE, s_iconv);
1840 #ifdef UTF8_INPUT_ENABLE
1841     } else if (input_f == UTF8_INPUT) {
1842         set_iconv(-TRUE, w_iconv);
1843     } else if (input_f == UTF16LE_INPUT) {
1844         set_iconv(-TRUE, w_iconv16);
1845 #endif
1846     } else {
1847         set_iconv(FALSE, e_iconv);
1848     }
1849
1850     {
1851         struct input_code *p = input_code_list;
1852         while (p->name){
1853             status_reinit(p++);
1854         }
1855     }
1856 }
1857
1858 /*
1859    Conversion main loop. Code detection only. 
1860  */
1861
1862 int
1863 kanji_convert(f)
1864     FILE  *f;
1865 {
1866     int    c1,
1867                     c2, c3;
1868
1869     module_connection();
1870     c2 = 0;
1871
1872
1873     input_mode = ASCII;
1874     output_mode = ASCII;
1875     shift_mode = FALSE;
1876
1877 #define NEXT continue      /* no output, get next */
1878 #define SEND ;             /* output c1 and c2, get next */
1879 #define LAST break         /* end of loop, go closing  */
1880
1881     while ((c1 = (*i_getc)(f)) != EOF) {
1882         code_status(c1);
1883         if (c2) {
1884             /* second byte */
1885             if (c2 > DEL) {
1886                 /* in case of 8th bit is on */
1887                 if (!estab_f) {
1888                     /* in case of not established yet */
1889                     /* It is still ambiguious */
1890                     if (h_conv(f, c2, c1)==EOF) 
1891                         LAST;
1892                     else 
1893                         c2 = 0;
1894                     NEXT;
1895                 } else
1896                     /* in case of already established */
1897                     if (c1 < AT) {
1898                         /* ignore bogus code */
1899                         c2 = 0;
1900                         NEXT;
1901                     } else
1902                         SEND;
1903             } else
1904                 /* second byte, 7 bit code */
1905                 /* it might be kanji shitfted */
1906                 if ((c1 == DEL) || (c1 <= SPACE)) {
1907                     /* ignore bogus first code */
1908                     c2 = 0;
1909                     NEXT;
1910                 } else
1911                     SEND;
1912         } else {
1913             /* first byte */
1914             if (
1915 #ifdef UTF8_INPUT_ENABLE
1916                 iconv == w_iconv16
1917 #else
1918                 0
1919 #endif
1920                 ) {
1921                 c2 = c1;
1922                 c1 = (*i_getc)(f);
1923                 SEND;
1924 #ifdef NUMCHAR_OPTION
1925             } else if ((c1 & CLASS_MASK) == CLASS_UTF16){
1926                 SEND;
1927 #endif
1928             } else if (c1 > DEL) {
1929                 /* 8 bit code */
1930                 if (!estab_f && !iso8859_f) {
1931                     /* not established yet */
1932                     c2 = c1;
1933                     NEXT;
1934                 } else { /* estab_f==TRUE */
1935                     if (iso8859_f) {
1936                         c2 = ISO8859_1;
1937                         c1 &= 0x7f;
1938                         SEND;
1939                     } else if (SSP<=c1 && c1<0xe0 && iconv == s_iconv) {
1940                         /* SJIS X0201 Case... */
1941                         if(iso2022jp_f && x0201_f==NO_X0201) {
1942                             (*oconv)(GETA1, GETA2);
1943                             NEXT;
1944                         } else {
1945                             c2 = X0201;
1946                             c1 &= 0x7f;
1947                             SEND;
1948                         }
1949                     } else if (c1==SSO && iconv != s_iconv) {
1950                         /* EUC X0201 Case */
1951                         c1 = (*i_getc)(f);  /* skip SSO */
1952                         code_status(c1);
1953                         if (SSP<=c1 && c1<0xe0) {
1954                             if(iso2022jp_f &&  x0201_f==NO_X0201) {
1955                                 (*oconv)(GETA1, GETA2);
1956                                 NEXT;
1957                             } else {
1958                                 c2 = X0201;
1959                                 c1 &= 0x7f;
1960                                 SEND;
1961                             }
1962                         } else  { /* bogus code, skip SSO and one byte */
1963                             NEXT;
1964                         }
1965                     } else {
1966                        /* already established */
1967                        c2 = c1;
1968                        NEXT;
1969                     }
1970                 }
1971             } else if ((c1 > SPACE) && (c1 != DEL)) {
1972                 /* in case of Roman characters */
1973                 if (shift_mode) { 
1974                     /* output 1 shifted byte */
1975                     if (iso8859_f) {
1976                         c2 = ISO8859_1;
1977                         SEND;
1978                     } else if (SPACE<=c1 && c1<(0xe0&0x7f) ){
1979                       /* output 1 shifted byte */
1980                         if(iso2022jp_f && x0201_f==NO_X0201) {
1981                             (*oconv)(GETA1, GETA2);
1982                             NEXT;
1983                         } else {
1984                             c2 = X0201;
1985                             SEND;
1986                         }
1987                     } else {
1988                         /* look like bogus code */
1989                         NEXT;
1990                     }
1991                 } else if (input_mode == X0208) {
1992                     /* in case of Kanji shifted */
1993                     c2 = c1;
1994                     NEXT;
1995                 } else if (c1 == '=' && mime_f && !mime_decode_mode ) {
1996                     /* Check MIME code */
1997                     if ((c1 = (*i_getc)(f)) == EOF) {
1998                         (*oconv)(0, '=');
1999                         LAST;
2000                     } else if (c1 == '?') {
2001                         /* =? is mime conversion start sequence */
2002                         if(mime_f == STRICT_MIME) {
2003                             /* check in real detail */
2004                             if (mime_begin_strict(f) == EOF) 
2005                                 LAST;
2006                             else
2007                                 NEXT;
2008                         } else if (mime_begin(f) == EOF) 
2009                             LAST;
2010                         else
2011                             NEXT;
2012                     } else {
2013                         (*oconv)(0, '=');
2014                         (*i_ungetc)(c1,f);
2015                         NEXT;
2016                     }
2017                 } else {
2018                     /* normal ASCII code */ 
2019                     SEND;
2020                 }
2021             } else if (c1 == SI) {
2022                 shift_mode = FALSE; 
2023                 NEXT;
2024             } else if (c1 == SO) {
2025                 shift_mode = TRUE; 
2026                 NEXT;
2027             } else if (c1 == ESC ) {
2028                 if ((c1 = (*i_getc)(f)) == EOF) {
2029                     /*  (*oconv)(0, ESC); don't send bogus code */
2030                     LAST;
2031                 } else if (c1 == '$') {
2032                     if ((c1 = (*i_getc)(f)) == EOF) {
2033                         /*
2034                         (*oconv)(0, ESC); don't send bogus code 
2035                         (*oconv)(0, '$'); */
2036                         LAST;
2037                     } else if (c1 == '@'|| c1 == 'B') {
2038                         /* This is kanji introduction */
2039                         input_mode = X0208;
2040                         shift_mode = FALSE;
2041                         set_input_codename("ISO-2022-JP");
2042                         debug(input_codename);
2043                         NEXT;
2044                     } else if (c1 == '(') {
2045                         if ((c1 = (*i_getc)(f)) == EOF) {
2046                             /* don't send bogus code 
2047                             (*oconv)(0, ESC);
2048                             (*oconv)(0, '$');
2049                             (*oconv)(0, '(');
2050                                 */
2051                             LAST;
2052                         } else if (c1 == '@'|| c1 == 'B') {
2053                             /* This is kanji introduction */
2054                             input_mode = X0208;
2055                             shift_mode = FALSE;
2056                             NEXT;
2057 #ifdef X0212_ENABLE
2058                         } else if (c1 == 'D'){
2059                             input_mode = X0212;
2060                             shift_mode = FALSE;
2061                             NEXT;
2062 #endif /* X0212_ENABLE */
2063                         } else {
2064                             /* could be some special code */
2065                             (*oconv)(0, ESC);
2066                             (*oconv)(0, '$');
2067                             (*oconv)(0, '(');
2068                             (*oconv)(0, c1);
2069                             NEXT;
2070                         }
2071                     } else if (broken_f&0x2) {
2072                         /* accept any ESC-(-x as broken code ... */
2073                         input_mode = X0208;
2074                         shift_mode = FALSE;
2075                         NEXT;
2076                     } else {
2077                         (*oconv)(0, ESC);
2078                         (*oconv)(0, '$');
2079                         (*oconv)(0, c1);
2080                         NEXT;
2081                     }
2082                 } else if (c1 == '(') {
2083                     if ((c1 = (*i_getc)(f)) == EOF) {
2084                         /* don't send bogus code 
2085                         (*oconv)(0, ESC);
2086                         (*oconv)(0, '('); */
2087                         LAST;
2088                     } else {
2089                         if (c1 == 'I') {
2090                             /* This is X0201 kana introduction */
2091                             input_mode = X0201; shift_mode = X0201;
2092                             NEXT;
2093                         } else if (c1 == 'B' || c1 == 'J' || c1 == 'H') {
2094                             /* This is X0208 kanji introduction */
2095                             input_mode = ASCII; shift_mode = FALSE;
2096                             NEXT;
2097                         } else if (broken_f&0x2) {
2098                             input_mode = ASCII; shift_mode = FALSE;
2099                             NEXT;
2100                         } else {
2101                             (*oconv)(0, ESC);
2102                             (*oconv)(0, '(');
2103                             /* maintain various input_mode here */
2104                             SEND;
2105                         }
2106                     }
2107                } else if ( c1 == 'N' || c1 == 'n' ){
2108                    /* SS2 */
2109                    c3 = (*i_getc)(f);  /* skip SS2 */
2110                    if ( (SPACE<=c3 && c3 < 0x60) || (0xa0<=c3 && c3 < 0xe0)){
2111                        c1 = c3;
2112                        c2 = X0201;
2113                        SEND;
2114                    }else{
2115                        (*i_ungetc)(c3, f);
2116                        /* lonely ESC  */
2117                        (*oconv)(0, ESC);
2118                        SEND;
2119                    }
2120                 } else {
2121                     /* lonely ESC  */
2122                     (*oconv)(0, ESC);
2123                     SEND;
2124                 }
2125             } else if ((c1 == NL || c1 == CR) && broken_f&4) {
2126                 input_mode = ASCII; set_iconv(FALSE, 0);
2127                 SEND;
2128             /*
2129             } else if (c1 == NL && mime_f && !mime_decode_mode ) {
2130                 if ((c1=(*i_getc)(f))!=EOF && c1 == SPACE) {
2131                     i_ungetc(SPACE,f);
2132                     continue;
2133                 } else {
2134                     i_ungetc(c1,f);
2135                 }
2136                 c1 = NL;
2137                 SEND;
2138             } else if (c1 == CR && mime_f && !mime_decode_mode ) {
2139                 if ((c1=(*i_getc)(f))!=EOF) {
2140                     if (c1==SPACE) {
2141                         i_ungetc(SPACE,f);
2142                         continue;
2143                     } else if (c1 == NL && (c1=(*i_getc)(f))!=EOF && c1 == SPACE) {
2144                         i_ungetc(SPACE,f);
2145                         continue;
2146                     } else {
2147                         i_ungetc(c1,f);
2148                     }
2149                     i_ungetc(NL,f);
2150                 } else {
2151                     i_ungetc(c1,f);
2152                 }
2153                 c1 = CR;
2154                 SEND;
2155             */
2156             } else 
2157                 SEND;
2158         }
2159         /* send: */
2160         if (input_mode == X0208) 
2161             (*oconv)(c2, c1);  /* this is JIS, not SJIS/EUC case */
2162 #ifdef X0212_ENABLE
2163         else if (input_mode == X0212) 
2164             (*oconv)((0x8f << 8) | c2, c1);
2165 #endif /* X0212_ENABLE */
2166         else if (input_mode) 
2167             (*oconv)(input_mode, c1);  /* other special case */
2168         else if ((*iconv)(c2, c1, 0) < 0){  /* can be EUC/SJIS */
2169             int c0 = (*i_getc)(f);
2170             if (c0 != EOF){
2171                 code_status(c0);
2172                 (*iconv)(c2, c1, c0);
2173             }
2174         }
2175
2176         c2 = 0;
2177         continue;
2178         /* goto next_word */
2179     }
2180
2181     /* epilogue */
2182     (*iconv)(EOF, 0, 0);
2183     return 1;
2184 }
2185
2186 int
2187 h_conv(f, c2, c1)
2188     FILE  *f;
2189     int    c1,
2190                     c2;
2191 {
2192     int    wc,c3;
2193
2194
2195     /** it must NOT be in the kanji shifte sequence      */
2196     /** it must NOT be written in JIS7                   */
2197     /** and it must be after 2 byte 8bit code            */
2198
2199     hold_count = 0;
2200     push_hold_buf(c2);
2201     push_hold_buf(c1);
2202     c2 = 0;
2203
2204     while ((c1 = (*i_getc)(f)) != EOF) {
2205         if (c1 == ESC){
2206             (*i_ungetc)(c1,f);
2207             break;
2208         }
2209         code_status(c1);
2210         if (push_hold_buf(c1) == EOF || estab_f){
2211             break;
2212         }
2213     }
2214
2215     if (!estab_f){
2216         struct input_code *p = input_code_list;
2217         struct input_code *result = p;
2218         if (c1 == EOF){
2219             code_status(c1);
2220         }
2221         while (p->name){
2222             if (p->score < result->score){
2223                 result = p;
2224             }
2225             ++p;
2226         }
2227         set_iconv(FALSE, result->iconv_func);
2228     }
2229
2230
2231     /** now,
2232      ** 1) EOF is detected, or
2233      ** 2) Code is established, or
2234      ** 3) Buffer is FULL (but last word is pushed)
2235      **
2236      ** in 1) and 3) cases, we continue to use
2237      ** Kanji codes by oconv and leave estab_f unchanged.
2238      **/
2239
2240     c3=c1;
2241     wc = 0;
2242     while (wc < hold_count){
2243         c2 = hold_buf[wc++];
2244         if (c2 <= DEL
2245 #ifdef NUMCHAR_OPTION
2246             || (c2 & CLASS_MASK) == CLASS_UTF16
2247 #endif
2248             ){
2249             (*iconv)(0, c2, 0);
2250             continue;
2251         }else if (iconv == s_iconv && 0xa1 <= c2 && c2 <= 0xdf){
2252             (*iconv)(X0201, c2, 0);
2253             continue;
2254         }
2255         if (wc < hold_count){
2256             c1 = hold_buf[wc++];
2257         }else{
2258             c1 = (*i_getc)(f);
2259             if (c1 == EOF){
2260                 c3 = EOF;
2261                 break;
2262             }
2263             code_status(c1);
2264         }
2265         if ((*iconv)(c2, c1, 0) < 0){
2266             int c0;
2267             if (wc < hold_count){
2268                 c0 = hold_buf[wc++];
2269             }else{
2270                 c0 = (*i_getc)(f);
2271                 if (c0 == EOF){
2272                     c3 = EOF;
2273                     break;
2274                 }
2275                 code_status(c0);
2276             }
2277             (*iconv)(c2, c1, c0);
2278             c1 = c0;
2279         }
2280     }
2281     return c3;
2282 }
2283
2284
2285
2286 int
2287 push_hold_buf(c2)
2288      int             c2;
2289 {
2290     if (hold_count >= HOLD_SIZE*2)
2291         return (EOF);
2292     hold_buf[hold_count++] = c2;
2293     return ((hold_count >= HOLD_SIZE*2) ? EOF : hold_count);
2294 }
2295
2296 int s2e_conv(c2, c1, p2, p1)
2297      int c2, c1;
2298      int *p2, *p1;
2299 {
2300     int val;
2301 #ifdef SHIFTJIS_CP932
2302     if (cp932_f && CP932_TABLE_BEGIN <= c2 && c2 <= CP932_TABLE_END){
2303         extern unsigned short shiftjis_cp932[3][189];
2304         val = shiftjis_cp932[c2 - CP932_TABLE_BEGIN][c1 - 0x40];
2305         if (val){
2306             c2 = val >> 8;
2307             c1 = val & 0xff;
2308         }
2309     }
2310 #endif /* SHIFTJIS_CP932 */
2311 #ifdef X0212_ENABLE
2312     if (x0212_f && 0xfa <= c2 && c2 <= 0xfc){
2313         extern unsigned short shiftjis_x0212[3][189];
2314         val = shiftjis_x0212[c2 - 0xfa][c1 - 0x40];
2315         if (val){
2316             if (val & 0x8000){
2317                 c2 = (0x8f << 8) | (val >> 8);
2318                 c1 = val & 0xff;
2319             }else{
2320                 c2 = val >> 8;
2321                 c1 = val & 0xff;
2322             }
2323             if (p2) *p2 = c2;
2324             if (p1) *p1 = c1;
2325             return 0;
2326         }
2327     }
2328 #endif
2329     c2 = c2 + c2 - ((c2 <= 0x9f) ? SJ0162 : SJ6394);
2330     if (c1 < 0x9f)
2331         c1 = c1 - ((c1 > DEL) ? SPACE : 0x1f);
2332     else {
2333         c1 = c1 - 0x7e;
2334         c2++;
2335     }
2336
2337 #ifdef X0212_ENABLE
2338     if (x0212_f){
2339         c2 = x0212_unshift(c2);
2340     }
2341 #endif
2342     if (p2) *p2 = c2;
2343     if (p1) *p1 = c1;
2344     return 0;
2345 }
2346
2347 int
2348 s_iconv(c2, c1, c0)
2349     int    c2,
2350                     c1, c0;
2351 {
2352     if (c2 == X0201) {
2353         c1 &= 0x7f;
2354     } else if ((c2 == EOF) || (c2 == 0) || c2 < SPACE) {
2355         /* NOP */
2356     } else {
2357         int ret = s2e_conv(c2, c1, &c2, &c1);
2358         if (ret) return ret;
2359     }
2360     (*oconv)(c2, c1);
2361     return 0;
2362 }
2363
2364 int
2365 e_iconv(c2, c1, c0)
2366     int    c2,
2367                     c1, c0;
2368 {
2369     if (c2 == X0201) {
2370         c1 &= 0x7f;
2371 #ifdef X0212_ENABLE
2372     }else if (c2 == 0x8f){
2373         if (c0 == 0){
2374             return -1;
2375         }
2376         c2 = (c2 << 8) | (c1 & 0x7f);
2377         c1 = c0 & 0x7f;
2378 #ifdef SHIFTJIS_CP932
2379         if (cp932_f){
2380             int s2, s1;
2381             if (e2s_conv(c2, c1, &s2, &s1) == 0){
2382                 s2e_conv(s2, s1, &c2, &c1);
2383                 if ((c2 & 0xff00) == 0){
2384                     c1 &= 0x7f;
2385                     c2 &= 0x7f;
2386                 }
2387             }
2388         }
2389 #endif /* SHIFTJIS_CP932 */
2390 #endif /* X0212_ENABLE */
2391     } else if (c2 == SSO){
2392         c2 = X0201;
2393         c1 &= 0x7f;
2394     } else if ((c2 == EOF) || (c2 == 0) || c2 < SPACE) {
2395         /* NOP */
2396     } else {
2397         c1 &= 0x7f;
2398         c2 &= 0x7f;
2399     }
2400     (*oconv)(c2, c1);
2401     return 0;
2402 }
2403
2404 #ifdef UTF8_INPUT_ENABLE
2405 int
2406 w2e_conv(c2, c1, c0, p2, p1)
2407     int    c2, c1, c0;
2408     int *p2, *p1;
2409 {
2410     extern unsigned short * utf8_to_euc_2bytes[];
2411     extern unsigned short ** utf8_to_euc_3bytes[];
2412     int ret = 0;
2413
2414     if (0xc0 <= c2 && c2 <= 0xef) {
2415         unsigned short **pp;
2416
2417         if (0xe0 <= c2) {
2418             if (c0 == 0) return -1;
2419             pp = utf8_to_euc_3bytes[c2 - 0x80];
2420             ret = w_iconv_common(c1, c0, pp, sizeof_utf8_to_euc_C2, p2, p1);
2421         } else {
2422             ret =  w_iconv_common(c2, c1, utf8_to_euc_2bytes, sizeof_utf8_to_euc_2bytes, p2, p1);
2423         }
2424 #ifdef NUMCHAR_OPTION
2425         if (ret){
2426             if (p2) *p2 = 0;
2427             if (p1) *p1 = CLASS_UTF16 | ww16_conv(c2, c1, c0);
2428             ret = 0;
2429         }
2430 #endif
2431         return ret;
2432     } else if (c2 == X0201) {
2433         c1 &= 0x7f;
2434     }
2435     if (p2) *p2 = c2;
2436     if (p1) *p1 = c1;
2437     return ret;
2438 }
2439
2440 int
2441 w_iconv(c2, c1, c0)
2442     int    c2,
2443                     c1, c0;
2444 {
2445     int ret = w2e_conv(c2, c1, c0, &c2, &c1);
2446     if (ret == 0){
2447         (*oconv)(c2, c1);
2448     }
2449     return ret;
2450 }
2451
2452 void
2453 w16w_conv(val, p2, p1, p0)
2454      unsigned short val;
2455      int *p2, *p1, *p0;
2456 {
2457     if (val < 0x80){
2458         *p2 = val;
2459         *p1 = 0;
2460         *p0 = 0;
2461     }else if (val < 0x800){
2462         *p2 = 0xc0 | (val >> 6);
2463         *p1 = 0x80 | (val & 0x3f);
2464         *p0 = 0;
2465     }else{
2466         *p2 = 0xe0 | (val >> 12);
2467         *p1 = 0x80 | ((val >> 6) & 0x3f);
2468         *p0 = 0x80 | (val        & 0x3f);
2469     }
2470 }
2471
2472 int
2473 ww16_conv(c2, c1, c0)
2474      int c2, c1, c0;
2475 {
2476     unsigned short val;
2477     if (c2 >= 0xe0){
2478         val = (c2 & 0x0f) << 12;
2479         val |= (c1 & 0x3f) << 6;
2480         val |= (c0 & 0x3f);
2481     }else if (c2 >= 0xc0){
2482         val = (c2 & 0x1f) << 6;
2483         val |= (c1 & 0x3f);
2484     }else{
2485         val = c2;
2486     }
2487     return val;
2488 }
2489
2490 int
2491 w16e_conv(val, p2, p1)
2492      unsigned short val;
2493      int *p2, *p1;
2494 {
2495     extern unsigned short * utf8_to_euc_2bytes[];
2496     extern unsigned short ** utf8_to_euc_3bytes[];
2497     int c2, c1, c0;
2498     unsigned short **pp;
2499     int psize;
2500     int ret = 0;
2501
2502     w16w_conv(val, &c2, &c1, &c0);
2503     if (c1){
2504         if (c0){
2505             pp = utf8_to_euc_3bytes[c2 - 0x80];
2506             psize = sizeof_utf8_to_euc_C2;
2507             ret =  w_iconv_common(c1, c0, pp, psize, p2, p1);
2508         }else{
2509             pp = utf8_to_euc_2bytes;
2510             psize = sizeof_utf8_to_euc_2bytes;
2511             ret =  w_iconv_common(c2, c1, pp, psize, p2, p1);
2512         }
2513 #ifdef NUMCHAR_OPTION
2514         if (ret){
2515             *p2 = 0;
2516             *p1 = CLASS_UTF16 | val;
2517             ret = 0;
2518         }
2519 #endif
2520     }else{
2521         *p2 = 0;
2522         *p1 = c2;
2523     }
2524     return ret;
2525 }
2526
2527 int
2528 w_iconv16(c2, c1, c0)
2529     int    c2, c1,c0;
2530 {
2531     int ret;
2532
2533     if (c2==0376 && c1==0377){
2534         utf16_mode = UTF16LE_INPUT;
2535         return 0;    
2536     } else if (c2==0377 && c1==0376){
2537         utf16_mode = UTF16BE_INPUT;
2538         return 0;    
2539     }
2540     if (c2 != EOF && utf16_mode == UTF16BE_INPUT) {
2541         int tmp;
2542         tmp=c1; c1=c2; c2=tmp;
2543     }
2544     if ((c2==0 && c1 < 0x80) || c2==EOF) {
2545         (*oconv)(c2, c1);
2546         return 0;
2547     }
2548     ret = w16e_conv(((c2<<8)&0xff00) + c1, &c2, &c1);
2549     if (ret) return ret;
2550     (*oconv)(c2, c1);
2551     return 0;
2552 }
2553
2554 int
2555 w_iconv_common(c1, c0, pp, psize, p2, p1)
2556     int    c1,c0;
2557     unsigned short **pp;
2558     int psize;
2559     int *p2, *p1;
2560 {
2561     int c2;
2562     unsigned short *p ;
2563     unsigned short val;
2564
2565     if (pp == 0) return 1;
2566
2567     c1 -= 0x80;
2568     if (c1 < 0 || psize <= c1) return 1;
2569     p = pp[c1];
2570     if (p == 0)  return 1;
2571
2572     c0 -= 0x80;
2573     if (c0 < 0 || sizeof_utf8_to_euc_E5B8 <= c0) return 1;
2574     val = p[c0];
2575     if (val == 0) return 1;
2576
2577     c2 = val >> 8;
2578     if (val & 0x8000){
2579         c2 &= 0x7f;
2580         c2 |= 0x8f00;
2581     }
2582     if (c2 == SO) c2 = X0201;
2583     c1 = val & 0x7f;
2584     if (p2) *p2 = c2;
2585     if (p1) *p1 = c1;
2586     return 0;
2587 }
2588
2589 #endif
2590
2591 #ifdef UTF8_OUTPUT_ENABLE
2592 int
2593 e2w_conv(c2, c1)
2594     int    c2, c1;
2595 {
2596     extern unsigned short euc_to_utf8_1byte[];
2597     extern unsigned short * euc_to_utf8_2bytes[];
2598     extern unsigned short * euc_to_utf8_2bytes_ms[];
2599     unsigned short *p;
2600
2601     if (c2 == X0201) {
2602         p = euc_to_utf8_1byte;
2603 #ifdef X0212_ENABLE
2604     } else if (c2 >> 8 == 0x8f){
2605         extern unsigned short * x0212_to_utf8_2bytes[];
2606         c2 = (c2&0x7f) - 0x21;
2607         if (0<=c2 && c2<sizeof_euc_to_utf8_2bytes)
2608             p = x0212_to_utf8_2bytes[c2];
2609         else
2610             return 0;
2611 #endif
2612     } else {
2613         c2 &= 0x7f;
2614         c2 = (c2&0x7f) - 0x21;
2615         if (0<=c2 && c2<sizeof_euc_to_utf8_2bytes)
2616             p = ms_ucs_map_f ? euc_to_utf8_2bytes_ms[c2] : euc_to_utf8_2bytes[c2];
2617         else
2618             return 0;
2619     }
2620     if (!p) return 0;
2621     c1 = (c1 & 0x7f) - 0x21;
2622     if (0<=c1 && c1<sizeof_euc_to_utf8_1byte)
2623         return p[c1];
2624     return 0;
2625 }
2626
2627 void
2628 w_oconv(c2, c1)
2629     int    c2,
2630                     c1;
2631 {
2632     int c0;
2633     if (c2 == EOF) {
2634         (*o_putc)(EOF);
2635         return;
2636     }
2637
2638     if (unicode_bom_f==2) {
2639         (*o_putc)('\357');
2640         (*o_putc)('\273');
2641         (*o_putc)('\277');
2642         unicode_bom_f=1;
2643     }
2644
2645 #ifdef NUMCHAR_OPTION
2646     if (c2 == 0 && (c1 & CLASS_MASK) == CLASS_UTF16){
2647         w16w_conv(c1, &c2, &c1, &c0);
2648         (*o_putc)(c2);
2649         if (c1){
2650             (*o_putc)(c1);
2651             if (c0) (*o_putc)(c0);
2652         }
2653         return;
2654     }
2655 #endif
2656
2657     if (c2 == 0) { 
2658         output_mode = ASCII;
2659         (*o_putc)(c1);
2660     } else if (c2 == ISO8859_1) {
2661         output_mode = ISO8859_1;
2662         (*o_putc)(c1 | 0x080);
2663     } else {
2664         unsigned short val;
2665         output_mode = UTF8;
2666         val = e2w_conv(c2, c1);
2667         if (val){
2668             w16w_conv(val, &c2, &c1, &c0);
2669             (*o_putc)(c2);
2670             if (c1){
2671                 (*o_putc)(c1);
2672                 if (c0) (*o_putc)(c0);
2673             }
2674         }
2675     }
2676 }
2677
2678 void
2679 w_oconv16(c2, c1)
2680     int    c2,
2681                     c1;
2682 {
2683     if (c2 == EOF) {
2684         (*o_putc)(EOF);
2685         return;
2686     }    
2687
2688     if (unicode_bom_f==2) {
2689         if (w_oconv16_LE){
2690             (*o_putc)((unsigned char)'\377');
2691             (*o_putc)('\376');
2692         }else{
2693             (*o_putc)('\376');
2694             (*o_putc)((unsigned char)'\377');
2695         }
2696         unicode_bom_f=1;
2697     }
2698
2699     if (c2 == ISO8859_1) {
2700         c2 = 0;
2701         c1 |= 0x80;
2702 #ifdef NUMCHAR_OPTION
2703     } else if (c2 == 0 && (c1 & CLASS_MASK) == CLASS_UTF16) {
2704         c2 = (c1 >> 8) & 0xff;
2705         c1 &= 0xff;
2706 #endif
2707     } else if (c2) {
2708         unsigned short val = e2w_conv(c2, c1);
2709         c2 = (val >> 8) & 0xff;
2710         c1 = val & 0xff;
2711     }
2712     if (w_oconv16_LE){
2713         (*o_putc)(c1);
2714         (*o_putc)(c2);
2715     }else{
2716         (*o_putc)(c2);
2717         (*o_putc)(c1);
2718     }
2719 }
2720
2721 #endif
2722
2723 void
2724 e_oconv(c2, c1)
2725     int    c2,
2726                     c1;
2727 {
2728 #ifdef NUMCHAR_OPTION
2729     if (c2 == 0 && (c1 & CLASS_MASK) == CLASS_UTF16){
2730         w16e_conv(c1, &c2, &c1);
2731         if (c2 == 0 && (c1 & CLASS_MASK) == CLASS_UTF16){
2732             return;
2733         }
2734     }
2735 #endif
2736     if (c2 == EOF) {
2737         (*o_putc)(EOF);
2738         return;
2739     } else if (c2 == 0) { 
2740         output_mode = ASCII;
2741         (*o_putc)(c1);
2742     } else if (c2 == X0201) {
2743         output_mode = JAPANESE_EUC;
2744         (*o_putc)(SSO); (*o_putc)(c1|0x80);
2745     } else if (c2 == ISO8859_1) {
2746         output_mode = ISO8859_1;
2747         (*o_putc)(c1 | 0x080);
2748 #ifdef X0212_ENABLE
2749     } else if ((c2 & 0xff00) >> 8 == 0x8f){
2750         output_mode = JAPANESE_EUC;
2751 #ifdef SHIFTJIS_CP932
2752         if (cp932_f){
2753             int s2, s1;
2754             if (e2s_conv(c2, c1, &s2, &s1) == 0){
2755                 s2e_conv(s2, s1, &c2, &c1);
2756             }
2757         }
2758 #endif
2759         if ((c2 & 0xff00) >> 8 == 0x8f){
2760             if (x0212_f){
2761                 (*o_putc)(0x8f);
2762                 (*o_putc)((c2 & 0x7f) | 0x080);
2763                 (*o_putc)(c1 | 0x080);
2764             }
2765         }else{
2766             (*o_putc)((c2 & 0x7f) | 0x080);
2767             (*o_putc)(c1 | 0x080);
2768         }
2769 #endif
2770     } else {
2771         if ((c1<0x21 || 0x7e<c1) ||
2772            (c2<0x21 || 0x7e<c2)) {
2773             set_iconv(FALSE, 0);
2774             return; /* too late to rescue this char */
2775         }
2776         output_mode = JAPANESE_EUC;
2777         (*o_putc)(c2 | 0x080);
2778         (*o_putc)(c1 | 0x080);
2779     }
2780 }
2781
2782 #ifdef X0212_ENABLE
2783 int x0212_shift(c)
2784      int c;
2785 {
2786     int ret = c;
2787     c &= 0x7f;
2788     if ((ret & 0xff00) == 0x8f00){
2789         if (0x75 <= c && c <= 0x7f){
2790             ret = c + (0x109 - 0x75);
2791         }
2792     }else{
2793         if (0x75 <= c && c <= 0x7f){
2794             ret = c + (0x113 - 0x75);
2795         }
2796     }
2797     return ret;
2798 }
2799
2800
2801 int x0212_unshift(c)
2802      int c;
2803 {
2804     int ret = c;
2805     if (0x7f <= c && c <= 0x88){
2806         ret = c + (0x75 - 0x7f);
2807     }else if (0x89 <= c && c <= 0x92){
2808         ret = (0x8f << 8) | 0x80 | (c + (0x75 - 0x89));
2809     }
2810     return ret;
2811 }
2812 #endif /* X0212_ENABLE */
2813
2814 int
2815 e2s_conv(c2, c1, p2, p1)
2816      int c2, c1, *p2, *p1;
2817 {
2818     int val = 0;
2819     unsigned short *ptr;
2820     int ndx;
2821     extern unsigned short *x0212_shiftjis[];
2822 #ifdef X0212_ENABLE
2823     if ((c2 & 0xff00) == 0x8f00){
2824         ndx = c2 & 0x7f;
2825         if (0x21 <= ndx && ndx <= 0x7e){
2826             ptr = x0212_shiftjis[ndx - 0x21];
2827             if (ptr){
2828                 val = ptr[(c1 & 0x7f) - 0x21];
2829             }
2830             if (val){
2831                 c2 = val >> 8;
2832                 c1 = val & 0xff;
2833                 if (p2) *p2 = c2;
2834                 if (p1) *p1 = c1;
2835                 return 0;
2836             }
2837         }
2838         c2 = x0212_shift(c2);
2839     }
2840 #endif /* X0212_ENABLE */
2841     if ((c2 & 0xff00) == 0x8f00){
2842         return 1;
2843     }
2844     if (p2) *p2 = ((c2 - 1) >> 1) + ((c2 <= 0x5e) ? 0x71 : 0xb1);
2845     if (p1) *p1 = c1 + ((c2 & 1) ? ((c1 < 0x60) ? 0x1f : 0x20) : 0x7e);
2846     return 0;
2847 }
2848
2849 void
2850 s_oconv(c2, c1)
2851     int    c2,
2852                     c1;
2853 {
2854 #ifdef NUMCHAR_OPTION
2855     if (c2 == 0 && (c1 & CLASS_MASK) == CLASS_UTF16){
2856         w16e_conv(c1, &c2, &c1);
2857     }
2858 #endif
2859     if (c2 == EOF) {
2860         (*o_putc)(EOF);
2861         return;
2862     } else if (c2 == 0) {
2863         output_mode = ASCII;
2864         (*o_putc)(c1);
2865     } else if (c2 == X0201) {
2866         output_mode = SHIFT_JIS;
2867         (*o_putc)(c1|0x80);
2868     } else if (c2 == ISO8859_1) {
2869         output_mode = ISO8859_1;
2870         (*o_putc)(c1 | 0x080);
2871 #ifdef X0212_ENABLE
2872     } else if ((c2 & 0xff00) >> 8 == 0x8f){
2873         output_mode = SHIFT_JIS;
2874         if (e2s_conv(c2, c1, &c2, &c1) == 0){
2875             (*o_putc)(c2);
2876             (*o_putc)(c1);
2877         }
2878 #endif
2879     } else {
2880         if ((c1<0x20 || 0x7e<c1) ||
2881            (c2<0x20 || 0x7e<c2)) {
2882             set_iconv(FALSE, 0);
2883             return; /* too late to rescue this char */
2884         }
2885         output_mode = SHIFT_JIS;
2886         e2s_conv(c2, c1, &c2, &c1);
2887
2888 #ifdef SHIFTJIS_CP932
2889         if (cp932inv_f
2890             && CP932INV_TABLE_BEGIN <= c2 && c2 <= CP932INV_TABLE_END){
2891             extern unsigned short cp932inv[2][189];
2892             int c = cp932inv[c2 - CP932INV_TABLE_BEGIN][c1 - 0x40];
2893             if (c){
2894                 c2 = c >> 8;
2895                 c1 = c & 0xff;
2896             }
2897         }
2898 #endif /* SHIFTJIS_CP932 */
2899
2900         (*o_putc)(c2);
2901         if (prefix_table[(unsigned char)c1]){
2902             (*o_putc)(prefix_table[(unsigned char)c1]);
2903         }
2904         (*o_putc)(c1);
2905     }
2906 }
2907
2908 void
2909 j_oconv(c2, c1)
2910     int    c2,
2911                     c1;
2912 {
2913 #ifdef NUMCHAR_OPTION
2914     if ((c1 & CLASS_MASK) == CLASS_UTF16){
2915         w16e_conv(c1, &c2, &c1);
2916     }
2917 #endif
2918     if (c2 == EOF) {
2919         if (output_mode !=ASCII && output_mode!=ISO8859_1) {
2920             (*o_putc)(ESC);
2921             (*o_putc)('(');
2922             (*o_putc)(ascii_intro);
2923             output_mode = ASCII;
2924         }
2925         (*o_putc)(EOF);
2926 #ifdef X0212_ENABLE
2927     } else if ((c2 & 0xff00) >> 8 == 0x8f){
2928         if (output_mode!=X0212) {
2929             output_mode = X0212;
2930             (*o_putc)(ESC);
2931             (*o_putc)('$');
2932             (*o_putc)('(');
2933             (*o_putc)('D');
2934         }
2935         (*o_putc)(c2 & 0x7f);
2936         (*o_putc)(c1);
2937 #endif
2938     } else if (c2==X0201) {
2939         if (output_mode!=X0201) {
2940             output_mode = X0201;
2941             (*o_putc)(ESC);
2942             (*o_putc)('(');
2943             (*o_putc)('I');
2944         }
2945         (*o_putc)(c1);
2946     } else if (c2==ISO8859_1) {
2947             /* iso8859 introduction, or 8th bit on */
2948             /* Can we convert in 7bit form using ESC-'-'-A ? 
2949                Is this popular? */
2950         output_mode = ISO8859_1;
2951         (*o_putc)(c1|0x80);
2952     } else if (c2 == 0) {
2953         if (output_mode !=ASCII && output_mode!=ISO8859_1) {
2954             (*o_putc)(ESC);
2955             (*o_putc)('(');
2956             (*o_putc)(ascii_intro);
2957             output_mode = ASCII;
2958         }
2959         (*o_putc)(c1);
2960     } else {
2961         if (output_mode != X0208) {
2962             output_mode = X0208;
2963             (*o_putc)(ESC);
2964             (*o_putc)('$');
2965             (*o_putc)(kanji_intro);
2966         }
2967         if (c1<0x20 || 0x7e<c1) 
2968             return;
2969         if (c2<0x20 || 0x7e<c2) 
2970             return;
2971         (*o_putc)(c2);
2972         (*o_putc)(c1);
2973     }
2974 }
2975
2976 void
2977 base64_conv(c2, c1)
2978     int    c2,
2979                     c1;
2980 {
2981     if (base64_count>50 && !mimeout_mode && c2==0 && c1==SPACE) {
2982         (*o_putc)(EOF);
2983         (*o_putc)(NL);
2984     } else if (base64_count>66 && mimeout_mode) {
2985         (*o_base64conv)(EOF,0);
2986         (*o_base64conv)(NL,0);
2987         (*o_base64conv)(SPACE,0);
2988     }
2989     (*o_base64conv)(c2,c1);
2990 }
2991
2992
2993 static int broken_buf[3];
2994 static int broken_counter = 0;
2995 static int broken_last = 0;
2996 int
2997 broken_getc(f)
2998 FILE *f;
2999 {
3000     int c,c1;
3001
3002     if (broken_counter>0) {
3003         return broken_buf[--broken_counter];
3004     }
3005     c= (*i_bgetc)(f);
3006     if (c=='$' && broken_last != ESC 
3007             && (input_mode==ASCII || input_mode==X0201)) {
3008         c1= (*i_bgetc)(f);
3009         broken_last = 0;
3010         if (c1=='@'|| c1=='B') {
3011             broken_buf[0]=c1; broken_buf[1]=c; 
3012             broken_counter=2;
3013             return ESC;
3014         } else {
3015             (*i_bungetc)(c1,f);
3016             return c;
3017         }
3018     } else if (c=='(' && broken_last != ESC 
3019             && (input_mode==X0208 || input_mode==X0201)) { /* ) */
3020         c1= (*i_bgetc)(f);
3021         broken_last = 0;
3022         if (c1=='J'|| c1=='B') {
3023             broken_buf[0]=c1; broken_buf[1]=c;
3024             broken_counter=2;
3025             return ESC;
3026         } else {
3027             (*i_bungetc)(c1,f);
3028             return c;
3029         }
3030     } else {
3031         broken_last = c;
3032         return c;
3033     }
3034 }
3035
3036 int
3037 broken_ungetc(c,f)
3038 int c;
3039 FILE *f;
3040 {
3041     if (broken_counter<2)
3042         broken_buf[broken_counter++]=c;
3043     return c;
3044 }
3045
3046 static int prev_cr = 0;
3047
3048 void
3049 cr_conv(c2,c1) 
3050 int c2,c1;
3051 {
3052     if (prev_cr) {
3053         prev_cr = 0;
3054         if (! (c2==0&&c1==NL) ) {
3055             cr_conv(0,'\n');
3056         }
3057     }
3058     if (c2) {
3059         (*o_crconv)(c2,c1);
3060     } else if (c1=='\r') {
3061         prev_cr = c1;
3062     } else if (c1=='\n') {
3063         if (crmode_f==CRLF) {
3064             (*o_crconv)(0,'\r');
3065         } else if (crmode_f==CR) {
3066             (*o_crconv)(0,'\r');
3067             return;
3068         } 
3069         (*o_crconv)(0,NL);
3070     } else if (c1!='\032' || crmode_f!=NL){
3071         (*o_crconv)(c2,c1);
3072     }
3073 }
3074
3075 /* 
3076   Return value of fold_conv()
3077
3078        \n  add newline  and output char
3079        \r  add newline  and output nothing
3080        ' ' space
3081        0   skip  
3082        1   (or else) normal output 
3083
3084   fold state in prev (previous character)
3085
3086       >0x80 Japanese (X0208/X0201)
3087       <0x80 ASCII
3088       \n    new line 
3089       ' '   space
3090
3091   This fold algorthm does not preserve heading space in a line.
3092   This is the main difference from fmt.
3093 */
3094
3095 #define char_size(c2,c1) (c2?2:1)
3096
3097 void
3098 fold_conv(c2,c1) 
3099 int c2,c1;
3100
3101     int prev0;
3102     int fold_state=0;
3103
3104     if (c1== '\r' && !fold_preserve_f) {
3105         fold_state=0;  /* ignore cr */
3106     }else if (c1== '\n'&&f_prev=='\r' && fold_preserve_f) {
3107         f_prev = '\n';
3108         fold_state=0;  /* ignore cr */
3109     } else if (c1== BS) {
3110         if (f_line>0) f_line--;
3111         fold_state =  1;
3112     } else if (c2==EOF && f_line != 0) {    /* close open last line */
3113             fold_state = '\n';
3114     } else if ((c1=='\n' && !fold_preserve_f)
3115                || ((c1=='\r'||(c1=='\n'&&f_prev!='\r'))
3116                    && fold_preserve_f)) {
3117         /* new line */
3118         if (fold_preserve_f) { 
3119             f_prev = c1;
3120             f_line = 0;
3121             fold_state =  '\r';
3122         } else if ((f_prev == c1 && !fold_preserve_f)
3123                    || (f_prev == '\n' && fold_preserve_f)
3124                    ) {        /* duplicate newline */
3125             if (f_line) {
3126                 f_line = 0;
3127                 fold_state =  '\n';    /* output two newline */
3128             } else {
3129                 f_line = 0;
3130                 fold_state =  1;
3131             }
3132         } else  {
3133             if (f_prev&0x80) {     /* Japanese? */
3134                 f_prev = c1;
3135                 fold_state =  0;       /* ignore given single newline */
3136             } else if (f_prev==' ') {
3137                 fold_state =  0;
3138             } else {
3139                 f_prev = c1;
3140                 if (++f_line<=fold_len) 
3141                     fold_state =  ' ';
3142                 else {
3143                     f_line = 0;
3144                     fold_state =  '\r';        /* fold and output nothing */
3145                 }
3146             }
3147         }
3148     } else if (c1=='\f') {
3149         f_prev = '\n';
3150         if (f_line==0)
3151             fold_state =  1;
3152         f_line = 0;
3153         fold_state =  '\n';            /* output newline and clear */
3154     } else if ( (c2==0  && c1==' ')||
3155                (c2==0  && c1=='\t')||
3156                (c2=='!'&& c1=='!')) {
3157         /* X0208 kankaku or ascii space */
3158             if (f_prev == ' ') {
3159                 fold_state = 0;         /* remove duplicate spaces */
3160             } else {
3161                 f_prev = ' ';    
3162                 if (++f_line<=fold_len) 
3163                     fold_state = ' ';         /* output ASCII space only */
3164                 else {
3165                     f_prev = ' '; f_line = 0;
3166                     fold_state = '\r';        /* fold and output nothing */
3167                 }
3168             }
3169     } else {
3170         prev0 = f_prev; /* we still need this one... , but almost done */
3171         f_prev = c1;
3172         if (c2 || c2==X0201) 
3173             f_prev |= 0x80;  /* this is Japanese */
3174         f_line += char_size(c2,c1);
3175         if (f_line<=fold_len) {   /* normal case */
3176             fold_state = 1;
3177         } else {
3178             if (f_line>=fold_len+fold_margin) { /* too many kinsou suspension */
3179                 f_line = char_size(c2,c1);
3180                 fold_state =  '\n';       /* We can't wait, do fold now */
3181             } else if (c2==X0201) {
3182             /* simple kinsoku rules  return 1 means no folding  */
3183                 if (c1==(0xde&0x7f)) fold_state = 1; /* \e$B!+\e(B*/
3184                 else if (c1==(0xdf&0x7f)) fold_state = 1; /* \e$B!,\e(B*/
3185                 else if (c1==(0xa4&0x7f)) fold_state = 1; /* \e$B!#\e(B*/
3186                 else if (c1==(0xa3&0x7f)) fold_state = 1; /* \e$B!$\e(B*/
3187                 else if (c1==(0xa1&0x7f)) fold_state = 1; /* \e$B!W\e(B*/
3188                 else if (c1==(0xb0&0x7f)) fold_state = 1; /* - */
3189                 else if (SPACE<=c1 && c1<=(0xdf&0x7f)) {      /* X0201 */
3190                     f_line = 1;
3191                     fold_state = '\n';/* add one new f_line before this character */
3192                 } else {
3193                     f_line = 1;
3194                     fold_state = '\n';/* add one new f_line before this character */
3195                 }
3196             } else if (c2==0) {
3197                 /* kinsoku point in ASCII */ 
3198                 if (  c1==')'||    /* { [ ( */
3199                      c1==']'||
3200                      c1=='}'||
3201                      c1=='.'||
3202                      c1==','||
3203                      c1=='!'||
3204                      c1=='?'||
3205                      c1=='/'||
3206                      c1==':'||
3207                      c1==';' ) {
3208                     fold_state = 1;
3209                 /* just after special */
3210                 } else if (!is_alnum(prev0)) {
3211                     f_line = char_size(c2,c1);
3212                     fold_state = '\n';
3213                 } else if ((prev0==' ') ||   /* ignored new f_line */
3214                       (prev0=='\n')||        /* ignored new f_line */
3215                       (prev0&0x80)) {        /* X0208 - ASCII */
3216                     f_line = char_size(c2,c1);
3217                     fold_state = '\n';/* add one new f_line before this character */
3218                 } else {
3219                     fold_state = 1;  /* default no fold in ASCII */
3220                 }
3221             } else {
3222                 if (c2=='!') {
3223                     if (c1=='"')  fold_state = 1; /* \e$B!"\e(B */
3224                     else if (c1=='#')  fold_state = 1; /* \e$B!#\e(B */
3225                     else if (c1=='W')  fold_state = 1; /* \e$B!W\e(B */
3226                     else if (c1=='K')  fold_state = 1; /* \e$B!K\e(B */
3227                     else if (c1=='$')  fold_state = 1; /* \e$B!$\e(B */
3228                     else if (c1=='%')  fold_state = 1; /* \e$B!%\e(B */
3229                     else if (c1=='\'') fold_state = 1; /* \e$B!\\e(B */
3230                     else if (c1=='(')  fold_state = 1; /* \e$B!(\e(B */
3231                     else if (c1==')')  fold_state = 1; /* \e$B!)\e(B */
3232                     else if (c1=='*')  fold_state = 1; /* \e$B!*\e(B */
3233                     else if (c1=='+')  fold_state = 1; /* \e$B!+\e(B */
3234                     else if (c1==',')  fold_state = 1; /* \e$B!,\e(B */
3235                          /* default no fold in kinsoku */
3236                     else { 
3237                         fold_state = '\n';
3238                         f_line = char_size(c2,c1);
3239                         /* add one new f_line before this character */
3240                     }
3241                 } else {
3242                     f_line = char_size(c2,c1);
3243                     fold_state = '\n'; 
3244                     /* add one new f_line before this character */
3245                 }
3246             }
3247         }
3248     }
3249     /* terminator process */
3250     switch(fold_state) {
3251         case '\n': 
3252             (*o_fconv)(0,'\n');
3253             (*o_fconv)(c2,c1);
3254             break;
3255         case 0:    
3256             return;
3257         case '\r': 
3258             (*o_fconv)(0,'\n');
3259             break;
3260         case '\t': 
3261         case ' ': 
3262             (*o_fconv)(0,' ');
3263             break;
3264         default:
3265             (*o_fconv)(c2,c1);
3266     }
3267 }
3268
3269 int z_prev2=0,z_prev1=0;
3270
3271 void
3272 z_conv(c2,c1)
3273 int c2,c1;
3274 {
3275
3276     /* if (c2) c1 &= 0x7f; assertion */
3277
3278     if (x0201_f && z_prev2==X0201) {  /* X0201 */
3279         if (c1==(0xde&0x7f)) { /* \e$BByE@\e(B */
3280             z_prev2=0;
3281             (*o_zconv)(dv[(z_prev1-SPACE)*2],dv[(z_prev1-SPACE)*2+1]);
3282             return;
3283         } else if (c1==(0xdf&0x7f)&&ev[(z_prev1-SPACE)*2]) {  /* \e$BH>ByE@\e(B */
3284             z_prev2=0;
3285             (*o_zconv)(ev[(z_prev1-SPACE)*2],ev[(z_prev1-SPACE)*2+1]);
3286             return;
3287         } else {
3288             z_prev2=0;
3289             (*o_zconv)(cv[(z_prev1-SPACE)*2],cv[(z_prev1-SPACE)*2+1]);
3290         }
3291     }
3292
3293     if (c2==EOF) {
3294         (*o_zconv)(c2,c1);
3295         return;
3296     }
3297
3298     if (x0201_f && c2==X0201) {
3299         if (dv[(c1-SPACE)*2]||ev[(c1-SPACE)*2]) {
3300             /* wait for \e$BByE@\e(B or \e$BH>ByE@\e(B */
3301             z_prev1 = c1; z_prev2 = c2;
3302             return;
3303         } else {
3304             (*o_zconv)(cv[(c1-SPACE)*2],cv[(c1-SPACE)*2+1]);
3305             return;
3306         }
3307     }
3308
3309     /* JISX0208 Alphabet */
3310     if (alpha_f && c2 == 0x23 ) {
3311         c2 = 0;
3312     } else if (alpha_f && c2 == 0x21 ) { 
3313     /* JISX0208 Kigou */
3314        if (0x21==c1) {
3315            if (alpha_f&0x2) {
3316                c1 = ' ';
3317                c2 = 0;
3318            } else if (alpha_f&0x4) {
3319                 (*o_zconv)(0,' ');
3320                 (*o_zconv)(0,' ');
3321                 return;
3322            } 
3323        } else if (0x20<c1 && c1<0x7f && fv[c1-0x20]) {
3324            c1 = fv[c1-0x20];
3325            c2 =  0;
3326            if (alpha_f&0x8) {
3327                char *entity = 0;
3328                switch (c1){
3329                  case '>': entity = "&gt;"; break;
3330                  case '<': entity = "&lt;"; break;
3331                  case '\"': entity = "&quot;"; break;
3332                  case '&': entity = "&amp;"; break;
3333                }
3334                if (entity){
3335                    while (*entity) (*o_zconv)(0, *entity++);
3336                    return;
3337                }
3338            }
3339        } 
3340     }
3341     (*o_zconv)(c2,c1);
3342 }
3343
3344
3345 #define rot13(c)  ( \
3346       ( c < 'A' ) ? c: \
3347       (c <= 'M')  ? (c + 13): \
3348       (c <= 'Z')  ? (c - 13): \
3349       (c < 'a')   ? (c): \
3350       (c <= 'm')  ? (c + 13): \
3351       (c <= 'z')  ? (c - 13): \
3352       (c) \
3353 )
3354
3355 #define  rot47(c) ( \
3356       ( c < '!' ) ? c: \
3357       ( c <= 'O' ) ? (c + 47) : \
3358       ( c <= '~' ) ?  (c - 47) : \
3359       c \
3360 )
3361
3362 void
3363 rot_conv(c2,c1)
3364 int c2,c1;
3365 {
3366     if (c2==0 || c2==X0201 || c2==ISO8859_1) {
3367         c1 = rot13(c1);
3368     } else if (c2) {
3369         c1 = rot47(c1);
3370         c2 = rot47(c2);
3371     }
3372     (*o_rot_conv)(c2,c1);
3373 }
3374
3375 void
3376 hira_conv(c2,c1)
3377 int c2,c1;
3378 {
3379     if ((hira_f & 1) && c2==0x25 && 0x20<c1 && c1<0x74) {
3380         c2 = 0x24;
3381     } else if ((hira_f & 2) && c2==0x24 && 0x20<c1 && c1<0x74) {
3382         c2 = 0x25;
3383     } 
3384     (*o_hira_conv)(c2,c1);
3385 }
3386
3387
3388 void
3389 iso2022jp_check_conv(c2,c1)
3390 int    c2, c1;
3391 {
3392     static int range[RANGE_NUM_MAX][2] = {
3393         {0x222f, 0x2239,},
3394         {0x2242, 0x2249,},
3395         {0x2251, 0x225b,},
3396         {0x226b, 0x2271,},
3397         {0x227a, 0x227d,},
3398         {0x2321, 0x232f,},
3399         {0x233a, 0x2340,},
3400         {0x235b, 0x2360,},
3401         {0x237b, 0x237e,},
3402         {0x2474, 0x247e,},
3403         {0x2577, 0x257e,},
3404         {0x2639, 0x2640,},
3405         {0x2659, 0x267e,},
3406         {0x2742, 0x2750,},
3407         {0x2772, 0x277e,},
3408         {0x2841, 0x287e,},
3409         {0x4f54, 0x4f7e,},
3410         {0x7425, 0x747e},
3411     };
3412     int i;
3413     int start, end, c;
3414
3415     if(c2 >= 0x00 && c2 <= 0x20 && c1 >= 0x7f && c1 <= 0xff) {
3416         c2 = GETA1;
3417         c1 = GETA2;
3418     }
3419     if((c2 >= 0x29 && c2 <= 0x2f) || (c2 >= 0x75 && c2 <= 0x7e)) {
3420         c2 = GETA1;
3421         c1 = GETA2;
3422     }
3423
3424     for (i = 0; i < RANGE_NUM_MAX; i++) {
3425         start = range[i][0];
3426         end   = range[i][1];
3427         c     = (c2 << 8) + c1;
3428         if (c >= start && c <= end) {
3429             c2 = GETA1;
3430             c1 = GETA2;
3431         }
3432     }
3433     (*o_iso2022jp_check_conv)(c2,c1);
3434 }
3435
3436
3437 /* This converts  =?ISO-2022-JP?B?HOGE HOGE?= */
3438
3439 unsigned char *mime_pattern[] = {
3440    (unsigned char *)"\075?EUC-JP?B?",
3441    (unsigned char *)"\075?SHIFT_JIS?B?",
3442    (unsigned char *)"\075?ISO-8859-1?Q?",
3443    (unsigned char *)"\075?ISO-8859-1?B?",
3444    (unsigned char *)"\075?ISO-2022-JP?B?",
3445    (unsigned char *)"\075?ISO-2022-JP?Q?",
3446 #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
3447    (unsigned char *)"\075?UTF-8?B?",
3448    (unsigned char *)"\075?UTF-8?Q?",
3449 #endif
3450    (unsigned char *)"\075?US-ASCII?Q?",
3451    NULL
3452 };
3453
3454
3455 /* \e$B3:Ev$9$k%3!<%I$NM%@hEY$r>e$2$k$?$a$NL\0u\e(B */
3456 int (*mime_priority_func[])PROTO((int c2, int c1, int c0)) = {
3457     e_iconv, s_iconv, 0, 0, 0, 0,
3458 #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
3459     w_iconv, w_iconv,
3460 #endif
3461     0,
3462 };
3463
3464 int      mime_encode[] = {
3465     JAPANESE_EUC, SHIFT_JIS,ISO8859_1, ISO8859_1, X0208, X0201,
3466 #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
3467     UTF8, UTF8,
3468 #endif
3469     ASCII,
3470     0
3471 };
3472
3473 int      mime_encode_method[] = {
3474     'B', 'B','Q', 'B', 'B', 'Q',
3475 #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
3476     'B', 'Q',
3477 #endif
3478     'Q',
3479     0
3480 };
3481
3482
3483 #define MAXRECOVER 20
3484
3485 /* I don't trust portablity of toupper */
3486 #define nkf_toupper(c)  (('a'<=c && c<='z')?(c-('a'-'A')):c)
3487 #define nkf_isdigit(c)  ('0'<=c && c<='9')
3488 #define nkf_isxdigit(c)  (nkf_isdigit(c) || ('a'<=c && c<='f') || ('A'<=c && c <= 'F'))
3489
3490 void
3491 switch_mime_getc()
3492 {
3493     if (i_getc!=mime_getc) {
3494         i_mgetc = i_getc; i_getc = mime_getc;
3495         i_mungetc = i_ungetc; i_ungetc = mime_ungetc;
3496         if(mime_f==STRICT_MIME) {
3497             i_mgetc_buf = i_mgetc; i_mgetc = mime_getc_buf;
3498             i_mungetc_buf = i_mungetc; i_mungetc = mime_ungetc_buf;
3499         }
3500     }
3501 }
3502
3503 void
3504 unswitch_mime_getc()
3505 {
3506     if(mime_f==STRICT_MIME) {
3507         i_mgetc = i_mgetc_buf;
3508         i_mungetc = i_mungetc_buf;
3509     }
3510     i_getc = i_mgetc;
3511     i_ungetc = i_mungetc;
3512 }
3513
3514 int
3515 mime_begin_strict(f)
3516 FILE *f;
3517 {
3518     int c1 = 0;
3519     int i,j,k;
3520     unsigned char *p,*q;
3521     int r[MAXRECOVER];    /* recovery buffer, max mime pattern lenght */
3522
3523     mime_decode_mode = FALSE;
3524     /* =? has been checked */
3525     j = 0;
3526     p = mime_pattern[j];
3527     r[0]='='; r[1]='?';
3528
3529     for(i=2;p[i]>' ';i++) {                   /* start at =? */
3530         if ( ((r[i] = c1 = (*i_getc)(f))==EOF) || nkf_toupper(c1) != p[i] ) {
3531             /* pattern fails, try next one */
3532             q = p;
3533             while ((p = mime_pattern[++j])) {
3534                 for(k=2;k<i;k++)              /* assume length(p) > i */
3535                     if (p[k]!=q[k]) break;
3536                 if (k==i && nkf_toupper(c1)==p[k]) break;
3537             }
3538             if (p) continue;  /* found next one, continue */
3539             /* all fails, output from recovery buffer */
3540             (*i_ungetc)(c1,f);
3541             for(j=0;j<i;j++) {
3542                 (*oconv)(0,r[j]);
3543             }
3544             return c1;
3545         }
3546     }
3547     mime_decode_mode = p[i-2];
3548
3549     clr_code_score(find_inputcode_byfunc(mime_priority_func[j]), SCORE_iMIME);
3550
3551     if (mime_decode_mode=='B') {
3552         mimebuf_f = unbuf_f;
3553         if (!unbuf_f) {
3554             /* do MIME integrity check */
3555             return mime_integrity(f,mime_pattern[j]);
3556         } 
3557     }
3558     switch_mime_getc();
3559     mimebuf_f = TRUE;
3560     return c1;
3561 }
3562
3563 int
3564 mime_getc_buf(f) 
3565 FILE *f;
3566 {
3567     /* we don't keep eof of Fifo, becase it contains ?= as
3568        a terminator. It was checked in mime_integrity. */
3569     return ((mimebuf_f)?
3570         (*i_mgetc_buf)(f):Fifo(mime_input++));
3571 }
3572
3573 int
3574 mime_ungetc_buf(c,f) 
3575 FILE *f;
3576 int c;
3577 {
3578     if (mimebuf_f)
3579         (*i_mungetc_buf)(c,f);
3580     else 
3581         Fifo(--mime_input)=c;
3582     return c;
3583 }
3584
3585 int
3586 mime_begin(f)
3587 FILE *f;
3588 {
3589     int c1;
3590     int i,k;
3591
3592     /* In NONSTRICT mode, only =? is checked. In case of failure, we  */
3593     /* re-read and convert again from mime_buffer.  */
3594
3595     /* =? has been checked */
3596     k = mime_last;
3597     Fifo(mime_last++)='='; Fifo(mime_last++)='?';
3598     for(i=2;i<MAXRECOVER;i++) {                   /* start at =? */
3599         /* We accept any character type even if it is breaked by new lines */
3600         c1 = (*i_getc)(f); Fifo(mime_last++)= c1 ;
3601         if (c1=='\n'||c1==' '||c1=='\r'||
3602                 c1=='-'||c1=='_'||is_alnum(c1) ) continue;
3603         if (c1=='=') {
3604             /* Failed. But this could be another MIME preemble */
3605             (*i_ungetc)(c1,f);
3606             mime_last--;
3607             break;
3608         }
3609         if (c1!='?') break;
3610         else {
3611             /* c1=='?' */
3612             c1 = (*i_getc)(f); Fifo(mime_last++) = c1;
3613             if (!(++i<MAXRECOVER) || c1==EOF) break;
3614             if (c1=='b'||c1=='B') {
3615                 mime_decode_mode = 'B';
3616             } else if (c1=='q'||c1=='Q') {
3617                 mime_decode_mode = 'Q';
3618             } else {
3619                 break;
3620             }
3621             c1 = (*i_getc)(f); Fifo(mime_last++) = c1;
3622             if (!(++i<MAXRECOVER) || c1==EOF) break;
3623             if (c1!='?') {
3624                 mime_decode_mode = FALSE;
3625             }
3626             break;
3627         }
3628     }
3629     switch_mime_getc();
3630     if (!mime_decode_mode) {
3631         /* false MIME premble, restart from mime_buffer */
3632         mime_decode_mode = 1;  /* no decode, but read from the mime_buffer */
3633         /* Since we are in MIME mode until buffer becomes empty,    */
3634         /* we never go into mime_begin again for a while.           */
3635         return c1;
3636     }
3637     /* discard mime preemble, and goto MIME mode */
3638     mime_last = k;
3639     /* do no MIME integrity check */
3640     return c1;   /* used only for checking EOF */
3641 }
3642
3643 #ifdef CHECK_OPTION
3644 void
3645 no_putc(c)
3646      int c;
3647 {
3648     ;
3649 }
3650
3651 void debug(str)
3652      char *str;
3653 {
3654     if (debug_f){
3655         fprintf(stderr, "%s\n", str);
3656     }
3657 }
3658 #endif
3659
3660 void
3661 set_input_codename (codename)
3662     char *codename;
3663 {
3664     if (guess_f && 
3665         is_inputcode_set &&
3666         strcmp(codename, "") != 0 && 
3667         strcmp(codename, input_codename) != 0)
3668     {
3669         is_inputcode_mixed = TRUE;
3670     }
3671     input_codename = codename;
3672     is_inputcode_set = TRUE;
3673 }
3674
3675 void
3676 print_guessed_code (filename)
3677     char *filename;
3678 {
3679     char *codename = "BINARY";
3680     if (!is_inputcode_mixed) {
3681         if (strcmp(input_codename, "") == 0) {
3682             codename = "ASCII";
3683         } else {
3684             codename = input_codename;
3685         }
3686     }
3687     if (filename != NULL) printf("%s:", filename);
3688     printf("%s\n", codename);
3689 }
3690
3691 int
3692 hex2bin(x)
3693      int x;
3694 {
3695     if (nkf_isdigit(x)) return x - '0';
3696     return nkf_toupper(x) - 'A' + 10;
3697 }
3698
3699 #ifdef INPUT_OPTION 
3700
3701 #ifdef ANSI_C_PROTOTYPE
3702 int hex_getc(int ch, FILE *f, int (*g)(FILE *f), int (*u)(int c, FILE *f))
3703 #else
3704 int
3705 hex_getc(ch, f, g, u)
3706      int ch;
3707      FILE *f;
3708      int (*g)();
3709      int (*u)();
3710 #endif
3711 {
3712     int c1, c2, c3;
3713     c1 = (*g)(f);
3714     if (c1 != ch){
3715         return c1;
3716     }
3717     c2 = (*g)(f);
3718     if (!nkf_isxdigit(c2)){
3719         (*u)(c2, f);
3720         return c1;
3721     }
3722     c3 = (*g)(f);
3723     if (!nkf_isxdigit(c3)){
3724         (*u)(c2, f);
3725         (*u)(c3, f);
3726         return c1;
3727     }
3728     return (hex2bin(c2) << 4) | hex2bin(c3);
3729 }
3730
3731 int
3732 cap_getc(f)
3733      FILE *f;
3734 {
3735     return hex_getc(':', f, i_cgetc, i_cungetc);
3736 }
3737
3738 int
3739 cap_ungetc(c, f)
3740      int c;
3741      FILE *f;
3742 {
3743     return (*i_cungetc)(c, f);
3744 }
3745
3746 int
3747 url_getc(f)
3748      FILE *f;
3749 {
3750     return hex_getc('%', f, i_ugetc, i_uungetc);
3751 }
3752
3753 int
3754 url_ungetc(c, f)
3755      int c;
3756      FILE *f;
3757 {
3758     return (*i_uungetc)(c, f);
3759 }
3760 #endif
3761
3762 #ifdef NUMCHAR_OPTION
3763 int
3764 numchar_getc(f)
3765      FILE *f;
3766 {
3767     int (*g)() = i_ngetc;
3768     int (*u)() = i_nungetc;
3769     int i = 0, j;
3770     int buf[8];
3771     long c = -1;
3772
3773     buf[i] = (*g)(f);
3774     if (buf[i] == '&'){
3775         buf[++i] = (*g)(f);
3776         if (buf[i] == '#'){
3777             c = 0;
3778             buf[++i] = (*g)(f);
3779             if (buf[i] == 'x' || buf[i] == 'X'){
3780                 for (j = 0; j < 5; j++){
3781                     buf[++i] = (*g)(f);
3782                     if (!nkf_isxdigit(buf[i])){
3783                         if (buf[i] != ';'){
3784                             c = -1;
3785                         }
3786                         break;
3787                     }
3788                     c <<= 4;
3789                     c |= hex2bin(buf[i]);
3790                 }
3791             }else{
3792                 for (j = 0; j < 6; j++){
3793                     if (j){
3794                         buf[++i] = (*g)(f);
3795                     }
3796                     if (!nkf_isdigit(buf[i])){
3797                         if (buf[i] != ';'){
3798                             c = -1;
3799                         }
3800                         break;
3801                     }
3802                     c *= 10;
3803                     c += hex2bin(buf[i]);
3804                 }
3805             }
3806         }
3807     }
3808     if (c != -1){
3809         return CLASS_UTF16 | c;
3810     }
3811     while (i > 0){
3812         (*u)(buf[i], f);
3813         --i;
3814     }
3815     return buf[0];
3816 }
3817
3818 int
3819 numchar_ungetc(c, f)
3820      int c;
3821      FILE *f;
3822 {
3823     return (*i_nungetc)(c, f);
3824 }
3825 #endif
3826
3827
3828 int 
3829 mime_getc(f)
3830 FILE *f;
3831 {
3832     int c1, c2, c3, c4, cc;
3833     int t1, t2, t3, t4, mode, exit_mode;
3834     int lwsp_count;
3835     char *lwsp_buf;
3836     char *lwsp_buf_new;
3837     int lwsp_size = 128;
3838
3839     if (mime_top != mime_last) {  /* Something is in FIFO */
3840         return  Fifo(mime_top++);
3841     }
3842     if (mime_decode_mode==1 ||mime_decode_mode==FALSE) {
3843         mime_decode_mode=FALSE;
3844         unswitch_mime_getc();
3845         return (*i_getc)(f);
3846     }
3847
3848     if (mimebuf_f == FIXED_MIME)
3849         exit_mode = mime_decode_mode;
3850     else
3851         exit_mode = FALSE;
3852     if (mime_decode_mode == 'Q') {
3853         if ((c1 = (*i_mgetc)(f)) == EOF) return (EOF);
3854 restart_mime_q:
3855         if (c1=='_') return ' ';
3856         if (c1!='=' && c1!='?') {
3857             return c1;
3858         }
3859                 
3860         mime_decode_mode = exit_mode; /* prepare for quit */
3861         if (c1<=' ') return c1;
3862         if ((c2 = (*i_mgetc)(f)) == EOF) return (EOF);
3863         if (c1=='?'&&c2=='=' && mimebuf_f != FIXED_MIME) {
3864             /* end Q encoding */
3865             input_mode = exit_mode;
3866             lwsp_count = 0;
3867             lwsp_buf = malloc((lwsp_size+5)*sizeof(char));
3868             if (lwsp_buf==NULL) {
3869                 perror("can't malloc");
3870                 return -1;
3871             }
3872             while ((c1=(*i_getc)(f))!=EOF) {
3873                 switch (c1) {
3874                 case NL:
3875                 case CR:
3876                     if (c1==NL) {
3877                         if ((c1=(*i_getc)(f))!=EOF && (c1==SPACE||c1==TAB)) {
3878                             i_ungetc(SPACE,f);
3879                             continue;
3880                         } else {
3881                             i_ungetc(c1,f);
3882                         }
3883                         c1 = NL;
3884                     } else {
3885                         if ((c1=(*i_getc)(f))!=EOF && c1 == NL) {
3886                             if ((c1=(*i_getc)(f))!=EOF && (c1==SPACE||c1==TAB)) {
3887                                 i_ungetc(SPACE,f);
3888                                 continue;
3889                             } else {
3890                                 i_ungetc(c1,f);
3891                             }
3892                             i_ungetc(NL,f);
3893                         } else {
3894                             i_ungetc(c1,f);
3895                         }
3896                         c1 = CR;
3897                     }
3898                     break;
3899                 case SPACE:
3900                 case TAB:
3901                     lwsp_buf[lwsp_count] = c1;
3902                     if (lwsp_count++>lwsp_size){
3903                         lwsp_size *= 2;
3904                         lwsp_buf_new = realloc(lwsp_buf, (lwsp_size+5)*sizeof(char));
3905                         if (lwsp_buf_new==NULL) {
3906                             free(lwsp_buf);
3907                             lwsp_buf = NULL;
3908                             perror("can't realloc");
3909                             return -1;
3910                         }
3911                         lwsp_buf = lwsp_buf_new;
3912                     }
3913                     continue;
3914                 }
3915                 break;
3916             }
3917             if (lwsp_count > 0) {
3918                 if (c1=='=' && (lwsp_buf[lwsp_count-1]==SPACE||lwsp_buf[lwsp_count-1]==TAB)) {
3919                     lwsp_count = 0;
3920                 } else {
3921                     i_ungetc(c1,f);
3922                     for(lwsp_count--;lwsp_count>0;lwsp_count--)
3923                         i_ungetc(lwsp_buf[lwsp_count],f);
3924                     c1 = lwsp_buf[0];
3925                 }
3926             }
3927             free(lwsp_buf);
3928             lwsp_buf = NULL;
3929             return c1;
3930         }
3931         if (c1=='='&&c2<' ') { /* this is soft wrap */
3932             while((c1 =  (*i_mgetc)(f)) <=' ') {
3933                 if ((c1 = (*i_mgetc)(f)) == EOF) return (EOF);
3934             }
3935             mime_decode_mode = 'Q'; /* still in MIME */
3936             goto restart_mime_q;
3937         }
3938         if (c1=='?') {
3939             mime_decode_mode = 'Q'; /* still in MIME */
3940             (*i_mungetc)(c2,f);
3941             return c1;
3942         }
3943         if ((c3 = (*i_mgetc)(f)) == EOF) return (EOF);
3944         if (c2<=' ') return c2;
3945         mime_decode_mode = 'Q'; /* still in MIME */
3946 #define hex(c)   (('0'<=c&&c<='9')?(c-'0'):\
3947      ('A'<=c&&c<='F')?(c-'A'+10):('a'<=c&&c<='f')?(c-'a'+10):0)
3948         return ((hex(c2)<<4) + hex(c3));
3949     }
3950
3951     if (mime_decode_mode != 'B') {
3952         mime_decode_mode = FALSE;
3953         return (*i_mgetc)(f);
3954     }
3955
3956
3957     /* Base64 encoding */
3958     /* 
3959         MIME allows line break in the middle of 
3960         Base64, but we are very pessimistic in decoding
3961         in unbuf mode because MIME encoded code may broken by 
3962         less or editor's control sequence (such as ESC-[-K in unbuffered
3963         mode. ignore incomplete MIME.
3964     */
3965     mode = mime_decode_mode;
3966     mime_decode_mode = exit_mode;  /* prepare for quit */
3967
3968     while ((c1 = (*i_mgetc)(f))<=' ') {
3969         if (c1==EOF)
3970             return (EOF);
3971     }
3972 mime_c2_retry:
3973     if ((c2 = (*i_mgetc)(f))<=' ') {
3974         if (c2==EOF)
3975             return (EOF);
3976         if (mime_f != STRICT_MIME) goto mime_c2_retry;
3977         if (mimebuf_f!=FIXED_MIME) input_mode = ASCII;  
3978         return c2;
3979     }
3980     if ((c1 == '?') && (c2 == '=')) {
3981         input_mode = ASCII;
3982         lwsp_count = 0;
3983         lwsp_buf = malloc((lwsp_size+5)*sizeof(char));
3984         if (lwsp_buf==NULL) {
3985             perror("can't malloc");
3986             return -1;
3987         }
3988         while ((c1=(*i_getc)(f))!=EOF) {
3989             switch (c1) {
3990             case NL:
3991             case CR:
3992                 if (c1==NL) {
3993                     if ((c1=(*i_getc)(f))!=EOF && (c1==SPACE||c1==TAB)) {
3994                         i_ungetc(SPACE,f);
3995                         continue;
3996                     } else {
3997                         i_ungetc(c1,f);
3998                     }
3999                     c1 = NL;
4000                 } else {
4001                     if ((c1=(*i_getc)(f))!=EOF) {
4002                         if (c1==SPACE) {
4003                             i_ungetc(SPACE,f);
4004                             continue;
4005                         } else if ((c1=(*i_getc)(f))!=EOF && (c1==SPACE||c1==TAB)) {
4006                             i_ungetc(SPACE,f);
4007                             continue;
4008                         } else {
4009                             i_ungetc(c1,f);
4010                         }
4011                         i_ungetc(NL,f);
4012                     } else {
4013                         i_ungetc(c1,f);
4014                     }
4015                     c1 = CR;
4016                 }
4017                 break;
4018             case SPACE:
4019             case TAB:
4020                 lwsp_buf[lwsp_count] = c1;
4021                 if (lwsp_count++>lwsp_size){
4022                     lwsp_size *= 2;
4023                     lwsp_buf_new = realloc(lwsp_buf, (lwsp_size+5)*sizeof(char));
4024                     if (lwsp_buf_new==NULL) {
4025                         free(lwsp_buf);
4026                         lwsp_buf = NULL;
4027                         perror("can't realloc");
4028                         return -1;
4029                     }
4030                     lwsp_buf = lwsp_buf_new;
4031                 }
4032                 continue;
4033             }
4034             break;
4035         }
4036         if (lwsp_count > 0) {
4037             if (c1=='=' && (lwsp_buf[lwsp_count-1]==SPACE||lwsp_buf[lwsp_count-1]==TAB)) {
4038                 lwsp_count = 0;
4039             } else {
4040                 i_ungetc(c1,f);
4041                 for(lwsp_count--;lwsp_count>0;lwsp_count--)
4042                     i_ungetc(lwsp_buf[lwsp_count],f);
4043                 c1 = lwsp_buf[0];
4044             }
4045         }
4046         free(lwsp_buf);
4047         lwsp_buf = NULL;
4048         return c1;
4049     }
4050 mime_c3_retry:
4051     if ((c3 = (*i_mgetc)(f))<=' ') {
4052         if (c3==EOF)
4053             return (EOF);
4054         if (mime_f != STRICT_MIME) goto mime_c3_retry;
4055         if (mimebuf_f!=FIXED_MIME) input_mode = ASCII;  
4056         return c3;
4057     }
4058 mime_c4_retry:
4059     if ((c4 = (*i_mgetc)(f))<=' ') {
4060         if (c4==EOF)
4061             return (EOF);
4062         if (mime_f != STRICT_MIME) goto mime_c4_retry;
4063         if (mimebuf_f!=FIXED_MIME) input_mode = ASCII;  
4064         return c4;
4065     }
4066
4067     mime_decode_mode = mode; /* still in MIME sigh... */
4068
4069     /* BASE 64 decoding */
4070
4071     t1 = 0x3f & base64decode(c1);
4072     t2 = 0x3f & base64decode(c2);
4073     t3 = 0x3f & base64decode(c3);
4074     t4 = 0x3f & base64decode(c4);
4075     cc = ((t1 << 2) & 0x0fc) | ((t2 >> 4) & 0x03);
4076     if (c2 != '=') {
4077         Fifo(mime_last++) = cc;
4078         cc = ((t2 << 4) & 0x0f0) | ((t3 >> 2) & 0x0f);
4079         if (c3 != '=') {
4080             Fifo(mime_last++) = cc;
4081             cc = ((t3 << 6) & 0x0c0) | (t4 & 0x3f);
4082             if (c4 != '=') 
4083                 Fifo(mime_last++) = cc;
4084         }
4085     } else {
4086         return c1;
4087     }
4088     return  Fifo(mime_top++);
4089 }
4090
4091 int
4092 mime_ungetc(c,f) 
4093 int   c;
4094 FILE  *f;
4095 {
4096     Fifo(--mime_top) = c;
4097     return c;
4098 }
4099
4100 int
4101 mime_integrity(f,p)
4102 FILE *f;
4103 unsigned char *p;
4104 {
4105     int c,d;
4106     unsigned int q;
4107     /* In buffered mode, read until =? or NL or buffer full
4108      */
4109     mime_input = mime_top;
4110     mime_last = mime_top;
4111     while(*p) Fifo(mime_input++) = *p++;
4112     d = 0;
4113     q = mime_input;
4114     while((c=(*i_getc)(f))!=EOF) {
4115         if (((mime_input-mime_top)&MIME_BUF_MASK)==0) {
4116             break;   /* buffer full */
4117         }
4118         if (c=='=' && d=='?') {
4119             /* checked. skip header, start decode */
4120             Fifo(mime_input++) = c;
4121             /* mime_last_input = mime_input; */
4122             mime_input = q; 
4123             switch_mime_getc();
4124             return 1;
4125         }
4126         if (!( (c=='+'||c=='/'|| c=='=' || c=='?' || is_alnum(c))))
4127             break;
4128         /* Should we check length mod 4? */
4129         Fifo(mime_input++) = c;
4130         d=c;
4131     }
4132     /* In case of Incomplete MIME, no MIME decode  */
4133     Fifo(mime_input++) = c;
4134     mime_last = mime_input;     /* point undecoded buffer */
4135     mime_decode_mode = 1;              /* no decode on Fifo last in mime_getc */
4136     switch_mime_getc();         /* anyway we need buffered getc */
4137     return 1;
4138 }
4139
4140 int
4141 base64decode(c)
4142     int            c;
4143 {
4144     int             i;
4145     if (c > '@') {
4146         if (c < '[') {
4147             i = c - 'A';                        /* A..Z 0-25 */
4148         } else {
4149             i = c - 'G'     /* - 'a' + 26 */ ;  /* a..z 26-51 */
4150         }
4151     } else if (c > '/') {
4152         i = c - '0' + '4'   /* - '0' + 52 */ ;  /* 0..9 52-61 */
4153     } else if (c == '+') {
4154         i = '>'             /* 62 */ ;          /* +  62 */
4155     } else {
4156         i = '?'             /* 63 */ ;          /* / 63 */
4157     }
4158     return (i);
4159 }
4160
4161 static char basis_64[] =
4162    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4163
4164 static int b64c;
4165 #define MIMEOUT_BUF_LENGTH (60)
4166 char mimeout_buf[MIMEOUT_BUF_LENGTH+1];
4167 int mimeout_buf_count = 0;
4168 int mimeout_preserve_space = 0;
4169 #define itoh4(c)   (c>=10?c+'A'-10:c+'0')
4170
4171 void
4172 open_mime(mode)
4173 int mode;
4174 {
4175     unsigned char *p;
4176     int i;
4177     int j;
4178     p  = mime_pattern[0];
4179     for(i=0;mime_encode[i];i++) {
4180         if (mode == mime_encode[i]) {
4181             p = mime_pattern[i];
4182             break;
4183         }
4184     }
4185     mimeout_mode = mime_encode_method[i];
4186     
4187     i = 0;
4188     if (base64_count>45) {
4189         (*o_mputc)(NL);
4190         (*o_mputc)(SPACE);
4191         base64_count = 1;
4192         if (!mimeout_preserve_space && mimeout_buf_count>0
4193             && (mimeout_buf[i]==SPACE || mimeout_buf[i]==TAB
4194                 || mimeout_buf[i]==CR || mimeout_buf[i]==NL )) {
4195             i++;
4196         }
4197     }
4198     if (!mimeout_preserve_space) {
4199         for (;i<mimeout_buf_count;i++) {
4200             if (mimeout_buf[i]==SPACE || mimeout_buf[i]==TAB
4201                 || mimeout_buf[i]==CR || mimeout_buf[i]==NL ) {
4202                 (*o_mputc)(mimeout_buf[i]);
4203                 base64_count ++;
4204             } else {
4205                 break;
4206             }
4207         }
4208     }
4209     mimeout_preserve_space = FALSE;
4210     
4211     while(*p) {
4212         (*o_mputc)(*p++);
4213         base64_count ++;
4214     }
4215     j = mimeout_buf_count;
4216     mimeout_buf_count = 0;
4217     for (;i<j;i++) {
4218         mime_putc(mimeout_buf[i]);
4219     }
4220 }
4221
4222 void
4223 close_mime()
4224 {
4225     (*o_mputc)('?');
4226     (*o_mputc)('=');
4227     base64_count += 2;
4228     mimeout_mode = 0;
4229 }
4230
4231 void
4232 eof_mime()
4233 {
4234     switch(mimeout_mode) {
4235     case 'Q':
4236     case 'B':
4237         break;
4238     case 2:
4239         (*o_mputc)(basis_64[((b64c & 0x3)<< 4)]);
4240         (*o_mputc)('=');
4241         (*o_mputc)('=');
4242         base64_count += 3;
4243         break;
4244     case 1:
4245         (*o_mputc)(basis_64[((b64c & 0xF) << 2)]);
4246         (*o_mputc)('=');
4247         base64_count += 2;
4248         break;
4249     }
4250     if (mimeout_mode) {
4251         if (mimeout_f!=FIXED_MIME) {
4252             close_mime(); 
4253         } else if (mimeout_mode != 'Q')
4254             mimeout_mode = 'B';
4255     }
4256 }
4257
4258 void
4259 mimeout_addchar(c)
4260     int            c;
4261 {
4262     switch(mimeout_mode) {
4263     case 'Q':
4264         if(c==SPACE){
4265             (*o_mputc)('_');
4266             base64_count++;
4267         } else if (c==CR||c==NL) {
4268             (*o_mputc)(c);
4269             base64_count = 0;
4270         } else if(c<SPACE||c=='='||c=='?'||c=='_'||DEL<=c) {
4271             (*o_mputc)('=');
4272             (*o_mputc)(itoh4(((c>>4)&0xf)));
4273             (*o_mputc)(itoh4((c&0xf)));
4274             base64_count += 3;
4275         } else {
4276             (*o_mputc)(c);
4277             base64_count++;
4278         }
4279         break;
4280     case 'B':
4281         b64c=c;
4282         (*o_mputc)(basis_64[c>>2]);
4283         mimeout_mode=2;
4284         base64_count ++;
4285         break;
4286     case 2:
4287         (*o_mputc)(basis_64[((b64c & 0x3)<< 4) | ((c & 0xF0) >> 4)]);
4288         b64c=c;
4289         mimeout_mode=1;
4290         base64_count ++;
4291         break;
4292     case 1:
4293         (*o_mputc)(basis_64[((b64c & 0xF) << 2) | ((c & 0xC0) >>6)]);
4294         (*o_mputc)(basis_64[c & 0x3F]);
4295         mimeout_mode='B';
4296         base64_count += 2;
4297         break;
4298     default:
4299         (*o_mputc)(c);
4300         base64_count++;
4301         break;
4302     }
4303 }
4304
4305 void
4306 mime_putc(c)
4307     int            c;
4308 {
4309     int i = 0;
4310     int j = 0;
4311     
4312     if (mimeout_f==FIXED_MIME && base64_count>71) {
4313         if (mimeout_mode=='Q') {
4314             if (c!=CR && c!=NL) {
4315                 (*o_mputc)('=');
4316                 (*o_mputc)(NL);
4317             }
4318         } else {
4319             eof_mime();
4320             (*o_mputc)(NL);
4321         }
4322         base64_count=0;
4323     } else if (mimeout_f!=FIXED_MIME && !mimeout_mode && (c==CR||c==NL)) {
4324         base64_count=0;
4325     }
4326     if (c!=EOF && mimeout_f!=FIXED_MIME) {
4327         if ( c<=DEL &&(output_mode==ASCII ||output_mode == ISO8859_1 ) ) {
4328             if (mimeout_mode=='Q') {
4329                 if (c<=SPACE) {
4330                     close_mime();
4331                     (*o_mputc)(SPACE);
4332                     base64_count++;
4333                 }
4334                 (*o_mputc)(c);
4335                 base64_count++;
4336                 return;
4337             } else if (mimeout_mode) {
4338                 if (mimeout_buf_count>0
4339                     && (mimeout_buf[mimeout_buf_count-1]==CR || mimeout_buf[mimeout_buf_count-1]==NL)) {
4340                     if (c==SPACE || c==TAB) {
4341                         for (i=0;i<mimeout_buf_count;i++) {
4342                             mimeout_addchar(mimeout_buf[i]);
4343                         }
4344                         mimeout_buf_count = 0;
4345                     } else if (SPACE<c && c<DEL) {
4346                         eof_mime();
4347                         for (i=0;i<mimeout_buf_count;i++) {
4348                             (*o_mputc)(mimeout_buf[i]);
4349                         }
4350                         base64_count = 0;
4351                         mimeout_buf_count = 0;
4352                     }
4353                 }
4354                 if (c==SPACE || c==TAB || c==CR || c==NL) {
4355                     for (i=0;i<mimeout_buf_count;i++) {
4356                         if (SPACE<mimeout_buf[i] && mimeout_buf[i]<DEL) {
4357                             eof_mime();
4358                             for (i=0;i<mimeout_buf_count;i++) {
4359                                 (*o_mputc)(mimeout_buf[i]);
4360                                 base64_count++;
4361                             }
4362                             mimeout_buf_count = 0;
4363                         }
4364                     }
4365                     mimeout_buf[mimeout_buf_count++] = c;
4366                     if (mimeout_buf_count>MIMEOUT_BUF_LENGTH) {
4367                         eof_mime();
4368                         for (i=0;i<mimeout_buf_count;i++) {
4369                             (*o_mputc)(mimeout_buf[i]);
4370                             base64_count++;
4371                         }
4372                         mimeout_buf_count = 0;
4373                     }
4374                     return;
4375                 }
4376                 
4377                 if (mimeout_buf_count>0 && SPACE<c && c!='=') {
4378                     mimeout_buf[mimeout_buf_count++] = c;
4379                     if (mimeout_buf_count>MIMEOUT_BUF_LENGTH) {
4380                         j = mimeout_buf_count;
4381                         mimeout_buf_count = 0;
4382                         for (i=0;i<j;i++) {
4383                             mimeout_addchar(mimeout_buf[i]);
4384                         }
4385                     }
4386                     return;
4387                 }
4388             } else if (!mimeout_mode) {
4389                 if (c==SPACE || c==TAB || c==CR || c==NL) {
4390                     if ((c==CR || c==NL)
4391                         &&(mimeout_buf[mimeout_buf_count-1]==SPACE
4392                            || mimeout_buf[mimeout_buf_count-1]==TAB)) {
4393                         mimeout_buf_count--;
4394                     }
4395                     for (i=0;i<mimeout_buf_count;i++) {
4396                         (*o_mputc)(mimeout_buf[i]);
4397                         base64_count++;
4398                     }
4399                     mimeout_buf_count = 0;
4400                 }
4401                 mimeout_buf[mimeout_buf_count++] = c;
4402                 if (mimeout_buf_count>MIMEOUT_BUF_LENGTH) {
4403                     open_mime(output_mode);
4404                 }
4405                 return;
4406             }
4407         } else if (!mimeout_mode) {
4408             if (mimeout_buf_count>0 && mimeout_buf[mimeout_buf_count-1]==SPACE) {
4409                 for (i=0;i<mimeout_buf_count-1;i++) {
4410                     (*o_mputc)(mimeout_buf[i]);
4411                     base64_count++;
4412                 }
4413                 mimeout_buf[0] = SPACE;
4414                 mimeout_buf_count = 1;
4415             }
4416             open_mime(output_mode);
4417         }
4418     } else if (c == EOF) { /* c==EOF */
4419         j = mimeout_buf_count;
4420         mimeout_buf_count = 0;
4421         i = 0;
4422         for (;i<j;i++) {
4423             if (mimeout_buf[i]==SPACE || mimeout_buf[i]==TAB
4424                 || mimeout_buf[i]==CR || mimeout_buf[i]==NL)
4425                 break;
4426             mimeout_addchar(mimeout_buf[i]);
4427         }
4428         eof_mime();
4429         for (;i<j;i++) {
4430             (*o_mputc)(mimeout_buf[i]);
4431             base64_count++;
4432         }
4433         return;
4434     }
4435     
4436     if (mimeout_buf_count>0) {
4437         j = mimeout_buf_count;
4438         mimeout_buf_count = 0;
4439     &