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