OSDN Git Service

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