OSDN Git Service

* remove extra SPACEs
[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.59 2005/02/19 00:57:06 naruse Exp $ */
43 #define NKF_VERSION "2.0.4"
44 #define NKF_RELEASE_DATE "2005-02-02"
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             mimebuf_f = FALSE;      /* MIME buffered input */
374 static int             broken_f = FALSE;       /* convert ESC-less broken JIS */
375 static int             iso8859_f = FALSE;      /* ISO8859 through */
376 static int             mimeout_f = FALSE;       /* base64 mode */
377 #if defined(MSDOS) || defined(__OS2__) 
378 static int             x0201_f = TRUE;         /* Assume JISX0201 kana */
379 #else
380 static int             x0201_f = NO_X0201;     /* Assume NO JISX0201 */
381 #endif
382 static int             iso2022jp_f = FALSE;    /* convert ISO-2022-JP */
383 #ifdef UTF8_OUTPUT_ENABLE
384 static int             unicode_bom_f= 0;   /* Output Unicode BOM */
385 static int             w_oconv16_LE = 0;   /* utf-16 little endian */
386 static int             ms_ucs_map_f = FALSE;   /* Microsoft UCS Mapping Compatible */
387 #endif
388
389
390 #ifdef NUMCHAR_OPTION
391
392 #define CLASS_MASK  0x0f000000
393 #define CLASS_UTF16 0x01000000
394 #endif
395
396 #ifdef INPUT_OPTION
397 static int cap_f = FALSE;
398 static int (*i_cgetc)PROTO((FILE *)) = std_getc; /* input of cgetc */
399 static int (*i_cungetc)PROTO((int c ,FILE *f)) = std_ungetc;
400 STATIC int cap_getc PROTO((FILE *f));
401 STATIC int cap_ungetc PROTO((int c,FILE *f));
402
403 static int url_f = FALSE;
404 static int (*i_ugetc)PROTO((FILE *)) = std_getc; /* input of ugetc */
405 static int (*i_uungetc)PROTO((int c ,FILE *f)) = std_ungetc;
406 STATIC int url_getc PROTO((FILE *f));
407 STATIC int url_ungetc PROTO((int c,FILE *f));
408
409 static int numchar_f = FALSE;
410 static int (*i_ngetc)PROTO((FILE *)) = std_getc; /* input of ugetc */
411 static int (*i_nungetc)PROTO((int c ,FILE *f)) = std_ungetc;
412 STATIC int numchar_getc PROTO((FILE *f));
413 STATIC int numchar_ungetc PROTO((int c,FILE *f));
414 #endif
415
416 #ifdef CHECK_OPTION
417 static int noout_f = FALSE;
418 STATIC void no_putc PROTO((int c));
419 static int debug_f = FALSE;
420 STATIC void debug PROTO((char *str));
421 #endif
422
423 static int guess_f = FALSE;
424 STATIC  void    print_guessed_code PROTO((char *filename));
425 STATIC  void    set_input_codename PROTO((char *codename));
426 static int is_inputcode_mixed = FALSE;
427 static int is_inputcode_set   = FALSE;
428
429 #ifdef EXEC_IO
430 static int exec_f = 0;
431 #endif
432
433 #ifdef SHIFTJIS_CP932
434 STATIC int cp932_f = TRUE;
435 #define CP932_TABLE_BEGIN (0xfa)
436 #define CP932_TABLE_END   (0xfc)
437
438 STATIC int cp932inv_f = TRUE;
439 #define CP932INV_TABLE_BEGIN (0xed)
440 #define CP932INV_TABLE_END   (0xee)
441
442 /* STATIC int cp932_conv PROTO((int c2, int c1)); */
443 #endif /* SHIFTJIS_CP932 */
444
445 #ifdef X0212_ENABLE
446 STATIC int x0212_f = FALSE;
447 static int x0212_shift PROTO((int c));
448 static int x0212_unshift PROTO((int c));
449 #endif
450
451 STATIC unsigned char prefix_table[256];
452
453 STATIC void e_status PROTO((struct input_code *, int));
454 STATIC void s_status PROTO((struct input_code *, int));
455
456 #ifdef UTF8_INPUT_ENABLE
457 STATIC void w_status PROTO((struct input_code *, int));
458 STATIC void w16_status PROTO((struct input_code *, int));
459 static int             utf16_mode = UTF16LE_INPUT;
460 #endif
461
462 struct input_code input_code_list[] = {
463     {"EUC-JP",    0, 0, 0, {0, 0, 0}, e_status, e_iconv, 0},
464     {"Shift_JIS", 0, 0, 0, {0, 0, 0}, s_status, s_iconv, 0},
465     {"UTF-8",     0, 0, 0, {0, 0, 0}, w_status, w_iconv, 0},
466     {"UTF-16",    0, 0, 0, {0, 0, 0}, w16_status, w_iconv16, 0},
467     {0}
468 };
469
470 static int              mimeout_mode = 0;
471 static int              base64_count = 0;
472
473 /* X0208 -> ASCII converter */
474
475 /* fold parameter */
476 static int             f_line = 0;    /* chars in line */
477 static int             f_prev = 0;
478 static int             fold_preserve_f = FALSE; /* preserve new lines */
479 static int             fold_f  = FALSE;
480 static int             fold_len  = 0;
481
482 /* options */
483 static unsigned char   kanji_intro = DEFAULT_J;
484 static unsigned char   ascii_intro = DEFAULT_R;
485
486 /* Folding */
487
488 #define FOLD_MARGIN  10
489 #define DEFAULT_FOLD 60
490
491 static int             fold_margin  = FOLD_MARGIN;
492
493 /* converters */
494
495 #ifdef DEFAULT_CODE_JIS
496 #   define  DEFAULT_CONV j_oconv
497 #endif
498 #ifdef DEFAULT_CODE_SJIS
499 #   define  DEFAULT_CONV s_oconv
500 #endif
501 #ifdef DEFAULT_CODE_EUC
502 #   define  DEFAULT_CONV e_oconv
503 #endif
504 #ifdef DEFAULT_CODE_UTF8
505 #   define  DEFAULT_CONV w_oconv
506 #endif
507
508 /* process default */
509 static void (*output_conv)PROTO((int c2,int c1)) = DEFAULT_CONV;   
510
511 static void (*oconv)PROTO((int c2,int c1)) = no_connection; 
512 /* s_iconv or oconv */
513 static int (*iconv)PROTO((int c2,int c1,int c0)) = no_connection2;   
514
515 static void (*o_zconv)PROTO((int c2,int c1)) = no_connection; 
516 static void (*o_fconv)PROTO((int c2,int c1)) = no_connection; 
517 static void (*o_crconv)PROTO((int c2,int c1)) = no_connection; 
518 static void (*o_rot_conv)PROTO((int c2,int c1)) = no_connection; 
519 static void (*o_hira_conv)PROTO((int c2,int c1)) = no_connection; 
520 static void (*o_base64conv)PROTO((int c2,int c1)) = no_connection;
521 static void (*o_iso2022jp_check_conv)PROTO((int c2,int c1)) = no_connection;
522
523 /* static redirections */
524
525 static  void   (*o_putc)PROTO((int c)) = std_putc;
526
527 static  int    (*i_getc)PROTO((FILE *f)) = std_getc; /* general input */
528 static  int    (*i_ungetc)PROTO((int c,FILE *f)) =std_ungetc;
529
530 static  int    (*i_bgetc)PROTO((FILE *)) = std_getc; /* input of mgetc */
531 static  int    (*i_bungetc)PROTO((int c ,FILE *f)) = std_ungetc;
532
533 static  void   (*o_mputc)PROTO((int c)) = std_putc ; /* output of mputc */
534
535 static  int    (*i_mgetc)PROTO((FILE *)) = std_getc; /* input of mgetc */
536 static  int    (*i_mungetc)PROTO((int c ,FILE *f)) = std_ungetc;
537
538 /* for strict mime */
539 static  int    (*i_mgetc_buf)PROTO((FILE *)) = std_getc; /* input of mgetc_buf */
540 static  int    (*i_mungetc_buf)PROTO((int c,FILE *f)) = std_ungetc;
541
542 /* Global states */
543 static int output_mode = ASCII,    /* output kanji mode */
544            input_mode =  ASCII,    /* input kanji mode */
545            shift_mode =  FALSE;    /* TRUE shift out, or X0201  */
546 static int mime_decode_mode =   FALSE;    /* MIME mode B base64, Q hex */
547
548 /* X0201 / X0208 conversion tables */
549
550 /* X0201 kana conversion table */
551 /* 90-9F A0-DF */
552 static
553 unsigned char cv[]= {
554     0x21,0x21,0x21,0x23,0x21,0x56,0x21,0x57,
555     0x21,0x22,0x21,0x26,0x25,0x72,0x25,0x21,
556     0x25,0x23,0x25,0x25,0x25,0x27,0x25,0x29,
557     0x25,0x63,0x25,0x65,0x25,0x67,0x25,0x43,
558     0x21,0x3c,0x25,0x22,0x25,0x24,0x25,0x26,
559     0x25,0x28,0x25,0x2a,0x25,0x2b,0x25,0x2d,
560     0x25,0x2f,0x25,0x31,0x25,0x33,0x25,0x35,
561     0x25,0x37,0x25,0x39,0x25,0x3b,0x25,0x3d,
562     0x25,0x3f,0x25,0x41,0x25,0x44,0x25,0x46,
563     0x25,0x48,0x25,0x4a,0x25,0x4b,0x25,0x4c,
564     0x25,0x4d,0x25,0x4e,0x25,0x4f,0x25,0x52,
565     0x25,0x55,0x25,0x58,0x25,0x5b,0x25,0x5e,
566     0x25,0x5f,0x25,0x60,0x25,0x61,0x25,0x62,
567     0x25,0x64,0x25,0x66,0x25,0x68,0x25,0x69,
568     0x25,0x6a,0x25,0x6b,0x25,0x6c,0x25,0x6d,
569     0x25,0x6f,0x25,0x73,0x21,0x2b,0x21,0x2c,
570     0x00,0x00};
571
572
573 /* X0201 kana conversion table for daguten */
574 /* 90-9F A0-DF */
575 static
576 unsigned char dv[]= { 
577     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
578     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
579     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
580     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
581     0x00,0x00,0x00,0x00,0x00,0x00,0x25,0x74,
582     0x00,0x00,0x00,0x00,0x25,0x2c,0x25,0x2e,
583     0x25,0x30,0x25,0x32,0x25,0x34,0x25,0x36,
584     0x25,0x38,0x25,0x3a,0x25,0x3c,0x25,0x3e,
585     0x25,0x40,0x25,0x42,0x25,0x45,0x25,0x47,
586     0x25,0x49,0x00,0x00,0x00,0x00,0x00,0x00,
587     0x00,0x00,0x00,0x00,0x25,0x50,0x25,0x53,
588     0x25,0x56,0x25,0x59,0x25,0x5c,0x00,0x00,
589     0x00,0x00,0x00,0x00,0x00,0x00,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};
594
595 /* X0201 kana conversion table for han-daguten */
596 /* 90-9F A0-DF */
597 static
598 unsigned char ev[]= { 
599     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
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,0x25,0x51,0x25,0x54,
610     0x25,0x57,0x25,0x5a,0x25,0x5d,0x00,0x00,
611     0x00,0x00,0x00,0x00,0x00,0x00,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};
616
617
618 /* X0208 kigou conversion table */
619 /* 0x8140 - 0x819e */
620 static
621 unsigned char fv[] = {
622
623     0x00,0x00,0x00,0x00,0x2c,0x2e,0x00,0x3a,
624     0x3b,0x3f,0x21,0x00,0x00,0x27,0x60,0x00,
625     0x5e,0x00,0x5f,0x00,0x00,0x00,0x00,0x00,
626     0x00,0x00,0x00,0x00,0x00,0x2d,0x00,0x2f,
627     0x5c,0x00,0x00,0x7c,0x00,0x00,0x60,0x27,
628     0x22,0x22,0x28,0x29,0x00,0x00,0x5b,0x5d,
629     0x7b,0x7d,0x3c,0x3e,0x00,0x00,0x00,0x00,
630     0x00,0x00,0x00,0x00,0x2b,0x2d,0x00,0x00,
631     0x00,0x3d,0x00,0x3c,0x3e,0x00,0x00,0x00,
632     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
633     0x24,0x00,0x00,0x25,0x23,0x26,0x2a,0x40,
634     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
635 } ;
636
637
638 #define    CRLF      1
639
640 static int             file_out = FALSE;
641 #ifdef OVERWRITE
642 static int             overwrite = FALSE;
643 #endif
644
645 static int             crmode_f = 0;   /* CR, NL, CRLF */
646 #ifdef EASYWIN /*Easy Win */
647 static int             end_check;
648 #endif /*Easy Win */
649
650 #ifndef PERL_XS
651 int
652 main(argc, argv)
653     int             argc;
654     char          **argv;
655 {
656     FILE  *fin;
657     unsigned char  *cp;
658
659     char *outfname = NULL;
660     char *origfname;
661
662 #ifdef EASYWIN /*Easy Win */
663     _BufferSize.y = 400;/*Set Scroll Buffer Size*/
664 #endif
665
666     for (argc--,argv++; (argc > 0) && **argv == '-'; argc--, argv++) {
667         cp = (unsigned char *)*argv;
668         options(cp);
669 #ifdef EXEC_IO
670         if (exec_f){
671             int fds[2], pid;
672             if (pipe(fds) < 0 || (pid = fork()) < 0){
673                 abort();
674             }
675             if (pid == 0){
676                 if (exec_f > 0){
677                     close(fds[0]);
678                     dup2(fds[1], 1);
679                 }else{
680                     close(fds[1]);
681                     dup2(fds[0], 0);
682                 }
683                 execvp(argv[1], &argv[1]);
684             }
685             if (exec_f > 0){
686                 close(fds[1]);
687                 dup2(fds[0], 0);
688             }else{
689                 close(fds[0]);
690                 dup2(fds[1], 1);
691             }
692             argc = 0;
693             break;
694         }
695 #endif
696     }
697     if(x0201_f == WISH_TRUE)
698          x0201_f = ((!iso2022jp_f)? TRUE : NO_X0201);
699
700     if (binmode_f == TRUE)
701 #ifdef __OS2__
702     if (freopen("","wb",stdout) == NULL) 
703         return (-1);
704 #else
705     setbinmode(stdout);
706 #endif
707
708     if (unbuf_f)
709       setbuf(stdout, (char *) NULL);
710     else
711       setvbuffer(stdout, stdobuf, IOBUF_SIZE);
712
713     if (argc == 0) {
714       if (binmode_f == TRUE)
715 #ifdef __OS2__
716       if (freopen("","rb",stdin) == NULL) return (-1);
717 #else
718       setbinmode(stdin);
719 #endif
720       setvbuffer(stdin, stdibuf, IOBUF_SIZE);
721       if (nop_f)
722           noconvert(stdin);
723       else {
724           kanji_convert(stdin);
725           if (guess_f) print_guessed_code(NULL);
726       }
727     } else {
728       int nfiles = argc;
729       while (argc--) {
730           if ((fin = fopen((origfname = *argv++), "r")) == NULL) {
731               perror(*--argv);
732               return(-1);
733           } else {
734 #ifdef OVERWRITE
735               int fd = 0;
736               int fd_backup = 0;
737 #endif
738
739 /* reopen file for stdout */
740               if (file_out == TRUE) {
741 #ifdef OVERWRITE
742                   if (overwrite){
743                       outfname = malloc(strlen(origfname)
744                                         + strlen(".nkftmpXXXXXX")
745                                         + 1);
746                       if (!outfname){
747                           perror(origfname);
748                           return -1;
749                       }
750                       strcpy(outfname, origfname);
751 #ifdef MSDOS
752                       {
753                           int i;
754                           for (i = strlen(outfname); i; --i){
755                               if (outfname[i - 1] == '/'
756                                   || outfname[i - 1] == '\\'){
757                                   break;
758                               }
759                           }
760                           outfname[i] = '\0';
761                       }
762                       strcat(outfname, "ntXXXXXX");
763                       mktemp(outfname);
764                       fd = open(outfname, O_WRONLY | O_CREAT | O_TRUNC,
765                                 S_IREAD | S_IWRITE);
766 #else
767                       strcat(outfname, ".nkftmpXXXXXX");
768                       fd = mkstemp(outfname);
769 #endif
770                       if (fd < 0
771                           || (fd_backup = dup(fileno(stdout))) < 0
772                           || dup2(fd, fileno(stdout)) < 0
773                           ){
774                           perror(origfname);
775                           return -1;
776                       }
777                   }else
778 #endif
779                   if(argc == 1 ) {
780                       outfname = *argv++;
781                       argc--;
782                   } else {
783                       outfname = "nkf.out";
784                   }
785
786                   if(freopen(outfname, "w", stdout) == NULL) {
787                       perror (outfname);
788                       return (-1);
789                   }
790                   if (binmode_f == TRUE) {
791 #ifdef __OS2__
792                       if (freopen("","wb",stdout) == NULL) 
793                            return (-1);
794 #else
795                       setbinmode(stdout);
796 #endif
797                   }
798               }
799               if (binmode_f == TRUE)
800 #ifdef __OS2__
801                  if (freopen("","rb",fin) == NULL) 
802                     return (-1);
803 #else
804                  setbinmode(fin);
805 #endif 
806               setvbuffer(fin, stdibuf, IOBUF_SIZE);
807               if (nop_f)
808                   noconvert(fin);
809               else {
810                   char *filename = NULL;
811                   kanji_convert(fin);
812                   if (nfiles > 1) filename = origfname;
813                   if (guess_f) print_guessed_code(filename);
814               }
815               fclose(fin);
816 #ifdef OVERWRITE
817               if (overwrite) {
818                   struct stat     sb;
819 #if defined(MSDOS) && !defined(__MINGW32__)
820                   time_t tb[2];
821 #else
822                   struct utimbuf  tb;
823 #endif
824
825                   fflush(stdout);
826                   close(fd);
827                   if (dup2(fd_backup, fileno(stdout)) < 0){
828                       perror("dup2");
829                   }
830                   if (stat(origfname, &sb)) {
831                       fprintf(stderr, "Can't stat %s\n", origfname);
832                   }
833                   /* \e$B%Q!<%_%C%7%g%s$rI|85\e(B */
834                   if (chmod(outfname, sb.st_mode)) {
835                       fprintf(stderr, "Can't set permission %s\n", outfname);
836                   }
837
838                   /* \e$B%?%$%`%9%?%s%W$rI|85\e(B */
839 #if defined(MSDOS) && !defined(__MINGW32__)
840                   tb[0] = tb[1] = sb.st_mtime;
841                   if (utime(outfname, tb)) {
842                       fprintf(stderr, "Can't set timestamp %s\n", outfname);
843                   }
844 #else
845                   tb.actime  = sb.st_atime;
846                   tb.modtime = sb.st_mtime;
847                   if (utime(outfname, &tb)) {
848                       fprintf(stderr, "Can't set timestamp %s\n", outfname);
849                   }
850 #endif
851 #ifdef MSDOS
852                   if (unlink(origfname)){
853                       perror(origfname);
854                   }
855 #endif
856                   if (rename(outfname, origfname)) {
857                       perror(origfname);
858                       fprintf(stderr, "Can't rename %s to %s\n",
859                               outfname, origfname);
860                   }
861                   free(outfname);
862               }
863 #endif
864           }
865       }
866     }
867 #ifdef EASYWIN /*Easy Win */
868     if (file_out == FALSE) 
869         scanf("%d",&end_check);
870     else 
871         fclose(stdout);
872 #else /* for Other OS */
873     if (file_out == TRUE) 
874         fclose(stdout);
875 #endif 
876     return (0);
877 }
878 #endif
879
880 static 
881 struct {
882     char *name;
883     char *alias;
884 } long_option[] = {
885     {"base64","jMB"},
886     {"euc","e"},
887     {"euc-input","E"},
888     {"fj","jm"},
889     {"help","v"},
890     {"jis","j"},
891     {"jis-input","J"},
892     {"mac","sLm"},
893     {"mime","jM"},
894     {"mime-input","m"},
895     {"msdos","sLw"},
896     {"sjis","s"},
897     {"sjis-input","S"},
898     {"unix","eLu"},
899     {"version","V"},
900     {"windows","sLw"},
901     {"hiragana","h1"},
902     {"katakana","h2"},
903     {"katakana-hiragana","h3"},
904     {"guess", "g"},
905     {"cp932", ""},
906     {"no-cp932", ""},
907 #ifdef X0212_ENABLE
908     {"x0212", ""},
909 #endif
910 #ifdef UTF8_OUTPUT_ENABLE
911     {"utf8", "w"},
912     {"utf16", "w16"},
913     {"ms-ucs-map", ""},
914 #endif
915 #ifdef UTF8_INPUT_ENABLE
916     {"utf8-input", "W"},
917     {"utf16-input", "W16"},
918 #endif
919 #ifdef OVERWRITE
920     {"overwrite", ""},
921 #endif
922 #ifdef INPUT_OPTION
923     {"cap-input", ""},
924     {"url-input", ""},
925 #endif
926 #ifdef NUMCHAR_OPTION
927     {"numchar-input", ""},
928 #endif
929 #ifdef CHECK_OPTION
930     {"no-output", ""},
931     {"debug", ""},
932 #endif
933 #ifdef SHIFTJIS_CP932
934     {"cp932inv", ""},
935 #endif
936 #ifdef EXEC_IO
937     {"exec-in", ""},
938     {"exec-out", ""},
939 #endif
940     {"prefix=", ""},
941 };
942
943 static int option_mode = 0;
944
945 void
946 options(cp) 
947      unsigned char *cp;
948 {
949     int i;
950     unsigned char *p = NULL;
951
952     if (option_mode==1)
953         return;
954     if (*cp++ != '-') 
955         return;
956     while (*cp) {
957         if (p && !*cp) {
958             cp = p;
959             p = 0;
960         }
961         switch (*cp++) {
962         case '-':  /* literal options */
963             if (!*cp) {        /* ignore the rest of arguments */
964                 option_mode = 1;
965                 return;
966             }
967             for (i=0;i<sizeof(long_option)/sizeof(long_option[0]);i++) {
968                 int j;
969                 p = (unsigned char *)long_option[i].name;
970                 for (j=0;*p && (*p != '=') && *p == cp[j];p++, j++);
971                 if (*p == cp[j]){
972                     p = &cp[j];
973                     break;
974                 }
975                 p = 0;
976             }
977             if (p == 0) return;
978             cp = (unsigned char *)long_option[i].alias;
979             if (!*cp){
980 #ifdef OVERWRITE
981                 if (strcmp(long_option[i].name, "overwrite") == 0){
982                     file_out = TRUE;
983                     overwrite = TRUE;
984                     continue;
985                 }
986 #endif
987 #ifdef INPUT_OPTION
988                 if (strcmp(long_option[i].name, "cap-input") == 0){
989                     cap_f = TRUE;
990                     continue;
991                 }
992                 if (strcmp(long_option[i].name, "url-input") == 0){
993                     url_f = TRUE;
994                     continue;
995                 }
996 #endif
997 #ifdef NUMCHAR_OPTION
998                 if (strcmp(long_option[i].name, "numchar-input") == 0){
999                     numchar_f = TRUE;
1000                     continue;
1001                 }
1002 #endif
1003 #ifdef CHECK_OPTION
1004                 if (strcmp(long_option[i].name, "no-output") == 0){
1005                     noout_f = TRUE;
1006                     continue;
1007                 }
1008                 if (strcmp(long_option[i].name, "debug") == 0){
1009                     debug_f = TRUE;
1010                     continue;
1011                 }
1012 #endif
1013                 if (strcmp(long_option[i].name, "cp932") == 0){
1014 #ifdef SHIFTJIS_CP932
1015                     cp932_f = TRUE;
1016                     cp932inv_f = TRUE;
1017 #endif
1018 #ifdef UTF8_OUTPUT_ENABLE
1019                     ms_ucs_map_f = TRUE;
1020 #endif
1021                     continue;
1022                 }
1023                 if (strcmp(long_option[i].name, "no-cp932") == 0){
1024 #ifdef SHIFTJIS_CP932
1025                     cp932_f = FALSE;
1026                     cp932inv_f = FALSE;
1027 #endif
1028 #ifdef UTF8_OUTPUT_ENABLE
1029                     ms_ucs_map_f = FALSE;
1030 #endif
1031                     continue;
1032                 }
1033 #ifdef SHIFTJIS_CP932
1034                 if (strcmp(long_option[i].name, "cp932inv") == 0){
1035                     cp932inv_f = TRUE;
1036                     continue;
1037                 }
1038 #endif
1039
1040 #ifdef X0212_ENABLE
1041                 if (strcmp(long_option[i].name, "x0212") == 0){
1042                     x0212_f = TRUE;
1043                     continue;
1044                 }
1045 #endif
1046
1047 #ifdef EXEC_IO
1048                   if (strcmp(long_option[i].name, "exec-in") == 0){
1049                       exec_f = 1;
1050                       return;
1051                   }
1052                   if (strcmp(long_option[i].name, "exec-out") == 0){
1053                       exec_f = -1;
1054                       return;
1055                   }
1056 #endif
1057 #ifdef UTF8_OUTPUT_ENABLE
1058                 if (strcmp(long_option[i].name, "ms-ucs-map") == 0){
1059                     ms_ucs_map_f = TRUE;
1060                     continue;
1061                 }
1062 #endif
1063                 if (strcmp(long_option[i].name, "prefix=") == 0){
1064                     if (*p == '=' && ' ' < p[1] && p[1] < 128){
1065                         for (i = 2; ' ' < p[i] && p[i] < 128; i++){
1066                             prefix_table[p[i]] = p[1];
1067                         }
1068                     }
1069                     continue;
1070                 }
1071             }
1072             continue;
1073         case 'b':           /* buffered mode */
1074             unbuf_f = FALSE;
1075             continue;
1076         case 'u':           /* non bufferd mode */
1077             unbuf_f = TRUE;
1078             continue;
1079         case 't':           /* transparent mode */
1080             nop_f = TRUE;
1081             continue;
1082         case 'j':           /* JIS output */
1083         case 'n':
1084             output_conv = j_oconv;
1085             continue;
1086         case 'e':           /* AT&T EUC output */
1087             output_conv = e_oconv;
1088             continue;
1089         case 's':           /* SJIS output */
1090             output_conv = s_oconv;
1091             continue;
1092         case 'l':           /* ISO8859 Latin-1 support, no conversion */
1093             iso8859_f = TRUE;  /* Only compatible with ISO-2022-JP */
1094             input_f = LATIN1_INPUT;
1095             continue;
1096         case 'i':           /* Kanji IN ESC-$-@/B */
1097             if (*cp=='@'||*cp=='B') 
1098                 kanji_intro = *cp++;
1099             continue;
1100         case 'o':           /* ASCII IN ESC-(-J/B */
1101             if (*cp=='J'||*cp=='B'||*cp=='H') 
1102                 ascii_intro = *cp++;
1103             continue;
1104         case 'h':
1105             /*  
1106                 bit:1   hira -> kata
1107                 bit:2   kata -> hira
1108             */
1109             if ('9'>= *cp && *cp>='0') 
1110                 hira_f |= (*cp++ -'0');
1111             else 
1112                 hira_f |= 1;
1113             continue;
1114         case 'r':
1115             rot_f = TRUE;
1116             continue;
1117 #if defined(MSDOS) || defined(__OS2__) 
1118         case 'T':
1119             binmode_f = FALSE;
1120             continue;
1121 #endif
1122 #ifndef PERL_XS
1123         case 'V':
1124             version();
1125             exit(1);
1126             break;
1127         case 'v':
1128             usage();
1129             exit(1);
1130             break;
1131 #endif
1132 #ifdef UTF8_OUTPUT_ENABLE
1133         case 'w':           /* UTF-8 output */
1134             if ('1'== cp[0] && '6'==cp[1]) {
1135                 output_conv = w_oconv16; cp+=2;
1136                 if (cp[0]=='L') {
1137                     unicode_bom_f=2; cp++;
1138                     w_oconv16_LE = 1;
1139                     if (cp[0] == '0'){
1140                         unicode_bom_f=1; cp++;
1141                     }
1142                 } else if (cp[0] == 'B') {
1143                     unicode_bom_f=2; cp++;
1144                     if (cp[0] == '0'){
1145                         unicode_bom_f=1; cp++;
1146                     }
1147                 } 
1148             } else if (cp[0] == '8') {
1149                 output_conv = w_oconv; cp++;
1150                 unicode_bom_f=2;
1151                 if (cp[0] == '0'){
1152                     unicode_bom_f=1; cp++;
1153                 }
1154             } else
1155                 output_conv = w_oconv;
1156             continue;
1157 #endif
1158 #ifdef UTF8_INPUT_ENABLE
1159         case 'W':           /* UTF-8 input */
1160             if ('1'== cp[0] && '6'==cp[1]) {
1161                 input_f = UTF16LE_INPUT;
1162                 if (cp[0]=='L') {
1163                     cp++;
1164                 } else if (cp[0] == 'B') {
1165                     cp++;
1166                     input_f = UTF16BE_INPUT;
1167                 }
1168             } else if (cp[0] == '8') {
1169                 cp++;
1170                 input_f = UTF8_INPUT;
1171             } else
1172                 input_f = UTF8_INPUT;
1173             continue;
1174 #endif
1175         /* Input code assumption */
1176         case 'J':   /* JIS input */
1177         case 'E':   /* AT&T EUC input */
1178             input_f = JIS_INPUT;
1179             continue;
1180         case 'S':   /* MS Kanji input */
1181             input_f = SJIS_INPUT;
1182             if (x0201_f==NO_X0201) x0201_f=TRUE;
1183             continue;
1184         case 'Z':   /* Convert X0208 alphabet to asii */
1185             /*  bit:0   Convert X0208
1186                 bit:1   Convert Kankaku to one space
1187                 bit:2   Convert Kankaku to two spaces
1188                 bit:3   Convert HTML Entity
1189             */
1190             if ('9'>= *cp && *cp>='0') 
1191                 alpha_f |= 1<<(*cp++ -'0');
1192             else 
1193                 alpha_f |= TRUE;
1194             continue;
1195         case 'x':   /* Convert X0201 kana to X0208 or X0201 Conversion */
1196             x0201_f = FALSE;    /* No X0201->X0208 conversion */
1197             /* accept  X0201
1198                     ESC-(-I     in JIS, EUC, MS Kanji
1199                     SI/SO       in JIS, EUC, MS Kanji
1200                     SSO         in EUC, JIS, not in MS Kanji
1201                     MS Kanji (0xa0-0xdf) 
1202                output  X0201
1203                     ESC-(-I     in JIS (0x20-0x5f)
1204                     SSO         in EUC (0xa0-0xdf)
1205                     0xa0-0xd    in MS Kanji (0xa0-0xdf) 
1206             */
1207             continue;
1208         case 'X':   /* Assume X0201 kana */
1209             /* Default value is NO_X0201 for EUC/MS-Kanji mix */
1210             x0201_f = TRUE;
1211             continue;
1212         case 'F':   /* prserve new lines */
1213             fold_preserve_f = TRUE;
1214         case 'f':   /* folding -f60 or -f */
1215             fold_f = TRUE;
1216             fold_len = 0;
1217             while('0'<= *cp && *cp <='9') { /* we don't use atoi here */
1218                 fold_len *= 10;
1219                 fold_len += *cp++ - '0';
1220             }
1221             if (!(0<fold_len && fold_len<BUFSIZ)) 
1222                 fold_len = DEFAULT_FOLD;
1223             if (*cp=='-') {
1224                 fold_margin = 0;
1225                 cp++;
1226                 while('0'<= *cp && *cp <='9') { /* we don't use atoi here */
1227                     fold_margin *= 10;
1228                     fold_margin += *cp++ - '0';
1229                 }
1230             }
1231             continue;
1232         case 'm':   /* MIME support */
1233             if (*cp=='B'||*cp=='Q') {
1234                 mime_decode_mode = *cp++;
1235                 mimebuf_f = FIXED_MIME;
1236             } else if (*cp=='N') {
1237                 mime_f = TRUE; cp++;
1238             } else if (*cp=='S') {
1239                 mime_f = STRICT_MIME; cp++;
1240             } else if (*cp=='0') {
1241                 mime_f = FALSE; cp++;
1242             }
1243             continue;
1244         case 'M':   /* MIME output */
1245             if (*cp=='B') {
1246                 mimeout_mode = 'B';
1247                 mimeout_f = FIXED_MIME; cp++;
1248             } else if (*cp=='Q') {
1249                 mimeout_mode = 'Q';
1250                 mimeout_f = FIXED_MIME; cp++;
1251             } else {
1252                 mimeout_f = TRUE;
1253             }
1254             continue;
1255         case 'B':   /* Broken JIS support */
1256             /*  bit:0   no ESC JIS
1257                 bit:1   allow any x on ESC-(-x or ESC-$-x
1258                 bit:2   reset to ascii on NL
1259             */
1260             if ('9'>= *cp && *cp>='0') 
1261                 broken_f |= 1<<(*cp++ -'0');
1262             else 
1263                 broken_f |= TRUE;
1264             continue;
1265 #ifndef PERL_XS
1266         case 'O':/* for Output file */
1267             file_out = TRUE;
1268             continue;
1269 #endif
1270         case 'c':/* add cr code */
1271             crmode_f = CRLF;
1272             continue;
1273         case 'd':/* delete cr code */
1274             crmode_f = NL;
1275             continue;
1276         case 'I':   /* ISO-2022-JP output */
1277             iso2022jp_f = TRUE;
1278             continue;
1279         case 'L':  /* line mode */
1280             if (*cp=='u') {         /* unix */
1281                 crmode_f = NL; cp++;
1282             } else if (*cp=='m') { /* mac */
1283                 crmode_f = CR; cp++;
1284             } else if (*cp=='w') { /* windows */
1285                 crmode_f = CRLF; cp++;
1286             } else if (*cp=='0') { /* no conversion  */
1287                 crmode_f = 0; cp++;
1288             }
1289             continue;
1290         case 'g':
1291 #ifndef PERL_XS
1292             guess_f = TRUE;
1293 #endif
1294             continue;
1295         case ' ':    
1296         /* module muliple options in a string are allowed for Perl moudle  */
1297             while(*cp && *cp!='-') cp++;
1298             if(*cp=='-') cp++;
1299             continue;
1300         default:
1301             /* bogus option but ignored */
1302             continue;
1303         }
1304     }
1305 }
1306
1307 #ifdef ANSI_C_PROTOTYPE
1308 struct input_code * find_inputcode_byfunc(int (*iconv_func)(int c2,int c1,int c0))
1309 #else
1310 struct input_code * find_inputcode_byfunc(iconv_func)
1311      int (*iconv_func)();
1312 #endif
1313 {
1314     if (iconv_func){
1315         struct input_code *p = input_code_list;
1316         while (p->name){
1317             if (iconv_func == p->iconv_func){
1318                 return p;
1319             }
1320             p++;
1321         }
1322     }
1323     return 0;
1324 }
1325
1326 #ifdef CHECK_OPTION
1327 static int (*iconv_for_check)() = 0;
1328 #endif
1329
1330 #ifdef ANSI_C_PROTOTYPE
1331 void set_iconv(int f, int (*iconv_func)(int c2,int c1,int c0))
1332 #else
1333 void set_iconv(f, iconv_func)
1334      int f;
1335      int (*iconv_func)();
1336 #endif
1337 {
1338 #ifdef INPUT_CODE_FIX
1339     if (f || !input_f)
1340 #endif
1341         if (estab_f != f){
1342             estab_f = f;
1343         }
1344
1345     if (iconv_func
1346 #ifdef INPUT_CODE_FIX
1347         && (f == -TRUE || !input_f) /* -TRUE means "FORCE" */
1348 #endif
1349         ){
1350         iconv = iconv_func;
1351     }
1352 #ifdef CHECK_OPTION
1353     if (estab_f && iconv_for_check != iconv){
1354         struct input_code *p = find_inputcode_byfunc(iconv);
1355         if (p){
1356             set_input_codename(p->name);
1357             debug(input_codename);
1358         }
1359         iconv_for_check = iconv;
1360     }
1361 #endif
1362 }
1363
1364 #define SCORE_L2       (1)                   /* \e$BBh\e(B2\e$B?e=`4A;z\e(B */
1365 #define SCORE_KANA     (SCORE_L2 << 1)       /* \e$B$$$o$f$kH>3Q%+%J\e(B */
1366 #define SCORE_DEPEND   (SCORE_KANA << 1)     /* \e$B5!<o0MB8J8;z\e(B */
1367 #ifdef SHIFTJIS_CP932
1368 #define SCORE_CP932    (SCORE_DEPEND << 1)   /* CP932 \e$B$K$h$kFI$_49$(\e(B */
1369 #define SCORE_NO_EXIST (SCORE_CP932 << 1)    /* \e$BB8:_$7$J$$J8;z\e(B */
1370 #else
1371 #define SCORE_NO_EXIST (SCORE_DEPEND << 1)   /* \e$BB8:_$7$J$$J8;z\e(B */
1372 #endif
1373 #define SCORE_iMIME    (SCORE_NO_EXIST << 1) /* MIME \e$B$K$h$k;XDj\e(B */
1374 #define SCORE_ERROR    (SCORE_iMIME << 1) /* \e$B%(%i!<\e(B */
1375
1376 #define SCORE_INIT (SCORE_iMIME)
1377
1378 int score_table_A0[] = {
1379     0, 0, 0, 0,
1380     0, 0, 0, 0,
1381     0, SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND,
1382     SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND, SCORE_NO_EXIST,
1383 };
1384
1385 int score_table_F0[] = {
1386     SCORE_L2, SCORE_L2, SCORE_L2, SCORE_L2,
1387     SCORE_L2, SCORE_DEPEND, SCORE_NO_EXIST, SCORE_NO_EXIST,
1388     SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND,
1389     SCORE_DEPEND, SCORE_NO_EXIST, SCORE_NO_EXIST, SCORE_ERROR,
1390 };
1391
1392 void set_code_score(ptr, score)
1393      struct input_code *ptr;
1394      int score;
1395 {
1396     if (ptr){
1397         ptr->score |= score;
1398     }
1399 }
1400
1401 void clr_code_score(ptr, score)
1402      struct input_code *ptr;
1403      int score;
1404 {
1405     if (ptr){
1406         ptr->score &= ~score;
1407     }
1408 }
1409
1410 void code_score(ptr)
1411      struct input_code *ptr;
1412 {
1413     int c2 = ptr->buf[0];
1414     int c1 = ptr->buf[1];
1415     if (c2 < 0){
1416         set_code_score(ptr, SCORE_ERROR);
1417     }else if (c2 == SSO){
1418         set_code_score(ptr, SCORE_KANA);
1419 #ifdef UTF8_OUTPUT_ENABLE
1420     }else if (!e2w_conv(c2, c1)){
1421         set_code_score(ptr, SCORE_NO_EXIST);
1422 #endif
1423     }else if ((c2 & 0x70) == 0x20){
1424         set_code_score(ptr, score_table_A0[c2 & 0x0f]);
1425     }else if ((c2 & 0x70) == 0x70){
1426         set_code_score(ptr, score_table_F0[c2 & 0x0f]);
1427     }else if ((c2 & 0x70) >= 0x50){
1428         set_code_score(ptr, SCORE_L2);
1429     }
1430 }
1431
1432 void status_disable(ptr)
1433 struct input_code *ptr;
1434 {
1435     ptr->stat = -1;
1436     ptr->buf[0] = -1;
1437     code_score(ptr);
1438     if (iconv == ptr->iconv_func) set_iconv(FALSE, 0);
1439 }
1440
1441 void status_push_ch(ptr, c)
1442      struct input_code *ptr;
1443      int c;
1444 {
1445     ptr->buf[ptr->index++] = c;
1446 }
1447
1448 void status_clear(ptr)
1449      struct input_code *ptr;
1450 {
1451     ptr->stat = 0;
1452     ptr->index = 0;
1453 }
1454
1455 void status_reset(ptr)
1456      struct input_code *ptr;
1457 {
1458     status_clear(ptr);
1459     ptr->score = SCORE_INIT;
1460 }
1461
1462 void status_reinit(ptr)
1463      struct input_code *ptr;
1464 {
1465     status_reset(ptr);
1466     ptr->_file_stat = 0;
1467 }
1468
1469 void status_check(ptr, c)
1470      struct input_code *ptr;
1471      int c;
1472 {
1473     if (c <= DEL && estab_f){
1474         status_reset(ptr);
1475     }
1476 }
1477
1478 void s_status(ptr, c)
1479      struct input_code *ptr;
1480      int c;
1481 {
1482     switch(ptr->stat){
1483       case -1:
1484           status_check(ptr, c);
1485           break;
1486       case 0:
1487           if (c <= DEL){
1488               break;
1489 #ifdef NUMCHAR_OPTION
1490           }else if ((c & CLASS_MASK) == CLASS_UTF16){
1491               break;
1492 #endif
1493           }else if (0xa1 <= c && c <= 0xdf){
1494               status_push_ch(ptr, SSO);
1495               status_push_ch(ptr, c);
1496               code_score(ptr);
1497               status_clear(ptr);
1498           }else if ((0x81 <= c && c < 0xa0) || (0xe0 <= c && c <= 0xef)){
1499               ptr->stat = 1;
1500               status_push_ch(ptr, c);
1501 #ifdef SHIFTJIS_CP932
1502           }else if (cp932_f
1503                     && CP932_TABLE_BEGIN <= c && c <= CP932_TABLE_END){
1504               ptr->stat = 2;
1505               status_push_ch(ptr, c);
1506 #endif /* SHIFTJIS_CP932 */
1507 #ifdef X0212_ENABLE
1508           }else if (x0212_f && 0xf0 <= c && c <= 0xfc){
1509               ptr->stat = 1;
1510               status_push_ch(ptr, c);
1511 #endif /* X0212_ENABLE */
1512           }else{
1513               status_disable(ptr);
1514           }
1515           break;
1516       case 1:
1517           if ((0x40 <= c && c <= 0x7e) || (0x80 <= c && c <= 0xfc)){
1518               status_push_ch(ptr, c);
1519               s2e_conv(ptr->buf[0], ptr->buf[1], &ptr->buf[0], &ptr->buf[1]);
1520               code_score(ptr);
1521               status_clear(ptr);
1522           }else{
1523               status_disable(ptr);
1524           }
1525           break;
1526       case 2:
1527 #ifdef SHIFTJIS_CP932
1528           if ((0x40 <= c && c <= 0x7e) || (0x80 <= c && c <= 0xfc)){
1529               status_push_ch(ptr, c);
1530               if (s2e_conv(ptr->buf[0], ptr->buf[1], &ptr->buf[0], &ptr->buf[1]) == 0){
1531                   set_code_score(ptr, SCORE_CP932);
1532                   status_clear(ptr);
1533                   break;
1534               }
1535           }
1536 #endif /* SHIFTJIS_CP932 */
1537 #ifndef X0212_ENABLE
1538           status_disable(ptr);
1539           break;
1540 #endif
1541     }
1542 }
1543
1544 void e_status(ptr, c)
1545      struct input_code *ptr;
1546      int c;
1547 {
1548     switch (ptr->stat){
1549       case -1:
1550           status_check(ptr, c);
1551           break;
1552       case 0:
1553           if (c <= DEL){
1554               break;
1555 #ifdef NUMCHAR_OPTION
1556           }else if ((c & CLASS_MASK) == CLASS_UTF16){
1557               break;
1558 #endif
1559           }else if (SSO == c || (0xa1 <= c && c <= 0xfe)){
1560               ptr->stat = 1;
1561               status_push_ch(ptr, c);
1562 #ifdef X0212_ENABLE
1563           }else if (0x8f == c){
1564               ptr->stat = 2;
1565               status_push_ch(ptr, c);
1566 #endif /* X0212_ENABLE */
1567           }else{
1568               status_disable(ptr);
1569           }
1570           break;
1571       case 1:
1572           if (0xa1 <= c && c <= 0xfe){
1573               status_push_ch(ptr, c);
1574               code_score(ptr);
1575               status_clear(ptr);
1576           }else{
1577               status_disable(ptr);
1578           }
1579           break;
1580 #ifdef X0212_ENABLE
1581       case 2:
1582           if (0xa1 <= c && c <= 0xfe){
1583               ptr->stat = 1;
1584               status_push_ch(ptr, c);
1585           }else{
1586               status_disable(ptr);
1587           }
1588 #endif /* X0212_ENABLE */
1589     }
1590 }
1591
1592 #ifdef UTF8_INPUT_ENABLE
1593 void w16_status(ptr, c)
1594      struct input_code *ptr;
1595      int c;
1596 {
1597     switch (ptr->stat){
1598       case -1:
1599           break;
1600       case 0:
1601           if (ptr->_file_stat == 0){
1602               if (c == 0xfe || c == 0xff){
1603                   ptr->stat = c;
1604                   status_push_ch(ptr, c);
1605                   ptr->_file_stat = 1;
1606               }else{
1607                   status_disable(ptr);
1608                   ptr->_file_stat = -1;
1609               }
1610           }else if (ptr->_file_stat > 0){
1611               ptr->stat = 1;
1612               status_push_ch(ptr, c);
1613           }else if (ptr->_file_stat < 0){
1614               status_disable(ptr);
1615           }
1616           break;
1617
1618       case 1:
1619           if (c == EOF){
1620               status_disable(ptr);
1621               ptr->_file_stat = -1;
1622           }else{
1623               status_push_ch(ptr, c);
1624               status_clear(ptr);
1625           }
1626           break;
1627
1628       case 0xfe:
1629       case 0xff:
1630           if (ptr->stat != c && (c == 0xfe || c == 0xff)){
1631               status_push_ch(ptr, c);
1632               status_clear(ptr);
1633           }else{
1634               status_disable(ptr);
1635               ptr->_file_stat = -1;
1636           }
1637           break;
1638     }
1639 }
1640
1641 void w_status(ptr, c)
1642      struct input_code *ptr;
1643      int c;
1644 {
1645     switch (ptr->stat){
1646       case -1:
1647           status_check(ptr, c);
1648           break;
1649       case 0:
1650           if (c <= DEL){
1651               break;
1652 #ifdef NUMCHAR_OPTION
1653           }else if ((c & CLASS_MASK) == CLASS_UTF16){
1654               break;
1655 #endif
1656           }else if (0xc0 <= c && c <= 0xdf){
1657               ptr->stat = 1;
1658               status_push_ch(ptr, c);
1659           }else if (0xe0 <= c && c <= 0xef){
1660               ptr->stat = 2;
1661               status_push_ch(ptr, c);
1662           }else{
1663               status_disable(ptr);
1664           }
1665           break;
1666       case 1:
1667       case 2:
1668           if (0x80 <= c && c <= 0xbf){
1669               status_push_ch(ptr, c);
1670               if (ptr->index > ptr->stat){
1671                   int bom = (ptr->buf[0] == 0xef && ptr->buf[1] == 0xbb
1672                              && ptr->buf[2] == 0xbf);
1673                   w2e_conv(ptr->buf[0], ptr->buf[1], ptr->buf[2],
1674                            &ptr->buf[0], &ptr->buf[1]);
1675                   if (!bom){
1676                       code_score(ptr);
1677                   }
1678                   status_clear(ptr);
1679               }
1680           }else{
1681               status_disable(ptr);
1682           }
1683           break;
1684     }
1685 }
1686 #endif
1687
1688 void
1689 code_status(c)
1690      int c;
1691 {
1692     int action_flag = 1;
1693     struct input_code *result = 0;
1694     struct input_code *p = input_code_list;
1695     while (p->name){
1696         (p->status_func)(p, c);
1697         if (p->stat > 0){
1698             action_flag = 0;
1699         }else if(p->stat == 0){
1700             if (result){
1701                 action_flag = 0;
1702             }else{
1703                 result = p;
1704             }
1705         }
1706         ++p;
1707     }
1708
1709     if (action_flag){
1710         if (result && !estab_f){
1711             set_iconv(TRUE, result->iconv_func);
1712         }else if (c <= DEL){
1713             struct input_code *ptr = input_code_list;
1714             while (ptr->name){
1715                 status_reset(ptr);
1716                 ++ptr;
1717             }
1718         }
1719     }
1720 }
1721
1722 #define STD_GC_BUFSIZE (256)
1723 int std_gc_buf[STD_GC_BUFSIZE];
1724 int std_gc_ndx;
1725
1726 int 
1727 std_getc(f)
1728 FILE *f;
1729 {
1730     if (std_gc_ndx){
1731         return std_gc_buf[--std_gc_ndx];
1732     }
1733     return getc(f);
1734 }
1735
1736 int 
1737 std_ungetc(c,f)
1738 int c;
1739 FILE *f;
1740 {
1741     if (std_gc_ndx == STD_GC_BUFSIZE){
1742         return EOF;
1743     }
1744     std_gc_buf[std_gc_ndx++] = c;
1745     return c;
1746 }
1747
1748 void 
1749 std_putc(c)
1750 int c;
1751 {
1752     if(c!=EOF)
1753       putchar(c);
1754 }
1755
1756 int
1757 noconvert(f)
1758     FILE  *f;
1759 {
1760     int    c;
1761
1762     while ((c = (*i_getc)(f)) != EOF)
1763       (*o_putc)(c);
1764     return 1;
1765 }
1766
1767
1768 void
1769 module_connection()
1770 {
1771     oconv = output_conv; 
1772     o_putc = std_putc;
1773
1774     /* replace continucation module, from output side */
1775
1776     /* output redicrection */
1777 #ifdef CHECK_OPTION
1778     if (noout_f || guess_f){
1779         o_putc = no_putc;
1780     }
1781 #endif
1782     if (mimeout_f) {
1783         o_mputc = o_putc;
1784         o_putc = mime_putc;
1785         if (mimeout_f == TRUE) {
1786             o_base64conv = oconv; oconv = base64_conv;
1787         }
1788         /* base64_count = 0; */
1789     }
1790
1791     if (crmode_f) {
1792         o_crconv = oconv; oconv = cr_conv;
1793     }
1794     if (rot_f) {
1795         o_rot_conv = oconv; oconv = rot_conv;
1796     }
1797     if (iso2022jp_f) {
1798         o_iso2022jp_check_conv = oconv; oconv = iso2022jp_check_conv;
1799     }
1800     if (hira_f) {
1801         o_hira_conv = oconv; oconv = hira_conv;
1802     }
1803     if (fold_f) {
1804         o_fconv = oconv; oconv = fold_conv;
1805         f_line = 0;
1806     }
1807     if (alpha_f || x0201_f) {
1808         o_zconv = oconv; oconv = z_conv;
1809     }
1810
1811     i_getc = std_getc;
1812     i_ungetc = std_ungetc;
1813     /* input redicrection */
1814 #ifdef INPUT_OPTION
1815     if (cap_f){
1816         i_cgetc = i_getc; i_getc = cap_getc;
1817         i_cungetc = i_ungetc; i_ungetc= cap_ungetc;
1818     }
1819     if (url_f){
1820         i_ugetc = i_getc; i_getc = url_getc;
1821         i_uungetc = i_ungetc; i_ungetc= url_ungetc;
1822     }
1823 #endif
1824 #ifdef NUMCHAR_OPTION
1825     if (numchar_f){
1826         i_ngetc = i_getc; i_getc = numchar_getc;
1827         i_nungetc = i_ungetc; i_ungetc= numchar_ungetc;
1828     }
1829 #endif
1830     if (mime_f && mimebuf_f==FIXED_MIME) {
1831         i_mgetc = i_getc; i_getc = mime_getc;
1832         i_mungetc = i_ungetc; i_ungetc = mime_ungetc;
1833     }
1834     if (broken_f & 1) {
1835         i_bgetc = i_getc; i_getc = broken_getc;
1836         i_bungetc = i_ungetc; i_ungetc = broken_ungetc;
1837     }
1838     if (input_f == JIS_INPUT || input_f == LATIN1_INPUT) {
1839         set_iconv(-TRUE, e_iconv);
1840     } else if (input_f == SJIS_INPUT) {
1841         set_iconv(-TRUE, s_iconv);
1842 #ifdef UTF8_INPUT_ENABLE
1843     } else if (input_f == UTF8_INPUT) {
1844         set_iconv(-TRUE, w_iconv);
1845     } else if (input_f == UTF16LE_INPUT) {
1846         set_iconv(-TRUE, w_iconv16);
1847 #endif
1848     } else {
1849         set_iconv(FALSE, e_iconv);
1850     }
1851
1852     {
1853         struct input_code *p = input_code_list;
1854         while (p->name){
1855             status_reinit(p++);
1856         }
1857     }
1858 }
1859
1860 /*
1861    Conversion main loop. Code detection only. 
1862  */
1863
1864 int
1865 kanji_convert(f)
1866     FILE  *f;
1867 {
1868     int    c1,
1869                     c2, c3;
1870
1871     module_connection();
1872     c2 = 0;
1873
1874
1875     input_mode = ASCII;
1876     output_mode = ASCII;
1877     shift_mode = FALSE;
1878
1879 #define NEXT continue      /* no output, get next */
1880 #define SEND ;             /* output c1 and c2, get next */
1881 #define LAST break         /* end of loop, go closing  */
1882
1883     while ((c1 = (*i_getc)(f)) != EOF) {
1884         code_status(c1);
1885         if (c2) {
1886             /* second byte */
1887             if (c2 > DEL) {
1888                 /* in case of 8th bit is on */
1889                 if (!estab_f&&!mime_decode_mode) {
1890                     /* in case of not established yet */
1891                     /* It is still ambiguious */
1892                     if (h_conv(f, c2, c1)==EOF) 
1893                         LAST;
1894                     else 
1895                         c2 = 0;
1896                     NEXT;
1897                 } else
1898                     /* in case of already established */
1899                     if (c1 < AT) {
1900                         /* ignore bogus code */
1901                         c2 = 0;
1902                         NEXT;
1903                     } else
1904                         SEND;
1905             } else
1906                 /* second byte, 7 bit code */
1907                 /* it might be kanji shitfted */
1908                 if ((c1 == DEL) || (c1 <= SPACE)) {
1909                     /* ignore bogus first code */
1910                     c2 = 0;
1911                     NEXT;
1912                 } else
1913                     SEND;
1914         } else {
1915             /* first byte */
1916             if (
1917 #ifdef UTF8_INPUT_ENABLE
1918                 iconv == w_iconv16
1919 #else
1920                 0
1921 #endif
1922                 ) {
1923                 c2 = c1;
1924                 c1 = (*i_getc)(f);
1925                 SEND;
1926 #ifdef NUMCHAR_OPTION
1927             } else if ((c1 & CLASS_MASK) == CLASS_UTF16){
1928                 SEND;
1929 #endif
1930             } else if (c1 > DEL) {
1931                 /* 8 bit code */
1932                 if (!estab_f && !iso8859_f) {
1933                     /* not established yet */
1934                     c2 = c1;
1935                     NEXT;
1936                 } else { /* estab_f==TRUE */
1937                     if (iso8859_f) {
1938                         c2 = ISO8859_1;
1939                         c1 &= 0x7f;
1940                         SEND;
1941                     } else if (SSP<=c1 && c1<0xe0 && iconv == s_iconv) {
1942                         /* SJIS X0201 Case... */
1943                         if(iso2022jp_f && x0201_f==NO_X0201) {
1944                             (*oconv)(GETA1, GETA2);
1945                             NEXT;
1946                         } else {
1947                             c2 = X0201;
1948                             c1 &= 0x7f;
1949                             SEND;
1950                         }
1951                     } else if (c1==SSO && iconv != s_iconv) {
1952                         /* EUC X0201 Case */
1953                         c1 = (*i_getc)(f);  /* skip SSO */
1954                         code_status(c1);
1955                         if (SSP<=c1 && c1<0xe0) {
1956                             if(iso2022jp_f &&  x0201_f==NO_X0201) {
1957                                 (*oconv)(GETA1, GETA2);
1958                                 NEXT;
1959                             } else {
1960                                 c2 = X0201;
1961                                 c1 &= 0x7f;
1962                                 SEND;
1963                             }
1964                         } else  { /* bogus code, skip SSO and one byte */
1965                             NEXT;
1966                         }
1967                     } else {
1968                        /* already established */
1969                        c2 = c1;
1970                        NEXT;
1971                     }
1972                 }
1973             } else if ((c1 > SPACE) && (c1 != DEL)) {
1974                 /* in case of Roman characters */
1975                 if (shift_mode) { 
1976                     /* output 1 shifted byte */
1977                     if (iso8859_f) {
1978                         c2 = ISO8859_1;
1979                         SEND;
1980                     } else if (SPACE<=c1 && c1<(0xe0&0x7f) ){
1981                       /* output 1 shifted byte */
1982                         if(iso2022jp_f && x0201_f==NO_X0201) {
1983                             (*oconv)(GETA1, GETA2);
1984                             NEXT;
1985                         } else {
1986                             c2 = X0201;
1987                             SEND;
1988                         }
1989                     } else {
1990                         /* look like bogus code */
1991                         NEXT;
1992                     }
1993                 } else if (input_mode == X0208) {
1994                     /* in case of Kanji shifted */
1995                     c2 = c1;
1996                     NEXT;
1997                 } else if (c1 == '=' && mime_f && !mime_decode_mode ) {
1998                     /* Check MIME code */
1999                     if ((c1 = (*i_getc)(f)) == EOF) {
2000                         (*oconv)(0, '=');
2001                         LAST;
2002                     } else if (c1 == '?') {
2003                         /* =? is mime conversion start sequence */
2004                         if(mime_f == STRICT_MIME) {
2005                             /* check in real detail */
2006                             if (mime_begin_strict(f) == EOF) 
2007                                 LAST;
2008                             else
2009                                 NEXT;
2010                         } else if (mime_begin(f) == EOF) 
2011                             LAST;
2012                         else
2013                             NEXT;
2014                     } else {
2015                         (*oconv)(0, '=');
2016                         (*i_ungetc)(c1,f);
2017                         NEXT;
2018                     }
2019                 } else {
2020                     /* normal ASCII code */ 
2021                     SEND;
2022                 }
2023             } else if (c1 == SI) {
2024                 shift_mode = FALSE; 
2025                 NEXT;
2026             } else if (c1 == SO) {
2027                 shift_mode = TRUE; 
2028                 NEXT;
2029             } else if (c1 == ESC ) {
2030                 if ((c1 = (*i_getc)(f)) == EOF) {
2031                     /*  (*oconv)(0, ESC); don't send bogus code */
2032                     LAST;
2033                 } else if (c1 == '$') {
2034                     if ((c1 = (*i_getc)(f)) == EOF) {
2035                         /*
2036                         (*oconv)(0, ESC); don't send bogus code 
2037                         (*oconv)(0, '$'); */
2038                         LAST;
2039                     } else if (c1 == '@'|| c1 == 'B') {
2040                         /* This is kanji introduction */
2041                         input_mode = X0208;
2042                         shift_mode = FALSE;
2043                         set_input_codename("ISO-2022-JP");
2044                         debug(input_codename);
2045                         NEXT;
2046                     } else if (c1 == '(') {
2047                         if ((c1 = (*i_getc)(f)) == EOF) {
2048                             /* don't send bogus code 
2049                             (*oconv)(0, ESC);
2050                             (*oconv)(0, '$');
2051                             (*oconv)(0, '(');
2052                                 */
2053                             LAST;
2054                         } else if (c1 == '@'|| c1 == 'B') {
2055                             /* This is kanji introduction */
2056                             input_mode = X0208;
2057                             shift_mode = FALSE;
2058                             NEXT;
2059 #ifdef X0212_ENABLE
2060                         } else if (c1 == 'D'){
2061                             input_mode = X0212;
2062                             shift_mode = FALSE;
2063                             NEXT;
2064 #endif /* X0212_ENABLE */
2065                         } else {
2066                             /* could be some special code */
2067                             (*oconv)(0, ESC);
2068                             (*oconv)(0, '$');
2069                             (*oconv)(0, '(');
2070                             (*oconv)(0, c1);
2071                             NEXT;
2072                         }
2073                     } else if (broken_f&0x2) {
2074                         /* accept any ESC-(-x as broken code ... */
2075                         input_mode = X0208;
2076                         shift_mode = FALSE;
2077                         NEXT;
2078                     } else {
2079                         (*oconv)(0, ESC);
2080                         (*oconv)(0, '$');
2081                         (*oconv)(0, c1);
2082                         NEXT;
2083                     }
2084                 } else if (c1 == '(') {
2085                     if ((c1 = (*i_getc)(f)) == EOF) {
2086                         /* don't send bogus code 
2087                         (*oconv)(0, ESC);
2088                         (*oconv)(0, '('); */
2089                         LAST;
2090                     } else {
2091                         if (c1 == 'I') {
2092                             /* This is X0201 kana introduction */
2093                             input_mode = X0201; shift_mode = X0201;
2094                             NEXT;
2095                         } else if (c1 == 'B' || c1 == 'J' || c1 == 'H') {
2096                             /* This is X0208 kanji introduction */
2097                             input_mode = ASCII; shift_mode = FALSE;
2098                             NEXT;
2099                         } else if (broken_f&0x2) {
2100                             input_mode = ASCII; shift_mode = FALSE;
2101                             NEXT;
2102                         } else {
2103                             (*oconv)(0, ESC);
2104                             (*oconv)(0, '(');
2105                             /* maintain various input_mode here */
2106                             SEND;
2107                         }
2108                     }
2109                } else if ( c1 == 'N' || c1 == 'n' ){
2110                    /* SS2 */
2111                    c3 = (*i_getc)(f);  /* skip SS2 */
2112                    if ( (SPACE<=c3 && c3 < 0x60) || (0xa0<=c3 && c3 < 0xe0)){
2113                        c1 = c3;
2114                        c2 = X0201;
2115                        SEND;
2116                    }else{
2117                        (*i_ungetc)(c3, f);
2118                        /* lonely ESC  */
2119                        (*oconv)(0, ESC);
2120                        SEND;
2121                    }
2122                 } else {
2123                     /* lonely ESC  */
2124                     (*oconv)(0, ESC);
2125                     SEND;
2126                 }
2127             } else if ((c1 == NL || c1 == CR) && broken_f&4) {
2128                 input_mode = ASCII; set_iconv(FALSE, 0);
2129                 SEND;
2130             /*
2131             } else if (c1 == NL && mime_f && !mime_decode_mode ) {
2132                 if ((c1=(*i_getc)(f))!=EOF && c1 == SPACE) {
2133                     i_ungetc(SPACE,f);
2134                     continue;
2135                 } else {
2136                     i_ungetc(c1,f);
2137                 }
2138                 c1 = NL;
2139                 SEND;
2140             } else if (c1 == CR && mime_f && !mime_decode_mode ) {
2141                 if ((c1=(*i_getc)(f))!=EOF) {
2142                     if (c1==SPACE) {
2143                         i_ungetc(SPACE,f);
2144                         continue;
2145                     } else if (c1 == NL && (c1=(*i_getc)(f))!=EOF && c1 == SPACE) {
2146                         i_ungetc(SPACE,f);
2147                         continue;
2148                     } else {
2149                         i_ungetc(c1,f);
2150                     }
2151                     i_ungetc(NL,f);
2152                 } else {
2153                     i_ungetc(c1,f);
2154                 }
2155                 c1 = CR;
2156                 SEND;
2157             */
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                     }
4458