OSDN Git Service

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