OSDN Git Service

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