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