OSDN Git Service

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