OSDN Git Service

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