OSDN Git Service

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