OSDN Git Service

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