OSDN Git Service

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