OSDN Git Service

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