OSDN Git Service

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