OSDN Git Service

e8880a56fdd30db1276e5ce972be4b857132f0bd
[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 = FALSE;
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_L2       (1)                   /* \e$BBh\e(B2\e$B?e=`4A;z\e(B */
1254 #define SCORE_KANA     (SCORE_L2 << 1)       /* \e$B$$$o$f$kH>3Q%+%J\e(B */
1255 #define SCORE_DEPEND   (SCORE_KANA << 1)     /* \e$B5!<o0MB8J8;z\e(B */
1256 #ifdef SHIFTJIS_CP932
1257 #define SCORE_CP932    (SCORE_DEPEND << 1)   /* CP932 \e$B$K$h$kFI$_49$(\e(B */
1258 #define SCORE_NO_EXIST (SCORE_CP932 << 1)    /* \e$BB8:_$7$J$$J8;z\e(B */
1259 #else
1260 #define SCORE_NO_EXIST (SCORE_DEPEND << 1)   /* \e$BB8:_$7$J$$J8;z\e(B */
1261 #endif
1262 #define SCORE_iMIME    (SCORE_NO_EXIST << 1) /* MIME \e$B$K$h$k;XDj\e(B */
1263 #define SCORE_ERROR    (SCORE_iMIME << 1) /* \e$B%(%i!<\e(B */
1264
1265 #define SCORE_INIT (SCORE_iMIME)
1266
1267 int score_table_A0[] = {
1268     0, 0, 0, 0,
1269     0, 0, 0, 0,
1270     0, SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND,
1271     SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND, SCORE_NO_EXIST,
1272 };
1273
1274 int score_table_F0[] = {
1275     SCORE_L2, SCORE_L2, SCORE_L2, SCORE_L2,
1276     SCORE_L2, SCORE_DEPEND, SCORE_NO_EXIST, SCORE_NO_EXIST,
1277     SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND,
1278     SCORE_DEPEND, SCORE_NO_EXIST, SCORE_NO_EXIST, SCORE_ERROR,
1279 };
1280
1281 void set_code_score(ptr, score)
1282      struct input_code *ptr;
1283      int score;
1284 {
1285     if (ptr){
1286         ptr->score |= score;
1287     }
1288 }
1289
1290 void clr_code_score(ptr, score)
1291      struct input_code *ptr;
1292      int score;
1293 {
1294     if (ptr){
1295         ptr->score &= ~score;
1296     }
1297 }
1298
1299 void code_score(ptr)
1300      struct input_code *ptr;
1301 {
1302     int c2 = ptr->buf[0];
1303     int c1 = ptr->buf[1];
1304     if (c2 < 0){
1305         set_code_score(ptr, SCORE_ERROR);
1306     }else if (c2 == SSO){
1307         set_code_score(ptr, SCORE_KANA);
1308 #ifdef UTF8_OUTPUT_ENABLE
1309     }else if (!e2w_conv(c2, c1)){
1310         set_code_score(ptr, SCORE_NO_EXIST);
1311 #endif
1312     }else if ((c2 & 0x70) == 0x20){
1313         set_code_score(ptr, score_table_A0[c2 & 0x0f]);
1314     }else if ((c2 & 0x70) == 0x70){
1315         set_code_score(ptr, score_table_F0[c2 & 0x0f]);
1316     }else if ((c2 & 0x70) >= 0x50){
1317         set_code_score(ptr, SCORE_L2);
1318     }
1319 }
1320
1321 void status_disable(ptr)
1322 struct input_code *ptr;
1323 {
1324     ptr->stat = -1;
1325     ptr->buf[0] = -1;
1326     code_score(ptr);
1327     if (iconv == ptr->iconv_func) set_iconv(FALSE, 0);
1328 }
1329
1330 void status_push_ch(ptr, c)
1331      struct input_code *ptr;
1332      int c;
1333 {
1334     ptr->buf[ptr->index++] = c;
1335 }
1336
1337 void status_clear(ptr)
1338      struct input_code *ptr;
1339 {
1340     ptr->stat = 0;
1341     ptr->index = 0;
1342 }
1343
1344 void status_reset(ptr)
1345      struct input_code *ptr;
1346 {
1347     status_clear(ptr);
1348     ptr->score = SCORE_INIT;
1349 }
1350
1351 void status_reinit(ptr)
1352      struct input_code *ptr;
1353 {
1354     status_reset(ptr);
1355     ptr->_file_stat = 0;
1356 }
1357
1358 void status_check(ptr, c)
1359      struct input_code *ptr;
1360      int c;
1361 {
1362     if (c <= DEL && estab_f){
1363         status_reset(ptr);
1364     }
1365 }
1366
1367 void s_status(ptr, c)
1368      struct input_code *ptr;
1369      int c;
1370 {
1371     switch(ptr->stat){
1372       case -1:
1373           status_check(ptr, c);
1374           break;
1375       case 0:
1376           if (c <= DEL){
1377               break;
1378 #ifdef NUMCHAR_OPTION
1379           }else if ((c & CLASS_MASK) == CLASS_UTF16){
1380               break;
1381 #endif
1382           }else if (0xa1 <= c && c <= 0xdf){
1383               status_push_ch(ptr, SSO);
1384               status_push_ch(ptr, c);
1385               code_score(ptr);
1386               status_clear(ptr);
1387           }else if ((0x81 <= c && c < 0xa0) || (0xe0 <= c && c <= 0xef)){
1388               ptr->stat = 1;
1389               status_push_ch(ptr, c);
1390 #ifdef SHIFTJIS_CP932
1391           }else if (cp932_f
1392                     && CP932_TABLE_BEGIN <= c && c <= CP932_TABLE_END){
1393               ptr->stat = 2;
1394               status_push_ch(ptr, c);
1395 #endif /* SHIFTJIS_CP932 */
1396           }else{
1397               status_disable(ptr);
1398           }
1399           break;
1400       case 1:
1401           if ((0x40 <= c && c <= 0x7e) || (0x80 <= c && c <= 0xfc)){
1402               status_push_ch(ptr, c);
1403               s2e_conv(ptr->buf[0], ptr->buf[1], &ptr->buf[0], &ptr->buf[1]);
1404               code_score(ptr);
1405               status_clear(ptr);
1406           }else{
1407               status_disable(ptr);
1408           }
1409           break;
1410 #ifdef SHIFTJIS_CP932
1411       case 2:
1412           if ((0x40 <= c && c <= 0x7e) || (0x80 <= c && c <= 0xfc)){
1413               status_push_ch(ptr, c);
1414               if (s2e_conv(ptr->buf[0], ptr->buf[1], &ptr->buf[0], &ptr->buf[1]) == 0){
1415                   set_code_score(ptr, SCORE_CP932);
1416                   status_clear(ptr);
1417                   break;
1418               }
1419           }
1420           status_disable(ptr);
1421           break;
1422 #endif /* SHIFTJIS_CP932 */
1423     }
1424 }
1425
1426 void e_status(ptr, c)
1427      struct input_code *ptr;
1428      int c;
1429 {
1430     switch (ptr->stat){
1431       case -1:
1432           status_check(ptr, c);
1433           break;
1434       case 0:
1435           if (c <= DEL){
1436               break;
1437 #ifdef NUMCHAR_OPTION
1438           }else if ((c & CLASS_MASK) == CLASS_UTF16){
1439               break;
1440 #endif
1441           }else if (SSO == c || (0xa1 <= c && c <= 0xfe)){
1442               ptr->stat = 1;
1443               status_push_ch(ptr, c);
1444           }else{
1445               status_disable(ptr);
1446           }
1447           break;
1448       case 1:
1449           if (0xa1 <= c && c <= 0xfe){
1450               status_push_ch(ptr, c);
1451               code_score(ptr);
1452               status_clear(ptr);
1453           }else{
1454               status_disable(ptr);
1455           }
1456           break;
1457     }
1458 }
1459
1460 #ifdef UTF8_INPUT_ENABLE
1461 void w16_status(ptr, c)
1462      struct input_code *ptr;
1463      int c;
1464 {
1465     switch (ptr->stat){
1466       case -1:
1467           break;
1468       case 0:
1469           if (ptr->_file_stat == 0){
1470               if (c == 0xfe || c == 0xff){
1471                   ptr->stat = c;
1472                   status_push_ch(ptr, c);
1473                   ptr->_file_stat = 1;
1474               }else{
1475                   status_disable(ptr);
1476                   ptr->_file_stat = -1;
1477               }
1478           }else if (ptr->_file_stat > 0){
1479               ptr->stat = 1;
1480               status_push_ch(ptr, c);
1481           }else if (ptr->_file_stat < 0){
1482               status_disable(ptr);
1483           }
1484           break;
1485
1486       case 1:
1487           if (c == EOF){
1488               status_disable(ptr);
1489               ptr->_file_stat = -1;
1490           }else{
1491               status_push_ch(ptr, c);
1492               status_clear(ptr);
1493           }
1494           break;
1495
1496       case 0xfe:
1497       case 0xff:
1498           if (ptr->stat != c && (c == 0xfe || c == 0xff)){
1499               status_push_ch(ptr, c);
1500               status_clear(ptr);
1501           }else{
1502               status_disable(ptr);
1503               ptr->_file_stat = -1;
1504           }
1505           break;
1506     }
1507 }
1508
1509 void w_status(ptr, c)
1510      struct input_code *ptr;
1511      int c;
1512 {
1513     switch (ptr->stat){
1514       case -1:
1515           status_check(ptr, c);
1516           break;
1517       case 0:
1518           if (c <= DEL){
1519               break;
1520 #ifdef NUMCHAR_OPTION
1521           }else if ((c & CLASS_MASK) == CLASS_UTF16){
1522               break;
1523 #endif
1524           }else if (0xc0 <= c && c <= 0xdf){
1525               ptr->stat = 1;
1526               status_push_ch(ptr, c);
1527           }else if (0xe0 <= c && c <= 0xef){
1528               ptr->stat = 2;
1529               status_push_ch(ptr, c);
1530           }else{
1531               status_disable(ptr);
1532           }
1533           break;
1534       case 1:
1535       case 2:
1536           if (0x80 <= c && c <= 0xbf){
1537               status_push_ch(ptr, c);
1538               if (ptr->index > ptr->stat){
1539                   w2e_conv(ptr->buf[0], ptr->buf[1], ptr->buf[2],
1540                            &ptr->buf[0], &ptr->buf[1]);
1541                   code_score(ptr);
1542                   status_clear(ptr);
1543               }
1544           }else{
1545               status_disable(ptr);
1546           }
1547           break;
1548     }
1549 }
1550 #endif
1551
1552 void
1553 code_status(c)
1554      int c;
1555 {
1556     int action_flag = 1;
1557     struct input_code *result = 0;
1558     struct input_code *p = input_code_list;
1559     while (p->name){
1560         (p->status_func)(p, c);
1561         if (p->stat > 0){
1562             action_flag = 0;
1563         }else if(p->stat == 0){
1564             if (result){
1565                 action_flag = 0;
1566             }else{
1567                 result = p;
1568             }
1569         }
1570         ++p;
1571     }
1572
1573     if (action_flag){
1574         if (result && !estab_f){
1575             set_iconv(TRUE, result->iconv_func);
1576         }else if (c <= DEL){
1577             struct input_code *ptr = input_code_list;
1578             while (ptr->name){
1579                 status_reset(ptr);
1580                 ++ptr;
1581             }
1582         }
1583     }
1584 }
1585
1586 #ifdef PERL_XS
1587 #define STD_GC_BUFSIZE (256)
1588 int std_gc_buf[STD_GC_BUFSIZE];
1589 int std_gc_ndx;
1590 #endif
1591
1592 int 
1593 std_getc(f)
1594 FILE *f;
1595 {
1596 #ifdef PERL_XS
1597     if (std_gc_ndx){
1598         return std_gc_buf[--std_gc_ndx];
1599     }
1600 #endif
1601     return getc(f);
1602 }
1603
1604 int 
1605 std_ungetc(c,f)
1606 int c;
1607 FILE *f;
1608 {
1609 #ifdef PERL_XS
1610     if (std_gc_ndx == STD_GC_BUFSIZE){
1611         return EOF;
1612     }
1613     std_gc_buf[std_gc_ndx++] = c;
1614     return c;
1615 #endif
1616     return ungetc(c,f);
1617 }
1618
1619 void 
1620 std_putc(c)
1621 int c;
1622 {
1623     if(c!=EOF)
1624       putchar(c);
1625 }
1626
1627 int
1628 noconvert(f)
1629     FILE  *f;
1630 {
1631     int    c;
1632
1633     while ((c = (*i_getc)(f)) != EOF)
1634       (*o_putc)(c);
1635     return 1;
1636 }
1637
1638
1639 void
1640 module_connection()
1641 {
1642     oconv = output_conv; 
1643     o_putc = std_putc;
1644
1645     /* replace continucation module, from output side */
1646
1647     /* output redicrection */
1648 #ifdef CHECK_OPTION
1649     if (noout_f){
1650         o_putc = no_putc;
1651     }
1652 #endif
1653     if (mimeout_f) {
1654         o_mputc = o_putc;
1655         o_putc = mime_putc;
1656         if (mimeout_f == TRUE) {
1657             o_base64conv = oconv; oconv = base64_conv;
1658         }
1659         /* base64_count = 0; */
1660     }
1661
1662     if (crmode_f) {
1663         o_crconv = oconv; oconv = cr_conv;
1664     }
1665     if (rot_f) {
1666         o_rot_conv = oconv; oconv = rot_conv;
1667     }
1668     if (iso2022jp_f) {
1669         o_iso2022jp_check_conv = oconv; oconv = iso2022jp_check_conv;
1670     }
1671     if (hira_f) {
1672         o_hira_conv = oconv; oconv = hira_conv;
1673     }
1674     if (fold_f) {
1675         o_fconv = oconv; oconv = fold_conv;
1676         f_line = 0;
1677     }
1678     if (alpha_f || x0201_f) {
1679         o_zconv = oconv; oconv = z_conv;
1680     }
1681
1682     i_getc = std_getc;
1683     i_ungetc = std_ungetc;
1684     /* input redicrection */
1685 #ifdef INPUT_OPTION
1686     if (cap_f){
1687         i_cgetc = i_getc; i_getc = cap_getc;
1688         i_cungetc = i_ungetc; i_ungetc= cap_ungetc;
1689     }
1690     if (url_f){
1691         i_ugetc = i_getc; i_getc = url_getc;
1692         i_uungetc = i_ungetc; i_ungetc= url_ungetc;
1693     }
1694 #endif
1695 #ifdef NUMCHAR_OPTION
1696     if (numchar_f){
1697         i_ngetc = i_getc; i_getc = numchar_getc;
1698         i_nungetc = i_ungetc; i_ungetc= numchar_ungetc;
1699     }
1700 #endif
1701     if (mime_f && mimebuf_f==FIXED_MIME) {
1702         i_mgetc = i_getc; i_getc = mime_getc;
1703         i_mungetc = i_ungetc; i_ungetc = mime_ungetc;
1704     }
1705     if (broken_f & 1) {
1706         i_bgetc = i_getc; i_getc = broken_getc;
1707         i_bungetc = i_ungetc; i_ungetc = broken_ungetc;
1708     }
1709     if (input_f == JIS_INPUT || input_f == LATIN1_INPUT) {
1710         set_iconv(-TRUE, e_iconv);
1711     } else if (input_f == SJIS_INPUT) {
1712         set_iconv(-TRUE, s_iconv);
1713 #ifdef UTF8_INPUT_ENABLE
1714     } else if (input_f == UTF8_INPUT) {
1715         set_iconv(-TRUE, w_iconv);
1716     } else if (input_f == UTF16_INPUT) {
1717         set_iconv(-TRUE, w_iconv16);
1718 #endif
1719     } else {
1720         set_iconv(FALSE, e_iconv);
1721     }
1722
1723     {
1724         struct input_code *p = input_code_list;
1725         while (p->name){
1726             status_reinit(p++);
1727         }
1728     }
1729 }
1730
1731 /*
1732    Conversion main loop. Code detection only. 
1733  */
1734
1735 int
1736 kanji_convert(f)
1737     FILE  *f;
1738 {
1739     int    c1,
1740                     c2;
1741
1742     module_connection();
1743     c2 = 0;
1744
1745
1746     input_mode = ASCII;
1747     output_mode = ASCII;
1748     shift_mode = FALSE;
1749
1750 #define NEXT continue      /* no output, get next */
1751 #define SEND ;             /* output c1 and c2, get next */
1752 #define LAST break         /* end of loop, go closing  */
1753
1754     while ((c1 = (*i_getc)(f)) != EOF) {
1755         code_status(c1);
1756         if (c2) {
1757             /* second byte */
1758             if (c2 > DEL) {
1759                 /* in case of 8th bit is on */
1760                 if (!estab_f) {
1761                     /* in case of not established yet */
1762                     /* It is still ambiguious */
1763                     if (h_conv(f, c2, c1)==EOF) 
1764                         LAST;
1765                     else 
1766                         c2 = 0;
1767                     NEXT;
1768                 } else
1769                     /* in case of already established */
1770                     if (c1 < AT) {
1771                         /* ignore bogus code */
1772                         c2 = 0;
1773                         NEXT;
1774                     } else
1775                         SEND;
1776             } else
1777                 /* second byte, 7 bit code */
1778                 /* it might be kanji shitfted */
1779                 if ((c1 == DEL) || (c1 <= SPACE)) {
1780                     /* ignore bogus first code */
1781                     c2 = 0;
1782                     NEXT;
1783                 } else
1784                     SEND;
1785         } else {
1786             /* first byte */
1787             if (
1788 #ifdef UTF8_INPUT_ENABLE
1789                 iconv == w_iconv16
1790 #else
1791                 0
1792 #endif
1793                 ) {
1794                 c2 = c1;
1795                 c1 = (*i_getc)(f);
1796                 SEND;
1797 #ifdef NUMCHAR_OPTION
1798             } else if ((c1 & CLASS_MASK) == CLASS_UTF16){
1799                 SEND;
1800 #endif
1801             } else if (c1 > DEL) {
1802                 /* 8 bit code */
1803                 if (!estab_f && !iso8859_f) {
1804                     /* not established yet */
1805                     c2 = c1;
1806                     NEXT;
1807                 } else { /* estab_f==TRUE */
1808                     if (iso8859_f) {
1809                         c2 = ISO8859_1;
1810                         c1 &= 0x7f;
1811                         SEND;
1812                     } else if (SSP<=c1 && c1<0xe0 && iconv == s_iconv) {
1813                         /* SJIS X0201 Case... */
1814                         if(iso2022jp_f && x0201_f==NO_X0201) {
1815                             (*oconv)(GETA1, GETA2);
1816                             NEXT;
1817                         } else {
1818                             c2 = X0201;
1819                             c1 &= 0x7f;
1820                             SEND;
1821                         }
1822                     } else if (c1==SSO && iconv != s_iconv) {
1823                         /* EUC X0201 Case */
1824                         c1 = (*i_getc)(f);  /* skip SSO */
1825                         code_status(c1);
1826                         if (SSP<=c1 && c1<0xe0) {
1827                             if(iso2022jp_f &&  x0201_f==NO_X0201) {
1828                                 (*oconv)(GETA1, GETA2);
1829                                 NEXT;
1830                             } else {
1831                                 c2 = X0201;
1832                                 c1 &= 0x7f;
1833                                 SEND;
1834                             }
1835                         } else  { /* bogus code, skip SSO and one byte */
1836                             NEXT;
1837                         }
1838                     } else {
1839                        /* already established */
1840                        c2 = c1;
1841                        NEXT;
1842                     }
1843                 }
1844             } else if ((c1 > SPACE) && (c1 != DEL)) {
1845                 /* in case of Roman characters */
1846                 if (shift_mode) { 
1847                     /* output 1 shifted byte */
1848                     if (iso8859_f) {
1849                         c2 = ISO8859_1;
1850                         SEND;
1851                     } else if (SPACE<=c1 && c1<(0xe0&0x7f) ){
1852                       /* output 1 shifted byte */
1853                         if(iso2022jp_f && x0201_f==NO_X0201) {
1854                             (*oconv)(GETA1, GETA2);
1855                             NEXT;
1856                         } else {
1857                             c2 = X0201;
1858                             SEND;
1859                         }
1860                     } else {
1861                         /* look like bogus code */
1862                         NEXT;
1863                     }
1864                 } else if (input_mode == X0208) {
1865                     /* in case of Kanji shifted */
1866                     c2 = c1;
1867                     NEXT;
1868                 } else if (c1 == '=' && mime_f && !mime_decode_mode ) {
1869                     /* Check MIME code */
1870                     if ((c1 = (*i_getc)(f)) == EOF) {
1871                         (*oconv)(0, '=');
1872                         LAST;
1873                     } else if (c1 == '?') {
1874                         /* =? is mime conversion start sequence */
1875                         if(mime_f == STRICT_MIME) {
1876                             /* check in real detail */
1877                             if (mime_begin_strict(f) == EOF) 
1878                                 LAST;
1879                             else
1880                                 NEXT;
1881                         } else if (mime_begin(f) == EOF) 
1882                             LAST;
1883                         else
1884                             NEXT;
1885                     } else {
1886                         (*oconv)(0, '=');
1887                         (*i_ungetc)(c1,f);
1888                         NEXT;
1889                     }
1890                 } else {
1891                     /* normal ASCII code */ 
1892                     SEND;
1893                 }
1894             } else if (c1 == SI) {
1895                 shift_mode = FALSE; 
1896                 NEXT;
1897             } else if (c1 == SO) {
1898                 shift_mode = TRUE; 
1899                 NEXT;
1900             } else if (c1 == ESC ) {
1901                 if ((c1 = (*i_getc)(f)) == EOF) {
1902                     /*  (*oconv)(0, ESC); don't send bogus code */
1903                     LAST;
1904                 } else if (c1 == '$') {
1905                     if ((c1 = (*i_getc)(f)) == EOF) {
1906                         /*
1907                         (*oconv)(0, ESC); don't send bogus code 
1908                         (*oconv)(0, '$'); */
1909                         LAST;
1910                     } else if (c1 == '@'|| c1 == 'B') {
1911                         /* This is kanji introduction */
1912                         input_mode = X0208;
1913                         shift_mode = FALSE;
1914                         debug(input_codename = "ISO-2022-JP");
1915                         NEXT;
1916                     } else if (c1 == '(') {
1917                         if ((c1 = (*i_getc)(f)) == EOF) {
1918                             /* don't send bogus code 
1919                             (*oconv)(0, ESC);
1920                             (*oconv)(0, '$');
1921                             (*oconv)(0, '(');
1922                                 */
1923                             LAST;
1924                         } else if (c1 == '@'|| c1 == 'B') {
1925                             /* This is kanji introduction */
1926                             input_mode = X0208;
1927                             shift_mode = FALSE;
1928                             NEXT;
1929                         } else {
1930                             /* could be some special code */
1931                             (*oconv)(0, ESC);
1932                             (*oconv)(0, '$');
1933                             (*oconv)(0, '(');
1934                             (*oconv)(0, c1);
1935                             NEXT;
1936                         }
1937                     } else if (broken_f&0x2) {
1938                         /* accept any ESC-(-x as broken code ... */
1939                         input_mode = X0208;
1940                         shift_mode = FALSE;
1941                         NEXT;
1942                     } else {
1943                         (*oconv)(0, ESC);
1944                         (*oconv)(0, '$');
1945                         (*oconv)(0, c1);
1946                         NEXT;
1947                     }
1948                 } else if (c1 == '(') {
1949                     if ((c1 = (*i_getc)(f)) == EOF) {
1950                         /* don't send bogus code 
1951                         (*oconv)(0, ESC);
1952                         (*oconv)(0, '('); */
1953                         LAST;
1954                     } else {
1955                         if (c1 == 'I') {
1956                             /* This is X0201 kana introduction */
1957                             input_mode = X0201; shift_mode = X0201;
1958                             NEXT;
1959                         } else if (c1 == 'B' || c1 == 'J' || c1 == 'H') {
1960                             /* This is X0208 kanji introduction */
1961                             input_mode = ASCII; shift_mode = FALSE;
1962                             NEXT;
1963                         } else if (broken_f&0x2) {
1964                             input_mode = ASCII; shift_mode = FALSE;
1965                             NEXT;
1966                         } else {
1967                             (*oconv)(0, ESC);
1968                             (*oconv)(0, '(');
1969                             /* maintain various input_mode here */
1970                             SEND;
1971                         }
1972                     }
1973                } else if ( c1 == 'N' || c1 == 'n' ){
1974                    /* SS2 */
1975                    c1 = (*i_getc)(f);  /* skip SS2 */
1976                    if ( SPACE<=c1 && c1 < 0xe0 ) {
1977                        c2 = X0201;
1978                        SEND;
1979                    }
1980                 } else {
1981                     /* lonely ESC  */
1982                     (*oconv)(0, ESC);
1983                     SEND;
1984                 }
1985             } else if ((c1 == NL || c1 == CR) && broken_f&4) {
1986                 input_mode = ASCII; set_iconv(FALSE, 0);
1987                 SEND;
1988             } else 
1989                 SEND;
1990         }
1991         /* send: */
1992         if (input_mode == X0208) 
1993             (*oconv)(c2, c1);  /* this is JIS, not SJIS/EUC case */
1994         else if (input_mode) 
1995             (*oconv)(input_mode, c1);  /* other special case */
1996         else if ((*iconv)(c2, c1, 0) < 0){  /* can be EUC/SJIS */
1997             int c0 = (*i_getc)(f);
1998             if (c0 != EOF){
1999                 code_status(c0);
2000                 (*iconv)(c2, c1, c0);
2001             }
2002         }
2003
2004         c2 = 0;
2005         continue;
2006         /* goto next_word */
2007     }
2008
2009     /* epilogue */
2010     (*iconv)(EOF, 0, 0);
2011     return 1;
2012 }
2013
2014 int
2015 h_conv(f, c2, c1)
2016     FILE  *f;
2017     int    c1,
2018                     c2;
2019 {
2020     int    wc,c3;
2021
2022
2023     /** it must NOT be in the kanji shifte sequence      */
2024     /** it must NOT be written in JIS7                   */
2025     /** and it must be after 2 byte 8bit code            */
2026
2027     hold_count = 0;
2028     push_hold_buf(c2);
2029     push_hold_buf(c1);
2030     c2 = 0;
2031
2032     while ((c1 = (*i_getc)(f)) != EOF) {
2033         if (c1 == ESC){
2034             (*i_ungetc)(c1,f);
2035             break;
2036         }
2037         code_status(c1);
2038         if (push_hold_buf(c1) == EOF || estab_f){
2039             break;
2040         }
2041     }
2042
2043     if (!estab_f){
2044         struct input_code *p = input_code_list;
2045         struct input_code *result = p;
2046         if (c1 == EOF){
2047             code_status(c1);
2048         }
2049         while (p->name){
2050             if (p->score < result->score){
2051                 result = p;
2052             }
2053             ++p;
2054         }
2055         set_iconv(FALSE, result->iconv_func);
2056     }
2057
2058
2059     /** now,
2060      ** 1) EOF is detected, or
2061      ** 2) Code is established, or
2062      ** 3) Buffer is FULL (but last word is pushed)
2063      **
2064      ** in 1) and 3) cases, we continue to use
2065      ** Kanji codes by oconv and leave estab_f unchanged.
2066      **/
2067
2068     c3=c1;
2069     wc = 0;
2070     while (wc < hold_count){
2071         c2 = hold_buf[wc++];
2072         if (c2 <= DEL
2073 #ifdef NUMCHAR_OPTION
2074             || (c2 & CLASS_MASK) == CLASS_UTF16
2075 #endif
2076             ){
2077             (*iconv)(0, c2, 0);
2078             continue;
2079         }else if (iconv == s_iconv && 0xa1 <= c2 && c2 <= 0xdf){
2080             (*iconv)(X0201, c2, 0);
2081             continue;
2082         }
2083         if (wc < hold_count){
2084             c1 = hold_buf[wc++];
2085         }else{
2086             c1 = (*i_getc)(f);
2087             if (c1 == EOF){
2088                 c3 = EOF;
2089                 break;
2090             }
2091             code_status(c1);
2092         }
2093         if ((*iconv)(c2, c1, 0) < 0){
2094             int c0;
2095             if (wc < hold_count){
2096                 c0 = hold_buf[wc++];
2097             }else{
2098                 c0 = (*i_getc)(f);
2099                 if (c0 == EOF){
2100                     c3 = EOF;
2101                     break;
2102                 }
2103                 code_status(c0);
2104             }
2105             (*iconv)(c2, c1, c0);
2106             c1 = c0;
2107         }
2108     }
2109     return c3;
2110 }
2111
2112
2113
2114 int
2115 push_hold_buf(c2)
2116      int             c2;
2117 {
2118     if (hold_count >= HOLD_SIZE*2)
2119         return (EOF);
2120     hold_buf[hold_count++] = c2;
2121     return ((hold_count >= HOLD_SIZE*2) ? EOF : hold_count);
2122 }
2123
2124 int s2e_conv(c2, c1, p2, p1)
2125      int c2, c1;
2126      int *p2, *p1;
2127 {
2128 #ifdef SHIFTJIS_CP932
2129     if (cp932_f && CP932_TABLE_BEGIN <= c2 && c2 <= CP932_TABLE_END){
2130         extern unsigned short shiftjis_cp932[3][189];
2131         c1 = shiftjis_cp932[c2 - CP932_TABLE_BEGIN][c1 - 0x40];
2132         if (c1 == 0) return 1;
2133         c2 = c1 >> 8;
2134         c1 &= 0xff;
2135     }
2136 #endif /* SHIFTJIS_CP932 */
2137     c2 = c2 + c2 - ((c2 <= 0x9f) ? SJ0162 : SJ6394);
2138     if (c1 < 0x9f)
2139         c1 = c1 - ((c1 > DEL) ? SPACE : 0x1f);
2140     else {
2141         c1 = c1 - 0x7e;
2142         c2++;
2143     }
2144     if (p2) *p2 = c2;
2145     if (p1) *p1 = c1;
2146     return 0;
2147 }
2148
2149 int
2150 s_iconv(c2, c1, c0)
2151     int    c2,
2152                     c1, c0;
2153 {
2154     if (c2 == X0201) {
2155         c1 &= 0x7f;
2156     } else if ((c2 == EOF) || (c2 == 0) || c2 < SPACE) {
2157         /* NOP */
2158     } else {
2159         int ret = s2e_conv(c2, c1, &c2, &c1);
2160         if (ret) return ret;
2161     }
2162     (*oconv)(c2, c1);
2163     return 0;
2164 }
2165
2166 int
2167 e_iconv(c2, c1, c0)
2168     int    c2,
2169                     c1, c0;
2170 {
2171     if (c2 == X0201) {
2172         c1 &= 0x7f;
2173     } else if (c2 == SSO){
2174         c2 = X0201;
2175         c1 &= 0x7f;
2176     } else if ((c2 == EOF) || (c2 == 0) || c2 < SPACE) {
2177         /* NOP */
2178     } else {
2179         c1 &= 0x7f;
2180         c2 &= 0x7f;
2181     }
2182     (*oconv)(c2, c1);
2183     return 0;
2184 }
2185
2186 #ifdef UTF8_INPUT_ENABLE
2187 int
2188 w2e_conv(c2, c1, c0, p2, p1)
2189     int    c2, c1, c0;
2190     int *p2, *p1;
2191 {
2192     extern unsigned short * utf8_to_euc_2bytes[];
2193     extern unsigned short ** utf8_to_euc_3bytes[];
2194     int ret = 0;
2195
2196     if (0xc0 <= c2 && c2 <= 0xef) {
2197         unsigned short **pp;
2198
2199         if (0xe0 <= c2) {
2200             if (c0 == 0) return -1;
2201             pp = utf8_to_euc_3bytes[c2 - 0x80];
2202             ret = w_iconv_common(c1, c0, pp, sizeof_utf8_to_euc_C2, p2, p1);
2203         } else {
2204             ret =  w_iconv_common(c2, c1, utf8_to_euc_2bytes, sizeof_utf8_to_euc_2bytes, p2, p1);
2205         }
2206 #ifdef NUMCHAR_OPTION
2207         if (ret){
2208             c1 = CLASS_UTF16 | ww16_conv(c2, c1, c0);
2209             c2 = 0;
2210             ret = 0;
2211         }
2212 #endif
2213         return ret;
2214     } else if (c2 == X0201) {
2215         c1 &= 0x7f;
2216     }
2217     if (p2) *p2 = c2;
2218     if (p1) *p1 = c1;
2219     return ret;
2220 }
2221
2222 int
2223 w_iconv(c2, c1, c0)
2224     int    c2,
2225                     c1, c0;
2226 {
2227     int ret = w2e_conv(c2, c1, c0, &c2, &c1);
2228     if (ret == 0){
2229         (*oconv)(c2, c1);
2230     }
2231     return ret;
2232 }
2233
2234 void
2235 w16w_conv(val, p2, p1, p0)
2236      unsigned short val;
2237      int *p2, *p1, *p0;
2238 {
2239     if (val < 0x80){
2240         *p2 = val;
2241         *p1 = 0;
2242         *p0 = 0;
2243     }else if (val < 0x800){
2244         *p2 = 0xc0 | (val >> 6);
2245         *p1 = 0x80 | (val & 0x3f);
2246         *p0 = 0;
2247     }else{
2248         *p2 = 0xe0 | (val >> 12);
2249         *p1 = 0x80 | ((val >> 6) & 0x3f);
2250         *p0 = 0x80 | (val        & 0x3f);
2251     }
2252 }
2253
2254 int
2255 ww16_conv(c2, c1, c0)
2256      int c2, c1, c0;
2257 {
2258     unsigned short val;
2259     if (c2 >= 0xe0){
2260         val = (c2 & 0x0f) << 12;
2261         val |= (c1 & 0x3f) << 6;
2262         val |= (c0 & 0x3f);
2263     }else if (c2 >= 0xc0){
2264         val = (c2 & 0x1f) << 6;
2265         val |= (c1 & 0x3f) << 6;
2266     }else{
2267         val = c2;
2268     }
2269     return val;
2270 }
2271
2272 int
2273 w16e_conv(val, p2, p1)
2274      unsigned short val;
2275      int *p2, *p1;
2276 {
2277     extern unsigned short * utf8_to_euc_2bytes[];
2278     extern unsigned short ** utf8_to_euc_3bytes[];
2279     int c2, c1, c0;
2280     unsigned short **pp;
2281     int psize;
2282     int ret = 0;
2283
2284     w16w_conv(val, &c2, &c1, &c0);
2285     if (c1){
2286         if (c0){
2287             pp = utf8_to_euc_3bytes[c2 - 0x80];
2288             psize = sizeof_utf8_to_euc_C2;
2289             ret =  w_iconv_common(c1, c0, pp, psize, p2, p1);
2290         }else{
2291             pp = utf8_to_euc_2bytes;
2292             psize = sizeof_utf8_to_euc_2bytes;
2293             ret =  w_iconv_common(c2, c1, pp, psize, p2, p1);
2294         }
2295 #ifdef NUMCHAR_OPTION
2296         if (ret){
2297             *p2 = 0;
2298             *p1 = CLASS_UTF16 | val;
2299             ret = 0;
2300         }
2301 #endif
2302     }
2303     return ret;
2304 }
2305
2306 int
2307 w_iconv16(c2, c1, c0)
2308     int    c2, c1,c0;
2309 {
2310     int ret;
2311
2312     if (c2==0376 && c1==0377){
2313         utf16_mode = UTF16_INPUT;
2314         return 0;    
2315     } else if (c2==0377 && c1==0376){
2316         utf16_mode = UTF16BE_INPUT;
2317         return 0;    
2318     }
2319     if (utf16_mode == UTF16BE_INPUT) {
2320         int tmp;
2321         tmp=c1; c1=c2; c2=tmp;
2322     }
2323     if ((c2==0 && c1 < 0x80) || c2==EOF) {
2324         (*oconv)(c2, c1);
2325         return 0;
2326     }
2327     ret = w16e_conv(((c2<<8)&0xff00) + c1, &c2, &c1);
2328     if (ret) return ret;
2329     (*oconv)(c2, c1);
2330     return 0;
2331 }
2332
2333 int
2334 w_iconv_common(c1, c0, pp, psize, p2, p1)
2335     int    c1,c0;
2336     unsigned short **pp;
2337     int psize;
2338     int *p2, *p1;
2339 {
2340     int c2;
2341     unsigned short *p ;
2342     unsigned short val;
2343
2344     if (pp == 0) return 1;
2345
2346     c1 -= 0x80;
2347     if (c1 < 0 || psize <= c1) return 1;
2348     p = pp[c1];
2349     if (p == 0)  return 1;
2350
2351     c0 -= 0x80;
2352     if (c0 < 0 || sizeof_utf8_to_euc_E5B8 <= c0) return 1;
2353     val = p[c0];
2354     if (val == 0) return 1;
2355
2356     c2 = val >> 8;
2357     if (c2 == SO) c2 = X0201;
2358     c1 = val & 0x7f;
2359     if (p2) *p2 = c2;
2360     if (p1) *p1 = c1;
2361     return 0;
2362 }
2363
2364 #endif
2365
2366 #ifdef UTF8_OUTPUT_ENABLE
2367 int
2368 e2w_conv(c2, c1)
2369     int    c2, c1;
2370 {
2371     extern unsigned short euc_to_utf8_1byte[];
2372     extern unsigned short * euc_to_utf8_2bytes[];
2373     unsigned short *p;
2374
2375     if (c2 == X0201) {
2376         p = euc_to_utf8_1byte;
2377     } else {
2378         c2 &= 0x7f;
2379         c2 = (c2&0x7f) - 0x21;
2380         if (0<=c2 && c2<sizeof_euc_to_utf8_2bytes)
2381             p = euc_to_utf8_2bytes[c2];
2382         else
2383             return 0;
2384     }
2385     if (!p) return 0;
2386     c1 = (c1 & 0x7f) - 0x21;
2387     if (0<=c1 && c1<sizeof_euc_to_utf8_1byte)
2388         return p[c1];
2389     return 0;
2390 }
2391
2392 void
2393 w_oconv(c2, c1)
2394     int    c2,
2395                     c1;
2396 {
2397     int c0;
2398 #ifdef NUMCHAR_OPTION
2399     if (c2 == 0 && (c1 & CLASS_MASK) == CLASS_UTF16){
2400         w16w_conv(c1, &c2, &c1, &c0);
2401         (*o_putc)(c2);
2402         if (c1){
2403             (*o_putc)(c1);
2404             if (c0) (*o_putc)(c0);
2405         }
2406     }
2407 #endif
2408     if (c2 == EOF) {
2409         (*o_putc)(EOF);
2410         return;
2411     } else if (c2 == 0) { 
2412         output_mode = ASCII;
2413         (*o_putc)(c1);
2414     } else if (c2 == ISO8859_1) {
2415         output_mode = ISO8859_1;
2416         (*o_putc)(c1 | 0x080);
2417     } else {
2418         output_mode = UTF8;
2419         w16w_conv((unsigned short)e2w_conv(c2, c1), &c2, &c1, &c0);
2420         (*o_putc)(c2);
2421         if (c1){
2422             (*o_putc)(c1);
2423             if (c0) (*o_putc)(c0);
2424         }
2425     }
2426 }
2427
2428 void
2429 w_oconv16(c2, c1)
2430     int    c2,
2431                     c1;
2432 {
2433     if (c2 == EOF) {
2434         (*o_putc)(EOF);
2435         return;
2436     }    
2437
2438     if (w_oconv16_begin_f==2) {
2439         if (w_oconv16_LE){
2440             (*o_putc)((unsigned char)'\377');
2441             (*o_putc)('\376');
2442         }else{
2443             (*o_putc)('\376');
2444             (*o_putc)((unsigned char)'\377');
2445         }
2446         w_oconv16_begin_f=1;
2447     }
2448
2449     if (c2 == ISO8859_1) {
2450         c2 = 0;
2451         c1 |= 0x80;
2452 #ifdef NUMCHAR_OPTION
2453     } else if (c2 == 0 && (c1 & CLASS_MASK) == CLASS_UTF16) {
2454         c2 = (c1 >> 8) & 0xff;
2455         c1 &= 0xff;
2456 #endif
2457     } else if (c2) {
2458         unsigned short val = (unsigned short)e2w_conv(c2, c1);
2459         c2 = (val >> 8) & 0xff;
2460         c1 = val & 0xff;
2461     }
2462     if (w_oconv16_LE){
2463         (*o_putc)(c1);
2464         (*o_putc)(c2);
2465     }else{
2466         (*o_putc)(c2);
2467         (*o_putc)(c1);
2468     }
2469 }
2470
2471 #endif
2472
2473 void
2474 e_oconv(c2, c1)
2475     int    c2,
2476                     c1;
2477 {
2478 #ifdef NUMCHAR_OPTION
2479     if (c2 == 0 && (c1 & CLASS_MASK) == CLASS_UTF16){
2480         w16e_conv(c1, &c2, &c1);
2481     }
2482 #endif
2483     if (c2 == EOF) {
2484         (*o_putc)(EOF);
2485         return;
2486     } else if (c2 == 0) { 
2487         output_mode = ASCII;
2488         (*o_putc)(c1);
2489     } else if (c2 == X0201) {
2490         output_mode = JAPANESE_EUC;
2491         (*o_putc)(SSO); (*o_putc)(c1|0x80);
2492     } else if (c2 == ISO8859_1) {
2493         output_mode = ISO8859_1;
2494         (*o_putc)(c1 | 0x080);
2495     } else {
2496         if ((c1<0x21 || 0x7e<c1) ||
2497            (c2<0x21 || 0x7e<c2)) {
2498             set_iconv(FALSE, 0);
2499             return; /* too late to rescue this char */
2500         }
2501         output_mode = JAPANESE_EUC;
2502         (*o_putc)(c2 | 0x080);
2503         (*o_putc)(c1 | 0x080);
2504     }
2505 }
2506
2507 void
2508 e2s_conv(c2, c1, p2, p1)
2509      int c2, c1, *p2, *p1;
2510 {
2511     if (p2) *p2 = ((c2 - 1) >> 1) + ((c2 <= 0x5e) ? 0x71 : 0xb1);
2512     if (p1) *p1 = c1 + ((c2 & 1) ? ((c1 < 0x60) ? 0x1f : 0x20) : 0x7e);
2513 }
2514
2515 void
2516 s_oconv(c2, c1)
2517     int    c2,
2518                     c1;
2519 {
2520 #ifdef NUMCHAR_OPTION
2521     if (c2 == 0 && (c1 & CLASS_MASK) == CLASS_UTF16){
2522         w16e_conv(c1, &c2, &c1);
2523     }
2524 #endif
2525     if (c2 == EOF) {
2526         (*o_putc)(EOF);
2527         return;
2528     } else if (c2 == 0) {
2529         output_mode = ASCII;
2530         (*o_putc)(c1);
2531     } else if (c2 == X0201) {
2532         output_mode = SHIFT_JIS;
2533         (*o_putc)(c1|0x80);
2534     } else if (c2 == ISO8859_1) {
2535         output_mode = ISO8859_1;
2536         (*o_putc)(c1 | 0x080);
2537     } else {
2538         if ((c1<0x20 || 0x7e<c1) ||
2539            (c2<0x20 || 0x7e<c2)) {
2540             set_iconv(FALSE, 0);
2541             return; /* too late to rescue this char */
2542         }
2543         output_mode = SHIFT_JIS;
2544         e2s_conv(c2, c1, &c2, &c1);
2545         (*o_putc)(c2);
2546         (*o_putc)(c1);
2547     }
2548 }
2549
2550 void
2551 j_oconv(c2, c1)
2552     int    c2,
2553                     c1;
2554 {
2555 #ifdef NUMCHAR_OPTION
2556     if ((c1 & CLASS_MASK) == CLASS_UTF16){
2557         w16e_conv(c1, &c2, &c1);
2558     }
2559 #endif
2560     if (c2 == EOF) {
2561         if (output_mode !=ASCII && output_mode!=ISO8859_1) {
2562             (*o_putc)(ESC);
2563             (*o_putc)('(');
2564             (*o_putc)(ascii_intro);
2565             output_mode = ASCII;
2566         }
2567         (*o_putc)(EOF);
2568     } else if (c2==X0201) {
2569         if (output_mode!=X0201) {
2570             output_mode = X0201;
2571             (*o_putc)(ESC);
2572             (*o_putc)('(');
2573             (*o_putc)('I');
2574         }
2575         (*o_putc)(c1);
2576     } else if (c2==ISO8859_1) {
2577             /* iso8859 introduction, or 8th bit on */
2578             /* Can we convert in 7bit form using ESC-'-'-A ? 
2579                Is this popular? */
2580         output_mode = ISO8859_1;
2581         (*o_putc)(c1|0x80);
2582     } else if (c2 == 0) {
2583         if (output_mode !=ASCII && output_mode!=ISO8859_1) {
2584             (*o_putc)(ESC);
2585             (*o_putc)('(');
2586             (*o_putc)(ascii_intro);
2587             output_mode = ASCII;
2588         }
2589         (*o_putc)(c1);
2590     } else {
2591         if (output_mode != X0208) {
2592             output_mode = X0208;
2593             (*o_putc)(ESC);
2594             (*o_putc)('$');
2595             (*o_putc)(kanji_intro);
2596         }
2597         if (c1<0x20 || 0x7e<c1) 
2598             return;
2599         if (c2<0x20 || 0x7e<c2) 
2600             return;
2601         (*o_putc)(c2);
2602         (*o_putc)(c1);
2603     }
2604 }
2605
2606 void
2607 base64_conv(c2, c1)
2608     int    c2,
2609                     c1;
2610 {
2611     if (base64_count>50 && !mimeout_mode && c2==0 && c1==SPACE) {
2612         (*o_putc)(NL);
2613     } else if (base64_count>66 && mimeout_mode) {
2614         (*o_base64conv)(EOF,0);
2615         (*o_putc)(NL);
2616         (*o_putc)('\t'); base64_count += 7;
2617     }
2618     (*o_base64conv)(c2,c1);
2619 }
2620
2621
2622 static int broken_buf[3];
2623 static int broken_counter = 0;
2624 static int broken_last = 0;
2625 int
2626 broken_getc(f)
2627 FILE *f;
2628 {
2629     int c,c1;
2630
2631     if (broken_counter>0) {
2632         return broken_buf[--broken_counter];
2633     }
2634     c= (*i_bgetc)(f);
2635     if (c=='$' && broken_last != ESC 
2636             && (input_mode==ASCII || input_mode==X0201)) {
2637         c1= (*i_bgetc)(f);
2638         broken_last = 0;
2639         if (c1=='@'|| c1=='B') {
2640             broken_buf[0]=c1; broken_buf[1]=c; 
2641             broken_counter=2;
2642             return ESC;
2643         } else {
2644             (*i_bungetc)(c1,f);
2645             return c;
2646         }
2647     } else if (c=='(' && broken_last != ESC 
2648             && (input_mode==X0208 || input_mode==X0201)) { /* ) */
2649         c1= (*i_bgetc)(f);
2650         broken_last = 0;
2651         if (c1=='J'|| c1=='B') {
2652             broken_buf[0]=c1; broken_buf[1]=c;
2653             broken_counter=2;
2654             return ESC;
2655         } else {
2656             (*i_bungetc)(c1,f);
2657             return c;
2658         }
2659     } else {
2660         broken_last = c;
2661         return c;
2662     }
2663 }
2664
2665 int
2666 broken_ungetc(c,f)
2667 int c;
2668 FILE *f;
2669 {
2670     if (broken_counter<2)
2671         broken_buf[broken_counter++]=c;
2672     return c;
2673 }
2674
2675 static int prev_cr = 0;
2676
2677 void
2678 cr_conv(c2,c1) 
2679 int c2,c1;
2680 {
2681     if (prev_cr) {
2682         prev_cr = 0;
2683         if (! (c2==0&&c1==NL) ) {
2684             cr_conv(0,'\n');
2685         }
2686     }
2687     if (c2) {
2688         (*o_crconv)(c2,c1);
2689     } else if (c1=='\r') {
2690         prev_cr = c1;
2691     } else if (c1=='\n') {
2692         if (crmode_f==CRLF) {
2693             (*o_crconv)(0,'\r');
2694         } else if (crmode_f==CR) {
2695             (*o_crconv)(0,'\r');
2696             return;
2697         } 
2698         (*o_crconv)(0,NL);
2699     } else if (c1!='\032' || crmode_f!=NL){
2700         (*o_crconv)(c2,c1);
2701     }
2702 }
2703
2704 /* 
2705   Return value of fold_conv()
2706
2707        \n  add newline  and output char
2708        \r  add newline  and output nothing
2709        ' ' space
2710        0   skip  
2711        1   (or else) normal output 
2712
2713   fold state in prev (previous character)
2714
2715       >0x80 Japanese (X0208/X0201)
2716       <0x80 ASCII
2717       \n    new line 
2718       ' '   space
2719
2720   This fold algorthm does not preserve heading space in a line.
2721   This is the main difference from fmt.
2722 */
2723
2724 #define char_size(c2,c1) (c2?2:1)
2725
2726 void
2727 fold_conv(c2,c1) 
2728 int c2,c1;
2729
2730     int prev0;
2731     int fold_state=0;
2732
2733     if (c1== '\r' && !fold_preserve_f) {
2734         fold_state=0;  /* ignore cr */
2735     }else if (c1== '\n'&&f_prev=='\r' && fold_preserve_f) {
2736         f_prev = '\n';
2737         fold_state=0;  /* ignore cr */
2738     } else if (c1== BS) {
2739         if (f_line>0) f_line--;
2740         fold_state =  1;
2741     } else if (c2==EOF && f_line != 0) {    /* close open last line */
2742             fold_state = '\n';
2743     } else if ((c1=='\n' && !fold_preserve_f)
2744                || ((c1=='\r'||(c1=='\n'&&f_prev!='\r'))
2745                    && fold_preserve_f)) {
2746         /* new line */
2747         if (fold_preserve_f) { 
2748             f_prev = c1;
2749             f_line = 0;
2750             fold_state =  '\r';
2751         } else if ((f_prev == c1 && !fold_preserve_f)
2752                    || (f_prev == '\n' && fold_preserve_f)
2753                    ) {        /* duplicate newline */
2754             if (f_line) {
2755                 f_line = 0;
2756                 fold_state =  '\n';    /* output two newline */
2757             } else {
2758                 f_line = 0;
2759                 fold_state =  1;
2760             }
2761         } else  {
2762             if (f_prev&0x80) {     /* Japanese? */
2763                 f_prev = c1;
2764                 fold_state =  0;       /* ignore given single newline */
2765             } else if (f_prev==' ') {
2766                 fold_state =  0;
2767             } else {
2768                 f_prev = c1;
2769                 if (++f_line<=fold_len) 
2770                     fold_state =  ' ';
2771                 else {
2772                     f_line = 0;
2773                     fold_state =  '\r';        /* fold and output nothing */
2774                 }
2775             }
2776         }
2777     } else if (c1=='\f') {
2778         f_prev = '\n';
2779         if (f_line==0)
2780             fold_state =  1;
2781         f_line = 0;
2782         fold_state =  '\n';            /* output newline and clear */
2783     } else if ( (c2==0  && c1==' ')||
2784                (c2==0  && c1=='\t')||
2785                (c2=='!'&& c1=='!')) {
2786         /* X0208 kankaku or ascii space */
2787             if (f_prev == ' ') {
2788                 fold_state = 0;         /* remove duplicate spaces */
2789             } else {
2790                 f_prev = ' ';    
2791                 if (++f_line<=fold_len) 
2792                     fold_state = ' ';         /* output ASCII space only */
2793                 else {
2794                     f_prev = ' '; f_line = 0;
2795                     fold_state = '\r';        /* fold and output nothing */
2796                 }
2797             }
2798     } else {
2799         prev0 = f_prev; /* we still need this one... , but almost done */
2800         f_prev = c1;
2801         if (c2 || c2==X0201) 
2802             f_prev |= 0x80;  /* this is Japanese */
2803         f_line += char_size(c2,c1);
2804         if (f_line<=fold_len) {   /* normal case */
2805             fold_state = 1;
2806         } else {
2807             if (f_line>=fold_len+fold_margin) { /* too many kinsou suspension */
2808                 f_line = char_size(c2,c1);
2809                 fold_state =  '\n';       /* We can't wait, do fold now */
2810             } else if (c2==X0201) {
2811             /* simple kinsoku rules  return 1 means no folding  */
2812                 if (c1==(0xde&0x7f)) fold_state = 1; /* \e$B!+\e(B*/
2813                 else if (c1==(0xdf&0x7f)) fold_state = 1; /* \e$B!,\e(B*/
2814                 else if (c1==(0xa4&0x7f)) fold_state = 1; /* \e$B!#\e(B*/
2815                 else if (c1==(0xa3&0x7f)) fold_state = 1; /* \e$B!$\e(B*/
2816                 else if (c1==(0xa1&0x7f)) fold_state = 1; /* \e$B!W\e(B*/
2817                 else if (c1==(0xb0&0x7f)) fold_state = 1; /* - */
2818                 else if (SPACE<=c1 && c1<=(0xdf&0x7f)) {      /* X0201 */
2819                     f_line = 1;
2820                     fold_state = '\n';/* add one new f_line before this character */
2821                 } else {
2822                     f_line = 1;
2823                     fold_state = '\n';/* add one new f_line before this character */
2824                 }
2825             } else if (c2==0) {
2826                 /* kinsoku point in ASCII */ 
2827                 if (  c1==')'||    /* { [ ( */
2828                      c1==']'||
2829                      c1=='}'||
2830                      c1=='.'||
2831                      c1==','||
2832                      c1=='!'||
2833                      c1=='?'||
2834                      c1=='/'||
2835                      c1==':'||
2836                      c1==';' ) {
2837                     fold_state = 1;
2838                 /* just after special */
2839                 } else if (!is_alnum(prev0)) {
2840                     f_line = char_size(c2,c1);
2841                     fold_state = '\n';
2842                 } else if ((prev0==' ') ||   /* ignored new f_line */
2843                       (prev0=='\n')||        /* ignored new f_line */
2844                       (prev0&0x80)) {        /* X0208 - ASCII */
2845                     f_line = char_size(c2,c1);
2846                     fold_state = '\n';/* add one new f_line before this character */
2847                 } else {
2848                     fold_state = 1;  /* default no fold in ASCII */
2849                 }
2850             } else {
2851                 if (c2=='!') {
2852                     if (c1=='"')  fold_state = 1; /* \e$B!"\e(B */
2853                     else if (c1=='#')  fold_state = 1; /* \e$B!#\e(B */
2854                     else if (c1=='W')  fold_state = 1; /* \e$B!W\e(B */
2855                     else if (c1=='K')  fold_state = 1; /* \e$B!K\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                     else if (c1=='+')  fold_state = 1; /* \e$B!+\e(B */
2863                     else if (c1==',')  fold_state = 1; /* \e$B!,\e(B */
2864                          /* default no fold in kinsoku */
2865                     else { 
2866                         fold_state = '\n';
2867                         f_line = char_size(c2,c1);
2868                         /* add one new f_line before this character */
2869                     }
2870                 } else {
2871                     f_line = char_size(c2,c1);
2872                     fold_state = '\n'; 
2873                     /* add one new f_line before this character */
2874                 }
2875             }
2876         }
2877     }
2878     /* terminator process */
2879     switch(fold_state) {
2880         case '\n': 
2881             (*o_fconv)(0,'\n');
2882             (*o_fconv)(c2,c1);
2883             break;
2884         case 0:    
2885             return;
2886         case '\r': 
2887             (*o_fconv)(0,'\n');
2888             break;
2889         case '\t': 
2890         case ' ': 
2891             (*o_fconv)(0,' ');
2892             break;
2893         default:
2894             (*o_fconv)(c2,c1);
2895     }
2896 }
2897
2898 int z_prev2=0,z_prev1=0;
2899
2900 void
2901 z_conv(c2,c1)
2902 int c2,c1;
2903 {
2904
2905     /* if (c2) c1 &= 0x7f; assertion */
2906
2907     if (x0201_f && z_prev2==X0201) {  /* X0201 */
2908         if (c1==(0xde&0x7f)) { /* \e$BByE@\e(B */
2909             z_prev2=0;
2910             (*o_zconv)(dv[(z_prev1-SPACE)*2],dv[(z_prev1-SPACE)*2+1]);
2911             return;
2912         } else if (c1==(0xdf&0x7f)&&ev[(z_prev1-SPACE)*2]) {  /* \e$BH>ByE@\e(B */
2913             z_prev2=0;
2914             (*o_zconv)(ev[(z_prev1-SPACE)*2],ev[(z_prev1-SPACE)*2+1]);
2915             return;
2916         } else {
2917             z_prev2=0;
2918             (*o_zconv)(cv[(z_prev1-SPACE)*2],cv[(z_prev1-SPACE)*2+1]);
2919         }
2920     }
2921
2922     if (c2==EOF) {
2923         (*o_zconv)(c2,c1);
2924         return;
2925     }
2926
2927     if (x0201_f && c2==X0201) {
2928         if (dv[(c1-SPACE)*2]||ev[(c1-SPACE)*2]) {
2929             /* wait for \e$BByE@\e(B or \e$BH>ByE@\e(B */
2930             z_prev1 = c1; z_prev2 = c2;
2931             return;
2932         } else {
2933             (*o_zconv)(cv[(c1-SPACE)*2],cv[(c1-SPACE)*2+1]);
2934             return;
2935         }
2936     }
2937
2938     /* JISX0208 Alphabet */
2939     if (alpha_f && c2 == 0x23 ) {
2940         c2 = 0;
2941     } else if (alpha_f && c2 == 0x21 ) { 
2942     /* JISX0208 Kigou */
2943        if (0x21==c1) {
2944            if (alpha_f&0x2) {
2945                c1 = ' ';
2946                c2 = 0;
2947            } else if (alpha_f&0x4) {
2948                 (*o_zconv)(0,' ');
2949                 (*o_zconv)(0,' ');
2950                 return;
2951            } 
2952        } else if (0x20<c1 && c1<0x7f && fv[c1-0x20]) {
2953            c1 = fv[c1-0x20];
2954            c2 =  0;
2955            if (alpha_f&0x8) {
2956                char *entity = 0;
2957                switch (c1){
2958                  case '>': entity = "&gt;"; break;
2959                  case '<': entity = "&lt;"; break;
2960                  case '\"': entity = "&quot;"; break;
2961                  case '&': entity = "&amp;"; break;
2962                }
2963                if (entity){
2964                    while (*entity) (*o_zconv)(0, *entity++);
2965                    return;
2966                }
2967            }
2968        } 
2969     }
2970     (*o_zconv)(c2,c1);
2971 }
2972
2973
2974 #define rot13(c)  ( \
2975       ( c < 'A' ) ? c: \
2976       (c <= 'M')  ? (c + 13): \
2977       (c <= 'Z')  ? (c - 13): \
2978       (c < 'a')   ? (c): \
2979       (c <= 'm')  ? (c + 13): \
2980       (c <= 'z')  ? (c - 13): \
2981       (c) \
2982 )
2983
2984 #define  rot47(c) ( \
2985       ( c < '!' ) ? c: \
2986       ( c <= 'O' ) ? (c + 47) : \
2987       ( c <= '~' ) ?  (c - 47) : \
2988       c \
2989 )
2990
2991 void
2992 rot_conv(c2,c1)
2993 int c2,c1;
2994 {
2995     if (c2==0 || c2==X0201 || c2==ISO8859_1) {
2996         c1 = rot13(c1);
2997     } else if (c2) {
2998         c1 = rot47(c1);
2999         c2 = rot47(c2);
3000     }
3001     (*o_rot_conv)(c2,c1);
3002 }
3003
3004 void
3005 hira_conv(c2,c1)
3006 int c2,c1;
3007 {
3008     if ((hira_f & 1) && c2==0x25 && 0x20<c1 && c1<0x74) {
3009         c2 = 0x24;
3010     } else if ((hira_f & 2) && c2==0x24 && 0x20<c1 && c1<0x74) {
3011         c2 = 0x25;
3012     } 
3013     (*o_hira_conv)(c2,c1);
3014 }
3015
3016
3017 void
3018 iso2022jp_check_conv(c2,c1)
3019 int    c2, c1;
3020 {
3021     static int range[RANGE_NUM_MAX][2] = {
3022         {0x222f, 0x2239,},
3023         {0x2242, 0x2249,},
3024         {0x2251, 0x225b,},
3025         {0x226b, 0x2271,},
3026         {0x227a, 0x227d,},
3027         {0x2321, 0x232f,},
3028         {0x233a, 0x2340,},
3029         {0x235b, 0x2360,},
3030         {0x237b, 0x237e,},
3031         {0x2474, 0x247e,},
3032         {0x2577, 0x257e,},
3033         {0x2639, 0x2640,},
3034         {0x2659, 0x267e,},
3035         {0x2742, 0x2750,},
3036         {0x2772, 0x277e,},
3037         {0x2841, 0x287e,},
3038         {0x4f54, 0x4f7e,},
3039         {0x7425, 0x747e},
3040     };
3041     int i;
3042     int start, end, c;
3043
3044     if(c2 >= 0x00 && c2 <= 0x20 && c1 >= 0x7f && c1 <= 0xff) {
3045         c2 = GETA1;
3046         c1 = GETA2;
3047     }
3048     if((c2 >= 0x29 && c2 <= 0x2f) || (c2 >= 0x75 && c2 <= 0x7e)) {
3049         c2 = GETA1;
3050         c1 = GETA2;
3051     }
3052
3053     for (i = 0; i < RANGE_NUM_MAX; i++) {
3054         start = range[i][0];
3055         end   = range[i][1];
3056         c     = (c2 << 8) + c1;
3057         if (c >= start && c <= end) {
3058             c2 = GETA1;
3059             c1 = GETA2;
3060         }
3061     }
3062     (*o_iso2022jp_check_conv)(c2,c1);
3063 }
3064
3065
3066 /* This converts  =?ISO-2022-JP?B?HOGE HOGE?= */
3067
3068 unsigned char *mime_pattern[] = {
3069    (unsigned char *)"\075?EUC-JP?B?",
3070    (unsigned char *)"\075?SHIFT_JIS?B?",
3071    (unsigned char *)"\075?ISO-8859-1?Q?",
3072    (unsigned char *)"\075?ISO-8859-1?B?",
3073    (unsigned char *)"\075?ISO-2022-JP?B?",
3074    (unsigned char *)"\075?ISO-2022-JP?Q?",
3075 #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
3076    (unsigned char *)"\075?UTF-8?B?",
3077 #endif
3078    (unsigned char *)"\075?US-ASCII?Q?",
3079    NULL
3080 };
3081
3082
3083 /* \e$B3:Ev$9$k%3!<%I$NM%@hEY$r>e$2$k$?$a$NL\0u\e(B */
3084 int (*mime_priority_func[])PROTO((int c2, int c1, int c0)) = {
3085     e_iconv, s_iconv, 0, 0, 0, 0,
3086 #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
3087     w_iconv,
3088 #endif
3089     0,
3090 };
3091
3092 int      mime_encode[] = {
3093     JAPANESE_EUC, SHIFT_JIS,ISO8859_1, ISO8859_1, X0208, X0201,
3094 #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
3095     UTF8,
3096 #endif
3097     ASCII,
3098     0
3099 };
3100
3101 int      mime_encode_method[] = {
3102     'B', 'B','Q', 'B', 'B', 'Q',
3103 #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
3104     'B',
3105 #endif
3106     'Q',
3107     0
3108 };
3109
3110
3111 #define MAXRECOVER 20
3112
3113 /* I don't trust portablity of toupper */
3114 #define nkf_toupper(c)  (('a'<=c && c<='z')?(c-('a'-'A')):c)
3115 #define nkf_isdigit(c)  ('0'<=c && c<='9')
3116 #define nkf_isxdigit(c)  (nkf_isdigit(c) || ('a'<=c && c<='f') || ('A'<=c && c <= 'F'))
3117
3118 void
3119 switch_mime_getc()
3120 {
3121     if (i_getc!=mime_getc) {
3122         i_mgetc = i_getc; i_getc = mime_getc;
3123         i_mungetc = i_ungetc; i_ungetc = mime_ungetc;
3124         if(mime_f==STRICT_MIME) {
3125             i_mgetc_buf = i_mgetc; i_mgetc = mime_getc_buf;
3126             i_mungetc_buf = i_mungetc; i_mungetc = mime_ungetc_buf;
3127         }
3128     }
3129 }
3130
3131 void
3132 unswitch_mime_getc()
3133 {
3134     if(mime_f==STRICT_MIME) {
3135         i_mgetc = i_mgetc_buf;
3136         i_mungetc = i_mungetc_buf;
3137     }
3138     i_getc = i_mgetc;
3139     i_ungetc = i_mungetc;
3140 }
3141
3142 int
3143 mime_begin_strict(f)
3144 FILE *f;
3145 {
3146     int c1 = 0;
3147     int i,j,k;
3148     unsigned char *p,*q;
3149     int r[MAXRECOVER];    /* recovery buffer, max mime pattern lenght */
3150
3151     mime_decode_mode = FALSE;
3152     /* =? has been checked */
3153     j = 0;
3154     p = mime_pattern[j];
3155     r[0]='='; r[1]='?';
3156
3157     for(i=2;p[i]>' ';i++) {                   /* start at =? */
3158         if ( ((r[i] = c1 = (*i_getc)(f))==EOF) || nkf_toupper(c1) != p[i] ) {
3159             /* pattern fails, try next one */
3160             q = p;
3161             while ((p = mime_pattern[++j])) {
3162                 for(k=2;k<i;k++)              /* assume length(p) > i */
3163                     if (p[k]!=q[k]) break;
3164                 if (k==i && nkf_toupper(c1)==p[k]) break;
3165             }
3166             if (p) continue;  /* found next one, continue */
3167             /* all fails, output from recovery buffer */
3168             (*i_ungetc)(c1,f);
3169             for(j=0;j<i;j++) {
3170                 (*oconv)(0,r[j]);
3171             }
3172             return c1;
3173         }
3174     }
3175     mime_decode_mode = p[i-2];
3176
3177     clr_code_score(find_inputcode_byfunc(mime_priority_func[j]), SCORE_iMIME);
3178
3179     if (mime_decode_mode=='B') {
3180         mimebuf_f = unbuf_f;
3181         if (!unbuf_f) {
3182             /* do MIME integrity check */
3183             return mime_integrity(f,mime_pattern[j]);
3184         } 
3185     }
3186     switch_mime_getc();
3187     mimebuf_f = TRUE;
3188     return c1;
3189 }
3190
3191 int
3192 mime_getc_buf(f) 
3193 FILE *f;
3194 {
3195     /* we don't keep eof of Fifo, becase it contains ?= as
3196        a terminator. It was checked in mime_integrity. */
3197     return ((mimebuf_f)?
3198         (*i_mgetc_buf)(f):Fifo(mime_input++));
3199 }
3200
3201 int
3202 mime_ungetc_buf(c,f) 
3203 FILE *f;
3204 int c;
3205 {
3206     if (mimebuf_f)
3207         (*i_mungetc_buf)(c,f);
3208     else 
3209         Fifo(--mime_input)=c;
3210     return c;
3211 }
3212
3213 int
3214 mime_begin(f)
3215 FILE *f;
3216 {
3217     int c1;
3218     int i,k;
3219
3220     /* In NONSTRICT mode, only =? is checked. In case of failure, we  */
3221     /* re-read and convert again from mime_buffer.  */
3222
3223     /* =? has been checked */
3224     k = mime_last;
3225     Fifo(mime_last++)='='; Fifo(mime_last++)='?';
3226     for(i=2;i<MAXRECOVER;i++) {                   /* start at =? */
3227         /* We accept any character type even if it is breaked by new lines */
3228         c1 = (*i_getc)(f); Fifo(mime_last++)= c1 ;
3229         if (c1=='\n'||c1==' '||c1=='\r'||
3230                 c1=='-'||c1=='_'||is_alnum(c1) ) continue;
3231         if (c1=='=') {
3232             /* Failed. But this could be another MIME preemble */
3233             (*i_ungetc)(c1,f);
3234             mime_last--;
3235             break;
3236         }
3237         if (c1!='?') break;
3238         else {
3239             /* c1=='?' */
3240             c1 = (*i_getc)(f); Fifo(mime_last++) = c1;
3241             if (!(++i<MAXRECOVER) || c1==EOF) break;
3242             if (c1=='b'||c1=='B') {
3243                 mime_decode_mode = 'B';
3244             } else if (c1=='q'||c1=='Q') {
3245                 mime_decode_mode = 'Q';
3246             } else {
3247                 break;
3248             }
3249             c1 = (*i_getc)(f); Fifo(mime_last++) = c1;
3250             if (!(++i<MAXRECOVER) || c1==EOF) break;
3251             if (c1!='?') {
3252                 mime_decode_mode = FALSE;
3253             }
3254             break;
3255         }
3256     }
3257     switch_mime_getc();
3258     if (!mime_decode_mode) {
3259         /* false MIME premble, restart from mime_buffer */
3260         mime_decode_mode = 1;  /* no decode, but read from the mime_buffer */
3261         /* Since we are in MIME mode until buffer becomes empty,    */
3262         /* we never go into mime_begin again for a while.           */
3263         return c1;
3264     }
3265     /* discard mime preemble, and goto MIME mode */
3266     mime_last = k;
3267     /* do no MIME integrity check */
3268     return c1;   /* used only for checking EOF */
3269 }
3270
3271 #ifdef CHECK_OPTION
3272 void
3273 no_putc(c)
3274      int c;
3275 {
3276     ;
3277 }
3278
3279 void debug(str)
3280      char *str;
3281 {
3282     if (debug_f){
3283         fprintf(stderr, "%s\n", str);
3284     }
3285 }
3286 #endif
3287
3288 int
3289 hex2bin(x)
3290      int x;
3291 {
3292     if (nkf_isdigit(x)) return x - '0';
3293     return nkf_toupper(x) - 'A' + 10;
3294 }
3295
3296 #ifdef INPUT_OPTION 
3297
3298 #ifdef ANSI_C_PROTOTYPE
3299 int hex_getc(int ch, FILE *f, int (*g)(FILE *f), int (*u)(int c, FILE *f))
3300 #else
3301 int
3302 hex_getc(ch, f, g, u)
3303      int ch;
3304      FILE *f;
3305      int (*g)();
3306      int (*u)();
3307 #endif
3308 {
3309     int c1, c2, c3;
3310     c1 = (*g)(f);
3311     if (c1 != ch){
3312         return c1;
3313     }
3314     c2 = (*g)(f);
3315     if (!nkf_isxdigit(c2)){
3316         (*u)(c2, f);
3317         return c1;
3318     }
3319     c3 = (*g)(f);
3320     if (!nkf_isxdigit(c3)){
3321         (*u)(c2, f);
3322         (*u)(c3, f);
3323         return c1;
3324     }
3325     return (hex2bin(c2) << 4) | hex2bin(c3);
3326 }
3327
3328 int
3329 cap_getc(f)
3330      FILE *f;
3331 {
3332     return hex_getc(':', f, i_cgetc, i_cungetc);
3333 }
3334
3335 int
3336 cap_ungetc(c, f)
3337      int c;
3338      FILE *f;
3339 {
3340     return (*i_cungetc)(c, f);
3341 }
3342
3343 int
3344 url_getc(f)
3345      FILE *f;
3346 {
3347     return hex_getc('%', f, i_ugetc, i_uungetc);
3348 }
3349
3350 int
3351 url_ungetc(c, f)
3352      int c;
3353      FILE *f;
3354 {
3355     return (*i_uungetc)(c, f);
3356 }
3357 #endif
3358
3359 #ifdef NUMCHAR_OPTION
3360 int
3361 numchar_getc(f)
3362      FILE *f;
3363 {
3364     int (*g)() = i_ngetc;
3365     int (*u)() = i_nungetc;
3366     int i = 0, j;
3367     int buf[8];
3368     long c = -1;
3369
3370     buf[i] = (*g)(f);
3371     if (buf[i] == '&'){
3372         buf[++i] = (*g)(f);
3373         if (buf[i] == '#'){
3374             c = 0;
3375             buf[++i] = (*g)(f);
3376             if (buf[i] == 'x' || buf[i] == 'X'){
3377                 for (j = 0; j < 5; j++){
3378                     buf[++i] = (*g)(f);
3379                     if (!nkf_isxdigit(buf[i])){
3380                         if (buf[i] != ';'){
3381                             c = -1;
3382                         }
3383                         break;
3384                     }
3385                     c <<= 4;
3386                     c |= hex2bin(buf[i]);
3387                 }
3388             }else{
3389                 for (j = 0; j < 6; j++){
3390                     if (j){
3391                         buf[++i] = (*g)(f);
3392                     }
3393                     if (!nkf_isdigit(buf[i])){
3394                         if (buf[i] != ';'){
3395                             c = -1;
3396                         }
3397                         break;
3398                     }
3399                     c *= 10;
3400                     c += hex2bin(buf[i]);
3401                 }
3402             }
3403         }
3404     }
3405     if (c != -1){
3406         return CLASS_UTF16 | c;
3407     }
3408     while (i > 0){
3409         (*u)(buf[i], f);
3410         --i;
3411     }
3412     return buf[0];
3413 }
3414
3415 int
3416 numchar_ungetc(c, f)
3417      int c;
3418      FILE *f;
3419 {
3420     return (*i_nungetc)(c, f);
3421 }
3422 #endif
3423
3424
3425 int 
3426 mime_getc(f)
3427 FILE *f;
3428 {
3429     int c1, c2, c3, c4, cc;
3430     int t1, t2, t3, t4, mode, exit_mode;
3431
3432     if (mime_top != mime_last) {  /* Something is in FIFO */
3433         return  Fifo(mime_top++);
3434     }
3435     if (mime_decode_mode==1 ||mime_decode_mode==FALSE) {
3436         mime_decode_mode=FALSE;
3437         unswitch_mime_getc();
3438         return (*i_getc)(f);
3439     }
3440
3441     if (mimebuf_f == FIXED_MIME)
3442         exit_mode = mime_decode_mode;
3443     else
3444         exit_mode = FALSE;
3445     if (mime_decode_mode == 'Q') {
3446         if ((c1 = (*i_mgetc)(f)) == EOF) return (EOF);
3447 restart_mime_q:
3448         if (c1=='_') return ' ';
3449         if (c1!='=' && c1!='?') {
3450             return c1;
3451         }
3452                 
3453         mime_decode_mode = exit_mode; /* prepare for quit */
3454         if (c1<=' ') return c1;
3455         if ((c2 = (*i_mgetc)(f)) == EOF) return (EOF);
3456         if (c1=='?'&&c2=='=' && mimebuf_f != FIXED_MIME) {
3457             /* end Q encoding */
3458             input_mode = exit_mode;
3459             while((c1=(*i_getc)(f))!=EOF && c1==SPACE 
3460                         /* && (c1==NL||c1==TAB||c1=='\r') */ ) ;
3461             return c1;
3462         }
3463         if (c1=='='&&c2<' ') { /* this is soft wrap */
3464             while((c1 =  (*i_mgetc)(f)) <=' ') {
3465                 if ((c1 = (*i_mgetc)(f)) == EOF) return (EOF);
3466             }
3467             mime_decode_mode = 'Q'; /* still in MIME */
3468             goto restart_mime_q;
3469         }
3470         if (c1=='?') {
3471             mime_decode_mode = 'Q'; /* still in MIME */
3472             (*i_mungetc)(c2,f);
3473             return c1;
3474         }
3475         if ((c3 = (*i_mgetc)(f)) == EOF) return (EOF);
3476         if (c2<=' ') return c2;
3477         mime_decode_mode = 'Q'; /* still in MIME */
3478 #define hex(c)   (('0'<=c&&c<='9')?(c-'0'):\
3479      ('A'<=c&&c<='F')?(c-'A'+10):('a'<=c&&c<='f')?(c-'a'+10):0)
3480         return ((hex(c2)<<4) + hex(c3));
3481     }
3482
3483     if (mime_decode_mode != 'B') {
3484         mime_decode_mode = FALSE;
3485         return (*i_mgetc)(f);
3486     }
3487
3488
3489     /* Base64 encoding */
3490     /* 
3491         MIME allows line break in the middle of 
3492         Base64, but we are very pessimistic in decoding
3493         in unbuf mode because MIME encoded code may broken by 
3494         less or editor's control sequence (such as ESC-[-K in unbuffered
3495         mode. ignore incomplete MIME.
3496     */
3497     mode = mime_decode_mode;
3498     mime_decode_mode = exit_mode;  /* prepare for quit */
3499
3500     while ((c1 = (*i_mgetc)(f))<=' ') {
3501         if (c1==EOF)
3502             return (EOF);
3503     }
3504 mime_c2_retry:
3505     if ((c2 = (*i_mgetc)(f))<=' ') {
3506         if (c2==EOF)
3507             return (EOF);
3508         if (mime_f != STRICT_MIME) goto mime_c2_retry;
3509         if (mimebuf_f!=FIXED_MIME) input_mode = ASCII;  
3510         return c2;
3511     }
3512     if ((c1 == '?') && (c2 == '=')) {
3513         input_mode = ASCII;
3514         while((c1=(*i_getc)(f))!=EOF && c1==SPACE 
3515                     /* && (c1==NL||c1==TAB||c1=='\r') */ ) ;
3516         return c1;
3517     }
3518 mime_c3_retry:
3519     if ((c3 = (*i_mgetc)(f))<=' ') {
3520         if (c3==EOF)
3521             return (EOF);
3522         if (mime_f != STRICT_MIME) goto mime_c3_retry;
3523         if (mimebuf_f!=FIXED_MIME) input_mode = ASCII;  
3524         return c3;
3525     }
3526 mime_c4_retry:
3527     if ((c4 = (*i_mgetc)(f))<=' ') {
3528         if (c4==EOF)
3529             return (EOF);
3530         if (mime_f != STRICT_MIME) goto mime_c4_retry;
3531         if (mimebuf_f!=FIXED_MIME) input_mode = ASCII;  
3532         return c4;
3533     }
3534
3535     mime_decode_mode = mode; /* still in MIME sigh... */
3536
3537     /* BASE 64 decoding */
3538
3539     t1 = 0x3f & base64decode(c1);
3540     t2 = 0x3f & base64decode(c2);
3541     t3 = 0x3f & base64decode(c3);
3542     t4 = 0x3f & base64decode(c4);
3543     cc = ((t1 << 2) & 0x0fc) | ((t2 >> 4) & 0x03);
3544     if (c2 != '=') {
3545         Fifo(mime_last++) = cc;
3546         cc = ((t2 << 4) & 0x0f0) | ((t3 >> 2) & 0x0f);
3547         if (c3 != '=') {
3548             Fifo(mime_last++) = cc;
3549             cc = ((t3 << 6) & 0x0c0) | (t4 & 0x3f);
3550             if (c4 != '=') 
3551                 Fifo(mime_last++) = cc;
3552         }
3553     } else {
3554         return c1;
3555     }
3556     return  Fifo(mime_top++);
3557 }
3558
3559 int
3560 mime_ungetc(c,f) 
3561 int   c;
3562 FILE  *f;
3563 {
3564     Fifo(--mime_top) = c;
3565     return c;
3566 }
3567
3568 int
3569 mime_integrity(f,p)
3570 FILE *f;
3571 unsigned char *p;
3572 {
3573     int c,d;
3574     unsigned int q;
3575     /* In buffered mode, read until =? or NL or buffer full
3576      */
3577     mime_input = mime_top;
3578     mime_last = mime_top;
3579     while(*p) Fifo(mime_input++) = *p++;
3580     d = 0;
3581     q = mime_input;
3582     while((c=(*i_getc)(f))!=EOF) {
3583         if (((mime_input-mime_top)&MIME_BUF_MASK)==0) {
3584             break;   /* buffer full */
3585         }
3586         if (c=='=' && d=='?') {
3587             /* checked. skip header, start decode */
3588             Fifo(mime_input++) = c;
3589             /* mime_last_input = mime_input; */
3590             mime_input = q; 
3591             switch_mime_getc();
3592             return 1;
3593         }
3594         if (!( (c=='+'||c=='/'|| c=='=' || c=='?' || is_alnum(c))))
3595             break;
3596         /* Should we check length mod 4? */
3597         Fifo(mime_input++) = c;
3598         d=c;
3599     }
3600     /* In case of Incomplete MIME, no MIME decode  */
3601     Fifo(mime_input++) = c;
3602     mime_last = mime_input;     /* point undecoded buffer */
3603     mime_decode_mode = 1;              /* no decode on Fifo last in mime_getc */
3604     switch_mime_getc();         /* anyway we need buffered getc */
3605     return 1;
3606 }
3607
3608 int
3609 base64decode(c)
3610     int            c;
3611 {
3612     int             i;
3613     if (c > '@') {
3614         if (c < '[') {
3615             i = c - 'A';                        /* A..Z 0-25 */
3616         } else {
3617             i = c - 'G'     /* - 'a' + 26 */ ;  /* a..z 26-51 */
3618         }
3619     } else if (c > '/') {
3620         i = c - '0' + '4'   /* - '0' + 52 */ ;  /* 0..9 52-61 */
3621     } else if (c == '+') {
3622         i = '>'             /* 62 */ ;          /* +  62 */
3623     } else {
3624         i = '?'             /* 63 */ ;          /* / 63 */
3625     }
3626     return (i);
3627 }
3628
3629 static char basis_64[] =
3630    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
3631
3632 static int b64c;
3633
3634 void
3635 open_mime(mode)
3636 int mode;
3637 {
3638     unsigned char *p;
3639     int i;
3640     p  = mime_pattern[0];
3641     for(i=0;mime_encode[i];i++) {
3642         if (mode == mime_encode[i]) {
3643             p = mime_pattern[i];
3644                 break;
3645         }
3646     }
3647     mimeout_mode = mime_encode_method[i];
3648             
3649     /* (*o_mputc)(' '); */
3650     while(*p) {
3651         (*o_mputc)(*p++);
3652         base64_count ++;
3653     }
3654 }
3655
3656 void
3657 close_mime()
3658 {
3659     (*o_mputc)('?');
3660     (*o_mputc)('=');
3661     (*o_mputc)(' ');
3662     base64_count += 3;
3663     mimeout_mode = 0;
3664 }
3665
3666 #define itoh4(c)   (c>=10?c+'A'-10:c+'0')
3667
3668 void
3669 mime_putc(c)
3670     int            c;
3671 {
3672     if (mimeout_f==FIXED_MIME) {
3673         if (base64_count>71) {
3674             (*o_mputc)('\n');
3675             base64_count=0;
3676         }
3677     } else if (c==NL) {
3678         base64_count=0;
3679     } 
3680     if (c!=EOF) {
3681         if ( c<=DEL &&(output_mode==ASCII ||output_mode == ISO8859_1 )
3682                 && mimeout_f!=FIXED_MIME) {
3683             if (mimeout_mode=='Q') {
3684                 if (c<=SPACE) {
3685                     close_mime();
3686                 }
3687                 (*o_mputc)(c);
3688                 return;
3689             }
3690             if (mimeout_mode!='B' || c!=SPACE) {
3691                 if (mimeout_mode) {
3692                     mime_putc(EOF);
3693                     mimeout_mode=0;
3694                 }
3695                 (*o_mputc)(c);
3696                 base64_count ++;
3697                 return;
3698             }
3699         } else if (!mimeout_mode && mimeout_f!=FIXED_MIME) {
3700             open_mime(output_mode);
3701         }
3702     } else { /* c==EOF */
3703         switch(mimeout_mode) {
3704         case 'Q':
3705         case 'B':
3706             break;
3707         case 2:
3708             (*o_mputc)(basis_64[((b64c & 0x3)<< 4)]);
3709             (*o_mputc)('=');
3710             (*o_mputc)('=');
3711             base64_count += 3;
3712             break;
3713         case 1:
3714             (*o_mputc)(basis_64[((b64c & 0xF) << 2)]);
3715             (*o_mputc)('=');
3716             base64_count += 2;
3717             break;
3718         }
3719         if (mimeout_mode) {
3720             if (mimeout_f!=FIXED_MIME) {
3721                 close_mime(); 
3722             } else if (mimeout_mode != 'Q')
3723                 mimeout_mode = 'B';
3724         }
3725         return;
3726     }
3727     switch(mimeout_mode) {
3728     case 'Q':
3729         if(c>=DEL) {
3730             (*o_mputc)('=');
3731             (*o_mputc)(itoh4(((c>>4)&0xf)));
3732             (*o_mputc)(itoh4((c&0xf)));
3733         } else {
3734             (*o_mputc)(c);
3735         }
3736         break;
3737     case 'B':
3738         b64c=c;
3739         (*o_mputc)(basis_64[c>>2]);
3740         mimeout_mode=2;
3741         base64_count ++;
3742         break;
3743     case 2:
3744         (*o_mputc)(basis_64[((b64c & 0x3)<< 4) | ((c & 0xF0) >> 4)]);
3745         b64c=c;
3746         mimeout_mode=1;
3747         base64_count ++;
3748         break;
3749     case 1:
3750         (*o_mputc)(basis_64[((b64c & 0xF) << 2) | ((c & 0xC0) >>6)]);
3751         (*o_mputc)(basis_64[c & 0x3F]);
3752         mimeout_mode='B';
3753         base64_count += 2;
3754         break;
3755     }
3756 }
3757
3758
3759 #ifdef PERL_XS
3760 void 
3761 reinit()
3762 {
3763     unbuf_f = FALSE;
3764     estab_f = FALSE;
3765     nop_f = FALSE;
3766     binmode_f = TRUE;       
3767     rot_f = FALSE;         
3768     hira_f = FALSE;         
3769     input_f = FALSE;      
3770     alpha_f = FALSE;     
3771     mime_f = STRICT_MIME; 
3772     mimebuf_f = FALSE; 
3773     broken_f = FALSE;  
3774     iso8859_f = FALSE; 
3775 #if defined(MSDOS) || defined(__OS2__) 
3776      x0201_f = TRUE;   
3777 #else
3778      x0201_f = NO_X0201;
3779 #endif
3780     iso2022jp_f = FALSE;
3781
3782     kanji_intro = DEFAULT_J;
3783     ascii_intro = DEFAULT_R;
3784
3785     output_conv = DEFAULT_CONV; 
3786     oconv = DEFAULT_CONV; 
3787
3788     i_mgetc  = std_getc; 
3789     i_mungetc  = std_ungetc;
3790     i_mgetc_buf = std_getc; 
3791     i_mungetc_buf = std_ungetc;
3792
3793     i_getc= std_getc; 
3794     i_ungetc=std_ungetc;
3795
3796     i_bgetc= std_getc;
3797     i_bungetc= std_ungetc;
3798
3799     o_putc = std_putc;
3800     o_mputc = std_putc;
3801     o_crconv = no_connection; 
3802     o_rot_conv = no_connection; 
3803     o_iso2022jp_check_conv = no_connection;
3804     o_hira_conv = no_connection; 
3805     o_fconv = no_connection; 
3806     o_zconv = no_connection;
3807
3808     i_getc = std_getc;
3809     i_ungetc = std_ungetc;
3810     i_mgetc = std_getc; 
3811     i_mungetc = std_ungetc; 
3812
3813     output_mode = ASCII;
3814     input_mode =  ASCII;
3815     shift_mode =  FALSE;
3816     mime_decode_mode =   FALSE;
3817     file_out = FALSE;
3818     mimeout_mode = 0;
3819     mimeout_f = FALSE;
3820     base64_count = 0;
3821     option_mode = 0;
3822     crmode_f = 0;
3823
3824     {
3825         struct input_code *p = input_code_list;
3826         while (p->name){
3827             status_reinit(p++);
3828         }
3829     }
3830 #ifdef UTF8_OUTPUT_ENABLE
3831     if (w_oconv16_begin_f) {
3832         w_oconv16_begin_f = 2;
3833     }
3834 #endif
3835     f_line = 0;    
3836     f_prev = 0;
3837     fold_preserve_f = FALSE; 
3838     fold_f  = FALSE;
3839     fold_len  = 0;
3840     fold_margin  = FOLD_MARGIN;
3841     broken_counter = 0;
3842     broken_last = 0;
3843     z_prev2=0,z_prev1=0;
3844
3845     input_codename = "";
3846 }
3847 #endif
3848
3849 void 
3850 no_connection(c2,c1) 
3851 int c2,c1;
3852 {
3853     no_connection2(c2,c1,0);
3854 }
3855
3856 int
3857 no_connection2(c2,c1,c0) 
3858 int c2,c1,c0;
3859 {
3860     fprintf(stderr,"nkf internal module connection failure.\n");
3861     exit(1);
3862 }
3863
3864 #ifndef PERL_XS
3865 void 
3866 usage()   
3867 {
3868     fprintf(stderr,"USAGE:  nkf(nkf32,wnkf,nkf2) -[flags] [in file] .. [out file for -O flag]\n");
3869     fprintf(stderr,"Flags:\n");
3870     fprintf(stderr,"b,u      Output is bufferred (DEFAULT),Output is unbufferred\n");
3871 #ifdef DEFAULT_CODE_SJIS
3872     fprintf(stderr,"j,s,e,w  Outout code is JIS 7 bit, Shift JIS (DEFAULT), AT&T JIS (EUC), UTF-8\n");
3873 #endif
3874 #ifdef DEFAULT_CODE_JIS
3875     fprintf(stderr,"j,s,e,w  Outout code is JIS 7 bit (DEFAULT), Shift JIS, AT&T JIS (EUC), UTF-8\n");
3876 #endif
3877 #ifdef DEFAULT_CODE_EUC
3878     fprintf(stderr,"j,s,e,w  Outout code is JIS 7 bit, Shift JIS, AT&T JIS (EUC) (DEFAULT), UTF-8\n");
3879 #endif
3880 #ifdef DEFAULT_CODE_UTF8
3881     fprintf(stderr,"j,s,e,w  Outout code is JIS 7 bit, Shift JIS, AT&T JIS (EUC), UTF-8 (DEFAULT)\n");
3882 #endif
3883     fprintf(stderr,"J,S,E,W  Input assumption is JIS 7 bit , Shift JIS, AT&T JIS (EUC), UTF-8\n");
3884     fprintf(stderr,"t        no conversion\n");
3885     fprintf(stderr,"i_/o_    Output sequence to designate JIS-kanji/ASCII (DEFAULT B)\n");
3886     fprintf(stderr,"r        {de/en}crypt ROT13/47\n");
3887     fprintf(stderr,"h        1 hirakana->katakana, 2 katakana->hirakana,3 both\n");
3888     fprintf(stderr,"v        Show this usage. V: show version\n");
3889     fprintf(stderr,"m[BQN0]  MIME decode [B:base64,Q:quoted,N:non-strict,0:no decode]\n");
3890     fprintf(stderr,"M[BQ]    MIME encode [B:base64 Q:quoted]\n");
3891     fprintf(stderr,"l        ISO8859-1 (Latin-1) support\n");
3892     fprintf(stderr,"f/F      Folding: -f60 or -f or -f60-10 (fold margin 10) F preserve nl\n");
3893     fprintf(stderr,"Z[0-3]   Convert X0208 alphabet to ASCII  1: Kankaku to space,2: 2 spaces,\n");
3894     fprintf(stderr,"                                          3: Convert HTML Entity\n");
3895     fprintf(stderr,"X,x      Assume X0201 kana in MS-Kanji, -x preserves X0201\n");
3896     fprintf(stderr,"B[0-2]   Broken input  0: missing ESC,1: any X on ESC-[($]-X,2: ASCII on NL\n");
3897 #ifdef MSDOS
3898     fprintf(stderr,"T        Text mode output\n");
3899 #endif
3900     fprintf(stderr,"O        Output to File (DEFAULT 'nkf.out')\n");
3901     fprintf(stderr,"d,c      Delete \\r in line feed and \\032, Add \\r in line feed\n");
3902     fprintf(stderr,"I        Convert non ISO-2022-JP charactor to GETA\n");
3903     fprintf(stderr,"-L[uwm]  line mode u:LF w:CRLF m:CR (DEFAULT noconversion)\n");
3904     fprintf(stderr,"long name options\n");
3905     fprintf(stderr," --fj,--unix,--mac,--windows                convert for the system\n");
3906     fprintf(stderr," --jis,--euc,--sjis,--utf8,--utf16,--mime,--base64  convert for the code\n");
3907 #ifdef OVERWRITE
3908     fprintf(stderr," --overwrite          Overwrite original listed files by filtered result\n");
3909 #endif
3910     fprintf(stderr," --help,--version\n");
3911     version();
3912 }
3913
3914 void
3915 version()
3916 {
3917     fprintf(stderr,"Network Kanji Filter Version %s (%s) "
3918 #if defined(MSDOS) && !defined(__WIN32__) && !defined(__WIN16__)
3919                   "for DOS"
3920 #endif
3921 #if defined(MSDOS) && defined(__WIN16__)
3922                   "for Win16"
3923 #endif
3924 #if defined(MSDOS) && defined(__WIN32__)
3925                   "for Win32"
3926 #endif
3927 #ifdef __OS2__
3928                   "for OS/2"
3929 #endif
3930                   ,Version,Patchlevel);
3931     fprintf(stderr,"\n%s\n",CopyRight);
3932 }
3933 #endif
3934
3935 /**
3936  ** \e$B%Q%C%A@):n<T\e(B
3937  **  void@merope.pleiades.or.jp (Kusakabe Youichi)
3938  **  NIDE Naoyuki <nide@ics.nara-wu.ac.jp>
3939  **  ohta@src.ricoh.co.jp (Junn Ohta)
3940  **  inouet@strl.nhk.or.jp (Tomoyuki Inoue)
3941  **  kiri@pulser.win.or.jp (Tetsuaki Kiriyama)
3942  **  Kimihiko Sato <sato@sail.t.u-tokyo.ac.jp>
3943  **  a_kuroe@kuroe.aoba.yokohama.jp (Akihiko Kuroe)
3944  **  kono@ie.u-ryukyu.ac.jp (Shinji Kono)
3945  **  GHG00637@nifty-serve.or.jp (COW)
3946  **
3947  **/
3948
3949 /* end */