OSDN Git Service

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