OSDN Git Service

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