OSDN Git Service

77e5ddad3f5816f07ec63077e6ec456c2b462a7e
[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.48 2004/12/18 10:33:53 rei_furukawa Exp $ */
43 #define NKF_VERSION "2.0.4"
44 #define NKF_RELEASE_DATE "2004-12-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 || *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 #ifdef X0212_ENABLE
2821     if ((c2 & 0xff00) == 0x8f00){
2822         extern unsigned short *x0212_shiftjis[];
2823         ptr = x0212_shiftjis[(c2 & 0x7f) - 0x21];
2824         if (ptr){
2825             val = ptr[(c1 & 0x7f) - 0x21];
2826         }
2827         if (val){
2828             c2 = val >> 8;
2829             c1 = val & 0xff;
2830             if (p2) *p2 = c2;
2831             if (p1) *p1 = c1;
2832             return 0;
2833         }
2834         c2 = x0212_shift(c2);
2835     }
2836 #endif /* X0212_ENABLE */
2837     if ((c2 & 0xff00) == 0x8f00){
2838         return 1;
2839     }
2840     if (p2) *p2 = ((c2 - 1) >> 1) + ((c2 <= 0x5e) ? 0x71 : 0xb1);
2841     if (p1) *p1 = c1 + ((c2 & 1) ? ((c1 < 0x60) ? 0x1f : 0x20) : 0x7e);
2842     return 0;
2843 }
2844
2845 void
2846 s_oconv(c2, c1)
2847     int    c2,
2848                     c1;
2849 {
2850 #ifdef NUMCHAR_OPTION
2851     if (c2 == 0 && (c1 & CLASS_MASK) == CLASS_UTF16){
2852         w16e_conv(c1, &c2, &c1);
2853     }
2854 #endif
2855     if (c2 == EOF) {
2856         (*o_putc)(EOF);
2857         return;
2858     } else if (c2 == 0) {
2859         output_mode = ASCII;
2860         (*o_putc)(c1);
2861     } else if (c2 == X0201) {
2862         output_mode = SHIFT_JIS;
2863         (*o_putc)(c1|0x80);
2864     } else if (c2 == ISO8859_1) {
2865         output_mode = ISO8859_1;
2866         (*o_putc)(c1 | 0x080);
2867 #ifdef X0212_ENABLE
2868     } else if ((c2 & 0xff00) >> 8 == 0x8f){
2869         output_mode = SHIFT_JIS;
2870         if (e2s_conv(c2, c1, &c2, &c1) == 0){
2871             (*o_putc)(c2);
2872             (*o_putc)(c1);
2873         }
2874 #endif
2875     } else {
2876         if ((c1<0x20 || 0x7e<c1) ||
2877            (c2<0x20 || 0x7e<c2)) {
2878             set_iconv(FALSE, 0);
2879             return; /* too late to rescue this char */
2880         }
2881         output_mode = SHIFT_JIS;
2882         e2s_conv(c2, c1, &c2, &c1);
2883
2884 #ifdef SHIFTJIS_CP932
2885         if (cp932inv_f
2886             && CP932INV_TABLE_BEGIN <= c2 && c2 <= CP932INV_TABLE_END){
2887             extern unsigned short cp932inv[2][189];
2888             int c = cp932inv[c2 - CP932INV_TABLE_BEGIN][c1 - 0x40];
2889             if (c){
2890                 c2 = c >> 8;
2891                 c1 = c & 0xff;
2892             }
2893         }
2894 #endif /* SHIFTJIS_CP932 */
2895
2896         (*o_putc)(c2);
2897         if (prefix_table[(unsigned char)c1]){
2898             (*o_putc)(prefix_table[(unsigned char)c1]);
2899         }
2900         (*o_putc)(c1);
2901     }
2902 }
2903
2904 void
2905 j_oconv(c2, c1)
2906     int    c2,
2907                     c1;
2908 {
2909 #ifdef NUMCHAR_OPTION
2910     if ((c1 & CLASS_MASK) == CLASS_UTF16){
2911         w16e_conv(c1, &c2, &c1);
2912     }
2913 #endif
2914     if (c2 == EOF) {
2915         if (output_mode !=ASCII && output_mode!=ISO8859_1) {
2916             (*o_putc)(ESC);
2917             (*o_putc)('(');
2918             (*o_putc)(ascii_intro);
2919             output_mode = ASCII;
2920         }
2921         (*o_putc)(EOF);
2922 #ifdef X0212_ENABLE
2923     } else if ((c2 & 0xff00) >> 8 == 0x8f){
2924         if (output_mode!=X0212) {
2925             output_mode = X0212;
2926             (*o_putc)(ESC);
2927             (*o_putc)('$');
2928             (*o_putc)('(');
2929             (*o_putc)('D');
2930         }
2931         (*o_putc)(c2 & 0x7f);
2932         (*o_putc)(c1);
2933 #endif
2934     } else if (c2==X0201) {
2935         if (output_mode!=X0201) {
2936             output_mode = X0201;
2937             (*o_putc)(ESC);
2938             (*o_putc)('(');
2939             (*o_putc)('I');
2940         }
2941         (*o_putc)(c1);
2942     } else if (c2==ISO8859_1) {
2943             /* iso8859 introduction, or 8th bit on */
2944             /* Can we convert in 7bit form using ESC-'-'-A ? 
2945                Is this popular? */
2946         output_mode = ISO8859_1;
2947         (*o_putc)(c1|0x80);
2948     } else if (c2 == 0) {
2949         if (output_mode !=ASCII && output_mode!=ISO8859_1) {
2950             (*o_putc)(ESC);
2951             (*o_putc)('(');
2952             (*o_putc)(ascii_intro);
2953             output_mode = ASCII;
2954         }
2955         (*o_putc)(c1);
2956     } else {
2957         if (output_mode != X0208) {
2958             output_mode = X0208;
2959             (*o_putc)(ESC);
2960             (*o_putc)('$');
2961             (*o_putc)(kanji_intro);
2962         }
2963         if (c1<0x20 || 0x7e<c1) 
2964             return;
2965         if (c2<0x20 || 0x7e<c2) 
2966             return;
2967         (*o_putc)(c2);
2968         (*o_putc)(c1);
2969     }
2970 }
2971
2972 void
2973 base64_conv(c2, c1)
2974     int    c2,
2975                     c1;
2976 {
2977     if (base64_count>50 && !mimeout_mode && c2==0 && c1==SPACE) {
2978         (*o_putc)(EOF);
2979         (*o_putc)(NL);
2980     } else if (base64_count>66 && mimeout_mode) {
2981         (*o_base64conv)(EOF,0);
2982         (*o_base64conv)(NL,0);
2983         (*o_base64conv)(SPACE,0);
2984     }
2985     (*o_base64conv)(c2,c1);
2986 }
2987
2988
2989 static int broken_buf[3];
2990 static int broken_counter = 0;
2991 static int broken_last = 0;
2992 int
2993 broken_getc(f)
2994 FILE *f;
2995 {
2996     int c,c1;
2997
2998     if (broken_counter>0) {
2999         return broken_buf[--broken_counter];
3000     }
3001     c= (*i_bgetc)(f);
3002     if (c=='$' && broken_last != ESC 
3003             && (input_mode==ASCII || input_mode==X0201)) {
3004         c1= (*i_bgetc)(f);
3005         broken_last = 0;
3006         if (c1=='@'|| c1=='B') {
3007             broken_buf[0]=c1; broken_buf[1]=c; 
3008             broken_counter=2;
3009             return ESC;
3010         } else {
3011             (*i_bungetc)(c1,f);
3012             return c;
3013         }
3014     } else if (c=='(' && broken_last != ESC 
3015             && (input_mode==X0208 || input_mode==X0201)) { /* ) */
3016         c1= (*i_bgetc)(f);
3017         broken_last = 0;
3018         if (c1=='J'|| c1=='B') {
3019             broken_buf[0]=c1; broken_buf[1]=c;
3020             broken_counter=2;
3021             return ESC;
3022         } else {
3023             (*i_bungetc)(c1,f);
3024             return c;
3025         }
3026     } else {
3027         broken_last = c;
3028         return c;
3029     }
3030 }
3031
3032 int
3033 broken_ungetc(c,f)
3034 int c;
3035 FILE *f;
3036 {
3037     if (broken_counter<2)
3038         broken_buf[broken_counter++]=c;
3039     return c;
3040 }
3041
3042 static int prev_cr = 0;
3043
3044 void
3045 cr_conv(c2,c1) 
3046 int c2,c1;
3047 {
3048     if (prev_cr) {
3049         prev_cr = 0;
3050         if (! (c2==0&&c1==NL) ) {
3051             cr_conv(0,'\n');
3052         }
3053     }
3054     if (c2) {
3055         (*o_crconv)(c2,c1);
3056     } else if (c1=='\r') {
3057         prev_cr = c1;
3058     } else if (c1=='\n') {
3059         if (crmode_f==CRLF) {
3060             (*o_crconv)(0,'\r');
3061         } else if (crmode_f==CR) {
3062             (*o_crconv)(0,'\r');
3063             return;
3064         } 
3065         (*o_crconv)(0,NL);
3066     } else if (c1!='\032' || crmode_f!=NL){
3067         (*o_crconv)(c2,c1);
3068     }
3069 }
3070
3071 /* 
3072   Return value of fold_conv()
3073
3074        \n  add newline  and output char
3075        \r  add newline  and output nothing
3076        ' ' space
3077        0   skip  
3078        1   (or else) normal output 
3079
3080   fold state in prev (previous character)
3081
3082       >0x80 Japanese (X0208/X0201)
3083       <0x80 ASCII
3084       \n    new line 
3085       ' '   space
3086
3087   This fold algorthm does not preserve heading space in a line.
3088   This is the main difference from fmt.
3089 */
3090
3091 #define char_size(c2,c1) (c2?2:1)
3092
3093 void
3094 fold_conv(c2,c1) 
3095 int c2,c1;
3096
3097     int prev0;
3098     int fold_state=0;
3099
3100     if (c1== '\r' && !fold_preserve_f) {
3101         fold_state=0;  /* ignore cr */
3102     }else if (c1== '\n'&&f_prev=='\r' && fold_preserve_f) {
3103         f_prev = '\n';
3104         fold_state=0;  /* ignore cr */
3105     } else if (c1== BS) {
3106         if (f_line>0) f_line--;
3107         fold_state =  1;
3108     } else if (c2==EOF && f_line != 0) {    /* close open last line */
3109             fold_state = '\n';
3110     } else if ((c1=='\n' && !fold_preserve_f)
3111                || ((c1=='\r'||(c1=='\n'&&f_prev!='\r'))
3112                    && fold_preserve_f)) {
3113         /* new line */
3114         if (fold_preserve_f) { 
3115             f_prev = c1;
3116             f_line = 0;
3117             fold_state =  '\r';
3118         } else if ((f_prev == c1 && !fold_preserve_f)
3119                    || (f_prev == '\n' && fold_preserve_f)
3120                    ) {        /* duplicate newline */
3121             if (f_line) {
3122                 f_line = 0;
3123                 fold_state =  '\n';    /* output two newline */
3124             } else {
3125                 f_line = 0;
3126                 fold_state =  1;
3127             }
3128         } else  {
3129             if (f_prev&0x80) {     /* Japanese? */
3130                 f_prev = c1;
3131                 fold_state =  0;       /* ignore given single newline */
3132             } else if (f_prev==' ') {
3133                 fold_state =  0;
3134             } else {
3135                 f_prev = c1;
3136                 if (++f_line<=fold_len) 
3137                     fold_state =  ' ';
3138                 else {
3139                     f_line = 0;
3140                     fold_state =  '\r';        /* fold and output nothing */
3141                 }
3142             }
3143         }
3144     } else if (c1=='\f') {
3145         f_prev = '\n';
3146         if (f_line==0)
3147             fold_state =  1;
3148         f_line = 0;
3149         fold_state =  '\n';            /* output newline and clear */
3150     } else if ( (c2==0  && c1==' ')||
3151                (c2==0  && c1=='\t')||
3152                (c2=='!'&& c1=='!')) {
3153         /* X0208 kankaku or ascii space */
3154             if (f_prev == ' ') {
3155                 fold_state = 0;         /* remove duplicate spaces */
3156             } else {
3157                 f_prev = ' ';    
3158                 if (++f_line<=fold_len) 
3159                     fold_state = ' ';         /* output ASCII space only */
3160                 else {
3161                     f_prev = ' '; f_line = 0;
3162                     fold_state = '\r';        /* fold and output nothing */
3163                 }
3164             }
3165     } else {
3166         prev0 = f_prev; /* we still need this one... , but almost done */
3167         f_prev = c1;
3168         if (c2 || c2==X0201) 
3169             f_prev |= 0x80;  /* this is Japanese */
3170         f_line += char_size(c2,c1);
3171         if (f_line<=fold_len) {   /* normal case */
3172             fold_state = 1;
3173         } else {
3174             if (f_line>=fold_len+fold_margin) { /* too many kinsou suspension */
3175                 f_line = char_size(c2,c1);
3176                 fold_state =  '\n';       /* We can't wait, do fold now */
3177             } else if (c2==X0201) {
3178             /* simple kinsoku rules  return 1 means no folding  */
3179                 if (c1==(0xde&0x7f)) fold_state = 1; /* \e$B!+\e(B*/
3180                 else if (c1==(0xdf&0x7f)) fold_state = 1; /* \e$B!,\e(B*/
3181                 else if (c1==(0xa4&0x7f)) fold_state = 1; /* \e$B!#\e(B*/
3182                 else if (c1==(0xa3&0x7f)) fold_state = 1; /* \e$B!$\e(B*/
3183                 else if (c1==(0xa1&0x7f)) fold_state = 1; /* \e$B!W\e(B*/
3184                 else if (c1==(0xb0&0x7f)) fold_state = 1; /* - */
3185                 else if (SPACE<=c1 && c1<=(0xdf&0x7f)) {      /* X0201 */
3186                     f_line = 1;
3187                     fold_state = '\n';/* add one new f_line before this character */
3188                 } else {
3189                     f_line = 1;
3190                     fold_state = '\n';/* add one new f_line before this character */
3191                 }
3192             } else if (c2==0) {
3193                 /* kinsoku point in ASCII */ 
3194                 if (  c1==')'||    /* { [ ( */
3195                      c1==']'||
3196                      c1=='}'||
3197                      c1=='.'||
3198                      c1==','||
3199                      c1=='!'||
3200                      c1=='?'||
3201                      c1=='/'||
3202                      c1==':'||
3203                      c1==';' ) {
3204                     fold_state = 1;
3205                 /* just after special */
3206                 } else if (!is_alnum(prev0)) {
3207                     f_line = char_size(c2,c1);
3208                     fold_state = '\n';
3209                 } else if ((prev0==' ') ||   /* ignored new f_line */
3210                       (prev0=='\n')||        /* ignored new f_line */
3211                       (prev0&0x80)) {        /* X0208 - ASCII */
3212                     f_line = char_size(c2,c1);
3213                     fold_state = '\n';/* add one new f_line before this character */
3214                 } else {
3215                     fold_state = 1;  /* default no fold in ASCII */
3216                 }
3217             } else {
3218                 if (c2=='!') {
3219                     if (c1=='"')  fold_state = 1; /* \e$B!"\e(B */
3220                     else if (c1=='#')  fold_state = 1; /* \e$B!#\e(B */
3221                     else if (c1=='W')  fold_state = 1; /* \e$B!W\e(B */
3222                     else if (c1=='K')  fold_state = 1; /* \e$B!K\e(B */
3223                     else if (c1=='$')  fold_state = 1; /* \e$B!$\e(B */
3224                     else if (c1=='%')  fold_state = 1; /* \e$B!%\e(B */
3225                     else if (c1=='\'') fold_state = 1; /* \e$B!\\e(B */
3226                     else if (c1=='(')  fold_state = 1; /* \e$B!(\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                          /* default no fold in kinsoku */
3232                     else { 
3233                         fold_state = '\n';
3234                         f_line = char_size(c2,c1);
3235                         /* add one new f_line before this character */
3236                     }
3237                 } else {
3238                     f_line = char_size(c2,c1);
3239                     fold_state = '\n'; 
3240                     /* add one new f_line before this character */
3241                 }
3242             }
3243         }
3244     }
3245     /* terminator process */
3246     switch(fold_state) {
3247         case '\n': 
3248             (*o_fconv)(0,'\n');
3249             (*o_fconv)(c2,c1);
3250             break;
3251         case 0:    
3252             return;
3253         case '\r': 
3254             (*o_fconv)(0,'\n');
3255             break;
3256         case '\t': 
3257         case ' ': 
3258             (*o_fconv)(0,' ');
3259             break;
3260         default:
3261             (*o_fconv)(c2,c1);
3262     }
3263 }
3264
3265 int z_prev2=0,z_prev1=0;
3266
3267 void
3268 z_conv(c2,c1)
3269 int c2,c1;
3270 {
3271
3272     /* if (c2) c1 &= 0x7f; assertion */
3273
3274     if (x0201_f && z_prev2==X0201) {  /* X0201 */
3275         if (c1==(0xde&0x7f)) { /* \e$BByE@\e(B */
3276             z_prev2=0;
3277             (*o_zconv)(dv[(z_prev1-SPACE)*2],dv[(z_prev1-SPACE)*2+1]);
3278             return;
3279         } else if (c1==(0xdf&0x7f)&&ev[(z_prev1-SPACE)*2]) {  /* \e$BH>ByE@\e(B */
3280             z_prev2=0;
3281             (*o_zconv)(ev[(z_prev1-SPACE)*2],ev[(z_prev1-SPACE)*2+1]);
3282             return;
3283         } else {
3284             z_prev2=0;
3285             (*o_zconv)(cv[(z_prev1-SPACE)*2],cv[(z_prev1-SPACE)*2+1]);
3286         }
3287     }
3288
3289     if (c2==EOF) {
3290         (*o_zconv)(c2,c1);
3291         return;
3292     }
3293
3294     if (x0201_f && c2==X0201) {
3295         if (dv[(c1-SPACE)*2]||ev[(c1-SPACE)*2]) {
3296             /* wait for \e$BByE@\e(B or \e$BH>ByE@\e(B */
3297             z_prev1 = c1; z_prev2 = c2;
3298             return;
3299         } else {
3300             (*o_zconv)(cv[(c1-SPACE)*2],cv[(c1-SPACE)*2+1]);
3301             return;
3302         }
3303     }
3304
3305     /* JISX0208 Alphabet */
3306     if (alpha_f && c2 == 0x23 ) {
3307         c2 = 0;
3308     } else if (alpha_f && c2 == 0x21 ) { 
3309     /* JISX0208 Kigou */
3310        if (0x21==c1) {
3311            if (alpha_f&0x2) {
3312                c1 = ' ';
3313                c2 = 0;
3314            } else if (alpha_f&0x4) {
3315                 (*o_zconv)(0,' ');
3316                 (*o_zconv)(0,' ');
3317                 return;
3318            } 
3319        } else if (0x20<c1 && c1<0x7f && fv[c1-0x20]) {
3320            c1 = fv[c1-0x20];
3321            c2 =  0;
3322            if (alpha_f&0x8) {
3323                char *entity = 0;
3324                switch (c1){
3325                  case '>': entity = "&gt;"; break;
3326                  case '<': entity = "&lt;"; break;
3327                  case '\"': entity = "&quot;"; break;
3328                  case '&': entity = "&amp;"; break;
3329                }
3330                if (entity){
3331                    while (*entity) (*o_zconv)(0, *entity++);
3332                    return;
3333                }
3334            }
3335        } 
3336     }
3337     (*o_zconv)(c2,c1);
3338 }
3339
3340
3341 #define rot13(c)  ( \
3342       ( c < 'A' ) ? c: \
3343       (c <= 'M')  ? (c + 13): \
3344       (c <= 'Z')  ? (c - 13): \
3345       (c < 'a')   ? (c): \
3346       (c <= 'm')  ? (c + 13): \
3347       (c <= 'z')  ? (c - 13): \
3348       (c) \
3349 )
3350
3351 #define  rot47(c) ( \
3352       ( c < '!' ) ? c: \
3353       ( c <= 'O' ) ? (c + 47) : \
3354       ( c <= '~' ) ?  (c - 47) : \
3355       c \
3356 )
3357
3358 void
3359 rot_conv(c2,c1)
3360 int c2,c1;
3361 {
3362     if (c2==0 || c2==X0201 || c2==ISO8859_1) {
3363         c1 = rot13(c1);
3364     } else if (c2) {
3365         c1 = rot47(c1);
3366         c2 = rot47(c2);
3367     }
3368     (*o_rot_conv)(c2,c1);
3369 }
3370
3371 void
3372 hira_conv(c2,c1)
3373 int c2,c1;
3374 {
3375     if ((hira_f & 1) && c2==0x25 && 0x20<c1 && c1<0x74) {
3376         c2 = 0x24;
3377     } else if ((hira_f & 2) && c2==0x24 && 0x20<c1 && c1<0x74) {
3378         c2 = 0x25;
3379     } 
3380     (*o_hira_conv)(c2,c1);
3381 }
3382
3383
3384 void
3385 iso2022jp_check_conv(c2,c1)
3386 int    c2, c1;
3387 {
3388     static int range[RANGE_NUM_MAX][2] = {
3389         {0x222f, 0x2239,},
3390         {0x2242, 0x2249,},
3391         {0x2251, 0x225b,},
3392         {0x226b, 0x2271,},
3393         {0x227a, 0x227d,},
3394         {0x2321, 0x232f,},
3395         {0x233a, 0x2340,},
3396         {0x235b, 0x2360,},
3397         {0x237b, 0x237e,},
3398         {0x2474, 0x247e,},
3399         {0x2577, 0x257e,},
3400         {0x2639, 0x2640,},
3401         {0x2659, 0x267e,},
3402         {0x2742, 0x2750,},
3403         {0x2772, 0x277e,},
3404         {0x2841, 0x287e,},
3405         {0x4f54, 0x4f7e,},
3406         {0x7425, 0x747e},
3407     };
3408     int i;
3409     int start, end, c;
3410
3411     if(c2 >= 0x00 && c2 <= 0x20 && c1 >= 0x7f && c1 <= 0xff) {
3412         c2 = GETA1;
3413         c1 = GETA2;
3414     }
3415     if((c2 >= 0x29 && c2 <= 0x2f) || (c2 >= 0x75 && c2 <= 0x7e)) {
3416         c2 = GETA1;
3417         c1 = GETA2;
3418     }
3419
3420     for (i = 0; i < RANGE_NUM_MAX; i++) {
3421         start = range[i][0];
3422         end   = range[i][1];
3423         c     = (c2 << 8) + c1;
3424         if (c >= start && c <= end) {
3425             c2 = GETA1;
3426             c1 = GETA2;
3427         }
3428     }
3429     (*o_iso2022jp_check_conv)(c2,c1);
3430 }
3431
3432
3433 /* This converts  =?ISO-2022-JP?B?HOGE HOGE?= */
3434
3435 unsigned char *mime_pattern[] = {
3436    (unsigned char *)"\075?EUC-JP?B?",
3437    (unsigned char *)"\075?SHIFT_JIS?B?",
3438    (unsigned char *)"\075?ISO-8859-1?Q?",
3439    (unsigned char *)"\075?ISO-8859-1?B?",
3440    (unsigned char *)"\075?ISO-2022-JP?B?",
3441    (unsigned char *)"\075?ISO-2022-JP?Q?",
3442 #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
3443    (unsigned char *)"\075?UTF-8?B?",
3444    (unsigned char *)"\075?UTF-8?Q?",
3445 #endif
3446    (unsigned char *)"\075?US-ASCII?Q?",
3447    NULL
3448 };
3449
3450
3451 /* \e$B3:Ev$9$k%3!<%I$NM%@hEY$r>e$2$k$?$a$NL\0u\e(B */
3452 int (*mime_priority_func[])PROTO((int c2, int c1, int c0)) = {
3453     e_iconv, s_iconv, 0, 0, 0, 0,
3454 #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
3455     w_iconv, w_iconv,
3456 #endif
3457     0,
3458 };
3459
3460 int      mime_encode[] = {
3461     JAPANESE_EUC, SHIFT_JIS,ISO8859_1, ISO8859_1, X0208, X0201,
3462 #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
3463     UTF8, UTF8,
3464 #endif
3465     ASCII,
3466     0
3467 };
3468
3469 int      mime_encode_method[] = {
3470     'B', 'B','Q', 'B', 'B', 'Q',
3471 #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
3472     'B', 'Q',
3473 #endif
3474     'Q',
3475     0
3476 };
3477
3478
3479 #define MAXRECOVER 20
3480
3481 /* I don't trust portablity of toupper */
3482 #define nkf_toupper(c)  (('a'<=c && c<='z')?(c-('a'-'A')):c)
3483 #define nkf_isdigit(c)  ('0'<=c && c<='9')
3484 #define nkf_isxdigit(c)  (nkf_isdigit(c) || ('a'<=c && c<='f') || ('A'<=c && c <= 'F'))
3485
3486 void
3487 switch_mime_getc()
3488 {
3489     if (i_getc!=mime_getc) {
3490         i_mgetc = i_getc; i_getc = mime_getc;
3491         i_mungetc = i_ungetc; i_ungetc = mime_ungetc;
3492         if(mime_f==STRICT_MIME) {
3493             i_mgetc_buf = i_mgetc; i_mgetc = mime_getc_buf;
3494             i_mungetc_buf = i_mungetc; i_mungetc = mime_ungetc_buf;
3495         }
3496     }
3497 }
3498
3499 void
3500 unswitch_mime_getc()
3501 {
3502     if(mime_f==STRICT_MIME) {
3503         i_mgetc = i_mgetc_buf;
3504         i_mungetc = i_mungetc_buf;
3505     }
3506     i_getc = i_mgetc;
3507     i_ungetc = i_mungetc;
3508 }
3509
3510 int
3511 mime_begin_strict(f)
3512 FILE *f;
3513 {
3514     int c1 = 0;
3515     int i,j,k;
3516     unsigned char *p,*q;
3517     int r[MAXRECOVER];    /* recovery buffer, max mime pattern lenght */
3518
3519     mime_decode_mode = FALSE;
3520     /* =? has been checked */
3521     j = 0;
3522     p = mime_pattern[j];
3523     r[0]='='; r[1]='?';
3524
3525     for(i=2;p[i]>' ';i++) {                   /* start at =? */
3526         if ( ((r[i] = c1 = (*i_getc)(f))==EOF) || nkf_toupper(c1) != p[i] ) {
3527             /* pattern fails, try next one */
3528             q = p;
3529             while ((p = mime_pattern[++j])) {
3530                 for(k=2;k<i;k++)              /* assume length(p) > i */
3531                     if (p[k]!=q[k]) break;
3532                 if (k==i && nkf_toupper(c1)==p[k]) break;
3533             }
3534             if (p) continue;  /* found next one, continue */
3535             /* all fails, output from recovery buffer */
3536             (*i_ungetc)(c1,f);
3537             for(j=0;j<i;j++) {
3538                 (*oconv)(0,r[j]);
3539             }
3540             return c1;
3541         }
3542     }
3543     mime_decode_mode = p[i-2];
3544
3545     clr_code_score(find_inputcode_byfunc(mime_priority_func[j]), SCORE_iMIME);
3546
3547     if (mime_decode_mode=='B') {
3548         mimebuf_f = unbuf_f;
3549         if (!unbuf_f) {
3550             /* do MIME integrity check */
3551             return mime_integrity(f,mime_pattern[j]);
3552         } 
3553     }
3554     switch_mime_getc();
3555     mimebuf_f = TRUE;
3556     return c1;
3557 }
3558
3559 int
3560 mime_getc_buf(f) 
3561 FILE *f;
3562 {
3563     /* we don't keep eof of Fifo, becase it contains ?= as
3564        a terminator. It was checked in mime_integrity. */
3565     return ((mimebuf_f)?
3566         (*i_mgetc_buf)(f):Fifo(mime_input++));
3567 }
3568
3569 int
3570 mime_ungetc_buf(c,f) 
3571 FILE *f;
3572 int c;
3573 {
3574     if (mimebuf_f)
3575         (*i_mungetc_buf)(c,f);
3576     else 
3577         Fifo(--mime_input)=c;
3578     return c;
3579 }
3580
3581 int
3582 mime_begin(f)
3583 FILE *f;
3584 {
3585     int c1;
3586     int i,k;
3587
3588     /* In NONSTRICT mode, only =? is checked. In case of failure, we  */
3589     /* re-read and convert again from mime_buffer.  */
3590
3591     /* =? has been checked */
3592     k = mime_last;
3593     Fifo(mime_last++)='='; Fifo(mime_last++)='?';
3594     for(i=2;i<MAXRECOVER;i++) {                   /* start at =? */
3595         /* We accept any character type even if it is breaked by new lines */
3596         c1 = (*i_getc)(f); Fifo(mime_last++)= c1 ;
3597         if (c1=='\n'||c1==' '||c1=='\r'||
3598                 c1=='-'||c1=='_'||is_alnum(c1) ) continue;
3599         if (c1=='=') {
3600             /* Failed. But this could be another MIME preemble */
3601             (*i_ungetc)(c1,f);
3602             mime_last--;
3603             break;
3604         }
3605         if (c1!='?') break;
3606         else {
3607             /* c1=='?' */
3608             c1 = (*i_getc)(f); Fifo(mime_last++) = c1;
3609             if (!(++i<MAXRECOVER) || c1==EOF) break;
3610             if (c1=='b'||c1=='B') {
3611                 mime_decode_mode = 'B';
3612             } else if (c1=='q'||c1=='Q') {
3613                 mime_decode_mode = 'Q';
3614             } else {
3615                 break;
3616             }
3617             c1 = (*i_getc)(f); Fifo(mime_last++) = c1;
3618             if (!(++i<MAXRECOVER) || c1==EOF) break;
3619             if (c1!='?') {
3620                 mime_decode_mode = FALSE;
3621             }
3622             break;
3623         }
3624     }
3625     switch_mime_getc();
3626     if (!mime_decode_mode) {
3627         /* false MIME premble, restart from mime_buffer */
3628         mime_decode_mode = 1;  /* no decode, but read from the mime_buffer */
3629         /* Since we are in MIME mode until buffer becomes empty,    */
3630         /* we never go into mime_begin again for a while.           */
3631         return c1;
3632     }
3633     /* discard mime preemble, and goto MIME mode */
3634     mime_last = k;
3635     /* do no MIME integrity check */
3636     return c1;   /* used only for checking EOF */
3637 }
3638
3639 #ifdef CHECK_OPTION
3640 void
3641 no_putc(c)
3642      int c;
3643 {
3644     ;
3645 }
3646
3647 void debug(str)
3648      char *str;
3649 {
3650     if (debug_f){
3651         fprintf(stderr, "%s\n", str);
3652     }
3653 }
3654 #endif
3655
3656 void
3657 set_input_codename (codename)
3658     char *codename;
3659 {
3660     if (guess_f && 
3661         is_inputcode_set &&
3662         strcmp(codename, "") != 0 && 
3663         strcmp(codename, input_codename) != 0)
3664     {
3665         is_inputcode_mixed = TRUE;
3666     }
3667     input_codename = codename;
3668     is_inputcode_set = TRUE;
3669 }
3670
3671 void
3672 print_guessed_code (filename)
3673     char *filename;
3674 {
3675     char *codename = "BINARY";
3676     if (!is_inputcode_mixed) {
3677         if (strcmp(input_codename, "") == 0) {
3678             codename = "ASCII";
3679         } else {
3680             codename = input_codename;
3681         }
3682     }
3683     if (filename != NULL) printf("%s:", filename);
3684     printf("%s\n", codename);
3685 }
3686
3687 int
3688 hex2bin(x)
3689      int x;
3690 {
3691     if (nkf_isdigit(x)) return x - '0';
3692     return nkf_toupper(x) - 'A' + 10;
3693 }
3694
3695 #ifdef INPUT_OPTION 
3696
3697 #ifdef ANSI_C_PROTOTYPE
3698 int hex_getc(int ch, FILE *f, int (*g)(FILE *f), int (*u)(int c, FILE *f))
3699 #else
3700 int
3701 hex_getc(ch, f, g, u)
3702      int ch;
3703      FILE *f;
3704      int (*g)();
3705      int (*u)();
3706 #endif
3707 {
3708     int c1, c2, c3;
3709     c1 = (*g)(f);
3710     if (c1 != ch){
3711         return c1;
3712     }
3713     c2 = (*g)(f);
3714     if (!nkf_isxdigit(c2)){
3715         (*u)(c2, f);
3716         return c1;
3717     }
3718     c3 = (*g)(f);
3719     if (!nkf_isxdigit(c3)){
3720         (*u)(c2, f);
3721         (*u)(c3, f);
3722         return c1;
3723     }
3724     return (hex2bin(c2) << 4) | hex2bin(c3);
3725 }
3726
3727 int
3728 cap_getc(f)
3729      FILE *f;
3730 {
3731     return hex_getc(':', f, i_cgetc, i_cungetc);
3732 }
3733
3734 int
3735 cap_ungetc(c, f)
3736      int c;
3737      FILE *f;
3738 {
3739     return (*i_cungetc)(c, f);
3740 }
3741
3742 int
3743 url_getc(f)
3744      FILE *f;
3745 {
3746     return hex_getc('%', f, i_ugetc, i_uungetc);
3747 }
3748
3749 int
3750 url_ungetc(c, f)
3751      int c;
3752      FILE *f;
3753 {
3754     return (*i_uungetc)(c, f);
3755 }
3756 #endif
3757
3758 #ifdef NUMCHAR_OPTION
3759 int
3760 numchar_getc(f)
3761      FILE *f;
3762 {
3763     int (*g)() = i_ngetc;
3764     int (*u)() = i_nungetc;
3765     int i = 0, j;
3766     int buf[8];
3767     long c = -1;
3768
3769     buf[i] = (*g)(f);
3770     if (buf[i] == '&'){
3771         buf[++i] = (*g)(f);
3772         if (buf[i] == '#'){
3773             c = 0;
3774             buf[++i] = (*g)(f);
3775             if (buf[i] == 'x' || buf[i] == 'X'){
3776                 for (j = 0; j < 5; j++){
3777                     buf[++i] = (*g)(f);
3778                     if (!nkf_isxdigit(buf[i])){
3779                         if (buf[i] != ';'){
3780                             c = -1;
3781                         }
3782                         break;
3783                     }
3784                     c <<= 4;
3785                     c |= hex2bin(buf[i]);
3786                 }
3787             }else{
3788                 for (j = 0; j < 6; j++){
3789                     if (j){
3790                         buf[++i] = (*g)(f);
3791                     }
3792                     if (!nkf_isdigit(buf[i])){
3793                         if (buf[i] != ';'){
3794                             c = -1;
3795                         }
3796                         break;
3797                     }
3798                     c *= 10;
3799                     c += hex2bin(buf[i]);
3800                 }
3801             }
3802         }
3803     }
3804     if (c != -1){
3805         return CLASS_UTF16 | c;
3806     }
3807     while (i > 0){
3808         (*u)(buf[i], f);
3809         --i;
3810     }
3811     return buf[0];
3812 }
3813
3814 int
3815 numchar_ungetc(c, f)
3816      int c;
3817      FILE *f;
3818 {
3819     return (*i_nungetc)(c, f);
3820 }
3821 #endif
3822
3823
3824 int 
3825 mime_getc(f)
3826 FILE *f;
3827 {
3828     int c1, c2, c3, c4, cc;
3829     int t1, t2, t3, t4, mode, exit_mode;
3830     int lwsp_count;
3831     char *lwsp_buf;
3832     char *lwsp_buf_new;
3833     int lwsp_size = 128;
3834
3835     if (mime_top != mime_last) {  /* Something is in FIFO */
3836         return  Fifo(mime_top++);
3837     }
3838     if (mime_decode_mode==1 ||mime_decode_mode==FALSE) {
3839         mime_decode_mode=FALSE;
3840         unswitch_mime_getc();
3841         return (*i_getc)(f);
3842     }
3843
3844     if (mimebuf_f == FIXED_MIME)
3845         exit_mode = mime_decode_mode;
3846     else
3847         exit_mode = FALSE;
3848     if (mime_decode_mode == 'Q') {
3849         if ((c1 = (*i_mgetc)(f)) == EOF) return (EOF);
3850 restart_mime_q:
3851         if (c1=='_') return ' ';
3852         if (c1!='=' && c1!='?') {
3853             return c1;
3854         }
3855                 
3856         mime_decode_mode = exit_mode; /* prepare for quit */
3857         if (c1<=' ') return c1;
3858         if ((c2 = (*i_mgetc)(f)) == EOF) return (EOF);
3859         if (c1=='?'&&c2=='=' && mimebuf_f != FIXED_MIME) {
3860             /* end Q encoding */
3861             input_mode = exit_mode;
3862             lwsp_count = 0;
3863             lwsp_buf = malloc((lwsp_size+5)*sizeof(char));
3864             if (lwsp_buf==NULL) {
3865                 perror("can't malloc");
3866                 return -1;
3867             }
3868             while ((c1=(*i_getc)(f))!=EOF) {
3869                 switch (c1) {
3870                 case NL:
3871                 case CR:
3872                     if (c1==NL) {
3873                         if ((c1=(*i_getc)(f))!=EOF && (c1==SPACE||c1==TAB)) {
3874                             i_ungetc(SPACE,f);
3875                             continue;
3876                         } else {
3877                             i_ungetc(c1,f);
3878                         }
3879                         c1 = NL;
3880                     } else {
3881                         if ((c1=(*i_getc)(f))!=EOF && c1 == NL) {
3882                             if ((c1=(*i_getc)(f))!=EOF && (c1==SPACE||c1==TAB)) {
3883                                 i_ungetc(SPACE,f);
3884                                 continue;
3885                             } else {
3886                                 i_ungetc(c1,f);
3887                             }
3888                             i_ungetc(NL,f);
3889                         } else {
3890                             i_ungetc(c1,f);
3891                         }
3892                         c1 = CR;
3893                     }
3894                     break;
3895                 case SPACE:
3896                 case TAB:
3897                     lwsp_buf[lwsp_count] = c1;
3898                     if (lwsp_count++>lwsp_size){
3899                         lwsp_size *= 2;
3900                         lwsp_buf_new = realloc(lwsp_buf, (lwsp_size+5)*sizeof(char));
3901                         if (lwsp_buf_new==NULL) {
3902                             free(lwsp_buf);
3903                             lwsp_buf = NULL;
3904                             perror("can't realloc");
3905                             return -1;
3906                         }
3907                         lwsp_buf = lwsp_buf_new;
3908                     }
3909                     continue;
3910                 }
3911                 break;
3912             }
3913             if (lwsp_count > 0) {
3914                 if (c1=='=' && (lwsp_buf[lwsp_count-1]==SPACE||lwsp_buf[lwsp_count-1]==TAB)) {
3915                     lwsp_count = 0;
3916                 } else {
3917                     i_ungetc(c1,f);
3918                     for(lwsp_count--;lwsp_count>0;lwsp_count--)
3919                         i_ungetc(lwsp_buf[lwsp_count],f);
3920                     c1 = lwsp_buf[0];
3921                 }
3922             }
3923             free(lwsp_buf);
3924             lwsp_buf = NULL;
3925             return c1;
3926         }
3927         if (c1=='='&&c2<' ') { /* this is soft wrap */
3928             while((c1 =  (*i_mgetc)(f)) <=' ') {
3929                 if ((c1 = (*i_mgetc)(f)) == EOF) return (EOF);
3930             }
3931             mime_decode_mode = 'Q'; /* still in MIME */
3932             goto restart_mime_q;
3933         }
3934         if (c1=='?') {
3935             mime_decode_mode = 'Q'; /* still in MIME */
3936             (*i_mungetc)(c2,f);
3937             return c1;
3938         }
3939         if ((c3 = (*i_mgetc)(f)) == EOF) return (EOF);
3940         if (c2<=' ') return c2;
3941         mime_decode_mode = 'Q'; /* still in MIME */
3942 #define hex(c)   (('0'<=c&&c<='9')?(c-'0'):\
3943      ('A'<=c&&c<='F')?(c-'A'+10):('a'<=c&&c<='f')?(c-'a'+10):0)
3944         return ((hex(c2)<<4) + hex(c3));
3945     }
3946
3947     if (mime_decode_mode != 'B') {
3948         mime_decode_mode = FALSE;
3949         return (*i_mgetc)(f);
3950     }
3951
3952
3953     /* Base64 encoding */
3954     /* 
3955         MIME allows line break in the middle of 
3956         Base64, but we are very pessimistic in decoding
3957         in unbuf mode because MIME encoded code may broken by 
3958         less or editor's control sequence (such as ESC-[-K in unbuffered
3959         mode. ignore incomplete MIME.
3960     */
3961     mode = mime_decode_mode;
3962     mime_decode_mode = exit_mode;  /* prepare for quit */
3963
3964     while ((c1 = (*i_mgetc)(f))<=' ') {
3965         if (c1==EOF)
3966             return (EOF);
3967     }
3968 mime_c2_retry:
3969     if ((c2 = (*i_mgetc)(f))<=' ') {
3970         if (c2==EOF)
3971             return (EOF);
3972         if (mime_f != STRICT_MIME) goto mime_c2_retry;
3973         if (mimebuf_f!=FIXED_MIME) input_mode = ASCII;  
3974         return c2;
3975     }
3976     if ((c1 == '?') && (c2 == '=')) {
3977         input_mode = ASCII;
3978         lwsp_count = 0;
3979         lwsp_buf = malloc((lwsp_size+5)*sizeof(char));
3980         if (lwsp_buf==NULL) {
3981             perror("can't malloc");
3982             return -1;
3983         }
3984         while ((c1=(*i_getc)(f))!=EOF) {
3985             switch (c1) {
3986             case NL:
3987             case CR:
3988                 if (c1==NL) {
3989                     if ((c1=(*i_getc)(f))!=EOF && (c1==SPACE||c1==TAB)) {
3990                         i_ungetc(SPACE,f);
3991                         continue;
3992                     } else {
3993                         i_ungetc(c1,f);
3994                     }
3995                     c1 = NL;
3996                 } else {
3997                     if ((c1=(*i_getc)(f))!=EOF) {
3998                         if (c1==SPACE) {
3999                             i_ungetc(SPACE,f);
4000                             continue;
4001                         } else if ((c1=(*i_getc)(f))!=EOF && (c1==SPACE||c1==TAB)) {
4002                             i_ungetc(SPACE,f);
4003                             continue;
4004                         } else {
4005                             i_ungetc(c1,f);
4006                         }
4007                         i_ungetc(NL,f);
4008                     } else {
4009                         i_ungetc(c1,f);
4010                     }
4011                     c1 = CR;
4012                 }
4013                 break;
4014             case SPACE:
4015             case TAB:
4016                 lwsp_buf[lwsp_count] = c1;
4017                 if (lwsp_count++>lwsp_size){
4018                     lwsp_size *= 2;
4019                     lwsp_buf_new = realloc(lwsp_buf, (lwsp_size+5)*sizeof(char));
4020                     if (lwsp_buf_new==NULL) {
4021                         free(lwsp_buf);
4022                         lwsp_buf = NULL;
4023                         perror("can't realloc");
4024                         return -1;
4025                     }
4026                     lwsp_buf = lwsp_buf_new;
4027                 }
4028                 continue;
4029             }
4030             break;
4031         }
4032         if (lwsp_count > 0) {
4033             if (c1=='=' && (lwsp_buf[lwsp_count-1]==SPACE||lwsp_buf[lwsp_count-1]==TAB)) {
4034                 lwsp_count = 0;
4035             } else {
4036                 i_ungetc(c1,f);
4037                 for(lwsp_count--;lwsp_count>0;lwsp_count--)
4038                     i_ungetc(lwsp_buf[lwsp_count],f);
4039                 c1 = lwsp_buf[0];
4040             }
4041         }
4042         free(lwsp_buf);
4043         lwsp_buf = NULL;
4044         return c1;
4045     }
4046 mime_c3_retry:
4047     if ((c3 = (*i_mgetc)(f))<=' ') {
4048         if (c3==EOF)
4049             return (EOF);
4050         if (mime_f != STRICT_MIME) goto mime_c3_retry;
4051         if (mimebuf_f!=FIXED_MIME) input_mode = ASCII;  
4052         return c3;
4053     }
4054 mime_c4_retry:
4055     if ((c4 = (*i_mgetc)(f))<=' ') {
4056         if (c4==EOF)
4057             return (EOF);
4058         if (mime_f != STRICT_MIME) goto mime_c4_retry;
4059         if (mimebuf_f!=FIXED_MIME) input_mode = ASCII;  
4060         return c4;
4061     }
4062
4063     mime_decode_mode = mode; /* still in MIME sigh... */
4064
4065     /* BASE 64 decoding */
4066
4067     t1 = 0x3f & base64decode(c1);
4068     t2 = 0x3f & base64decode(c2);
4069     t3 = 0x3f & base64decode(c3);
4070     t4 = 0x3f & base64decode(c4);
4071     cc = ((t1 << 2) & 0x0fc) | ((t2 >> 4) & 0x03);
4072     if (c2 != '=') {
4073         Fifo(mime_last++) = cc;
4074         cc = ((t2 << 4) & 0x0f0) | ((t3 >> 2) & 0x0f);
4075         if (c3 != '=') {
4076             Fifo(mime_last++) = cc;
4077             cc = ((t3 << 6) & 0x0c0) | (t4 & 0x3f);
4078             if (c4 != '=') 
4079                 Fifo(mime_last++) = cc;
4080         }
4081     } else {
4082         return c1;
4083     }
4084     return  Fifo(mime_top++);
4085 }
4086
4087 int
4088 mime_ungetc(c,f) 
4089 int   c;
4090 FILE  *f;
4091 {
4092     Fifo(--mime_top) = c;
4093     return c;
4094 }
4095
4096 int
4097 mime_integrity(f,p)
4098 FILE *f;
4099 unsigned char *p;
4100 {
4101     int c,d;
4102     unsigned int q;
4103     /* In buffered mode, read until =? or NL or buffer full
4104      */
4105     mime_input = mime_top;
4106     mime_last = mime_top;
4107     while(*p) Fifo(mime_input++) = *p++;
4108     d = 0;
4109     q = mime_input;
4110     while((c=(*i_getc)(f))!=EOF) {
4111         if (((mime_input-mime_top)&MIME_BUF_MASK)==0) {
4112             break;   /* buffer full */
4113         }
4114         if (c=='=' && d=='?') {
4115             /* checked. skip header, start decode */
4116             Fifo(mime_input++) = c;
4117             /* mime_last_input = mime_input; */
4118             mime_input = q; 
4119             switch_mime_getc();
4120             return 1;
4121         }
4122         if (!( (c=='+'||c=='/'|| c=='=' || c=='?' || is_alnum(c))))
4123             break;
4124         /* Should we check length mod 4? */
4125         Fifo(mime_input++) = c;
4126         d=c;
4127     }
4128     /* In case of Incomplete MIME, no MIME decode  */
4129     Fifo(mime_input++) = c;
4130     mime_last = mime_input;     /* point undecoded buffer */
4131     mime_decode_mode = 1;              /* no decode on Fifo last in mime_getc */
4132     switch_mime_getc();         /* anyway we need buffered getc */
4133     return 1;
4134 }
4135
4136 int
4137 base64decode(c)
4138     int            c;
4139 {
4140     int             i;
4141     if (c > '@') {
4142         if (c < '[') {
4143             i = c - 'A';                        /* A..Z 0-25 */
4144         } else {
4145             i = c - 'G'     /* - 'a' + 26 */ ;  /* a..z 26-51 */
4146         }
4147     } else if (c > '/') {
4148         i = c - '0' + '4'   /* - '0' + 52 */ ;  /* 0..9 52-61 */
4149     } else if (c == '+') {
4150         i = '>'             /* 62 */ ;          /* +  62 */
4151     } else {
4152         i = '?'             /* 63 */ ;          /* / 63 */
4153     }
4154     return (i);
4155 }
4156
4157 static char basis_64[] =
4158    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4159
4160 static int b64c;
4161 #define MIMEOUT_BUF_LENGTH (60)
4162 char mimeout_buf[MIMEOUT_BUF_LENGTH+1];
4163 int mimeout_buf_count = 0;
4164 int mimeout_preserve_space = 0;
4165 #define itoh4(c)   (c>=10?c+'A'-10:c+'0')
4166
4167 void
4168 open_mime(mode)
4169 int mode;
4170 {
4171     unsigned char *p;
4172     int i;
4173     int j;
4174     p  = mime_pattern[0];
4175     for(i=0;mime_encode[i];i++) {
4176         if (mode == mime_encode[i]) {
4177             p = mime_pattern[i];
4178             break;
4179         }
4180     }
4181     mimeout_mode = mime_encode_method[i];
4182     
4183     i = 0;
4184     if (base64_count>45) {
4185         (*o_mputc)(NL);
4186         (*o_mputc)(SPACE);
4187         base64_count = 1;
4188         if (!mimeout_preserve_space && mimeout_buf_count>0
4189             && (mimeout_buf[i]==SPACE || mimeout_buf[i]==TAB
4190                 || mimeout_buf[i]==CR || mimeout_buf[i]==NL )) {
4191             i++;
4192         }
4193     }
4194     if (!mimeout_preserve_space) {
4195         for (;i<mimeout_buf_count;i++) {
4196             if (mimeout_buf[i]==SPACE || mimeout_buf[i]==TAB
4197                 || mimeout_buf[i]==CR || mimeout_buf[i]==NL ) {
4198                 (*o_mputc)(mimeout_buf[i]);
4199                 base64_count ++;
4200             } else {
4201                 break;
4202             }
4203         }
4204     }
4205     mimeout_preserve_space = FALSE;
4206     
4207     while(*p) {
4208         (*o_mputc)(*p++);
4209         base64_count ++;
4210     }
4211     j = mimeout_buf_count;
4212     mimeout_buf_count = 0;
4213     for (;i<j;i++) {
4214         mime_putc(mimeout_buf[i]);
4215     }
4216 }
4217
4218 void
4219 close_mime()
4220 {
4221     (*o_mputc)('?');
4222     (*o_mputc)('=');
4223     base64_count += 2;
4224     mimeout_mode = 0;
4225 }
4226
4227 void
4228 eof_mime()
4229 {
4230     switch(mimeout_mode) {
4231     case 'Q':
4232     case 'B':
4233         break;
4234     case 2:
4235         (*o_mputc)(basis_64[((b64c & 0x3)<< 4)]);
4236         (*o_mputc)('=');
4237         (*o_mputc)('=');
4238         base64_count += 3;
4239         break;
4240     case 1:
4241         (*o_mputc)(basis_64[((b64c & 0xF) << 2)]);
4242         (*o_mputc)('=');
4243         base64_count += 2;
4244         break;
4245     }
4246     if (mimeout_mode) {
4247         if (mimeout_f!=FIXED_MIME) {
4248             close_mime(); 
4249         } else if (mimeout_mode != 'Q')
4250             mimeout_mode = 'B';
4251     }
4252 }
4253
4254 void
4255 mimeout_addchar(c)
4256     int            c;
4257 {
4258     switch(mimeout_mode) {
4259     case 'Q':
4260         if(c>=DEL) {
4261             (*o_mputc)('=');
4262             (*o_mputc)(itoh4(((c>>4)&0xf)));
4263             (*o_mputc)(itoh4((c&0xf)));
4264             base64_count += 3;
4265         } else {
4266             (*o_mputc)(c);
4267             base64_count++;
4268         }
4269         break;
4270     case 'B':
4271         b64c=c;
4272         (*o_mputc)(basis_64[c>>2]);
4273         mimeout_mode=2;
4274         base64_count ++;
4275         break;
4276     case 2:
4277         (*o_mputc)(basis_64[((b64c & 0x3)<< 4) | ((c & 0xF0) >> 4)]);
4278         b64c=c;
4279         mimeout_mode=1;
4280         base64_count ++;
4281         break;
4282     case 1:
4283         (*o_mputc)(basis_64[((b64c & 0xF) << 2) | ((c & 0xC0) >>6)]);
4284         (*o_mputc)(basis_64[c & 0x3F]);
4285         mimeout_mode='B';
4286         base64_count += 2;
4287         break;
4288     }
4289 }
4290
4291 void
4292 mime_putc(c)
4293     int            c;
4294 {
4295     int i = 0;
4296     int j = 0;
4297     
4298     if (mimeout_f==FIXED_MIME && base64_count>50) {
4299         eof_mime();
4300         (*o_mputc)(NL);
4301         base64_count=0;
4302     } else if (c==CR||c==NL) {
4303         base64_count=0;
4304     }
4305     if (c!=EOF && mimeout_f!=FIXED_MIME) {
4306         if ( c<=DEL &&(output_mode==ASCII ||output_mode == ISO8859_1 ) ) {
4307             if (mimeout_mode=='Q') {
4308                 if (c<=SPACE) {
4309                     close_mime();
4310                     (*o_mputc)(SPACE);
4311                     base64_count++;
4312                 }
4313                 (*o_mputc)(c);
4314                 base64_count++;
4315                 return;
4316             } else if (mimeout_mode) {
4317                 if (base64_count>63) {
4318                     eof_mime();
4319                     (*o_mputc)(NL);
4320                     (*o_mputc)(SPACE);
4321                     base64_count=1;
4322                     mimeout_preserve_space = TRUE;
4323                 }
4324                 if (c==SPACE || c==TAB || c==CR || c==NL) {
4325                     for (i=0;i<mimeout_buf_count;i++) {
4326                         if (SPACE<mimeout_buf[i] && mimeout_buf[i]<DEL) {
4327                             eof_mime();
4328                             for (i=0;i<mimeout_buf_count;i++) {
4329                                 (*o_mputc)(mimeout_buf[i]);
4330                                 base64_count++;
4331                             }
4332                             mimeout_buf_count = 0;
4333                         }
4334                     }
4335                     mimeout_buf[mimeout_buf_count++] = c;
4336                     if (mimeout_buf_count>MIMEOUT_BUF_LENGTH) {
4337                         eof_mime();
4338                         base64_count = 0;
4339                         for (i=0;i<mimeout_buf_count;i++) {
4340                             (*o_mputc)(mimeout_buf[i]);
4341                             base64_count++;
4342                         }
4343                     }
4344                     return;
4345                 }
4346                 if (mimeout_buf_count>0 && SPACE<c) {
4347                     mimeout_buf[mimeout_buf_count++] = c;
4348                     if (mimeout_buf_count>MIMEOUT_BUF_LENGTH) {
4349                     } else {
4350                         return;
4351                     }
4352                 }
4353             } else if (!mimeout_mode) {
4354                 if (c==SPACE || c==TAB || c==CR || c==NL) {
4355                     if ((c==CR || c==NL)
4356                         &&(mimeout_buf[mimeout_buf_count-1]==SPACE
4357                            || mimeout_buf[mimeout_buf_count-1]==TAB)) {
4358                         mimeout_buf_count--;
4359                     }
4360                     for (i=0;i<mimeout_buf_count;i++) {
4361                         (*o_mputc)(mimeout_buf[i]);
4362                         base64_count++;
4363                     }
4364                     mimeout_buf_count = 0;
4365                 }
4366                 mimeout_buf[mimeout_buf_count++] = c;
4367                 if (mimeout_buf_count>75) {
4368                     open_mime(output_mode);
4369                 }
4370                 return;
4371             }
4372         } else if (!mimeout_mode) {
4373             if (mimeout_buf_count>0 && mimeout_buf[mimeout_buf_count-1]==SPACE) {
4374                 for (i=0;i<mimeout_buf_count-1;i++) {
4375                     (*o_mputc)(mimeout_buf[i]);
4376                     base64_count++;
4377                 }
4378                 mimeout_buf[0] = SPACE;
4379                 mimeout_buf_count = 1;
4380             }
4381             open_mime(output_mode);
4382         }
4383     } else { /* c==EOF */
4384         j = mimeout_buf_count;
4385         i = 0;
4386         for (;i<j;i++) {
4387             if (mimeout_buf[i]==SPACE || mimeout_buf[i]==TAB
4388                 || mimeout_buf[i]==CR || mimeout_buf[i]==NL)
4389                 break;
4390             (*mime_putc)(mimeout_buf[i]);
4391         }
4392         eof_mime();
4393         for (;i<j;i++) {
4394             (*o_mputc)(mimeout_buf[i]);
4395             base64_count++;
4396         }
4397         return;
4398     }
4399     
4400     if (mimeout_buf_count>0) {
4401         j = mimeout_buf_count;
4402         mimeout_buf_count = 0;
4403         for (i=0;i<j;i++) {
4404             mimeout_addchar(mimeout_buf[i]);
4405         }
4406     }
4407     mimeout_addchar(c);
4408 }
4409
4410
4411 #ifdef PERL_XS
4412 void 
4413 reinit()
4414 {
4415     {
4416         struct input_code *p = input_code_list;
4417         while (p->name){
4418             status_reinit(p++);
4419         }
4420     }
4421     unbuf_f = FALSE;
4422     estab_f = FALSE;
4423     nop_f = FALSE;
4424     binmode_f = TRUE;
4425     rot_f = FALSE;
4426     hira_f = FALSE;
4427     input_f = FALSE;
4428     alpha_f = FALSE;
4429     mime_f = STRICT_MIME;
4430     mimebuf_f = FALSE;
4431     broken_f = FALSE;
4432     iso8859_f = FALSE;
4433     mimeout_f = FALSE;
4434 #if defined(MSDOS) || defined(__OS2__)
4435      x0201_f = TRUE;
4436 #else
4437      x0201_f = NO_X0201;
4438 #endif
4439     iso2022jp_f = FALSE;
4440 #ifdef UTF8_OUTPUT_ENABLE
4441     unicode_bom_f = 0;
4442     w_oconv16_LE = 0;
4443     ms_ucs_map_f = FALSE;
4444 #endif
4445 #ifdef INPUT_OPTION
4446     cap_f = FALSE;
4447     url_f = FALSE;
4448     numchar_f = FALSE;
4449 #endif
4450 #ifdef CHECK_OPTION
4451     noout_f = FALSE;
4452     debug_f = FALSE;
4453 #endif
4454     guess_f = FALSE;
4455     is_inputcode_mixed = FALSE;
4456     is_inputcode_set   = FALSE;
4457 #ifdef EXEC_IO
4458     exec_f = 0;
4459 #endif
4460 #ifdef SHIFTJIS_CP932
4461     cp932_f = TRUE;
4462     cp932inv_f = TRUE;
4463 #endif
4464     {
4465         int i;
4466         for (i = 0; i < 256; i++){
4467             prefix_table[i] = 0;
4468         }
4469     }
4470 #ifdef UTF8_INPUT_ENABLE
4471     utf16_mode = UTF16LE_INPUT;
4472 #endif
4473     mimeout_buf_count = 0;
4474     mimeout_mode = 0;
4475     base64_count = 0;
4476     f_line = 0;
4477     f_prev = 0;
4478     fold_preserve_f = FALSE;
4479     fold_f = FALSE;
4480     fold_len = 0;
4481     kanji_intro = DEFAULT_J;
4482     ascii_intro = DEFAULT_R;
4483