OSDN Git Service

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