OSDN Git Service

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