OSDN Git Service

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