OSDN Git Service

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