OSDN Git Service

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