OSDN Git Service

* improve mime encode
[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.40 2004/11/19 15:18:43 naruse 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 #ifdef PERL_XS
1664 #define STD_GC_BUFSIZE (256)
1665 int std_gc_buf[STD_GC_BUFSIZE];
1666 int std_gc_ndx;
1667 #endif
1668
1669 int 
1670 std_getc(f)
1671 FILE *f;
1672 {
1673 #ifdef PERL_XS
1674     if (std_gc_ndx){
1675         return std_gc_buf[--std_gc_ndx];
1676     }
1677 #endif
1678     return getc(f);
1679 }
1680
1681 int 
1682 std_ungetc(c,f)
1683 int c;
1684 FILE *f;
1685 {
1686 #ifdef PERL_XS
1687     if (std_gc_ndx == STD_GC_BUFSIZE){
1688         return EOF;
1689     }
1690     std_gc_buf[std_gc_ndx++] = c;
1691     return c;
1692 #endif
1693     return ungetc(c,f);
1694 }
1695
1696 void 
1697 std_putc(c)
1698 int c;
1699 {
1700     if(c!=EOF)
1701       putchar(c);
1702 }
1703
1704 int
1705 noconvert(f)
1706     FILE  *f;
1707 {
1708     int    c;
1709
1710     while ((c = (*i_getc)(f)) != EOF)
1711       (*o_putc)(c);
1712     return 1;
1713 }
1714
1715
1716 void
1717 module_connection()
1718 {
1719     oconv = output_conv; 
1720     o_putc = std_putc;
1721
1722     /* replace continucation module, from output side */
1723
1724     /* output redicrection */
1725 #ifdef CHECK_OPTION
1726     if (noout_f || guess_f){
1727         o_putc = no_putc;
1728     }
1729 #endif
1730     if (mimeout_f) {
1731         o_mputc = o_putc;
1732         o_putc = mime_putc;
1733         if (mimeout_f == TRUE) {
1734             o_base64conv = oconv; oconv = base64_conv;
1735         }
1736         /* base64_count = 0; */
1737     }
1738
1739     if (crmode_f) {
1740         o_crconv = oconv; oconv = cr_conv;
1741     }
1742     if (rot_f) {
1743         o_rot_conv = oconv; oconv = rot_conv;
1744     }
1745     if (iso2022jp_f) {
1746         o_iso2022jp_check_conv = oconv; oconv = iso2022jp_check_conv;
1747     }
1748     if (hira_f) {
1749         o_hira_conv = oconv; oconv = hira_conv;
1750     }
1751     if (fold_f) {
1752         o_fconv = oconv; oconv = fold_conv;
1753         f_line = 0;
1754     }
1755     if (alpha_f || x0201_f) {
1756         o_zconv = oconv; oconv = z_conv;
1757     }
1758
1759     i_getc = std_getc;
1760     i_ungetc = std_ungetc;
1761     /* input redicrection */
1762 #ifdef INPUT_OPTION
1763     if (cap_f){
1764         i_cgetc = i_getc; i_getc = cap_getc;
1765         i_cungetc = i_ungetc; i_ungetc= cap_ungetc;
1766     }
1767     if (url_f){
1768         i_ugetc = i_getc; i_getc = url_getc;
1769         i_uungetc = i_ungetc; i_ungetc= url_ungetc;
1770     }
1771 #endif
1772 #ifdef NUMCHAR_OPTION
1773     if (numchar_f){
1774         i_ngetc = i_getc; i_getc = numchar_getc;
1775         i_nungetc = i_ungetc; i_ungetc= numchar_ungetc;
1776     }
1777 #endif
1778     if (mime_f && mimebuf_f==FIXED_MIME) {
1779         i_mgetc = i_getc; i_getc = mime_getc;
1780         i_mungetc = i_ungetc; i_ungetc = mime_ungetc;
1781     }
1782     if (broken_f & 1) {
1783         i_bgetc = i_getc; i_getc = broken_getc;
1784         i_bungetc = i_ungetc; i_ungetc = broken_ungetc;
1785     }
1786     if (input_f == JIS_INPUT || input_f == LATIN1_INPUT) {
1787         set_iconv(-TRUE, e_iconv);
1788     } else if (input_f == SJIS_INPUT) {
1789         set_iconv(-TRUE, s_iconv);
1790 #ifdef UTF8_INPUT_ENABLE
1791     } else if (input_f == UTF8_INPUT) {
1792         set_iconv(-TRUE, w_iconv);
1793     } else if (input_f == UTF16LE_INPUT) {
1794         set_iconv(-TRUE, w_iconv16);
1795 #endif
1796     } else {
1797         set_iconv(FALSE, e_iconv);
1798     }
1799
1800     {
1801         struct input_code *p = input_code_list;
1802         while (p->name){
1803             status_reinit(p++);
1804         }
1805     }
1806 }
1807
1808 /*
1809    Conversion main loop. Code detection only. 
1810  */
1811
1812 int
1813 kanji_convert(f)
1814     FILE  *f;
1815 {
1816     int    c1,
1817                     c2, c3;
1818
1819     module_connection();
1820     c2 = 0;
1821
1822
1823     input_mode = ASCII;
1824     output_mode = ASCII;
1825     shift_mode = FALSE;
1826
1827 #define NEXT continue      /* no output, get next */
1828 #define SEND ;             /* output c1 and c2, get next */
1829 #define LAST break         /* end of loop, go closing  */
1830
1831     while ((c1 = (*i_getc)(f)) != EOF) {
1832         code_status(c1);
1833         if (c2) {
1834             /* second byte */
1835             if (c2 > DEL) {
1836                 /* in case of 8th bit is on */
1837                 if (!estab_f) {
1838                     /* in case of not established yet */
1839                     /* It is still ambiguious */
1840                     if (h_conv(f, c2, c1)==EOF) 
1841                         LAST;
1842                     else 
1843                         c2 = 0;
1844                     NEXT;
1845                 } else
1846                     /* in case of already established */
1847                     if (c1 < AT) {
1848                         /* ignore bogus code */
1849                         c2 = 0;
1850                         NEXT;
1851                     } else
1852                         SEND;
1853             } else
1854                 /* second byte, 7 bit code */
1855                 /* it might be kanji shitfted */
1856                 if ((c1 == DEL) || (c1 <= SPACE)) {
1857                     /* ignore bogus first code */
1858                     c2 = 0;
1859                     NEXT;
1860                 } else
1861                     SEND;
1862         } else {
1863             /* first byte */
1864             if (
1865 #ifdef UTF8_INPUT_ENABLE
1866                 iconv == w_iconv16
1867 #else
1868                 0
1869 #endif
1870                 ) {
1871                 c2 = c1;
1872                 c1 = (*i_getc)(f);
1873                 SEND;
1874 #ifdef NUMCHAR_OPTION
1875             } else if ((c1 & CLASS_MASK) == CLASS_UTF16){
1876                 SEND;
1877 #endif
1878             } else if (c1 > DEL) {
1879                 /* 8 bit code */
1880                 if (!estab_f && !iso8859_f) {
1881                     /* not established yet */
1882                     c2 = c1;
1883                     NEXT;
1884                 } else { /* estab_f==TRUE */
1885                     if (iso8859_f) {
1886                         c2 = ISO8859_1;
1887                         c1 &= 0x7f;
1888                         SEND;
1889                     } else if (SSP<=c1 && c1<0xe0 && iconv == s_iconv) {
1890                         /* SJIS X0201 Case... */
1891                         if(iso2022jp_f && x0201_f==NO_X0201) {
1892                             (*oconv)(GETA1, GETA2);
1893                             NEXT;
1894                         } else {
1895                             c2 = X0201;
1896                             c1 &= 0x7f;
1897                             SEND;
1898                         }
1899                     } else if (c1==SSO && iconv != s_iconv) {
1900                         /* EUC X0201 Case */
1901                         c1 = (*i_getc)(f);  /* skip SSO */
1902                         code_status(c1);
1903                         if (SSP<=c1 && c1<0xe0) {
1904                             if(iso2022jp_f &&  x0201_f==NO_X0201) {
1905                                 (*oconv)(GETA1, GETA2);
1906                                 NEXT;
1907                             } else {
1908                                 c2 = X0201;
1909                                 c1 &= 0x7f;
1910                                 SEND;
1911                             }
1912                         } else  { /* bogus code, skip SSO and one byte */
1913                             NEXT;
1914                         }
1915                     } else {
1916                        /* already established */
1917                        c2 = c1;
1918                        NEXT;
1919                     }
1920                 }
1921             } else if ((c1 > SPACE) && (c1 != DEL)) {
1922                 /* in case of Roman characters */
1923                 if (shift_mode) { 
1924                     /* output 1 shifted byte */
1925                     if (iso8859_f) {
1926                         c2 = ISO8859_1;
1927                         SEND;
1928                     } else if (SPACE<=c1 && c1<(0xe0&0x7f) ){
1929                       /* output 1 shifted byte */
1930                         if(iso2022jp_f && x0201_f==NO_X0201) {
1931                             (*oconv)(GETA1, GETA2);
1932                             NEXT;
1933                         } else {
1934                             c2 = X0201;
1935                             SEND;
1936                         }
1937                     } else {
1938                         /* look like bogus code */
1939                         NEXT;
1940                     }
1941                 } else if (input_mode == X0208) {
1942                     /* in case of Kanji shifted */
1943                     c2 = c1;
1944                     NEXT;
1945                 } else if (c1 == '=' && mime_f && !mime_decode_mode ) {
1946                     /* Check MIME code */
1947                     if ((c1 = (*i_getc)(f)) == EOF) {
1948                         (*oconv)(0, '=');
1949                         LAST;
1950                     } else if (c1 == '?') {
1951                         /* =? is mime conversion start sequence */
1952                         if(mime_f == STRICT_MIME) {
1953                             /* check in real detail */
1954                             if (mime_begin_strict(f) == EOF) 
1955                                 LAST;
1956                             else
1957                                 NEXT;
1958                         } else if (mime_begin(f) == EOF) 
1959                             LAST;
1960                         else
1961                             NEXT;
1962                     } else {
1963                         (*oconv)(0, '=');
1964                         (*i_ungetc)(c1,f);
1965                         NEXT;
1966                     }
1967                 } else {
1968                     /* normal ASCII code */ 
1969                     SEND;
1970                 }
1971             } else if (c1 == SI) {
1972                 shift_mode = FALSE; 
1973                 NEXT;
1974             } else if (c1 == SO) {
1975                 shift_mode = TRUE; 
1976                 NEXT;
1977             } else if (c1 == ESC ) {
1978                 if ((c1 = (*i_getc)(f)) == EOF) {
1979                     /*  (*oconv)(0, ESC); don't send bogus code */
1980                     LAST;
1981                 } else if (c1 == '$') {
1982                     if ((c1 = (*i_getc)(f)) == EOF) {
1983                         /*
1984                         (*oconv)(0, ESC); don't send bogus code 
1985                         (*oconv)(0, '$'); */
1986                         LAST;
1987                     } else if (c1 == '@'|| c1 == 'B') {
1988                         /* This is kanji introduction */
1989                         input_mode = X0208;
1990                         shift_mode = FALSE;
1991                         set_input_codename("ISO-2022-JP");
1992                         debug(input_codename);
1993                         NEXT;
1994                     } else if (c1 == '(') {
1995                         if ((c1 = (*i_getc)(f)) == EOF) {
1996                             /* don't send bogus code 
1997                             (*oconv)(0, ESC);
1998                             (*oconv)(0, '$');
1999                             (*oconv)(0, '(');
2000                                 */
2001                             LAST;
2002                         } else if (c1 == '@'|| c1 == 'B') {
2003                             /* This is kanji introduction */
2004                             input_mode = X0208;
2005                             shift_mode = FALSE;
2006                             NEXT;
2007                         } else {
2008                             /* could be some special code */
2009                             (*oconv)(0, ESC);
2010                             (*oconv)(0, '$');
2011                             (*oconv)(0, '(');
2012                             (*oconv)(0, c1);
2013                             NEXT;
2014                         }
2015                     } else if (broken_f&0x2) {
2016                         /* accept any ESC-(-x as broken code ... */
2017                         input_mode = X0208;
2018                         shift_mode = FALSE;
2019                         NEXT;
2020                     } else {
2021                         (*oconv)(0, ESC);
2022                         (*oconv)(0, '$');
2023                         (*oconv)(0, c1);
2024                         NEXT;
2025                     }
2026                 } else if (c1 == '(') {
2027                     if ((c1 = (*i_getc)(f)) == EOF) {
2028                         /* don't send bogus code 
2029                         (*oconv)(0, ESC);
2030                         (*oconv)(0, '('); */
2031                         LAST;
2032                     } else {
2033                         if (c1 == 'I') {
2034                             /* This is X0201 kana introduction */
2035                             input_mode = X0201; shift_mode = X0201;
2036                             NEXT;
2037                         } else if (c1 == 'B' || c1 == 'J' || c1 == 'H') {
2038                             /* This is X0208 kanji introduction */
2039                             input_mode = ASCII; shift_mode = FALSE;
2040                             NEXT;
2041                         } else if (broken_f&0x2) {
2042                             input_mode = ASCII; shift_mode = FALSE;
2043                             NEXT;
2044                         } else {
2045                             (*oconv)(0, ESC);
2046                             (*oconv)(0, '(');
2047                             /* maintain various input_mode here */
2048                             SEND;
2049                         }
2050                     }
2051                } else if ( c1 == 'N' || c1 == 'n' ){
2052                    /* SS2 */
2053                    c3 = (*i_getc)(f);  /* skip SS2 */
2054                    if ( (SPACE<=c3 && c3 < 0x60) || (0xa0<=c3 && c3 < 0xe0)){
2055                        c1 = c3;
2056                        c2 = X0201;
2057                        SEND;
2058                    }else{
2059                        (*i_ungetc)(c3, f);
2060                        /* lonely ESC  */
2061                        (*oconv)(0, ESC);
2062                        SEND;
2063                    }
2064                 } else {
2065                     /* lonely ESC  */
2066                     (*oconv)(0, ESC);
2067                     SEND;
2068                 }
2069             } else if ((c1 == NL || c1 == CR) && broken_f&4) {
2070                 input_mode = ASCII; set_iconv(FALSE, 0);
2071                 SEND;
2072             } else if (c1 == NL && mime_f && !mime_decode_mode ) {
2073                 if ((c1=(*i_getc)(f))!=EOF && c1 == SPACE) {
2074                     i_ungetc(SPACE,f);
2075                     continue;
2076                 } else {
2077                     i_ungetc(c1,f);
2078                 }
2079                 c1 = NL;
2080                 SEND;
2081             } else if (c1 == CR && mime_f && !mime_decode_mode ) {
2082                 if ((c1=(*i_getc)(f))!=EOF) {
2083                     if (c1==SPACE) {
2084                         i_ungetc(SPACE,f);
2085                         continue;
2086                     } else if (c1 == NL && (c1=(*i_getc)(f))!=EOF && c1 == SPACE) {
2087                         i_ungetc(SPACE,f);
2088                         continue;
2089                     } else {
2090                         i_ungetc(c1,f);
2091                     }
2092                     i_ungetc(NL,f);
2093                 } else {
2094                     i_ungetc(c1,f);
2095                 }
2096                 c1 = CR;
2097                 SEND;
2098             } else 
2099                 SEND;
2100         }
2101         /* send: */
2102         if (input_mode == X0208) 
2103             (*oconv)(c2, c1);  /* this is JIS, not SJIS/EUC case */
2104         else if (input_mode) 
2105             (*oconv)(input_mode, c1);  /* other special case */
2106         else if ((*iconv)(c2, c1, 0) < 0){  /* can be EUC/SJIS */
2107             int c0 = (*i_getc)(f);
2108             if (c0 != EOF){
2109                 code_status(c0);
2110                 (*iconv)(c2, c1, c0);
2111             }
2112         }
2113
2114         c2 = 0;
2115         continue;
2116         /* goto next_word */
2117     }
2118
2119     /* epilogue */
2120     (*iconv)(EOF, 0, 0);
2121     return 1;
2122 }
2123
2124 int
2125 h_conv(f, c2, c1)
2126     FILE  *f;
2127     int    c1,
2128                     c2;
2129 {
2130     int    wc,c3;
2131
2132
2133     /** it must NOT be in the kanji shifte sequence      */
2134     /** it must NOT be written in JIS7                   */
2135     /** and it must be after 2 byte 8bit code            */
2136
2137     hold_count = 0;
2138     push_hold_buf(c2);
2139     push_hold_buf(c1);
2140     c2 = 0;
2141
2142     while ((c1 = (*i_getc)(f)) != EOF) {
2143         if (c1 == ESC){
2144             (*i_ungetc)(c1,f);
2145             break;
2146         }
2147         code_status(c1);
2148         if (push_hold_buf(c1) == EOF || estab_f){
2149             break;
2150         }
2151     }
2152
2153     if (!estab_f){
2154         struct input_code *p = input_code_list;
2155         struct input_code *result = p;
2156         if (c1 == EOF){
2157             code_status(c1);
2158         }
2159         while (p->name){
2160             if (p->score < result->score){
2161                 result = p;
2162             }
2163             ++p;
2164         }
2165         set_iconv(FALSE, result->iconv_func);
2166     }
2167
2168
2169     /** now,
2170      ** 1) EOF is detected, or
2171      ** 2) Code is established, or
2172      ** 3) Buffer is FULL (but last word is pushed)
2173      **
2174      ** in 1) and 3) cases, we continue to use
2175      ** Kanji codes by oconv and leave estab_f unchanged.
2176      **/
2177
2178     c3=c1;
2179     wc = 0;
2180     while (wc < hold_count){
2181         c2 = hold_buf[wc++];
2182         if (c2 <= DEL
2183 #ifdef NUMCHAR_OPTION
2184             || (c2 & CLASS_MASK) == CLASS_UTF16
2185 #endif
2186             ){
2187             (*iconv)(0, c2, 0);
2188             continue;
2189         }else if (iconv == s_iconv && 0xa1 <= c2 && c2 <= 0xdf){
2190             (*iconv)(X0201, c2, 0);
2191             continue;
2192         }
2193         if (wc < hold_count){
2194             c1 = hold_buf[wc++];
2195         }else{
2196             c1 = (*i_getc)(f);
2197             if (c1 == EOF){
2198                 c3 = EOF;
2199                 break;
2200             }
2201             code_status(c1);
2202         }
2203         if ((*iconv)(c2, c1, 0) < 0){
2204             int c0;
2205             if (wc < hold_count){
2206                 c0 = hold_buf[wc++];
2207             }else{
2208                 c0 = (*i_getc)(f);
2209                 if (c0 == EOF){
2210                     c3 = EOF;
2211                     break;
2212                 }
2213                 code_status(c0);
2214             }
2215             (*iconv)(c2, c1, c0);
2216             c1 = c0;
2217         }
2218     }
2219     return c3;
2220 }
2221
2222
2223
2224 int
2225 push_hold_buf(c2)
2226      int             c2;
2227 {
2228     if (hold_count >= HOLD_SIZE*2)
2229         return (EOF);
2230     hold_buf[hold_count++] = c2;
2231     return ((hold_count >= HOLD_SIZE*2) ? EOF : hold_count);
2232 }
2233
2234 int s2e_conv(c2, c1, p2, p1)
2235      int c2, c1;
2236      int *p2, *p1;
2237 {
2238 #ifdef SHIFTJIS_CP932
2239     if (cp932_f && CP932_TABLE_BEGIN <= c2 && c2 <= CP932_TABLE_END){
2240         extern unsigned short shiftjis_cp932[3][189];
2241         c1 = shiftjis_cp932[c2 - CP932_TABLE_BEGIN][c1 - 0x40];
2242         if (c1 == 0) return 1;
2243         c2 = c1 >> 8;
2244         c1 &= 0xff;
2245     }
2246 #endif /* SHIFTJIS_CP932 */
2247     c2 = c2 + c2 - ((c2 <= 0x9f) ? SJ0162 : SJ6394);
2248     if (c1 < 0x9f)
2249         c1 = c1 - ((c1 > DEL) ? SPACE : 0x1f);
2250     else {
2251         c1 = c1 - 0x7e;
2252         c2++;
2253     }
2254     if (p2) *p2 = c2;
2255     if (p1) *p1 = c1;
2256     return 0;
2257 }
2258
2259 int
2260 s_iconv(c2, c1, c0)
2261     int    c2,
2262                     c1, c0;
2263 {
2264     if (c2 == X0201) {
2265         c1 &= 0x7f;
2266     } else if ((c2 == EOF) || (c2 == 0) || c2 < SPACE) {
2267         /* NOP */
2268     } else {
2269         int ret = s2e_conv(c2, c1, &c2, &c1);
2270         if (ret) return ret;
2271     }
2272     (*oconv)(c2, c1);
2273     return 0;
2274 }
2275
2276 int
2277 e_iconv(c2, c1, c0)
2278     int    c2,
2279                     c1, c0;
2280 {
2281     if (c2 == X0201) {
2282         c1 &= 0x7f;
2283     } else if (c2 == SSO){
2284         c2 = X0201;
2285         c1 &= 0x7f;
2286     } else if ((c2 == EOF) || (c2 == 0) || c2 < SPACE) {
2287         /* NOP */
2288     } else {
2289         c1 &= 0x7f;
2290         c2 &= 0x7f;
2291     }
2292     (*oconv)(c2, c1);
2293     return 0;
2294 }
2295
2296 #ifdef UTF8_INPUT_ENABLE
2297 int
2298 w2e_conv(c2, c1, c0, p2, p1)
2299     int    c2, c1, c0;
2300     int *p2, *p1;
2301 {
2302     extern unsigned short * utf8_to_euc_2bytes[];
2303     extern unsigned short ** utf8_to_euc_3bytes[];
2304     int ret = 0;
2305
2306     if (0xc0 <= c2 && c2 <= 0xef) {
2307         unsigned short **pp;
2308
2309         if (0xe0 <= c2) {
2310             if (c0 == 0) return -1;
2311             pp = utf8_to_euc_3bytes[c2 - 0x80];
2312             ret = w_iconv_common(c1, c0, pp, sizeof_utf8_to_euc_C2, p2, p1);
2313         } else {
2314             ret =  w_iconv_common(c2, c1, utf8_to_euc_2bytes, sizeof_utf8_to_euc_2bytes, p2, p1);
2315         }
2316 #ifdef NUMCHAR_OPTION
2317         if (ret){
2318             if (p2) *p2 = 0;
2319             if (p1) *p1 = CLASS_UTF16 | ww16_conv(c2, c1, c0);
2320             ret = 0;
2321         }
2322 #endif
2323         return ret;
2324     } else if (c2 == X0201) {
2325         c1 &= 0x7f;
2326     }
2327     if (p2) *p2 = c2;
2328     if (p1) *p1 = c1;
2329     return ret;
2330 }
2331
2332 int
2333 w_iconv(c2, c1, c0)
2334     int    c2,
2335                     c1, c0;
2336 {
2337     int ret = w2e_conv(c2, c1, c0, &c2, &c1);
2338     if (ret == 0){
2339         (*oconv)(c2, c1);
2340     }
2341     return ret;
2342 }
2343
2344 void
2345 w16w_conv(val, p2, p1, p0)
2346      unsigned short val;
2347      int *p2, *p1, *p0;
2348 {
2349     if (val < 0x80){
2350         *p2 = val;
2351         *p1 = 0;
2352         *p0 = 0;
2353     }else if (val < 0x800){
2354         *p2 = 0xc0 | (val >> 6);
2355         *p1 = 0x80 | (val & 0x3f);
2356         *p0 = 0;
2357     }else{
2358         *p2 = 0xe0 | (val >> 12);
2359         *p1 = 0x80 | ((val >> 6) & 0x3f);
2360         *p0 = 0x80 | (val        & 0x3f);
2361     }
2362 }
2363
2364 int
2365 ww16_conv(c2, c1, c0)
2366      int c2, c1, c0;
2367 {
2368     unsigned short val;
2369     if (c2 >= 0xe0){
2370         val = (c2 & 0x0f) << 12;
2371         val |= (c1 & 0x3f) << 6;
2372         val |= (c0 & 0x3f);
2373     }else if (c2 >= 0xc0){
2374         val = (c2 & 0x1f) << 6;
2375         val |= (c1 & 0x3f) << 6;
2376     }else{
2377         val = c2;
2378     }
2379     return val;
2380 }
2381
2382 int
2383 w16e_conv(val, p2, p1)
2384      unsigned short val;
2385      int *p2, *p1;
2386 {
2387     extern unsigned short * utf8_to_euc_2bytes[];
2388     extern unsigned short ** utf8_to_euc_3bytes[];
2389     int c2, c1, c0;
2390     unsigned short **pp;
2391     int psize;
2392     int ret = 0;
2393
2394     w16w_conv(val, &c2, &c1, &c0);
2395     if (c1){
2396         if (c0){
2397             pp = utf8_to_euc_3bytes[c2 - 0x80];
2398             psize = sizeof_utf8_to_euc_C2;
2399             ret =  w_iconv_common(c1, c0, pp, psize, p2, p1);
2400         }else{
2401             pp = utf8_to_euc_2bytes;
2402             psize = sizeof_utf8_to_euc_2bytes;
2403             ret =  w_iconv_common(c2, c1, pp, psize, p2, p1);
2404         }
2405 #ifdef NUMCHAR_OPTION
2406         if (ret){
2407             *p2 = 0;
2408             *p1 = CLASS_UTF16 | val;
2409             ret = 0;
2410         }
2411 #endif
2412     }
2413     return ret;
2414 }
2415
2416 int
2417 w_iconv16(c2, c1, c0)
2418     int    c2, c1,c0;
2419 {
2420     int ret;
2421
2422     if (c2==0376 && c1==0377){
2423         utf16_mode = UTF16LE_INPUT;
2424         return 0;    
2425     } else if (c2==0377 && c1==0376){
2426         utf16_mode = UTF16BE_INPUT;
2427         return 0;    
2428     }
2429     if (c2 != EOF && utf16_mode == UTF16BE_INPUT) {
2430         int tmp;
2431         tmp=c1; c1=c2; c2=tmp;
2432     }
2433     if ((c2==0 && c1 < 0x80) || c2==EOF) {
2434         (*oconv)(c2, c1);
2435         return 0;
2436     }
2437     ret = w16e_conv(((c2<<8)&0xff00) + c1, &c2, &c1);
2438     if (ret) return ret;
2439     (*oconv)(c2, c1);
2440     return 0;
2441 }
2442
2443 int
2444 w_iconv_common(c1, c0, pp, psize, p2, p1)
2445     int    c1,c0;
2446     unsigned short **pp;
2447     int psize;
2448     int *p2, *p1;
2449 {
2450     int c2;
2451     unsigned short *p ;
2452     unsigned short val;
2453
2454     if (pp == 0) return 1;
2455
2456     c1 -= 0x80;
2457     if (c1 < 0 || psize <= c1) return 1;
2458     p = pp[c1];
2459     if (p == 0)  return 1;
2460
2461     c0 -= 0x80;
2462     if (c0 < 0 || sizeof_utf8_to_euc_E5B8 <= c0) return 1;
2463     val = p[c0];
2464     if (val == 0) return 1;
2465
2466     c2 = val >> 8;
2467     if (c2 == SO) c2 = X0201;
2468     c1 = val & 0x7f;
2469     if (p2) *p2 = c2;
2470     if (p1) *p1 = c1;
2471     return 0;
2472 }
2473
2474 #endif
2475
2476 #ifdef UTF8_OUTPUT_ENABLE
2477 int
2478 e2w_conv(c2, c1)
2479     int    c2, c1;
2480 {
2481     extern unsigned short euc_to_utf8_1byte[];
2482     extern unsigned short * euc_to_utf8_2bytes[];
2483     extern unsigned short * euc_to_utf8_2bytes_ms[];
2484     unsigned short *p;
2485
2486     if (c2 == X0201) {
2487         p = euc_to_utf8_1byte;
2488     } else {
2489         c2 &= 0x7f;
2490         c2 = (c2&0x7f) - 0x21;
2491         if (0<=c2 && c2<sizeof_euc_to_utf8_2bytes)
2492             p = ms_ucs_map_f ? euc_to_utf8_2bytes_ms[c2] : euc_to_utf8_2bytes[c2];
2493         else
2494             return 0;
2495     }
2496     if (!p) return 0;
2497     c1 = (c1 & 0x7f) - 0x21;
2498     if (0<=c1 && c1<sizeof_euc_to_utf8_1byte)
2499         return p[c1];
2500     return 0;
2501 }
2502
2503 void
2504 w_oconv(c2, c1)
2505     int    c2,
2506                     c1;
2507 {
2508     int c0;
2509 #ifdef NUMCHAR_OPTION
2510     if (c2 == 0 && (c1 & CLASS_MASK) == CLASS_UTF16){
2511         w16w_conv(c1, &c2, &c1, &c0);
2512         (*o_putc)(c2);
2513         if (c1){
2514             (*o_putc)(c1);
2515             if (c0) (*o_putc)(c0);
2516         }
2517     }
2518 #endif
2519     if (c2 == EOF) {
2520         (*o_putc)(EOF);
2521         return;
2522     }
2523
2524     if (unicode_bom_f==2) {
2525         (*o_putc)('\357');
2526         (*o_putc)('\273');
2527         (*o_putc)('\277');
2528         unicode_bom_f=1;
2529     }
2530
2531     if (c2 == 0) { 
2532         output_mode = ASCII;
2533         (*o_putc)(c1);
2534     } else if (c2 == ISO8859_1) {
2535         output_mode = ISO8859_1;
2536         (*o_putc)(c1 | 0x080);
2537     } else {
2538         output_mode = UTF8;
2539         w16w_conv((unsigned short)e2w_conv(c2, c1), &c2, &c1, &c0);
2540         (*o_putc)(c2);
2541         if (c1){
2542             (*o_putc)(c1);
2543             if (c0) (*o_putc)(c0);
2544         }
2545     }
2546 }
2547
2548 void
2549 w_oconv16(c2, c1)
2550     int    c2,
2551                     c1;
2552 {
2553     if (c2 == EOF) {
2554         (*o_putc)(EOF);
2555         return;
2556     }    
2557
2558     if (unicode_bom_f==2) {
2559         if (w_oconv16_LE){
2560             (*o_putc)((unsigned char)'\377');
2561             (*o_putc)('\376');
2562         }else{
2563             (*o_putc)('\376');
2564             (*o_putc)((unsigned char)'\377');
2565         }
2566         unicode_bom_f=1;
2567     }
2568
2569     if (c2 == ISO8859_1) {
2570         c2 = 0;
2571         c1 |= 0x80;
2572 #ifdef NUMCHAR_OPTION
2573     } else if (c2 == 0 && (c1 & CLASS_MASK) == CLASS_UTF16) {
2574         c2 = (c1 >> 8) & 0xff;
2575         c1 &= 0xff;
2576 #endif
2577     } else if (c2) {
2578         unsigned short val = (unsigned short)e2w_conv(c2, c1);
2579         c2 = (val >> 8) & 0xff;
2580         c1 = val & 0xff;
2581     }
2582     if (w_oconv16_LE){
2583         (*o_putc)(c1);
2584         (*o_putc)(c2);
2585     }else{
2586         (*o_putc)(c2);
2587         (*o_putc)(c1);
2588     }
2589 }
2590
2591 #endif
2592
2593 void
2594 e_oconv(c2, c1)
2595     int    c2,
2596                     c1;
2597 {
2598 #ifdef NUMCHAR_OPTION
2599     if (c2 == 0 && (c1 & CLASS_MASK) == CLASS_UTF16){
2600         w16e_conv(c1, &c2, &c1);
2601     }
2602 #endif
2603     if (c2 == EOF) {
2604         (*o_putc)(EOF);
2605         return;
2606     } else if (c2 == 0) { 
2607         output_mode = ASCII;
2608         (*o_putc)(c1);
2609     } else if (c2 == X0201) {
2610         output_mode = JAPANESE_EUC;
2611         (*o_putc)(SSO); (*o_putc)(c1|0x80);
2612     } else if (c2 == ISO8859_1) {
2613         output_mode = ISO8859_1;
2614         (*o_putc)(c1 | 0x080);
2615     } else {
2616         if ((c1<0x21 || 0x7e<c1) ||
2617            (c2<0x21 || 0x7e<c2)) {
2618             set_iconv(FALSE, 0);
2619             return; /* too late to rescue this char */
2620         }
2621         output_mode = JAPANESE_EUC;
2622         (*o_putc)(c2 | 0x080);
2623         (*o_putc)(c1 | 0x080);
2624     }
2625 }
2626
2627 void
2628 e2s_conv(c2, c1, p2, p1)
2629      int c2, c1, *p2, *p1;
2630 {
2631     if (p2) *p2 = ((c2 - 1) >> 1) + ((c2 <= 0x5e) ? 0x71 : 0xb1);
2632     if (p1) *p1 = c1 + ((c2 & 1) ? ((c1 < 0x60) ? 0x1f : 0x20) : 0x7e);
2633 }
2634
2635 void
2636 s_oconv(c2, c1)
2637     int    c2,
2638                     c1;
2639 {
2640 #ifdef NUMCHAR_OPTION
2641     if (c2 == 0 && (c1 & CLASS_MASK) == CLASS_UTF16){
2642         w16e_conv(c1, &c2, &c1);
2643     }
2644 #endif
2645     if (c2 == EOF) {
2646         (*o_putc)(EOF);
2647         return;
2648     } else if (c2 == 0) {
2649         output_mode = ASCII;
2650         (*o_putc)(c1);
2651     } else if (c2 == X0201) {
2652         output_mode = SHIFT_JIS;
2653         (*o_putc)(c1|0x80);
2654     } else if (c2 == ISO8859_1) {
2655         output_mode = ISO8859_1;
2656         (*o_putc)(c1 | 0x080);
2657     } else {
2658         if ((c1<0x20 || 0x7e<c1) ||
2659            (c2<0x20 || 0x7e<c2)) {
2660             set_iconv(FALSE, 0);
2661             return; /* too late to rescue this char */
2662         }
2663         output_mode = SHIFT_JIS;
2664         e2s_conv(c2, c1, &c2, &c1);
2665
2666 #ifdef SHIFTJIS_CP932
2667         if (cp932inv_f
2668             && CP932INV_TABLE_BEGIN <= c2 && c2 <= CP932INV_TABLE_END){
2669             extern unsigned short cp932inv[2][189];
2670             int c = cp932inv[c2 - CP932INV_TABLE_BEGIN][c1 - 0x40];
2671             if (c){
2672                 c2 = c >> 8;
2673                 c1 = c & 0xff;
2674             }
2675         }
2676 #endif /* SHIFTJIS_CP932 */
2677
2678         (*o_putc)(c2);
2679         if (prefix_table[(unsigned char)c1]){
2680             (*o_putc)(prefix_table[(unsigned char)c1]);
2681         }
2682         (*o_putc)(c1);
2683     }
2684 }
2685
2686 void
2687 j_oconv(c2, c1)
2688     int    c2,
2689                     c1;
2690 {
2691 #ifdef NUMCHAR_OPTION
2692     if ((c1 & CLASS_MASK) == CLASS_UTF16){
2693         w16e_conv(c1, &c2, &c1);
2694     }
2695 #endif
2696     if (c2 == EOF) {
2697         if (output_mode !=ASCII && output_mode!=ISO8859_1) {
2698             (*o_putc)(ESC);
2699             (*o_putc)('(');
2700             (*o_putc)(ascii_intro);
2701             output_mode = ASCII;
2702         }
2703         (*o_putc)(EOF);
2704     } else if (c2==X0201) {
2705         if (output_mode!=X0201) {
2706             output_mode = X0201;
2707             (*o_putc)(ESC);
2708             (*o_putc)('(');
2709             (*o_putc)('I');
2710         }
2711         (*o_putc)(c1);
2712     } else if (c2==ISO8859_1) {
2713             /* iso8859 introduction, or 8th bit on */
2714             /* Can we convert in 7bit form using ESC-'-'-A ? 
2715                Is this popular? */
2716         output_mode = ISO8859_1;
2717         (*o_putc)(c1|0x80);
2718     } else if (c2 == 0) {
2719         if (output_mode !=ASCII && output_mode!=ISO8859_1) {
2720             (*o_putc)(ESC);
2721             (*o_putc)('(');
2722             (*o_putc)(ascii_intro);
2723             output_mode = ASCII;
2724         }
2725         (*o_putc)(c1);
2726     } else {
2727         if (output_mode != X0208) {
2728             output_mode = X0208;
2729             (*o_putc)(ESC);
2730             (*o_putc)('$');
2731             (*o_putc)(kanji_intro);
2732         }
2733         if (c1<0x20 || 0x7e<c1) 
2734             return;
2735         if (c2<0x20 || 0x7e<c2) 
2736             return;
2737         (*o_putc)(c2);
2738         (*o_putc)(c1);
2739     }
2740 }
2741
2742 void
2743 base64_conv(c2, c1)
2744     int    c2,
2745                     c1;
2746 {
2747     if (base64_count>50 && !mimeout_mode && c2==0 && c1==SPACE) {
2748         (*o_putc)(EOF);
2749         (*o_putc)(NL);
2750     } else if (base64_count>66 && mimeout_mode) {
2751         (*o_base64conv)(EOF,0);
2752         (*o_base64conv)(NL,0);
2753         (*o_base64conv)(SPACE,0);
2754     }
2755     (*o_base64conv)(c2,c1);
2756 }
2757
2758
2759 static int broken_buf[3];
2760 static int broken_counter = 0;
2761 static int broken_last = 0;
2762 int
2763 broken_getc(f)
2764 FILE *f;
2765 {
2766     int c,c1;
2767
2768     if (broken_counter>0) {
2769         return broken_buf[--broken_counter];
2770     }
2771     c= (*i_bgetc)(f);
2772     if (c=='$' && broken_last != ESC 
2773             && (input_mode==ASCII || input_mode==X0201)) {
2774         c1= (*i_bgetc)(f);
2775         broken_last = 0;
2776         if (c1=='@'|| c1=='B') {
2777             broken_buf[0]=c1; broken_buf[1]=c; 
2778             broken_counter=2;
2779             return ESC;
2780         } else {
2781             (*i_bungetc)(c1,f);
2782             return c;
2783         }
2784     } else if (c=='(' && broken_last != ESC 
2785             && (input_mode==X0208 || input_mode==X0201)) { /* ) */
2786         c1= (*i_bgetc)(f);
2787         broken_last = 0;
2788         if (c1=='J'|| c1=='B') {
2789             broken_buf[0]=c1; broken_buf[1]=c;
2790             broken_counter=2;
2791             return ESC;
2792         } else {
2793             (*i_bungetc)(c1,f);
2794             return c;
2795         }
2796     } else {
2797         broken_last = c;
2798         return c;
2799     }
2800 }
2801
2802 int
2803 broken_ungetc(c,f)
2804 int c;
2805 FILE *f;
2806 {
2807     if (broken_counter<2)
2808         broken_buf[broken_counter++]=c;
2809     return c;
2810 }
2811
2812 static int prev_cr = 0;
2813
2814 void
2815 cr_conv(c2,c1) 
2816 int c2,c1;
2817 {
2818     if (prev_cr) {
2819         prev_cr = 0;
2820         if (! (c2==0&&c1==NL) ) {
2821             cr_conv(0,'\n');
2822         }
2823     }
2824     if (c2) {
2825         (*o_crconv)(c2,c1);
2826     } else if (c1=='\r') {
2827         prev_cr = c1;
2828     } else if (c1=='\n') {
2829         if (crmode_f==CRLF) {
2830             (*o_crconv)(0,'\r');
2831         } else if (crmode_f==CR) {
2832             (*o_crconv)(0,'\r');
2833             return;
2834         } 
2835         (*o_crconv)(0,NL);
2836     } else if (c1!='\032' || crmode_f!=NL){
2837         (*o_crconv)(c2,c1);
2838     }
2839 }
2840
2841 /* 
2842   Return value of fold_conv()
2843
2844        \n  add newline  and output char
2845        \r  add newline  and output nothing
2846        ' ' space
2847        0   skip  
2848        1   (or else) normal output 
2849
2850   fold state in prev (previous character)
2851
2852       >0x80 Japanese (X0208/X0201)
2853       <0x80 ASCII
2854       \n    new line 
2855       ' '   space
2856
2857   This fold algorthm does not preserve heading space in a line.
2858   This is the main difference from fmt.
2859 */
2860
2861 #define char_size(c2,c1) (c2?2:1)
2862
2863 void
2864 fold_conv(c2,c1) 
2865 int c2,c1;
2866
2867     int prev0;
2868     int fold_state=0;
2869
2870     if (c1== '\r' && !fold_preserve_f) {
2871         fold_state=0;  /* ignore cr */
2872     }else if (c1== '\n'&&f_prev=='\r' && fold_preserve_f) {
2873         f_prev = '\n';
2874         fold_state=0;  /* ignore cr */
2875     } else if (c1== BS) {
2876         if (f_line>0) f_line--;
2877         fold_state =  1;
2878     } else if (c2==EOF && f_line != 0) {    /* close open last line */
2879             fold_state = '\n';
2880     } else if ((c1=='\n' && !fold_preserve_f)
2881                || ((c1=='\r'||(c1=='\n'&&f_prev!='\r'))
2882                    && fold_preserve_f)) {
2883         /* new line */
2884         if (fold_preserve_f) { 
2885             f_prev = c1;
2886             f_line = 0;
2887             fold_state =  '\r';
2888         } else if ((f_prev == c1 && !fold_preserve_f)
2889                    || (f_prev == '\n' && fold_preserve_f)
2890                    ) {        /* duplicate newline */
2891             if (f_line) {
2892                 f_line = 0;
2893                 fold_state =  '\n';    /* output two newline */
2894             } else {
2895                 f_line = 0;
2896                 fold_state =  1;
2897             }
2898         } else  {
2899             if (f_prev&0x80) {     /* Japanese? */
2900                 f_prev = c1;
2901                 fold_state =  0;       /* ignore given single newline */
2902             } else if (f_prev==' ') {
2903                 fold_state =  0;
2904             } else {
2905                 f_prev = c1;
2906                 if (++f_line<=fold_len) 
2907                     fold_state =  ' ';
2908                 else {
2909                     f_line = 0;
2910                     fold_state =  '\r';        /* fold and output nothing */
2911                 }
2912             }
2913         }
2914     } else if (c1=='\f') {
2915         f_prev = '\n';
2916         if (f_line==0)
2917             fold_state =  1;
2918         f_line = 0;
2919         fold_state =  '\n';            /* output newline and clear */
2920     } else if ( (c2==0  && c1==' ')||
2921                (c2==0  && c1=='\t')||
2922                (c2=='!'&& c1=='!')) {
2923         /* X0208 kankaku or ascii space */
2924             if (f_prev == ' ') {
2925                 fold_state = 0;         /* remove duplicate spaces */
2926             } else {
2927                 f_prev = ' ';    
2928                 if (++f_line<=fold_len) 
2929                     fold_state = ' ';         /* output ASCII space only */
2930                 else {
2931                     f_prev = ' '; f_line = 0;
2932                     fold_state = '\r';        /* fold and output nothing */
2933                 }
2934             }
2935     } else {
2936         prev0 = f_prev; /* we still need this one... , but almost done */
2937         f_prev = c1;
2938         if (c2 || c2==X0201) 
2939             f_prev |= 0x80;  /* this is Japanese */
2940         f_line += char_size(c2,c1);
2941         if (f_line<=fold_len) {   /* normal case */
2942             fold_state = 1;
2943         } else {
2944             if (f_line>=fold_len+fold_margin) { /* too many kinsou suspension */
2945                 f_line = char_size(c2,c1);
2946                 fold_state =  '\n';       /* We can't wait, do fold now */
2947             } else if (c2==X0201) {
2948             /* simple kinsoku rules  return 1 means no folding  */
2949                 if (c1==(0xde&0x7f)) fold_state = 1; /* \e$B!+\e(B*/
2950                 else if (c1==(0xdf&0x7f)) fold_state = 1; /* \e$B!,\e(B*/
2951                 else if (c1==(0xa4&0x7f)) fold_state = 1; /* \e$B!#\e(B*/
2952                 else if (c1==(0xa3&0x7f)) fold_state = 1; /* \e$B!$\e(B*/
2953                 else if (c1==(0xa1&0x7f)) fold_state = 1; /* \e$B!W\e(B*/
2954                 else if (c1==(0xb0&0x7f)) fold_state = 1; /* - */
2955                 else if (SPACE<=c1 && c1<=(0xdf&0x7f)) {      /* X0201 */
2956                     f_line = 1;
2957                     fold_state = '\n';/* add one new f_line before this character */
2958                 } else {
2959                     f_line = 1;
2960                     fold_state = '\n';/* add one new f_line before this character */
2961                 }
2962             } else if (c2==0) {
2963                 /* kinsoku point in ASCII */ 
2964                 if (  c1==')'||    /* { [ ( */
2965                      c1==']'||
2966                      c1=='}'||
2967                      c1=='.'||
2968                      c1==','||
2969                      c1=='!'||
2970                      c1=='?'||
2971                      c1=='/'||
2972                      c1==':'||
2973                      c1==';' ) {
2974                     fold_state = 1;
2975                 /* just after special */
2976                 } else if (!is_alnum(prev0)) {
2977                     f_line = char_size(c2,c1);
2978                     fold_state = '\n';
2979                 } else if ((prev0==' ') ||   /* ignored new f_line */
2980                       (prev0=='\n')||        /* ignored new f_line */
2981                       (prev0&0x80)) {        /* X0208 - ASCII */
2982                     f_line = char_size(c2,c1);
2983                     fold_state = '\n';/* add one new f_line before this character */
2984                 } else {
2985                     fold_state = 1;  /* default no fold in ASCII */
2986                 }
2987             } else {
2988                 if (c2=='!') {
2989                     if (c1=='"')  fold_state = 1; /* \e$B!"\e(B */
2990                     else if (c1=='#')  fold_state = 1; /* \e$B!#\e(B */
2991                     else if (c1=='W')  fold_state = 1; /* \e$B!W\e(B */
2992                     else if (c1=='K')  fold_state = 1; /* \e$B!K\e(B */
2993                     else if (c1=='$')  fold_state = 1; /* \e$B!$\e(B */
2994                     else if (c1=='%')  fold_state = 1; /* \e$B!%\e(B */
2995                     else if (c1=='\'') fold_state = 1; /* \e$B!\\e(B */
2996                     else if (c1=='(')  fold_state = 1; /* \e$B!(\e(B */
2997                     else if (c1==')')  fold_state = 1; /* \e$B!)\e(B */
2998                     else if (c1=='*')  fold_state = 1; /* \e$B!*\e(B */
2999                     else if (c1=='+')  fold_state = 1; /* \e$B!+\e(B */
3000                     else if (c1==',')  fold_state = 1; /* \e$B!,\e(B */
3001                          /* default no fold in kinsoku */
3002                     else { 
3003                         fold_state = '\n';
3004                         f_line = char_size(c2,c1);
3005                         /* add one new f_line before this character */
3006                     }
3007                 } else {
3008                     f_line = char_size(c2,c1);
3009                     fold_state = '\n'; 
3010                     /* add one new f_line before this character */
3011                 }
3012             }
3013         }
3014     }
3015     /* terminator process */
3016     switch(fold_state) {
3017         case '\n': 
3018             (*o_fconv)(0,'\n');
3019             (*o_fconv)(c2,c1);
3020             break;
3021         case 0:    
3022             return;
3023         case '\r': 
3024             (*o_fconv)(0,'\n');
3025             break;
3026         case '\t': 
3027         case ' ': 
3028             (*o_fconv)(0,' ');
3029             break;
3030         default:
3031             (*o_fconv)(c2,c1);
3032     }
3033 }
3034
3035 int z_prev2=0,z_prev1=0;
3036
3037 void
3038 z_conv(c2,c1)
3039 int c2,c1;
3040 {
3041
3042     /* if (c2) c1 &= 0x7f; assertion */
3043
3044     if (x0201_f && z_prev2==X0201) {  /* X0201 */
3045         if (c1==(0xde&0x7f)) { /* \e$BByE@\e(B */
3046             z_prev2=0;
3047             (*o_zconv)(dv[(z_prev1-SPACE)*2],dv[(z_prev1-SPACE)*2+1]);
3048             return;
3049         } else if (c1==(0xdf&0x7f)&&ev[(z_prev1-SPACE)*2]) {  /* \e$BH>ByE@\e(B */
3050             z_prev2=0;
3051             (*o_zconv)(ev[(z_prev1-SPACE)*2],ev[(z_prev1-SPACE)*2+1]);
3052             return;
3053         } else {
3054             z_prev2=0;
3055             (*o_zconv)(cv[(z_prev1-SPACE)*2],cv[(z_prev1-SPACE)*2+1]);
3056         }
3057     }
3058
3059     if (c2==EOF) {
3060         (*o_zconv)(c2,c1);
3061         return;
3062     }
3063
3064     if (x0201_f && c2==X0201) {
3065         if (dv[(c1-SPACE)*2]||ev[(c1-SPACE)*2]) {
3066             /* wait for \e$BByE@\e(B or \e$BH>ByE@\e(B */
3067             z_prev1 = c1; z_prev2 = c2;
3068             return;
3069         } else {
3070             (*o_zconv)(cv[(c1-SPACE)*2],cv[(c1-SPACE)*2+1]);
3071             return;
3072         }
3073     }
3074
3075     /* JISX0208 Alphabet */
3076     if (alpha_f && c2 == 0x23 ) {
3077         c2 = 0;
3078     } else if (alpha_f && c2 == 0x21 ) { 
3079     /* JISX0208 Kigou */
3080        if (0x21==c1) {
3081            if (alpha_f&0x2) {
3082                c1 = ' ';
3083                c2 = 0;
3084            } else if (alpha_f&0x4) {
3085                 (*o_zconv)(0,' ');
3086                 (*o_zconv)(0,' ');
3087                 return;
3088            } 
3089        } else if (0x20<c1 && c1<0x7f && fv[c1-0x20]) {
3090            c1 = fv[c1-0x20];
3091            c2 =  0;
3092            if (alpha_f&0x8) {
3093                char *entity = 0;
3094                switch (c1){
3095                  case '>': entity = "&gt;"; break;
3096                  case '<': entity = "&lt;"; break;
3097                  case '\"': entity = "&quot;"; break;
3098                  case '&': entity = "&amp;"; break;
3099                }
3100                if (entity){
3101                    while (*entity) (*o_zconv)(0, *entity++);
3102                    return;
3103                }
3104            }
3105        } 
3106     }
3107     (*o_zconv)(c2,c1);
3108 }
3109
3110
3111 #define rot13(c)  ( \
3112       ( c < 'A' ) ? c: \
3113       (c <= 'M')  ? (c + 13): \
3114       (c <= 'Z')  ? (c - 13): \
3115       (c < 'a')   ? (c): \
3116       (c <= 'm')  ? (c + 13): \
3117       (c <= 'z')  ? (c - 13): \
3118       (c) \
3119 )
3120
3121 #define  rot47(c) ( \
3122       ( c < '!' ) ? c: \
3123       ( c <= 'O' ) ? (c + 47) : \
3124       ( c <= '~' ) ?  (c - 47) : \
3125       c \
3126 )
3127
3128 void
3129 rot_conv(c2,c1)
3130 int c2,c1;
3131 {
3132     if (c2==0 || c2==X0201 || c2==ISO8859_1) {
3133         c1 = rot13(c1);
3134     } else if (c2) {
3135         c1 = rot47(c1);
3136         c2 = rot47(c2);
3137     }
3138     (*o_rot_conv)(c2,c1);
3139 }
3140
3141 void
3142 hira_conv(c2,c1)
3143 int c2,c1;
3144 {
3145     if ((hira_f & 1) && c2==0x25 && 0x20<c1 && c1<0x74) {
3146         c2 = 0x24;
3147     } else if ((hira_f & 2) && c2==0x24 && 0x20<c1 && c1<0x74) {
3148         c2 = 0x25;
3149     } 
3150     (*o_hira_conv)(c2,c1);
3151 }
3152
3153
3154 void
3155 iso2022jp_check_conv(c2,c1)
3156 int    c2, c1;
3157 {
3158     static int range[RANGE_NUM_MAX][2] = {
3159         {0x222f, 0x2239,},
3160         {0x2242, 0x2249,},
3161         {0x2251, 0x225b,},
3162         {0x226b, 0x2271,},
3163         {0x227a, 0x227d,},
3164         {0x2321, 0x232f,},
3165         {0x233a, 0x2340,},
3166         {0x235b, 0x2360,},
3167         {0x237b, 0x237e,},
3168         {0x2474, 0x247e,},
3169         {0x2577, 0x257e,},
3170         {0x2639, 0x2640,},
3171         {0x2659, 0x267e,},
3172         {0x2742, 0x2750,},
3173         {0x2772, 0x277e,},
3174         {0x2841, 0x287e,},
3175         {0x4f54, 0x4f7e,},
3176         {0x7425, 0x747e},
3177     };
3178     int i;
3179     int start, end, c;
3180
3181     if(c2 >= 0x00 && c2 <= 0x20 && c1 >= 0x7f && c1 <= 0xff) {
3182         c2 = GETA1;
3183         c1 = GETA2;
3184     }
3185     if((c2 >= 0x29 && c2 <= 0x2f) || (c2 >= 0x75 && c2 <= 0x7e)) {
3186         c2 = GETA1;
3187         c1 = GETA2;
3188     }
3189
3190     for (i = 0; i < RANGE_NUM_MAX; i++) {
3191         start = range[i][0];
3192         end   = range[i][1];
3193         c     = (c2 << 8) + c1;
3194         if (c >= start && c <= end) {
3195             c2 = GETA1;
3196             c1 = GETA2;
3197         }
3198     }
3199     (*o_iso2022jp_check_conv)(c2,c1);
3200 }
3201
3202
3203 /* This converts  =?ISO-2022-JP?B?HOGE HOGE?= */
3204
3205 unsigned char *mime_pattern[] = {
3206    (unsigned char *)"\075?EUC-JP?B?",
3207    (unsigned char *)"\075?SHIFT_JIS?B?",
3208    (unsigned char *)"\075?ISO-8859-1?Q?",
3209    (unsigned char *)"\075?ISO-8859-1?B?",
3210    (unsigned char *)"\075?ISO-2022-JP?B?",
3211    (unsigned char *)"\075?ISO-2022-JP?Q?",
3212 #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
3213    (unsigned char *)"\075?UTF-8?B?",
3214    (unsigned char *)"\075?UTF-8?Q?",
3215 #endif
3216    (unsigned char *)"\075?US-ASCII?Q?",
3217    NULL
3218 };
3219
3220
3221 /* \e$B3:Ev$9$k%3!<%I$NM%@hEY$r>e$2$k$?$a$NL\0u\e(B */
3222 int (*mime_priority_func[])PROTO((int c2, int c1, int c0)) = {
3223     e_iconv, s_iconv, 0, 0, 0, 0,
3224 #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
3225     w_iconv, w_iconv,
3226 #endif
3227     0,
3228 };
3229
3230 int      mime_encode[] = {
3231     JAPANESE_EUC, SHIFT_JIS,ISO8859_1, ISO8859_1, X0208, X0201,
3232 #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
3233     UTF8, UTF8,
3234 #endif
3235     ASCII,
3236     0
3237 };
3238
3239 int      mime_encode_method[] = {
3240     'B', 'B','Q', 'B', 'B', 'Q',
3241 #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
3242     'B', 'Q',
3243 #endif
3244     'Q',
3245     0
3246 };
3247
3248
3249 #define MAXRECOVER 20
3250
3251 /* I don't trust portablity of toupper */
3252 #define nkf_toupper(c)  (('a'<=c && c<='z')?(c-('a'-'A')):c)
3253 #define nkf_isdigit(c)  ('0'<=c && c<='9')
3254 #define nkf_isxdigit(c)  (nkf_isdigit(c) || ('a'<=c && c<='f') || ('A'<=c && c <= 'F'))
3255
3256 void
3257 switch_mime_getc()
3258 {
3259     if (i_getc!=mime_getc) {
3260         i_mgetc = i_getc; i_getc = mime_getc;
3261         i_mungetc = i_ungetc; i_ungetc = mime_ungetc;
3262         if(mime_f==STRICT_MIME) {
3263             i_mgetc_buf = i_mgetc; i_mgetc = mime_getc_buf;
3264             i_mungetc_buf = i_mungetc; i_mungetc = mime_ungetc_buf;
3265         }
3266     }
3267 }
3268
3269 void
3270 unswitch_mime_getc()
3271 {
3272     if(mime_f==STRICT_MIME) {
3273         i_mgetc = i_mgetc_buf;
3274         i_mungetc = i_mungetc_buf;
3275     }
3276     i_getc = i_mgetc;
3277     i_ungetc = i_mungetc;
3278 }
3279
3280 int
3281 mime_begin_strict(f)
3282 FILE *f;
3283 {
3284     int c1 = 0;
3285     int i,j,k;
3286     unsigned char *p,*q;
3287     int r[MAXRECOVER];    /* recovery buffer, max mime pattern lenght */
3288
3289     mime_decode_mode = FALSE;
3290     /* =? has been checked */
3291     j = 0;
3292     p = mime_pattern[j];
3293     r[0]='='; r[1]='?';
3294
3295     for(i=2;p[i]>' ';i++) {                   /* start at =? */
3296         if ( ((r[i] = c1 = (*i_getc)(f))==EOF) || nkf_toupper(c1) != p[i] ) {
3297             /* pattern fails, try next one */
3298             q = p;
3299             while ((p = mime_pattern[++j])) {
3300                 for(k=2;k<i;k++)              /* assume length(p) > i */
3301                     if (p[k]!=q[k]) break;
3302                 if (k==i && nkf_toupper(c1)==p[k]) break;
3303             }
3304             if (p) continue;  /* found next one, continue */
3305             /* all fails, output from recovery buffer */
3306             (*i_ungetc)(c1,f);
3307             for(j=0;j<i;j++) {
3308                 (*oconv)(0,r[j]);
3309             }
3310             return c1;
3311         }
3312     }
3313     mime_decode_mode = p[i-2];
3314
3315     clr_code_score(find_inputcode_byfunc(mime_priority_func[j]), SCORE_iMIME);
3316
3317     if (mime_decode_mode=='B') {
3318         mimebuf_f = unbuf_f;
3319         if (!unbuf_f) {
3320             /* do MIME integrity check */
3321             return mime_integrity(f,mime_pattern[j]);
3322         } 
3323     }
3324     switch_mime_getc();
3325     mimebuf_f = TRUE;
3326     return c1;
3327 }
3328
3329 int
3330 mime_getc_buf(f) 
3331 FILE *f;
3332 {
3333     /* we don't keep eof of Fifo, becase it contains ?= as
3334        a terminator. It was checked in mime_integrity. */
3335     return ((mimebuf_f)?
3336         (*i_mgetc_buf)(f):Fifo(mime_input++));
3337 }
3338
3339 int
3340 mime_ungetc_buf(c,f) 
3341 FILE *f;
3342 int c;
3343 {
3344     if (mimebuf_f)
3345         (*i_mungetc_buf)(c,f);
3346     else 
3347         Fifo(--mime_input)=c;
3348     return c;
3349 }
3350
3351 int
3352 mime_begin(f)
3353 FILE *f;
3354 {
3355     int c1;
3356     int i,k;
3357
3358     /* In NONSTRICT mode, only =? is checked. In case of failure, we  */
3359     /* re-read and convert again from mime_buffer.  */
3360
3361     /* =? has been checked */
3362     k = mime_last;
3363     Fifo(mime_last++)='='; Fifo(mime_last++)='?';
3364     for(i=2;i<MAXRECOVER;i++) {                   /* start at =? */
3365         /* We accept any character type even if it is breaked by new lines */
3366         c1 = (*i_getc)(f); Fifo(mime_last++)= c1 ;
3367         if (c1=='\n'||c1==' '||c1=='\r'||
3368                 c1=='-'||c1=='_'||is_alnum(c1) ) continue;
3369         if (c1=='=') {
3370             /* Failed. But this could be another MIME preemble */
3371             (*i_ungetc)(c1,f);
3372             mime_last--;
3373             break;
3374         }
3375         if (c1!='?') break;
3376         else {
3377             /* c1=='?' */
3378             c1 = (*i_getc)(f); Fifo(mime_last++) = c1;
3379             if (!(++i<MAXRECOVER) || c1==EOF) break;
3380             if (c1=='b'||c1=='B') {
3381                 mime_decode_mode = 'B';
3382             } else if (c1=='q'||c1=='Q') {
3383                 mime_decode_mode = 'Q';
3384             } else {
3385                 break;
3386             }
3387             c1 = (*i_getc)(f); Fifo(mime_last++) = c1;
3388             if (!(++i<MAXRECOVER) || c1==EOF) break;
3389             if (c1!='?') {
3390                 mime_decode_mode = FALSE;
3391             }
3392             break;
3393         }
3394     }
3395     switch_mime_getc();
3396     if (!mime_decode_mode) {
3397         /* false MIME premble, restart from mime_buffer */
3398         mime_decode_mode = 1;  /* no decode, but read from the mime_buffer */
3399         /* Since we are in MIME mode until buffer becomes empty,    */
3400         /* we never go into mime_begin again for a while.           */
3401         return c1;
3402     }
3403     /* discard mime preemble, and goto MIME mode */
3404     mime_last = k;
3405     /* do no MIME integrity check */
3406     return c1;   /* used only for checking EOF */
3407 }
3408
3409 #ifdef CHECK_OPTION
3410 void
3411 no_putc(c)
3412      int c;
3413 {
3414     ;
3415 }
3416
3417 void debug(str)
3418      char *str;
3419 {
3420     if (debug_f){
3421         fprintf(stderr, "%s\n", str);
3422     }
3423 }
3424 #endif
3425
3426 void
3427 set_input_codename (codename)
3428     char *codename;
3429 {
3430     if (guess_f && 
3431         is_inputcode_set &&
3432         strcmp(codename, "") != 0 && 
3433         strcmp(codename, input_codename) != 0)
3434     {
3435         is_inputcode_mixed = TRUE;
3436     }
3437     input_codename = codename;
3438     is_inputcode_set = TRUE;
3439 }
3440
3441 void
3442 print_guessed_code (filename)
3443     char *filename;
3444 {
3445     char *codename = "BINARY";
3446     if (!is_inputcode_mixed) {
3447         if (strcmp(input_codename, "") == 0) {
3448             codename = "ASCII";
3449         } else {
3450             codename = input_codename;
3451         }
3452     }
3453     if (filename != NULL) printf("%s:", filename);
3454     printf("%s\n", codename);
3455 }
3456
3457 int
3458 hex2bin(x)
3459      int x;
3460 {
3461     if (nkf_isdigit(x)) return x - '0';
3462     return nkf_toupper(x) - 'A' + 10;
3463 }
3464
3465 #ifdef INPUT_OPTION 
3466
3467 #ifdef ANSI_C_PROTOTYPE
3468 int hex_getc(int ch, FILE *f, int (*g)(FILE *f), int (*u)(int c, FILE *f))
3469 #else
3470 int
3471 hex_getc(ch, f, g, u)
3472      int ch;
3473      FILE *f;
3474      int (*g)();
3475      int (*u)();
3476 #endif
3477 {
3478     int c1, c2, c3;
3479     c1 = (*g)(f);
3480     if (c1 != ch){
3481         return c1;
3482     }
3483     c2 = (*g)(f);
3484     if (!nkf_isxdigit(c2)){
3485         (*u)(c2, f);
3486         return c1;
3487     }
3488     c3 = (*g)(f);
3489     if (!nkf_isxdigit(c3)){
3490         (*u)(c2, f);
3491         (*u)(c3, f);
3492         return c1;
3493     }
3494     return (hex2bin(c2) << 4) | hex2bin(c3);
3495 }
3496
3497 int
3498 cap_getc(f)
3499      FILE *f;
3500 {
3501     return hex_getc(':', f, i_cgetc, i_cungetc);
3502 }
3503
3504 int
3505 cap_ungetc(c, f)
3506      int c;
3507      FILE *f;
3508 {
3509     return (*i_cungetc)(c, f);
3510 }
3511
3512 int
3513 url_getc(f)
3514      FILE *f;
3515 {
3516     return hex_getc('%', f, i_ugetc, i_uungetc);
3517 }
3518
3519 int
3520 url_ungetc(c, f)
3521      int c;
3522      FILE *f;
3523 {
3524     return (*i_uungetc)(c, f);
3525 }
3526 #endif
3527
3528 #ifdef NUMCHAR_OPTION
3529 int
3530 numchar_getc(f)
3531      FILE *f;
3532 {
3533     int (*g)() = i_ngetc;
3534     int (*u)() = i_nungetc;
3535     int i = 0, j;
3536     int buf[8];
3537     long c = -1;
3538
3539     buf[i] = (*g)(f);
3540     if (buf[i] == '&'){
3541         buf[++i] = (*g)(f);
3542         if (buf[i] == '#'){
3543             c = 0;
3544             buf[++i] = (*g)(f);
3545             if (buf[i] == 'x' || buf[i] == 'X'){
3546                 for (j = 0; j < 5; j++){
3547                     buf[++i] = (*g)(f);
3548                     if (!nkf_isxdigit(buf[i])){
3549                         if (buf[i] != ';'){
3550                             c = -1;
3551                         }
3552                         break;
3553                     }
3554                     c <<= 4;
3555                     c |= hex2bin(buf[i]);
3556                 }
3557             }else{
3558                 for (j = 0; j < 6; j++){
3559                     if (j){
3560                         buf[++i] = (*g)(f);
3561                     }
3562                     if (!nkf_isdigit(buf[i])){
3563                         if (buf[i] != ';'){
3564                             c = -1;
3565                         }
3566                         break;
3567                     }
3568                     c *= 10;
3569                     c += hex2bin(buf[i]);
3570                 }
3571             }
3572         }
3573     }
3574     if (c != -1){
3575         return CLASS_UTF16 | c;
3576     }
3577     while (i > 0){
3578         (*u)(buf[i], f);
3579         --i;
3580     }
3581     return buf[0];
3582 }
3583
3584 int
3585 numchar_ungetc(c, f)
3586      int c;
3587      FILE *f;
3588 {
3589     return (*i_nungetc)(c, f);
3590 }
3591 #endif
3592
3593
3594 int 
3595 mime_getc(f)
3596 FILE *f;
3597 {
3598     int c1, c2, c3, c4, cc;
3599     int t1, t2, t3, t4, mode, exit_mode;
3600     int lwsp_count;
3601     char *lwsp_buf;
3602     char *lwsp_buf_new;
3603     int lwsp_size = 128;
3604
3605     if (mime_top != mime_last) {  /* Something is in FIFO */
3606         return  Fifo(mime_top++);
3607     }
3608     if (mime_decode_mode==1 ||mime_decode_mode==FALSE) {
3609         mime_decode_mode=FALSE;
3610         unswitch_mime_getc();
3611         return (*i_getc)(f);
3612     }
3613
3614     if (mimebuf_f == FIXED_MIME)
3615         exit_mode = mime_decode_mode;
3616     else
3617         exit_mode = FALSE;
3618     if (mime_decode_mode == 'Q') {
3619         if ((c1 = (*i_mgetc)(f)) == EOF) return (EOF);
3620 restart_mime_q:
3621         if (c1=='_') return ' ';
3622         if (c1!='=' && c1!='?') {
3623             return c1;
3624         }
3625                 
3626         mime_decode_mode = exit_mode; /* prepare for quit */
3627         if (c1<=' ') return c1;
3628         if ((c2 = (*i_mgetc)(f)) == EOF) return (EOF);
3629         if (c1=='?'&&c2=='=' && mimebuf_f != FIXED_MIME) {
3630             /* end Q encoding */
3631             input_mode = exit_mode;
3632             lwsp_count = 0;
3633             lwsp_buf = malloc((lwsp_size+5)*sizeof(char));
3634             if (lwsp_buf==NULL) {
3635                 perror("can't malloc");
3636                 return -1;
3637             }
3638             while ((c1=(*i_getc)(f))!=EOF) {
3639                 switch (c1) {
3640                 case NL:
3641                 case CR:
3642                     if (c1==NL) {
3643                         if ((c1=(*i_getc)(f))!=EOF && (c1==SPACE||c1==TAB)) {
3644                             i_ungetc(SPACE,f);
3645                             continue;
3646                         } else {
3647                             i_ungetc(c1,f);
3648                         }
3649                         c1 = NL;
3650                     } else {
3651                         if ((c1=(*i_getc)(f))!=EOF && c1 == NL) {
3652                             if ((c1=(*i_getc)(f))!=EOF && (c1==SPACE||c1==TAB)) {
3653                                 i_ungetc(SPACE,f);
3654                                 continue;
3655                             } else {
3656                                 i_ungetc(c1,f);
3657                             }
3658                             i_ungetc(NL,f);
3659                         } else {
3660                             i_ungetc(c1,f);
3661                         }
3662                         c1 = CR;
3663                     }
3664                     break;
3665                 case SPACE:
3666                 case TAB:
3667                     lwsp_buf[lwsp_count] = c1;
3668                     if (lwsp_count++>lwsp_size){
3669                         lwsp_size *= 2;
3670                         lwsp_buf_new = realloc(lwsp_buf, (lwsp_size+5)*sizeof(char));
3671                         if (lwsp_buf_new==NULL) {
3672                             free(lwsp_buf);
3673                             lwsp_buf = NULL;
3674                             perror("can't realloc");
3675                             return -1;
3676                         }
3677                         lwsp_buf = lwsp_buf_new;
3678                     }
3679                     continue;
3680                 }
3681                 break;
3682             }
3683             if (lwsp_count > 0) {
3684                 if (c1=='=' && (lwsp_buf[lwsp_count-1]==SPACE||lwsp_buf[lwsp_count-1]==TAB)) {
3685                     lwsp_count = 0;
3686                 } else {
3687                     i_ungetc(c1,f);
3688                     for(lwsp_count--;lwsp_count>0;lwsp_count--)
3689                         i_ungetc(lwsp_buf[lwsp_count],f);
3690                     c1 = lwsp_buf[0];
3691                 }
3692             }
3693             free(lwsp_buf);
3694             lwsp_buf = NULL;
3695             return c1;
3696         }
3697         if (c1=='='&&c2<' ') { /* this is soft wrap */
3698             while((c1 =  (*i_mgetc)(f)) <=' ') {
3699                 if ((c1 = (*i_mgetc)(f)) == EOF) return (EOF);
3700             }
3701             mime_decode_mode = 'Q'; /* still in MIME */
3702             goto restart_mime_q;
3703         }
3704         if (c1=='?') {
3705             mime_decode_mode = 'Q'; /* still in MIME */
3706             (*i_mungetc)(c2,f);
3707             return c1;
3708         }
3709         if ((c3 = (*i_mgetc)(f)) == EOF) return (EOF);
3710         if (c2<=' ') return c2;
3711         mime_decode_mode = 'Q'; /* still in MIME */
3712 #define hex(c)   (('0'<=c&&c<='9')?(c-'0'):\
3713      ('A'<=c&&c<='F')?(c-'A'+10):('a'<=c&&c<='f')?(c-'a'+10):0)
3714         return ((hex(c2)<<4) + hex(c3));
3715     }
3716
3717     if (mime_decode_mode != 'B') {
3718         mime_decode_mode = FALSE;
3719         return (*i_mgetc)(f);
3720     }
3721
3722
3723     /* Base64 encoding */
3724     /* 
3725         MIME allows line break in the middle of 
3726         Base64, but we are very pessimistic in decoding
3727         in unbuf mode because MIME encoded code may broken by 
3728         less or editor's control sequence (such as ESC-[-K in unbuffered
3729         mode. ignore incomplete MIME.
3730     */
3731     mode = mime_decode_mode;
3732     mime_decode_mode = exit_mode;  /* prepare for quit */
3733
3734     while ((c1 = (*i_mgetc)(f))<=' ') {
3735         if (c1==EOF)
3736             return (EOF);
3737     }
3738 mime_c2_retry:
3739     if ((c2 = (*i_mgetc)(f))<=' ') {
3740         if (c2==EOF)
3741             return (EOF);
3742         if (mime_f != STRICT_MIME) goto mime_c2_retry;
3743         if (mimebuf_f!=FIXED_MIME) input_mode = ASCII;  
3744         return c2;
3745     }
3746     if ((c1 == '?') && (c2 == '=')) {
3747         input_mode = ASCII;
3748         lwsp_count = 0;
3749         lwsp_buf = malloc((lwsp_size+5)*sizeof(char));
3750         if (lwsp_buf==NULL) {
3751             perror("can't malloc");
3752             return -1;
3753         }
3754         while ((c1=(*i_getc)(f))!=EOF) {
3755             switch (c1) {
3756             case NL:
3757             case CR:
3758                 if (c1==NL) {
3759                     if ((c1=(*i_getc)(f))!=EOF && (c1==SPACE||c1==TAB)) {
3760                         i_ungetc(SPACE,f);
3761                         continue;
3762                     } else {
3763                         i_ungetc(c1,f);
3764                     }
3765                     c1 = NL;
3766                 } else {
3767                     if ((c1=(*i_getc)(f))!=EOF) {
3768                         if (c1==SPACE) {
3769                             i_ungetc(SPACE,f);
3770                             continue;
3771                         } else if ((c1=(*i_getc)(f))!=EOF && (c1==SPACE||c1==TAB)) {
3772                             i_ungetc(SPACE,f);
3773                             continue;
3774                         } else {
3775                             i_ungetc(c1,f);
3776                         }
3777                         i_ungetc(NL,f);
3778                     } else {
3779                         i_ungetc(c1,f);
3780                     }
3781                     c1 = CR;
3782                 }
3783                 break;
3784             case SPACE:
3785             case TAB:
3786                 lwsp_buf[lwsp_count] = c1;
3787                 if (lwsp_count++>lwsp_size){
3788                     lwsp_size *= 2;
3789                     lwsp_buf_new = realloc(lwsp_buf, (lwsp_size+5)*sizeof(char));
3790                     if (lwsp_buf_new==NULL) {
3791                         free(lwsp_buf);
3792                         lwsp_buf = NULL;
3793                         perror("can't realloc");
3794                         return -1;
3795                     }
3796                     lwsp_buf = lwsp_buf_new;
3797                 }
3798                 continue;
3799             }
3800             break;
3801         }
3802         if (lwsp_count > 0) {
3803             if (c1=='=' && (lwsp_buf[lwsp_count-1]==SPACE||lwsp_buf[lwsp_count-1]==TAB)) {
3804                 lwsp_count = 0;
3805             } else {
3806                 i_ungetc(c1,f);
3807                 for(lwsp_count--;lwsp_count>0;lwsp_count--)
3808                     i_ungetc(lwsp_buf[lwsp_count],f);
3809                 c1 = lwsp_buf[0];
3810             }
3811         }
3812         free(lwsp_buf);
3813         lwsp_buf = NULL;
3814         return c1;
3815     }
3816 mime_c3_retry:
3817     if ((c3 = (*i_mgetc)(f))<=' ') {
3818         if (c3==EOF)
3819             return (EOF);
3820         if (mime_f != STRICT_MIME) goto mime_c3_retry;
3821         if (mimebuf_f!=FIXED_MIME) input_mode = ASCII;  
3822         return c3;
3823     }
3824 mime_c4_retry:
3825     if ((c4 = (*i_mgetc)(f))<=' ') {
3826         if (c4==EOF)
3827             return (EOF);
3828         if (mime_f != STRICT_MIME) goto mime_c4_retry;
3829         if (mimebuf_f!=FIXED_MIME) input_mode = ASCII;  
3830         return c4;
3831     }
3832
3833     mime_decode_mode = mode; /* still in MIME sigh... */
3834
3835     /* BASE 64 decoding */
3836
3837     t1 = 0x3f & base64decode(c1);
3838     t2 = 0x3f & base64decode(c2);
3839     t3 = 0x3f & base64decode(c3);
3840     t4 = 0x3f & base64decode(c4);
3841     cc = ((t1 << 2) & 0x0fc) | ((t2 >> 4) & 0x03);
3842     if (c2 != '=') {
3843         Fifo(mime_last++) = cc;
3844         cc = ((t2 << 4) & 0x0f0) | ((t3 >> 2) & 0x0f);
3845         if (c3 != '=') {
3846             Fifo(mime_last++) = cc;
3847             cc = ((t3 << 6) & 0x0c0) | (t4 & 0x3f);
3848             if (c4 != '=') 
3849                 Fifo(mime_last++) = cc;
3850         }
3851     } else {
3852         return c1;
3853     }
3854     return  Fifo(mime_top++);
3855 }
3856
3857 int
3858 mime_ungetc(c,f) 
3859 int   c;
3860 FILE  *f;
3861 {
3862     Fifo(--mime_top) = c;
3863     return c;
3864 }
3865
3866 int
3867 mime_integrity(f,p)
3868 FILE *f;
3869 unsigned char *p;
3870 {
3871     int c,d;
3872     unsigned int q;
3873     /* In buffered mode, read until =? or NL or buffer full
3874      */
3875     mime_input = mime_top;
3876     mime_last = mime_top;
3877     while(*p) Fifo(mime_input++) = *p++;
3878     d = 0;
3879     q = mime_input;
3880     while((c=(*i_getc)(f))!=EOF) {
3881         if (((mime_input-mime_top)&MIME_BUF_MASK)==0) {
3882             break;   /* buffer full */
3883         }
3884         if (c=='=' && d=='?') {
3885             /* checked. skip header, start decode */
3886             Fifo(mime_input++) = c;
3887             /* mime_last_input = mime_input; */
3888             mime_input = q; 
3889             switch_mime_getc();
3890             return 1;
3891         }
3892         if (!( (c=='+'||c=='/'|| c=='=' || c=='?' || is_alnum(c))))
3893             break;
3894         /* Should we check length mod 4? */
3895         Fifo(mime_input++) = c;
3896         d=c;
3897     }
3898     /* In case of Incomplete MIME, no MIME decode  */
3899     Fifo(mime_input++) = c;
3900     mime_last = mime_input;     /* point undecoded buffer */
3901     mime_decode_mode = 1;              /* no decode on Fifo last in mime_getc */
3902     switch_mime_getc();         /* anyway we need buffered getc */
3903     return 1;
3904 }
3905
3906 int
3907 base64decode(c)
3908     int            c;
3909 {
3910     int             i;
3911     if (c > '@') {
3912         if (c < '[') {
3913             i = c - 'A';                        /* A..Z 0-25 */
3914         } else {
3915             i = c - 'G'     /* - 'a' + 26 */ ;  /* a..z 26-51 */
3916         }
3917     } else if (c > '/') {
3918         i = c - '0' + '4'   /* - '0' + 52 */ ;  /* 0..9 52-61 */
3919     } else if (c == '+') {
3920         i = '>'             /* 62 */ ;          /* +  62 */
3921     } else {
3922         i = '?'             /* 63 */ ;          /* / 63 */
3923     }
3924     return (i);
3925 }
3926
3927 static char basis_64[] =
3928    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
3929
3930 static int b64c;
3931 #define MIMEOUT_BUF_LENGTH (60)
3932 char mimeout_buf[MIMEOUT_BUF_LENGTH+1];
3933 int mimeout_buf_count = 0;
3934 int mimeout_preserve_space = 0;
3935 #define itoh4(c)   (c>=10?c+'A'-10:c+'0')
3936
3937 void
3938 open_mime(mode)
3939 int mode;
3940 {
3941     unsigned char *p;
3942     int i;
3943     int j;
3944     p  = mime_pattern[0];
3945     for(i=0;mime_encode[i];i++) {
3946         if (mode == mime_encode[i]) {
3947             p = mime_pattern[i];
3948             break;
3949         }
3950     }
3951     mimeout_mode = mime_encode_method[i];
3952     
3953     i = 0;
3954     if (base64_count>45) {
3955         (*o_mputc)(NL);
3956         (*o_mputc)(SPACE);
3957         base64_count = 1;
3958         if (!mimeout_preserve_space && mimeout_buf_count>0
3959             && (mimeout_buf[i]==SPACE || mimeout_buf[i]==TAB
3960                 || mimeout_buf[i]==CR || mimeout_buf[i]==NL )) {
3961             i++;
3962         }
3963     }
3964     if (!mimeout_preserve_space) {
3965         for (;i<mimeout_buf_count;i++) {
3966             if (mimeout_buf[i]==SPACE || mimeout_buf[i]==TAB
3967                 || mimeout_buf[i]==CR || mimeout_buf[i]==NL ) {
3968                 (*o_mputc)(mimeout_buf[i]);
3969                 base64_count ++;
3970             } else {
3971                 break;
3972             }
3973         }
3974     }
3975     mimeout_preserve_space = FALSE;
3976     
3977     while(*p) {
3978         (*o_mputc)(*p++);
3979         base64_count ++;
3980     }
3981     j = mimeout_buf_count;
3982     mimeout_buf_count = 0;
3983     for (;i<j;i++) {
3984         mime_putc(mimeout_buf[i]);
3985     }
3986 }
3987
3988 void
3989 close_mime()
3990 {
3991     (*o_mputc)('?');
3992     (*o_mputc)('=');
3993     base64_count += 2;
3994     mimeout_mode = 0;
3995 }
3996
3997 void
3998 eof_mime()
3999 {
4000     switch(mimeout_mode) {
4001     case 'Q':
4002     case 'B':
4003         break;
4004     case 2:
4005         (*o_mputc)(basis_64[((b64c & 0x3)<< 4)]);
4006         (*o_mputc)('=');
4007         (*o_mputc)('=');
4008         base64_count += 3;
4009         break;
4010     case 1:
4011         (*o_mputc)(basis_64[((b64c & 0xF) << 2)]);
4012         (*o_mputc)('=');
4013         base64_count += 2;
4014         break;
4015     }
4016     if (mimeout_mode) {
4017         if (mimeout_f!=FIXED_MIME) {
4018             close_mime(); 
4019         } else if (mimeout_mode != 'Q')
4020             mimeout_mode = 'B';
4021     }
4022 }
4023
4024 void
4025 mimeout_addchar(c)
4026     int            c;
4027 {
4028     switch(mimeout_mode) {
4029     case 'Q':
4030         if(c>=DEL) {
4031             (*o_mputc)('=');
4032             (*o_mputc)(itoh4(((c>>4)&0xf)));
4033             (*o_mputc)(itoh4((c&0xf)));
4034             base64_count += 3;
4035         } else {
4036             (*o_mputc)(c);
4037             base64_count++;
4038         }
4039         break;
4040     case 'B':
4041         b64c=c;
4042         (*o_mputc)(basis_64[c>>2]);
4043         mimeout_mode=2;
4044         base64_count ++;
4045         break;
4046     case 2:
4047         (*o_mputc)(basis_64[((b64c & 0x3)<< 4) | ((c & 0xF0) >> 4)]);
4048         b64c=c;
4049         mimeout_mode=1;
4050         base64_count ++;
4051         break;
4052     case 1:
4053         (*o_mputc)(basis_64[((b64c & 0xF) << 2) | ((c & 0xC0) >>6)]);
4054         (*o_mputc)(basis_64[c & 0x3F]);
4055         mimeout_mode='B';
4056         base64_count += 2;
4057         break;
4058     }
4059 }
4060
4061 void
4062 mime_putc(c)
4063     int            c;
4064 {
4065     int i = 0;
4066     int j = 0;
4067     
4068     if (mimeout_f==FIXED_MIME && base64_count>50) {
4069         eof_mime();
4070         (*o_mputc)(NL);
4071         base64_count=0;
4072     } else if (c==CR||c==NL) {
4073         base64_count=0;
4074     }
4075     if (c!=EOF && mimeout_f!=FIXED_MIME) {
4076         if ( c<=DEL &&(output_mode==ASCII ||output_mode == ISO8859_1 ) ) {
4077             if (mimeout_mode=='Q') {
4078                 if (c<=SPACE) {
4079                     close_mime();
4080                     (*o_mputc)(SPACE);
4081                     base64_count++;
4082                 }
4083                 (*o_mputc)(c);
4084                 base64_count++;
4085                 return;
4086             } else if (mimeout_mode) {
4087                 if (base64_count>63) {
4088                     eof_mime();
4089                     (*o_mputc)(NL);
4090                     (*o_mputc)(SPACE);
4091                     base64_count=1;
4092                     mimeout_preserve_space = TRUE;
4093                 }
4094                 if (c==SPACE || c==TAB || c==CR || c==NL) {
4095                     for (i=0;i<mimeout_buf_count;i++) {
4096                         if (SPACE<mimeout_buf[i] && mimeout_buf[i]<DEL) {
4097                             eof_mime();
4098                             for (i=0;i<mimeout_buf_count;i++) {
4099                                 (*o_mputc)(mimeout_buf[i]);
4100                                 base64_count++;
4101                             }
4102                             mimeout_buf_count = 0;
4103                         }
4104                     }
4105                     mimeout_buf[mimeout_buf_count++] = c;
4106                     if (mimeout_buf_count>MIMEOUT_BUF_LENGTH) {
4107                         eof_mime();
4108                         base64_count = 0;
4109                         for (i=0;i<mimeout_buf_count;i++) {
4110                             (*o_mputc)(mimeout_buf[i]);
4111                             base64_count++;
4112                         }
4113                     }
4114                     return;
4115                 }
4116                 if (mimeout_buf_count>0 && SPACE<c) {
4117                     mimeout_buf[mimeout_buf_count++] = c;
4118                     if (mimeout_buf_count>MIMEOUT_BUF_LENGTH) {
4119                     } else {
4120                         return;
4121                     }
4122                 }
4123             } else if (!mimeout_mode) {
4124                 if (c==SPACE || c==TAB || c==CR || c==NL) {
4125                     if ((c==CR || c==NL)
4126                         &&(mimeout_buf[mimeout_buf_count-1]==SPACE
4127                            || mimeout_buf[mimeout_buf_count-1]==TAB)) {
4128                         mimeout_buf_count--;
4129                     }
4130                     for (i=0;i<mimeout_buf_count;i++) {
4131                         (*o_mputc)(mimeout_buf[i]);
4132                         base64_count++;
4133                     }
4134                     mimeout_buf_count = 0;
4135                 }
4136                 mimeout_buf[mimeout_buf_count++] = c;
4137                 if (mimeout_buf_count>75) {
4138                     open_mime(output_mode);
4139                 }
4140                 return;
4141             }
4142         } else if (!mimeout_mode) {
4143             if (mimeout_buf_count>0 && mimeout_buf[mimeout_buf_count-1]==SPACE) {
4144                 for (i=0;i<mimeout_buf_count-1;i++) {
4145                     (*o_mputc)(mimeout_buf[i]);
4146                     base64_count++;
4147                 }
4148                 mimeout_buf[0] = SPACE;
4149                 mimeout_buf_count = 1;
4150             }
4151             open_mime(output_mode);
4152         }
4153     } else { /* c==EOF */
4154         j = mimeout_buf_count;
4155         i = 0;
4156         for (;i<j;i++) {
4157             if (mimeout_buf[i]==SPACE || mimeout_buf[i]==TAB
4158                 || mimeout_buf[i]==CR || mimeout_buf[i]==NL)
4159                 break;
4160             (*mime_putc)(mimeout_buf[i]);
4161         }
4162         eof_mime();
4163         for (;i<j;i++) {
4164             (*o_mputc)(mimeout_buf[i]);
4165             base64_count++;
4166         }
4167         return;
4168     }
4169     
4170     if (mimeout_buf_count>0) {
4171         j = mimeout_buf_count;
4172         mimeout_buf_count = 0;
4173         for (i=0;i<j;i++) {
4174             mimeout_addchar(mimeout_buf[i]);
4175         }
4176     }
4177     mimeout_addchar(c);
4178 }
4179
4180
4181 #ifdef PERL_XS
4182 void 
4183 reinit()
4184 {
4185     {
4186         struct input_code *p = input_code_list;
4187         while (p->name){
4188             status_reinit(p++);
4189         }
4190     }
4191     unbuf_f = FALSE;
4192     estab_f = FALSE;
4193     nop_f = FALSE;
4194     binmode_f = TRUE;
4195     rot_f = FALSE;
4196     hira_f = FALSE;
4197     input_f = FALSE;
4198     alpha_f = FALSE;
4199     mime_f = STRICT_MIME;
4200     mimebuf_f = FALSE;
4201     broken_f = FALSE;
4202     iso8859_f = FALSE;
4203     mimeout_f = FALSE;
4204 #if defined(MSDOS) || defined(__OS2__)
4205      x0201_f = TRUE;
4206 #else
4207      x0201_f = NO_X0201;
4208 #endif
4209     iso2022jp_f = FALSE;
4210 #ifdef UTF8_OUTPUT_ENABLE
4211     unicode_bom_f = 0;
4212     w_oconv16_LE = 0;
4213     ms_ucs_map_f = FALSE;
4214 #endif
4215 #ifdef INPUT_OPTION
4216     cap_f = FALSE;
4217     url_f = FALSE;
4218     numchar_f = FALSE;
4219 #endif
4220 #ifdef CHECK_OPTION
4221     noout_f = FALSE;
4222     debug_f = FALSE;
4223 #endif
4224     guess_f = FALSE;
4225     is_inputcode_mixed = FALSE;
4226     is_inputcode_set   = FALSE;
4227 #ifdef EXEC_IO
4228     exec_f = 0;
4229 #endif
4230 #ifdef SHIFTJIS_CP932
4231     cp932_f = TRUE;
4232     cp932inv_f = FALSE;
4233 #endif
4234     {
4235         int i;
4236         for (i = 0; i < 256; i++){
4237             prefix_table[i] = 0;
4238         }
4239     }
4240 #ifdef UTF8_INPUT_ENABLE
4241     utf16_mode = UTF16LE_INPUT;
4242 #endif
4243     mimeout_mode = 0;
4244     base64_count = 0;
4245     f_line = 0;
4246     f_prev = 0;
4247     fold_preserve_f = FALSE;
4248     fold_f = FALSE;
4249     fold_len = 0;
4250     kanji_intro = DEFAULT_J;
4251     ascii_intro = DEFAULT_R;
4252     fold_margin  = FOLD_MARGIN;
4253     output_conv = DEFAULT_CONV;
4254     oconv = DEFAULT_CONV;
4255     o_zconv = no_connection;
4256     o_fconv = no_connection;
4257     o_crconv = no_connection;
4258     o_rot_conv = no_connection;
4259     o_hira_conv = no_connection;
4260     o_base64conv = no_connection;
4261     o_iso2022jp_check_conv = no_connection;
4262     o_putc = std_putc;
4263     i_getc = std_getc;
4264     i_ungetc = std_ungetc;
4265     i_bgetc = std_getc;
4266     i_bungetc = std_ungetc;
4267     o_mputc = std_putc;
4268     i_mgetc = std_getc;
4269     i_mungetc  = std_ungetc;
4270     i_mgetc_buf = std_getc;
4271     i_mungetc_buf = std_ungetc;
4272     output_mode = ASCII;
4273     input_mode =  ASCII;
4274     shift_mode =  FALSE;
4275     mime_decode_mode = FALSE;
4276     file_out = FALSE;
4277     crmode_f = 0;
4278     option_mode = 0;
4279     broken_counter = 0;
4280     broken_last = 0;
4281     z_prev2=0,z_prev1=0;
4282
4283 }
4284 #endif
4285
4286 void 
4287 no_connection(c2,c1) 
4288 int c2,c1;
4289 {
4290     no_connection2(c2,c1,0);
4291 }
4292
4293 int
4294 no_connection2(c2,c1,c0) 
4295 int c2,c1,c0;
4296 {
4297     fprintf(stderr,"nkf internal module connection failure.\n");
4298     exit(1);
4299 }
4300
4301 #ifndef PERL_XS
4302 void 
4303 usage()   
4304 {
4305     fprintf(stderr,"USAGE:  nkf(nkf32,wnkf,nkf2) -[flags] [in file] .. [out file for -O flag]\n");
4306     fprintf(stderr,"Flags:\n");
4307     fprintf(stderr,"b,u      Output is buffered (DEFAULT),Output is unbuffered\n");
4308 #ifdef DEFAULT_CODE_SJIS
4309     fprintf(stderr,"j,s,e,w  Outout code is JIS 7 bit, Shift JIS (DEFAULT), AT&T JIS (EUC), UTF-8\n");
4310 #endif
4311 #ifdef DEFAULT_CODE_JIS
4312     fprintf(stderr,"j,s,e,w  Outout code is JIS 7 bit (DEFAULT), Shift JIS, AT&T JIS (EUC), UTF-8\n");
4313 #endif
4314 #ifdef DEFAULT_CODE_EUC
4315     fprintf(stderr,"j,s,e,w  Outout code is JIS 7 bit, Shift JIS, AT&T JIS (EUC) (DEFAULT), UTF-8\n");
4316 #endif
4317 #ifdef DEFAULT_CODE_UTF8
4318     fprintf(stderr,"j,s,e,w  Outout code is JIS 7 bit, Shift JIS, AT&T JIS (EUC), UTF-8 (DEFAULT)\n");
4319 #endif
4320 #ifdef UTF8_OUTPUT_ENABLE
4321     fprintf(stderr,"         After 'w' you can add more options. (80?|16((B|L)0?)?) \n");
4322 #endif
4323     fprintf(stderr,"J,S,E,W  Input assumption is JIS 7 bit , Shift JIS, AT&T JIS (EUC), UTF-8\n");
4324 #ifdef UTF8_INPUT_ENABLE
4325     fprintf(stderr,"         After 'W' you can add more options. (8|16(B|L)?) \n");
4326 #endif
4327     fprintf(stderr,"t        no conversion\n");
4328     fprintf(stderr,"i_/o_    Output sequence to designate JIS-kanji/ASCII (DEFAULT B)\n");
4329     fprintf(stderr,"r        {de/en}crypt ROT13/47\n");
4330     fprintf(stderr,"h        1 hirakana->katakana, 2 katakana->hirakana,3 both\n");
4331     fprintf(stderr,"v        Show this usage. V: show version\n");
4332     fprintf(stderr,"m[BQN0]  MIME decode [B:base64,Q:quoted,N:non-strict,0:no decode]\n");
4333     fprintf(stderr,"M[BQ]    MIME encode [B:base64 Q:quoted]\n");
4334     fprintf(stderr,"l        ISO8859-1 (Latin-1) support\n");
4335     fprintf(stderr,"f/F      Folding: -f60 or -f or -f60-10 (fold margin 10) F preserve nl\n");
4336     fprintf(stderr,"Z[0-3]   Convert X0208 alphabet to ASCII  1: Kankaku to space,2: 2 spaces,\n");
4337     fprintf(stderr,"                                          3: Convert HTML Entity\n");
4338     fprintf(stderr,"X,x      Assume X0201 kana in MS-Kanji, -x preserves X0201\n");
4339     fprintf(stderr,"B[0-2]   Broken input  0: missing ESC,1: any X on ESC-[($]-X,2: ASCII on NL\n");
4340 #ifdef MSDOS
4341     fprintf(stderr,"T        Text mode output\n");
4342 #endif
4343     fprintf(stderr,"O        Output to File (DEFAULT 'nkf.out')\n");
4344     fprintf(stderr,"d,c      Delete \\r in line feed and \\032, Add \\r in line feed\n");
4345     fprintf(stderr,"I        Convert non ISO-2022-JP charactor to GETA\n");
4346     fprintf(stderr,"-L[uwm]  line mode u:LF w:CRLF m:CR (DEFAULT noconversion)\n");
4347     fprintf(stderr,"long name options\n");
4348     fprintf(stderr," --fj,--unix,--mac,--windows                        convert for the system\n");
4349     fprintf(stderr," --jis,--euc,--sjis,--utf8,--utf16,--mime,--base64  convert for the code\n");
4350     fprintf(stderr," --hiragana, --katakana    Hiragana/Katakana Conversion\n");
4351 #ifdef INPUT_OPTION
4352     fprintf(stderr," --cap-input, --url-input  Convert hex after ':' or '%'\n");
4353 #endif
4354 #ifdef NUMCHAR_OPTION
4355     fprintf(stderr," --numchar-input   Convert Unicode Character Reference\n");
4356 #endif
4357 #ifdef SHIFTJIS_CP932
4358     fprintf(stderr," --no-cp932        Don't convert Shift_JIS FAxx-FCxx to equivalnet CP932\n");
4359     fprintf(stderr," --cp932inv        convert Shift_JIS EDxx-EFxx to equivalnet CP932 FAxx-FCxx\n");
4360 #endif
4361 #ifdef UTF8_OUTPUT_ENABLE
4362     fprintf(stderr," --ms-ucs-map      Microsoft UCS Mapping Compatible\n");
4363 #endif
4364 #ifdef OVERWRITE
4365     fprintf(stderr," --overwrite       Overwrite original listed files by filtered result\n");
4366 #endif
4367     fprintf(stderr," -g, --guess       Guess the input code\n");
4368     fprintf(stderr," --help,--version\n");
4369     version();
4370 }
4371
4372 void
4373 version()
4374 {
4375     fprintf(stderr,"Network Kanji Filter Version %s (%s) "
4376 #if defined(MSDOS) && !defined(__WIN32__) && !defined(__WIN16__)
4377                   "for DOS"
4378 #endif
4379 #if defined(MSDOS) && defined(__WIN16__)
4380                   "for Win16"
4381 #endif
4382 #if defined(MSDOS) && defined(__WIN32__)
4383                   "for Win32"
4384 #endif
4385 #ifdef __OS2__
4386                   "for OS/2"
4387 #endif
4388                   ,NKF_VERSION,NKF_RELEASE_DATE);
4389     fprintf(stderr,"\n%s\n",CopyRight);
4390 }
4391 #endif
4392
4393 /**
4394  ** \e$B%Q%C%A@):n<T\e(B
4395  **  void@merope.pleiades.or.jp (Kusakabe Youichi)
4396  **  NIDE Naoyuki <nide@ics.nara-wu.ac.jp>
4397  **  ohta@src.ricoh.co.jp (Junn Ohta)
4398  **  inouet@strl.nhk.or.jp (Tomoyuki Inoue)
4399  **  kiri@pulser.win.or.jp (Tetsuaki Kiriyama)
4400  **  Kimihiko Sato <sato@sail.t.u-tokyo.ac.jp>
4401  **  a_kuroe@kuroe.aoba.yokohama.jp (Akihiko Kuroe)
4402  **  kono@ie.u-ryukyu.ac.jp (Shinji Kono)
4403  **  GHG00637@nifty-serve.or.jp (COW)
4404  **
4405  **/
4406
4407 /* end */