(Qenable_decomposition): New variable in XEmacs CHISE.
[chise/xemacs-chise.git.1] / src / text-coding.c
1 /* Code conversion functions.
2    Copyright (C) 1991, 1995 Free Software Foundation, Inc.
3    Copyright (C) 1995 Sun Microsystems, Inc.
4    Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2011,
5      2012 MORIOKA Tomohiko
6
7 This file is part of XEmacs.
8
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
12 later version.
13
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17 for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING.  If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.  */
23
24 /* Synched up with: Mule 2.3.   Not in FSF. */
25
26 /* Rewritten by Ben Wing <ben@xemacs.org>. */
27 /* Rewritten by MORIOKA Tomohiko <tomo@m17n.org> for XEmacs CHISE. */
28
29 #include <config.h>
30 #include "lisp.h"
31
32 #include "buffer.h"
33 #include "elhash.h"
34 #include "insdel.h"
35 #include "lstream.h"
36 #include "opaque.h"
37 #ifdef MULE
38 #include "mule-ccl.h"
39 #include "chartab.h"
40 #endif
41 #include "file-coding.h"
42
43 Lisp_Object Qcoding_system_error;
44
45 Lisp_Object Vkeyboard_coding_system;
46 Lisp_Object Vterminal_coding_system;
47 Lisp_Object Vcoding_system_for_read;
48 Lisp_Object Vcoding_system_for_write;
49 Lisp_Object Vfile_name_coding_system;
50
51 Lisp_Object Vcoded_charset_entity_reference_alist;
52
53 /* Table of symbols identifying each coding category. */
54 Lisp_Object coding_category_symbol[CODING_CATEGORY_LAST];
55
56
57
58 struct file_coding_dump {
59   /* Coding system currently associated with each coding category. */
60   Lisp_Object coding_category_system[CODING_CATEGORY_LAST];
61
62   /* Table of all coding categories in decreasing order of priority.
63      This describes a permutation of the possible coding categories. */
64   int coding_category_by_priority[CODING_CATEGORY_LAST];
65
66 #if defined(MULE) && !defined(UTF2000)
67   Lisp_Object ucs_to_mule_table[65536];
68 #endif
69 } *fcd;
70
71 static const struct lrecord_description fcd_description_1[] = {
72   { XD_LISP_OBJECT_ARRAY, offsetof (struct file_coding_dump, coding_category_system), CODING_CATEGORY_LAST },
73 #if defined(MULE) && !defined(UTF2000)
74   { XD_LISP_OBJECT_ARRAY, offsetof (struct file_coding_dump, ucs_to_mule_table), countof (fcd->ucs_to_mule_table) },
75 #endif
76   { XD_END }
77 };
78
79 static const struct struct_description fcd_description = {
80   sizeof (struct file_coding_dump),
81   fcd_description_1
82 };
83
84 Lisp_Object mule_to_ucs_table;
85
86 Lisp_Object Qcoding_systemp;
87
88 Lisp_Object Qraw_text, Qno_conversion, Qccl, Qiso2022;
89 /* Qinternal in general.c */
90
91 Lisp_Object Qmnemonic, Qeol_type;
92 Lisp_Object Qcr, Qcrlf, Qlf;
93 Lisp_Object Qeol_cr, Qeol_crlf, Qeol_lf;
94 Lisp_Object Qpost_read_conversion;
95 Lisp_Object Qpre_write_conversion;
96
97 #ifdef MULE
98 Lisp_Object Qucs4, Qutf16, Qutf8;
99 Lisp_Object Qbig5, Qshift_jis;
100 Lisp_Object Qcharset_g0, Qcharset_g1, Qcharset_g2, Qcharset_g3;
101 Lisp_Object Qforce_g0_on_output, Qforce_g1_on_output;
102 Lisp_Object Qforce_g2_on_output, Qforce_g3_on_output;
103 Lisp_Object Qno_iso6429;
104 Lisp_Object Qinput_charset_conversion, Qoutput_charset_conversion;
105 Lisp_Object Qescape_quoted;
106 Lisp_Object Qshort, Qno_ascii_eol, Qno_ascii_cntl, Qseven, Qlock_shift;
107 #endif
108 #ifdef UTF2000
109 Lisp_Object Qutf_8_mcs;
110 Lisp_Object Qdisable_composition, Qenable_decomposition;
111 Lisp_Object Qccs_priority_list;
112 Lisp_Object Quse_entity_reference;
113 Lisp_Object Qd, Qx, QX;
114 Lisp_Object Vdecomposition_feature_list;
115 #endif
116 Lisp_Object Qencode, Qdecode;
117
118 Lisp_Object Vcoding_system_hash_table;
119
120 int enable_multibyte_characters;
121
122 #ifdef MULE
123 /* Additional information used by the ISO2022 decoder and detector. */
124 struct iso2022_decoder
125 {
126   /* CHARSET holds the character sets currently assigned to the G0
127      through G3 variables.  It is initialized from the array
128      INITIAL_CHARSET in CODESYS. */
129   Lisp_Object charset[4];
130
131   /* Which registers are currently invoked into the left (GL) and
132      right (GR) halves of the 8-bit encoding space? */
133   int register_left, register_right;
134
135   /* ISO_ESC holds a value indicating part of an escape sequence
136      that has already been seen. */
137   enum iso_esc_flag esc;
138
139   /* This records the bytes we've seen so far in an escape sequence,
140      in case the sequence is invalid (we spit out the bytes unchanged). */
141   unsigned char esc_bytes[8];
142
143   /* Index for next byte to store in ISO escape sequence. */
144   int esc_bytes_index;
145
146 #ifdef ENABLE_COMPOSITE_CHARS
147   /* Stuff seen so far when composing a string. */
148   unsigned_char_dynarr *composite_chars;
149 #endif
150
151   /* If we saw an invalid designation sequence for a particular
152      register, we flag it here and switch to ASCII.  The next time we
153      see a valid designation for this register, we turn off the flag
154      and do the designation normally, but pretend the sequence was
155      invalid.  The effect of all this is that (most of the time) the
156      escape sequences for both the switch to the unknown charset, and
157      the switch back to the known charset, get inserted literally into
158      the buffer and saved out as such.  The hope is that we can
159      preserve the escape sequences so that the resulting written out
160      file makes sense.  If we don't do any of this, the designation
161      to the invalid charset will be preserved but that switch back
162      to the known charset will probably get eaten because it was
163      the same charset that was already present in the register. */
164   unsigned char invalid_designated[4];
165
166   /* We try to do similar things as above for direction-switching
167      sequences.  If we encountered a direction switch while an
168      invalid designation was present, or an invalid designation
169      just after a direction switch (i.e. no valid designation
170      encountered yet), we insert the direction-switch escape
171      sequence literally into the output stream, and later on
172      insert the corresponding direction-restoring escape sequence
173      literally also. */
174   unsigned int switched_dir_and_no_valid_charset_yet :1;
175   unsigned int invalid_switch_dir :1;
176
177   /* Tells the decoder to output the escape sequence literally
178      even though it was valid.  Used in the games we play to
179      avoid lossage when we encounter invalid designations. */
180   unsigned int output_literally :1;
181   /* We encountered a direction switch followed by an invalid
182      designation.  We didn't output the direction switch
183      literally because we didn't know about the invalid designation;
184      but we have to do so now. */
185   unsigned int output_direction_sequence :1;
186 };
187 #endif /* MULE */
188 EXFUN (Fcopy_coding_system, 2);
189 #ifdef MULE
190 struct detection_state;
191
192 static void
193 text_encode_generic (Lstream *encoding, const Bufbyte *src,
194                      unsigned_char_dynarr *dst, Lstream_data_count n);
195
196 static int detect_coding_sjis (struct detection_state *st,
197                                const Extbyte *src, Lstream_data_count n);
198 static void decode_coding_sjis (Lstream *decoding, const Extbyte *src,
199                                 unsigned_char_dynarr *dst, Lstream_data_count n);
200 void char_encode_shift_jis (struct encoding_stream *str, Emchar c,
201                             unsigned_char_dynarr *dst, unsigned int *flags);
202 void char_finish_shift_jis (struct encoding_stream *str,
203                             unsigned_char_dynarr *dst, unsigned int *flags);
204
205 static int detect_coding_big5 (struct detection_state *st,
206                                const Extbyte *src, Lstream_data_count n);
207 static void decode_coding_big5 (Lstream *decoding, const Extbyte *src,
208                                 unsigned_char_dynarr *dst, Lstream_data_count n);
209 void char_encode_big5 (struct encoding_stream *str, Emchar c,
210                        unsigned_char_dynarr *dst, unsigned int *flags);
211 void char_finish_big5 (struct encoding_stream *str,
212                        unsigned_char_dynarr *dst, unsigned int *flags);
213
214 static int detect_coding_ucs4 (struct detection_state *st,
215                                const Extbyte *src, Lstream_data_count n);
216 static void decode_coding_ucs4 (Lstream *decoding, const Extbyte *src,
217                                 unsigned_char_dynarr *dst, Lstream_data_count n);
218 void char_encode_ucs4 (struct encoding_stream *str, Emchar c,
219                        unsigned_char_dynarr *dst, unsigned int *flags);
220 void char_finish_ucs4 (struct encoding_stream *str,
221                        unsigned_char_dynarr *dst, unsigned int *flags);
222
223 static int detect_coding_utf16 (struct detection_state *st,
224                                const Extbyte *src, Lstream_data_count n);
225 static void decode_coding_utf16 (Lstream *decoding, const Extbyte *src,
226                                 unsigned_char_dynarr *dst, Lstream_data_count n);
227 void char_encode_utf16 (struct encoding_stream *str, Emchar c,
228                        unsigned_char_dynarr *dst, unsigned int *flags);
229 void char_finish_utf16 (struct encoding_stream *str,
230                        unsigned_char_dynarr *dst, unsigned int *flags);
231
232 static int detect_coding_utf8 (struct detection_state *st,
233                                const Extbyte *src, Lstream_data_count n);
234 static void decode_coding_utf8 (Lstream *decoding, const Extbyte *src,
235                                 unsigned_char_dynarr *dst, Lstream_data_count n);
236 void char_encode_utf8 (struct encoding_stream *str, Emchar c,
237                        unsigned_char_dynarr *dst, unsigned int *flags);
238 void char_finish_utf8 (struct encoding_stream *str,
239                        unsigned_char_dynarr *dst, unsigned int *flags);
240
241 static int postprocess_iso2022_mask (int mask);
242 static void reset_iso2022 (Lisp_Object coding_system,
243                            struct iso2022_decoder *iso);
244 static int detect_coding_iso2022 (struct detection_state *st,
245                                   const Extbyte *src, Lstream_data_count n);
246 static void decode_coding_iso2022 (Lstream *decoding, const Extbyte *src,
247                                    unsigned_char_dynarr *dst, Lstream_data_count n);
248 void char_encode_iso2022 (struct encoding_stream *str, Emchar c,
249                           unsigned_char_dynarr *dst, unsigned int *flags);
250 void char_finish_iso2022 (struct encoding_stream *str,
251                           unsigned_char_dynarr *dst, unsigned int *flags);
252 #endif /* MULE */
253 static void decode_coding_no_conversion (Lstream *decoding, const Extbyte *src,
254                                          unsigned_char_dynarr *dst, Lstream_data_count n);
255 static void encode_coding_no_conversion (Lstream *encoding, const Bufbyte *src,
256                                          unsigned_char_dynarr *dst, Lstream_data_count n);
257 static void mule_decode (Lstream *decoding, const Extbyte *src,
258                          unsigned_char_dynarr *dst, Lstream_data_count n);
259 static void mule_encode (Lstream *encoding, const Bufbyte *src,
260                          unsigned_char_dynarr *dst, Lstream_data_count n);
261
262 typedef struct codesys_prop codesys_prop;
263 struct codesys_prop
264 {
265   Lisp_Object sym;
266   int prop_type;
267 };
268
269 typedef struct
270 {
271   Dynarr_declare (codesys_prop);
272 } codesys_prop_dynarr;
273
274 static const struct lrecord_description codesys_prop_description_1[] = {
275   { XD_LISP_OBJECT, offsetof (codesys_prop, sym) },
276   { XD_END }
277 };
278
279 static const struct struct_description codesys_prop_description = {
280   sizeof (codesys_prop),
281   codesys_prop_description_1
282 };
283
284 static const struct lrecord_description codesys_prop_dynarr_description_1[] = {
285   XD_DYNARR_DESC (codesys_prop_dynarr, &codesys_prop_description),
286   { XD_END }
287 };
288
289 static const struct struct_description codesys_prop_dynarr_description = {
290   sizeof (codesys_prop_dynarr),
291   codesys_prop_dynarr_description_1
292 };
293
294 codesys_prop_dynarr *the_codesys_prop_dynarr;
295
296 enum codesys_prop_enum
297 {
298   CODESYS_PROP_ALL_OK,
299   CODESYS_PROP_ISO2022,
300   CODESYS_PROP_CCL
301 };
302
303 \f
304 /************************************************************************/
305 /*                       Coding system functions                        */
306 /************************************************************************/
307
308 static Lisp_Object mark_coding_system (Lisp_Object);
309 static void print_coding_system (Lisp_Object, Lisp_Object, int);
310 static void finalize_coding_system (void *header, int for_disksave);
311
312 #ifdef MULE
313 static const struct lrecord_description ccs_description_1[] = {
314   { XD_LISP_OBJECT, offsetof (charset_conversion_spec, from_charset) },
315   { XD_LISP_OBJECT, offsetof (charset_conversion_spec, to_charset) },
316   { XD_END }
317 };
318
319 static const struct struct_description ccs_description = {
320   sizeof (charset_conversion_spec),
321   ccs_description_1
322 };
323
324 static const struct lrecord_description ccsd_description_1[] = {
325   XD_DYNARR_DESC (charset_conversion_spec_dynarr, &ccs_description),
326   { XD_END }
327 };
328
329 static const struct struct_description ccsd_description = {
330   sizeof (charset_conversion_spec_dynarr),
331   ccsd_description_1
332 };
333 #endif
334
335 static const struct lrecord_description coding_system_description[] = {
336   { XD_LISP_OBJECT, offsetof (Lisp_Coding_System, name) },
337   { XD_LISP_OBJECT, offsetof (Lisp_Coding_System, doc_string) },
338   { XD_LISP_OBJECT, offsetof (Lisp_Coding_System, mnemonic) },
339   { XD_LISP_OBJECT, offsetof (Lisp_Coding_System, post_read_conversion) },
340   { XD_LISP_OBJECT, offsetof (Lisp_Coding_System, pre_write_conversion) },
341   { XD_LISP_OBJECT, offsetof (Lisp_Coding_System, eol_lf) },
342   { XD_LISP_OBJECT, offsetof (Lisp_Coding_System, eol_crlf) },
343   { XD_LISP_OBJECT, offsetof (Lisp_Coding_System, eol_cr) },
344 #ifdef MULE
345   { XD_LISP_OBJECT_ARRAY, offsetof (Lisp_Coding_System, iso2022.initial_charset), 4 },
346   { XD_STRUCT_PTR,  offsetof (Lisp_Coding_System, iso2022.input_conv),  1, &ccsd_description },
347   { XD_STRUCT_PTR,  offsetof (Lisp_Coding_System, iso2022.output_conv), 1, &ccsd_description },
348   { XD_LISP_OBJECT, offsetof (Lisp_Coding_System, ccl.decode) },
349   { XD_LISP_OBJECT, offsetof (Lisp_Coding_System, ccl.encode) },
350 #ifdef UTF2000
351   { XD_LISP_OBJECT, offsetof (Lisp_Coding_System, ccs_priority_list) },
352 #endif
353 #endif
354   { XD_END }
355 };
356
357 DEFINE_LRECORD_IMPLEMENTATION ("coding-system", coding_system,
358                                mark_coding_system, print_coding_system,
359                                finalize_coding_system,
360                                0, 0, coding_system_description,
361                                Lisp_Coding_System);
362
363 static Lisp_Object
364 mark_coding_system (Lisp_Object obj)
365 {
366   Lisp_Coding_System *codesys = XCODING_SYSTEM (obj);
367
368   mark_object (CODING_SYSTEM_NAME (codesys));
369   mark_object (CODING_SYSTEM_DOC_STRING (codesys));
370   mark_object (CODING_SYSTEM_MNEMONIC (codesys));
371   mark_object (CODING_SYSTEM_EOL_LF (codesys));
372   mark_object (CODING_SYSTEM_EOL_CRLF (codesys));
373   mark_object (CODING_SYSTEM_EOL_CR (codesys));
374
375   switch (CODING_SYSTEM_TYPE (codesys))
376     {
377 #ifdef MULE
378       int i;
379     case CODESYS_ISO2022:
380       for (i = 0; i < 4; i++)
381         mark_object (CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, i));
382       if (codesys->iso2022.input_conv)
383         {
384           for (i = 0; i < Dynarr_length (codesys->iso2022.input_conv); i++)
385             {
386               struct charset_conversion_spec *ccs =
387                 Dynarr_atp (codesys->iso2022.input_conv, i);
388               mark_object (ccs->from_charset);
389               mark_object (ccs->to_charset);
390             }
391         }
392       if (codesys->iso2022.output_conv)
393         {
394           for (i = 0; i < Dynarr_length (codesys->iso2022.output_conv); i++)
395             {
396               struct charset_conversion_spec *ccs =
397                 Dynarr_atp (codesys->iso2022.output_conv, i);
398               mark_object (ccs->from_charset);
399               mark_object (ccs->to_charset);
400             }
401         }
402       break;
403 #ifdef UTF2000
404
405     case CODESYS_BIG5:
406       mark_object (CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, 0));
407       mark_object (CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, 1));
408       break;
409 #endif
410
411     case CODESYS_CCL:
412       mark_object (CODING_SYSTEM_CCL_DECODE (codesys));
413       mark_object (CODING_SYSTEM_CCL_ENCODE (codesys));
414       break;
415 #endif /* MULE */
416     default:
417       break;
418     }
419
420   mark_object (CODING_SYSTEM_PRE_WRITE_CONVERSION (codesys));
421 #ifdef UTF2000
422   mark_object (CODING_SYSTEM_CCS_PRIORITY_LIST (codesys));
423 #endif
424   return CODING_SYSTEM_POST_READ_CONVERSION (codesys);
425 }
426
427 static void
428 print_coding_system (Lisp_Object obj, Lisp_Object printcharfun,
429                      int escapeflag)
430 {
431   Lisp_Coding_System *c = XCODING_SYSTEM (obj);
432   if (print_readably)
433     error ("printing unreadable object #<coding_system 0x%x>",
434            c->header.uid);
435
436   write_c_string ("#<coding_system ", printcharfun);
437   print_internal (c->name, printcharfun, 1);
438   write_c_string (">", printcharfun);
439 }
440
441 static void
442 finalize_coding_system (void *header, int for_disksave)
443 {
444   Lisp_Coding_System *c = (Lisp_Coding_System *) header;
445   /* Since coding systems never go away, this function is not
446      necessary.  But it would be necessary if we changed things
447      so that coding systems could go away. */
448   if (!for_disksave) /* see comment in lstream.c */
449     {
450       switch (CODING_SYSTEM_TYPE (c))
451         {
452 #ifdef MULE
453         case CODESYS_ISO2022:
454           if (c->iso2022.input_conv)
455             {
456               Dynarr_free (c->iso2022.input_conv);
457               c->iso2022.input_conv = 0;
458             }
459           if (c->iso2022.output_conv)
460             {
461               Dynarr_free (c->iso2022.output_conv);
462               c->iso2022.output_conv = 0;
463             }
464           break;
465 #endif /* MULE */
466         default:
467           break;
468         }
469     }
470 }
471
472 static eol_type_t
473 symbol_to_eol_type (Lisp_Object symbol)
474 {
475   CHECK_SYMBOL (symbol);
476   if (NILP (symbol))      return EOL_AUTODETECT;
477   if (EQ (symbol, Qlf))   return EOL_LF;
478   if (EQ (symbol, Qcrlf)) return EOL_CRLF;
479   if (EQ (symbol, Qcr))   return EOL_CR;
480
481   signal_simple_error ("Unrecognized eol type", symbol);
482   return EOL_AUTODETECT; /* not reached */
483 }
484
485 static Lisp_Object
486 eol_type_to_symbol (eol_type_t type)
487 {
488   switch (type)
489     {
490     default: abort ();
491     case EOL_LF:         return Qlf;
492     case EOL_CRLF:       return Qcrlf;
493     case EOL_CR:         return Qcr;
494     case EOL_AUTODETECT: return Qnil;
495     }
496 }
497
498 static void
499 setup_eol_coding_systems (Lisp_Coding_System *codesys)
500 {
501   Lisp_Object codesys_obj;
502   int len = string_length (XSYMBOL (CODING_SYSTEM_NAME (codesys))->name);
503   char *codesys_name = (char *) alloca (len + 7);
504   int mlen = -1;
505   char *codesys_mnemonic=0;
506
507   Lisp_Object codesys_name_sym, sub_codesys_obj;
508
509   /* kludge */
510
511   XSETCODING_SYSTEM (codesys_obj, codesys);
512
513   memcpy (codesys_name,
514           string_data (XSYMBOL (CODING_SYSTEM_NAME (codesys))->name), len);
515
516   if (STRINGP (CODING_SYSTEM_MNEMONIC (codesys)))
517     {
518       mlen = XSTRING_LENGTH (CODING_SYSTEM_MNEMONIC (codesys));
519       codesys_mnemonic = (char *) alloca (mlen + 7);
520       memcpy (codesys_mnemonic,
521               XSTRING_DATA (CODING_SYSTEM_MNEMONIC (codesys)), mlen);
522     }
523
524 #define DEFINE_SUB_CODESYS(op_sys, op_sys_abbr, Type) do {                      \
525   strcpy (codesys_name + len, "-" op_sys);                                      \
526   if (mlen != -1)                                                               \
527     strcpy (codesys_mnemonic + mlen, op_sys_abbr);                              \
528   codesys_name_sym = intern (codesys_name);                                     \
529   sub_codesys_obj = Fcopy_coding_system (codesys_obj, codesys_name_sym);        \
530   XCODING_SYSTEM_EOL_TYPE (sub_codesys_obj) = Type;                             \
531   if (mlen != -1)                                                               \
532     XCODING_SYSTEM_MNEMONIC(sub_codesys_obj) =                                  \
533       build_string (codesys_mnemonic);                                          \
534   CODING_SYSTEM_##Type (codesys) = sub_codesys_obj;                             \
535 } while (0)
536
537   DEFINE_SUB_CODESYS("unix", "", EOL_LF);
538   DEFINE_SUB_CODESYS("dos",  ":T", EOL_CRLF);
539   DEFINE_SUB_CODESYS("mac",  ":t", EOL_CR);
540 }
541
542 DEFUN ("coding-system-p", Fcoding_system_p, 1, 1, 0, /*
543 Return t if OBJECT is a coding system.
544 A coding system is an object that defines how text containing multiple
545 character sets is encoded into a stream of (typically 8-bit) bytes.
546 The coding system is used to decode the stream into a series of
547 characters (which may be from multiple charsets) when the text is read
548 from a file or process, and is used to encode the text back into the
549 same format when it is written out to a file or process.
550
551 For example, many ISO2022-compliant coding systems (such as Compound
552 Text, which is used for inter-client data under the X Window System)
553 use escape sequences to switch between different charsets -- Japanese
554 Kanji, for example, is invoked with "ESC $ ( B"; ASCII is invoked
555 with "ESC ( B"; and Cyrillic is invoked with "ESC - L".  See
556 `make-coding-system' for more information.
557
558 Coding systems are normally identified using a symbol, and the
559 symbol is accepted in place of the actual coding system object whenever
560 a coding system is called for. (This is similar to how faces work.)
561 */
562        (object))
563 {
564   return CODING_SYSTEMP (object) ? Qt : Qnil;
565 }
566
567 DEFUN ("find-coding-system", Ffind_coding_system, 1, 1, 0, /*
568 Retrieve the coding system of the given name.
569
570 If CODING-SYSTEM-OR-NAME is a coding-system object, it is simply
571 returned.  Otherwise, CODING-SYSTEM-OR-NAME should be a symbol.
572 If there is no such coding system, nil is returned.  Otherwise the
573 associated coding system object is returned.
574 */
575        (coding_system_or_name))
576 {
577   if (NILP (coding_system_or_name))
578     coding_system_or_name = Qbinary;
579   else if (CODING_SYSTEMP (coding_system_or_name))
580     return coding_system_or_name;
581   else
582     CHECK_SYMBOL (coding_system_or_name);
583
584   while (1)
585     {
586       coding_system_or_name =
587         Fgethash (coding_system_or_name, Vcoding_system_hash_table, Qnil);
588
589       if (CODING_SYSTEMP (coding_system_or_name) || NILP (coding_system_or_name))
590         return coding_system_or_name;
591     }
592 }
593
594 DEFUN ("get-coding-system", Fget_coding_system, 1, 1, 0, /*
595 Retrieve the coding system of the given name.
596 Same as `find-coding-system' except that if there is no such
597 coding system, an error is signaled instead of returning nil.
598 */
599        (name))
600 {
601   Lisp_Object coding_system = Ffind_coding_system (name);
602
603   if (NILP (coding_system))
604     signal_simple_error ("No such coding system", name);
605   return coding_system;
606 }
607
608 /* We store the coding systems in hash tables with the names as the key and the
609    actual coding system object as the value.  Occasionally we need to use them
610    in a list format.  These routines provide us with that. */
611 struct coding_system_list_closure
612 {
613   Lisp_Object *coding_system_list;
614 };
615
616 static int
617 add_coding_system_to_list_mapper (Lisp_Object key, Lisp_Object value,
618                                   void *coding_system_list_closure)
619 {
620   /* This function can GC */
621   struct coding_system_list_closure *cscl =
622     (struct coding_system_list_closure *) coding_system_list_closure;
623   Lisp_Object *coding_system_list = cscl->coding_system_list;
624
625   *coding_system_list = Fcons (key, *coding_system_list);
626   return 0;
627 }
628
629 DEFUN ("coding-system-list", Fcoding_system_list, 0, 0, 0, /*
630 Return a list of the names of all defined coding systems.
631 */
632        ())
633 {
634   Lisp_Object coding_system_list = Qnil;
635   struct gcpro gcpro1;
636   struct coding_system_list_closure coding_system_list_closure;
637
638   GCPRO1 (coding_system_list);
639   coding_system_list_closure.coding_system_list = &coding_system_list;
640   elisp_maphash (add_coding_system_to_list_mapper, Vcoding_system_hash_table,
641                  &coding_system_list_closure);
642   UNGCPRO;
643
644   return coding_system_list;
645 }
646
647 DEFUN ("coding-system-name", Fcoding_system_name, 1, 1, 0, /*
648 Return the name of the given coding system.
649 */
650        (coding_system))
651 {
652   coding_system = Fget_coding_system (coding_system);
653   return XCODING_SYSTEM_NAME (coding_system);
654 }
655
656 static Lisp_Coding_System *
657 allocate_coding_system (enum coding_system_type type, Lisp_Object name)
658 {
659   Lisp_Coding_System *codesys =
660     alloc_lcrecord_type (Lisp_Coding_System, &lrecord_coding_system);
661
662   zero_lcrecord (codesys);
663   CODING_SYSTEM_PRE_WRITE_CONVERSION (codesys) = Qnil;
664   CODING_SYSTEM_POST_READ_CONVERSION (codesys) = Qnil;
665   CODING_SYSTEM_EOL_TYPE (codesys) = EOL_AUTODETECT;
666   CODING_SYSTEM_EOL_CRLF (codesys) = Qnil;
667   CODING_SYSTEM_EOL_CR   (codesys) = Qnil;
668   CODING_SYSTEM_EOL_LF   (codesys) = Qnil;
669   CODING_SYSTEM_TYPE     (codesys) = type;
670   CODING_SYSTEM_MNEMONIC (codesys) = Qnil;
671 #ifdef MULE
672 #ifdef UTF2000
673   CODING_SYSTEM_CCS_PRIORITY_LIST (codesys) = Qnil;
674 #endif
675   if (type == CODESYS_ISO2022)
676     {
677       int i;
678       for (i = 0; i < 4; i++)
679         CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, i) = Qnil;
680     }
681 #ifdef UTF2000
682   if (type == CODESYS_UTF8)
683     {
684       CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, 0)
685         = Vcharset_ucs;
686       CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, 1)
687         = Qnil;
688       CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, 2)
689         = Qnil;
690       CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, 3)
691         = Qnil;
692     }
693   else if (type == CODESYS_BIG5)
694     {
695       CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, 0)
696         = Vcharset_ascii;
697       CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, 1)
698         = Vcharset_chinese_big5;
699       CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, 2)
700         = Qnil;
701       CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, 3)
702         = Qnil;
703     }
704 #endif
705   else if (type == CODESYS_CCL)
706     {
707       CODING_SYSTEM_CCL_DECODE (codesys) = Qnil;
708       CODING_SYSTEM_CCL_ENCODE (codesys) = Qnil;
709     }
710 #endif /* MULE */
711   CODING_SYSTEM_NAME (codesys) = name;
712
713   return codesys;
714 }
715
716 #ifdef MULE
717 /* Given a list of charset conversion specs as specified in a Lisp
718    program, parse it into STORE_HERE. */
719
720 static void
721 parse_charset_conversion_specs (charset_conversion_spec_dynarr *store_here,
722                                 Lisp_Object spec_list)
723 {
724   Lisp_Object rest;
725
726   EXTERNAL_LIST_LOOP (rest, spec_list)
727     {
728       Lisp_Object car = XCAR (rest);
729       Lisp_Object from, to;
730       struct charset_conversion_spec spec;
731
732       if (!CONSP (car) || !CONSP (XCDR (car)) || !NILP (XCDR (XCDR (car))))
733         signal_simple_error ("Invalid charset conversion spec", car);
734       from = Fget_charset (XCAR (car));
735       to = Fget_charset (XCAR (XCDR (car)));
736       if ( (XCHARSET_CHARS (from) != XCHARSET_CHARS (to)) ||
737            (XCHARSET_DIMENSION (from) != XCHARSET_DIMENSION (to)) )
738         signal_simple_error_2
739           ("Attempted conversion between different charset types",
740            from, to);
741       spec.from_charset = from;
742       spec.to_charset = to;
743
744       Dynarr_add (store_here, spec);
745     }
746 }
747
748 /* Given a dynarr LOAD_HERE of internally-stored charset conversion
749    specs, return the equivalent as the Lisp programmer would see it.
750
751    If LOAD_HERE is 0, return Qnil. */
752
753 static Lisp_Object
754 unparse_charset_conversion_specs (charset_conversion_spec_dynarr *load_here)
755 {
756   int i;
757   Lisp_Object result;
758
759   if (!load_here)
760     return Qnil;
761   for (i = 0, result = Qnil; i < Dynarr_length (load_here); i++)
762     {
763       struct charset_conversion_spec *ccs = Dynarr_atp (load_here, i);
764       result = Fcons (list2 (ccs->from_charset, ccs->to_charset), result);
765     }
766
767   return Fnreverse (result);
768 }
769
770 #endif /* MULE */
771
772 DEFUN ("make-coding-system", Fmake_coding_system, 2, 4, 0, /*
773 Register symbol NAME as a coding system.
774
775 TYPE describes the conversion method used and should be one of
776
777 nil or 'undecided
778      Automatic conversion.  XEmacs attempts to detect the coding system
779      used in the file.
780 'no-conversion
781      No conversion.  Use this for binary files and such.  On output,
782      graphic characters that are not in ASCII or Latin-1 will be
783      replaced by a ?. (For a no-conversion-encoded buffer, these
784      characters will only be present if you explicitly insert them.)
785 'shift-jis
786      Shift-JIS (a Japanese encoding commonly used in PC operating systems).
787 'ucs-4
788      ISO 10646 UCS-4 encoding.
789 'utf-8
790      ISO 10646 UTF-8 encoding.
791 'iso2022
792      Any ISO2022-compliant encoding.  Among other things, this includes
793      JIS (the Japanese encoding commonly used for e-mail), EUC (the
794      standard Unix encoding for Japanese and other languages), and
795      Compound Text (the encoding used in X11).  You can specify more
796      specific information about the conversion with the PROPS argument.
797 'big5
798      Big5 (the encoding commonly used for Taiwanese).
799 'ccl
800      The conversion is performed using a user-written pseudo-code
801      program.  CCL (Code Conversion Language) is the name of this
802      pseudo-code.
803 'internal
804      Write out or read in the raw contents of the memory representing
805      the buffer's text.  This is primarily useful for debugging
806      purposes, and is only enabled when XEmacs has been compiled with
807      DEBUG_XEMACS defined (via the --debug configure option).
808      WARNING: Reading in a file using 'internal conversion can result
809      in an internal inconsistency in the memory representing a
810      buffer's text, which will produce unpredictable results and may
811      cause XEmacs to crash.  Under normal circumstances you should
812      never use 'internal conversion.
813
814 DOC-STRING is a string describing the coding system.
815
816 PROPS is a property list, describing the specific nature of the
817 character set.  Recognized properties are:
818
819 'mnemonic
820      String to be displayed in the modeline when this coding system is
821      active.
822
823 'eol-type
824      End-of-line conversion to be used.  It should be one of
825
826         nil
827                 Automatically detect the end-of-line type (LF, CRLF,
828                 or CR).  Also generate subsidiary coding systems named
829                 `NAME-unix', `NAME-dos', and `NAME-mac', that are
830                 identical to this coding system but have an EOL-TYPE
831                 value of 'lf, 'crlf, and 'cr, respectively.
832         'lf
833                 The end of a line is marked externally using ASCII LF.
834                 Since this is also the way that XEmacs represents an
835                 end-of-line internally, specifying this option results
836                 in no end-of-line conversion.  This is the standard
837                 format for Unix text files.
838         'crlf
839                 The end of a line is marked externally using ASCII
840                 CRLF.  This is the standard format for MS-DOS text
841                 files.
842         'cr
843                 The end of a line is marked externally using ASCII CR.
844                 This is the standard format for Macintosh text files.
845         t
846                 Automatically detect the end-of-line type but do not
847                 generate subsidiary coding systems.  (This value is
848                 converted to nil when stored internally, and
849                 `coding-system-property' will return nil.)
850
851 'disable-composition
852      If non-nil, composition for combining characters is disabled.
853
854 'enable-decomposition
855      If non-nil, decomposition for combining characters is enabled.
856
857 'use-entity-reference
858      If non-nil, SGML style entity-reference is used for non-system-characters.
859
860 'post-read-conversion
861      Function called after a file has been read in, to perform the
862      decoding.  Called with two arguments, START and END, denoting
863      a region of the current buffer to be decoded.
864
865 'pre-write-conversion
866      Function called before a file is written out, to perform the
867      encoding.  Called with two arguments, START and END, denoting
868      a region of the current buffer to be encoded.
869
870
871 The following additional properties are recognized if TYPE is 'iso2022:
872
873 'charset-g0
874 'charset-g1
875 'charset-g2
876 'charset-g3
877      The character set initially designated to the G0 - G3 registers.
878      The value should be one of
879
880           -- A charset object (designate that character set)
881           -- nil (do not ever use this register)
882           -- t (no character set is initially designated to
883                 the register, but may be later on; this automatically
884                 sets the corresponding `force-g*-on-output' property)
885
886 'force-g0-on-output
887 'force-g1-on-output
888 'force-g2-on-output
889 'force-g2-on-output
890      If non-nil, send an explicit designation sequence on output before
891      using the specified register.
892
893 'short
894      If non-nil, use the short forms "ESC $ @", "ESC $ A", and
895      "ESC $ B" on output in place of the full designation sequences
896      "ESC $ ( @", "ESC $ ( A", and "ESC $ ( B".
897
898 'no-ascii-eol
899      If non-nil, don't designate ASCII to G0 at each end of line on output.
900      Setting this to non-nil also suppresses other state-resetting that
901      normally happens at the end of a line.
902
903 'no-ascii-cntl
904      If non-nil, don't designate ASCII to G0 before control chars on output.
905
906 'seven
907      If non-nil, use 7-bit environment on output.  Otherwise, use 8-bit
908      environment.
909
910 'lock-shift
911      If non-nil, use locking-shift (SO/SI) instead of single-shift
912      or designation by escape sequence.
913
914 'no-iso6429
915      If non-nil, don't use ISO6429's direction specification.
916
917 'escape-quoted
918      If non-nil, literal control characters that are the same as
919      the beginning of a recognized ISO2022 or ISO6429 escape sequence
920      (in particular, ESC (0x1B), SO (0x0E), SI (0x0F), SS2 (0x8E),
921      SS3 (0x8F), and CSI (0x9B)) are "quoted" with an escape character
922      so that they can be properly distinguished from an escape sequence.
923      (Note that doing this results in a non-portable encoding.) This
924      encoding flag is used for byte-compiled files.  Note that ESC
925      is a good choice for a quoting character because there are no
926      escape sequences whose second byte is a character from the Control-0
927      or Control-1 character sets; this is explicitly disallowed by the
928      ISO2022 standard.
929
930 'input-charset-conversion
931      A list of conversion specifications, specifying conversion of
932      characters in one charset to another when decoding is performed.
933      Each specification is a list of two elements: the source charset,
934      and the destination charset.
935
936 'output-charset-conversion
937      A list of conversion specifications, specifying conversion of
938      characters in one charset to another when encoding is performed.
939      The form of each specification is the same as for
940      'input-charset-conversion.
941
942
943 The following additional properties are recognized (and required)
944 if TYPE is 'ccl:
945
946 'decode
947      CCL program used for decoding (converting to internal format).
948
949 'encode
950      CCL program used for encoding (converting to external format).
951 */
952        (name, type, doc_string, props))
953 {
954   Lisp_Coding_System *codesys;
955   enum coding_system_type ty;
956   int need_to_setup_eol_systems = 1;
957
958   /* Convert type to constant */
959   if (NILP (type) || EQ (type, Qundecided))
960                                       { ty = CODESYS_AUTODETECT; }
961 #ifdef MULE
962   else if (EQ (type, Qshift_jis))     { ty = CODESYS_SHIFT_JIS; }
963   else if (EQ (type, Qiso2022))       { ty = CODESYS_ISO2022; }
964   else if (EQ (type, Qbig5))          { ty = CODESYS_BIG5; }
965   else if (EQ (type, Qucs4))          { ty = CODESYS_UCS4; }
966   else if (EQ (type, Qutf16))         { ty = CODESYS_UTF16; }
967   else if (EQ (type, Qutf8))          { ty = CODESYS_UTF8; }
968   else if (EQ (type, Qccl))           { ty = CODESYS_CCL; }
969 #endif
970   else if (EQ (type, Qno_conversion)) { ty = CODESYS_NO_CONVERSION; }
971 #ifdef DEBUG_XEMACS
972   else if (EQ (type, Qinternal))      { ty = CODESYS_INTERNAL; }
973 #endif
974   else
975     signal_simple_error ("Invalid coding system type", type);
976
977   CHECK_SYMBOL (name);
978
979   codesys = allocate_coding_system (ty, name);
980
981   if (NILP (doc_string))
982     doc_string = build_string ("");
983   else
984     CHECK_STRING (doc_string);
985   CODING_SYSTEM_DOC_STRING (codesys) = doc_string;
986
987   {
988     EXTERNAL_PROPERTY_LIST_LOOP_3 (key, value, props)
989       {
990         if (EQ (key, Qmnemonic))
991           {
992             if (!NILP (value))
993               CHECK_STRING (value);
994             CODING_SYSTEM_MNEMONIC (codesys) = value;
995           }
996
997         else if (EQ (key, Qeol_type))
998           {
999             need_to_setup_eol_systems = NILP (value);
1000             if (EQ (value, Qt))
1001               value = Qnil;
1002             CODING_SYSTEM_EOL_TYPE (codesys) = symbol_to_eol_type (value);
1003           }
1004
1005         else if (EQ (key, Qpost_read_conversion))
1006           CODING_SYSTEM_POST_READ_CONVERSION (codesys) = value;
1007         else if (EQ (key, Qpre_write_conversion))
1008           CODING_SYSTEM_PRE_WRITE_CONVERSION (codesys) = value;
1009 #ifdef UTF2000
1010         else if (EQ (key, Qdisable_composition))
1011           CODING_SYSTEM_DISABLE_COMPOSITION (codesys) = !NILP (value);
1012         else if (EQ (key, Qenable_decomposition))
1013           CODING_SYSTEM_ENABLE_DECOMPOSITION (codesys) = !NILP (value);
1014         else if (EQ (key, Quse_entity_reference))
1015           CODING_SYSTEM_USE_ENTITY_REFERENCE (codesys) = !NILP (value);
1016 #endif
1017 #ifdef MULE
1018         else if (ty == CODESYS_ISO2022)
1019           {
1020 #define FROB_INITIAL_CHARSET(charset_num) \
1021   CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, charset_num) = \
1022     ((EQ (value, Qt) || EQ (value, Qnil)) ? value : Fget_charset (value))
1023
1024             if      (EQ (key, Qcharset_g0)) FROB_INITIAL_CHARSET (0);
1025             else if (EQ (key, Qcharset_g1)) FROB_INITIAL_CHARSET (1);
1026             else if (EQ (key, Qcharset_g2)) FROB_INITIAL_CHARSET (2);
1027             else if (EQ (key, Qcharset_g3)) FROB_INITIAL_CHARSET (3);
1028
1029 #define FROB_FORCE_CHARSET(charset_num) \
1030   CODING_SYSTEM_ISO2022_FORCE_CHARSET_ON_OUTPUT (codesys, charset_num) = !NILP (value)
1031
1032             else if (EQ (key, Qforce_g0_on_output)) FROB_FORCE_CHARSET (0);
1033             else if (EQ (key, Qforce_g1_on_output)) FROB_FORCE_CHARSET (1);
1034             else if (EQ (key, Qforce_g2_on_output)) FROB_FORCE_CHARSET (2);
1035             else if (EQ (key, Qforce_g3_on_output)) FROB_FORCE_CHARSET (3);
1036
1037 #define FROB_BOOLEAN_PROPERTY(prop) \
1038   CODING_SYSTEM_ISO2022_##prop (codesys) = !NILP (value)
1039
1040             else if (EQ (key, Qshort))         FROB_BOOLEAN_PROPERTY (SHORT);
1041             else if (EQ (key, Qno_ascii_eol))  FROB_BOOLEAN_PROPERTY (NO_ASCII_EOL);
1042             else if (EQ (key, Qno_ascii_cntl)) FROB_BOOLEAN_PROPERTY (NO_ASCII_CNTL);
1043             else if (EQ (key, Qseven))         FROB_BOOLEAN_PROPERTY (SEVEN);
1044             else if (EQ (key, Qlock_shift))    FROB_BOOLEAN_PROPERTY (LOCK_SHIFT);
1045             else if (EQ (key, Qno_iso6429))    FROB_BOOLEAN_PROPERTY (NO_ISO6429);
1046             else if (EQ (key, Qescape_quoted)) FROB_BOOLEAN_PROPERTY (ESCAPE_QUOTED);
1047
1048             else if (EQ (key, Qinput_charset_conversion))
1049               {
1050                 codesys->iso2022.input_conv =
1051                   Dynarr_new (charset_conversion_spec);
1052                 parse_charset_conversion_specs (codesys->iso2022.input_conv,
1053                                                 value);
1054               }
1055             else if (EQ (key, Qoutput_charset_conversion))
1056               {
1057                 codesys->iso2022.output_conv =
1058                   Dynarr_new (charset_conversion_spec);
1059                 parse_charset_conversion_specs (codesys->iso2022.output_conv,
1060                                                 value);
1061               }
1062 #ifdef UTF2000
1063             else if (EQ (key, Qccs_priority_list))
1064               {
1065                 codesys->ccs_priority_list = value;
1066               }
1067 #endif
1068             else
1069               signal_simple_error ("Unrecognized property", key);
1070           }
1071 #ifdef UTF2000
1072         else if (ty == CODESYS_UTF8)
1073           {
1074             if      (EQ (key, Qcharset_g0)) FROB_INITIAL_CHARSET (0);
1075             else if (EQ (key, Qcharset_g1))
1076               CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, 1) = value;
1077             else if (EQ (key, Qcharset_g2))
1078               CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, 2) = value;
1079             else
1080               signal_simple_error ("Unrecognized property", key);
1081           }
1082         else if (ty == CODESYS_BIG5)
1083           {
1084             if      (EQ (key, Qcharset_g0)) FROB_INITIAL_CHARSET (0);
1085             else if (EQ (key, Qcharset_g1)) FROB_INITIAL_CHARSET (1);
1086             else
1087               signal_simple_error ("Unrecognized property", key);
1088           }
1089 #endif
1090         else if (EQ (type, Qccl))
1091           {
1092             Lisp_Object sym;
1093             struct ccl_program test_ccl;
1094             Extbyte *suffix;
1095
1096             /* Check key first.  */
1097             if (EQ (key, Qdecode))
1098               suffix = "-ccl-decode";
1099             else if (EQ (key, Qencode))
1100               suffix = "-ccl-encode";
1101             else
1102               signal_simple_error ("Unrecognized property", key);
1103
1104             /* If value is vector, register it as a ccl program
1105                associated with an newly created symbol for
1106                backward compatibility.  */
1107             if (VECTORP (value))
1108               {
1109                 sym = Fintern (concat2 (Fsymbol_name (name),
1110                                         build_string (suffix)),
1111                                Qnil);
1112                 Fregister_ccl_program (sym, value);
1113               }
1114             else
1115               {
1116                 CHECK_SYMBOL (value);
1117                 sym = value;
1118               }
1119             /* check if the given ccl programs are valid.  */
1120             if (setup_ccl_program (&test_ccl, sym) < 0)
1121               signal_simple_error ("Invalid CCL program", value);
1122
1123             if (EQ (key, Qdecode))
1124               CODING_SYSTEM_CCL_DECODE (codesys) = sym;
1125             else if (EQ (key, Qencode))
1126               CODING_SYSTEM_CCL_ENCODE (codesys) = sym;
1127
1128           }
1129 #endif /* MULE */
1130         else
1131           signal_simple_error ("Unrecognized property", key);
1132       }
1133   }
1134
1135   if (need_to_setup_eol_systems)
1136     setup_eol_coding_systems (codesys);
1137
1138   {
1139     Lisp_Object codesys_obj;
1140     XSETCODING_SYSTEM (codesys_obj, codesys);
1141     Fputhash (name, codesys_obj, Vcoding_system_hash_table);
1142     return codesys_obj;
1143   }
1144 }
1145
1146 DEFUN ("copy-coding-system", Fcopy_coding_system, 2, 2, 0, /*
1147 Copy OLD-CODING-SYSTEM to NEW-NAME.
1148 If NEW-NAME does not name an existing coding system, a new one will
1149 be created.
1150 */
1151        (old_coding_system, new_name))
1152 {
1153   Lisp_Object new_coding_system;
1154   old_coding_system = Fget_coding_system (old_coding_system);
1155   new_coding_system = Ffind_coding_system (new_name);
1156   if (NILP (new_coding_system))
1157     {
1158       XSETCODING_SYSTEM (new_coding_system,
1159                          allocate_coding_system
1160                          (XCODING_SYSTEM_TYPE (old_coding_system),
1161                           new_name));
1162       Fputhash (new_name, new_coding_system, Vcoding_system_hash_table);
1163     }
1164
1165   {
1166     Lisp_Coding_System *to = XCODING_SYSTEM (new_coding_system);
1167     Lisp_Coding_System *from = XCODING_SYSTEM (old_coding_system);
1168     memcpy (((char *) to  ) + sizeof (to->header),
1169             ((char *) from) + sizeof (from->header),
1170             sizeof (*from) - sizeof (from->header));
1171     to->name = new_name;
1172   }
1173   return new_coding_system;
1174 }
1175
1176 DEFUN ("coding-system-canonical-name-p", Fcoding_system_canonical_name_p, 1, 1, 0, /*
1177 Return t if OBJECT names a coding system, and is not a coding system alias.
1178 */
1179        (object))
1180 {
1181   return CODING_SYSTEMP (Fgethash (object, Vcoding_system_hash_table, Qnil))
1182     ? Qt : Qnil;
1183 }
1184
1185 DEFUN ("coding-system-alias-p", Fcoding_system_alias_p, 1, 1, 0, /*
1186 Return t if OBJECT is a coding system alias.
1187 All coding system aliases are created by `define-coding-system-alias'.
1188 */
1189        (object))
1190 {
1191   return SYMBOLP (Fgethash (object, Vcoding_system_hash_table, Qzero))
1192     ? Qt : Qnil;
1193 }
1194
1195 DEFUN ("coding-system-aliasee", Fcoding_system_aliasee, 1, 1, 0, /*
1196 Return the coding-system symbol for which symbol ALIAS is an alias.
1197 */
1198        (alias))
1199 {
1200   Lisp_Object aliasee = Fgethash (alias, Vcoding_system_hash_table, Qnil);
1201   if (SYMBOLP (aliasee))
1202     return aliasee;
1203   else
1204     signal_simple_error ("Symbol is not a coding system alias", alias);
1205   return Qnil;          /* To keep the compiler happy */
1206 }
1207
1208 static Lisp_Object
1209 append_suffix_to_symbol (Lisp_Object symbol, const char *ascii_string)
1210 {
1211   return Fintern (concat2 (Fsymbol_name (symbol), build_string (ascii_string)),
1212                   Qnil);
1213 }
1214
1215 /* A maphash function, for removing dangling coding system aliases. */
1216 static int
1217 dangling_coding_system_alias_p (Lisp_Object alias,
1218                                 Lisp_Object aliasee,
1219                                 void *dangling_aliases)
1220 {
1221   if (SYMBOLP (aliasee)
1222       && NILP (Fgethash (aliasee, Vcoding_system_hash_table, Qnil)))
1223     {
1224       (*(int *) dangling_aliases)++;
1225       return 1;
1226     }
1227   else
1228     return 0;
1229 }
1230
1231 DEFUN ("define-coding-system-alias", Fdefine_coding_system_alias, 2, 2, 0, /*
1232 Define symbol ALIAS as an alias for coding system ALIASEE.
1233
1234 You can use this function to redefine an alias that has already been defined,
1235 but you cannot redefine a name which is the canonical name for a coding system.
1236 \(a canonical name of a coding system is what is returned when you call
1237 `coding-system-name' on a coding system).
1238
1239 ALIASEE itself can be an alias, which allows you to define nested aliases.
1240
1241 You are forbidden, however, from creating alias loops or `dangling' aliases.
1242 These will be detected, and an error will be signaled if you attempt to do so.
1243
1244 If ALIASEE is nil, then ALIAS will simply be undefined.
1245
1246 See also `coding-system-alias-p', `coding-system-aliasee',
1247 and `coding-system-canonical-name-p'.
1248 */
1249        (alias, aliasee))
1250 {
1251   Lisp_Object real_coding_system, probe;
1252
1253   CHECK_SYMBOL (alias);
1254
1255   if (!NILP (Fcoding_system_canonical_name_p (alias)))
1256     signal_simple_error
1257       ("Symbol is the canonical name of a coding system and cannot be redefined",
1258        alias);
1259
1260   if (NILP (aliasee))
1261     {
1262       Lisp_Object subsidiary_unix = append_suffix_to_symbol (alias, "-unix");
1263       Lisp_Object subsidiary_dos  = append_suffix_to_symbol (alias, "-dos");
1264       Lisp_Object subsidiary_mac  = append_suffix_to_symbol (alias, "-mac");
1265
1266       Fremhash (alias, Vcoding_system_hash_table);
1267
1268       /* Undefine subsidiary aliases,
1269          presumably created by a previous call to this function */
1270       if (! NILP (Fcoding_system_alias_p (subsidiary_unix)) &&
1271           ! NILP (Fcoding_system_alias_p (subsidiary_dos))  &&
1272           ! NILP (Fcoding_system_alias_p (subsidiary_mac)))
1273         {
1274           Fdefine_coding_system_alias (subsidiary_unix, Qnil);
1275           Fdefine_coding_system_alias (subsidiary_dos,  Qnil);
1276           Fdefine_coding_system_alias (subsidiary_mac,  Qnil);
1277         }
1278
1279       /* Undefine dangling coding system aliases. */
1280       {
1281         int dangling_aliases;
1282
1283         do {
1284           dangling_aliases = 0;
1285           elisp_map_remhash (dangling_coding_system_alias_p,
1286                              Vcoding_system_hash_table,
1287                              &dangling_aliases);
1288         } while (dangling_aliases > 0);
1289       }
1290
1291       return Qnil;
1292     }
1293
1294   if (CODING_SYSTEMP (aliasee))
1295     aliasee = XCODING_SYSTEM_NAME (aliasee);
1296
1297   /* Checks that aliasee names a coding-system */
1298   real_coding_system = Fget_coding_system (aliasee);
1299
1300   /* Check for coding system alias loops */
1301   if (EQ (alias, aliasee))
1302     alias_loop: signal_simple_error_2
1303       ("Attempt to create a coding system alias loop", alias, aliasee);
1304
1305   for (probe = aliasee;
1306        SYMBOLP (probe);
1307        probe = Fgethash (probe, Vcoding_system_hash_table, Qzero))
1308     {
1309       if (EQ (probe, alias))
1310         goto alias_loop;
1311     }
1312
1313   Fputhash (alias, aliasee, Vcoding_system_hash_table);
1314
1315   /* Set up aliases for subsidiaries.
1316      #### There must be a better way to handle subsidiary coding systems. */
1317   {
1318     static const char *suffixes[] = { "-unix", "-dos", "-mac" };
1319     int i;
1320     for (i = 0; i < countof (suffixes); i++)
1321       {
1322         Lisp_Object alias_subsidiary =
1323           append_suffix_to_symbol (alias, suffixes[i]);
1324         Lisp_Object aliasee_subsidiary =
1325           append_suffix_to_symbol (aliasee, suffixes[i]);
1326
1327         if (! NILP (Ffind_coding_system (aliasee_subsidiary)))
1328           Fdefine_coding_system_alias (alias_subsidiary, aliasee_subsidiary);
1329       }
1330   }
1331   /* FSF return value is a vector of [ALIAS-unix ALIAS-dos ALIAS-mac],
1332      but it doesn't look intentional, so I'd rather return something
1333      meaningful or nothing at all. */
1334   return Qnil;
1335 }
1336
1337 static Lisp_Object
1338 subsidiary_coding_system (Lisp_Object coding_system, eol_type_t type)
1339 {
1340   Lisp_Coding_System *cs = XCODING_SYSTEM (coding_system);
1341   Lisp_Object new_coding_system;
1342
1343   if (CODING_SYSTEM_EOL_TYPE (cs) != EOL_AUTODETECT)
1344     return coding_system;
1345
1346   switch (type)
1347     {
1348     case EOL_AUTODETECT: return coding_system;
1349     case EOL_LF:   new_coding_system = CODING_SYSTEM_EOL_LF   (cs); break;
1350     case EOL_CR:   new_coding_system = CODING_SYSTEM_EOL_CR   (cs); break;
1351     case EOL_CRLF: new_coding_system = CODING_SYSTEM_EOL_CRLF (cs); break;
1352     default:       abort (); return Qnil;
1353     }
1354
1355   return NILP (new_coding_system) ? coding_system : new_coding_system;
1356 }
1357
1358 DEFUN ("subsidiary-coding-system", Fsubsidiary_coding_system, 2, 2, 0, /*
1359 Return the subsidiary coding system of CODING-SYSTEM with eol type EOL-TYPE.
1360 */
1361        (coding_system, eol_type))
1362 {
1363   coding_system = Fget_coding_system (coding_system);
1364
1365   return subsidiary_coding_system (coding_system,
1366                                    symbol_to_eol_type (eol_type));
1367 }
1368
1369 \f
1370 /************************************************************************/
1371 /*                         Coding system accessors                      */
1372 /************************************************************************/
1373
1374 DEFUN ("coding-system-doc-string", Fcoding_system_doc_string, 1, 1, 0, /*
1375 Return the doc string for CODING-SYSTEM.
1376 */
1377        (coding_system))
1378 {
1379   coding_system = Fget_coding_system (coding_system);
1380   return XCODING_SYSTEM_DOC_STRING (coding_system);
1381 }
1382
1383 DEFUN ("coding-system-type", Fcoding_system_type, 1, 1, 0, /*
1384 Return the type of CODING-SYSTEM.
1385 */
1386        (coding_system))
1387 {
1388   switch (XCODING_SYSTEM_TYPE (Fget_coding_system (coding_system)))
1389     {
1390     default: abort ();
1391     case CODESYS_AUTODETECT:    return Qundecided;
1392 #ifdef MULE
1393     case CODESYS_SHIFT_JIS:     return Qshift_jis;
1394     case CODESYS_ISO2022:       return Qiso2022;
1395     case CODESYS_BIG5:          return Qbig5;
1396     case CODESYS_UCS4:          return Qucs4;
1397     case CODESYS_UTF16:         return Qutf16;
1398     case CODESYS_UTF8:          return Qutf8;
1399     case CODESYS_CCL:           return Qccl;
1400 #endif
1401     case CODESYS_NO_CONVERSION: return Qno_conversion;
1402 #ifdef DEBUG_XEMACS
1403     case CODESYS_INTERNAL:      return Qinternal;
1404 #endif
1405     }
1406 }
1407
1408 #ifdef MULE
1409 static
1410 Lisp_Object coding_system_charset (Lisp_Object coding_system, int gnum)
1411 {
1412   Lisp_Object cs
1413     = XCODING_SYSTEM_ISO2022_INITIAL_CHARSET (coding_system, gnum);
1414
1415   return CHARSETP (cs) ? XCHARSET_NAME (cs) : Qnil;
1416 }
1417
1418 DEFUN ("coding-system-charset", Fcoding_system_charset, 2, 2, 0, /*
1419 Return initial charset of CODING-SYSTEM designated to GNUM.
1420 GNUM allows 0 .. 3.
1421 */
1422        (coding_system, gnum))
1423 {
1424   coding_system = Fget_coding_system (coding_system);
1425   CHECK_INT (gnum);
1426
1427   return coding_system_charset (coding_system, XINT (gnum));
1428 }
1429 #endif /* MULE */
1430
1431 DEFUN ("coding-system-property", Fcoding_system_property, 2, 2, 0, /*
1432 Return the PROP property of CODING-SYSTEM.
1433 */
1434        (coding_system, prop))
1435 {
1436   int i, ok = 0;
1437   enum coding_system_type type;
1438
1439   coding_system = Fget_coding_system (coding_system);
1440   CHECK_SYMBOL (prop);
1441   type = XCODING_SYSTEM_TYPE (coding_system);
1442
1443   for (i = 0; !ok && i < Dynarr_length (the_codesys_prop_dynarr); i++)
1444     if (EQ (Dynarr_at (the_codesys_prop_dynarr, i).sym, prop))
1445       {
1446         ok = 1;
1447         switch (Dynarr_at (the_codesys_prop_dynarr, i).prop_type)
1448           {
1449           case CODESYS_PROP_ALL_OK:
1450             break;
1451 #ifdef MULE
1452           case CODESYS_PROP_ISO2022:
1453             if (type != CODESYS_ISO2022)
1454               signal_simple_error
1455                 ("Property only valid in ISO2022 coding systems",
1456                  prop);
1457             break;
1458
1459           case CODESYS_PROP_CCL:
1460             if (type != CODESYS_CCL)
1461               signal_simple_error
1462                 ("Property only valid in CCL coding systems",
1463                  prop);
1464             break;
1465 #endif /* MULE */
1466           default:
1467             abort ();
1468           }
1469       }
1470
1471   if (!ok)
1472     signal_simple_error ("Unrecognized property", prop);
1473
1474   if (EQ (prop, Qname))
1475     return XCODING_SYSTEM_NAME (coding_system);
1476   else if (EQ (prop, Qtype))
1477     return Fcoding_system_type (coding_system);
1478   else if (EQ (prop, Qdoc_string))
1479     return XCODING_SYSTEM_DOC_STRING (coding_system);
1480   else if (EQ (prop, Qmnemonic))
1481     return XCODING_SYSTEM_MNEMONIC (coding_system);
1482   else if (EQ (prop, Qeol_type))
1483     return eol_type_to_symbol (XCODING_SYSTEM_EOL_TYPE (coding_system));
1484   else if (EQ (prop, Qeol_lf))
1485     return XCODING_SYSTEM_EOL_LF (coding_system);
1486   else if (EQ (prop, Qeol_crlf))
1487     return XCODING_SYSTEM_EOL_CRLF (coding_system);
1488   else if (EQ (prop, Qeol_cr))
1489     return XCODING_SYSTEM_EOL_CR (coding_system);
1490   else if (EQ (prop, Qpost_read_conversion))
1491     return XCODING_SYSTEM_POST_READ_CONVERSION (coding_system);
1492   else if (EQ (prop, Qpre_write_conversion))
1493     return XCODING_SYSTEM_PRE_WRITE_CONVERSION (coding_system);
1494 #ifdef MULE
1495 #ifdef UTF2000
1496   else if (EQ (prop, Qdisable_composition))
1497     return XCODING_SYSTEM_DISABLE_COMPOSITION (coding_system) ? Qt : Qnil;
1498   else if (EQ (prop, Qenable_decomposition))
1499     return XCODING_SYSTEM_ENABLE_DECOMPOSITION (coding_system) ? Qt : Qnil;
1500   else if (EQ (prop, Quse_entity_reference))
1501     return XCODING_SYSTEM_USE_ENTITY_REFERENCE (coding_system) ? Qt : Qnil;
1502   else if (EQ (prop, Qccs_priority_list))
1503     return XCODING_SYSTEM_CCS_PRIORITY_LIST (coding_system);
1504 #endif
1505   else if (type == CODESYS_ISO2022)
1506     {
1507       if (EQ (prop, Qcharset_g0))
1508         return coding_system_charset (coding_system, 0);
1509       else if (EQ (prop, Qcharset_g1))
1510         return coding_system_charset (coding_system, 1);
1511       else if (EQ (prop, Qcharset_g2))
1512         return coding_system_charset (coding_system, 2);
1513       else if (EQ (prop, Qcharset_g3))
1514         return coding_system_charset (coding_system, 3);
1515
1516 #define FORCE_CHARSET(charset_num) \
1517   (XCODING_SYSTEM_ISO2022_FORCE_CHARSET_ON_OUTPUT \
1518    (coding_system, charset_num) ? Qt : Qnil)
1519
1520       else if (EQ (prop, Qforce_g0_on_output)) return FORCE_CHARSET (0);
1521       else if (EQ (prop, Qforce_g1_on_output)) return FORCE_CHARSET (1);
1522       else if (EQ (prop, Qforce_g2_on_output)) return FORCE_CHARSET (2);
1523       else if (EQ (prop, Qforce_g3_on_output)) return FORCE_CHARSET (3);
1524
1525 #define LISP_BOOLEAN(prop) \
1526   (XCODING_SYSTEM_ISO2022_##prop (coding_system) ? Qt : Qnil)
1527
1528       else if (EQ (prop, Qshort))         return LISP_BOOLEAN (SHORT);
1529       else if (EQ (prop, Qno_ascii_eol))  return LISP_BOOLEAN (NO_ASCII_EOL);
1530       else if (EQ (prop, Qno_ascii_cntl)) return LISP_BOOLEAN (NO_ASCII_CNTL);
1531       else if (EQ (prop, Qseven))         return LISP_BOOLEAN (SEVEN);
1532       else if (EQ (prop, Qlock_shift))    return LISP_BOOLEAN (LOCK_SHIFT);
1533       else if (EQ (prop, Qno_iso6429))    return LISP_BOOLEAN (NO_ISO6429);
1534       else if (EQ (prop, Qescape_quoted)) return LISP_BOOLEAN (ESCAPE_QUOTED);
1535
1536       else if (EQ (prop, Qinput_charset_conversion))
1537         return
1538           unparse_charset_conversion_specs
1539             (XCODING_SYSTEM (coding_system)->iso2022.input_conv);
1540       else if (EQ (prop, Qoutput_charset_conversion))
1541         return
1542           unparse_charset_conversion_specs
1543             (XCODING_SYSTEM (coding_system)->iso2022.output_conv);
1544       else
1545         abort ();
1546     }
1547   else if (type == CODESYS_CCL)
1548     {
1549       if (EQ (prop, Qdecode))
1550         return XCODING_SYSTEM_CCL_DECODE (coding_system);
1551       else if (EQ (prop, Qencode))
1552         return XCODING_SYSTEM_CCL_ENCODE (coding_system);
1553       else
1554         abort ();
1555     }
1556 #endif /* MULE */
1557   else
1558     abort ();
1559
1560   return Qnil; /* not reached */
1561 }
1562
1563 \f
1564 /************************************************************************/
1565 /*                       Coding category functions                      */
1566 /************************************************************************/
1567
1568 static int
1569 decode_coding_category (Lisp_Object symbol)
1570 {
1571   int i;
1572
1573   CHECK_SYMBOL (symbol);
1574   for (i = 0; i < CODING_CATEGORY_LAST; i++)
1575     if (EQ (coding_category_symbol[i], symbol))
1576       return i;
1577
1578   signal_simple_error ("Unrecognized coding category", symbol);
1579   return 0; /* not reached */
1580 }
1581
1582 DEFUN ("coding-category-list", Fcoding_category_list, 0, 0, 0, /*
1583 Return a list of all recognized coding categories.
1584 */
1585        ())
1586 {
1587   int i;
1588   Lisp_Object list = Qnil;
1589
1590   for (i = CODING_CATEGORY_LAST - 1; i >= 0; i--)
1591     list = Fcons (coding_category_symbol[i], list);
1592   return list;
1593 }
1594
1595 DEFUN ("set-coding-priority-list", Fset_coding_priority_list, 1, 1, 0, /*
1596 Change the priority order of the coding categories.
1597 LIST should be list of coding categories, in descending order of
1598 priority.  Unspecified coding categories will be lower in priority
1599 than all specified ones, in the same relative order they were in
1600 previously.
1601 */
1602        (list))
1603 {
1604   int category_to_priority[CODING_CATEGORY_LAST];
1605   int i, j;
1606   Lisp_Object rest;
1607
1608   /* First generate a list that maps coding categories to priorities. */
1609
1610   for (i = 0; i < CODING_CATEGORY_LAST; i++)
1611     category_to_priority[i] = -1;
1612
1613   /* Highest priority comes from the specified list. */
1614   i = 0;
1615   EXTERNAL_LIST_LOOP (rest, list)
1616     {
1617       int cat = decode_coding_category (XCAR (rest));
1618
1619       if (category_to_priority[cat] >= 0)
1620         signal_simple_error ("Duplicate coding category in list", XCAR (rest));
1621       category_to_priority[cat] = i++;
1622     }
1623
1624   /* Now go through the existing categories by priority to retrieve
1625      the categories not yet specified and preserve their priority
1626      order. */
1627   for (j = 0; j < CODING_CATEGORY_LAST; j++)
1628     {
1629       int cat = fcd->coding_category_by_priority[j];
1630       if (category_to_priority[cat] < 0)
1631         category_to_priority[cat] = i++;
1632     }
1633
1634   /* Now we need to construct the inverse of the mapping we just
1635      constructed. */
1636
1637   for (i = 0; i < CODING_CATEGORY_LAST; i++)
1638     fcd->coding_category_by_priority[category_to_priority[i]] = i;
1639
1640   /* Phew!  That was confusing. */
1641   return Qnil;
1642 }
1643
1644 DEFUN ("coding-priority-list", Fcoding_priority_list, 0, 0, 0, /*
1645 Return a list of coding categories in descending order of priority.
1646 */
1647        ())
1648 {
1649   int i;
1650   Lisp_Object list = Qnil;
1651
1652   for (i = CODING_CATEGORY_LAST - 1; i >= 0; i--)
1653     list = Fcons (coding_category_symbol[fcd->coding_category_by_priority[i]],
1654                   list);
1655   return list;
1656 }
1657
1658 DEFUN ("set-coding-category-system", Fset_coding_category_system, 2, 2, 0, /*
1659 Change the coding system associated with a coding category.
1660 */
1661        (coding_category, coding_system))
1662 {
1663   int cat = decode_coding_category (coding_category);
1664
1665   coding_system = Fget_coding_system (coding_system);
1666   fcd->coding_category_system[cat] = coding_system;
1667   return Qnil;
1668 }
1669
1670 DEFUN ("coding-category-system", Fcoding_category_system, 1, 1, 0, /*
1671 Return the coding system associated with a coding category.
1672 */
1673        (coding_category))
1674 {
1675   int cat = decode_coding_category (coding_category);
1676   Lisp_Object sys = fcd->coding_category_system[cat];
1677
1678   if (!NILP (sys))
1679     return XCODING_SYSTEM_NAME (sys);
1680   return Qnil;
1681 }
1682
1683 \f
1684 /************************************************************************/
1685 /*                     Detecting the encoding of data                   */
1686 /************************************************************************/
1687
1688 struct detection_state
1689 {
1690   eol_type_t eol_type;
1691   int seen_non_ascii;
1692   int mask;
1693 #ifdef MULE
1694   struct
1695     {
1696       int mask;
1697       int in_second_byte;
1698     }
1699   big5;
1700
1701   struct
1702     {
1703       int mask;
1704       int in_second_byte;
1705     }
1706   shift_jis;
1707
1708   struct
1709     {
1710       int mask;
1711       int in_byte;
1712   }
1713   ucs4;
1714
1715   struct
1716     {
1717       int mask;
1718       int in_byte;
1719     }
1720   utf16;
1721
1722   struct
1723     {
1724       int mask;
1725       int in_byte;
1726     }
1727   utf8;
1728
1729   struct
1730     {
1731       int mask;
1732       int initted;
1733       struct iso2022_decoder iso;
1734       unsigned int flags;
1735       int high_byte_count;
1736       unsigned int saw_single_shift:1;
1737     }
1738   iso2022;
1739 #endif
1740   struct
1741     {
1742       int seen_anything;
1743       int just_saw_cr;
1744     }
1745   eol;
1746 };
1747
1748 static int
1749 acceptable_control_char_p (int c)
1750 {
1751   switch (c)
1752     {
1753       /* Allow and ignore control characters that you might
1754          reasonably see in a text file */
1755     case '\r':
1756     case '\n':
1757     case '\t':
1758     case  7: /* bell */
1759     case  8: /* backspace */
1760     case 11: /* vertical tab */
1761     case 12: /* form feed */
1762     case 26: /* MS-DOS C-z junk */
1763     case 31: /* '^_' -- for info */
1764       return 1;
1765     default:
1766       return 0;
1767     }
1768 }
1769
1770 static int
1771 mask_has_at_most_one_bit_p (int mask)
1772 {
1773   /* Perhaps the only thing useful you learn from intensive Microsoft
1774      technical interviews */
1775   return (mask & (mask - 1)) == 0;
1776 }
1777
1778 static eol_type_t
1779 detect_eol_type (struct detection_state *st, const Extbyte *src,
1780                  Lstream_data_count n)
1781 {
1782   while (n--)
1783     {
1784       unsigned char c = *(unsigned char *)src++;
1785       if (c == '\n')
1786         {
1787           if (st->eol.just_saw_cr)
1788             return EOL_CRLF;
1789           else if (st->eol.seen_anything)
1790             return EOL_LF;
1791         }
1792       else if (st->eol.just_saw_cr)
1793         return EOL_CR;
1794       else if (c == '\r')
1795         st->eol.just_saw_cr = 1;
1796       else
1797         st->eol.just_saw_cr = 0;
1798       st->eol.seen_anything = 1;
1799     }
1800
1801   return EOL_AUTODETECT;
1802 }
1803
1804 /* Attempt to determine the encoding and EOL type of the given text.
1805    Before calling this function for the first type, you must initialize
1806    st->eol_type as appropriate and initialize st->mask to ~0.
1807
1808    st->eol_type holds the determined EOL type, or EOL_AUTODETECT if
1809    not yet known.
1810
1811    st->mask holds the determined coding category mask, or ~0 if only
1812    ASCII has been seen so far.
1813
1814    Returns:
1815
1816    0 == st->eol_type is EOL_AUTODETECT and/or more than coding category
1817         is present in st->mask
1818    1 == definitive answers are here for both st->eol_type and st->mask
1819 */
1820
1821 static int
1822 detect_coding_type (struct detection_state *st, const Extbyte *src,
1823                     Lstream_data_count n, int just_do_eol)
1824 {
1825   if (st->eol_type == EOL_AUTODETECT)
1826     st->eol_type = detect_eol_type (st, src, n);
1827
1828   if (just_do_eol)
1829     return st->eol_type != EOL_AUTODETECT;
1830
1831   if (!st->seen_non_ascii)
1832     {
1833       for (; n; n--, src++)
1834         {
1835           unsigned char c = *(unsigned char *) src;
1836           if ((c < 0x20 && !acceptable_control_char_p (c)) || c >= 0x80)
1837             {
1838               st->seen_non_ascii = 1;
1839 #ifdef MULE
1840               st->shift_jis.mask = ~0;
1841               st->big5.mask = ~0;
1842               st->ucs4.mask = ~0;
1843               st->utf16.mask = ~0;
1844               st->utf8.mask = ~0;
1845               st->iso2022.mask = ~0;
1846 #endif
1847               break;
1848             }
1849         }
1850     }
1851
1852   if (!n)
1853     return 0;
1854 #ifdef MULE
1855   if (!mask_has_at_most_one_bit_p (st->iso2022.mask))
1856     st->iso2022.mask = detect_coding_iso2022 (st, src, n);
1857   if (!mask_has_at_most_one_bit_p (st->shift_jis.mask))
1858     st->shift_jis.mask = detect_coding_sjis (st, src, n);
1859   if (!mask_has_at_most_one_bit_p (st->big5.mask))
1860     st->big5.mask = detect_coding_big5 (st, src, n);
1861   if (!mask_has_at_most_one_bit_p (st->utf8.mask))
1862     st->utf8.mask = detect_coding_utf8 (st, src, n);
1863   if (!mask_has_at_most_one_bit_p (st->utf16.mask))
1864     st->utf16.mask = detect_coding_utf16 (st, src, n);
1865   if (!mask_has_at_most_one_bit_p (st->ucs4.mask))
1866     st->ucs4.mask = detect_coding_ucs4 (st, src, n);
1867
1868   st->mask
1869     = st->iso2022.mask | st->shift_jis.mask | st->big5.mask
1870     | st->utf8.mask | st->ucs4.mask;
1871 #endif
1872   {
1873     int retval = mask_has_at_most_one_bit_p (st->mask);
1874     st->mask |= CODING_CATEGORY_NO_CONVERSION_MASK;
1875     return retval && st->eol_type != EOL_AUTODETECT;
1876   }
1877 }
1878
1879 static Lisp_Object
1880 coding_system_from_mask (int mask)
1881 {
1882   if (mask == ~0)
1883     {
1884       /* If the file was entirely or basically ASCII, use the
1885          default value of `buffer-file-coding-system'. */
1886       Lisp_Object retval =
1887         XBUFFER (Vbuffer_defaults)->buffer_file_coding_system;
1888       if (!NILP (retval))
1889         {
1890           retval = Ffind_coding_system (retval);
1891           if (NILP (retval))
1892             {
1893               warn_when_safe
1894                 (Qbad_variable, Qwarning,
1895                  "Invalid `default-buffer-file-coding-system', set to nil");
1896               XBUFFER (Vbuffer_defaults)->buffer_file_coding_system = Qnil;
1897             }
1898         }
1899       if (NILP (retval))
1900         retval = Fget_coding_system (Qraw_text);
1901       return retval;
1902     }
1903   else
1904     {
1905       int i;
1906       int cat = -1;
1907 #ifdef MULE
1908       mask = postprocess_iso2022_mask (mask);
1909 #endif
1910       /* Look through the coding categories by priority and find
1911          the first one that is allowed. */
1912       for (i = 0; i < CODING_CATEGORY_LAST; i++)
1913         {
1914           cat = fcd->coding_category_by_priority[i];
1915           if ((mask & (1 << cat)) &&
1916               !NILP (fcd->coding_category_system[cat]))
1917             break;
1918         }
1919       if (cat >= 0)
1920         return fcd->coding_category_system[cat];
1921       else
1922         return Fget_coding_system (Qraw_text);
1923     }
1924 }
1925
1926 /* Given a seekable read stream and potential coding system and EOL type
1927    as specified, do any autodetection that is called for.  If the
1928    coding system and/or EOL type are not `autodetect', they will be left
1929    alone; but this function will never return an autodetect coding system
1930    or EOL type.
1931
1932    This function does not automatically fetch subsidiary coding systems;
1933    that should be unnecessary with the explicit eol-type argument. */
1934
1935 #define LENGTH(string_constant) (sizeof (string_constant) - 1)
1936 /* number of leading lines to check for a coding cookie */
1937 #define LINES_TO_CHECK 2
1938
1939 void
1940 determine_real_coding_system (Lstream *stream, Lisp_Object *codesys_in_out,
1941                               eol_type_t *eol_type_in_out)
1942 {
1943   struct detection_state decst;
1944
1945   if (*eol_type_in_out == EOL_AUTODETECT)
1946     *eol_type_in_out = XCODING_SYSTEM_EOL_TYPE (*codesys_in_out);
1947
1948   xzero (decst);
1949   decst.eol_type = *eol_type_in_out;
1950   decst.mask = ~0;
1951
1952   /* If autodetection is called for, do it now. */
1953   if (XCODING_SYSTEM_TYPE (*codesys_in_out) == CODESYS_AUTODETECT
1954       || *eol_type_in_out == EOL_AUTODETECT)
1955     {
1956       Extbyte buf[4096];
1957       Lisp_Object coding_system = Qnil;
1958       Extbyte *p;
1959       Lstream_data_count nread = Lstream_read (stream, buf, sizeof (buf));
1960       Extbyte *scan_end;
1961       int lines_checked = 0;
1962
1963       /* Look for initial "-*-"; mode line prefix */
1964       for (p = buf,
1965              scan_end = buf + nread - LENGTH ("-*-coding:?-*-");
1966            p <= scan_end
1967              && lines_checked < LINES_TO_CHECK;
1968            p++)
1969         if (*p == '-' && *(p+1) == '*' && *(p+2) == '-')
1970           {
1971             Extbyte *local_vars_beg = p + 3;
1972             /* Look for final "-*-"; mode line suffix */
1973             for (p = local_vars_beg,
1974                    scan_end = buf + nread - LENGTH ("-*-");
1975                  p <= scan_end
1976                    && lines_checked < LINES_TO_CHECK;
1977                  p++)
1978               if (*p == '-' && *(p+1) == '*' && *(p+2) == '-')
1979                 {
1980                   Extbyte *suffix = p;
1981                   /* Look for "coding:" */
1982                   for (p = local_vars_beg,
1983                          scan_end = suffix - LENGTH ("coding:?");
1984                        p <= scan_end;
1985                        p++)
1986                     if (memcmp ("coding:", p, LENGTH ("coding:")) == 0
1987                         && (p == local_vars_beg
1988                             || (*(p-1) == ' '  ||
1989                                 *(p-1) == '\t' ||
1990                                 *(p-1) == ';')))
1991                       {
1992                         Extbyte save;
1993                         int n;
1994                         p += LENGTH ("coding:");
1995                         while (*p == ' ' || *p == '\t') p++;
1996
1997                         /* Get coding system name */
1998                         save = *suffix; *suffix = '\0';
1999                         /* Characters valid in a MIME charset name (rfc 1521),
2000                            and in a Lisp symbol name. */
2001                         n = strspn ( (char *) p,
2002                                     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2003                                     "abcdefghijklmnopqrstuvwxyz"
2004                                     "0123456789"
2005                                     "!$%&*+-.^_{|}~");
2006                         *suffix = save;
2007                         if (n > 0)
2008                           {
2009                             save = p[n]; p[n] = '\0';
2010                             coding_system =
2011                               Ffind_coding_system (intern ((char *) p));
2012                             p[n] = save;
2013                           }
2014                         break;
2015                       }
2016                   break;
2017                 }
2018               /* #### file must use standard EOLs or we miss 2d line */
2019               /* #### not to mention this is broken for UTF-16 DOS files */
2020               else if (*p == '\n' || *p == '\r')
2021                 {
2022                   lines_checked++;
2023                   /* skip past multibyte (DOS) newline */
2024                   if (*p == '\r' && *(p+1) == '\n') p++;
2025                 }
2026             break;
2027           }
2028         /* #### file must use standard EOLs or we miss 2d line */
2029         /* #### not to mention this is broken for UTF-16 DOS files */
2030         else if (*p == '\n' || *p == '\r')
2031           {
2032             lines_checked++;
2033             /* skip past multibyte (DOS) newline */
2034             if (*p == '\r' && *(p+1) == '\n') p++;
2035           }
2036
2037       if (NILP (coding_system))
2038         do
2039           {
2040             if (detect_coding_type (&decst, buf, nread,
2041                                     XCODING_SYSTEM_TYPE (*codesys_in_out)
2042                                     != CODESYS_AUTODETECT))
2043               break;
2044             nread = Lstream_read (stream, buf, sizeof (buf));
2045             if (nread == 0)
2046               break;
2047           }
2048         while (1);
2049
2050       else if (XCODING_SYSTEM_TYPE (*codesys_in_out) == CODESYS_AUTODETECT
2051                && XCODING_SYSTEM_EOL_TYPE (coding_system) == EOL_AUTODETECT)
2052         do
2053           {
2054             if (detect_coding_type (&decst, buf, nread, 1))
2055               break;
2056             nread = Lstream_read (stream, buf, sizeof (buf));
2057             if (!nread)
2058               break;
2059           }
2060         while (1);
2061
2062       *eol_type_in_out = decst.eol_type;
2063       if (XCODING_SYSTEM_TYPE (*codesys_in_out) == CODESYS_AUTODETECT)
2064         {
2065           if (NILP (coding_system))
2066             *codesys_in_out = coding_system_from_mask (decst.mask);
2067           else
2068             *codesys_in_out = coding_system;
2069         }
2070     }
2071
2072   /* If we absolutely can't determine the EOL type, just assume LF. */
2073   if (*eol_type_in_out == EOL_AUTODETECT)
2074     *eol_type_in_out = EOL_LF;
2075
2076   Lstream_rewind (stream);
2077 }
2078
2079 DEFUN ("detect-coding-region", Fdetect_coding_region, 2, 3, 0, /*
2080 Detect coding system of the text in the region between START and END.
2081 Return a list of possible coding systems ordered by priority.
2082 If only ASCII characters are found, return 'undecided or one of
2083 its subsidiary coding systems according to a detected end-of-line
2084 type.  Optional arg BUFFER defaults to the current buffer.
2085 */
2086        (start, end, buffer))
2087 {
2088   Lisp_Object val = Qnil;
2089   struct buffer *buf = decode_buffer (buffer, 0);
2090   Bufpos b, e;
2091   Lisp_Object instream, lb_instream;
2092   Lstream *istr, *lb_istr;
2093   struct detection_state decst;
2094   struct gcpro gcpro1, gcpro2;
2095
2096   get_buffer_range_char (buf, start, end, &b, &e, 0);
2097   lb_instream = make_lisp_buffer_input_stream (buf, b, e, 0);
2098   lb_istr = XLSTREAM (lb_instream);
2099   instream = make_encoding_input_stream (lb_istr, Fget_coding_system (Qbinary));
2100   istr = XLSTREAM (instream);
2101   GCPRO2 (instream, lb_instream);
2102   xzero (decst);
2103   decst.eol_type = EOL_AUTODETECT;
2104   decst.mask = ~0;
2105   while (1)
2106     {
2107       Extbyte random_buffer[4096];
2108       Lstream_data_count nread = Lstream_read (istr, random_buffer, sizeof (random_buffer));
2109
2110       if (!nread)
2111         break;
2112       if (detect_coding_type (&decst, random_buffer, nread, 0))
2113         break;
2114     }
2115
2116   if (decst.mask == ~0)
2117     val = subsidiary_coding_system (Fget_coding_system (Qundecided),
2118                                     decst.eol_type);
2119   else
2120     {
2121       int i;
2122
2123       val = Qnil;
2124 #ifdef MULE
2125       decst.mask = postprocess_iso2022_mask (decst.mask);
2126 #endif
2127       for (i = CODING_CATEGORY_LAST - 1; i >= 0; i--)
2128         {
2129           int sys = fcd->coding_category_by_priority[i];
2130           if (decst.mask & (1 << sys))
2131             {
2132               Lisp_Object codesys = fcd->coding_category_system[sys];
2133               if (!NILP (codesys))
2134                 codesys = subsidiary_coding_system (codesys, decst.eol_type);
2135               val = Fcons (codesys, val);
2136             }
2137         }
2138     }
2139   Lstream_close (istr);
2140   UNGCPRO;
2141   Lstream_delete (istr);
2142   Lstream_delete (lb_istr);
2143   return val;
2144 }
2145
2146 \f
2147 /************************************************************************/
2148 /*           Converting to internal Mule format ("decoding")            */
2149 /************************************************************************/
2150
2151 /* A decoding stream is a stream used for decoding text (i.e.
2152    converting from some external format to internal format).
2153    The decoding-stream object keeps track of the actual coding
2154    stream, the stream that is at the other end, and data that
2155    needs to be persistent across the lifetime of the stream. */
2156
2157 /* Handle the EOL stuff related to just-read-in character C.
2158    EOL_TYPE is the EOL type of the coding stream.
2159    FLAGS is the current value of FLAGS in the coding stream, and may
2160    be modified by this macro.  (The macro only looks at the
2161    CODING_STATE_CR flag.)  DST is the Dynarr to which the decoded
2162    bytes are to be written.  You need to also define a local goto
2163    label "label_continue_loop" that is at the end of the main
2164    character-reading loop.
2165
2166    If C is a CR character, then this macro handles it entirely and
2167    jumps to label_continue_loop.  Otherwise, this macro does not add
2168    anything to DST, and continues normally.  You should continue
2169    processing C normally after this macro. */
2170
2171 #define DECODE_HANDLE_EOL_TYPE(eol_type, c, flags, dst)         \
2172 do {                                                            \
2173   if (c == '\r')                                                \
2174     {                                                           \
2175       if (eol_type == EOL_CR)                                   \
2176         Dynarr_add (dst, '\n');                                 \
2177       else if (eol_type != EOL_CRLF || flags & CODING_STATE_CR) \
2178         Dynarr_add (dst, c);                                    \
2179       else                                                      \
2180         flags |= CODING_STATE_CR;                               \
2181       goto label_continue_loop;                                 \
2182     }                                                           \
2183   else if (flags & CODING_STATE_CR)                             \
2184     {   /* eol_type == CODING_SYSTEM_EOL_CRLF */                \
2185       if (c != '\n')                                            \
2186         Dynarr_add (dst, '\r');                                 \
2187       flags &= ~CODING_STATE_CR;                                \
2188     }                                                           \
2189 } while (0)
2190
2191 /* C should be a binary character in the range 0 - 255; convert
2192    to internal format and add to Dynarr DST. */
2193
2194 #ifdef UTF2000
2195 #define DECODE_ADD_BINARY_CHAR(c, dst) \
2196 do {                                            \
2197   if (BYTE_ASCII_P (c))                         \
2198     Dynarr_add (dst, c);                        \
2199   else                                          \
2200     {                                           \
2201       Dynarr_add (dst, (c >> 6) | 0xc0);        \
2202       Dynarr_add (dst, (c & 0x3f) | 0x80);      \
2203     }                                           \
2204 } while (0)
2205
2206 static void DECODE_ADD_UCS_CHAR(Emchar c, unsigned_char_dynarr* dst);
2207 static void
2208 DECODE_ADD_UCS_CHAR(Emchar c, unsigned_char_dynarr* dst)
2209 {
2210   if ( c <= 0x7f )
2211     {
2212       Dynarr_add (dst, c);
2213     }
2214   else if ( c <= 0x7ff )
2215     {
2216       Dynarr_add (dst, (c >> 6) | 0xc0);
2217       Dynarr_add (dst, (c & 0x3f) | 0x80);
2218     }
2219   else if ( c <= 0xffff )
2220     {
2221       Dynarr_add (dst,  (c >> 12) | 0xe0);
2222       Dynarr_add (dst, ((c >>  6) & 0x3f) | 0x80);
2223       Dynarr_add (dst,  (c        & 0x3f) | 0x80);
2224     }
2225   else if ( c <= 0x1fffff )
2226     {
2227       Dynarr_add (dst,  (c >> 18) | 0xf0);
2228       Dynarr_add (dst, ((c >> 12) & 0x3f) | 0x80);
2229       Dynarr_add (dst, ((c >>  6) & 0x3f) | 0x80);
2230       Dynarr_add (dst,  (c        & 0x3f) | 0x80);
2231     }
2232   else if ( c <= 0x3ffffff )
2233     {
2234       Dynarr_add (dst,  (c >> 24) | 0xf8);
2235       Dynarr_add (dst, ((c >> 18) & 0x3f) | 0x80);
2236       Dynarr_add (dst, ((c >> 12) & 0x3f) | 0x80);
2237       Dynarr_add (dst, ((c >>  6) & 0x3f) | 0x80);
2238       Dynarr_add (dst,  (c        & 0x3f) | 0x80);
2239     }
2240   else
2241     {
2242       Dynarr_add (dst,  (c >> 30) | 0xfc);
2243       Dynarr_add (dst, ((c >> 24) & 0x3f) | 0x80);
2244       Dynarr_add (dst, ((c >> 18) & 0x3f) | 0x80);
2245       Dynarr_add (dst, ((c >> 12) & 0x3f) | 0x80);
2246       Dynarr_add (dst, ((c >>  6) & 0x3f) | 0x80);
2247       Dynarr_add (dst,  (c        & 0x3f) | 0x80);
2248     }
2249 }
2250 #else
2251 #define DECODE_ADD_BINARY_CHAR(c, dst)          \
2252 do {                                            \
2253   if (BYTE_ASCII_P (c))                         \
2254     Dynarr_add (dst, c);                        \
2255   else if (BYTE_C1_P (c))                       \
2256     {                                           \
2257       Dynarr_add (dst, LEADING_BYTE_CONTROL_1); \
2258       Dynarr_add (dst, c + 0x20);               \
2259     }                                           \
2260   else                                          \
2261     {                                           \
2262       Dynarr_add (dst, LEADING_BYTE_LATIN_ISO8859_1); \
2263       Dynarr_add (dst, c);                      \
2264     }                                           \
2265 } while (0)
2266 #endif
2267
2268 #define DECODE_OUTPUT_PARTIAL_CHAR(ch)  \
2269 do {                                    \
2270   if (ch)                               \
2271     {                                   \
2272       DECODE_ADD_BINARY_CHAR (ch, dst); \
2273       ch = 0;                           \
2274     }                                   \
2275 } while (0)
2276
2277 #define DECODE_HANDLE_END_OF_CONVERSION(flags, ch, dst) \
2278 do {                                    \
2279   if (flags & CODING_STATE_END)         \
2280     {                                   \
2281       DECODE_OUTPUT_PARTIAL_CHAR (ch);  \
2282       if (flags & CODING_STATE_CR)      \
2283         Dynarr_add (dst, '\r');         \
2284     }                                   \
2285 } while (0)
2286
2287 #define DECODING_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, decoding)
2288
2289 #define ER_BUF_SIZE 24
2290
2291 struct decoding_stream
2292 {
2293   /* Coding system that governs the conversion. */
2294   Lisp_Coding_System *codesys;
2295
2296   /* Stream that we read the encoded data from or
2297      write the decoded data to. */
2298   Lstream *other_end;
2299
2300   /* If we are reading, then we can return only a fixed amount of
2301      data, so if the conversion resulted in too much data, we store it
2302      here for retrieval the next time around. */
2303   unsigned_char_dynarr *runoff;
2304
2305   /* FLAGS holds flags indicating the current state of the decoding.
2306      Some of these flags are dependent on the coding system. */
2307   unsigned int flags;
2308
2309   /* CPOS holds a partially built-up code-point of character. */
2310   unsigned int cpos;
2311
2312   /* EOL_TYPE specifies the type of end-of-line conversion that
2313      currently applies.  We need to keep this separate from the
2314      EOL type stored in CODESYS because the latter might indicate
2315      automatic EOL-type detection while the former will always
2316      indicate a particular EOL type. */
2317   eol_type_t eol_type;
2318 #ifdef MULE
2319   /* Additional ISO2022 information.  We define the structure above
2320      because it's also needed by the detection routines. */
2321   struct iso2022_decoder iso2022;
2322
2323   /* Additional information (the state of the running CCL program)
2324      used by the CCL decoder. */
2325   struct ccl_program ccl;
2326
2327   /* counter for UTF-8 or UCS-4 */
2328   unsigned char counter;
2329 #endif
2330 #ifdef UTF2000
2331   char bom_flag;
2332   unsigned char er_counter;
2333   unsigned char er_buf[ER_BUF_SIZE];
2334
2335   unsigned combined_char_count;
2336   Emchar combined_chars[16];
2337   Lisp_Object combining_table;
2338 #endif
2339   struct detection_state decst;
2340 };
2341
2342 static Lstream_data_count decoding_reader (Lstream *stream,
2343                                 unsigned char *data, Lstream_data_count size);
2344 static Lstream_data_count decoding_writer (Lstream *stream,
2345                                 const unsigned char *data, Lstream_data_count size);
2346 static int decoding_rewinder   (Lstream *stream);
2347 static int decoding_seekable_p (Lstream *stream);
2348 static int decoding_flusher    (Lstream *stream);
2349 static int decoding_closer     (Lstream *stream);
2350
2351 static Lisp_Object decoding_marker (Lisp_Object stream);
2352
2353 DEFINE_LSTREAM_IMPLEMENTATION ("decoding", lstream_decoding,
2354                                sizeof (struct decoding_stream));
2355
2356 static Lisp_Object
2357 decoding_marker (Lisp_Object stream)
2358 {
2359   Lstream *str = DECODING_STREAM_DATA (XLSTREAM (stream))->other_end;
2360   Lisp_Object str_obj;
2361
2362   /* We do not need to mark the coding systems or charsets stored
2363      within the stream because they are stored in a global list
2364      and automatically marked. */
2365
2366   XSETLSTREAM (str_obj, str);
2367   mark_object (str_obj);
2368   if (str->imp->marker)
2369     return (str->imp->marker) (str_obj);
2370   else
2371     return Qnil;
2372 }
2373
2374 /* Read SIZE bytes of data and store it into DATA.  We are a decoding stream
2375    so we read data from the other end, decode it, and store it into DATA. */
2376
2377 static Lstream_data_count
2378 decoding_reader (Lstream *stream, unsigned char *data, Lstream_data_count size)
2379 {
2380   struct decoding_stream *str = DECODING_STREAM_DATA (stream);
2381   unsigned char *orig_data = data;
2382   Lstream_data_count read_size;
2383   int error_occurred = 0;
2384
2385   /* We need to interface to mule_decode(), which expects to take some
2386      amount of data and store the result into a Dynarr.  We have
2387      mule_decode() store into str->runoff, and take data from there
2388      as necessary. */
2389
2390   /* We loop until we have enough data, reading chunks from the other
2391      end and decoding it. */
2392   while (1)
2393     {
2394       /* Take data from the runoff if we can.  Make sure to take at
2395          most SIZE bytes, and delete the data from the runoff. */
2396       if (Dynarr_length (str->runoff) > 0)
2397         {
2398           Lstream_data_count chunk = min (size, (Lstream_data_count) Dynarr_length (str->runoff));
2399           memcpy (data, Dynarr_atp (str->runoff, 0), chunk);
2400           Dynarr_delete_many (str->runoff, 0, chunk);
2401           data += chunk;
2402           size -= chunk;
2403         }
2404
2405       if (size == 0)
2406         break; /* No more room for data */
2407
2408       if (str->flags & CODING_STATE_END)
2409         /* This means that on the previous iteration, we hit the EOF on
2410            the other end.  We loop once more so that mule_decode() can
2411            output any final stuff it may be holding, or any "go back
2412            to a sane state" escape sequences. (This latter makes sense
2413            during encoding.) */
2414         break;
2415
2416       /* Exhausted the runoff, so get some more.  DATA has at least
2417          SIZE bytes left of storage in it, so it's OK to read directly
2418          into it.  (We'll be overwriting above, after we've decoded it
2419          into the runoff.) */
2420       read_size = Lstream_read (str->other_end, data, size);
2421       if (read_size < 0)
2422         {
2423           error_occurred = 1;
2424           break;
2425         }
2426       if (read_size == 0)
2427         /* There might be some more end data produced in the translation.
2428            See the comment above. */
2429         str->flags |= CODING_STATE_END;
2430       mule_decode (stream, (Extbyte *) data, str->runoff, read_size);
2431     }
2432
2433   if (data - orig_data == 0)
2434     return error_occurred ? -1 : 0;
2435   else
2436     return data - orig_data;
2437 }
2438
2439 static Lstream_data_count
2440 decoding_writer (Lstream *stream, const unsigned char *data, Lstream_data_count size)
2441 {
2442   struct decoding_stream *str = DECODING_STREAM_DATA (stream);
2443   Lstream_data_count retval;
2444
2445   /* Decode all our data into the runoff, and then attempt to write
2446      it all out to the other end.  Remove whatever chunk we succeeded
2447      in writing. */
2448   mule_decode (stream, (Extbyte *) data, str->runoff, size);
2449   retval = Lstream_write (str->other_end, Dynarr_atp (str->runoff, 0),
2450                           Dynarr_length (str->runoff));
2451   if (retval > 0)
2452     Dynarr_delete_many (str->runoff, 0, retval);
2453   /* Do NOT return retval.  The return value indicates how much
2454      of the incoming data was written, not how many bytes were
2455      written. */
2456   return size;
2457 }
2458
2459 static void
2460 reset_decoding_stream (struct decoding_stream *str)
2461 {
2462 #ifdef MULE
2463   if (CODING_SYSTEM_TYPE (str->codesys) == CODESYS_ISO2022)
2464     {
2465       Lisp_Object coding_system;
2466       XSETCODING_SYSTEM (coding_system, str->codesys);
2467       reset_iso2022 (coding_system, &str->iso2022);
2468     }
2469   else if (CODING_SYSTEM_TYPE (str->codesys) == CODESYS_CCL)
2470     {
2471       setup_ccl_program (&str->ccl, CODING_SYSTEM_CCL_DECODE (str->codesys));
2472     }
2473   str->counter = 0;
2474 #endif /* MULE */
2475 #ifdef UTF2000
2476   str->bom_flag = 0;
2477   str->er_counter = 0;
2478   str->combined_char_count = 0;
2479   str->combining_table = Qnil;
2480 #endif
2481   if (CODING_SYSTEM_TYPE (str->codesys) == CODESYS_AUTODETECT
2482       || CODING_SYSTEM_EOL_TYPE (str->codesys) == EOL_AUTODETECT)
2483     {
2484       xzero (str->decst);
2485       str->decst.eol_type = EOL_AUTODETECT;
2486       str->decst.mask = ~0;
2487     }
2488   str->flags = str->cpos = 0;
2489 }
2490
2491 static int
2492 decoding_rewinder (Lstream *stream)
2493 {
2494   struct decoding_stream *str = DECODING_STREAM_DATA (stream);
2495   reset_decoding_stream (str);
2496   Dynarr_reset (str->runoff);
2497   return Lstream_rewind (str->other_end);
2498 }
2499
2500 static int
2501 decoding_seekable_p (Lstream *stream)
2502 {
2503   struct decoding_stream *str = DECODING_STREAM_DATA (stream);
2504   return Lstream_seekable_p (str->other_end);
2505 }
2506
2507 static int
2508 decoding_flusher (Lstream *stream)
2509 {
2510   struct decoding_stream *str = DECODING_STREAM_DATA (stream);
2511   return Lstream_flush (str->other_end);
2512 }
2513
2514 static int
2515 decoding_closer (Lstream *stream)
2516 {
2517   struct decoding_stream *str = DECODING_STREAM_DATA (stream);
2518   if (stream->flags & LSTREAM_FL_WRITE)
2519     {
2520       str->flags |= CODING_STATE_END;
2521       decoding_writer (stream, 0, 0);
2522     }
2523   Dynarr_free (str->runoff);
2524 #ifdef MULE
2525 #ifdef ENABLE_COMPOSITE_CHARS
2526   if (str->iso2022.composite_chars)
2527     Dynarr_free (str->iso2022.composite_chars);
2528 #endif
2529 #endif
2530   return Lstream_close (str->other_end);
2531 }
2532
2533 Lisp_Object
2534 decoding_stream_coding_system (Lstream *stream)
2535 {
2536   Lisp_Object coding_system;
2537   struct decoding_stream *str = DECODING_STREAM_DATA (stream);
2538
2539   XSETCODING_SYSTEM (coding_system, str->codesys);
2540   return subsidiary_coding_system (coding_system, str->eol_type);
2541 }
2542
2543 void
2544 set_decoding_stream_coding_system (Lstream *lstr, Lisp_Object codesys)
2545 {
2546   Lisp_Coding_System *cs = XCODING_SYSTEM (codesys);
2547   struct decoding_stream *str = DECODING_STREAM_DATA (lstr);
2548   str->codesys = cs;
2549   if (CODING_SYSTEM_EOL_TYPE (cs) != EOL_AUTODETECT)
2550     str->eol_type = CODING_SYSTEM_EOL_TYPE (cs);
2551   reset_decoding_stream (str);
2552 }
2553
2554 /* WARNING WARNING WARNING WARNING!!!!!  If you open up a decoding
2555    stream for writing, no automatic code detection will be performed.
2556    The reason for this is that automatic code detection requires a
2557    seekable input.  Things will also fail if you open a decoding
2558    stream for reading using a non-fully-specified coding system and
2559    a non-seekable input stream. */
2560
2561 static Lisp_Object
2562 make_decoding_stream_1 (Lstream *stream, Lisp_Object codesys,
2563                         const char *mode)
2564 {
2565   Lstream *lstr = Lstream_new (lstream_decoding, mode);
2566   struct decoding_stream *str = DECODING_STREAM_DATA (lstr);
2567   Lisp_Object obj;
2568
2569   xzero (*str);
2570   str->other_end = stream;
2571   str->runoff = (unsigned_char_dynarr *) Dynarr_new (unsigned_char);
2572   str->eol_type = EOL_AUTODETECT;
2573   if (!strcmp (mode, "r")
2574       && Lstream_seekable_p (stream))
2575     /* We can determine the coding system now. */
2576     determine_real_coding_system (stream, &codesys, &str->eol_type);
2577   set_decoding_stream_coding_system (lstr, codesys);
2578   str->decst.eol_type = str->eol_type;
2579   str->decst.mask = ~0;
2580   XSETLSTREAM (obj, lstr);
2581   return obj;
2582 }
2583
2584 Lisp_Object
2585 make_decoding_input_stream (Lstream *stream, Lisp_Object codesys)
2586 {
2587   return make_decoding_stream_1 (stream, codesys, "r");
2588 }
2589
2590 Lisp_Object
2591 make_decoding_output_stream (Lstream *stream, Lisp_Object codesys)
2592 {
2593   return make_decoding_stream_1 (stream, codesys, "w");
2594 }
2595
2596 /* Note: the decode_coding_* functions all take the same
2597    arguments as mule_decode(), which is to say some SRC data of
2598    size N, which is to be stored into dynamic array DST.
2599    DECODING is the stream within which the decoding is
2600    taking place, but no data is actually read from or
2601    written to that stream; that is handled in decoding_reader()
2602    or decoding_writer().  This allows the same functions to
2603    be used for both reading and writing. */
2604
2605 static void
2606 mule_decode (Lstream *decoding, const Extbyte *src,
2607              unsigned_char_dynarr *dst, Lstream_data_count n)
2608 {
2609   struct decoding_stream *str = DECODING_STREAM_DATA (decoding);
2610
2611   /* If necessary, do encoding-detection now.  We do this when
2612      we're a writing stream or a non-seekable reading stream,
2613      meaning that we can't just process the whole input,
2614      rewind, and start over. */
2615
2616   if (CODING_SYSTEM_TYPE (str->codesys) == CODESYS_AUTODETECT ||
2617       str->eol_type == EOL_AUTODETECT)
2618     {
2619       Lisp_Object codesys;
2620
2621       XSETCODING_SYSTEM (codesys, str->codesys);
2622       detect_coding_type (&str->decst, src, n,
2623                           CODING_SYSTEM_TYPE (str->codesys) !=
2624                           CODESYS_AUTODETECT);
2625       if (CODING_SYSTEM_TYPE (str->codesys) == CODESYS_AUTODETECT &&
2626           str->decst.mask != ~0)
2627         /* #### This is cheesy.  What we really ought to do is
2628            buffer up a certain amount of data so as to get a
2629            less random result. */
2630         codesys = coding_system_from_mask (str->decst.mask);
2631       str->eol_type = str->decst.eol_type;
2632       if (XCODING_SYSTEM (codesys) != str->codesys)
2633         {
2634           /* Preserve the CODING_STATE_END flag in case it was set.
2635              If we erase it, bad things might happen. */
2636           int was_end = str->flags & CODING_STATE_END;
2637           set_decoding_stream_coding_system (decoding, codesys);
2638           if (was_end)
2639             str->flags |= CODING_STATE_END;
2640         }
2641     }
2642
2643   switch (CODING_SYSTEM_TYPE (str->codesys))
2644     {
2645 #ifdef DEBUG_XEMACS
2646     case CODESYS_INTERNAL:
2647       Dynarr_add_many (dst, src, n);
2648       break;
2649 #endif
2650     case CODESYS_AUTODETECT:
2651       /* If we got this far and still haven't decided on the coding
2652          system, then do no conversion. */
2653     case CODESYS_NO_CONVERSION:
2654       decode_coding_no_conversion (decoding, src, dst, n);
2655       break;
2656 #ifdef MULE
2657     case CODESYS_SHIFT_JIS:
2658       decode_coding_sjis (decoding, src, dst, n);
2659       break;
2660     case CODESYS_BIG5:
2661       decode_coding_big5 (decoding, src, dst, n);
2662       break;
2663     case CODESYS_UCS4:
2664       decode_coding_ucs4 (decoding, src, dst, n);
2665       break;
2666     case CODESYS_UTF16:
2667       decode_coding_utf16 (decoding, src, dst, n);
2668       break;
2669     case CODESYS_UTF8:
2670       decode_coding_utf8 (decoding, src, dst, n);
2671       break;
2672     case CODESYS_CCL:
2673       str->ccl.last_block = str->flags & CODING_STATE_END;
2674       /* When applying ccl program to stream, MUST NOT set NULL
2675          pointer to src.  */
2676       ccl_driver (&str->ccl, (src ? (unsigned char *)src : (unsigned char*)""),
2677                   dst, n, 0, CCL_MODE_DECODING);
2678       break;
2679     case CODESYS_ISO2022:
2680       decode_coding_iso2022 (decoding, src, dst, n);
2681       break;
2682 #endif /* MULE */
2683     default:
2684       abort ();
2685     }
2686 }
2687
2688 DEFUN ("decode-coding-region", Fdecode_coding_region, 3, 4, 0, /*
2689 Decode the text between START and END which is encoded in CODING-SYSTEM.
2690 This is useful if you've read in encoded text from a file without decoding
2691 it (e.g. you read in a JIS-formatted file but used the `binary' or
2692 `no-conversion' coding system, so that it shows up as "^[$B!<!+^[(B").
2693 Return length of decoded text.
2694 BUFFER defaults to the current buffer if unspecified.
2695 */
2696        (start, end, coding_system, buffer))
2697 {
2698   Bufpos b, e;
2699   struct buffer *buf = decode_buffer (buffer, 0);
2700   Lisp_Object instream, lb_outstream, de_outstream, outstream;
2701   Lstream *istr, *ostr;
2702   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
2703
2704   get_buffer_range_char (buf, start, end, &b, &e, 0);
2705
2706   barf_if_buffer_read_only (buf, b, e);
2707
2708   coding_system = Fget_coding_system (coding_system);
2709   instream = make_lisp_buffer_input_stream  (buf, b, e, 0);
2710   lb_outstream = make_lisp_buffer_output_stream (buf, b, 0);
2711   de_outstream = make_decoding_output_stream (XLSTREAM (lb_outstream),
2712                                               coding_system);
2713   outstream = make_encoding_output_stream (XLSTREAM (de_outstream),
2714                                            Fget_coding_system (Qbinary));
2715   istr = XLSTREAM (instream);
2716   ostr = XLSTREAM (outstream);
2717   GCPRO4 (instream, lb_outstream, de_outstream, outstream);
2718
2719   /* The chain of streams looks like this:
2720
2721      [BUFFER] <----- send through
2722                      ------> [ENCODE AS BINARY]
2723                              ------> [DECODE AS SPECIFIED]
2724                                      ------> [BUFFER]
2725    */
2726
2727   while (1)
2728     {
2729       char tempbuf[1024]; /* some random amount */
2730       Bufpos newpos, even_newer_pos;
2731       Bufpos oldpos = lisp_buffer_stream_startpos (istr);
2732       Lstream_data_count size_in_bytes = Lstream_read (istr, tempbuf, sizeof (tempbuf));
2733
2734       if (!size_in_bytes)
2735         break;
2736       newpos = lisp_buffer_stream_startpos (istr);
2737       Lstream_write (ostr, tempbuf, size_in_bytes);
2738       even_newer_pos = lisp_buffer_stream_startpos (istr);
2739       buffer_delete_range (buf, even_newer_pos - (newpos - oldpos),
2740                            even_newer_pos, 0);
2741     }
2742   Lstream_close (istr);
2743   Lstream_close (ostr);
2744   UNGCPRO;
2745   Lstream_delete (istr);
2746   Lstream_delete (ostr);
2747   Lstream_delete (XLSTREAM (de_outstream));
2748   Lstream_delete (XLSTREAM (lb_outstream));
2749   return Qnil;
2750 }
2751
2752 \f
2753 /************************************************************************/
2754 /*           Converting to an external encoding ("encoding")            */
2755 /************************************************************************/
2756
2757 /* An encoding stream is an output stream.  When you create the
2758    stream, you specify the coding system that governs the encoding
2759    and another stream that the resulting encoded data is to be
2760    sent to, and then start sending data to it. */
2761
2762 #define ENCODING_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, encoding)
2763
2764 struct encoding_stream
2765 {
2766   /* Coding system that governs the conversion. */
2767   Lisp_Coding_System *codesys;
2768
2769   /* Stream that we read the encoded data from or
2770      write the decoded data to. */
2771   Lstream *other_end;
2772
2773   /* If we are reading, then we can return only a fixed amount of
2774      data, so if the conversion resulted in too much data, we store it
2775      here for retrieval the next time around. */
2776   unsigned_char_dynarr *runoff;
2777
2778   /* FLAGS holds flags indicating the current state of the encoding.
2779      Some of these flags are dependent on the coding system. */
2780   unsigned int flags;
2781
2782   /* CH holds a partially built-up character.  Since we only deal
2783      with one- and two-byte characters at the moment, we only use
2784      this to store the first byte of a two-byte character. */
2785   unsigned int ch;
2786 #ifdef MULE
2787   /* Additional information used by the ISO2022 encoder. */
2788   struct
2789     {
2790       /* CHARSET holds the character sets currently assigned to the G0
2791          through G3 registers.  It is initialized from the array
2792          INITIAL_CHARSET in CODESYS. */
2793       Lisp_Object charset[4];
2794
2795       /* Which registers are currently invoked into the left (GL) and
2796          right (GR) halves of the 8-bit encoding space? */
2797       int register_left, register_right;
2798
2799       /* Whether we need to explicitly designate the charset in the
2800          G? register before using it.  It is initialized from the
2801          array FORCE_CHARSET_ON_OUTPUT in CODESYS. */
2802       unsigned char force_charset_on_output[4];
2803
2804       /* Other state variables that need to be preserved across
2805          invocations. */
2806       Lisp_Object current_charset;
2807       int current_half;
2808       int current_char_boundary;
2809     } iso2022;
2810
2811   void (*encode_char) (struct encoding_stream *str, Emchar c,
2812                        unsigned_char_dynarr *dst, unsigned int *flags);
2813   void (*finish) (struct encoding_stream *str,
2814                   unsigned_char_dynarr *dst, unsigned int *flags);
2815
2816   /* Additional information (the state of the running CCL program)
2817      used by the CCL encoder. */
2818   struct ccl_program ccl;
2819 #endif /* MULE */
2820 };
2821
2822 static Lstream_data_count encoding_reader (Lstream *stream, unsigned char *data, Lstream_data_count size);
2823 static Lstream_data_count encoding_writer (Lstream *stream, const unsigned char *data,
2824                                 Lstream_data_count size);
2825 static int encoding_rewinder   (Lstream *stream);
2826 static int encoding_seekable_p (Lstream *stream);
2827 static int encoding_flusher    (Lstream *stream);
2828 static int encoding_closer     (Lstream *stream);
2829
2830 static Lisp_Object encoding_marker (Lisp_Object stream);
2831
2832 DEFINE_LSTREAM_IMPLEMENTATION ("encoding", lstream_encoding,
2833                                sizeof (struct encoding_stream));
2834
2835 static Lisp_Object
2836 encoding_marker (Lisp_Object stream)
2837 {
2838   Lstream *str = ENCODING_STREAM_DATA (XLSTREAM (stream))->other_end;
2839   Lisp_Object str_obj;
2840
2841   /* We do not need to mark the coding systems or charsets stored
2842      within the stream because they are stored in a global list
2843      and automatically marked. */
2844
2845   XSETLSTREAM (str_obj, str);
2846   mark_object (str_obj);
2847   if (str->imp->marker)
2848     return (str->imp->marker) (str_obj);
2849   else
2850     return Qnil;
2851 }
2852
2853 /* Read SIZE bytes of data and store it into DATA.  We are a encoding stream
2854    so we read data from the other end, encode it, and store it into DATA. */
2855
2856 static Lstream_data_count
2857 encoding_reader (Lstream *stream, unsigned char *data, Lstream_data_count size)
2858 {
2859   struct encoding_stream *str = ENCODING_STREAM_DATA (stream);
2860   unsigned char *orig_data = data;
2861   Lstream_data_count read_size;
2862   int error_occurred = 0;
2863
2864   /* We need to interface to mule_encode(), which expects to take some
2865      amount of data and store the result into a Dynarr.  We have
2866      mule_encode() store into str->runoff, and take data from there
2867      as necessary. */
2868
2869   /* We loop until we have enough data, reading chunks from the other
2870      end and encoding it. */
2871   while (1)
2872     {
2873       /* Take data from the runoff if we can.  Make sure to take at
2874          most SIZE bytes, and delete the data from the runoff. */
2875       if (Dynarr_length (str->runoff) > 0)
2876         {
2877           int chunk = min ((int) size, Dynarr_length (str->runoff));
2878           memcpy (data, Dynarr_atp (str->runoff, 0), chunk);
2879           Dynarr_delete_many (str->runoff, 0, chunk);
2880           data += chunk;
2881           size -= chunk;
2882         }
2883
2884       if (size == 0)
2885         break; /* No more room for data */
2886
2887       if (str->flags & CODING_STATE_END)
2888         /* This means that on the previous iteration, we hit the EOF on
2889            the other end.  We loop once more so that mule_encode() can
2890            output any final stuff it may be holding, or any "go back
2891            to a sane state" escape sequences. (This latter makes sense
2892            during encoding.) */
2893         break;
2894
2895       /* Exhausted the runoff, so get some more.  DATA at least SIZE bytes
2896          left of storage in it, so it's OK to read directly into it.
2897          (We'll be overwriting above, after we've encoded it into the
2898          runoff.) */
2899       read_size = Lstream_read (str->other_end, data, size);
2900       if (read_size < 0)
2901         {
2902           error_occurred = 1;
2903           break;
2904         }
2905       if (read_size == 0)
2906         /* There might be some more end data produced in the translation.
2907            See the comment above. */
2908         str->flags |= CODING_STATE_END;
2909       mule_encode (stream, data, str->runoff, read_size);
2910     }
2911
2912   if (data == orig_data)
2913     return error_occurred ? -1 : 0;
2914   else
2915     return data - orig_data;
2916 }
2917
2918 static Lstream_data_count
2919 encoding_writer (Lstream *stream, const unsigned char *data, Lstream_data_count size)
2920 {
2921   struct encoding_stream *str = ENCODING_STREAM_DATA (stream);
2922   Lstream_data_count retval;
2923
2924   /* Encode all our data into the runoff, and then attempt to write
2925      it all out to the other end.  Remove whatever chunk we succeeded
2926      in writing. */
2927   mule_encode (stream, data, str->runoff, size);
2928   retval = Lstream_write (str->other_end, Dynarr_atp (str->runoff, 0),
2929                           Dynarr_length (str->runoff));
2930   if (retval > 0)
2931     Dynarr_delete_many (str->runoff, 0, retval);
2932   /* Do NOT return retval.  The return value indicates how much
2933      of the incoming data was written, not how many bytes were
2934      written. */
2935   return size;
2936 }
2937
2938 static void
2939 reset_encoding_stream (struct encoding_stream *str)
2940 {
2941 #ifdef MULE
2942   switch (CODING_SYSTEM_TYPE (str->codesys))
2943     {
2944     case CODESYS_ISO2022:
2945       {
2946         int i;
2947
2948         str->encode_char = &char_encode_iso2022;
2949         str->finish = &char_finish_iso2022;
2950         for (i = 0; i < 4; i++)
2951           {
2952             str->iso2022.charset[i] =
2953               CODING_SYSTEM_ISO2022_INITIAL_CHARSET (str->codesys, i);
2954             str->iso2022.force_charset_on_output[i] =
2955               CODING_SYSTEM_ISO2022_FORCE_CHARSET_ON_OUTPUT (str->codesys, i);
2956           }
2957         str->iso2022.register_left = 0;
2958         str->iso2022.register_right = 1;
2959         str->iso2022.current_charset = Qnil;
2960         str->iso2022.current_half = 0;
2961         break;
2962       }
2963     case CODESYS_CCL:
2964       setup_ccl_program (&str->ccl, CODING_SYSTEM_CCL_ENCODE (str->codesys));
2965       break;
2966     case CODESYS_UTF8:
2967       str->encode_char = &char_encode_utf8;
2968       str->finish = &char_finish_utf8;
2969       break;
2970     case CODESYS_UTF16:
2971       str->encode_char = &char_encode_utf16;
2972       str->finish = &char_finish_utf16;
2973       break;
2974     case CODESYS_UCS4:
2975       str->encode_char = &char_encode_ucs4;
2976       str->finish = &char_finish_ucs4;
2977       break;
2978     case CODESYS_SHIFT_JIS:
2979       str->encode_char = &char_encode_shift_jis;
2980       str->finish = &char_finish_shift_jis;
2981       break;
2982     case CODESYS_BIG5:
2983       str->encode_char = &char_encode_big5;
2984       str->finish = &char_finish_big5;
2985       break;
2986     default:
2987       break;
2988     }
2989 #endif /* MULE */
2990   str->iso2022.current_char_boundary = 0;
2991   str->flags = str->ch = 0;
2992 }
2993
2994 static int
2995 encoding_rewinder (Lstream *stream)
2996 {
2997   struct encoding_stream *str = ENCODING_STREAM_DATA (stream);
2998   reset_encoding_stream (str);
2999   Dynarr_reset (str->runoff);
3000   return Lstream_rewind (str->other_end);
3001 }
3002
3003 static int
3004 encoding_seekable_p (Lstream *stream)
3005 {
3006   struct encoding_stream *str = ENCODING_STREAM_DATA (stream);
3007   return Lstream_seekable_p (str->other_end);
3008 }
3009
3010 static int
3011 encoding_flusher (Lstream *stream)
3012 {
3013   struct encoding_stream *str = ENCODING_STREAM_DATA (stream);
3014   return Lstream_flush (str->other_end);
3015 }
3016
3017 static int
3018 encoding_closer (Lstream *stream)
3019 {
3020   struct encoding_stream *str = ENCODING_STREAM_DATA (stream);
3021   if (stream->flags & LSTREAM_FL_WRITE)
3022     {
3023       str->flags |= CODING_STATE_END;
3024       encoding_writer (stream, 0, 0);
3025     }
3026   Dynarr_free (str->runoff);
3027   return Lstream_close (str->other_end);
3028 }
3029
3030 Lisp_Object
3031 encoding_stream_coding_system (Lstream *stream)
3032 {
3033   Lisp_Object coding_system;
3034   struct encoding_stream *str = ENCODING_STREAM_DATA (stream);
3035
3036   XSETCODING_SYSTEM (coding_system, str->codesys);
3037   return coding_system;
3038 }
3039
3040 void
3041 set_encoding_stream_coding_system (Lstream *lstr, Lisp_Object codesys)
3042 {
3043   Lisp_Coding_System *cs = XCODING_SYSTEM (codesys);
3044   struct encoding_stream *str = ENCODING_STREAM_DATA (lstr);
3045   str->codesys = cs;
3046   reset_encoding_stream (str);
3047 }
3048
3049 static Lisp_Object
3050 make_encoding_stream_1 (Lstream *stream, Lisp_Object codesys,
3051                         const char *mode)
3052 {
3053   Lstream *lstr = Lstream_new (lstream_encoding, mode);
3054   struct encoding_stream *str = ENCODING_STREAM_DATA (lstr);
3055   Lisp_Object obj;
3056
3057   xzero (*str);
3058   str->runoff = Dynarr_new (unsigned_char);
3059   str->other_end = stream;
3060   set_encoding_stream_coding_system (lstr, codesys);
3061   XSETLSTREAM (obj, lstr);
3062   return obj;
3063 }
3064
3065 Lisp_Object
3066 make_encoding_input_stream (Lstream *stream, Lisp_Object codesys)
3067 {
3068   return make_encoding_stream_1 (stream, codesys, "r");
3069 }
3070
3071 Lisp_Object
3072 make_encoding_output_stream (Lstream *stream, Lisp_Object codesys)
3073 {
3074   return make_encoding_stream_1 (stream, codesys, "w");
3075 }
3076
3077 /* Convert N bytes of internally-formatted data stored in SRC to an
3078    external format, according to the encoding stream ENCODING.
3079    Store the encoded data into DST. */
3080
3081 static void
3082 mule_encode (Lstream *encoding, const Bufbyte *src,
3083              unsigned_char_dynarr *dst, Lstream_data_count n)
3084 {
3085   struct encoding_stream *str = ENCODING_STREAM_DATA (encoding);
3086
3087   switch (CODING_SYSTEM_TYPE (str->codesys))
3088     {
3089 #ifdef DEBUG_XEMACS
3090     case CODESYS_INTERNAL:
3091       Dynarr_add_many (dst, src, n);
3092       break;
3093 #endif
3094     case CODESYS_AUTODETECT:
3095       /* If we got this far and still haven't decided on the coding
3096          system, then do no conversion. */
3097     case CODESYS_NO_CONVERSION:
3098       encode_coding_no_conversion (encoding, src, dst, n);
3099       break;
3100 #ifdef MULE
3101     case CODESYS_CCL:
3102       str->ccl.last_block = str->flags & CODING_STATE_END;
3103       /* When applying ccl program to stream, MUST NOT set NULL
3104          pointer to src.  */
3105       ccl_driver (&str->ccl, ((src) ? src : (unsigned char*)""),
3106                   dst, n, 0, CCL_MODE_ENCODING);
3107       break;
3108 #endif /* MULE */
3109     default:
3110       text_encode_generic (encoding, src, dst, n);
3111     }
3112 }
3113
3114 DEFUN ("encode-coding-region", Fencode_coding_region, 3, 4, 0, /*
3115 Encode the text between START and END using CODING-SYSTEM.
3116 This will, for example, convert Japanese characters into stuff such as
3117 "^[$B!<!+^[(B" if you use the JIS encoding.  Return length of encoded
3118 text.  BUFFER defaults to the current buffer if unspecified.
3119 */
3120        (start, end, coding_system, buffer))
3121 {
3122   Bufpos b, e;
3123   struct buffer *buf = decode_buffer (buffer, 0);
3124   Lisp_Object instream, lb_outstream, de_outstream, outstream;
3125   Lstream *istr, *ostr;
3126   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
3127
3128   get_buffer_range_char (buf, start, end, &b, &e, 0);
3129
3130   barf_if_buffer_read_only (buf, b, e);
3131
3132   coding_system = Fget_coding_system (coding_system);
3133   instream  = make_lisp_buffer_input_stream  (buf, b, e, 0);
3134   lb_outstream = make_lisp_buffer_output_stream (buf, b, 0);
3135   de_outstream = make_decoding_output_stream (XLSTREAM (lb_outstream),
3136                                               Fget_coding_system (Qbinary));
3137   outstream = make_encoding_output_stream (XLSTREAM (de_outstream),
3138                                            coding_system);
3139   istr = XLSTREAM (instream);
3140   ostr = XLSTREAM (outstream);
3141   GCPRO4 (instream, outstream, de_outstream, lb_outstream);
3142   /* The chain of streams looks like this:
3143
3144      [BUFFER] <----- send through
3145                      ------> [ENCODE AS SPECIFIED]
3146                              ------> [DECODE AS BINARY]
3147                                      ------> [BUFFER]
3148    */
3149   while (1)
3150     {
3151       char tempbuf[1024]; /* some random amount */
3152       Bufpos newpos, even_newer_pos;
3153       Bufpos oldpos = lisp_buffer_stream_startpos (istr);
3154       Lstream_data_count size_in_bytes = Lstream_read (istr, tempbuf, sizeof (tempbuf));
3155
3156       if (!size_in_bytes)
3157         break;
3158       newpos = lisp_buffer_stream_startpos (istr);
3159       Lstream_write (ostr, tempbuf, size_in_bytes);
3160       even_newer_pos = lisp_buffer_stream_startpos (istr);
3161       buffer_delete_range (buf, even_newer_pos - (newpos - oldpos),
3162                            even_newer_pos, 0);
3163     }
3164
3165   {
3166     Charcount retlen =
3167       lisp_buffer_stream_startpos (XLSTREAM (instream)) - b;
3168     Lstream_close (istr);
3169     Lstream_close (ostr);
3170     UNGCPRO;
3171     Lstream_delete (istr);
3172     Lstream_delete (ostr);
3173     Lstream_delete (XLSTREAM (de_outstream));
3174     Lstream_delete (XLSTREAM (lb_outstream));
3175     return make_int (retlen);
3176   }
3177 }
3178
3179 #ifdef MULE
3180 \f
3181 static void
3182 text_encode_generic (Lstream *encoding, const Bufbyte *src,
3183                      unsigned_char_dynarr *dst, Lstream_data_count n)
3184 {
3185   unsigned char c;
3186   unsigned char char_boundary;
3187   struct encoding_stream *str = ENCODING_STREAM_DATA (encoding);
3188   unsigned int flags          = str->flags;
3189   Emchar ch                   = str->ch;
3190
3191   char_boundary = str->iso2022.current_char_boundary;
3192
3193   while (n--)
3194     {
3195       c = *src++;
3196
3197       if (char_boundary == 0)
3198         {
3199           if (c >= 0xfc)
3200             {
3201               ch = c & 0x01;
3202               char_boundary = 5;
3203             }
3204           else if (c >= 0xf8)
3205             {
3206               ch = c & 0x03;
3207               char_boundary = 4;
3208             }
3209           else if (c >= 0xf0)
3210             {
3211               ch = c & 0x07;
3212               char_boundary = 3;
3213             }
3214           else if (c >= 0xe0)
3215             {
3216               ch = c & 0x0f;
3217               char_boundary = 2;
3218             }
3219           else if (c >= 0xc0)
3220             {
3221               ch = c & 0x1f;
3222               char_boundary = 1;
3223             }
3224           else
3225             (*str->encode_char) (str, c, dst, &flags);
3226         }
3227       else if (char_boundary == 1)
3228         {
3229           (*str->encode_char) (str, (ch << 6) | (c & 0x3f), dst, &flags);
3230           ch =0;
3231           char_boundary = 0;
3232         }
3233       else
3234         {
3235           ch = (ch << 6) | (c & 0x3f);
3236           char_boundary--;
3237         }
3238     }
3239
3240   if ((char_boundary == 0) && (flags & CODING_STATE_END))
3241     {
3242       (*str->finish) (str, dst, &flags);
3243     }
3244
3245   str->flags = flags;
3246   str->ch    = ch;
3247   str->iso2022.current_char_boundary = char_boundary;
3248 }
3249
3250 \f
3251 #ifdef UTF2000
3252 /************************************************************************/
3253 /*                          entity reference                            */
3254 /************************************************************************/
3255
3256 INLINE_HEADER void
3257 decode_flush_er_chars (struct decoding_stream *str, unsigned_char_dynarr* dst);
3258 INLINE_HEADER void
3259 decode_flush_er_chars (struct decoding_stream *str, unsigned_char_dynarr* dst)
3260 {
3261   if ( str->er_counter > 0)
3262     {
3263       Dynarr_add_many (dst, str->er_buf, str->er_counter);
3264       str->er_counter = 0;
3265     }
3266 }
3267
3268 EXFUN (Fregexp_quote, 1);
3269
3270 void decode_add_er_char (struct decoding_stream *str, Emchar character,
3271                          unsigned_char_dynarr* dst);
3272 void
3273 decode_add_er_char (struct decoding_stream *str, Emchar c,
3274                     unsigned_char_dynarr* dst)
3275 {
3276   if (str->er_counter == 0)
3277     {
3278       if (CODING_SYSTEM_USE_ENTITY_REFERENCE (str->codesys)
3279           && (c == '&') )
3280         {
3281           str->er_buf[0] = '&';
3282           str->er_counter++;
3283         }
3284       else
3285         DECODE_ADD_UCS_CHAR (c, dst);
3286     }
3287   else if (c == ';')
3288     {
3289       Lisp_Object string = make_string (str->er_buf,
3290                                         str->er_counter);
3291       Lisp_Object rest;
3292       Lisp_Object cell;
3293       Lisp_Object ret;
3294       Lisp_Object pat;
3295       Lisp_Object ccs;
3296       Lisp_Object char_type;
3297       int base;
3298
3299       for ( rest = Vcoded_charset_entity_reference_alist;
3300             !NILP (rest); rest = Fcdr (rest) )
3301         {                     
3302           cell = Fcar (rest);
3303           ccs = Fcar (cell);
3304           if (CONSP (ccs))
3305             {
3306               char_type = XCDR (ccs);
3307               ccs = XCAR (ccs);
3308             }
3309           else
3310             char_type = Qnil;
3311           if (NILP (ccs = Ffind_charset (ccs)))
3312             continue;
3313
3314           cell = Fcdr (cell);
3315           ret = Fcar (cell);
3316           if (STRINGP (ret))
3317             pat = ret;
3318           else
3319             continue;
3320           pat = Fregexp_quote (pat);
3321
3322           cell = Fcdr (cell);
3323           cell = Fcdr (cell);
3324           ret = Fcar (cell);
3325           if (EQ (ret, Qd))
3326             {
3327               pat = concat3 (build_string ("^&"),
3328                              pat, build_string ("\\([0-9]+\\)$"));
3329               base = 10;
3330             }
3331           else if (EQ (ret, Qx))
3332             {
3333               pat = concat3 (build_string ("^&"),
3334                              pat, build_string ("\\([0-9a-f]+\\)$"));
3335               base = 16;
3336             }
3337           else if (EQ (ret, QX))
3338             {
3339               pat = concat3 (build_string ("^&"),
3340                              pat, build_string ("\\([0-9A-F]+\\)$"));
3341               base = 16;
3342             }
3343           else
3344             continue;
3345
3346           if (!NILP (Fstring_match (pat, string, Qnil, Qnil)))
3347             {
3348               int code
3349                 = XINT (Fstring_to_number
3350                         (Fsubstring (string,
3351                                      Fmatch_beginning (make_int (1)),
3352                                      Fmatch_end (make_int (1))),
3353                          make_int (base)));
3354               Emchar chr
3355                 = NILP (char_type)
3356                 ? DECODE_CHAR (ccs, code, 0)
3357                 : decode_builtin_char (ccs, code);
3358
3359               if ( chr >= 0 )
3360                 DECODE_ADD_UCS_CHAR (chr, dst);
3361               else
3362                 {
3363                   Dynarr_add_many (dst, str->er_buf, str->er_counter);
3364                   Dynarr_add (dst, ';');
3365                 }
3366
3367               goto decoded;
3368             }
3369         }
3370       if (!NILP (Fstring_match (build_string ("^&MCS-\\([0-9A-F]+\\)$"),
3371                                 string, Qnil, Qnil)))
3372         {
3373           int code
3374             = XUINT (Fstring_to_number
3375                      (Fsubstring (string,
3376                                   Fmatch_beginning (make_int (1)),
3377                                   Fmatch_end (make_int (1))),
3378                       make_int (16)));
3379
3380           DECODE_ADD_UCS_CHAR (code, dst);
3381         }
3382       else
3383         {
3384           Dynarr_add_many (dst, str->er_buf, str->er_counter);
3385           Dynarr_add (dst, ';');
3386         }
3387     decoded:
3388       str->er_counter = 0;
3389     }
3390   else if ( (str->er_counter >= ER_BUF_SIZE) || (c >= 0x7F) )
3391     {
3392       Dynarr_add_many (dst, str->er_buf, str->er_counter);
3393       str->er_counter = 0;
3394       DECODE_ADD_UCS_CHAR (c, dst);
3395     }
3396   else
3397     str->er_buf[str->er_counter++] = c;
3398 }
3399
3400 void char_encode_as_entity_reference (Emchar ch, char* buf);
3401 void
3402 char_encode_as_entity_reference (Emchar ch, char* buf)
3403 {
3404   Lisp_Object rest = Vcoded_charset_entity_reference_alist;
3405   Lisp_Object cell;
3406   Lisp_Object ccs;
3407   Lisp_Object char_type;
3408   int format_columns, idx;
3409   char format[ER_BUF_SIZE];
3410
3411   while (!NILP (rest))
3412     {
3413       cell = Fcar (rest);
3414       ccs = Fcar (cell);
3415       if (CONSP (ccs))
3416         {
3417           char_type = XCDR (ccs);
3418           ccs = XCAR (ccs);
3419         }
3420       else
3421         char_type = Qnil;
3422       if (!NILP (ccs = Ffind_charset (ccs)))
3423         {
3424           int code_point
3425             = charset_code_point (ccs, ch,
3426                                   NILP (char_type) ?
3427                                   CHAR_ALL : CHAR_ISOLATED_ONLY );
3428
3429           if ( (code_point >= 0)
3430                && ( NILP (char_type)
3431 #if 1
3432                     || ( charset_code_point (ccs, ch, CHAR_DEFINED_ONLY)
3433                          == -1 )
3434 #endif
3435 #if 0
3436                     || ( DECODE_CHAR (ccs, code_point, 0) != ch )
3437 #endif
3438                     )
3439                )
3440             {
3441               Lisp_Object ret;
3442
3443               cell = Fcdr (cell);
3444               ret = Fcar (cell);
3445               if ( STRINGP (ret) &&
3446                    ( (idx = XSTRING_LENGTH (ret)) <= (ER_BUF_SIZE - 4) ) )
3447                 {
3448                   format[0] = '&';
3449                   strncpy (&format[1], XSTRING_DATA (ret), idx);
3450                   idx++;
3451                 }
3452               else
3453                 goto try_next;
3454
3455               cell = Fcdr (cell);
3456               ret = Fcar (cell);
3457               if (INTP (ret))
3458                 {
3459                   format[idx++] = '%';
3460                   format_columns = XINT (ret);
3461                   if ( (2 <= format_columns) && (format_columns <= 8)
3462                        && (idx + format_columns <= ER_BUF_SIZE - 1) )
3463                     {
3464                       format [idx++] = '0';
3465                       format [idx++] = '0' + format_columns;
3466                     }
3467                 }
3468               else
3469                 goto try_next;
3470
3471               cell = Fcdr (cell);
3472               ret = Fcar (cell);
3473               if (EQ (ret, Qd))
3474                 format [idx++] = 'd';
3475               else if (EQ (ret, Qx))
3476                 format [idx++] = 'x';
3477               else if (EQ (ret, QX))
3478                 format [idx++] = 'X';
3479               else
3480                 goto try_next;
3481               format [idx++] = ';';
3482               format [idx++] = 0;
3483
3484               sprintf (buf, format, code_point);
3485               return;
3486             }
3487         }
3488     try_next:
3489       rest = Fcdr (rest);
3490     }
3491   sprintf (buf, "&MCS-%08X;", ch);
3492 }
3493
3494 \f
3495 /************************************************************************/
3496 /*                          character composition                       */
3497 /************************************************************************/
3498 extern Lisp_Object Qcomposition, Qrep_decomposition;
3499
3500 INLINE_HEADER void
3501 COMPOSE_FLUSH_CHARS (struct decoding_stream *str, unsigned_char_dynarr* dst);
3502 INLINE_HEADER void
3503 COMPOSE_FLUSH_CHARS (struct decoding_stream *str, unsigned_char_dynarr* dst)
3504 {
3505   unsigned i;
3506
3507   for (i = 0; i < str->combined_char_count; i++)
3508     decode_add_er_char (str, str->combined_chars[i], dst);
3509   str->combined_char_count = 0;
3510   str->combining_table = Qnil;
3511 }
3512
3513 void COMPOSE_ADD_CHAR (struct decoding_stream *str, Emchar character,
3514                        unsigned_char_dynarr* dst);
3515 void
3516 COMPOSE_ADD_CHAR (struct decoding_stream *str,
3517                   Emchar character, unsigned_char_dynarr* dst)
3518 {
3519   if (CODING_SYSTEM_DISABLE_COMPOSITION (str->codesys))
3520     decode_add_er_char (str, character, dst);
3521   else if (!CONSP (str->combining_table))
3522     {
3523       Lisp_Object ret
3524         = Fchar_feature (make_char (character), Qcomposition, Qnil,
3525                          Qnil, Qnil);
3526
3527       if (NILP (ret))
3528         decode_add_er_char (str, character, dst);
3529       else
3530         {
3531           str->combined_chars[0] = character;
3532           str->combined_char_count = 1;
3533           str->combining_table = ret;
3534         }
3535     }
3536   else
3537     {
3538       Lisp_Object ret
3539         = Fcdr (Fassq (make_char (character), str->combining_table));
3540
3541       if (CHARP (ret))
3542         {
3543           Emchar char2 = XCHARVAL (ret);
3544           Lisp_Object ret2 = Fchar_feature (ret, Qcomposition, Qnil,
3545                                             Qnil, Qnil);
3546
3547           if (NILP (ret2))
3548             {
3549               decode_add_er_char (str, char2, dst);
3550               str->combined_char_count = 0;
3551               str->combining_table = Qnil;
3552             }
3553           else
3554             {
3555               str->combined_chars[0] = char2;
3556               str->combined_char_count = 1;
3557               str->combining_table = ret2;
3558             }
3559         }
3560       else
3561         {
3562           ret = Fchar_feature (make_char (character), Qcomposition, Qnil,
3563                                Qnil, Qnil);
3564
3565           COMPOSE_FLUSH_CHARS (str, dst);
3566           if (NILP (ret))
3567             decode_add_er_char (str, character, dst);
3568           else
3569             {
3570               str->combined_chars[0] = character;
3571               str->combined_char_count = 1;
3572               str->combining_table = ret;
3573             }
3574         }
3575     }
3576 }
3577 #else /* not UTF2000 */
3578 #define COMPOSE_FLUSH_CHARS(str, dst)
3579 #define COMPOSE_ADD_CHAR(str, ch, dst) DECODE_ADD_UCS_CHAR (ch, dst)
3580 #endif /* UTF2000 */
3581
3582 \f
3583 /************************************************************************/
3584 /*                          Shift-JIS methods                           */
3585 /************************************************************************/
3586
3587 /* Shift-JIS is a coding system encoding three character sets: ASCII, right
3588    half of JISX0201-Kana, and JISX0208.  An ASCII character is encoded
3589    as is.  A character of JISX0201-Kana (DIMENSION1_CHARS94 character set) is
3590    encoded by "position-code + 0x80".  A character of JISX0208
3591    (DIMENSION2_CHARS94 character set) is encoded in 2-byte but two
3592    position-codes are divided and shifted so that it fit in the range
3593    below.
3594
3595    --- CODE RANGE of Shift-JIS ---
3596    (character set)      (range)
3597    ASCII                0x00 .. 0x7F
3598    JISX0201-Kana        0xA0 .. 0xDF
3599    JISX0208 (1st byte)  0x80 .. 0x9F and 0xE0 .. 0xEF
3600             (2nd byte)  0x40 .. 0x7E and 0x80 .. 0xFC
3601    -------------------------------
3602
3603 */
3604
3605 /* Is this the first byte of a Shift-JIS two-byte char? */
3606
3607 #define BYTE_SJIS_TWO_BYTE_1_P(c) \
3608   (((c) >= 0x81 && (c) <= 0x9F) || ((c) >= 0xE0 && (c) <= 0xEF))
3609
3610 /* Is this the second byte of a Shift-JIS two-byte char? */
3611
3612 #define BYTE_SJIS_TWO_BYTE_2_P(c) \
3613   (((c) >= 0x40 && (c) <= 0x7E) || ((c) >= 0x80 && (c) <= 0xFC))
3614
3615 #define BYTE_SJIS_KATAKANA_P(c) \
3616   ((c) >= 0xA1 && (c) <= 0xDF)
3617
3618 static int
3619 detect_coding_sjis (struct detection_state *st, const Extbyte *src, Lstream_data_count n)
3620 {
3621   while (n--)
3622     {
3623       unsigned char c = *(unsigned char *)src++;
3624       if (c == ISO_CODE_ESC || c == ISO_CODE_SI || c == ISO_CODE_SO)
3625         return 0;
3626       if (st->shift_jis.in_second_byte)
3627         {
3628           st->shift_jis.in_second_byte = 0;
3629           if (c < 0x40)
3630             return 0;
3631         }
3632       else if ((c >= 0x80 && c < 0xA0) || c >= 0xE0)
3633         st->shift_jis.in_second_byte = 1;
3634     }
3635   return CODING_CATEGORY_SHIFT_JIS_MASK;
3636 }
3637
3638 /* Convert Shift-JIS data to internal format. */
3639
3640 static void
3641 decode_coding_sjis (Lstream *decoding, const Extbyte *src,
3642                     unsigned_char_dynarr *dst, Lstream_data_count n)
3643 {
3644   struct decoding_stream *str = DECODING_STREAM_DATA (decoding);
3645   unsigned int flags  = str->flags;
3646   unsigned int cpos   = str->cpos;
3647   eol_type_t eol_type = str->eol_type;
3648
3649   while (n--)
3650     {
3651       unsigned char c = *(unsigned char *)src++;
3652
3653       if (cpos)
3654         {
3655           /* Previous character was first byte of Shift-JIS Kanji char. */
3656           if (BYTE_SJIS_TWO_BYTE_2_P (c))
3657             {
3658               unsigned char e1, e2;
3659
3660               DECODE_SJIS (cpos, c, e1, e2);
3661 #ifdef UTF2000
3662               DECODE_ADD_UCS_CHAR(MAKE_CHAR(Vcharset_japanese_jisx0208,
3663                                             e1 & 0x7F,
3664                                             e2 & 0x7F), dst);
3665 #else
3666               Dynarr_add (dst, LEADING_BYTE_JAPANESE_JISX0208);
3667               Dynarr_add (dst, e1);
3668               Dynarr_add (dst, e2);
3669 #endif
3670             }
3671           else
3672             {
3673               DECODE_ADD_BINARY_CHAR (cpos, dst);
3674               DECODE_ADD_BINARY_CHAR (c, dst);
3675             }
3676           cpos = 0;
3677         }
3678       else
3679         {
3680           DECODE_HANDLE_EOL_TYPE (eol_type, c, flags, dst);
3681           if (BYTE_SJIS_TWO_BYTE_1_P (c))
3682             cpos = c;
3683           else if (BYTE_SJIS_KATAKANA_P (c))
3684             {
3685 #ifdef UTF2000
3686               DECODE_ADD_UCS_CHAR(MAKE_CHAR(Vcharset_katakana_jisx0201,
3687                                             c & 0x7F, 0), dst);
3688 #else
3689               Dynarr_add (dst, LEADING_BYTE_KATAKANA_JISX0201);
3690               Dynarr_add (dst, c);
3691 #endif
3692             }
3693 #ifdef UTF2000
3694           else if (c > 32)
3695             DECODE_ADD_UCS_CHAR(MAKE_CHAR(Vcharset_latin_jisx0201,
3696                                           c, 0), dst);
3697 #endif
3698           else
3699             DECODE_ADD_BINARY_CHAR (c, dst);
3700         }
3701     label_continue_loop:;
3702     }
3703
3704   DECODE_HANDLE_END_OF_CONVERSION (flags, cpos, dst);
3705
3706   str->flags = flags;
3707   str->cpos  = cpos;
3708 }
3709
3710 /* Convert internal character representation to Shift_JIS. */
3711
3712 void
3713 char_encode_shift_jis (struct encoding_stream *str, Emchar ch,
3714                        unsigned_char_dynarr *dst, unsigned int *flags)
3715 {
3716   eol_type_t eol_type = CODING_SYSTEM_EOL_TYPE (str->codesys);
3717
3718   if (ch == '\n')
3719     {
3720       if (eol_type != EOL_LF && eol_type != EOL_AUTODETECT)
3721         Dynarr_add (dst, '\r');
3722       if (eol_type != EOL_CR)
3723         Dynarr_add (dst, ch);
3724     }
3725   else
3726     {
3727       unsigned int s1, s2;
3728 #ifdef UTF2000
3729       int code_point = charset_code_point (Vcharset_latin_jisx0201, ch, 0);
3730
3731       if (code_point >= 0)
3732         Dynarr_add (dst, code_point);
3733       else if ((code_point
3734                 = charset_code_point (Vcharset_japanese_jisx0208_1990, ch, 0))
3735                >= 0)
3736         {
3737           ENCODE_SJIS ((code_point >> 8) | 0x80,
3738                        (code_point & 0xFF) | 0x80, s1, s2);
3739           Dynarr_add (dst, s1);
3740           Dynarr_add (dst, s2);
3741         }
3742       else if ((code_point
3743                 = charset_code_point (Vcharset_katakana_jisx0201, ch, 0))
3744                >= 0)
3745         Dynarr_add (dst, code_point | 0x80);
3746       else if ((code_point
3747                 = charset_code_point (Vcharset_japanese_jisx0208, ch, 0))
3748                >= 0)
3749         {
3750           ENCODE_SJIS ((code_point >> 8) | 0x80,
3751                        (code_point & 0xFF) | 0x80, s1, s2);
3752           Dynarr_add (dst, s1);
3753           Dynarr_add (dst, s2);
3754         }
3755       else if ((code_point = charset_code_point (Vcharset_ascii, ch, 0))
3756                >= 0)
3757         Dynarr_add (dst, code_point);
3758       else
3759         Dynarr_add (dst, '?');
3760 #else
3761       Lisp_Object charset;
3762       unsigned int c1, c2;
3763
3764       BREAKUP_CHAR (ch, charset, c1, c2);
3765           
3766       if (EQ(charset, Vcharset_katakana_jisx0201))
3767         {
3768           Dynarr_add (dst, c1 | 0x80);
3769         }
3770       else if (c2 == 0)
3771         {
3772           Dynarr_add (dst, c1);
3773         }
3774       else if (EQ(charset, Vcharset_japanese_jisx0208))
3775         {
3776           ENCODE_SJIS (c1 | 0x80, c2 | 0x80, s1, s2);
3777           Dynarr_add (dst, s1);
3778           Dynarr_add (dst, s2);
3779         }
3780       else
3781         Dynarr_add (dst, '?');
3782 #endif
3783     }
3784 }
3785
3786 void
3787 char_finish_shift_jis (struct encoding_stream *str, unsigned_char_dynarr *dst,
3788                        unsigned int *flags)
3789 {
3790 }
3791
3792 DEFUN ("decode-shift-jis-char", Fdecode_shift_jis_char, 1, 1, 0, /*
3793 Decode a JISX0208 character of Shift-JIS coding-system.
3794 CODE is the character code in Shift-JIS as a cons of type bytes.
3795 Return the corresponding character.
3796 */
3797        (code))
3798 {
3799   unsigned char c1, c2, s1, s2;
3800
3801   CHECK_CONS (code);
3802   CHECK_INT (XCAR (code));
3803   CHECK_INT (XCDR (code));
3804   s1 = XINT (XCAR (code));
3805   s2 = XINT (XCDR (code));
3806   if (BYTE_SJIS_TWO_BYTE_1_P (s1) &&
3807       BYTE_SJIS_TWO_BYTE_2_P (s2))
3808     {
3809       DECODE_SJIS (s1, s2, c1, c2);
3810       return make_char (MAKE_CHAR (Vcharset_japanese_jisx0208,
3811                                    c1 & 0x7F, c2 & 0x7F));
3812     }
3813   else
3814     return Qnil;
3815 }
3816
3817 DEFUN ("encode-shift-jis-char", Fencode_shift_jis_char, 1, 1, 0, /*
3818 Encode a JISX0208 character CHARACTER to SHIFT-JIS coding-system.
3819 Return the corresponding character code in SHIFT-JIS as a cons of two bytes.
3820 */
3821        (character))
3822 {
3823   Lisp_Object charset;
3824   int c1, c2, s1, s2;
3825
3826   CHECK_CHAR_COERCE_INT (character);
3827   BREAKUP_CHAR (XCHAR (character), charset, c1, c2);
3828   if (EQ (charset, Vcharset_japanese_jisx0208))
3829     {
3830       ENCODE_SJIS (c1 | 0x80, c2 | 0x80, s1, s2);
3831       return Fcons (make_int (s1), make_int (s2));
3832     }
3833   else
3834     return Qnil;
3835 }
3836
3837 \f
3838 /************************************************************************/
3839 /*                            Big5 methods                              */
3840 /************************************************************************/
3841
3842 /* BIG5 is a coding system encoding two character sets: ASCII and
3843    Big5.  An ASCII character is encoded as is.  Big5 is a two-byte
3844    character set and is encoded in two-byte.
3845
3846    --- CODE RANGE of BIG5 ---
3847    (character set)      (range)
3848    ASCII                0x00 .. 0x7F
3849    Big5 (1st byte)      0xA1 .. 0xFE
3850         (2nd byte)      0x40 .. 0x7E and 0xA1 .. 0xFE
3851    --------------------------
3852
3853    Since the number of characters in Big5 is larger than maximum
3854    characters in Emacs' charset (96x96), it can't be handled as one
3855    charset.  So, in Emacs, Big5 is divided into two: `charset-big5-1'
3856    and `charset-big5-2'.  Both <type>s are DIMENSION2_CHARS94.  The former
3857    contains frequently used characters and the latter contains less
3858    frequently used characters.  */
3859
3860 #ifdef UTF2000
3861 #define BYTE_BIG5_TWO_BYTE_1_P(c) \
3862   ((c) >= 0x81 && (c) <= 0xFE)
3863 #else
3864 #define BYTE_BIG5_TWO_BYTE_1_P(c) \
3865   ((c) >= 0xA1 && (c) <= 0xFE)
3866 #endif
3867
3868 /* Is this the second byte of a Shift-JIS two-byte char? */
3869
3870 #define BYTE_BIG5_TWO_BYTE_2_P(c) \
3871   (((c) >= 0x40 && (c) <= 0x7E) || ((c) >= 0xA1 && (c) <= 0xFE))
3872
3873 /* Number of Big5 characters which have the same code in 1st byte.  */
3874
3875 #define BIG5_SAME_ROW (0xFF - 0xA1 + 0x7F - 0x40)
3876
3877 /* Code conversion macros.  These are macros because they are used in
3878    inner loops during code conversion.
3879
3880    Note that temporary variables in macros introduce the classic
3881    dynamic-scoping problems with variable names.  We use capital-
3882    lettered variables in the assumption that XEmacs does not use
3883    capital letters in variables except in a very formalized way
3884    (e.g. Qstring). */
3885
3886 /* Convert Big5 code (b1, b2) into its internal string representation
3887    (lb, c1, c2). */
3888
3889 /* There is a much simpler way to split the Big5 charset into two.
3890    For the moment I'm going to leave the algorithm as-is because it
3891    claims to separate out the most-used characters into a single
3892    charset, which perhaps will lead to optimizations in various
3893    places.
3894
3895    The way the algorithm works is something like this:
3896
3897    Big5 can be viewed as a 94x157 charset, where the row is
3898    encoded into the bytes 0xA1 .. 0xFE and the column is encoded
3899    into the bytes 0x40 .. 0x7E and 0xA1 .. 0xFE.  As for frequency,
3900    the split between low and high column numbers is apparently
3901    meaningless; ascending rows produce less and less frequent chars.
3902    Therefore, we assign the lower half of rows (0xA1 .. 0xC8) to
3903    the first charset, and the upper half (0xC9 .. 0xFE) to the
3904    second.  To do the conversion, we convert the character into
3905    a single number where 0 .. 156 is the first row, 157 .. 313
3906    is the second, etc.  That way, the characters are ordered by
3907    decreasing frequency.  Then we just chop the space in two
3908    and coerce the result into a 94x94 space.
3909    */
3910
3911 #define DECODE_BIG5(b1, b2, lb, c1, c2) do                              \
3912 {                                                                       \
3913   int B1 = b1, B2 = b2;                                                 \
3914   unsigned int I                                                        \
3915     = (B1 - 0xA1) * BIG5_SAME_ROW + B2 - (B2 < 0x7F ? 0x40 : 0x62);     \
3916                                                                         \
3917   if (B1 < 0xC9)                                                        \
3918     {                                                                   \
3919       lb = LEADING_BYTE_CHINESE_BIG5_1;                                 \
3920     }                                                                   \
3921   else                                                                  \
3922     {                                                                   \
3923       lb = LEADING_BYTE_CHINESE_BIG5_2;                                 \
3924       I -= (BIG5_SAME_ROW) * (0xC9 - 0xA1);                             \
3925     }                                                                   \
3926   c1 = I / (0xFF - 0xA1) + 0xA1;                                        \
3927   c2 = I % (0xFF - 0xA1) + 0xA1;                                        \
3928 } while (0)
3929
3930 /* Convert the internal string representation of a Big5 character
3931    (lb, c1, c2) into Big5 code (b1, b2). */
3932
3933 #define ENCODE_BIG5(lb, c1, c2, b1, b2) do                              \
3934 {                                                                       \
3935   unsigned int I = ((c1) - 0xA1) * (0xFF - 0xA1) + ((c2) - 0xA1);       \
3936                                                                         \
3937   if (lb == LEADING_BYTE_CHINESE_BIG5_2)                                \
3938     {                                                                   \
3939       I += BIG5_SAME_ROW * (0xC9 - 0xA1);                               \
3940     }                                                                   \
3941   b1 = I / BIG5_SAME_ROW + 0xA1;                                        \
3942   b2 = I % BIG5_SAME_ROW;                                               \
3943   b2 += b2 < 0x3F ? 0x40 : 0x62;                                        \
3944 } while (0)
3945
3946 static int
3947 detect_coding_big5 (struct detection_state *st, const Extbyte *src, Lstream_data_count n)
3948 {
3949   while (n--)
3950     {
3951       unsigned char c = *(unsigned char *)src++;
3952       if (c == ISO_CODE_ESC || c == ISO_CODE_SI || c == ISO_CODE_SO
3953 #ifndef UTF2000
3954           || (c >= 0x80 && c <= 0xA0)
3955 #endif
3956           )
3957         return 0;
3958       if (st->big5.in_second_byte)
3959         {
3960           st->big5.in_second_byte = 0;
3961           if (c < 0x40 || (c >= 0x80 && c <= 0xA0))
3962             return 0;
3963         }
3964       else if (
3965 #ifdef UTF2000
3966                c >= 0x81
3967 #else
3968                c >= 0xA1
3969 #endif
3970                )
3971         st->big5.in_second_byte = 1;
3972     }
3973   return CODING_CATEGORY_BIG5_MASK;
3974 }
3975
3976 /* Convert Big5 data to internal format. */
3977
3978 static void
3979 decode_coding_big5 (Lstream *decoding, const Extbyte *src,
3980                     unsigned_char_dynarr *dst, Lstream_data_count n)
3981 {
3982   struct decoding_stream *str = DECODING_STREAM_DATA (decoding);
3983   unsigned int flags  = str->flags;
3984   unsigned int cpos   = str->cpos;
3985   eol_type_t eol_type = str->eol_type;
3986 #ifdef UTF2000
3987   Lisp_Object ccs
3988     = CODING_SYSTEM_ISO2022_INITIAL_CHARSET (DECODING_STREAM_DATA
3989                                              (decoding)->codesys, 1);
3990 #endif
3991
3992   while (n--)
3993     {
3994       unsigned char c = *(unsigned char *)src++;
3995       if (cpos)
3996         {
3997           /* Previous character was first byte of Big5 char. */
3998           if (BYTE_BIG5_TWO_BYTE_2_P (c))
3999             {
4000 #ifdef UTF2000
4001               int code_point = (cpos << 8) | c;
4002               Emchar char_id = decode_defined_char (ccs, code_point, 0);
4003
4004               if (char_id < 0)
4005                 char_id
4006                   = DECODE_CHAR (Vcharset_chinese_big5, code_point, 0);
4007               DECODE_ADD_UCS_CHAR (char_id, dst);
4008 #else
4009               unsigned char b1, b2, b3;
4010               DECODE_BIG5 (cpos, c, b1, b2, b3);
4011               Dynarr_add (dst, b1);
4012               Dynarr_add (dst, b2);
4013               Dynarr_add (dst, b3);
4014 #endif
4015             }
4016           else
4017             {
4018               DECODE_ADD_BINARY_CHAR (cpos, dst);
4019               DECODE_ADD_BINARY_CHAR (c, dst);
4020             }
4021           cpos = 0;
4022         }
4023       else
4024         {
4025           DECODE_HANDLE_EOL_TYPE (eol_type, c, flags, dst);
4026           if (BYTE_BIG5_TWO_BYTE_1_P (c))
4027             {
4028               decode_flush_er_chars (str, dst);
4029               cpos = c;
4030             }
4031           else if ( c < ' ' )
4032             {
4033               decode_flush_er_chars (str, dst);
4034               DECODE_HANDLE_EOL_TYPE (eol_type, c, flags, dst);
4035               DECODE_ADD_BINARY_CHAR (c, dst);
4036             }
4037           else
4038             {
4039               /* DECODE_ADD_BINARY_CHAR (c, dst); */
4040               decode_add_er_char (str, c, dst);
4041             }
4042         }
4043     label_continue_loop:;
4044     }
4045
4046   /* DECODE_HANDLE_END_OF_CONVERSION (flags, cpos, dst); */
4047   if (flags & CODING_STATE_END)
4048     {
4049       decode_flush_er_chars (str, dst);
4050       DECODE_OUTPUT_PARTIAL_CHAR (cpos);
4051       if (flags & CODING_STATE_CR)
4052         Dynarr_add (dst, '\r');
4053     }
4054
4055   str->flags = flags;
4056   str->cpos  = cpos;
4057 }
4058
4059 /* Convert internally-formatted data to Big5. */
4060
4061 void
4062 char_encode_big5 (struct encoding_stream *str, Emchar ch,
4063                   unsigned_char_dynarr *dst, unsigned int *flags)
4064 {
4065   eol_type_t eol_type = CODING_SYSTEM_EOL_TYPE (str->codesys);
4066
4067   if (ch == '\n')
4068     {
4069       if (eol_type != EOL_LF && eol_type != EOL_AUTODETECT)
4070         Dynarr_add (dst, '\r');
4071       if (eol_type != EOL_CR)
4072         Dynarr_add (dst, ch);
4073     }
4074   else
4075     {
4076 #ifdef UTF2000
4077       int code_point;
4078       Lisp_Object ccs
4079         = CODING_SYSTEM_ISO2022_INITIAL_CHARSET (str->codesys, 1);
4080
4081       if ((code_point = charset_code_point (Vcharset_ascii, ch, 0)) >= 0)
4082         Dynarr_add (dst, code_point);
4083       else if ((code_point = charset_code_point (ccs, ch, 0)) >= 0)
4084         {
4085           Dynarr_add (dst, code_point >> 8);
4086           Dynarr_add (dst, code_point & 0xFF);
4087         }
4088       else if ((code_point
4089                 = charset_code_point (Vcharset_chinese_big5, ch, 0)) >= 0)
4090         {
4091           Dynarr_add (dst, code_point >> 8);
4092           Dynarr_add (dst, code_point & 0xFF);
4093         }
4094       else if ((code_point
4095                 = charset_code_point (Vcharset_chinese_big5_1, ch, 0)) >= 0)
4096         {
4097           unsigned int I
4098             = ((code_point >> 8) - 33) * (0xFF - 0xA1)
4099             + ((code_point & 0xFF) - 33);
4100           unsigned char b1 = I / BIG5_SAME_ROW + 0xA1;
4101           unsigned char b2 = I % BIG5_SAME_ROW;
4102
4103           b2 += b2 < 0x3F ? 0x40 : 0x62;
4104           Dynarr_add (dst, b1);
4105           Dynarr_add (dst, b2);
4106         }
4107       else if ((code_point
4108                 = charset_code_point (Vcharset_chinese_big5_2, ch, 0)) >= 0)
4109         {
4110           unsigned int I
4111             = ((code_point >> 8) - 33) * (0xFF - 0xA1)
4112             + ((code_point & 0xFF) - 33);
4113           unsigned char b1, b2;
4114
4115           I += BIG5_SAME_ROW * (0xC9 - 0xA1);
4116           b1 = I / BIG5_SAME_ROW + 0xA1;
4117           b2 = I % BIG5_SAME_ROW;
4118           b2 += b2 < 0x3F ? 0x40 : 0x62;
4119           Dynarr_add (dst, b1);
4120           Dynarr_add (dst, b2);
4121         }
4122       else if (CODING_SYSTEM_USE_ENTITY_REFERENCE (str->codesys))
4123         {
4124           char buf[18];
4125
4126           char_encode_as_entity_reference (ch, buf);
4127           Dynarr_add_many (dst, buf, strlen (buf));
4128         }
4129       else
4130         Dynarr_add (dst, '?');
4131 #else
4132 #endif
4133     }
4134 }
4135
4136 void
4137 char_finish_big5 (struct encoding_stream *str, unsigned_char_dynarr *dst,
4138                   unsigned int *flags)
4139 {
4140 }
4141
4142
4143 DEFUN ("decode-big5-char", Fdecode_big5_char, 1, 1, 0, /*
4144 Decode a Big5 character CODE of BIG5 coding-system.
4145 CODE is the character code in BIG5, a cons of two integers.
4146 Return the corresponding character.
4147 */
4148        (code))
4149 {
4150   unsigned char c1, c2, b1, b2;
4151
4152   CHECK_CONS (code);
4153   CHECK_INT (XCAR (code));
4154   CHECK_INT (XCDR (code));
4155   b1 = XINT (XCAR (code));
4156   b2 = XINT (XCDR (code));
4157   if (BYTE_BIG5_TWO_BYTE_1_P (b1) &&
4158       BYTE_BIG5_TWO_BYTE_2_P (b2))
4159     {
4160       Charset_ID leading_byte;
4161       Lisp_Object charset;
4162       DECODE_BIG5 (b1, b2, leading_byte, c1, c2);
4163       charset = CHARSET_BY_LEADING_BYTE (leading_byte);
4164       return make_char (MAKE_CHAR (charset, c1 & 0x7F, c2 & 0x7F));
4165     }
4166   else
4167     return Qnil;
4168 }
4169
4170 DEFUN ("encode-big5-char", Fencode_big5_char, 1, 1, 0, /*
4171 Encode the Big5 character CHARACTER in the BIG5 coding-system.
4172 Return the corresponding character code in Big5.
4173 */
4174        (character))
4175 {
4176   Lisp_Object charset;
4177   int c1, c2, b1, b2;
4178
4179   CHECK_CHAR_COERCE_INT (character);
4180   BREAKUP_CHAR (XCHAR (character), charset, c1, c2);
4181   if (EQ (charset, Vcharset_chinese_big5_1) ||
4182       EQ (charset, Vcharset_chinese_big5_2))
4183     {
4184       ENCODE_BIG5 (XCHARSET_LEADING_BYTE (charset), c1 | 0x80, c2 | 0x80,
4185                    b1, b2);
4186       return Fcons (make_int (b1), make_int (b2));
4187     }
4188   else
4189     return Qnil;
4190 }
4191
4192 \f
4193 /************************************************************************/
4194 /*                           UCS-4 methods                              */
4195 /************************************************************************/
4196
4197 static int
4198 detect_coding_ucs4 (struct detection_state *st, const Extbyte *src, Lstream_data_count n)
4199 {
4200   while (n--)
4201     {
4202       unsigned char c = *(unsigned char *)src++;
4203       switch (st->ucs4.in_byte)
4204         {
4205         case 0:
4206           if (c >= 128)
4207             return 0;
4208           else
4209             st->ucs4.in_byte++;
4210           break;
4211         case 3:
4212           st->ucs4.in_byte = 0;
4213           break;
4214         default:
4215           st->ucs4.in_byte++;
4216         }
4217     }
4218   return CODING_CATEGORY_UCS4_MASK;
4219 }
4220
4221 static void
4222 decode_coding_ucs4 (Lstream *decoding, const Extbyte *src,
4223                     unsigned_char_dynarr *dst, Lstream_data_count n)
4224 {
4225   struct decoding_stream *str = DECODING_STREAM_DATA (decoding);
4226   unsigned int flags = str->flags;
4227   unsigned int cpos  = str->cpos;
4228   unsigned char counter = str->counter;
4229
4230   while (n--)
4231     {
4232       unsigned char c = *(unsigned char *)src++;
4233       switch (counter)
4234         {
4235         case 0:
4236           cpos = c;
4237           counter = 3;
4238           break;
4239         case 1:
4240           DECODE_ADD_UCS_CHAR ((cpos << 8) | c, dst);
4241           cpos = 0;
4242           counter = 0;
4243           break;
4244         default:
4245           cpos = ( cpos << 8 ) | c;
4246           counter--;
4247         }
4248     }
4249   if (counter & CODING_STATE_END)
4250     DECODE_OUTPUT_PARTIAL_CHAR (cpos);
4251
4252   str->flags    = flags;
4253   str->cpos     = cpos;
4254   str->counter  = counter;
4255 }
4256
4257 void
4258 char_encode_ucs4 (struct encoding_stream *str, Emchar ch,
4259                   unsigned_char_dynarr *dst, unsigned int *flags)
4260 {
4261   Dynarr_add (dst, ch >> 24);
4262   Dynarr_add (dst, ch >> 16);
4263   Dynarr_add (dst, ch >>  8);
4264   Dynarr_add (dst, ch      );
4265 }
4266
4267 void
4268 char_finish_ucs4 (struct encoding_stream *str, unsigned_char_dynarr *dst,
4269                   unsigned int *flags)
4270 {
4271 }
4272
4273 \f
4274 /************************************************************************/
4275 /*                           UTF-16 methods                             */
4276 /************************************************************************/
4277
4278 static int
4279 detect_coding_utf16 (struct detection_state *st, const Extbyte *src, Lstream_data_count n)
4280 {
4281   return CODING_CATEGORY_UTF16_MASK;
4282 }
4283
4284 static void
4285 decode_coding_utf16 (Lstream *decoding, const Extbyte *src,
4286                     unsigned_char_dynarr *dst, Lstream_data_count n)
4287 {
4288   struct decoding_stream *str = DECODING_STREAM_DATA (decoding);
4289   unsigned int flags = str->flags;
4290   unsigned int cpos  = str->cpos;
4291   unsigned char counter = str->counter & 3;
4292   unsigned char byte_order = str->counter >> 2;
4293   eol_type_t eol_type = str->eol_type;
4294
4295   while (n--)
4296     {
4297       unsigned char c = *(unsigned char *)src++;
4298       if (counter == 0)
4299         {
4300           cpos = c;
4301           counter = 1;
4302         }
4303       else if (counter == 1)
4304         {
4305           int code;
4306
4307           if (byte_order == 0)
4308             code = (c << 8) | cpos;
4309           else
4310             code = (cpos << 8) | c;
4311           if (code == 0xFFFE)
4312             {
4313               code = ((code & 0xFF) << 8) | (code >> 8);
4314               if ( byte_order == 0 )
4315                 byte_order = 1;
4316               else
4317                 byte_order = 0;
4318             }
4319           if ( (0xD800 <= code) && (code <= 0xDBFF) )
4320             {
4321               counter = 2;
4322               cpos = code;
4323             }
4324           else
4325             {
4326               counter = 0;
4327               cpos = 0;
4328               if (code != 0xFEFF)
4329                 {
4330                   DECODE_HANDLE_EOL_TYPE (eol_type, code, flags, dst);
4331                   DECODE_ADD_UCS_CHAR (code, dst);
4332                 }
4333             }
4334         }
4335       else if (counter == 2)
4336         {
4337           cpos = (cpos << 8) | c;
4338           counter++;
4339         }
4340       else
4341         {
4342           int x = cpos >> 8;
4343           int y
4344             = (byte_order == 0)
4345             ? (c << 8) | (cpos & 0xFF)
4346             : ((cpos & 0xFF) << 8) | c;
4347
4348           DECODE_ADD_UCS_CHAR ((x - 0xD800) * 0x400 + (y - 0xDC00)
4349                                + 0x10000, dst);
4350           counter = 0;
4351           cpos = 0;
4352         }
4353     label_continue_loop:;
4354     }
4355   if (counter & CODING_STATE_END)
4356     DECODE_OUTPUT_PARTIAL_CHAR (cpos);
4357
4358   str->flags    = flags;
4359   str->cpos     = cpos;
4360   str->counter  = (byte_order << 2) | counter;
4361 }
4362
4363 void
4364 char_encode_utf16 (struct encoding_stream *str, Emchar ch,
4365                   unsigned_char_dynarr *dst, unsigned int *flags)
4366 {
4367   if (ch <= 0xFFFF)
4368     {
4369       Dynarr_add (dst, ch);
4370       Dynarr_add (dst, ch >> 8);
4371     }
4372   else
4373     {
4374       int y = ((ch - 0x10000) / 0x400) + 0xD800;
4375       int z = ((ch - 0x10000) % 0x400) + 0xDC00;
4376       
4377       Dynarr_add (dst, y);
4378       Dynarr_add (dst, y >> 8);
4379       Dynarr_add (dst, z);
4380       Dynarr_add (dst, z >> 8);
4381     }
4382 }
4383
4384 void
4385 char_finish_utf16 (struct encoding_stream *str, unsigned_char_dynarr *dst,
4386                   unsigned int *flags)
4387 {
4388 }
4389
4390 \f
4391 /************************************************************************/
4392 /*                           UTF-8 methods                              */
4393 /************************************************************************/
4394
4395 static int
4396 detect_coding_utf8 (struct detection_state *st, const Extbyte *src, Lstream_data_count n)
4397 {
4398   while (n--)
4399     {
4400       unsigned char c = *(unsigned char *)src++;
4401       switch (st->utf8.in_byte)
4402         {
4403         case 0:
4404           if (c == ISO_CODE_ESC || c == ISO_CODE_SI || c == ISO_CODE_SO)
4405             return 0;
4406           else if (c >= 0xfc)
4407             st->utf8.in_byte = 5;
4408           else if (c >= 0xf8)
4409             st->utf8.in_byte = 4;
4410           else if (c >= 0xf0)
4411             st->utf8.in_byte = 3;
4412           else if (c >= 0xe0)
4413             st->utf8.in_byte = 2;
4414           else if (c >= 0xc0)
4415             st->utf8.in_byte = 1;
4416           else if (c >= 0x80)
4417             return 0;
4418           break;
4419         default:
4420           if ((c & 0xc0) != 0x80)
4421             return 0;
4422           else
4423             st->utf8.in_byte--;
4424         }
4425     }
4426   return CODING_CATEGORY_UTF8_MASK;
4427 }
4428
4429 static void
4430 decode_output_utf8_partial_char (unsigned char counter,
4431                                  unsigned int cpos,
4432                                  unsigned_char_dynarr *dst)
4433 {
4434   if (counter == 5)
4435     DECODE_ADD_BINARY_CHAR ( (cpos|0xFC), dst);
4436   else if (counter == 4)
4437     {
4438       if (cpos < (1 << 6))
4439         DECODE_ADD_BINARY_CHAR ( (cpos|0xF8), dst);
4440       else
4441         {
4442           DECODE_ADD_BINARY_CHAR ( ((cpos >> 6)|0xFC), dst);
4443           DECODE_ADD_BINARY_CHAR ( ((cpos&0x3F)|0x80), dst);
4444         }
4445     }
4446   else if (counter == 3)
4447     {
4448       if (cpos < (1 << 6))
4449         DECODE_ADD_BINARY_CHAR ( (cpos|0xF0), dst);
4450       else if (cpos < (1 << 12))
4451         {
4452           DECODE_ADD_BINARY_CHAR ( ((cpos >> 6)|0xF8), dst);
4453           DECODE_ADD_BINARY_CHAR ( ((cpos&0x3F)|0x80), dst);
4454         }
4455       else
4456         {
4457           DECODE_ADD_BINARY_CHAR ( ( (cpos >> 12)|0xFC), dst);
4458           DECODE_ADD_BINARY_CHAR ( (((cpos >>  6)&0x3F)|0x80), dst);
4459           DECODE_ADD_BINARY_CHAR ( ( (cpos       &0x3F)|0x80), dst);
4460         }
4461     }
4462   else if (counter == 2)
4463     {
4464       if (cpos < (1 << 6))
4465         DECODE_ADD_BINARY_CHAR ( (cpos|0xE0), dst);
4466       else if (cpos < (1 << 12))
4467         {
4468           DECODE_ADD_BINARY_CHAR ( ((cpos >> 6)|0xF0), dst);
4469           DECODE_ADD_BINARY_CHAR ( ((cpos&0x3F)|0x80), dst);
4470         }
4471       else if (cpos < (1 << 18))
4472         {
4473           DECODE_ADD_BINARY_CHAR ( ( (cpos >> 12)|0xF8), dst);
4474           DECODE_ADD_BINARY_CHAR ( (((cpos >> 6)&0x3F)|0x80), dst);
4475           DECODE_ADD_BINARY_CHAR ( ( (cpos      &0x3F)|0x80), dst);
4476         }
4477       else
4478         {
4479           DECODE_ADD_BINARY_CHAR ( ( (cpos >> 18)|0xFC), dst);
4480           DECODE_ADD_BINARY_CHAR ( (((cpos >> 12)&0x3F)|0x80), dst);
4481           DECODE_ADD_BINARY_CHAR ( (((cpos >>  6)&0x3F)|0x80), dst);
4482           DECODE_ADD_BINARY_CHAR ( ( (cpos       &0x3F)|0x80), dst);
4483         }
4484     }
4485   else
4486     {
4487       if (cpos < (1 << 6))
4488         DECODE_ADD_BINARY_CHAR ( (cpos|0xC0), dst);
4489       else if (cpos < (1 << 12))
4490         {
4491           DECODE_ADD_BINARY_CHAR ( ((cpos >> 6)|0xE0), dst);
4492           DECODE_ADD_BINARY_CHAR ( ((cpos&0x3F)|0x80), dst);
4493         }
4494       else if (cpos < (1 << 18))
4495         {
4496           DECODE_ADD_BINARY_CHAR ( ( (cpos >> 12)|0xF0), dst);
4497           DECODE_ADD_BINARY_CHAR ( (((cpos >>  6)&0x3F)|0x80), dst);
4498           DECODE_ADD_BINARY_CHAR ( ( (cpos       &0x3F)|0x80), dst);
4499         }
4500       else if (cpos < (1 << 24))
4501         {
4502           DECODE_ADD_BINARY_CHAR ( ( (cpos >> 18)|0xF8), dst);
4503           DECODE_ADD_BINARY_CHAR ( (((cpos >> 12)&0x3F)|0x80), dst);
4504           DECODE_ADD_BINARY_CHAR ( (((cpos >>  6)&0x3F)|0x80), dst);
4505           DECODE_ADD_BINARY_CHAR ( ( (cpos       &0x3F)|0x80), dst);
4506         }
4507       else
4508         {
4509           DECODE_ADD_BINARY_CHAR ( ( (cpos >> 24)|0xFC), dst);
4510           DECODE_ADD_BINARY_CHAR ( (((cpos >> 18)&0x3F)|0x80), dst);
4511           DECODE_ADD_BINARY_CHAR ( (((cpos >> 12)&0x3F)|0x80), dst);
4512           DECODE_ADD_BINARY_CHAR ( (((cpos >>  6)&0x3F)|0x80), dst);
4513           DECODE_ADD_BINARY_CHAR ( ( (cpos       &0x3F)|0x80), dst);
4514         }
4515     }
4516 }
4517
4518 static void
4519 decode_coding_utf8 (Lstream *decoding, const Extbyte *src,
4520                     unsigned_char_dynarr *dst, Lstream_data_count n)
4521 {
4522   struct decoding_stream *str = DECODING_STREAM_DATA (decoding);
4523   unsigned int flags    = str->flags;
4524   unsigned int cpos     = str->cpos;
4525   eol_type_t eol_type   = str->eol_type;
4526   unsigned char counter = str->counter;
4527 #ifdef UTF2000
4528   int bom_flag = str->bom_flag;
4529   Lisp_Object ccs
4530     = CODING_SYSTEM_ISO2022_INITIAL_CHARSET (DECODING_STREAM_DATA
4531                                              (decoding)->codesys, 0);
4532 #endif
4533
4534   while (n--)
4535     {
4536       unsigned char c = *(unsigned char *)src++;
4537       if (counter == 0)
4538         {
4539           if ( c < ' ' )
4540             {
4541               COMPOSE_FLUSH_CHARS (str, dst);
4542               decode_flush_er_chars (str, dst);
4543               DECODE_HANDLE_EOL_TYPE (eol_type, c, flags, dst);
4544
4545               if ( bom_flag == 0 )
4546                 bom_flag = -1;
4547
4548               DECODE_ADD_UCS_CHAR (c, dst);
4549             }
4550           else if ( c < 0xC0 )
4551             {         
4552               if ( bom_flag == 0 )
4553                 bom_flag = -1;
4554
4555               /* decode_add_er_char (str, c, dst); */
4556               COMPOSE_ADD_CHAR (str, c, dst);
4557             }
4558           else
4559             {
4560               /* decode_flush_er_chars (str, dst); */
4561               if ( c < 0xE0 )
4562                 {
4563                   cpos = c & 0x1f;
4564                   counter = 1;
4565                 }
4566               else if ( c < 0xF0 )
4567                 {
4568                   cpos = c & 0x0f;
4569                   counter = 2;
4570                 }
4571               else if ( c < 0xF8 )
4572                 {
4573                   cpos = c & 0x07;
4574                   counter = 3;
4575                 }
4576               else if ( c < 0xFC )
4577                 {
4578                   cpos = c & 0x03;
4579                   counter = 4;
4580                 }
4581               else
4582                 {
4583                   cpos = c & 0x01;
4584                   counter = 5;
4585                 }
4586             }
4587         }
4588       else if ( (c & 0xC0) == 0x80 )
4589         {
4590           cpos = ( cpos << 6 ) | ( c & 0x3f );
4591           if (counter == 1)
4592             {
4593               Emchar char_id;
4594
4595               if ( bom_flag == 0 )
4596                 {
4597                   if ( cpos == 0xFEFF )
4598                     {
4599                       bom_flag = 1;
4600                       goto decoded;
4601                     }
4602                   else
4603                     bom_flag = -1;
4604                 }
4605
4606               if (!NILP (ccs))
4607                 {
4608                   char_id = decode_defined_char (ccs, cpos, 0);
4609
4610                   if (char_id < 0)
4611                     char_id = cpos;
4612                 }
4613               else
4614                 char_id = cpos;
4615               COMPOSE_ADD_CHAR (str, char_id, dst);
4616             decoded:
4617               cpos = 0;
4618               counter = 0;
4619             }
4620           else
4621             counter--;
4622         }
4623       else
4624         {
4625           COMPOSE_FLUSH_CHARS (str, dst);
4626           decode_flush_er_chars (str, dst);
4627           decode_output_utf8_partial_char (counter, cpos, dst);
4628           DECODE_ADD_BINARY_CHAR (c, dst);
4629           cpos = 0;
4630           counter = 0;
4631         }
4632     label_continue_loop:;
4633     }
4634
4635   if (flags & CODING_STATE_END)
4636     {
4637       COMPOSE_FLUSH_CHARS (str, dst);
4638       decode_flush_er_chars (str, dst);
4639       if (counter > 0)
4640         {
4641           decode_output_utf8_partial_char (counter, cpos, dst);
4642           cpos = 0;
4643           counter = 0;
4644         }
4645     }
4646   str->flags    = flags;
4647   str->cpos     = cpos;
4648   str->counter  = counter;
4649 #ifdef UTF2000
4650   str->bom_flag = bom_flag;
4651 #endif
4652 }
4653
4654 void
4655 char_encode_utf8 (struct encoding_stream *str, Emchar ch,
4656                   unsigned_char_dynarr *dst, unsigned int *flags)
4657 {
4658   eol_type_t eol_type = CODING_SYSTEM_EOL_TYPE (str->codesys);
4659
4660   if (ch == '\n')
4661     {
4662       if (eol_type != EOL_LF && eol_type != EOL_AUTODETECT)
4663         Dynarr_add (dst, '\r');
4664       if (eol_type != EOL_CR)
4665         Dynarr_add (dst, ch);
4666     }
4667   else if (ch <= 0x7f)
4668     {
4669       Dynarr_add (dst, ch);
4670     }
4671   else
4672     {
4673       Lisp_Object ucs_ccs
4674         = CODING_SYSTEM_ISO2022_INITIAL_CHARSET (str->codesys, 0);
4675       int code_point = charset_code_point (ucs_ccs, ch, 0);
4676
4677       if ( (code_point < 0) || (code_point > 0xEFFFF) )
4678         {
4679           Lisp_Object map, ret;
4680
4681           if ( CODING_SYSTEM_ENABLE_DECOMPOSITION (str->codesys) )
4682             {
4683               Lisp_Object rest = Vdecomposition_feature_list;
4684               Lisp_Object decomp_f;
4685               Lisp_Object seq = Qnil;
4686               struct gcpro gcpro1;
4687
4688               while ( CONSP (rest) )
4689                 {
4690                   decomp_f = XCAR (rest);
4691                   GCPRO1 (rest);
4692                   seq = Fchar_feature (make_char (ch), decomp_f, Qnil,
4693                                        Qnil, Qnil);
4694                   UNGCPRO;
4695                   if ( !NILP (seq) )
4696                     break;
4697                   rest = XCDR (rest);
4698                 }
4699
4700               if ( CONSP (seq) )
4701                 {
4702                   Lisp_Object base = Fcar (seq);
4703
4704                   seq = Fcdr (seq);
4705                   if ( CHARP (base) && CONSP (seq) )
4706                     {
4707                       Lisp_Object comb = Fcar (seq);
4708
4709                       if ( CHARP (comb) )
4710                         {
4711                           char_encode_utf8 (str, XCHAR (base), dst, flags);
4712                           char_encode_utf8 (str, XCHAR (comb), dst, flags);
4713                           return;
4714                         }
4715                     }
4716                 }
4717             }
4718
4719           map = CODING_SYSTEM_ISO2022_INITIAL_CHARSET (str->codesys, 1);
4720           if ( !NILP (map)
4721                && INTP (ret = Fchar_feature (make_char (ch),
4722                                              map, Qnil,
4723                                              Qnil, Qnil)) )
4724             code_point = XINT (ret);
4725           else if ( !NILP (map =
4726                            CODING_SYSTEM_ISO2022_INITIAL_CHARSET
4727                            (str->codesys, 2))
4728                     && INTP (ret = Fchar_feature (make_char (ch),
4729                                                   map, Qnil,
4730                                                   Qnil, Qnil)) )
4731             code_point = XINT (ret);
4732           else if (CODING_SYSTEM_USE_ENTITY_REFERENCE (str->codesys))
4733             {
4734               char buf[18];
4735
4736               char_encode_as_entity_reference (ch, buf);
4737               Dynarr_add_many (dst, buf, strlen (buf));
4738               return;
4739             }
4740           else
4741             code_point = ch;
4742         }
4743       if (code_point <= 0x7ff)
4744         {
4745           Dynarr_add (dst, (code_point >> 6) | 0xc0);
4746           Dynarr_add (dst, (code_point & 0x3f) | 0x80);
4747         }
4748       else if (code_point <= 0xffff)
4749         {
4750           Dynarr_add (dst,  (code_point >> 12) | 0xe0);
4751           Dynarr_add (dst, ((code_point >>  6) & 0x3f) | 0x80);
4752           Dynarr_add (dst,  (code_point        & 0x3f) | 0x80);
4753         }
4754       else if (code_point <= 0x1fffff)
4755         {
4756           Dynarr_add (dst,  (code_point >> 18) | 0xf0);
4757           Dynarr_add (dst, ((code_point >> 12) & 0x3f) | 0x80);
4758           Dynarr_add (dst, ((code_point >>  6) & 0x3f) | 0x80);
4759           Dynarr_add (dst,  (code_point        & 0x3f) | 0x80);
4760         }
4761       else if (code_point <= 0x3ffffff)
4762         {
4763           Dynarr_add (dst,  (code_point >> 24) | 0xf8);
4764           Dynarr_add (dst, ((code_point >> 18) & 0x3f) | 0x80);
4765           Dynarr_add (dst, ((code_point >> 12) & 0x3f) | 0x80);
4766           Dynarr_add (dst, ((code_point >>  6) & 0x3f) | 0x80);
4767           Dynarr_add (dst,  (code_point        & 0x3f) | 0x80);
4768         }
4769       else
4770         {
4771           Dynarr_add (dst,  (code_point >> 30) | 0xfc);
4772           Dynarr_add (dst, ((code_point >> 24) & 0x3f) | 0x80);
4773           Dynarr_add (dst, ((code_point >> 18) & 0x3f) | 0x80);
4774           Dynarr_add (dst, ((code_point >> 12) & 0x3f) | 0x80);
4775           Dynarr_add (dst, ((code_point >>  6) & 0x3f) | 0x80);
4776           Dynarr_add (dst,  (code_point        & 0x3f) | 0x80);
4777         }
4778     }
4779 }
4780
4781 void
4782 char_finish_utf8 (struct encoding_stream *str, unsigned_char_dynarr *dst,
4783                   unsigned int *flags)
4784 {
4785 }
4786
4787 \f
4788 /************************************************************************/
4789 /*                           ISO2022 methods                            */
4790 /************************************************************************/
4791
4792 /* The following note describes the coding system ISO2022 briefly.
4793    Since the intention of this note is to help understand the
4794    functions in this file, some parts are NOT ACCURATE or OVERLY
4795    SIMPLIFIED.  For thorough understanding, please refer to the
4796    original document of ISO2022.
4797
4798    ISO2022 provides many mechanisms to encode several character sets
4799    in 7-bit and 8-bit environments.  For 7-bit environments, all text
4800    is encoded using bytes less than 128.  This may make the encoded
4801    text a little bit longer, but the text passes more easily through
4802    several gateways, some of which strip off MSB (Most Signigant Bit).
4803
4804    There are two kinds of character sets: control character set and
4805    graphic character set.  The former contains control characters such
4806    as `newline' and `escape' to provide control functions (control
4807    functions are also provided by escape sequences).  The latter
4808    contains graphic characters such as 'A' and '-'.  Emacs recognizes
4809    two control character sets and many graphic character sets.
4810
4811    Graphic character sets are classified into one of the following
4812    four classes, according to the number of bytes (DIMENSION) and
4813    number of characters in one dimension (CHARS) of the set:
4814    - DIMENSION1_CHARS94
4815    - DIMENSION1_CHARS96
4816    - DIMENSION2_CHARS94
4817    - DIMENSION2_CHARS96
4818
4819    In addition, each character set is assigned an identification tag,
4820    unique for each set, called "final character" (denoted as <F>
4821    hereafter).  The <F> of each character set is decided by ECMA(*)
4822    when it is registered in ISO.  The code range of <F> is 0x30..0x7F
4823    (0x30..0x3F are for private use only).
4824
4825    Note (*): ECMA = European Computer Manufacturers Association
4826
4827    Here are examples of graphic character set [NAME(<F>)]:
4828         o DIMENSION1_CHARS94 -- ASCII('B'), right-half-of-JISX0201('I'), ...
4829         o DIMENSION1_CHARS96 -- right-half-of-ISO8859-1('A'), ...
4830         o DIMENSION2_CHARS94 -- GB2312('A'), JISX0208('B'), ...
4831         o DIMENSION2_CHARS96 -- none for the moment
4832
4833    A code area (1 byte = 8 bits) is divided into 4 areas, C0, GL, C1, and GR.
4834         C0 [0x00..0x1F] -- control character plane 0
4835         GL [0x20..0x7F] -- graphic character plane 0
4836         C1 [0x80..0x9F] -- control character plane 1
4837         GR [0xA0..0xFF] -- graphic character plane 1
4838
4839    A control character set is directly designated and invoked to C0 or
4840    C1 by an escape sequence.  The most common case is that:
4841    - ISO646's  control character set is designated/invoked to C0, and
4842    - ISO6429's control character set is designated/invoked to C1,
4843    and usually these designations/invocations are omitted in encoded
4844    text.  In a 7-bit environment, only C0 can be used, and a control
4845    character for C1 is encoded by an appropriate escape sequence to
4846    fit into the environment.  All control characters for C1 are
4847    defined to have corresponding escape sequences.
4848
4849    A graphic character set is at first designated to one of four
4850    graphic registers (G0 through G3), then these graphic registers are
4851    invoked to GL or GR.  These designations and invocations can be
4852    done independently.  The most common case is that G0 is invoked to
4853    GL, G1 is invoked to GR, and ASCII is designated to G0.  Usually
4854    these invocations and designations are omitted in encoded text.
4855    In a 7-bit environment, only GL can be used.
4856
4857    When a graphic character set of CHARS94 is invoked to GL, codes
4858    0x20 and 0x7F of the GL area work as control characters SPACE and
4859    DEL respectively, and codes 0xA0 and 0xFF of the GR area should not
4860    be used.
4861
4862    There are two ways of invocation: locking-shift and single-shift.
4863    With locking-shift, the invocation lasts until the next different
4864    invocation, whereas with single-shift, the invocation affects the
4865    following character only and doesn't affect the locking-shift
4866    state.  Invocations are done by the following control characters or
4867    escape sequences:
4868
4869    ----------------------------------------------------------------------
4870    abbrev  function                  cntrl escape seq   description
4871    ----------------------------------------------------------------------
4872    SI/LS0  (shift-in)                0x0F  none         invoke G0 into GL
4873    SO/LS1  (shift-out)               0x0E  none         invoke G1 into GL
4874    LS2     (locking-shift-2)         none  ESC 'n'      invoke G2 into GL
4875    LS3     (locking-shift-3)         none  ESC 'o'      invoke G3 into GL
4876    LS1R    (locking-shift-1 right)   none  ESC '~'      invoke G1 into GR (*)
4877    LS2R    (locking-shift-2 right)   none  ESC '}'      invoke G2 into GR (*)
4878    LS3R    (locking-shift 3 right)   none  ESC '|'      invoke G3 into GR (*)
4879    SS2     (single-shift-2)          0x8E  ESC 'N'      invoke G2 for one char
4880    SS3     (single-shift-3)          0x8F  ESC 'O'      invoke G3 for one char
4881    ----------------------------------------------------------------------
4882    (*) These are not used by any known coding system.
4883
4884    Control characters for these functions are defined by macros
4885    ISO_CODE_XXX in `coding.h'.
4886
4887    Designations are done by the following escape sequences:
4888    ----------------------------------------------------------------------
4889    escape sequence      description
4890    ----------------------------------------------------------------------
4891    ESC '(' <F>          designate DIMENSION1_CHARS94<F> to G0
4892    ESC ')' <F>          designate DIMENSION1_CHARS94<F> to G1
4893    ESC '*' <F>          designate DIMENSION1_CHARS94<F> to G2
4894    ESC '+' <F>          designate DIMENSION1_CHARS94<F> to G3
4895    ESC ',' <F>          designate DIMENSION1_CHARS96<F> to G0 (*)
4896    ESC '-' <F>          designate DIMENSION1_CHARS96<F> to G1
4897    ESC '.' <F>          designate DIMENSION1_CHARS96<F> to G2
4898    ESC '/' <F>          designate DIMENSION1_CHARS96<F> to G3
4899    ESC '$' '(' <F>      designate DIMENSION2_CHARS94<F> to G0 (**)
4900    ESC '$' ')' <F>      designate DIMENSION2_CHARS94<F> to G1
4901    ESC '$' '*' <F>      designate DIMENSION2_CHARS94<F> to G2
4902    ESC '$' '+' <F>      designate DIMENSION2_CHARS94<F> to G3
4903    ESC '$' ',' <F>      designate DIMENSION2_CHARS96<F> to G0 (*)
4904    ESC '$' '-' <F>      designate DIMENSION2_CHARS96<F> to G1
4905    ESC '$' '.' <F>      designate DIMENSION2_CHARS96<F> to G2
4906    ESC '$' '/' <F>      designate DIMENSION2_CHARS96<F> to G3
4907    ----------------------------------------------------------------------
4908
4909    In this list, "DIMENSION1_CHARS94<F>" means a graphic character set
4910    of dimension 1, chars 94, and final character <F>, etc...
4911
4912    Note (*): Although these designations are not allowed in ISO2022,
4913    Emacs accepts them on decoding, and produces them on encoding
4914    CHARS96 character sets in a coding system which is characterized as
4915    7-bit environment, non-locking-shift, and non-single-shift.
4916
4917    Note (**): If <F> is '@', 'A', or 'B', the intermediate character
4918    '(' can be omitted.  We refer to this as "short-form" hereafter.
4919
4920    Now you may notice that there are a lot of ways for encoding the
4921    same multilingual text in ISO2022.  Actually, there exist many
4922    coding systems such as Compound Text (used in X11's inter client
4923    communication, ISO-2022-JP (used in Japanese internet), ISO-2022-KR
4924    (used in Korean internet), EUC (Extended UNIX Code, used in Asian
4925    localized platforms), and all of these are variants of ISO2022.
4926
4927    In addition to the above, Emacs handles two more kinds of escape
4928    sequences: ISO6429's direction specification and Emacs' private
4929    sequence for specifying character composition.
4930
4931    ISO6429's direction specification takes the following form:
4932         o CSI ']'      -- end of the current direction
4933         o CSI '0' ']'  -- end of the current direction
4934         o CSI '1' ']'  -- start of left-to-right text
4935         o CSI '2' ']'  -- start of right-to-left text
4936    The control character CSI (0x9B: control sequence introducer) is
4937    abbreviated to the escape sequence ESC '[' in a 7-bit environment.
4938
4939    Character composition specification takes the following form:
4940         o ESC '0' -- start character composition
4941         o ESC '1' -- end character composition
4942    Since these are not standard escape sequences of any ISO standard,
4943    their use with these meanings is restricted to Emacs only.  */
4944
4945 static void
4946 reset_iso2022 (Lisp_Object coding_system, struct iso2022_decoder *iso)
4947 {
4948   int i;
4949
4950   for (i = 0; i < 4; i++)
4951     {
4952       if (!NILP (coding_system))
4953         iso->charset[i] =
4954           XCODING_SYSTEM_ISO2022_INITIAL_CHARSET (coding_system, i);
4955       else
4956         iso->charset[i] = Qt;
4957       iso->invalid_designated[i] = 0;
4958     }
4959   iso->esc = ISO_ESC_NOTHING;
4960   iso->esc_bytes_index = 0;
4961   iso->register_left = 0;
4962   iso->register_right = 1;
4963   iso->switched_dir_and_no_valid_charset_yet = 0;
4964   iso->invalid_switch_dir = 0;
4965   iso->output_direction_sequence = 0;
4966   iso->output_literally = 0;
4967 #ifdef ENABLE_COMPOSITE_CHARS
4968   if (iso->composite_chars)
4969     Dynarr_reset (iso->composite_chars);
4970 #endif
4971 }
4972
4973 static int
4974 fit_to_be_escape_quoted (unsigned char c)
4975 {
4976   switch (c)
4977     {
4978     case ISO_CODE_ESC:
4979     case ISO_CODE_CSI:
4980     case ISO_CODE_SS2:
4981     case ISO_CODE_SS3:
4982     case ISO_CODE_SO:
4983     case ISO_CODE_SI:
4984       return 1;
4985
4986     default:
4987       return 0;
4988     }
4989 }
4990
4991 /* Parse one byte of an ISO2022 escape sequence.
4992    If the result is an invalid escape sequence, return 0 and
4993    do not change anything in STR.  Otherwise, if the result is
4994    an incomplete escape sequence, update ISO2022.ESC and
4995    ISO2022.ESC_BYTES and return -1.  Otherwise, update
4996    all the state variables (but not ISO2022.ESC_BYTES) and
4997    return 1.
4998
4999    If CHECK_INVALID_CHARSETS is non-zero, check for designation
5000    or invocation of an invalid character set and treat that as
5001    an unrecognized escape sequence. */
5002
5003 static int
5004 parse_iso2022_esc (Lisp_Object codesys, struct iso2022_decoder *iso,
5005                    unsigned char c, unsigned int *flags,
5006                    int check_invalid_charsets)
5007 {
5008   /* (1) If we're at the end of a designation sequence, CS is the
5009      charset being designated and REG is the register to designate
5010      it to.
5011
5012      (2) If we're at the end of a locking-shift sequence, REG is
5013      the register to invoke and HALF (0 == left, 1 == right) is
5014      the half to invoke it into.
5015
5016      (3) If we're at the end of a single-shift sequence, REG is
5017      the register to invoke. */
5018   Lisp_Object cs = Qnil;
5019   int reg, half;
5020
5021   /* NOTE: This code does goto's all over the fucking place.
5022      The reason for this is that we're basically implementing
5023      a state machine here, and hierarchical languages like C
5024      don't really provide a clean way of doing this. */
5025
5026   if (! (*flags & CODING_STATE_ESCAPE))
5027     /* At beginning of escape sequence; we need to reset our
5028        escape-state variables. */
5029     iso->esc = ISO_ESC_NOTHING;
5030
5031   iso->output_literally = 0;
5032   iso->output_direction_sequence = 0;
5033
5034   switch (iso->esc)
5035     {
5036     case ISO_ESC_NOTHING:
5037       iso->esc_bytes_index = 0;
5038       switch (c)
5039         {
5040         case ISO_CODE_ESC:      /* Start escape sequence */
5041           *flags |= CODING_STATE_ESCAPE;
5042           iso->esc = ISO_ESC;
5043           goto not_done;
5044
5045         case ISO_CODE_CSI:      /* ISO6429 (specifying directionality) */
5046           *flags |= CODING_STATE_ESCAPE;
5047           iso->esc = ISO_ESC_5_11;
5048           goto not_done;
5049
5050         case ISO_CODE_SO:       /* locking shift 1 */
5051           reg = 1; half = 0;
5052           goto locking_shift;
5053         case ISO_CODE_SI:       /* locking shift 0 */
5054           reg = 0; half = 0;
5055           goto locking_shift;
5056
5057         case ISO_CODE_SS2:      /* single shift */
5058           reg = 2;
5059           goto single_shift;
5060         case ISO_CODE_SS3:      /* single shift */
5061           reg = 3;
5062           goto single_shift;
5063
5064         default:                        /* Other control characters */
5065           return 0;
5066         }
5067
5068     case ISO_ESC:
5069       switch (c)
5070         {
5071           /**** single shift ****/
5072
5073         case 'N':       /* single shift 2 */
5074           reg = 2;
5075           goto single_shift;
5076         case 'O':       /* single shift 3 */
5077           reg = 3;
5078           goto single_shift;
5079
5080           /**** locking shift ****/
5081
5082         case '~':       /* locking shift 1 right */
5083           reg = 1; half = 1;
5084           goto locking_shift;
5085         case 'n':       /* locking shift 2 */
5086           reg = 2; half = 0;
5087           goto locking_shift;
5088         case '}':       /* locking shift 2 right */
5089           reg = 2; half = 1;
5090           goto locking_shift;
5091         case 'o':       /* locking shift 3 */
5092           reg = 3; half = 0;
5093           goto locking_shift;
5094         case '|':       /* locking shift 3 right */
5095           reg = 3; half = 1;
5096           goto locking_shift;
5097
5098 #ifdef ENABLE_COMPOSITE_CHARS
5099           /**** composite ****/
5100
5101         case '0':
5102           iso->esc = ISO_ESC_START_COMPOSITE;
5103           *flags = (*flags & CODING_STATE_ISO2022_LOCK) |
5104             CODING_STATE_COMPOSITE;
5105           return 1;
5106
5107         case '1':
5108           iso->esc = ISO_ESC_END_COMPOSITE;
5109           *flags = (*flags & CODING_STATE_ISO2022_LOCK) &
5110             ~CODING_STATE_COMPOSITE;
5111           return 1;
5112 #endif /* ENABLE_COMPOSITE_CHARS */
5113
5114           /**** directionality ****/
5115
5116         case '[':
5117           iso->esc = ISO_ESC_5_11;
5118           goto not_done;
5119
5120           /**** designation ****/
5121
5122         case '$':       /* multibyte charset prefix */
5123           iso->esc = ISO_ESC_2_4;
5124           goto not_done;
5125
5126         default:
5127           if (0x28 <= c && c <= 0x2F)
5128             {
5129               iso->esc = (enum iso_esc_flag) (c - 0x28 + ISO_ESC_2_8);
5130               goto not_done;
5131             }
5132
5133           /* This function is called with CODESYS equal to nil when
5134              doing coding-system detection. */
5135           if (!NILP (codesys)
5136               && XCODING_SYSTEM_ISO2022_ESCAPE_QUOTED (codesys)
5137               && fit_to_be_escape_quoted (c))
5138             {
5139               iso->esc = ISO_ESC_LITERAL;
5140               *flags &= CODING_STATE_ISO2022_LOCK;
5141               return 1;
5142             }
5143
5144           /* bzzzt! */
5145           return 0;
5146         }
5147
5148
5149
5150       /**** directionality ****/
5151
5152     case ISO_ESC_5_11:          /* ISO6429 direction control */
5153       if (c == ']')
5154         {
5155           *flags &= (CODING_STATE_ISO2022_LOCK & ~CODING_STATE_R2L);
5156           goto directionality;
5157         }
5158       if      (c == '0') iso->esc = ISO_ESC_5_11_0;
5159       else if (c == '1') iso->esc = ISO_ESC_5_11_1;
5160       else if (c == '2') iso->esc = ISO_ESC_5_11_2;
5161       else               return 0;
5162       goto not_done;
5163
5164     case ISO_ESC_5_11_0:
5165       if (c == ']')
5166         {
5167           *flags &= (CODING_STATE_ISO2022_LOCK & ~CODING_STATE_R2L);
5168           goto directionality;
5169         }
5170       return 0;
5171
5172     case ISO_ESC_5_11_1:
5173       if (c == ']')
5174         {
5175           *flags = (CODING_STATE_ISO2022_LOCK & ~CODING_STATE_R2L);
5176           goto directionality;
5177         }
5178       return 0;
5179
5180     case ISO_ESC_5_11_2:
5181       if (c == ']')
5182         {
5183           *flags = (*flags & CODING_STATE_ISO2022_LOCK) | CODING_STATE_R2L;
5184           goto directionality;
5185         }
5186       return 0;
5187
5188     directionality:
5189       iso->esc = ISO_ESC_DIRECTIONALITY;
5190       /* Various junk here to attempt to preserve the direction sequences
5191          literally in the text if they would otherwise be swallowed due
5192          to invalid designations that don't show up as actual charset
5193          changes in the text. */
5194       if (iso->invalid_switch_dir)
5195         {
5196           /* We already inserted a direction switch literally into the
5197              text.  We assume (#### this may not be right) that the
5198              next direction switch is the one going the other way,
5199              and we need to output that literally as well. */
5200           iso->output_literally = 1;
5201           iso->invalid_switch_dir = 0;
5202         }
5203       else
5204         {
5205           int jj;
5206
5207           /* If we are in the thrall of an invalid designation,
5208            then stick the directionality sequence literally into the
5209            output stream so it ends up in the original text again. */
5210           for (jj = 0; jj < 4; jj++)
5211             if (iso->invalid_designated[jj])
5212               break;
5213           if (jj < 4)
5214             {
5215               iso->output_literally = 1;
5216               iso->invalid_switch_dir = 1;
5217             }
5218           else
5219             /* Indicate that we haven't yet seen a valid designation,
5220                so that if a switch-dir is directly followed by an
5221                invalid designation, both get inserted literally. */
5222             iso->switched_dir_and_no_valid_charset_yet = 1;
5223         }
5224       return 1;
5225
5226
5227       /**** designation ****/
5228
5229     case ISO_ESC_2_4:
5230       if (0x28 <= c && c <= 0x2F)
5231         {
5232           iso->esc = (enum iso_esc_flag) (c - 0x28 + ISO_ESC_2_4_8);
5233           goto not_done;
5234         }
5235       if (0x40 <= c && c <= 0x42)
5236         {
5237           /* 94^n-set */
5238           cs = CHARSET_BY_ATTRIBUTES (94, -1, c,
5239                                       *flags & CODING_STATE_R2L ?
5240                                       CHARSET_RIGHT_TO_LEFT :
5241                                       CHARSET_LEFT_TO_RIGHT);
5242           reg = 0;
5243           goto designated;
5244         }
5245       return 0;
5246
5247     default:
5248       {
5249         int chars = 0;
5250         int single = 0;
5251
5252         if (c < '0' || c > '~')
5253           return 0; /* bad final byte */
5254
5255         if (iso->esc >= ISO_ESC_2_8 &&
5256             iso->esc <= ISO_ESC_2_15)
5257           {
5258             chars = (iso->esc >= ISO_ESC_2_12) ? 96 : 94;
5259             single = 1; /* single-byte */
5260             reg = (iso->esc - ISO_ESC_2_8) & 3;
5261           }
5262         else if (iso->esc >= ISO_ESC_2_4_8 &&
5263                  iso->esc <= ISO_ESC_2_4_15)
5264           {
5265             chars = (iso->esc >= ISO_ESC_2_4_12) ? 96 : 94;
5266             single = -1; /* multi-byte */
5267             reg = (iso->esc - ISO_ESC_2_4_8) & 3;
5268           }
5269         else
5270           {
5271             /* Can this ever be reached? -slb */
5272             abort();
5273           }
5274
5275         cs = CHARSET_BY_ATTRIBUTES (chars, single, c,
5276                                     *flags & CODING_STATE_R2L ?
5277                                     CHARSET_RIGHT_TO_LEFT :
5278                                     CHARSET_LEFT_TO_RIGHT);
5279         goto designated;
5280       }
5281     }
5282
5283  not_done:
5284   iso->esc_bytes[iso->esc_bytes_index++] = (unsigned char) c;
5285   return -1;
5286
5287  single_shift:
5288   if (check_invalid_charsets && !CHARSETP (iso->charset[reg]))
5289     /* can't invoke something that ain't there. */
5290     return 0;
5291   iso->esc = ISO_ESC_SINGLE_SHIFT;
5292   *flags &= CODING_STATE_ISO2022_LOCK;
5293   if (reg == 2)
5294     *flags |= CODING_STATE_SS2;
5295   else
5296     *flags |= CODING_STATE_SS3;
5297   return 1;
5298
5299  locking_shift:
5300   if (check_invalid_charsets &&
5301       !CHARSETP (iso->charset[reg]))
5302     /* can't invoke something that ain't there. */
5303     return 0;
5304   if (half)
5305     iso->register_right = reg;
5306   else
5307     iso->register_left = reg;
5308   *flags &= CODING_STATE_ISO2022_LOCK;
5309   iso->esc = ISO_ESC_LOCKING_SHIFT;
5310   return 1;
5311
5312  designated:
5313   if (NILP (cs) && check_invalid_charsets)
5314     {
5315       iso->invalid_designated[reg] = 1;
5316       iso->charset[reg] = Vcharset_ascii;
5317       iso->esc = ISO_ESC_DESIGNATE;
5318       *flags &= CODING_STATE_ISO2022_LOCK;
5319       iso->output_literally = 1;
5320       if (iso->switched_dir_and_no_valid_charset_yet)
5321         {
5322           /* We encountered a switch-direction followed by an
5323              invalid designation.  Ensure that the switch-direction
5324              gets outputted; otherwise it will probably get eaten
5325              when the text is written out again. */
5326           iso->switched_dir_and_no_valid_charset_yet = 0;
5327           iso->output_direction_sequence = 1;
5328           /* And make sure that the switch-dir going the other
5329              way gets outputted, as well. */
5330           iso->invalid_switch_dir = 1;
5331         }
5332       return 1;
5333     }
5334   /* This function is called with CODESYS equal to nil when
5335      doing coding-system detection. */
5336   if (!NILP (codesys))
5337     {
5338       charset_conversion_spec_dynarr *dyn =
5339         XCODING_SYSTEM (codesys)->iso2022.input_conv;
5340
5341       if (dyn)
5342         {
5343           int i;
5344
5345           for (i = 0; i < Dynarr_length (dyn); i++)
5346             {
5347               struct charset_conversion_spec *spec = Dynarr_atp (dyn, i);
5348               if (EQ (cs, spec->from_charset))
5349                 cs = spec->to_charset;
5350             }
5351         }
5352     }
5353
5354   iso->charset[reg] = cs;
5355   iso->esc = ISO_ESC_DESIGNATE;
5356   *flags &= CODING_STATE_ISO2022_LOCK;
5357   if (iso->invalid_designated[reg])
5358     {
5359       iso->invalid_designated[reg] = 0;
5360       iso->output_literally = 1;
5361     }
5362   if (iso->switched_dir_and_no_valid_charset_yet)
5363     iso->switched_dir_and_no_valid_charset_yet = 0;
5364   return 1;
5365 }
5366
5367 static int
5368 detect_coding_iso2022 (struct detection_state *st, const Extbyte *src, Lstream_data_count n)
5369 {
5370   int mask;
5371
5372   /* #### There are serious deficiencies in the recognition mechanism
5373      here.  This needs to be much smarter if it's going to cut it.
5374      The sequence "\xff\x0f" is currently detected as LOCK_SHIFT while
5375      it should be detected as Latin-1.
5376      All the ISO2022 stuff in this file should be synced up with the
5377      code from FSF Emacs-20.4, in which Mule should be more or less stable.
5378      Perhaps we should wait till R2L works in FSF Emacs? */
5379
5380   if (!st->iso2022.initted)
5381     {
5382       reset_iso2022 (Qnil, &st->iso2022.iso);
5383       st->iso2022.mask = (CODING_CATEGORY_ISO_7_MASK |
5384                           CODING_CATEGORY_ISO_8_DESIGNATE_MASK |
5385                           CODING_CATEGORY_ISO_8_1_MASK |
5386                           CODING_CATEGORY_ISO_8_2_MASK |
5387                           CODING_CATEGORY_ISO_LOCK_SHIFT_MASK);
5388       st->iso2022.flags = 0;
5389       st->iso2022.high_byte_count = 0;
5390       st->iso2022.saw_single_shift = 0;
5391       st->iso2022.initted = 1;
5392     }
5393
5394   mask = st->iso2022.mask;
5395
5396   while (n--)
5397     {
5398       unsigned char c = *(unsigned char *)src++;
5399       if (c >= 0xA0)
5400         {
5401           mask &= ~CODING_CATEGORY_ISO_7_MASK;
5402           st->iso2022.high_byte_count++;
5403         }
5404       else
5405         {
5406           if (st->iso2022.high_byte_count && !st->iso2022.saw_single_shift)
5407             {
5408               if (st->iso2022.high_byte_count & 1)
5409                 /* odd number of high bytes; assume not iso-8-2 */
5410                 mask &= ~CODING_CATEGORY_ISO_8_2_MASK;
5411             }
5412           st->iso2022.high_byte_count = 0;
5413           st->iso2022.saw_single_shift = 0;
5414           if (c > 0x80)
5415             mask &= ~CODING_CATEGORY_ISO_7_MASK;
5416         }
5417       if (!(st->iso2022.flags & CODING_STATE_ESCAPE)
5418           && (BYTE_C0_P (c) || BYTE_C1_P (c)))
5419         { /* control chars */
5420           switch (c)
5421             {
5422               /* Allow and ignore control characters that you might
5423                  reasonably see in a text file */
5424             case '\r':
5425             case '\n':
5426             case '\t':
5427             case  7: /* bell */
5428             case  8: /* backspace */
5429             case 11: /* vertical tab */
5430             case 12: /* form feed */
5431             case 26: /* MS-DOS C-z junk */
5432             case 31: /* '^_' -- for info */
5433               goto label_continue_loop;
5434
5435             default:
5436               break;
5437             }
5438         }
5439
5440       if ((st->iso2022.flags & CODING_STATE_ESCAPE) || BYTE_C0_P (c)
5441           || BYTE_C1_P (c))
5442         {
5443           if (parse_iso2022_esc (Qnil, &st->iso2022.iso, c,
5444                                  &st->iso2022.flags, 0))
5445             {
5446               switch (st->iso2022.iso.esc)
5447                 {
5448                 case ISO_ESC_DESIGNATE:
5449                   mask &= ~CODING_CATEGORY_ISO_8_1_MASK;
5450                   mask &= ~CODING_CATEGORY_ISO_8_2_MASK;
5451                   break;
5452                 case ISO_ESC_LOCKING_SHIFT:
5453                   mask = CODING_CATEGORY_ISO_LOCK_SHIFT_MASK;
5454                   goto ran_out_of_chars;
5455                 case ISO_ESC_SINGLE_SHIFT:
5456                   mask &= ~CODING_CATEGORY_ISO_8_DESIGNATE_MASK;
5457                   st->iso2022.saw_single_shift = 1;
5458                   break;
5459                 default:
5460                   break;
5461                 }
5462             }
5463           else
5464             {
5465               mask = 0;
5466               goto ran_out_of_chars;
5467             }
5468         }
5469     label_continue_loop:;
5470     }
5471
5472  ran_out_of_chars:
5473
5474   return mask;
5475 }
5476
5477 static int
5478 postprocess_iso2022_mask (int mask)
5479 {
5480   /* #### kind of cheesy */
5481   /* If seven-bit ISO is allowed, then assume that the encoding is
5482      entirely seven-bit and turn off the eight-bit ones. */
5483   if (mask & CODING_CATEGORY_ISO_7_MASK)
5484     mask &= ~ (CODING_CATEGORY_ISO_8_DESIGNATE_MASK |
5485                CODING_CATEGORY_ISO_8_1_MASK |
5486                CODING_CATEGORY_ISO_8_2_MASK);
5487   return mask;
5488 }
5489
5490 /* If FLAGS is a null pointer or specifies right-to-left motion,
5491    output a switch-dir-to-left-to-right sequence to DST.
5492    Also update FLAGS if it is not a null pointer.
5493    If INTERNAL_P is set, we are outputting in internal format and
5494    need to handle the CSI differently. */
5495
5496 static void
5497 restore_left_to_right_direction (Lisp_Coding_System *codesys,
5498                                  unsigned_char_dynarr *dst,
5499                                  unsigned int *flags,
5500                                  int internal_p)
5501 {
5502   if (!flags || (*flags & CODING_STATE_R2L))
5503     {
5504       if (CODING_SYSTEM_ISO2022_SEVEN (codesys))
5505         {
5506           Dynarr_add (dst, ISO_CODE_ESC);
5507           Dynarr_add (dst, '[');
5508         }
5509       else if (internal_p)
5510         DECODE_ADD_BINARY_CHAR (ISO_CODE_CSI, dst);
5511       else
5512         Dynarr_add (dst, ISO_CODE_CSI);
5513       Dynarr_add (dst, '0');
5514       Dynarr_add (dst, ']');
5515       if (flags)
5516         *flags &= ~CODING_STATE_R2L;
5517     }
5518 }
5519
5520 /* If FLAGS is a null pointer or specifies a direction different from
5521    DIRECTION (which should be either CHARSET_RIGHT_TO_LEFT or
5522    CHARSET_LEFT_TO_RIGHT), output the appropriate switch-dir escape
5523    sequence to DST.  Also update FLAGS if it is not a null pointer.
5524    If INTERNAL_P is set, we are outputting in internal format and
5525    need to handle the CSI differently. */
5526
5527 static void
5528 ensure_correct_direction (int direction, Lisp_Coding_System *codesys,
5529                           unsigned_char_dynarr *dst, unsigned int *flags,
5530                           int internal_p)
5531 {
5532   if ((!flags || (*flags & CODING_STATE_R2L)) &&
5533       direction == CHARSET_LEFT_TO_RIGHT)
5534     restore_left_to_right_direction (codesys, dst, flags, internal_p);
5535   else if (!CODING_SYSTEM_ISO2022_NO_ISO6429 (codesys)
5536            && (!flags || !(*flags & CODING_STATE_R2L)) &&
5537            direction == CHARSET_RIGHT_TO_LEFT)
5538     {
5539       if (CODING_SYSTEM_ISO2022_SEVEN (codesys))
5540         {
5541           Dynarr_add (dst, ISO_CODE_ESC);
5542           Dynarr_add (dst, '[');
5543         }
5544       else if (internal_p)
5545         DECODE_ADD_BINARY_CHAR (ISO_CODE_CSI, dst);
5546       else
5547         Dynarr_add (dst, ISO_CODE_CSI);
5548       Dynarr_add (dst, '2');
5549       Dynarr_add (dst, ']');
5550       if (flags)
5551         *flags |= CODING_STATE_R2L;
5552     }
5553 }
5554
5555 /* Convert ISO2022-format data to internal format. */
5556
5557 static void
5558 decode_coding_iso2022 (Lstream *decoding, const Extbyte *src,
5559                        unsigned_char_dynarr *dst, Lstream_data_count n)
5560 {
5561   struct decoding_stream *str = DECODING_STREAM_DATA (decoding);
5562   unsigned int flags    = str->flags;
5563   unsigned int cpos     = str->cpos;
5564   unsigned char counter = str->counter;
5565   eol_type_t eol_type   = str->eol_type;
5566 #ifdef ENABLE_COMPOSITE_CHARS
5567   unsigned_char_dynarr *real_dst = dst;
5568 #endif
5569   Lisp_Object coding_system;
5570
5571   XSETCODING_SYSTEM (coding_system, str->codesys);
5572
5573 #ifdef ENABLE_COMPOSITE_CHARS
5574   if (flags & CODING_STATE_COMPOSITE)
5575     dst = str->iso2022.composite_chars;
5576 #endif /* ENABLE_COMPOSITE_CHARS */
5577
5578   while (n--)
5579     {
5580       unsigned char c = *(unsigned char *)src++;
5581       if (flags & CODING_STATE_ESCAPE)
5582         {       /* Within ESC sequence */
5583           int retval = parse_iso2022_esc (coding_system, &str->iso2022,
5584                                           c, &flags, 1);
5585
5586           if (retval)
5587             {
5588               switch (str->iso2022.esc)
5589                 {
5590 #ifdef ENABLE_COMPOSITE_CHARS
5591                 case ISO_ESC_START_COMPOSITE:
5592                   if (str->iso2022.composite_chars)
5593                     Dynarr_reset (str->iso2022.composite_chars);
5594                   else
5595                     str->iso2022.composite_chars = Dynarr_new (unsigned_char);
5596                   dst = str->iso2022.composite_chars;
5597                   break;
5598                 case ISO_ESC_END_COMPOSITE:
5599                   {
5600                     Bufbyte comstr[MAX_EMCHAR_LEN];
5601                     Bytecount len;
5602                     Emchar emch = lookup_composite_char (Dynarr_atp (dst, 0),
5603                                                          Dynarr_length (dst));
5604                     dst = real_dst;
5605                     len = set_charptr_emchar (comstr, emch);
5606                     Dynarr_add_many (dst, comstr, len);
5607                     break;
5608                   }
5609 #endif /* ENABLE_COMPOSITE_CHARS */
5610
5611                 case ISO_ESC_LITERAL:
5612                   COMPOSE_FLUSH_CHARS (str, dst);
5613                   decode_flush_er_chars (str, dst);
5614                   DECODE_ADD_BINARY_CHAR (c, dst);
5615                   break;
5616
5617                 default:
5618                   /* Everything else handled already */
5619                   break;
5620                 }
5621             }
5622
5623           /* Attempted error recovery. */
5624           if (str->iso2022.output_direction_sequence)
5625             ensure_correct_direction (flags & CODING_STATE_R2L ?
5626                                       CHARSET_RIGHT_TO_LEFT :
5627                                       CHARSET_LEFT_TO_RIGHT,
5628                                       str->codesys, dst, 0, 1);
5629           /* More error recovery. */
5630           if (!retval || str->iso2022.output_literally)
5631             {
5632               /* Output the (possibly invalid) sequence */
5633               int i;
5634               COMPOSE_FLUSH_CHARS (str, dst);
5635               decode_flush_er_chars (str, dst);
5636               for (i = 0; i < str->iso2022.esc_bytes_index; i++)
5637                 DECODE_ADD_BINARY_CHAR (str->iso2022.esc_bytes[i], dst);
5638               flags &= CODING_STATE_ISO2022_LOCK;
5639               if (!retval)
5640                 n++, src--;/* Repeat the loop with the same character. */
5641               else
5642                 {
5643                   /* No sense in reprocessing the final byte of the
5644                      escape sequence; it could mess things up anyway.
5645                      Just add it now. */
5646                   COMPOSE_FLUSH_CHARS (str, dst);
5647                   decode_flush_er_chars (str, dst);
5648                   DECODE_ADD_BINARY_CHAR (c, dst);
5649                 }
5650             }
5651           cpos = 0;
5652           counter = 0;
5653         }
5654       else if (BYTE_C0_P (c) || BYTE_C1_P (c))
5655         { /* Control characters */
5656
5657           /***** Error-handling *****/
5658
5659           /* If we were in the middle of a character, dump out the
5660              partial character. */
5661           if (counter)
5662             {
5663               COMPOSE_FLUSH_CHARS (str, dst);
5664               decode_flush_er_chars (str, dst);
5665               while (counter > 0)
5666                 {
5667                   counter--;
5668                   DECODE_ADD_BINARY_CHAR
5669                     ((unsigned char)(cpos >> (counter * 8)), dst);
5670                 }
5671               cpos = 0;
5672             }
5673
5674           /* If we just saw a single-shift character, dump it out.
5675              This may dump out the wrong sort of single-shift character,
5676              but least it will give an indication that something went
5677              wrong. */
5678           if (flags & CODING_STATE_SS2)
5679             {
5680               COMPOSE_FLUSH_CHARS (str, dst);
5681               decode_flush_er_chars (str, dst);
5682               DECODE_ADD_BINARY_CHAR (ISO_CODE_SS2, dst);
5683               flags &= ~CODING_STATE_SS2;
5684             }
5685           if (flags & CODING_STATE_SS3)
5686             {
5687               COMPOSE_FLUSH_CHARS (str, dst);
5688               decode_flush_er_chars (str, dst);
5689               DECODE_ADD_BINARY_CHAR (ISO_CODE_SS3, dst);
5690               flags &= ~CODING_STATE_SS3;
5691             }
5692
5693           /***** Now handle the control characters. *****/
5694
5695           /* Handle CR/LF */
5696 #ifdef UTF2000
5697           if (c == '\r')
5698             {
5699               COMPOSE_FLUSH_CHARS (str, dst);
5700               decode_flush_er_chars (str, dst);
5701               if (eol_type == EOL_CR)
5702                 Dynarr_add (dst, '\n');
5703               else if (eol_type != EOL_CRLF || flags & CODING_STATE_CR)
5704                 Dynarr_add (dst, c);
5705               else
5706                 flags |= CODING_STATE_CR;
5707               goto label_continue_loop;
5708             }
5709           else if (flags & CODING_STATE_CR)
5710             {   /* eol_type == CODING_SYSTEM_EOL_CRLF */
5711               if (c != '\n')
5712                 Dynarr_add (dst, '\r');
5713               flags &= ~CODING_STATE_CR;
5714             }
5715 #else
5716           DECODE_HANDLE_EOL_TYPE (eol_type, c, flags, dst);
5717 #endif
5718
5719           flags &= CODING_STATE_ISO2022_LOCK;
5720
5721           if (!parse_iso2022_esc (coding_system, &str->iso2022, c, &flags, 1))
5722             {
5723               COMPOSE_FLUSH_CHARS (str, dst);
5724               decode_flush_er_chars (str, dst);
5725               DECODE_ADD_BINARY_CHAR (c, dst);
5726             }
5727         }
5728       else
5729         {                       /* Graphic characters */
5730           Lisp_Object charset;
5731 #ifndef UTF2000
5732           Charset_ID lb;
5733 #endif
5734           int reg;
5735
5736 #ifdef UTF2000
5737           if (c == '\r')
5738             {
5739               COMPOSE_FLUSH_CHARS (str, dst);
5740               decode_flush_er_chars (str, dst);
5741               if (eol_type == EOL_CR)
5742                 Dynarr_add (dst, '\n');
5743               else if (eol_type != EOL_CRLF || flags & CODING_STATE_CR)
5744                 Dynarr_add (dst, c);
5745               else
5746                 flags |= CODING_STATE_CR;
5747               goto label_continue_loop;
5748             }
5749           else if (flags & CODING_STATE_CR)
5750             {   /* eol_type == CODING_SYSTEM_EOL_CRLF */
5751               if (c != '\n')
5752                 Dynarr_add (dst, '\r');
5753               flags &= ~CODING_STATE_CR;
5754             }
5755 #else
5756           DECODE_HANDLE_EOL_TYPE (eol_type, c, flags, dst);
5757 #endif
5758
5759           /* Now determine the charset. */
5760           reg = ((flags & CODING_STATE_SS2) ? 2
5761                  : (flags & CODING_STATE_SS3) ? 3
5762                  : !BYTE_ASCII_P (c) ? str->iso2022.register_right
5763                  : str->iso2022.register_left);
5764           charset = str->iso2022.charset[reg];
5765
5766           /* Error checking: */
5767           if (! CHARSETP (charset)
5768               || str->iso2022.invalid_designated[reg]
5769               || (((c & 0x7F) == ' ' || (c & 0x7F) == ISO_CODE_DEL)
5770                   && XCHARSET_CHARS (charset) == 94))
5771             /* Mrmph.  We are trying to invoke a register that has no
5772                or an invalid charset in it, or trying to add a character
5773                outside the range of the charset.  Insert that char literally
5774                to preserve it for the output. */
5775             {
5776               COMPOSE_FLUSH_CHARS (str, dst);
5777               decode_flush_er_chars (str, dst);
5778               while (counter > 0)
5779                 {
5780                   counter--;
5781                   DECODE_ADD_BINARY_CHAR
5782                     ((unsigned char)(cpos >> (counter * 8)), dst);
5783                 }
5784               cpos = 0;
5785               DECODE_ADD_BINARY_CHAR (c, dst);
5786             }
5787
5788           else
5789             {
5790               /* Things are probably hunky-dorey. */
5791
5792               /* Fetch reverse charset, maybe. */
5793               if (((flags & CODING_STATE_R2L) &&
5794                    XCHARSET_DIRECTION (charset) == CHARSET_LEFT_TO_RIGHT)
5795                   ||
5796                   (!(flags & CODING_STATE_R2L) &&
5797                    XCHARSET_DIRECTION (charset) == CHARSET_RIGHT_TO_LEFT))
5798                 {
5799                   Lisp_Object new_charset =
5800                     XCHARSET_REVERSE_DIRECTION_CHARSET (charset);
5801                   if (!NILP (new_charset))
5802                     charset = new_charset;
5803                 }
5804
5805 #ifdef UTF2000
5806               counter++;
5807               if (XCHARSET_DIMENSION (charset) == counter)
5808                 {
5809                   COMPOSE_ADD_CHAR (str,
5810                                     DECODE_CHAR (charset,
5811                                                  ((cpos & 0x7F7F7F) << 8)
5812                                                  | (c & 0x7F), 0),
5813                                     dst);
5814                   cpos = 0;
5815                   counter = 0;
5816                 }
5817               else
5818                 cpos = (cpos << 8) | c;
5819 #else
5820               lb = XCHARSET_LEADING_BYTE (charset);
5821               switch (XCHARSET_REP_BYTES (charset))
5822                 {
5823                 case 1: /* ASCII */
5824                   DECODE_OUTPUT_PARTIAL_CHAR (ch);
5825                   Dynarr_add (dst, c & 0x7F);
5826                   break;
5827
5828                 case 2: /* one-byte official */
5829                   DECODE_OUTPUT_PARTIAL_CHAR (ch);
5830                   Dynarr_add (dst, lb);
5831                   Dynarr_add (dst, c | 0x80);
5832                   break;
5833
5834                 case 3: /* one-byte private or two-byte official */
5835                   if (XCHARSET_PRIVATE_P (charset))
5836                     {
5837                       DECODE_OUTPUT_PARTIAL_CHAR (ch);
5838                       Dynarr_add (dst, PRE_LEADING_BYTE_PRIVATE_1);
5839                       Dynarr_add (dst, lb);
5840                       Dynarr_add (dst, c | 0x80);
5841                     }
5842                   else
5843                     {
5844                       if (ch)
5845                         {
5846                           Dynarr_add (dst, lb);
5847                           Dynarr_add (dst, ch | 0x80);
5848                           Dynarr_add (dst, c | 0x80);
5849                           ch = 0;
5850                         }
5851                       else
5852                         ch = c;
5853                     }
5854                   break;
5855
5856                 default:        /* two-byte private */
5857                   if (ch)
5858                     {
5859                       Dynarr_add (dst, PRE_LEADING_BYTE_PRIVATE_2);
5860                       Dynarr_add (dst, lb);
5861                       Dynarr_add (dst, ch | 0x80);
5862                       Dynarr_add (dst, c | 0x80);
5863                       ch = 0;
5864                     }
5865                   else
5866                     ch = c;
5867                 }
5868 #endif
5869             }
5870
5871           if (!cpos)
5872             flags &= CODING_STATE_ISO2022_LOCK;
5873         }
5874
5875     label_continue_loop:;
5876     }
5877
5878   if (flags & CODING_STATE_END)
5879     {
5880       COMPOSE_FLUSH_CHARS (str, dst);
5881       decode_flush_er_chars (str, dst);
5882       DECODE_OUTPUT_PARTIAL_CHAR (cpos);
5883     }
5884   str->flags   = flags;
5885   str->cpos    = cpos;
5886   str->counter = counter;
5887 }
5888
5889
5890 /***** ISO2022 encoder *****/
5891
5892 /* Designate CHARSET into register REG. */
5893
5894 static void
5895 iso2022_designate (Lisp_Object charset, unsigned char reg,
5896                    struct encoding_stream *str, unsigned_char_dynarr *dst)
5897 {
5898   static const char inter94[] = "()*+";
5899   static const char inter96[] = ",-./";
5900   unsigned short chars;
5901   unsigned char dimension;
5902   unsigned char final;
5903   Lisp_Object old_charset = str->iso2022.charset[reg];
5904
5905   str->iso2022.charset[reg] = charset;
5906   if (!CHARSETP (charset))
5907     /* charset might be an initial nil or t. */
5908     return;
5909   chars = XCHARSET_CHARS (charset);
5910   dimension = XCHARSET_DIMENSION (charset);
5911   final = XCHARSET_FINAL (charset);
5912   if (!str->iso2022.force_charset_on_output[reg] &&
5913       CHARSETP (old_charset) &&
5914       XCHARSET_CHARS (old_charset) == chars &&
5915       XCHARSET_DIMENSION (old_charset) == dimension &&
5916       XCHARSET_FINAL (old_charset) == final)
5917     return;
5918
5919   str->iso2022.force_charset_on_output[reg] = 0;
5920
5921   {
5922     charset_conversion_spec_dynarr *dyn =
5923       str->codesys->iso2022.output_conv;
5924
5925     if (dyn)
5926       {
5927         int i;
5928
5929         for (i = 0; i < Dynarr_length (dyn); i++)
5930           {
5931             struct charset_conversion_spec *spec = Dynarr_atp (dyn, i);
5932             if (EQ (charset, spec->from_charset))
5933                 charset = spec->to_charset;
5934           }
5935       }
5936   }
5937
5938   Dynarr_add (dst, ISO_CODE_ESC);
5939   switch (chars)
5940     {
5941     case 94:
5942       if (dimension == 1)
5943         Dynarr_add (dst, inter94[reg]);
5944       else
5945         {
5946           Dynarr_add (dst, '$');
5947           if (reg != 0
5948               || !(CODING_SYSTEM_ISO2022_SHORT (str->codesys))
5949               || final < '@'
5950               || final > 'B')
5951             Dynarr_add (dst, inter94[reg]);
5952         }
5953       break;
5954     case 96:
5955       if (dimension == 1)
5956         Dynarr_add (dst, inter96[reg]);
5957       else
5958         {
5959           Dynarr_add (dst, '$');
5960           Dynarr_add (dst, inter96[reg]);
5961         }
5962       break;
5963     }
5964   Dynarr_add (dst, final);
5965 }
5966
5967 static void
5968 ensure_normal_shift (struct encoding_stream *str, unsigned_char_dynarr *dst)
5969 {
5970   if (str->iso2022.register_left != 0)
5971     {
5972       Dynarr_add (dst, ISO_CODE_SI);
5973       str->iso2022.register_left = 0;
5974     }
5975 }
5976
5977 static void
5978 ensure_shift_out (struct encoding_stream *str, unsigned_char_dynarr *dst)
5979 {
5980   if (str->iso2022.register_left != 1)
5981     {
5982       Dynarr_add (dst, ISO_CODE_SO);
5983       str->iso2022.register_left = 1;
5984     }
5985 }
5986
5987 void
5988 char_encode_iso2022 (struct encoding_stream *str, Emchar ch,
5989                      unsigned_char_dynarr *dst, unsigned int *flags)
5990 {
5991   unsigned char charmask;
5992   Lisp_Coding_System* codesys = str->codesys;
5993   eol_type_t eol_type         = CODING_SYSTEM_EOL_TYPE (str->codesys);
5994   int i;
5995   Lisp_Object charset = str->iso2022.current_charset;
5996   int half = str->iso2022.current_half;
5997   int code_point = -1;
5998
5999   if (ch <= 0x7F)
6000     {
6001       restore_left_to_right_direction (codesys, dst, flags, 0);
6002               
6003       /* Make sure G0 contains ASCII */
6004       if ((ch > ' ' && ch < ISO_CODE_DEL)
6005           || !CODING_SYSTEM_ISO2022_NO_ASCII_CNTL (codesys))
6006         {
6007           ensure_normal_shift (str, dst);
6008           iso2022_designate (Vcharset_ascii, 0, str, dst);
6009         }
6010               
6011       /* If necessary, restore everything to the default state
6012          at end-of-line */
6013       if (ch == '\n' && !(CODING_SYSTEM_ISO2022_NO_ASCII_EOL (codesys)))
6014         {
6015           restore_left_to_right_direction (codesys, dst, flags, 0);
6016
6017           ensure_normal_shift (str, dst);
6018
6019           for (i = 0; i < 4; i++)
6020             {
6021               Lisp_Object initial_charset =
6022                 CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, i);
6023               iso2022_designate (initial_charset, i, str, dst);
6024             }
6025         }
6026       if (ch == '\n')
6027         {
6028           if (eol_type != EOL_LF && eol_type != EOL_AUTODETECT)
6029             Dynarr_add (dst, '\r');
6030           if (eol_type != EOL_CR)
6031             Dynarr_add (dst, ch);
6032         }
6033       else
6034         {
6035           if (CODING_SYSTEM_ISO2022_ESCAPE_QUOTED (codesys)
6036               && fit_to_be_escape_quoted (ch))
6037             Dynarr_add (dst, ISO_CODE_ESC);
6038           Dynarr_add (dst, ch);
6039         }
6040     }
6041   else if ( (0x80 <= ch) && (ch <= 0x9f) )
6042     {
6043       charmask = (half == 0 ? 0x00 : 0x80);
6044           
6045       if (CODING_SYSTEM_ISO2022_ESCAPE_QUOTED (codesys)
6046           && fit_to_be_escape_quoted (ch))
6047         Dynarr_add (dst, ISO_CODE_ESC);
6048       /* you asked for it ... */
6049       Dynarr_add (dst, ch);
6050     }
6051   else
6052     {
6053       int reg;
6054
6055       /* Now determine which register to use. */
6056       reg = -1;
6057       for (i = 0; i < 4; i++)
6058         {
6059           if ((CHARSETP (charset = str->iso2022.charset[i])
6060                && ((code_point = charset_code_point (charset, ch, 0)) >= 0))
6061               ||
6062               (CHARSETP
6063                (charset
6064                 = CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, i))
6065                && ((code_point = charset_code_point (charset, ch, 0)) >= 0)))
6066             {
6067               reg = i;
6068               break;
6069             }
6070         }
6071       if (reg == -1)
6072         {
6073           Lisp_Object original_default_coded_charset_priority_list
6074             = Vdefault_coded_charset_priority_list;
6075           Vdefault_coded_charset_priority_list
6076             = CODING_SYSTEM_CCS_PRIORITY_LIST (codesys);
6077           while (!EQ (Vdefault_coded_charset_priority_list, Qnil))
6078             {
6079               code_point = ENCODE_CHAR (ch, charset);
6080               if (XCHARSET_FINAL (charset))
6081                 goto found;
6082               Vdefault_coded_charset_priority_list
6083                 = Fcdr (Fmemq (XCHARSET_NAME (charset),
6084                                Vdefault_coded_charset_priority_list));
6085             }
6086           Vdefault_coded_charset_priority_list
6087             = original_default_coded_charset_priority_list;
6088           while (!EQ (Vdefault_coded_charset_priority_list, Qnil))
6089             {
6090               code_point = ENCODE_CHAR (ch, charset);
6091               if (XCHARSET_FINAL (charset))
6092                 goto found;
6093               Vdefault_coded_charset_priority_list
6094                 = Fcdr (Fmemq (XCHARSET_NAME (charset),
6095                                Vdefault_coded_charset_priority_list));
6096             }
6097           code_point = ENCODE_CHAR (ch, charset);
6098           if (!XCHARSET_FINAL (charset))
6099             {
6100               charset = Vcharset_ascii;
6101               code_point = '~';
6102             }
6103         found:
6104           Vdefault_coded_charset_priority_list
6105             = original_default_coded_charset_priority_list;
6106         }
6107       ensure_correct_direction (XCHARSET_DIRECTION (charset),
6108                                 codesys, dst, flags, 0);
6109       
6110       if (reg == -1)
6111         {
6112           if (XCHARSET_GRAPHIC (charset) != 0)
6113             {
6114               if (!NILP (str->iso2022.charset[1]) &&
6115                   (!CODING_SYSTEM_ISO2022_SEVEN (codesys)
6116                    || CODING_SYSTEM_ISO2022_LOCK_SHIFT (codesys)))
6117                 reg = 1;
6118               else if (!NILP (str->iso2022.charset[2]))
6119                 reg = 2;
6120               else if (!NILP (str->iso2022.charset[3]))
6121                 reg = 3;
6122               else
6123                 reg = 0;
6124             }
6125           else
6126             reg = 0;
6127         }
6128
6129       iso2022_designate (charset, reg, str, dst);
6130               
6131       /* Now invoke that register. */
6132       switch (reg)
6133         {
6134         case 0:
6135           ensure_normal_shift (str, dst);
6136           half = 0;
6137           break;
6138         case 1:
6139           if (CODING_SYSTEM_ISO2022_SEVEN (codesys))
6140             {
6141               ensure_shift_out (str, dst);
6142               half = 0;
6143             }
6144           else
6145             half = 1;
6146           break;
6147         case 2:
6148           if (CODING_SYSTEM_ISO2022_SEVEN (str->codesys))
6149             {
6150               Dynarr_add (dst, ISO_CODE_ESC);
6151               Dynarr_add (dst, 'N');
6152               half = 0;
6153             }
6154           else
6155             {
6156               Dynarr_add (dst, ISO_CODE_SS2);
6157               half = 1;
6158             }
6159           break;
6160         case 3:
6161           if (CODING_SYSTEM_ISO2022_SEVEN (str->codesys))
6162             {
6163               Dynarr_add (dst, ISO_CODE_ESC);
6164               Dynarr_add (dst, 'O');
6165               half = 0;
6166             }
6167           else
6168             {
6169               Dynarr_add (dst, ISO_CODE_SS3);
6170               half = 1;
6171             }
6172           break;
6173         default:
6174           abort ();
6175         }
6176       
6177       charmask = (half == 0 ? 0x00 : 0x80);
6178       
6179       switch (XCHARSET_DIMENSION (charset))
6180         {
6181         case 1:
6182           Dynarr_add (dst, (code_point & 0xFF) | charmask);
6183           break;
6184         case 2:
6185           Dynarr_add (dst, ((code_point >> 8) & 0xFF) | charmask);
6186           Dynarr_add (dst, ( code_point       & 0xFF) | charmask);
6187           break;
6188         case 3:
6189           Dynarr_add (dst, ((code_point >> 16) & 0xFF) | charmask);
6190           Dynarr_add (dst, ((code_point >>  8) & 0xFF) | charmask);
6191           Dynarr_add (dst, ( code_point        & 0xFF) | charmask);
6192           break;
6193         case 4:
6194           Dynarr_add (dst, ((code_point >> 24) & 0xFF) | charmask);
6195           Dynarr_add (dst, ((code_point >> 16) & 0xFF) | charmask);
6196           Dynarr_add (dst, ((code_point >>  8) & 0xFF) | charmask);
6197           Dynarr_add (dst, ( code_point        & 0xFF) | charmask);
6198           break;
6199         default:
6200           abort ();
6201         }
6202     }
6203   str->iso2022.current_charset = charset;
6204   str->iso2022.current_half = half;
6205 }
6206
6207 void
6208 char_finish_iso2022 (struct encoding_stream *str, unsigned_char_dynarr *dst,
6209                      unsigned int *flags)
6210 {
6211   Lisp_Coding_System* codesys = str->codesys;
6212   int i;
6213
6214   restore_left_to_right_direction (codesys, dst, flags, 0);
6215   ensure_normal_shift (str, dst);
6216   for (i = 0; i < 4; i++)
6217     {
6218       Lisp_Object initial_charset
6219         = CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, i);
6220       iso2022_designate (initial_charset, i, str, dst);
6221     }
6222 }
6223 #endif /* MULE */
6224 \f
6225 /************************************************************************/
6226 /*                     No-conversion methods                            */
6227 /************************************************************************/
6228
6229 /* This is used when reading in "binary" files -- i.e. files that may
6230    contain all 256 possible byte values and that are not to be
6231    interpreted as being in any particular decoding. */
6232 static void
6233 decode_coding_no_conversion (Lstream *decoding, const Extbyte *src,
6234                              unsigned_char_dynarr *dst, Lstream_data_count n)
6235 {
6236   struct decoding_stream *str = DECODING_STREAM_DATA (decoding);
6237   unsigned int flags  = str->flags;
6238   unsigned int cpos   = str->cpos;
6239   eol_type_t eol_type = str->eol_type;
6240
6241   while (n--)
6242     {
6243       unsigned char c = *(unsigned char *)src++;
6244
6245       DECODE_HANDLE_EOL_TYPE (eol_type, c, flags, dst);
6246       DECODE_ADD_BINARY_CHAR (c, dst);
6247     label_continue_loop:;
6248     }
6249
6250   DECODE_HANDLE_END_OF_CONVERSION (flags, cpos, dst);
6251
6252   str->flags = flags;
6253   str->cpos  = cpos;
6254 }
6255
6256 static void
6257 encode_coding_no_conversion (Lstream *encoding, const Bufbyte *src,
6258                              unsigned_char_dynarr *dst, Lstream_data_count n)
6259 {
6260   unsigned char c;
6261   struct encoding_stream *str = ENCODING_STREAM_DATA (encoding);
6262   unsigned int flags  = str->flags;
6263   unsigned int ch     = str->ch;
6264   eol_type_t eol_type = CODING_SYSTEM_EOL_TYPE (str->codesys);
6265 #ifdef UTF2000
6266   unsigned char char_boundary = str->iso2022.current_char_boundary;
6267 #endif
6268
6269   while (n--)
6270     {
6271       c = *src++;         
6272 #ifdef UTF2000
6273       if (char_boundary == 0)
6274         if ( c >= 0xfc )
6275           {
6276             ch = c & 0x01;
6277             char_boundary = 5;
6278           }
6279         else if ( c >= 0xf8 )
6280           {
6281             ch = c & 0x03;
6282             char_boundary = 4;
6283           }
6284         else if ( c >= 0xf0 )
6285           {
6286             ch = c & 0x07;
6287             char_boundary = 3;
6288           }
6289         else if ( c >= 0xe0 )
6290           {
6291             ch = c & 0x0f;
6292             char_boundary = 2;
6293           }
6294         else if ( c >= 0xc0 )
6295           {
6296             ch = c & 0x1f;
6297             char_boundary = 1;
6298           }
6299         else
6300           {
6301             ch = 0;
6302             if (c == '\n')
6303               {
6304                 if (eol_type != EOL_LF && eol_type != EOL_AUTODETECT)
6305                   Dynarr_add (dst, '\r');
6306                 if (eol_type != EOL_CR)
6307                   Dynarr_add (dst, c);
6308               }
6309             else
6310               Dynarr_add (dst, c);
6311             char_boundary = 0;
6312           }
6313       else if (char_boundary == 1)
6314         {
6315           ch = ( ch << 6 ) | ( c & 0x3f );
6316           Dynarr_add (dst, ch & 0xff);
6317           char_boundary = 0;
6318         }
6319       else
6320         {
6321           ch = ( ch << 6 ) | ( c & 0x3f );
6322           char_boundary--;
6323         }
6324 #else /* not UTF2000 */
6325       if (c == '\n')
6326         {
6327           if (eol_type != EOL_LF && eol_type != EOL_AUTODETECT)
6328             Dynarr_add (dst, '\r');
6329           if (eol_type != EOL_CR)
6330             Dynarr_add (dst, '\n');
6331           ch = 0;
6332         }
6333       else if (BYTE_ASCII_P (c))
6334         {
6335           assert (ch == 0);
6336           Dynarr_add (dst, c);
6337         }
6338       else if (BUFBYTE_LEADING_BYTE_P (c))
6339         {
6340           assert (ch == 0);
6341           if (c == LEADING_BYTE_LATIN_ISO8859_1 ||
6342               c == LEADING_BYTE_CONTROL_1)
6343             ch = c;
6344           else
6345             Dynarr_add (dst, '~'); /* untranslatable character */
6346         }
6347       else
6348         {
6349           if (ch == LEADING_BYTE_LATIN_ISO8859_1)
6350             Dynarr_add (dst, c);
6351           else if (ch == LEADING_BYTE_CONTROL_1)
6352             {
6353               assert (c < 0xC0);
6354               Dynarr_add (dst, c - 0x20);
6355             }
6356           /* else it should be the second or third byte of an
6357              untranslatable character, so ignore it */
6358           ch = 0;
6359         }
6360 #endif /* not UTF2000 */
6361     }
6362
6363   str->flags = flags;
6364   str->ch    = ch;
6365 #ifdef UTF2000
6366   str->iso2022.current_char_boundary = char_boundary;
6367 #endif
6368 }
6369
6370 \f
6371
6372 /************************************************************************/
6373 /*                             Initialization                           */
6374 /************************************************************************/
6375
6376 void
6377 syms_of_file_coding (void)
6378 {
6379   INIT_LRECORD_IMPLEMENTATION (coding_system);
6380
6381   DEFERROR_STANDARD (Qcoding_system_error, Qio_error);
6382
6383   DEFSUBR (Fcoding_system_p);
6384   DEFSUBR (Ffind_coding_system);
6385   DEFSUBR (Fget_coding_system);
6386   DEFSUBR (Fcoding_system_list);
6387   DEFSUBR (Fcoding_system_name);
6388   DEFSUBR (Fmake_coding_system);
6389   DEFSUBR (Fcopy_coding_system);
6390   DEFSUBR (Fcoding_system_canonical_name_p);
6391   DEFSUBR (Fcoding_system_alias_p);
6392   DEFSUBR (Fcoding_system_aliasee);
6393   DEFSUBR (Fdefine_coding_system_alias);
6394   DEFSUBR (Fsubsidiary_coding_system);
6395
6396   DEFSUBR (Fcoding_system_type);
6397   DEFSUBR (Fcoding_system_doc_string);
6398 #ifdef MULE
6399   DEFSUBR (Fcoding_system_charset);
6400 #endif
6401   DEFSUBR (Fcoding_system_property);
6402
6403   DEFSUBR (Fcoding_category_list);
6404   DEFSUBR (Fset_coding_priority_list);
6405   DEFSUBR (Fcoding_priority_list);
6406   DEFSUBR (Fset_coding_category_system);
6407   DEFSUBR (Fcoding_category_system);
6408
6409   DEFSUBR (Fdetect_coding_region);
6410   DEFSUBR (Fdecode_coding_region);
6411   DEFSUBR (Fencode_coding_region);
6412 #ifdef MULE
6413   DEFSUBR (Fdecode_shift_jis_char);
6414   DEFSUBR (Fencode_shift_jis_char);
6415   DEFSUBR (Fdecode_big5_char);
6416   DEFSUBR (Fencode_big5_char);
6417 #endif /* MULE */
6418   defsymbol (&Qcoding_systemp, "coding-system-p");
6419   defsymbol (&Qno_conversion, "no-conversion");
6420   defsymbol (&Qraw_text, "raw-text");
6421 #ifdef MULE
6422   defsymbol (&Qbig5, "big5");
6423   defsymbol (&Qshift_jis, "shift-jis");
6424   defsymbol (&Qucs4, "ucs-4");
6425   defsymbol (&Qutf8, "utf-8");
6426   defsymbol (&Qutf16, "utf-16");
6427   defsymbol (&Qccl, "ccl");
6428   defsymbol (&Qiso2022, "iso2022");
6429 #endif /* MULE */
6430   defsymbol (&Qmnemonic, "mnemonic");
6431   defsymbol (&Qeol_type, "eol-type");
6432   defsymbol (&Qpost_read_conversion, "post-read-conversion");
6433   defsymbol (&Qpre_write_conversion, "pre-write-conversion");
6434
6435   defsymbol (&Qcr, "cr");
6436   defsymbol (&Qlf, "lf");
6437   defsymbol (&Qcrlf, "crlf");
6438   defsymbol (&Qeol_cr, "eol-cr");
6439   defsymbol (&Qeol_lf, "eol-lf");
6440   defsymbol (&Qeol_crlf, "eol-crlf");
6441 #ifdef MULE
6442   defsymbol (&Qcharset_g0, "charset-g0");
6443   defsymbol (&Qcharset_g1, "charset-g1");
6444   defsymbol (&Qcharset_g2, "charset-g2");
6445   defsymbol (&Qcharset_g3, "charset-g3");
6446   defsymbol (&Qforce_g0_on_output, "force-g0-on-output");
6447   defsymbol (&Qforce_g1_on_output, "force-g1-on-output");
6448   defsymbol (&Qforce_g2_on_output, "force-g2-on-output");
6449   defsymbol (&Qforce_g3_on_output, "force-g3-on-output");
6450   defsymbol (&Qno_iso6429, "no-iso6429");
6451   defsymbol (&Qinput_charset_conversion, "input-charset-conversion");
6452   defsymbol (&Qoutput_charset_conversion, "output-charset-conversion");
6453
6454   defsymbol (&Qshort, "short");
6455   defsymbol (&Qno_ascii_eol, "no-ascii-eol");
6456   defsymbol (&Qno_ascii_cntl, "no-ascii-cntl");
6457   defsymbol (&Qseven, "seven");
6458   defsymbol (&Qlock_shift, "lock-shift");
6459   defsymbol (&Qescape_quoted, "escape-quoted");
6460 #endif /* MULE */
6461 #ifdef UTF2000
6462   defsymbol (&Qutf_8_mcs, "utf-8-mcs");
6463   defsymbol (&Qdisable_composition, "disable-composition");
6464   defsymbol (&Qenable_decomposition, "enable-decomposition");
6465   defsymbol (&Qccs_priority_list, "ccs-priority-list");
6466   defsymbol (&Quse_entity_reference, "use-entity-reference");
6467   defsymbol (&Qd, "d");
6468   defsymbol (&Qx, "x");
6469   defsymbol (&QX, "X");
6470 #endif
6471   defsymbol (&Qencode, "encode");
6472   defsymbol (&Qdecode, "decode");
6473
6474 #ifdef MULE
6475   defsymbol (&coding_category_symbol[CODING_CATEGORY_SHIFT_JIS],
6476              "shift-jis");
6477   defsymbol (&coding_category_symbol[CODING_CATEGORY_BIG5],
6478              "big5");
6479   defsymbol (&coding_category_symbol[CODING_CATEGORY_UCS4],
6480              "ucs-4");
6481   defsymbol (&coding_category_symbol[CODING_CATEGORY_UTF16],
6482              "utf-16");
6483   defsymbol (&coding_category_symbol[CODING_CATEGORY_UTF8],
6484              "utf-8");
6485   defsymbol (&coding_category_symbol[CODING_CATEGORY_ISO_7],
6486              "iso-7");
6487   defsymbol (&coding_category_symbol[CODING_CATEGORY_ISO_8_DESIGNATE],
6488              "iso-8-designate");
6489   defsymbol (&coding_category_symbol[CODING_CATEGORY_ISO_8_1],
6490              "iso-8-1");
6491   defsymbol (&coding_category_symbol[CODING_CATEGORY_ISO_8_2],
6492              "iso-8-2");
6493   defsymbol (&coding_category_symbol[CODING_CATEGORY_ISO_LOCK_SHIFT],
6494              "iso-lock-shift");
6495 #endif /* MULE */
6496   defsymbol (&coding_category_symbol[CODING_CATEGORY_NO_CONVERSION],
6497              "no-conversion");
6498 }
6499
6500 void
6501 lstream_type_create_file_coding (void)
6502 {
6503   LSTREAM_HAS_METHOD (decoding, reader);
6504   LSTREAM_HAS_METHOD (decoding, writer);
6505   LSTREAM_HAS_METHOD (decoding, rewinder);
6506   LSTREAM_HAS_METHOD (decoding, seekable_p);
6507   LSTREAM_HAS_METHOD (decoding, flusher);
6508   LSTREAM_HAS_METHOD (decoding, closer);
6509   LSTREAM_HAS_METHOD (decoding, marker);
6510
6511   LSTREAM_HAS_METHOD (encoding, reader);
6512   LSTREAM_HAS_METHOD (encoding, writer);
6513   LSTREAM_HAS_METHOD (encoding, rewinder);
6514   LSTREAM_HAS_METHOD (encoding, seekable_p);
6515   LSTREAM_HAS_METHOD (encoding, flusher);
6516   LSTREAM_HAS_METHOD (encoding, closer);
6517   LSTREAM_HAS_METHOD (encoding, marker);
6518 }
6519
6520 void
6521 vars_of_file_coding (void)
6522 {
6523   int i;
6524
6525   fcd = xnew (struct file_coding_dump);
6526   dump_add_root_struct_ptr (&fcd, &fcd_description);
6527
6528   /* Initialize to something reasonable ... */
6529   for (i = 0; i < CODING_CATEGORY_LAST; i++)
6530     {
6531       fcd->coding_category_system[i] = Qnil;
6532       fcd->coding_category_by_priority[i] = i;
6533     }
6534
6535   Fprovide (intern ("file-coding"));
6536
6537   DEFVAR_LISP ("keyboard-coding-system", &Vkeyboard_coding_system /*
6538 Coding system used for TTY keyboard input.
6539 Not used under a windowing system.
6540 */ );
6541   Vkeyboard_coding_system = Qnil;
6542
6543   DEFVAR_LISP ("terminal-coding-system", &Vterminal_coding_system /*
6544 Coding system used for TTY display output.
6545 Not used under a windowing system.
6546 */ );
6547   Vterminal_coding_system = Qnil;
6548
6549   DEFVAR_LISP ("coding-system-for-read", &Vcoding_system_for_read /*
6550 Overriding coding system used when reading from a file or process.
6551 You should bind this variable with `let', but do not set it globally.
6552 If this is non-nil, it specifies the coding system that will be used
6553 to decode input on read operations, such as from a file or process.
6554 It overrides `buffer-file-coding-system-for-read',
6555 `insert-file-contents-pre-hook', etc.  Use those variables instead of
6556 this one for permanent changes to the environment.  */ );
6557   Vcoding_system_for_read = Qnil;
6558
6559   DEFVAR_LISP ("coding-system-for-write",
6560                &Vcoding_system_for_write /*
6561 Overriding coding system used when writing to a file or process.
6562 You should bind this variable with `let', but do not set it globally.
6563 If this is non-nil, it specifies the coding system that will be used
6564 to encode output for write operations, such as to a file or process.
6565 It overrides `buffer-file-coding-system', `write-region-pre-hook', etc.
6566 Use those variables instead of this one for permanent changes to the
6567 environment.  */ );
6568   Vcoding_system_for_write = Qnil;
6569
6570   DEFVAR_LISP ("file-name-coding-system", &Vfile_name_coding_system /*
6571 Coding system used to convert pathnames when accessing files.
6572 */ );
6573   Vfile_name_coding_system = Qnil;
6574
6575   DEFVAR_LISP ("coded-charset-entity-reference-alist",
6576                &Vcoded_charset_entity_reference_alist /*
6577 Alist of coded-charset vs corresponding entity-reference.
6578 Each element looks like (CCS PREFIX CODE-COLUMNS CODE-TYPE).
6579 CCS is coded-charset.
6580 CODE-COLUMNS is columns of code-point of entity-reference.
6581 CODE-TYPE is format type of code-point of entity-reference.
6582 `d' means decimal value and `x' means hexadecimal value.
6583 */ );
6584   Vcoded_charset_entity_reference_alist = Qnil;
6585
6586   DEFVAR_BOOL ("enable-multibyte-characters", &enable_multibyte_characters /*
6587 Non-nil means the buffer contents are regarded as multi-byte form
6588 of characters, not a binary code.  This affects the display, file I/O,
6589 and behaviors of various editing commands.
6590
6591 Setting this to nil does not do anything.
6592 */ );
6593   enable_multibyte_characters = 1;
6594
6595 #ifdef UTF2000
6596   DEFVAR_LISP ("decomposition-feature-list",
6597                &Vdecomposition_feature_list /*
6598 List of `=decomposition@FOO' feature to encode characters as IVS.
6599 */ );
6600   Vdecomposition_feature_list = Qnil;
6601 #endif
6602 }
6603
6604 void
6605 complex_vars_of_file_coding (void)
6606 {
6607   staticpro (&Vcoding_system_hash_table);
6608   Vcoding_system_hash_table =
6609     make_lisp_hash_table (50, HASH_TABLE_NON_WEAK, HASH_TABLE_EQ);
6610
6611   the_codesys_prop_dynarr = Dynarr_new (codesys_prop);
6612   dump_add_root_struct_ptr (&the_codesys_prop_dynarr, &codesys_prop_dynarr_description);
6613
6614 #define DEFINE_CODESYS_PROP(Prop_Type, Sym) do  \
6615 {                                               \
6616   struct codesys_prop csp;                      \
6617   csp.sym = (Sym);                              \
6618   csp.prop_type = (Prop_Type);                  \
6619   Dynarr_add (the_codesys_prop_dynarr, csp);    \
6620 } while (0)
6621
6622   DEFINE_CODESYS_PROP (CODESYS_PROP_ALL_OK,  Qmnemonic);
6623   DEFINE_CODESYS_PROP (CODESYS_PROP_ALL_OK,  Qeol_type);
6624   DEFINE_CODESYS_PROP (CODESYS_PROP_ALL_OK,  Qeol_cr);
6625   DEFINE_CODESYS_PROP (CODESYS_PROP_ALL_OK,  Qeol_crlf);
6626   DEFINE_CODESYS_PROP (CODESYS_PROP_ALL_OK,  Qeol_lf);
6627   DEFINE_CODESYS_PROP (CODESYS_PROP_ALL_OK,  Qpost_read_conversion);
6628   DEFINE_CODESYS_PROP (CODESYS_PROP_ALL_OK,  Qpre_write_conversion);
6629 #ifdef MULE
6630   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qcharset_g0);
6631   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qcharset_g1);
6632   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qcharset_g2);
6633   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qcharset_g3);
6634   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qforce_g0_on_output);
6635   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qforce_g1_on_output);
6636   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qforce_g2_on_output);
6637   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qforce_g3_on_output);
6638   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qshort);
6639   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qno_ascii_eol);
6640   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qno_ascii_cntl);
6641   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qseven);
6642   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qlock_shift);
6643   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qno_iso6429);
6644   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qescape_quoted);
6645   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qinput_charset_conversion);
6646   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qoutput_charset_conversion);
6647 #ifdef UTF2000
6648   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qccs_priority_list);
6649 #endif
6650
6651   DEFINE_CODESYS_PROP (CODESYS_PROP_CCL,     Qencode);
6652   DEFINE_CODESYS_PROP (CODESYS_PROP_CCL,     Qdecode);
6653 #ifdef UTF2000
6654   DEFINE_CODESYS_PROP (CODESYS_PROP_ALL_OK,  Qdisable_composition);
6655   DEFINE_CODESYS_PROP (CODESYS_PROP_ALL_OK,  Qenable_decomposition);
6656   DEFINE_CODESYS_PROP (CODESYS_PROP_ALL_OK,  Quse_entity_reference);
6657 #endif
6658 #endif /* MULE */
6659   /* Need to create this here or we're really screwed. */
6660   Fmake_coding_system
6661     (Qraw_text, Qno_conversion,
6662      build_string ("Raw text, which means it converts only line-break-codes."),
6663      list2 (Qmnemonic, build_string ("Raw")));
6664
6665   Fmake_coding_system
6666     (Qbinary, Qno_conversion,
6667      build_string ("Binary, which means it does not convert anything."),
6668      list4 (Qeol_type, Qlf,
6669             Qmnemonic, build_string ("Binary")));
6670
6671 #ifdef UTF2000
6672   Fmake_coding_system
6673     (Qutf_8_mcs, Qutf8,
6674      build_string
6675      ("Coding-system of UTF-8 with Multiple Coded-character-Sets extension."),
6676      list2 (Qmnemonic, build_string ("MTF8")));
6677 #endif
6678
6679   Fdefine_coding_system_alias (Qno_conversion, Qraw_text);
6680
6681   Fdefine_coding_system_alias (Qfile_name, Qbinary);
6682
6683   Fdefine_coding_system_alias (Qterminal, Qbinary);
6684   Fdefine_coding_system_alias (Qkeyboard, Qbinary);
6685
6686   /* Need this for bootstrapping */
6687   fcd->coding_category_system[CODING_CATEGORY_NO_CONVERSION] =
6688     Fget_coding_system (Qraw_text);
6689
6690 #ifdef UTF2000
6691   fcd->coding_category_system[CODING_CATEGORY_UTF8]
6692    = Fget_coding_system (Qutf_8_mcs);
6693 #endif
6694
6695 #if defined(MULE) && !defined(UTF2000)
6696   {
6697     size_t i;
6698
6699     for (i = 0; i < countof (fcd->ucs_to_mule_table); i++)
6700       fcd->ucs_to_mule_table[i] = Qnil;
6701   }
6702   staticpro (&mule_to_ucs_table);
6703   mule_to_ucs_table = Fmake_char_table(Qgeneric);
6704 #endif /* defined(MULE) && !defined(UTF2000) */
6705 }