OSDN Git Service

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