OSDN Git Service

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