OSDN Git Service

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