OSDN Git Service

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