OSDN Git Service

change release date
[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.47 2004/12/01 04:18:04 naruse Exp $ */
43 #define NKF_VERSION "2.0.4"
44 #define NKF_RELEASE_DATE "2004-12-01"
45 #include "config.h"
46
47 static char *CopyRight =
48       "Copyright (C) 1987, FUJITSU LTD. (I.Ichikawa),2000 S. Kono, COW, 2002-2004 Kono, Furukawa";
49
50
51 /*
52 **
53 **
54 **
55 ** USAGE:       nkf [flags] [file] 
56 **
57 ** Flags:
58 ** b    Output is buffered             (DEFAULT)
59 ** u    Output is unbuffered
60 **
61 ** t    no operation
62 **
63 ** j    Outout code is JIS 7 bit        (DEFAULT SELECT) 
64 ** s    Output code is MS Kanji         (DEFAULT SELECT) 
65 ** e    Output code is AT&T JIS         (DEFAULT SELECT) 
66 ** w    Output code is AT&T JIS         (DEFAULT SELECT) 
67 ** l    Output code is JIS 7bit and ISO8859-1 Latin-1
68 **
69 ** m    MIME conversion for ISO-2022-JP
70 ** I    Convert non ISO-2022-JP charactor to GETA by Pekoe <pekoe@lair.net>
71 ** i_ Output sequence to designate JIS-kanji (DEFAULT_J)
72 ** o_ Output sequence to designate single-byte roman characters (DEFAULT_R)
73 ** M    MIME output conversion 
74 **
75 ** r  {de/en}crypt ROT13/47
76 **
77 ** v  display Version
78 **
79 ** T  Text mode output        (for MS-DOS)
80 **
81 ** x    Do not convert X0201 kana into X0208
82 ** Z    Convert X0208 alphabet to ASCII
83 **
84 ** f60  fold option
85 **
86 ** m    MIME decode
87 ** B    try to fix broken JIS, missing Escape
88 ** B[1-9]  broken level
89 **
90 ** O   Output to 'nkf.out' file or last file name
91 ** d   Delete \r in line feed 
92 ** c   Add \r in line feed 
93 ** -- other long option
94 ** -- ignore following option (don't use with -O )
95 **
96 **/
97
98 #if (defined(__TURBOC__) || defined(_MSC_VER) || defined(LSI_C) || defined(__MINGW32__)) && !defined(MSDOS)
99 #define MSDOS
100 #if (defined(__Win32__) || defined(_WIN32)) && !defined(__WIN32__)
101 #define __WIN32__
102 #endif
103 #endif
104
105 #ifdef PERL_XS
106 #undef OVERWRITE
107 #endif
108
109 #ifndef PERL_XS
110 #include <stdio.h>
111 #endif
112
113 #include <stdlib.h>
114
115 #if defined(MSDOS) || defined(__OS2__) 
116 #include <fcntl.h>
117 #include <io.h>
118 #endif
119
120 #ifdef MSDOS
121 #ifdef LSI_C
122 #define setbinmode(fp) fsetbin(fp)
123 #else /* Microsoft C, Turbo C */
124 #define setbinmode(fp) setmode(fileno(fp), O_BINARY)
125 #endif
126 #else /* UNIX,OS/2 */
127 #define setbinmode(fp)
128 #endif
129
130 #ifdef _IOFBF /* SysV and MSDOS, Windows */
131 #define       setvbuffer(fp, buf, size)       setvbuf(fp, buf, _IOFBF, size)
132 #else /* BSD */
133 #define       setvbuffer(fp, buf, size)       setbuffer(fp, buf, size)
134 #endif
135
136 /*Borland C++ 4.5 EasyWin*/
137 #if defined(__TURBOC__) && defined(_Windows) && !defined(__WIN32__) /*Easy Win */
138 #define         EASYWIN
139 #ifndef __WIN16__
140 #define __WIN16__
141 #endif
142 #include <windows.h>
143 #endif
144
145 #ifdef OVERWRITE
146 /* added by satoru@isoternet.org */
147 #include <string.h>
148 #include <sys/stat.h>
149 #ifndef MSDOS /* UNIX, OS/2 */
150 #include <unistd.h>
151 #include <utime.h>
152 #else
153 #if defined(_MSC_VER) || defined(__MINGW32__) /* VC++, MinGW */
154 #include <sys/utime.h>
155 #elif defined(__TURBOC__) /* BCC */
156 #include <utime.h>
157 #elif defined(LSI_C) /* LSI C */
158 #endif
159 #endif
160 #endif 
161
162 #ifdef INT_IS_SHORT
163 #define int long
164 #endif
165
166 #define         FALSE   0
167 #define         TRUE    1
168
169 /* state of output_mode and input_mode  
170
171    c2           0 means ASCII
172                 X0201
173                 ISO8859_1
174                 X0208
175                 EOF      all termination
176    c1           32bit data
177
178  */
179
180 #define         ASCII           0
181 #define         X0208           1
182 #define         X0201           2
183 #define         ISO8859_1       8
184 #define         NO_X0201        3
185
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 = TRUE;
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 = NULL;
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 = 0;
727               int fd_backup = 0;
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     {"cp932", ""},
897     {"no-cp932", ""},
898 #ifdef UTF8_OUTPUT_ENABLE
899     {"utf8", "w"},
900     {"utf16", "w16"},
901     {"ms-ucs-map", ""},
902 #endif
903 #ifdef UTF8_INPUT_ENABLE
904     {"utf8-input", "W"},
905     {"utf16-input", "W16"},
906 #endif
907 #ifdef OVERWRITE
908     {"overwrite", ""},
909 #endif
910 #ifdef INPUT_OPTION
911     {"cap-input", ""},
912     {"url-input", ""},
913 #endif
914 #ifdef NUMCHAR_OPTION
915     {"numchar-input", ""},
916 #endif
917 #ifdef CHECK_OPTION
918     {"no-output", ""},
919     {"debug", ""},
920 #endif
921 #ifdef SHIFTJIS_CP932
922     {"cp932inv", ""},
923 #endif
924 #ifdef EXEC_IO
925     {"exec-in", ""},
926     {"exec-out", ""},
927 #endif
928     {"prefix=", ""},
929 };
930
931 static int option_mode = 0;
932
933 void
934 options(cp) 
935      unsigned char *cp;
936 {
937     int i;
938     unsigned char *p = NULL;
939
940     if (option_mode==1)
941         return;
942     if (*cp++ != '-') 
943         return;
944     while (*cp) {
945         if (p && !*cp) {
946             cp = p;
947             p = 0;
948         }
949         switch (*cp++) {
950         case '-':  /* literal options */
951             if (!*cp) {        /* ignore the rest of arguments */
952                 option_mode = 1;
953                 return;
954             }
955             for (i=0;i<sizeof(long_option)/sizeof(long_option[0]);i++) {
956                 int j;
957                 p = (unsigned char *)long_option[i].name;
958                 for (j=0;*p && (*p != '=') && *p == cp[j];p++, j++);
959                 if (!*p || *p == cp[j]){
960                     p = &cp[j];
961                     break;
962                 }
963                 p = 0;
964             }
965             if (p == 0) return;
966             cp = (unsigned char *)long_option[i].alias;
967             if (!*cp){
968 #ifdef OVERWRITE
969                 if (strcmp(long_option[i].name, "overwrite") == 0){
970                     file_out = TRUE;
971                     overwrite = TRUE;
972                     continue;
973                 }
974 #endif
975 #ifdef INPUT_OPTION
976                 if (strcmp(long_option[i].name, "cap-input") == 0){
977                     cap_f = TRUE;
978                     continue;
979                 }
980                 if (strcmp(long_option[i].name, "url-input") == 0){
981                     url_f = TRUE;
982                     continue;
983                 }
984 #endif
985 #ifdef NUMCHAR_OPTION
986                 if (strcmp(long_option[i].name, "numchar-input") == 0){
987                     numchar_f = TRUE;
988                     continue;
989                 }
990 #endif
991 #ifdef CHECK_OPTION
992                 if (strcmp(long_option[i].name, "no-output") == 0){
993                     noout_f = TRUE;
994                     continue;
995                 }
996                 if (strcmp(long_option[i].name, "debug") == 0){
997                     debug_f = TRUE;
998                     continue;
999                 }
1000 #endif
1001                 if (strcmp(long_option[i].name, "cp932") == 0){
1002 #ifdef SHIFTJIS_CP932
1003                     cp932_f = TRUE;
1004                     cp932inv_f = TRUE;
1005 #endif
1006 #ifdef UTF8_OUTPUT_ENABLE
1007                     ms_ucs_map_f = TRUE;
1008 #endif
1009                     continue;
1010                 }
1011                 if (strcmp(long_option[i].name, "no-cp932") == 0){
1012 #ifdef SHIFTJIS_CP932
1013                     cp932_f = FALSE;
1014                     cp932inv_f = FALSE;
1015 #endif
1016 #ifdef UTF8_OUTPUT_ENABLE
1017                     ms_ucs_map_f = FALSE;
1018 #endif
1019                     continue;
1020                 }
1021 #ifdef SHIFTJIS_CP932
1022                 if (strcmp(long_option[i].name, "cp932inv") == 0){
1023                     cp932inv_f = TRUE;
1024                     continue;
1025                 }
1026 #endif
1027 #ifdef EXEC_IO
1028                   if (strcmp(long_option[i].name, "exec-in") == 0){
1029                       exec_f = 1;
1030                       return;
1031                   }
1032                   if (strcmp(long_option[i].name, "exec-out") == 0){
1033                       exec_f = -1;
1034                       return;
1035                   }
1036 #endif
1037 #ifdef UTF8_OUTPUT_ENABLE
1038                 if (strcmp(long_option[i].name, "ms-ucs-map") == 0){
1039                     ms_ucs_map_f = TRUE;
1040                     continue;
1041                 }
1042 #endif
1043                 if (strcmp(long_option[i].name, "prefix=") == 0){
1044                     if (*p == '=' && ' ' < p[1] && p[1] < 128){
1045                         for (i = 2; ' ' < p[i] && p[i] < 128; i++){
1046                             prefix_table[p[i]] = p[1];
1047                         }
1048                     }
1049                     continue;
1050                 }
1051             }
1052             continue;
1053         case 'b':           /* buffered mode */
1054             unbuf_f = FALSE;
1055             continue;
1056         case 'u':           /* non bufferd mode */
1057             unbuf_f = TRUE;
1058             continue;
1059         case 't':           /* transparent mode */
1060             nop_f = TRUE;
1061             continue;
1062         case 'j':           /* JIS output */
1063         case 'n':
1064             output_conv = j_oconv;
1065             continue;
1066         case 'e':           /* AT&T EUC output */
1067             output_conv = e_oconv;
1068             continue;
1069         case 's':           /* SJIS output */
1070             output_conv = s_oconv;
1071             continue;
1072         case 'l':           /* ISO8859 Latin-1 support, no conversion */
1073             iso8859_f = TRUE;  /* Only compatible with ISO-2022-JP */
1074             input_f = LATIN1_INPUT;
1075             continue;
1076         case 'i':           /* Kanji IN ESC-$-@/B */
1077             if (*cp=='@'||*cp=='B') 
1078                 kanji_intro = *cp++;
1079             continue;
1080         case 'o':           /* ASCII IN ESC-(-J/B */
1081             if (*cp=='J'||*cp=='B'||*cp=='H') 
1082                 ascii_intro = *cp++;
1083             continue;
1084         case 'h':
1085             /*  
1086                 bit:1   hira -> kata
1087                 bit:2   kata -> hira
1088             */
1089             if ('9'>= *cp && *cp>='0') 
1090                 hira_f |= (*cp++ -'0');
1091             else 
1092                 hira_f |= 1;
1093             continue;
1094         case 'r':
1095             rot_f = TRUE;
1096             continue;
1097 #if defined(MSDOS) || defined(__OS2__) 
1098         case 'T':
1099             binmode_f = FALSE;
1100             continue;
1101 #endif
1102 #ifndef PERL_XS
1103         case 'V':
1104             version();
1105             exit(1);
1106             break;
1107         case 'v':
1108             usage();
1109             exit(1);
1110             break;
1111 #endif
1112 #ifdef UTF8_OUTPUT_ENABLE
1113         case 'w':           /* UTF-8 output */
1114             if ('1'== cp[0] && '6'==cp[1]) {
1115                 output_conv = w_oconv16; cp+=2;
1116                 if (cp[0]=='L') {
1117                     unicode_bom_f=2; cp++;
1118                     w_oconv16_LE = 1;
1119                     if (cp[0] == '0'){
1120                         unicode_bom_f=1; cp++;
1121                     }
1122                 } else if (cp[0] == 'B') {
1123                     unicode_bom_f=2; cp++;
1124                     if (cp[0] == '0'){
1125                         unicode_bom_f=1; cp++;
1126                     }
1127                 } 
1128             } else if (cp[0] == '8') {
1129                 output_conv = w_oconv; cp++;
1130                 unicode_bom_f=2;
1131                 if (cp[0] == '0'){
1132                     unicode_bom_f=1; cp++;
1133                 }
1134             } else
1135                 output_conv = w_oconv;
1136             continue;
1137 #endif
1138 #ifdef UTF8_INPUT_ENABLE
1139         case 'W':           /* UTF-8 input */
1140             if ('1'== cp[0] && '6'==cp[1]) {
1141                 input_f = UTF16LE_INPUT;
1142                 if (cp[0]=='L') {
1143                     cp++;
1144                 } else if (cp[0] == 'B') {
1145                     cp++;
1146                     input_f = UTF16BE_INPUT;
1147                 }
1148             } else if (cp[0] == '8') {
1149                 cp++;
1150                 input_f = UTF8_INPUT;
1151             } else
1152                 input_f = UTF8_INPUT;
1153             continue;
1154 #endif
1155         /* Input code assumption */
1156         case 'J':   /* JIS input */
1157         case 'E':   /* AT&T EUC input */
1158             input_f = JIS_INPUT;
1159             continue;
1160         case 'S':   /* MS Kanji input */
1161             input_f = SJIS_INPUT;
1162             if (x0201_f==NO_X0201) x0201_f=TRUE;
1163             continue;
1164         case 'Z':   /* Convert X0208 alphabet to asii */
1165             /*  bit:0   Convert X0208
1166                 bit:1   Convert Kankaku to one space
1167                 bit:2   Convert Kankaku to two spaces
1168                 bit:3   Convert HTML Entity
1169             */
1170             if ('9'>= *cp && *cp>='0') 
1171                 alpha_f |= 1<<(*cp++ -'0');
1172             else 
1173                 alpha_f |= TRUE;
1174             continue;
1175         case 'x':   /* Convert X0201 kana to X0208 or X0201 Conversion */
1176             x0201_f = FALSE;    /* No X0201->X0208 conversion */
1177             /* accept  X0201
1178                     ESC-(-I     in JIS, EUC, MS Kanji
1179                     SI/SO       in JIS, EUC, MS Kanji
1180                     SSO         in EUC, JIS, not in MS Kanji
1181                     MS Kanji (0xa0-0xdf) 
1182                output  X0201
1183                     ESC-(-I     in JIS (0x20-0x5f)
1184                     SSO         in EUC (0xa0-0xdf)
1185                     0xa0-0xd    in MS Kanji (0xa0-0xdf) 
1186             */
1187             continue;
1188         case 'X':   /* Assume X0201 kana */
1189             /* Default value is NO_X0201 for EUC/MS-Kanji mix */
1190             x0201_f = TRUE;
1191             continue;
1192         case 'F':   /* prserve new lines */
1193             fold_preserve_f = TRUE;
1194         case 'f':   /* folding -f60 or -f */
1195             fold_f = TRUE;
1196             fold_len = 0;
1197             while('0'<= *cp && *cp <='9') { /* we don't use atoi here */
1198                 fold_len *= 10;
1199                 fold_len += *cp++ - '0';
1200             }
1201             if (!(0<fold_len && fold_len<BUFSIZ)) 
1202                 fold_len = DEFAULT_FOLD;
1203             if (*cp=='-') {
1204                 fold_margin = 0;
1205                 cp++;
1206                 while('0'<= *cp && *cp <='9') { /* we don't use atoi here */
1207                     fold_margin *= 10;
1208                     fold_margin += *cp++ - '0';
1209                 }
1210             }
1211             continue;
1212         case 'm':   /* MIME support */
1213             if (*cp=='B'||*cp=='Q') {
1214                 mime_decode_mode = *cp++;
1215                 mimebuf_f = FIXED_MIME;
1216             } else if (*cp=='N') {
1217                 mime_f = TRUE; cp++;
1218             } else if (*cp=='S') {
1219                 mime_f = STRICT_MIME; cp++;
1220             } else if (*cp=='0') {
1221                 mime_f = FALSE; cp++;
1222             }
1223             continue;
1224         case 'M':   /* MIME output */
1225             if (*cp=='B') {
1226                 mimeout_mode = 'B';
1227                 mimeout_f = FIXED_MIME; cp++;
1228             } else if (*cp=='Q') {
1229                 mimeout_mode = 'Q';
1230                 mimeout_f = FIXED_MIME; cp++;
1231             } else {
1232                 mimeout_f = TRUE;
1233             }
1234             continue;
1235         case 'B':   /* Broken JIS support */
1236             /*  bit:0   no ESC JIS
1237                 bit:1   allow any x on ESC-(-x or ESC-$-x
1238                 bit:2   reset to ascii on NL
1239             */
1240             if ('9'>= *cp && *cp>='0') 
1241                 broken_f |= 1<<(*cp++ -'0');
1242             else 
1243                 broken_f |= TRUE;
1244             continue;
1245 #ifndef PERL_XS
1246         case 'O':/* for Output file */
1247             file_out = TRUE;
1248             continue;
1249 #endif
1250         case 'c':/* add cr code */
1251             crmode_f = CRLF;
1252             continue;
1253         case 'd':/* delete cr code */
1254             crmode_f = NL;
1255             continue;
1256         case 'I':   /* ISO-2022-JP output */
1257             iso2022jp_f = TRUE;
1258             continue;
1259         case 'L':  /* line mode */
1260             if (*cp=='u') {         /* unix */
1261                 crmode_f = NL; cp++;
1262             } else if (*cp=='m') { /* mac */
1263                 crmode_f = CR; cp++;
1264             } else if (*cp=='w') { /* windows */
1265                 crmode_f = CRLF; cp++;
1266             } else if (*cp=='0') { /* no conversion  */
1267                 crmode_f = 0; cp++;
1268             }
1269             continue;
1270         case 'g':
1271 #ifndef PERL_XS
1272             guess_f = TRUE;
1273 #endif
1274             continue;
1275         case ' ':    
1276         /* module muliple options in a string are allowed for Perl moudle  */
1277             while(*cp && *cp!='-') cp++;
1278             if(*cp=='-') cp++;
1279             continue;
1280         default:
1281             /* bogus option but ignored */
1282             continue;
1283         }
1284     }
1285 }
1286
1287 #ifdef ANSI_C_PROTOTYPE
1288 struct input_code * find_inputcode_byfunc(int (*iconv_func)(int c2,int c1,int c0))
1289 #else
1290 struct input_code * find_inputcode_byfunc(iconv_func)
1291      int (*iconv_func)();
1292 #endif
1293 {
1294     if (iconv_func){
1295         struct input_code *p = input_code_list;
1296         while (p->name){
1297             if (iconv_func == p->iconv_func){
1298                 return p;
1299             }
1300             p++;
1301         }
1302     }
1303     return 0;
1304 }
1305
1306 #ifdef ANSI_C_PROTOTYPE
1307 void set_iconv(int f, int (*iconv_func)(int c2,int c1,int c0))
1308 #else
1309 void set_iconv(f, iconv_func)
1310      int f;
1311      int (*iconv_func)();
1312 #endif
1313 {
1314 #ifdef CHECK_OPTION
1315     static int (*iconv_for_check)() = 0;
1316 #endif
1317 #ifdef INPUT_CODE_FIX
1318     if (f || !input_f)
1319 #endif
1320         if (estab_f != f){
1321             estab_f = f;
1322         }
1323
1324     if (iconv_func
1325 #ifdef INPUT_CODE_FIX
1326         && (f == -TRUE || !input_f) /* -TRUE means "FORCE" */
1327 #endif
1328         ){
1329         iconv = iconv_func;
1330     }
1331 #ifdef CHECK_OPTION
1332     if (estab_f && iconv_for_check != iconv){
1333         struct input_code *p = find_inputcode_byfunc(iconv);
1334         if (p){
1335             set_input_codename(p->name);
1336             debug(input_codename);
1337         }
1338         iconv_for_check = iconv;
1339     }
1340 #endif
1341 }
1342
1343 #define SCORE_L2       (1)                   /* \e$BBh\e(B2\e$B?e=`4A;z\e(B */
1344 #define SCORE_KANA     (SCORE_L2 << 1)       /* \e$B$$$o$f$kH>3Q%+%J\e(B */
1345 #define SCORE_DEPEND   (SCORE_KANA << 1)     /* \e$B5!<o0MB8J8;z\e(B */
1346 #ifdef SHIFTJIS_CP932
1347 #define SCORE_CP932    (SCORE_DEPEND << 1)   /* CP932 \e$B$K$h$kFI$_49$(\e(B */
1348 #define SCORE_NO_EXIST (SCORE_CP932 << 1)    /* \e$BB8:_$7$J$$J8;z\e(B */
1349 #else
1350 #define SCORE_NO_EXIST (SCORE_DEPEND << 1)   /* \e$BB8:_$7$J$$J8;z\e(B */
1351 #endif
1352 #define SCORE_iMIME    (SCORE_NO_EXIST << 1) /* MIME \e$B$K$h$k;XDj\e(B */
1353 #define SCORE_ERROR    (SCORE_iMIME << 1) /* \e$B%(%i!<\e(B */
1354
1355 #define SCORE_INIT (SCORE_iMIME)
1356
1357 int score_table_A0[] = {
1358     0, 0, 0, 0,
1359     0, 0, 0, 0,
1360     0, SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND,
1361     SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND, SCORE_NO_EXIST,
1362 };
1363
1364 int score_table_F0[] = {
1365     SCORE_L2, SCORE_L2, SCORE_L2, SCORE_L2,
1366     SCORE_L2, SCORE_DEPEND, SCORE_NO_EXIST, SCORE_NO_EXIST,
1367     SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND,
1368     SCORE_DEPEND, SCORE_NO_EXIST, SCORE_NO_EXIST, SCORE_ERROR,
1369 };
1370
1371 void set_code_score(ptr, score)
1372      struct input_code *ptr;
1373      int score;
1374 {
1375     if (ptr){
1376         ptr->score |= score;
1377     }
1378 }
1379
1380 void clr_code_score(ptr, score)
1381      struct input_code *ptr;
1382      int score;
1383 {
1384     if (ptr){
1385         ptr->score &= ~score;
1386     }
1387 }
1388
1389 void code_score(ptr)
1390      struct input_code *ptr;
1391 {
1392     int c2 = ptr->buf[0];
1393     int c1 = ptr->buf[1];
1394     if (c2 < 0){
1395         set_code_score(ptr, SCORE_ERROR);
1396     }else if (c2 == SSO){
1397         set_code_score(ptr, SCORE_KANA);
1398 #ifdef UTF8_OUTPUT_ENABLE
1399     }else if (!e2w_conv(c2, c1)){
1400         set_code_score(ptr, SCORE_NO_EXIST);
1401 #endif
1402     }else if ((c2 & 0x70) == 0x20){
1403         set_code_score(ptr, score_table_A0[c2 & 0x0f]);
1404     }else if ((c2 & 0x70) == 0x70){
1405         set_code_score(ptr, score_table_F0[c2 & 0x0f]);
1406     }else if ((c2 & 0x70) >= 0x50){
1407         set_code_score(ptr, SCORE_L2);
1408     }
1409 }
1410
1411 void status_disable(ptr)
1412 struct input_code *ptr;
1413 {
1414     ptr->stat = -1;
1415     ptr->buf[0] = -1;
1416     code_score(ptr);
1417     if (iconv == ptr->iconv_func) set_iconv(FALSE, 0);
1418 }
1419
1420 void status_push_ch(ptr, c)
1421      struct input_code *ptr;
1422      int c;
1423 {
1424     ptr->buf[ptr->index++] = c;
1425 }
1426
1427 void status_clear(ptr)
1428      struct input_code *ptr;
1429 {
1430     ptr->stat = 0;
1431     ptr->index = 0;
1432 }
1433
1434 void status_reset(ptr)
1435      struct input_code *ptr;
1436 {
1437     status_clear(ptr);
1438     ptr->score = SCORE_INIT;
1439 }
1440
1441 void status_reinit(ptr)
1442      struct input_code *ptr;
1443 {
1444     status_reset(ptr);
1445     ptr->_file_stat = 0;
1446 }
1447
1448 void status_check(ptr, c)
1449      struct input_code *ptr;
1450      int c;
1451 {
1452     if (c <= DEL && estab_f){
1453         status_reset(ptr);
1454     }
1455 }
1456
1457 void s_status(ptr, c)
1458      struct input_code *ptr;
1459      int c;
1460 {
1461     switch(ptr->stat){
1462       case -1:
1463           status_check(ptr, c);
1464           break;
1465       case 0:
1466           if (c <= DEL){
1467               break;
1468 #ifdef NUMCHAR_OPTION
1469           }else if ((c & CLASS_MASK) == CLASS_UTF16){
1470               break;
1471 #endif
1472           }else if (0xa1 <= c && c <= 0xdf){
1473               status_push_ch(ptr, SSO);
1474               status_push_ch(ptr, c);
1475               code_score(ptr);
1476               status_clear(ptr);
1477           }else if ((0x81 <= c && c < 0xa0) || (0xe0 <= c && c <= 0xef)){
1478               ptr->stat = 1;
1479               status_push_ch(ptr, c);
1480 #ifdef SHIFTJIS_CP932
1481           }else if (cp932_f
1482                     && CP932_TABLE_BEGIN <= c && c <= CP932_TABLE_END){
1483               ptr->stat = 2;
1484               status_push_ch(ptr, c);
1485 #endif /* SHIFTJIS_CP932 */
1486           }else{
1487               status_disable(ptr);
1488           }
1489           break;
1490       case 1:
1491           if ((0x40 <= c && c <= 0x7e) || (0x80 <= c && c <= 0xfc)){
1492               status_push_ch(ptr, c);
1493               s2e_conv(ptr->buf[0], ptr->buf[1], &ptr->buf[0], &ptr->buf[1]);
1494               code_score(ptr);
1495               status_clear(ptr);
1496           }else{
1497               status_disable(ptr);
1498           }
1499           break;
1500 #ifdef SHIFTJIS_CP932
1501       case 2:
1502           if ((0x40 <= c && c <= 0x7e) || (0x80 <= c && c <= 0xfc)){
1503               status_push_ch(ptr, c);
1504               if (s2e_conv(ptr->buf[0], ptr->buf[1], &ptr->buf[0], &ptr->buf[1]) == 0){
1505                   set_code_score(ptr, SCORE_CP932);
1506                   status_clear(ptr);
1507                   break;
1508               }
1509           }
1510           status_disable(ptr);
1511           break;
1512 #endif /* SHIFTJIS_CP932 */
1513     }
1514 }
1515
1516 void e_status(ptr, c)
1517      struct input_code *ptr;
1518      int c;
1519 {
1520     switch (ptr->stat){
1521       case -1:
1522           status_check(ptr, c);
1523           break;
1524       case 0:
1525           if (c <= DEL){
1526               break;
1527 #ifdef NUMCHAR_OPTION
1528           }else if ((c & CLASS_MASK) == CLASS_UTF16){
1529               break;
1530 #endif
1531           }else if (SSO == c || (0xa1 <= c && c <= 0xfe)){
1532               ptr->stat = 1;
1533               status_push_ch(ptr, c);
1534           }else{
1535               status_disable(ptr);
1536           }
1537           break;
1538       case 1:
1539           if (0xa1 <= c && c <= 0xfe){
1540               status_push_ch(ptr, c);
1541               code_score(ptr);
1542               status_clear(ptr);
1543           }else{
1544               status_disable(ptr);
1545           }
1546           break;
1547     }
1548 }
1549
1550 #ifdef UTF8_INPUT_ENABLE
1551 void w16_status(ptr, c)
1552      struct input_code *ptr;
1553      int c;
1554 {
1555     switch (ptr->stat){
1556       case -1:
1557           break;
1558       case 0:
1559           if (ptr->_file_stat == 0){
1560               if (c == 0xfe || c == 0xff){
1561                   ptr->stat = c;
1562                   status_push_ch(ptr, c);
1563                   ptr->_file_stat = 1;
1564               }else{
1565                   status_disable(ptr);
1566                   ptr->_file_stat = -1;
1567               }
1568           }else if (ptr->_file_stat > 0){
1569               ptr->stat = 1;
1570               status_push_ch(ptr, c);
1571           }else if (ptr->_file_stat < 0){
1572               status_disable(ptr);
1573           }
1574           break;
1575
1576       case 1:
1577           if (c == EOF){
1578               status_disable(ptr);
1579               ptr->_file_stat = -1;
1580           }else{
1581               status_push_ch(ptr, c);
1582               status_clear(ptr);
1583           }
1584           break;
1585
1586       case 0xfe:
1587       case 0xff:
1588           if (ptr->stat != c && (c == 0xfe || c == 0xff)){
1589               status_push_ch(ptr, c);
1590               status_clear(ptr);
1591           }else{
1592               status_disable(ptr);
1593               ptr->_file_stat = -1;
1594           }
1595           break;
1596     }
1597 }
1598
1599 void w_status(ptr, c)
1600      struct input_code *ptr;
1601      int c;
1602 {
1603     switch (ptr->stat){
1604       case -1:
1605           status_check(ptr, c);
1606           break;
1607       case 0:
1608           if (c <= DEL){
1609               break;
1610 #ifdef NUMCHAR_OPTION
1611           }else if ((c & CLASS_MASK) == CLASS_UTF16){
1612               break;
1613 #endif
1614           }else if (0xc0 <= c && c <= 0xdf){
1615               ptr->stat = 1;
1616               status_push_ch(ptr, c);
1617           }else if (0xe0 <= c && c <= 0xef){
1618               ptr->stat = 2;
1619               status_push_ch(ptr, c);
1620           }else{
1621               status_disable(ptr);
1622           }
1623           break;
1624       case 1:
1625       case 2:
1626           if (0x80 <= c && c <= 0xbf){
1627               status_push_ch(ptr, c);
1628               if (ptr->index > ptr->stat){
1629                   int bom = (ptr->buf[0] == 0xef && ptr->buf[1] == 0xbb
1630                              && ptr->buf[2] == 0xbf);
1631                   w2e_conv(ptr->buf[0], ptr->buf[1], ptr->buf[2],
1632                            &ptr->buf[0], &ptr->buf[1]);
1633                   if (!bom){
1634                       code_score(ptr);
1635                   }
1636                   status_clear(ptr);
1637               }
1638           }else{
1639               status_disable(ptr);
1640           }
1641           break;
1642     }
1643 }
1644 #endif
1645
1646 void
1647 code_status(c)
1648      int c;
1649 {
1650     int action_flag = 1;
1651     struct input_code *result = 0;
1652     struct input_code *p = input_code_list;
1653     while (p->name){
1654         (p->status_func)(p, c);
1655         if (p->stat > 0){
1656             action_flag = 0;
1657         }else if(p->stat == 0){
1658             if (result){
1659                 action_flag = 0;
1660             }else{
1661                 result = p;
1662             }
1663         }
1664         ++p;
1665     }
1666
1667     if (action_flag){
1668         if (result && !estab_f){
1669             set_iconv(TRUE, result->iconv_func);
1670         }else if (c <= DEL){
1671             struct input_code *ptr = input_code_list;
1672             while (ptr->name){
1673                 status_reset(ptr);
1674                 ++ptr;
1675             }
1676         }
1677     }
1678 }
1679
1680 #define STD_GC_BUFSIZE (256)
1681 int std_gc_buf[STD_GC_BUFSIZE];
1682 int std_gc_ndx;
1683
1684 int 
1685 std_getc(f)
1686 FILE *f;
1687 {
1688     if (std_gc_ndx){
1689         return std_gc_buf[--std_gc_ndx];
1690     }
1691     return getc(f);
1692 }
1693
1694 int 
1695 std_ungetc(c,f)
1696 int c;
1697 FILE *f;
1698 {
1699     if (std_gc_ndx == STD_GC_BUFSIZE){
1700         return EOF;
1701     }
1702     std_gc_buf[std_gc_ndx++] = c;
1703     return c;
1704 }
1705
1706 void 
1707 std_putc(c)
1708 int c;
1709 {
1710     if(c!=EOF)
1711       putchar(c);
1712 }
1713
1714 int
1715 noconvert(f)
1716     FILE  *f;
1717 {
1718     int    c;
1719
1720     while ((c = (*i_getc)(f)) != EOF)
1721       (*o_putc)(c);
1722     return 1;
1723 }
1724
1725
1726 void
1727 module_connection()
1728 {
1729     oconv = output_conv; 
1730     o_putc = std_putc;
1731
1732     /* replace continucation module, from output side */
1733
1734     /* output redicrection */
1735 #ifdef CHECK_OPTION
1736     if (noout_f || guess_f){
1737         o_putc = no_putc;
1738     }
1739 #endif
1740     if (mimeout_f) {
1741         o_mputc = o_putc;
1742         o_putc = mime_putc;
1743         if (mimeout_f == TRUE) {
1744             o_base64conv = oconv; oconv = base64_conv;
1745         }
1746         /* base64_count = 0; */
1747     }
1748
1749     if (crmode_f) {
1750         o_crconv = oconv; oconv = cr_conv;
1751     }
1752     if (rot_f) {
1753         o_rot_conv = oconv; oconv = rot_conv;
1754     }
1755     if (iso2022jp_f) {
1756         o_iso2022jp_check_conv = oconv; oconv = iso2022jp_check_conv;
1757     }
1758     if (hira_f) {
1759         o_hira_conv = oconv; oconv = hira_conv;
1760     }
1761     if (fold_f) {
1762         o_fconv = oconv; oconv = fold_conv;
1763         f_line = 0;
1764     }
1765     if (alpha_f || x0201_f) {
1766         o_zconv = oconv; oconv = z_conv;
1767     }
1768
1769     i_getc = std_getc;
1770     i_ungetc = std_ungetc;
1771     /* input redicrection */
1772 #ifdef INPUT_OPTION
1773     if (cap_f){
1774         i_cgetc = i_getc; i_getc = cap_getc;
1775         i_cungetc = i_ungetc; i_ungetc= cap_ungetc;
1776     }
1777     if (url_f){
1778         i_ugetc = i_getc; i_getc = url_getc;
1779         i_uungetc = i_ungetc; i_ungetc= url_ungetc;
1780     }
1781 #endif
1782 #ifdef NUMCHAR_OPTION
1783     if (numchar_f){
1784         i_ngetc = i_getc; i_getc = numchar_getc;
1785         i_nungetc = i_ungetc; i_ungetc= numchar_ungetc;
1786     }
1787 #endif
1788     if (mime_f && mimebuf_f==FIXED_MIME) {
1789         i_mgetc = i_getc; i_getc = mime_getc;
1790         i_mungetc = i_ungetc; i_ungetc = mime_ungetc;
1791     }
1792     if (broken_f & 1) {
1793         i_bgetc = i_getc; i_getc = broken_getc;
1794         i_bungetc = i_ungetc; i_ungetc = broken_ungetc;
1795     }
1796     if (input_f == JIS_INPUT || input_f == LATIN1_INPUT) {
1797         set_iconv(-TRUE, e_iconv);
1798     } else if (input_f == SJIS_INPUT) {
1799         set_iconv(-TRUE, s_iconv);
1800 #ifdef UTF8_INPUT_ENABLE
1801     } else if (input_f == UTF8_INPUT) {
1802         set_iconv(-TRUE, w_iconv);
1803     } else if (input_f == UTF16LE_INPUT) {
1804         set_iconv(-TRUE, w_iconv16);
1805 #endif
1806     } else {
1807         set_iconv(FALSE, e_iconv);
1808     }
1809
1810     {
1811         struct input_code *p = input_code_list;
1812         while (p->name){
1813             status_reinit(p++);
1814         }
1815     }
1816 }
1817
1818 /*
1819    Conversion main loop. Code detection only. 
1820  */
1821
1822 int
1823 kanji_convert(f)
1824     FILE  *f;
1825 {
1826     int    c1,
1827                     c2, c3;
1828
1829     module_connection();
1830     c2 = 0;
1831
1832
1833     input_mode = ASCII;
1834     output_mode = ASCII;
1835     shift_mode = FALSE;
1836
1837 #define NEXT continue      /* no output, get next */
1838 #define SEND ;             /* output c1 and c2, get next */
1839 #define LAST break         /* end of loop, go closing  */
1840
1841     while ((c1 = (*i_getc)(f)) != EOF) {
1842         code_status(c1);
1843         if (c2) {
1844             /* second byte */
1845             if (c2 > DEL) {
1846                 /* in case of 8th bit is on */
1847                 if (!estab_f) {
1848                     /* in case of not established yet */
1849                     /* It is still ambiguious */
1850                     if (h_conv(f, c2, c1)==EOF) 
1851                         LAST;
1852                     else 
1853                         c2 = 0;
1854                     NEXT;
1855                 } else
1856                     /* in case of already established */
1857                     if (c1 < AT) {
1858                         /* ignore bogus code */
1859                         c2 = 0;
1860                         NEXT;
1861                     } else
1862                         SEND;
1863             } else
1864                 /* second byte, 7 bit code */
1865                 /* it might be kanji shitfted */
1866                 if ((c1 == DEL) || (c1 <= SPACE)) {
1867                     /* ignore bogus first code */
1868                     c2 = 0;
1869                     NEXT;
1870                 } else
1871                     SEND;
1872         } else {
1873             /* first byte */
1874             if (
1875 #ifdef UTF8_INPUT_ENABLE
1876                 iconv == w_iconv16
1877 #else
1878                 0
1879 #endif
1880                 ) {
1881                 c2 = c1;
1882                 c1 = (*i_getc)(f);
1883                 SEND;
1884 #ifdef NUMCHAR_OPTION
1885             } else if ((c1 & CLASS_MASK) == CLASS_UTF16){
1886                 SEND;
1887 #endif
1888             } else if (c1 > DEL) {
1889                 /* 8 bit code */
1890                 if (!estab_f && !iso8859_f) {
1891                     /* not established yet */
1892                     c2 = c1;
1893                     NEXT;
1894                 } else { /* estab_f==TRUE */
1895                     if (iso8859_f) {
1896                         c2 = ISO8859_1;
1897                         c1 &= 0x7f;
1898                         SEND;
1899                     } else if (SSP<=c1 && c1<0xe0 && iconv == s_iconv) {
1900                         /* SJIS X0201 Case... */
1901                         if(iso2022jp_f && x0201_f==NO_X0201) {
1902                             (*oconv)(GETA1, GETA2);
1903                             NEXT;
1904                         } else {
1905                             c2 = X0201;
1906                             c1 &= 0x7f;
1907                             SEND;
1908                         }
1909                     } else if (c1==SSO && iconv != s_iconv) {
1910                         /* EUC X0201 Case */
1911                         c1 = (*i_getc)(f);  /* skip SSO */
1912                         code_status(c1);
1913                         if (SSP<=c1 && c1<0xe0) {
1914                             if(iso2022jp_f &&  x0201_f==NO_X0201) {
1915                                 (*oconv)(GETA1, GETA2);
1916                                 NEXT;
1917                             } else {
1918                                 c2 = X0201;
1919                                 c1 &= 0x7f;
1920                                 SEND;
1921                             }
1922                         } else  { /* bogus code, skip SSO and one byte */
1923                             NEXT;
1924                         }
1925                     } else {
1926                        /* already established */
1927                        c2 = c1;
1928                        NEXT;
1929                     }
1930                 }
1931             } else if ((c1 > SPACE) && (c1 != DEL)) {
1932                 /* in case of Roman characters */
1933                 if (shift_mode) { 
1934                     /* output 1 shifted byte */
1935                     if (iso8859_f) {
1936                         c2 = ISO8859_1;
1937                         SEND;
1938                     } else if (SPACE<=c1 && c1<(0xe0&0x7f) ){
1939                       /* output 1 shifted byte */
1940                         if(iso2022jp_f && x0201_f==NO_X0201) {
1941                             (*oconv)(GETA1, GETA2);
1942                             NEXT;
1943                         } else {
1944                             c2 = X0201;
1945                             SEND;
1946                         }
1947                     } else {
1948                         /* look like bogus code */
1949                         NEXT;
1950                     }
1951                 } else if (input_mode == X0208) {
1952                     /* in case of Kanji shifted */
1953                     c2 = c1;
1954                     NEXT;
1955                 } else if (c1 == '=' && mime_f && !mime_decode_mode ) {
1956                     /* Check MIME code */
1957                     if ((c1 = (*i_getc)(f)) == EOF) {
1958                         (*oconv)(0, '=');
1959                         LAST;
1960                     } else if (c1 == '?') {
1961                         /* =? is mime conversion start sequence */
1962                         if(mime_f == STRICT_MIME) {
1963                             /* check in real detail */
1964                             if (mime_begin_strict(f) == EOF) 
1965                                 LAST;
1966                             else
1967                                 NEXT;
1968                         } else if (mime_begin(f) == EOF) 
1969                             LAST;
1970                         else
1971                             NEXT;
1972                     } else {
1973                         (*oconv)(0, '=');
1974                         (*i_ungetc)(c1,f);
1975                         NEXT;
1976                     }
1977                 } else {
1978                     /* normal ASCII code */ 
1979                     SEND;
1980                 }
1981             } else if (c1 == SI) {
1982                 shift_mode = FALSE; 
1983                 NEXT;
1984             } else if (c1 == SO) {
1985                 shift_mode = TRUE; 
1986                 NEXT;
1987             } else if (c1 == ESC ) {
1988                 if ((c1 = (*i_getc)(f)) == EOF) {
1989                     /*  (*oconv)(0, ESC); don't send bogus code */
1990                     LAST;
1991                 } else if (c1 == '$') {
1992                     if ((c1 = (*i_getc)(f)) == EOF) {
1993                         /*
1994                         (*oconv)(0, ESC); don't send bogus code 
1995                         (*oconv)(0, '$'); */
1996                         LAST;
1997                     } else if (c1 == '@'|| c1 == 'B') {
1998                         /* This is kanji introduction */
1999                         input_mode = X0208;
2000                         shift_mode = FALSE;
2001                         set_input_codename("ISO-2022-JP");
2002                         debug(input_codename);
2003                         NEXT;
2004                     } else if (c1 == '(') {
2005                         if ((c1 = (*i_getc)(f)) == EOF) {
2006                             /* don't send bogus code 
2007                             (*oconv)(0, ESC);
2008                             (*oconv)(0, '$');
2009                             (*oconv)(0, '(');
2010                                 */
2011                             LAST;
2012                         } else if (c1 == '@'|| c1 == 'B') {
2013                             /* This is kanji introduction */
2014                             input_mode = X0208;
2015                             shift_mode = FALSE;
2016                             NEXT;
2017                         } else {
2018                             /* could be some special code */
2019                             (*oconv)(0, ESC);
2020                             (*oconv)(0, '$');
2021                             (*oconv)(0, '(');
2022                             (*oconv)(0, c1);
2023                             NEXT;
2024                         }
2025                     } else if (broken_f&0x2) {
2026                         /* accept any ESC-(-x as broken code ... */
2027                         input_mode = X0208;
2028                         shift_mode = FALSE;
2029                         NEXT;
2030                     } else {
2031                         (*oconv)(0, ESC);
2032                         (*oconv)(0, '$');
2033                         (*oconv)(0, c1);
2034                         NEXT;
2035                     }
2036                 } else if (c1 == '(') {
2037                     if ((c1 = (*i_getc)(f)) == EOF) {
2038                         /* don't send bogus code 
2039                         (*oconv)(0, ESC);
2040                         (*oconv)(0, '('); */
2041                         LAST;
2042                     } else {
2043                         if (c1 == 'I') {
2044                             /* This is X0201 kana introduction */
2045                             input_mode = X0201; shift_mode = X0201;
2046                             NEXT;
2047                         } else if (c1 == 'B' || c1 == 'J' || c1 == 'H') {
2048                             /* This is X0208 kanji introduction */
2049                             input_mode = ASCII; shift_mode = FALSE;
2050                             NEXT;
2051                         } else if (broken_f&0x2) {
2052                             input_mode = ASCII; shift_mode = FALSE;
2053                             NEXT;
2054                         } else {
2055                             (*oconv)(0, ESC);
2056                             (*oconv)(0, '(');
2057                             /* maintain various input_mode here */
2058                             SEND;
2059                         }
2060                     }
2061                } else if ( c1 == 'N' || c1 == 'n' ){
2062                    /* SS2 */
2063                    c3 = (*i_getc)(f);  /* skip SS2 */
2064                    if ( (SPACE<=c3 && c3 < 0x60) || (0xa0<=c3 && c3 < 0xe0)){
2065                        c1 = c3;
2066                        c2 = X0201;
2067                        SEND;
2068                    }else{
2069                        (*i_ungetc)(c3, f);
2070                        /* lonely ESC  */
2071                        (*oconv)(0, ESC);
2072                        SEND;
2073                    }
2074                 } else {
2075                     /* lonely ESC  */
2076                     (*oconv)(0, ESC);
2077                     SEND;
2078                 }
2079             } else if ((c1 == NL || c1 == CR) && broken_f&4) {
2080                 input_mode = ASCII; set_iconv(FALSE, 0);
2081                 SEND;
2082             /*
2083             } else if (c1 == NL && mime_f && !mime_decode_mode ) {
2084                 if ((c1=(*i_getc)(f))!=EOF && c1 == SPACE) {
2085                     i_ungetc(SPACE,f);
2086                     continue;
2087                 } else {
2088                     i_ungetc(c1,f);
2089                 }
2090                 c1 = NL;
2091                 SEND;
2092             } else if (c1 == CR && mime_f && !mime_decode_mode ) {
2093                 if ((c1=(*i_getc)(f))!=EOF) {
2094                     if (c1==SPACE) {
2095                         i_ungetc(SPACE,f);
2096                         continue;
2097                     } else if (c1 == NL && (c1=(*i_getc)(f))!=EOF && c1 == SPACE) {
2098                         i_ungetc(SPACE,f);
2099                         continue;
2100                     } else {
2101                         i_ungetc(c1,f);
2102                     }
2103                     i_ungetc(NL,f);
2104                 } else {
2105                     i_ungetc(c1,f);
2106                 }
2107                 c1 = CR;
2108                 SEND;
2109             */
2110             } else 
2111                 SEND;
2112         }
2113         /* send: */
2114         if (input_mode == X0208) 
2115             (*oconv)(c2, c1);  /* this is JIS, not SJIS/EUC case */
2116         else if (input_mode) 
2117             (*oconv)(input_mode, c1);  /* other special case */
2118         else if ((*iconv)(c2, c1, 0) < 0){  /* can be EUC/SJIS */
2119             int c0 = (*i_getc)(f);
2120             if (c0 != EOF){
2121                 code_status(c0);
2122                 (*iconv)(c2, c1, c0);
2123             }
2124         }
2125
2126         c2 = 0;
2127         continue;
2128         /* goto next_word */
2129     }
2130
2131     /* epilogue */
2132     (*iconv)(EOF, 0, 0);
2133     return 1;
2134 }
2135
2136 int
2137 h_conv(f, c2, c1)
2138     FILE  *f;
2139     int    c1,
2140                     c2;
2141 {
2142     int    wc,c3;
2143
2144
2145     /** it must NOT be in the kanji shifte sequence      */
2146     /** it must NOT be written in JIS7                   */
2147     /** and it must be after 2 byte 8bit code            */
2148
2149     hold_count = 0;
2150     push_hold_buf(c2);
2151     push_hold_buf(c1);
2152     c2 = 0;
2153
2154     while ((c1 = (*i_getc)(f)) != EOF) {
2155         if (c1 == ESC){
2156             (*i_ungetc)(c1,f);
2157             break;
2158         }
2159         code_status(c1);
2160         if (push_hold_buf(c1) == EOF || estab_f){
2161             break;
2162         }
2163     }
2164
2165     if (!estab_f){
2166         struct input_code *p = input_code_list;
2167         struct input_code *result = p;
2168         if (c1 == EOF){
2169             code_status(c1);
2170         }
2171         while (p->name){
2172             if (p->score < result->score){
2173                 result = p;
2174             }
2175             ++p;
2176         }
2177         set_iconv(FALSE, result->iconv_func);
2178     }
2179
2180
2181     /** now,
2182      ** 1) EOF is detected, or
2183      ** 2) Code is established, or
2184      ** 3) Buffer is FULL (but last word is pushed)
2185      **
2186      ** in 1) and 3) cases, we continue to use
2187      ** Kanji codes by oconv and leave estab_f unchanged.
2188      **/
2189
2190     c3=c1;
2191     wc = 0;
2192     while (wc < hold_count){
2193         c2 = hold_buf[wc++];
2194         if (c2 <= DEL
2195 #ifdef NUMCHAR_OPTION
2196             || (c2 & CLASS_MASK) == CLASS_UTF16
2197 #endif
2198             ){
2199             (*iconv)(0, c2, 0);
2200             continue;
2201         }else if (iconv == s_iconv && 0xa1 <= c2 && c2 <= 0xdf){
2202             (*iconv)(X0201, c2, 0);
2203             continue;
2204         }
2205         if (wc < hold_count){
2206             c1 = hold_buf[wc++];
2207         }else{
2208             c1 = (*i_getc)(f);
2209             if (c1 == EOF){
2210                 c3 = EOF;
2211                 break;
2212             }
2213             code_status(c1);
2214         }
2215         if ((*iconv)(c2, c1, 0) < 0){
2216             int c0;
2217             if (wc < hold_count){
2218                 c0 = hold_buf[wc++];
2219             }else{
2220                 c0 = (*i_getc)(f);
2221                 if (c0 == EOF){
2222                     c3 = EOF;
2223                     break;
2224                 }
2225                 code_status(c0);
2226             }
2227             (*iconv)(c2, c1, c0);
2228             c1 = c0;
2229         }
2230     }
2231     return c3;
2232 }
2233
2234
2235
2236 int
2237 push_hold_buf(c2)
2238      int             c2;
2239 {
2240     if (hold_count >= HOLD_SIZE*2)
2241         return (EOF);
2242     hold_buf[hold_count++] = c2;
2243     return ((hold_count >= HOLD_SIZE*2) ? EOF : hold_count);
2244 }
2245
2246 int s2e_conv(c2, c1, p2, p1)
2247      int c2, c1;
2248      int *p2, *p1;
2249 {
2250 #ifdef SHIFTJIS_CP932
2251     if (cp932_f && CP932_TABLE_BEGIN <= c2 && c2 <= CP932_TABLE_END){
2252         extern unsigned short shiftjis_cp932[3][189];
2253         c1 = shiftjis_cp932[c2 - CP932_TABLE_BEGIN][c1 - 0x40];
2254         if (c1 == 0) return 1;
2255         c2 = c1 >> 8;
2256         c1 &= 0xff;
2257     }
2258 #endif /* SHIFTJIS_CP932 */
2259     c2 = c2 + c2 - ((c2 <= 0x9f) ? SJ0162 : SJ6394);
2260     if (c1 < 0x9f)
2261         c1 = c1 - ((c1 > DEL) ? SPACE : 0x1f);
2262     else {
2263         c1 = c1 - 0x7e;
2264         c2++;
2265     }
2266     if (p2) *p2 = c2;
2267     if (p1) *p1 = c1;
2268     return 0;
2269 }
2270
2271 int
2272 s_iconv(c2, c1, c0)
2273     int    c2,
2274                     c1, c0;
2275 {
2276     if (c2 == X0201) {
2277         c1 &= 0x7f;
2278     } else if ((c2 == EOF) || (c2 == 0) || c2 < SPACE) {
2279         /* NOP */
2280     } else {
2281         int ret = s2e_conv(c2, c1, &c2, &c1);
2282         if (ret) return ret;
2283     }
2284     (*oconv)(c2, c1);
2285     return 0;
2286 }
2287
2288 int
2289 e_iconv(c2, c1, c0)
2290     int    c2,
2291                     c1, c0;
2292 {
2293     if (c2 == X0201) {
2294         c1 &= 0x7f;
2295     } else if (c2 == SSO){
2296         c2 = X0201;
2297         c1 &= 0x7f;
2298     } else if ((c2 == EOF) || (c2 == 0) || c2 < SPACE) {
2299         /* NOP */
2300     } else {
2301         c1 &= 0x7f;
2302         c2 &= 0x7f;
2303     }
2304     (*oconv)(c2, c1);
2305     return 0;
2306 }
2307
2308 #ifdef UTF8_INPUT_ENABLE
2309 int
2310 w2e_conv(c2, c1, c0, p2, p1)
2311     int    c2, c1, c0;
2312     int *p2, *p1;
2313 {
2314     extern unsigned short * utf8_to_euc_2bytes[];
2315     extern unsigned short ** utf8_to_euc_3bytes[];
2316     int ret = 0;
2317
2318     if (0xc0 <= c2 && c2 <= 0xef) {
2319         unsigned short **pp;
2320
2321         if (0xe0 <= c2) {
2322             if (c0 == 0) return -1;
2323             pp = utf8_to_euc_3bytes[c2 - 0x80];
2324             ret = w_iconv_common(c1, c0, pp, sizeof_utf8_to_euc_C2, p2, p1);
2325         } else {
2326             ret =  w_iconv_common(c2, c1, utf8_to_euc_2bytes, sizeof_utf8_to_euc_2bytes, p2, p1);
2327         }
2328 #ifdef NUMCHAR_OPTION
2329         if (ret){
2330             if (p2) *p2 = 0;
2331             if (p1) *p1 = CLASS_UTF16 | ww16_conv(c2, c1, c0);
2332             ret = 0;
2333         }
2334 #endif
2335         return ret;
2336     } else if (c2 == X0201) {
2337         c1 &= 0x7f;
2338     }
2339     if (p2) *p2 = c2;
2340     if (p1) *p1 = c1;
2341     return ret;
2342 }
2343
2344 int
2345 w_iconv(c2, c1, c0)
2346     int    c2,
2347                     c1, c0;
2348 {
2349     int ret = w2e_conv(c2, c1, c0, &c2, &c1);
2350     if (ret == 0){
2351         (*oconv)(c2, c1);
2352     }
2353     return ret;
2354 }
2355
2356 void
2357 w16w_conv(val, p2, p1, p0)
2358      unsigned short val;
2359      int *p2, *p1, *p0;
2360 {
2361     if (val < 0x80){
2362         *p2 = val;
2363         *p1 = 0;
2364         *p0 = 0;
2365     }else if (val < 0x800){
2366         *p2 = 0xc0 | (val >> 6);
2367         *p1 = 0x80 | (val & 0x3f);
2368         *p0 = 0;
2369     }else{
2370         *p2 = 0xe0 | (val >> 12);
2371         *p1 = 0x80 | ((val >> 6) & 0x3f);
2372         *p0 = 0x80 | (val        & 0x3f);
2373     }
2374 }
2375
2376 int
2377 ww16_conv(c2, c1, c0)
2378      int c2, c1, c0;
2379 {
2380     unsigned short val;
2381     if (c2 >= 0xe0){
2382         val = (c2 & 0x0f) << 12;
2383         val |= (c1 & 0x3f) << 6;
2384         val |= (c0 & 0x3f);
2385     }else if (c2 >= 0xc0){
2386         val = (c2 & 0x1f) << 6;
2387         val |= (c1 & 0x3f) << 6;
2388     }else{
2389         val = c2;
2390     }
2391     return val;
2392 }
2393
2394 int
2395 w16e_conv(val, p2, p1)
2396      unsigned short val;
2397      int *p2, *p1;
2398 {
2399     extern unsigned short * utf8_to_euc_2bytes[];
2400     extern unsigned short ** utf8_to_euc_3bytes[];
2401     int c2, c1, c0;
2402     unsigned short **pp;
2403     int psize;
2404     int ret = 0;
2405
2406     w16w_conv(val, &c2, &c1, &c0);
2407     if (c1){
2408         if (c0){
2409             pp = utf8_to_euc_3bytes[c2 - 0x80];
2410             psize = sizeof_utf8_to_euc_C2;
2411             ret =  w_iconv_common(c1, c0, pp, psize, p2, p1);
2412         }else{
2413             pp = utf8_to_euc_2bytes;
2414             psize = sizeof_utf8_to_euc_2bytes;
2415             ret =  w_iconv_common(c2, c1, pp, psize, p2, p1);
2416         }
2417 #ifdef NUMCHAR_OPTION
2418         if (ret){
2419             *p2 = 0;
2420             *p1 = CLASS_UTF16 | val;
2421             ret = 0;
2422         }
2423 #endif
2424     }
2425     return ret;
2426 }
2427
2428 int
2429 w_iconv16(c2, c1, c0)
2430     int    c2, c1,c0;
2431 {
2432     int ret;
2433
2434     if (c2==0376 && c1==0377){
2435         utf16_mode = UTF16LE_INPUT;
2436         return 0;    
2437     } else if (c2==0377 && c1==0376){
2438         utf16_mode = UTF16BE_INPUT;
2439         return 0;    
2440     }
2441     if (c2 != EOF && utf16_mode == UTF16BE_INPUT) {
2442         int tmp;
2443         tmp=c1; c1=c2; c2=tmp;
2444     }
2445     if ((c2==0 && c1 < 0x80) || c2==EOF) {
2446         (*oconv)(c2, c1);
2447         return 0;
2448     }
2449     ret = w16e_conv(((c2<<8)&0xff00) + c1, &c2, &c1);
2450     if (ret) return ret;
2451     (*oconv)(c2, c1);
2452     return 0;
2453 }
2454
2455 int
2456 w_iconv_common(c1, c0, pp, psize, p2, p1)
2457     int    c1,c0;
2458     unsigned short **pp;
2459     int psize;
2460     int *p2, *p1;
2461 {
2462     int c2;
2463     unsigned short *p ;
2464     unsigned short val;
2465
2466     if (pp == 0) return 1;
2467
2468     c1 -= 0x80;
2469     if (c1 < 0 || psize <= c1) return 1;
2470     p = pp[c1];
2471     if (p == 0)  return 1;
2472
2473     c0 -= 0x80;
2474     if (c0 < 0 || sizeof_utf8_to_euc_E5B8 <= c0) return 1;
2475     val = p[c0];
2476     if (val == 0) return 1;
2477
2478     c2 = val >> 8;
2479     if (c2 == SO) c2 = X0201;
2480     c1 = val & 0x7f;
2481     if (p2) *p2 = c2;
2482     if (p1) *p1 = c1;
2483     return 0;
2484 }
2485
2486 #endif
2487
2488 #ifdef UTF8_OUTPUT_ENABLE
2489 int
2490 e2w_conv(c2, c1)
2491     int    c2, c1;
2492 {
2493     extern unsigned short euc_to_utf8_1byte[];
2494     extern unsigned short * euc_to_utf8_2bytes[];
2495     extern unsigned short * euc_to_utf8_2bytes_ms[];
2496     unsigned short *p;
2497
2498     if (c2 == X0201) {
2499         p = euc_to_utf8_1byte;
2500     } else {
2501         c2 &= 0x7f;
2502         c2 = (c2&0x7f) - 0x21;
2503         if (0<=c2 && c2<sizeof_euc_to_utf8_2bytes)
2504             p = ms_ucs_map_f ? euc_to_utf8_2bytes_ms[c2] : euc_to_utf8_2bytes[c2];
2505         else
2506             return 0;
2507     }
2508     if (!p) return 0;
2509     c1 = (c1 & 0x7f) - 0x21;
2510     if (0<=c1 && c1<sizeof_euc_to_utf8_1byte)
2511         return p[c1];
2512     return 0;
2513 }
2514
2515 void
2516 w_oconv(c2, c1)
2517     int    c2,
2518                     c1;
2519 {
2520     int c0;
2521 #ifdef NUMCHAR_OPTION
2522     if (c2 == 0 && (c1 & CLASS_MASK) == CLASS_UTF16){
2523         w16w_conv(c1, &c2, &c1, &c0);
2524         (*o_putc)(c2);
2525         if (c1){
2526             (*o_putc)(c1);
2527             if (c0) (*o_putc)(c0);
2528         }
2529     }
2530 #endif
2531     if (c2 == EOF) {
2532         (*o_putc)(EOF);
2533         return;
2534     }
2535
2536     if (unicode_bom_f==2) {
2537         (*o_putc)('\357');
2538         (*o_putc)('\273');
2539         (*o_putc)('\277');
2540         unicode_bom_f=1;
2541     }
2542
2543     if (c2 == 0) { 
2544         output_mode = ASCII;
2545         (*o_putc)(c1);
2546     } else if (c2 == ISO8859_1) {
2547         output_mode = ISO8859_1;
2548         (*o_putc)(c1 | 0x080);
2549     } else {
2550         output_mode = UTF8;
2551         w16w_conv((unsigned short)e2w_conv(c2, c1), &c2, &c1, &c0);
2552         (*o_putc)(c2);
2553         if (c1){
2554             (*o_putc)(c1);
2555             if (c0) (*o_putc)(c0);
2556         }
2557     }
2558 }
2559
2560 void
2561 w_oconv16(c2, c1)
2562     int    c2,
2563                     c1;
2564 {
2565     if (c2 == EOF) {
2566         (*o_putc)(EOF);
2567         return;
2568     }    
2569
2570     if (unicode_bom_f==2) {
2571         if (w_oconv16_LE){
2572             (*o_putc)((unsigned char)'\377');
2573             (*o_putc)('\376');
2574         }else{
2575             (*o_putc)('\376');
2576             (*o_putc)((unsigned char)'\377');
2577         }
2578         unicode_bom_f=1;
2579     }
2580
2581     if (c2 == ISO8859_1) {
2582         c2 = 0;
2583         c1 |= 0x80;
2584 #ifdef NUMCHAR_OPTION
2585     } else if (c2 == 0 && (c1 & CLASS_MASK) == CLASS_UTF16) {
2586         c2 = (c1 >> 8) & 0xff;
2587         c1 &= 0xff;
2588 #endif
2589     } else if (c2) {
2590         unsigned short val = (unsigned short)e2w_conv(c2, c1);
2591         c2 = (val >> 8) & 0xff;
2592         c1 = val & 0xff;
2593     }
2594     if (w_oconv16_LE){
2595         (*o_putc)(c1);
2596         (*o_putc)(c2);
2597     }else{
2598         (*o_putc)(c2);
2599         (*o_putc)(c1);
2600     }
2601 }
2602
2603 #endif
2604
2605 void
2606 e_oconv(c2, c1)
2607     int    c2,
2608                     c1;
2609 {
2610 #ifdef NUMCHAR_OPTION
2611     if (c2 == 0 && (c1 & CLASS_MASK) == CLASS_UTF16){
2612         w16e_conv(c1, &c2, &c1);
2613     }
2614 #endif
2615     if (c2 == EOF) {
2616         (*o_putc)(EOF);
2617         return;
2618     } else if (c2 == 0) { 
2619         output_mode = ASCII;
2620         (*o_putc)(c1);
2621     } else if (c2 == X0201) {
2622         output_mode = JAPANESE_EUC;
2623         (*o_putc)(SSO); (*o_putc)(c1|0x80);
2624     } else if (c2 == ISO8859_1) {
2625         output_mode = ISO8859_1;
2626         (*o_putc)(c1 | 0x080);
2627     } else {
2628         if ((c1<0x21 || 0x7e<c1) ||
2629            (c2<0x21 || 0x7e<c2)) {
2630             set_iconv(FALSE, 0);
2631             return; /* too late to rescue this char */
2632         }
2633         output_mode = JAPANESE_EUC;
2634         (*o_putc)(c2 | 0x080);
2635         (*o_putc)(c1 | 0x080);
2636     }
2637 }
2638
2639 void
2640 e2s_conv(c2, c1, p2, p1)
2641      int c2, c1, *p2, *p1;
2642 {
2643     if (p2) *p2 = ((c2 - 1) >> 1) + ((c2 <= 0x5e) ? 0x71 : 0xb1);
2644     if (p1) *p1 = c1 + ((c2 & 1) ? ((c1 < 0x60) ? 0x1f : 0x20) : 0x7e);
2645 }
2646
2647 void
2648 s_oconv(c2, c1)
2649     int    c2,
2650                     c1;
2651 {
2652 #ifdef NUMCHAR_OPTION
2653     if (c2 == 0 && (c1 & CLASS_MASK) == CLASS_UTF16){
2654         w16e_conv(c1, &c2, &c1);
2655     }
2656 #endif
2657     if (c2 == EOF) {
2658         (*o_putc)(EOF);
2659         return;
2660     } else if (c2 == 0) {
2661         output_mode = ASCII;
2662         (*o_putc)(c1);
2663     } else if (c2 == X0201) {
2664         output_mode = SHIFT_JIS;
2665         (*o_putc)(c1|0x80);
2666     } else if (c2 == ISO8859_1) {
2667         output_mode = ISO8859_1;
2668         (*o_putc)(c1 | 0x080);
2669     } else {
2670         if ((c1<0x20 || 0x7e<c1) ||
2671            (c2<0x20 || 0x7e<c2)) {
2672             set_iconv(FALSE, 0);
2673             return; /* too late to rescue this char */
2674         }
2675         output_mode = SHIFT_JIS;
2676         e2s_conv(c2, c1, &c2, &c1);
2677
2678 #ifdef SHIFTJIS_CP932
2679         if (cp932inv_f
2680             && CP932INV_TABLE_BEGIN <= c2 && c2 <= CP932INV_TABLE_END){
2681             extern unsigned short cp932inv[2][189];
2682             int c = cp932inv[c2 - CP932INV_TABLE_BEGIN][c1 - 0x40];
2683             if (c){
2684                 c2 = c >> 8;
2685                 c1 = c & 0xff;
2686             }
2687         }
2688 #endif /* SHIFTJIS_CP932 */
2689
2690         (*o_putc)(c2);
2691         if (prefix_table[(unsigned char)c1]){
2692             (*o_putc)(prefix_table[(unsigned char)c1]);
2693         }
2694         (*o_putc)(c1);
2695     }
2696 }
2697
2698 void
2699 j_oconv(c2, c1)
2700     int    c2,
2701                     c1;
2702 {
2703 #ifdef NUMCHAR_OPTION
2704     if ((c1 & CLASS_MASK) == CLASS_UTF16){
2705         w16e_conv(c1, &c2, &c1);
2706     }
2707 #endif
2708     if (c2 == EOF) {
2709         if (output_mode !=ASCII && output_mode!=ISO8859_1) {
2710             (*o_putc)(ESC);
2711             (*o_putc)('(');
2712             (*o_putc)(ascii_intro);
2713             output_mode = ASCII;
2714         }
2715         (*o_putc)(EOF);
2716     } else if (c2==X0201) {
2717         if (output_mode!=X0201) {
2718             output_mode = X0201;
2719             (*o_putc)(ESC);
2720             (*o_putc)('(');
2721             (*o_putc)('I');
2722         }
2723         (*o_putc)(c1);
2724     } else if (c2==ISO8859_1) {
2725             /* iso8859 introduction, or 8th bit on */
2726             /* Can we convert in 7bit form using ESC-'-'-A ? 
2727                Is this popular? */
2728         output_mode = ISO8859_1;
2729         (*o_putc)(c1|0x80);
2730     } else if (c2 == 0) {
2731         if (output_mode !=ASCII && output_mode!=ISO8859_1) {
2732             (*o_putc)(ESC);
2733             (*o_putc)('(');
2734             (*o_putc)(ascii_intro);
2735             output_mode = ASCII;
2736         }
2737         (*o_putc)(c1);
2738     } else {
2739         if (output_mode != X0208) {
2740             output_mode = X0208;
2741             (*o_putc)(ESC);
2742             (*o_putc)('$');
2743             (*o_putc)(kanji_intro);
2744         }
2745         if (c1<0x20 || 0x7e<c1) 
2746             return;
2747         if (c2<0x20 || 0x7e<c2) 
2748             return;
2749         (*o_putc)(c2);
2750         (*o_putc)(c1);
2751     }
2752 }
2753
2754 void
2755 base64_conv(c2, c1)
2756     int    c2,
2757                     c1;
2758 {
2759     if (base64_count>50 && !mimeout_mode && c2==0 && c1==SPACE) {
2760         (*o_putc)(EOF);
2761         (*o_putc)(NL);
2762     } else if (base64_count>66 && mimeout_mode) {
2763         (*o_base64conv)(EOF,0);
2764         (*o_base64conv)(NL,0);
2765         (*o_base64conv)(SPACE,0);
2766     }
2767     (*o_base64conv)(c2,c1);
2768 }
2769
2770
2771 static int broken_buf[3];
2772 static int broken_counter = 0;
2773 static int broken_last = 0;
2774 int
2775 broken_getc(f)
2776 FILE *f;
2777 {
2778     int c,c1;
2779
2780     if (broken_counter>0) {
2781         return broken_buf[--broken_counter];
2782     }
2783     c= (*i_bgetc)(f);
2784     if (c=='$' && broken_last != ESC 
2785             && (input_mode==ASCII || input_mode==X0201)) {
2786         c1= (*i_bgetc)(f);
2787         broken_last = 0;
2788         if (c1=='@'|| 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 if (c=='(' && broken_last != ESC 
2797             && (input_mode==X0208 || input_mode==X0201)) { /* ) */
2798         c1= (*i_bgetc)(f);
2799         broken_last = 0;
2800         if (c1=='J'|| c1=='B') {
2801             broken_buf[0]=c1; broken_buf[1]=c;
2802             broken_counter=2;
2803             return ESC;
2804         } else {
2805             (*i_bungetc)(c1,f);
2806             return c;
2807         }
2808     } else {
2809         broken_last = c;
2810         return c;
2811     }
2812 }
2813
2814 int
2815 broken_ungetc(c,f)
2816 int c;
2817 FILE *f;
2818 {
2819     if (broken_counter<2)
2820         broken_buf[broken_counter++]=c;
2821     return c;
2822 }
2823
2824 static int prev_cr = 0;
2825
2826 void
2827 cr_conv(c2,c1) 
2828 int c2,c1;
2829 {
2830     if (prev_cr) {
2831         prev_cr = 0;
2832         if (! (c2==0&&c1==NL) ) {
2833             cr_conv(0,'\n');
2834         }
2835     }
2836     if (c2) {
2837         (*o_crconv)(c2,c1);
2838     } else if (c1=='\r') {
2839         prev_cr = c1;
2840     } else if (c1=='\n') {
2841         if (crmode_f==CRLF) {
2842             (*o_crconv)(0,'\r');
2843         } else if (crmode_f==CR) {
2844             (*o_crconv)(0,'\r');
2845             return;
2846         } 
2847         (*o_crconv)(0,NL);
2848     } else if (c1!='\032' || crmode_f!=NL){
2849         (*o_crconv)(c2,c1);
2850     }
2851 }
2852
2853 /* 
2854   Return value of fold_conv()
2855
2856        \n  add newline  and output char
2857        \r  add newline  and output nothing
2858        ' ' space
2859        0   skip  
2860        1   (or else) normal output 
2861
2862   fold state in prev (previous character)
2863
2864       >0x80 Japanese (X0208/X0201)
2865       <0x80 ASCII
2866       \n    new line 
2867       ' '   space
2868
2869   This fold algorthm does not preserve heading space in a line.
2870   This is the main difference from fmt.
2871 */
2872
2873 #define char_size(c2,c1) (c2?2:1)
2874
2875 void
2876 fold_conv(c2,c1) 
2877 int c2,c1;
2878
2879     int prev0;
2880     int fold_state=0;
2881
2882     if (c1== '\r' && !fold_preserve_f) {
2883         fold_state=0;  /* ignore cr */
2884     }else if (c1== '\n'&&f_prev=='\r' && fold_preserve_f) {
2885         f_prev = '\n';
2886         fold_state=0;  /* ignore cr */
2887     } else if (c1== BS) {
2888         if (f_line>0) f_line--;
2889         fold_state =  1;
2890     } else if (c2==EOF && f_line != 0) {    /* close open last line */
2891             fold_state = '\n';
2892     } else if ((c1=='\n' && !fold_preserve_f)
2893                || ((c1=='\r'||(c1=='\n'&&f_prev!='\r'))
2894                    && fold_preserve_f)) {
2895         /* new line */
2896         if (fold_preserve_f) { 
2897             f_prev = c1;
2898             f_line = 0;
2899             fold_state =  '\r';
2900         } else if ((f_prev == c1 && !fold_preserve_f)
2901                    || (f_prev == '\n' && fold_preserve_f)
2902                    ) {        /* duplicate newline */
2903             if (f_line) {
2904                 f_line = 0;
2905                 fold_state =  '\n';    /* output two newline */
2906             } else {
2907                 f_line = 0;
2908                 fold_state =  1;
2909             }
2910         } else  {
2911             if (f_prev&0x80) {     /* Japanese? */
2912                 f_prev = c1;
2913                 fold_state =  0;       /* ignore given single newline */
2914             } else if (f_prev==' ') {
2915                 fold_state =  0;
2916             } else {
2917                 f_prev = c1;
2918                 if (++f_line<=fold_len) 
2919                     fold_state =  ' ';
2920                 else {
2921                     f_line = 0;
2922                     fold_state =  '\r';        /* fold and output nothing */
2923                 }
2924             }
2925         }
2926     } else if (c1=='\f') {
2927         f_prev = '\n';
2928         if (f_line==0)
2929             fold_state =  1;
2930         f_line = 0;
2931         fold_state =  '\n';            /* output newline and clear */
2932     } else if ( (c2==0  && c1==' ')||
2933                (c2==0  && c1=='\t')||
2934                (c2=='!'&& c1=='!')) {
2935         /* X0208 kankaku or ascii space */
2936             if (f_prev == ' ') {
2937                 fold_state = 0;         /* remove duplicate spaces */
2938             } else {
2939                 f_prev = ' ';    
2940                 if (++f_line<=fold_len) 
2941                     fold_state = ' ';         /* output ASCII space only */
2942                 else {
2943                     f_prev = ' '; f_line = 0;
2944                     fold_state = '\r';        /* fold and output nothing */
2945                 }
2946             }
2947     } else {
2948         prev0 = f_prev; /* we still need this one... , but almost done */
2949         f_prev = c1;
2950         if (c2 || c2==X0201) 
2951             f_prev |= 0x80;  /* this is Japanese */
2952         f_line += char_size(c2,c1);
2953         if (f_line<=fold_len) {   /* normal case */
2954             fold_state = 1;
2955         } else {
2956             if (f_line>=fold_len+fold_margin) { /* too many kinsou suspension */
2957                 f_line = char_size(c2,c1);
2958                 fold_state =  '\n';       /* We can't wait, do fold now */
2959             } else if (c2==X0201) {
2960             /* simple kinsoku rules  return 1 means no folding  */
2961                 if (c1==(0xde&0x7f)) fold_state = 1; /* \e$B!+\e(B*/
2962                 else if (c1==(0xdf&0x7f)) fold_state = 1; /* \e$B!,\e(B*/
2963                 else if (c1==(0xa4&0x7f)) fold_state = 1; /* \e$B!#\e(B*/
2964                 else if (c1==(0xa3&0x7f)) fold_state = 1; /* \e$B!$\e(B*/
2965                 else if (c1==(0xa1&0x7f)) fold_state = 1; /* \e$B!W\e(B*/
2966                 else if (c1==(0xb0&0x7f)) fold_state = 1; /* - */
2967                 else if (SPACE<=c1 && c1<=(0xdf&0x7f)) {      /* X0201 */
2968                     f_line = 1;
2969                     fold_state = '\n';/* add one new f_line before this character */
2970                 } else {
2971                     f_line = 1;
2972                     fold_state = '\n';/* add one new f_line before this character */
2973                 }
2974             } else if (c2==0) {
2975                 /* kinsoku point in ASCII */ 
2976                 if (  c1==')'||    /* { [ ( */
2977                      c1==']'||
2978                      c1=='}'||
2979                      c1=='.'||
2980                      c1==','||
2981                      c1=='!'||
2982                      c1=='?'||
2983                      c1=='/'||
2984                      c1==':'||
2985                      c1==';' ) {
2986                     fold_state = 1;
2987                 /* just after special */
2988                 } else if (!is_alnum(prev0)) {
2989                     f_line = char_size(c2,c1);
2990                     fold_state = '\n';
2991                 } else if ((prev0==' ') ||   /* ignored new f_line */
2992                       (prev0=='\n')||        /* ignored new f_line */
2993                       (prev0&0x80)) {        /* X0208 - ASCII */
2994                     f_line = char_size(c2,c1);
2995                     fold_state = '\n';/* add one new f_line before this character */
2996                 } else {
2997                     fold_state = 1;  /* default no fold in ASCII */
2998                 }
2999             } else {
3000                 if (c2=='!') {
3001                     if (c1=='"')  fold_state = 1; /* \e$B!"\e(B */
3002                     else if (c1=='#')  fold_state = 1; /* \e$B!#\e(B */
3003                     else if (c1=='W')  fold_state = 1; /* \e$B!W\e(B */
3004                     else if (c1=='K')  fold_state = 1; /* \e$B!K\e(B */
3005                     else if (c1=='$')  fold_state = 1; /* \e$B!$\e(B */
3006                     else if (c1=='%')  fold_state = 1; /* \e$B!%\e(B */
3007                     else if (c1=='\'') fold_state = 1; /* \e$B!\\e(B */
3008                     else if (c1=='(')  fold_state = 1; /* \e$B!(\e(B */
3009                     else if (c1==')')  fold_state = 1; /* \e$B!)\e(B */
3010                     else if (c1=='*')  fold_state = 1; /* \e$B!*\e(B */
3011                     else if (c1=='+')  fold_state = 1; /* \e$B!+\e(B */
3012                     else if (c1==',')  fold_state = 1; /* \e$B!,\e(B */
3013                          /* default no fold in kinsoku */
3014                     else { 
3015                         fold_state = '\n';
3016                         f_line = char_size(c2,c1);
3017                         /* add one new f_line before this character */
3018                     }
3019                 } else {
3020                     f_line = char_size(c2,c1);
3021                     fold_state = '\n'; 
3022                     /* add one new f_line before this character */
3023                 }
3024             }
3025         }
3026     }
3027     /* terminator process */
3028     switch(fold_state) {
3029         case '\n': 
3030             (*o_fconv)(0,'\n');
3031             (*o_fconv)(c2,c1);
3032             break;
3033         case 0:    
3034             return;
3035         case '\r': 
3036             (*o_fconv)(0,'\n');
3037             break;
3038         case '\t': 
3039         case ' ': 
3040             (*o_fconv)(0,' ');
3041             break;
3042         default:
3043             (*o_fconv)(c2,c1);
3044     }
3045 }
3046
3047 int z_prev2=0,z_prev1=0;
3048
3049 void
3050 z_conv(c2,c1)
3051 int c2,c1;
3052 {
3053
3054     /* if (c2) c1 &= 0x7f; assertion */
3055
3056     if (x0201_f && z_prev2==X0201) {  /* X0201 */
3057         if (c1==(0xde&0x7f)) { /* \e$BByE@\e(B */
3058             z_prev2=0;
3059             (*o_zconv)(dv[(z_prev1-SPACE)*2],dv[(z_prev1-SPACE)*2+1]);
3060             return;
3061         } else if (c1==(0xdf&0x7f)&&ev[(z_prev1-SPACE)*2]) {  /* \e$BH>ByE@\e(B */
3062             z_prev2=0;
3063             (*o_zconv)(ev[(z_prev1-SPACE)*2],ev[(z_prev1-SPACE)*2+1]);
3064             return;
3065         } else {
3066             z_prev2=0;
3067             (*o_zconv)(cv[(z_prev1-SPACE)*2],cv[(z_prev1-SPACE)*2+1]);
3068         }
3069     }
3070
3071     if (c2==EOF) {
3072         (*o_zconv)(c2,c1);
3073         return;
3074     }
3075
3076     if (x0201_f && c2==X0201) {
3077         if (dv[(c1-SPACE)*2]||ev[(c1-SPACE)*2]) {
3078             /* wait for \e$BByE@\e(B or \e$BH>ByE@\e(B */
3079             z_prev1 = c1; z_prev2 = c2;
3080             return;
3081         } else {
3082             (*o_zconv)(cv[(c1-SPACE)*2],cv[(c1-SPACE)*2+1]);
3083             return;
3084         }
3085     }
3086
3087     /* JISX0208 Alphabet */
3088     if (alpha_f && c2 == 0x23 ) {
3089         c2 = 0;
3090     } else if (alpha_f && c2 == 0x21 ) { 
3091     /* JISX0208 Kigou */
3092        if (0x21==c1) {
3093            if (alpha_f&0x2) {
3094                c1 = ' ';
3095                c2 = 0;
3096            } else if (alpha_f&0x4) {
3097                 (*o_zconv)(0,' ');
3098                 (*o_zconv)(0,' ');
3099                 return;
3100            } 
3101        } else if (0x20<c1 && c1<0x7f && fv[c1-0x20]) {
3102            c1 = fv[c1-0x20];
3103            c2 =  0;
3104            if (alpha_f&0x8) {
3105                char *entity = 0;
3106                switch (c1){
3107                  case '>': entity = "&gt;"; break;
3108                  case '<': entity = "&lt;"; break;
3109                  case '\"': entity = "&quot;"; break;
3110                  case '&': entity = "&amp;"; break;
3111                }
3112                if (entity){
3113                    while (*entity) (*o_zconv)(0, *entity++);
3114                    return;
3115                }
3116            }
3117        } 
3118     }
3119     (*o_zconv)(c2,c1);
3120 }
3121
3122
3123 #define rot13(c)  ( \
3124       ( c < 'A' ) ? c: \
3125       (c <= 'M')  ? (c + 13): \
3126       (c <= 'Z')  ? (c - 13): \
3127       (c < 'a')   ? (c): \
3128       (c <= 'm')  ? (c + 13): \
3129       (c <= 'z')  ? (c - 13): \
3130       (c) \
3131 )
3132
3133 #define  rot47(c) ( \
3134       ( c < '!' ) ? c: \
3135       ( c <= 'O' ) ? (c + 47) : \
3136       ( c <= '~' ) ?  (c - 47) : \
3137       c \
3138 )
3139
3140 void
3141 rot_conv(c2,c1)
3142 int c2,c1;
3143 {
3144     if (c2==0 || c2==X0201 || c2==ISO8859_1) {
3145         c1 = rot13(c1);
3146     } else if (c2) {
3147         c1 = rot47(c1);
3148         c2 = rot47(c2);
3149     }
3150     (*o_rot_conv)(c2,c1);
3151 }
3152
3153 void
3154 hira_conv(c2,c1)
3155 int c2,c1;
3156 {
3157     if ((hira_f & 1) && c2==0x25 && 0x20<c1 && c1<0x74) {
3158         c2 = 0x24;
3159     } else if ((hira_f & 2) && c2==0x24 && 0x20<c1 && c1<0x74) {
3160         c2 = 0x25;
3161     } 
3162     (*o_hira_conv)(c2,c1);
3163 }
3164
3165
3166 void
3167 iso2022jp_check_conv(c2,c1)
3168 int    c2, c1;
3169 {
3170     static int range[RANGE_NUM_MAX][2] = {
3171         {0x222f, 0x2239,},
3172         {0x2242, 0x2249,},
3173         {0x2251, 0x225b,},
3174         {0x226b, 0x2271,},
3175         {0x227a, 0x227d,},
3176         {0x2321, 0x232f,},
3177         {0x233a, 0x2340,},
3178         {0x235b, 0x2360,},
3179         {0x237b, 0x237e,},
3180         {0x2474, 0x247e,},
3181         {0x2577, 0x257e,},
3182         {0x2639, 0x2640,},
3183         {0x2659, 0x267e,},
3184         {0x2742, 0x2750,},
3185         {0x2772, 0x277e,},
3186         {0x2841, 0x287e,},
3187         {0x4f54, 0x4f7e,},
3188         {0x7425, 0x747e},
3189     };
3190     int i;
3191     int start, end, c;
3192
3193     if(c2 >= 0x00 && c2 <= 0x20 && c1 >= 0x7f && c1 <= 0xff) {
3194         c2 = GETA1;
3195         c1 = GETA2;
3196     }
3197     if((c2 >= 0x29 && c2 <= 0x2f) || (c2 >= 0x75 && c2 <= 0x7e)) {
3198         c2 = GETA1;
3199         c1 = GETA2;
3200     }
3201
3202     for (i = 0; i < RANGE_NUM_MAX; i++) {
3203         start = range[i][0];
3204         end   = range[i][1];
3205         c     = (c2 << 8) + c1;
3206         if (c >= start && c <= end) {
3207             c2 = GETA1;
3208             c1 = GETA2;
3209         }
3210     }
3211     (*o_iso2022jp_check_conv)(c2,c1);
3212 }
3213
3214
3215 /* This converts  =?ISO-2022-JP?B?HOGE HOGE?= */
3216
3217 unsigned char *mime_pattern[] = {
3218    (unsigned char *)"\075?EUC-JP?B?",
3219    (unsigned char *)"\075?SHIFT_JIS?B?",
3220    (unsigned char *)"\075?ISO-8859-1?Q?",
3221    (unsigned char *)"\075?ISO-8859-1?B?",
3222    (unsigned char *)"\075?ISO-2022-JP?B?",
3223    (unsigned char *)"\075?ISO-2022-JP?Q?",
3224 #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
3225    (unsigned char *)"\075?UTF-8?B?",
3226    (unsigned char *)"\075?UTF-8?Q?",
3227 #endif
3228    (unsigned char *)"\075?US-ASCII?Q?",
3229    NULL
3230 };
3231
3232
3233 /* \e$B3:Ev$9$k%3!<%I$NM%@hEY$r>e$2$k$?$a$NL\0u\e(B */
3234 int (*mime_priority_func[])PROTO((int c2, int c1, int c0)) = {
3235     e_iconv, s_iconv, 0, 0, 0, 0,
3236 #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
3237     w_iconv, w_iconv,
3238 #endif
3239     0,
3240 };
3241
3242 int      mime_encode[] = {
3243     JAPANESE_EUC, SHIFT_JIS,ISO8859_1, ISO8859_1, X0208, X0201,
3244 #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
3245     UTF8, UTF8,
3246 #endif
3247     ASCII,
3248     0
3249 };
3250
3251 int      mime_encode_method[] = {
3252     'B', 'B','Q', 'B', 'B', 'Q',
3253 #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
3254     'B', 'Q',
3255 #endif
3256     'Q',
3257     0
3258 };
3259
3260
3261 #define MAXRECOVER 20
3262
3263 /* I don't trust portablity of toupper */
3264 #define nkf_toupper(c)  (('a'<=c && c<='z')?(c-('a'-'A')):c)
3265 #define nkf_isdigit(c)  ('0'<=c && c<='9')
3266 #define nkf_isxdigit(c)  (nkf_isdigit(c) || ('a'<=c && c<='f') || ('A'<=c && c <= 'F'))
3267
3268 void
3269 switch_mime_getc()
3270 {
3271     if (i_getc!=mime_getc) {
3272         i_mgetc = i_getc; i_getc = mime_getc;
3273         i_mungetc = i_ungetc; i_ungetc = mime_ungetc;
3274         if(mime_f==STRICT_MIME) {
3275             i_mgetc_buf = i_mgetc; i_mgetc = mime_getc_buf;
3276             i_mungetc_buf = i_mungetc; i_mungetc = mime_ungetc_buf;
3277         }
3278     }
3279 }
3280
3281 void
3282 unswitch_mime_getc()
3283 {
3284     if(mime_f==STRICT_MIME) {
3285         i_mgetc = i_mgetc_buf;
3286         i_mungetc = i_mungetc_buf;
3287     }
3288     i_getc = i_mgetc;
3289     i_ungetc = i_mungetc;
3290 }
3291
3292 int
3293 mime_begin_strict(f)
3294 FILE *f;
3295 {
3296     int c1 = 0;
3297     int i,j,k;
3298     unsigned char *p,*q;
3299     int r[MAXRECOVER];    /* recovery buffer, max mime pattern lenght */
3300
3301     mime_decode_mode = FALSE;
3302     /* =? has been checked */
3303     j = 0;
3304     p = mime_pattern[j];
3305     r[0]='='; r[1]='?';
3306
3307     for(i=2;p[i]>' ';i++) {                   /* start at =? */
3308         if ( ((r[i] = c1 = (*i_getc)(f))==EOF) || nkf_toupper(c1) != p[i] ) {
3309             /* pattern fails, try next one */
3310             q = p;
3311             while ((p = mime_pattern[++j])) {
3312                 for(k=2;k<i;k++)              /* assume length(p) > i */
3313                     if (p[k]!=q[k]) break;
3314                 if (k==i && nkf_toupper(c1)==p[k]) break;
3315             }
3316             if (p) continue;  /* found next one, continue */
3317             /* all fails, output from recovery buffer */
3318             (*i_ungetc)(c1,f);
3319             for(j=0;j<i;j++) {
3320                 (*oconv)(0,r[j]);
3321             }
3322             return c1;
3323         }
3324     }
3325     mime_decode_mode = p[i-2];
3326
3327     clr_code_score(find_inputcode_byfunc(mime_priority_func[j]), SCORE_iMIME);
3328
3329     if (mime_decode_mode=='B') {
3330         mimebuf_f = unbuf_f;
3331         if (!unbuf_f) {
3332             /* do MIME integrity check */
3333             return mime_integrity(f,mime_pattern[j]);
3334         } 
3335     }
3336     switch_mime_getc();
3337     mimebuf_f = TRUE;
3338     return c1;
3339 }
3340
3341 int
3342 mime_getc_buf(f) 
3343 FILE *f;
3344 {
3345     /* we don't keep eof of Fifo, becase it contains ?= as
3346        a terminator. It was checked in mime_integrity. */
3347     return ((mimebuf_f)?
3348         (*i_mgetc_buf)(f):Fifo(mime_input++));
3349 }
3350
3351 int
3352 mime_ungetc_buf(c,f) 
3353 FILE *f;
3354 int c;
3355 {
3356     if (mimebuf_f)
3357         (*i_mungetc_buf)(c,f);
3358     else 
3359         Fifo(--mime_input)=c;
3360     return c;
3361 }
3362
3363 int
3364 mime_begin(f)
3365 FILE *f;
3366 {
3367     int c1;
3368     int i,k;
3369
3370     /* In NONSTRICT mode, only =? is checked. In case of failure, we  */
3371     /* re-read and convert again from mime_buffer.  */
3372
3373     /* =? has been checked */
3374     k = mime_last;
3375     Fifo(mime_last++)='='; Fifo(mime_last++)='?';
3376     for(i=2;i<MAXRECOVER;i++) {                   /* start at =? */
3377         /* We accept any character type even if it is breaked by new lines */
3378         c1 = (*i_getc)(f); Fifo(mime_last++)= c1 ;
3379         if (c1=='\n'||c1==' '||c1=='\r'||
3380                 c1=='-'||c1=='_'||is_alnum(c1) ) continue;
3381         if (c1=='=') {
3382             /* Failed. But this could be another MIME preemble */
3383             (*i_ungetc)(c1,f);
3384             mime_last--;
3385             break;
3386         }
3387         if (c1!='?') break;
3388         else {
3389             /* c1=='?' */
3390             c1 = (*i_getc)(f); Fifo(mime_last++) = c1;
3391             if (!(++i<MAXRECOVER) || c1==EOF) break;
3392             if (c1=='b'||c1=='B') {
3393                 mime_decode_mode = 'B';
3394             } else if (c1=='q'||c1=='Q') {
3395                 mime_decode_mode = 'Q';
3396             } else {
3397                 break;
3398             }
3399             c1 = (*i_getc)(f); Fifo(mime_last++) = c1;
3400             if (!(++i<MAXRECOVER) || c1==EOF) break;
3401             if (c1!='?') {
3402                 mime_decode_mode = FALSE;
3403             }
3404             break;
3405         }
3406     }
3407     switch_mime_getc();
3408     if (!mime_decode_mode) {
3409         /* false MIME premble, restart from mime_buffer */
3410         mime_decode_mode = 1;  /* no decode, but read from the mime_buffer */
3411         /* Since we are in MIME mode until buffer becomes empty,    */
3412         /* we never go into mime_begin again for a while.           */
3413         return c1;
3414     }
3415     /* discard mime preemble, and goto MIME mode */
3416     mime_last = k;
3417     /* do no MIME integrity check */
3418     return c1;   /* used only for checking EOF */
3419 }
3420
3421 #ifdef CHECK_OPTION
3422 void
3423 no_putc(c)
3424      int c;
3425 {
3426     ;
3427 }
3428
3429 void debug(str)
3430      char *str;
3431 {
3432     if (debug_f){
3433         fprintf(stderr, "%s\n", str);
3434     }
3435 }
3436 #endif
3437
3438 void
3439 set_input_codename (codename)
3440     char *codename;
3441 {
3442     if (guess_f && 
3443         is_inputcode_set &&
3444         strcmp(codename, "") != 0 && 
3445         strcmp(codename, input_codename) != 0)
3446     {
3447         is_inputcode_mixed = TRUE;
3448     }
3449     input_codename = codename;
3450     is_inputcode_set = TRUE;
3451 }
3452
3453 void
3454 print_guessed_code (filename)
3455     char *filename;
3456 {
3457     char *codename = "BINARY";
3458     if (!is_inputcode_mixed) {
3459         if (strcmp(input_codename, "") == 0) {
3460             codename = "ASCII";
3461         } else {
3462             codename = input_codename;
3463         }
3464     }
3465     if (filename != NULL) printf("%s:", filename);
3466     printf("%s\n", codename);
3467 }
3468
3469 int
3470 hex2bin(x)
3471      int x;
3472 {
3473     if (nkf_isdigit(x)) return x - '0';
3474     return nkf_toupper(x) - 'A' + 10;
3475 }
3476
3477 #ifdef INPUT_OPTION 
3478
3479 #ifdef ANSI_C_PROTOTYPE
3480 int hex_getc(int ch, FILE *f, int (*g)(FILE *f), int (*u)(int c, FILE *f))
3481 #else
3482 int
3483 hex_getc(ch, f, g, u)
3484      int ch;
3485      FILE *f;
3486      int (*g)();
3487      int (*u)();
3488 #endif
3489 {
3490     int c1, c2, c3;
3491     c1 = (*g)(f);
3492     if (c1 != ch){
3493         return c1;
3494     }
3495     c2 = (*g)(f);
3496     if (!nkf_isxdigit(c2)){
3497         (*u)(c2, f);
3498         return c1;
3499     }
3500     c3 = (*g)(f);
3501     if (!nkf_isxdigit(c3)){
3502         (*u)(c2, f);
3503         (*u)(c3, f);
3504         return c1;
3505     }
3506     return (hex2bin(c2) << 4) | hex2bin(c3);
3507 }
3508
3509 int
3510 cap_getc(f)
3511      FILE *f;
3512 {
3513     return hex_getc(':', f, i_cgetc, i_cungetc);
3514 }
3515
3516 int
3517 cap_ungetc(c, f)
3518      int c;
3519      FILE *f;
3520 {
3521     return (*i_cungetc)(c, f);
3522 }
3523
3524 int
3525 url_getc(f)
3526      FILE *f;
3527 {
3528     return hex_getc('%', f, i_ugetc, i_uungetc);
3529 }
3530
3531 int
3532 url_ungetc(c, f)
3533      int c;
3534      FILE *f;
3535 {
3536     return (*i_uungetc)(c, f);
3537 }
3538 #endif
3539
3540 #ifdef NUMCHAR_OPTION
3541 int
3542 numchar_getc(f)
3543      FILE *f;
3544 {
3545     int (*g)() = i_ngetc;
3546     int (*u)() = i_nungetc;
3547     int i = 0, j;
3548     int buf[8];
3549     long c = -1;
3550
3551     buf[i] = (*g)(f);
3552     if (buf[i] == '&'){
3553         buf[++i] = (*g)(f);
3554         if (buf[i] == '#'){
3555             c = 0;
3556             buf[++i] = (*g)(f);
3557             if (buf[i] == 'x' || buf[i] == 'X'){
3558                 for (j = 0; j < 5; j++){
3559                     buf[++i] = (*g)(f);
3560                     if (!nkf_isxdigit(buf[i])){
3561                         if (buf[i] != ';'){
3562                             c = -1;
3563                         }
3564                         break;
3565                     }
3566                     c <<= 4;
3567                     c |= hex2bin(buf[i]);
3568                 }
3569             }else{
3570                 for (j = 0; j < 6; j++){
3571                     if (j){
3572                         buf[++i] = (*g)(f);
3573                     }
3574                     if (!nkf_isdigit(buf[i])){
3575                         if (buf[i] != ';'){
3576                             c = -1;
3577                         }
3578                         break;
3579                     }
3580                     c *= 10;
3581                     c += hex2bin(buf[i]);
3582                 }
3583             }
3584         }
3585     }
3586     if (c != -1){
3587         return CLASS_UTF16 | c;
3588     }
3589     while (i > 0){
3590         (*u)(buf[i], f);
3591         --i;
3592     }
3593     return buf[0];
3594 }
3595
3596 int
3597 numchar_ungetc(c, f)
3598      int c;
3599      FILE *f;
3600 {
3601     return (*i_nungetc)(c, f);
3602 }
3603 #endif
3604
3605
3606 int 
3607 mime_getc(f)
3608 FILE *f;
3609 {
3610     int c1, c2, c3, c4, cc;
3611     int t1, t2, t3, t4, mode, exit_mode;
3612     int lwsp_count;
3613     char *lwsp_buf;
3614     char *lwsp_buf_new;
3615     int lwsp_size = 128;
3616
3617     if (mime_top != mime_last) {  /* Something is in FIFO */
3618         return  Fifo(mime_top++);
3619     }
3620     if (mime_decode_mode==1 ||mime_decode_mode==FALSE) {
3621         mime_decode_mode=FALSE;
3622         unswitch_mime_getc();
3623         return (*i_getc)(f);
3624     }
3625
3626     if (mimebuf_f == FIXED_MIME)
3627         exit_mode = mime_decode_mode;
3628     else
3629         exit_mode = FALSE;
3630     if (mime_decode_mode == 'Q') {
3631         if ((c1 = (*i_mgetc)(f)) == EOF) return (EOF);
3632 restart_mime_q:
3633         if (c1=='_') return ' ';
3634         if (c1!='=' && c1!='?') {
3635             return c1;
3636         }
3637                 
3638         mime_decode_mode = exit_mode; /* prepare for quit */
3639         if (c1<=' ') return c1;
3640         if ((c2 = (*i_mgetc)(f)) == EOF) return (EOF);
3641         if (c1=='?'&&c2=='=' && mimebuf_f != FIXED_MIME) {
3642             /* end Q encoding */
3643             input_mode = exit_mode;
3644             lwsp_count = 0;
3645             lwsp_buf = malloc((lwsp_size+5)*sizeof(char));
3646             if (lwsp_buf==NULL) {
3647                 perror("can't malloc");
3648                 return -1;
3649             }
3650             while ((c1=(*i_getc)(f))!=EOF) {
3651                 switch (c1) {
3652                 case NL:
3653                 case CR:
3654                     if (c1==NL) {
3655                         if ((c1=(*i_getc)(f))!=EOF && (c1==SPACE||c1==TAB)) {
3656                             i_ungetc(SPACE,f);
3657                             continue;
3658                         } else {
3659                             i_ungetc(c1,f);
3660                         }
3661                         c1 = NL;
3662                     } else {
3663                         if ((c1=(*i_getc)(f))!=EOF && c1 == NL) {
3664                             if ((c1=(*i_getc)(f))!=EOF && (c1==SPACE||c1==TAB)) {
3665                                 i_ungetc(SPACE,f);
3666                                 continue;
3667                             } else {
3668                                 i_ungetc(c1,f);
3669                             }
3670                             i_ungetc(NL,f);
3671                         } else {
3672                             i_ungetc(c1,f);
3673                         }
3674                         c1 = CR;
3675                     }
3676                     break;
3677                 case SPACE:
3678                 case TAB:
3679                     lwsp_buf[lwsp_count] = c1;
3680                     if (lwsp_count++>lwsp_size){
3681                         lwsp_size *= 2;
3682                         lwsp_buf_new = realloc(lwsp_buf, (lwsp_size+5)*sizeof(char));
3683                         if (lwsp_buf_new==NULL) {
3684                             free(lwsp_buf);
3685                             lwsp_buf = NULL;
3686                             perror("can't realloc");
3687                             return -1;
3688                         }
3689                         lwsp_buf = lwsp_buf_new;
3690                     }
3691                     continue;
3692                 }
3693                 break;
3694             }
3695             if (lwsp_count > 0) {
3696                 if (c1=='=' && (lwsp_buf[lwsp_count-1]==SPACE||lwsp_buf[lwsp_count-1]==TAB)) {
3697                     lwsp_count = 0;
3698                 } else {
3699                     i_ungetc(c1,f);
3700                     for(lwsp_count--;lwsp_count>0;lwsp_count--)
3701                         i_ungetc(lwsp_buf[lwsp_count],f);
3702                     c1 = lwsp_buf[0];
3703                 }
3704             }
3705             free(lwsp_buf);
3706             lwsp_buf = NULL;
3707             return c1;
3708         }
3709         if (c1=='='&&c2<' ') { /* this is soft wrap */
3710             while((c1 =  (*i_mgetc)(f)) <=' ') {
3711                 if ((c1 = (*i_mgetc)(f)) == EOF) return (EOF);
3712             }
3713             mime_decode_mode = 'Q'; /* still in MIME */
3714             goto restart_mime_q;
3715         }
3716         if (c1=='?') {
3717             mime_decode_mode = 'Q'; /* still in MIME */
3718             (*i_mungetc)(c2,f);
3719             return c1;
3720         }
3721         if ((c3 = (*i_mgetc)(f)) == EOF) return (EOF);
3722         if (c2<=' ') return c2;
3723         mime_decode_mode = 'Q'; /* still in MIME */
3724 #define hex(c)   (('0'<=c&&c<='9')?(c-'0'):\
3725      ('A'<=c&&c<='F')?(c-'A'+10):('a'<=c&&c<='f')?(c-'a'+10):0)
3726         return ((hex(c2)<<4) + hex(c3));
3727     }
3728
3729     if (mime_decode_mode != 'B') {
3730         mime_decode_mode = FALSE;
3731         return (*i_mgetc)(f);
3732     }
3733
3734
3735     /* Base64 encoding */
3736     /* 
3737         MIME allows line break in the middle of 
3738         Base64, but we are very pessimistic in decoding
3739         in unbuf mode because MIME encoded code may broken by 
3740         less or editor's control sequence (such as ESC-[-K in unbuffered
3741         mode. ignore incomplete MIME.
3742     */
3743     mode = mime_decode_mode;
3744     mime_decode_mode = exit_mode;  /* prepare for quit */
3745
3746     while ((c1 = (*i_mgetc)(f))<=' ') {
3747         if (c1==EOF)
3748             return (EOF);
3749     }
3750 mime_c2_retry:
3751     if ((c2 = (*i_mgetc)(f))<=' ') {
3752         if (c2==EOF)
3753             return (EOF);
3754         if (mime_f != STRICT_MIME) goto mime_c2_retry;
3755         if (mimebuf_f!=FIXED_MIME) input_mode = ASCII;  
3756         return c2;
3757     }
3758     if ((c1 == '?') && (c2 == '=')) {
3759         input_mode = ASCII;
3760         lwsp_count = 0;
3761         lwsp_buf = malloc((lwsp_size+5)*sizeof(char));
3762         if (lwsp_buf==NULL) {
3763             perror("can't malloc");
3764             return -1;