8742dee7b79dfe4d444f522e041856045eec4d02
[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                     (94, 2, 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 (94, 2, 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         int chars = 0;
4760         int single = 0;
4761
4762         if (c < '0' || c > '~')
4763           return 0; /* bad final byte */
4764
4765         if (iso->esc >= ISO_ESC_2_8 &&
4766             iso->esc <= ISO_ESC_2_15)
4767           {
4768             chars = (iso->esc >= ISO_ESC_2_12) ? 96 : 94;
4769             single = 1; /* single-byte */
4770             reg = (iso->esc - ISO_ESC_2_8) & 3;
4771           }
4772         else if (iso->esc >= ISO_ESC_2_4_8 &&
4773                  iso->esc <= ISO_ESC_2_4_15)
4774           {
4775             chars = (iso->esc >= ISO_ESC_2_4_12) ? 96 : 94;
4776             single = -1; /* multi-byte */
4777             reg = (iso->esc - ISO_ESC_2_4_8) & 3;
4778           }
4779         else
4780           {
4781             /* Can this ever be reached? -slb */
4782             abort();
4783           }
4784
4785         cs = CHARSET_BY_ATTRIBUTES (chars, single, c,
4786                                     *flags & CODING_STATE_R2L ?
4787                                     CHARSET_RIGHT_TO_LEFT :
4788                                     CHARSET_LEFT_TO_RIGHT);
4789         goto designated;
4790       }
4791     }
4792
4793  not_done:
4794   iso->esc_bytes[iso->esc_bytes_index++] = (unsigned char) c;
4795   return -1;
4796
4797  single_shift:
4798   if (check_invalid_charsets && !CHARSETP (iso->charset[reg]))
4799     /* can't invoke something that ain't there. */
4800     return 0;
4801   iso->esc = ISO_ESC_SINGLE_SHIFT;
4802   *flags &= CODING_STATE_ISO2022_LOCK;
4803   if (reg == 2)
4804     *flags |= CODING_STATE_SS2;
4805   else
4806     *flags |= CODING_STATE_SS3;
4807   return 1;
4808
4809  locking_shift:
4810   if (check_invalid_charsets &&
4811       !CHARSETP (iso->charset[reg]))
4812     /* can't invoke something that ain't there. */
4813     return 0;
4814   if (half)
4815     iso->register_right = reg;
4816   else
4817     iso->register_left = reg;
4818   *flags &= CODING_STATE_ISO2022_LOCK;
4819   iso->esc = ISO_ESC_LOCKING_SHIFT;
4820   return 1;
4821
4822  designated:
4823   if (NILP (cs) && check_invalid_charsets)
4824     {
4825       iso->invalid_designated[reg] = 1;
4826       iso->charset[reg] = Vcharset_ascii;
4827       iso->esc = ISO_ESC_DESIGNATE;
4828       *flags &= CODING_STATE_ISO2022_LOCK;
4829       iso->output_literally = 1;
4830       if (iso->switched_dir_and_no_valid_charset_yet)
4831         {
4832           /* We encountered a switch-direction followed by an
4833              invalid designation.  Ensure that the switch-direction
4834              gets outputted; otherwise it will probably get eaten
4835              when the text is written out again. */
4836           iso->switched_dir_and_no_valid_charset_yet = 0;
4837           iso->output_direction_sequence = 1;
4838           /* And make sure that the switch-dir going the other
4839              way gets outputted, as well. */
4840           iso->invalid_switch_dir = 1;
4841         }
4842       return 1;
4843     }
4844   /* This function is called with CODESYS equal to nil when
4845      doing coding-system detection. */
4846   if (!NILP (codesys))
4847     {
4848       charset_conversion_spec_dynarr *dyn =
4849         XCODING_SYSTEM (codesys)->iso2022.input_conv;
4850
4851       if (dyn)
4852         {
4853           int i;
4854
4855           for (i = 0; i < Dynarr_length (dyn); i++)
4856             {
4857               struct charset_conversion_spec *spec = Dynarr_atp (dyn, i);
4858               if (EQ (cs, spec->from_charset))
4859                 cs = spec->to_charset;
4860             }
4861         }
4862     }
4863
4864   iso->charset[reg] = cs;
4865   iso->esc = ISO_ESC_DESIGNATE;
4866   *flags &= CODING_STATE_ISO2022_LOCK;
4867   if (iso->invalid_designated[reg])
4868     {
4869       iso->invalid_designated[reg] = 0;
4870       iso->output_literally = 1;
4871     }
4872   if (iso->switched_dir_and_no_valid_charset_yet)
4873     iso->switched_dir_and_no_valid_charset_yet = 0;
4874   return 1;
4875 }
4876
4877 static int
4878 detect_coding_iso2022 (struct detection_state *st, const unsigned char *src,
4879                        unsigned int n)
4880 {
4881   int mask;
4882
4883   /* #### There are serious deficiencies in the recognition mechanism
4884      here.  This needs to be much smarter if it's going to cut it.
4885      The sequence "\xff\x0f" is currently detected as LOCK_SHIFT while
4886      it should be detected as Latin-1.
4887      All the ISO2022 stuff in this file should be synced up with the
4888      code from FSF Emacs-20.4, in which Mule should be more or less stable.
4889      Perhaps we should wait till R2L works in FSF Emacs? */
4890
4891   if (!st->iso2022.initted)
4892     {
4893       reset_iso2022 (Qnil, &st->iso2022.iso);
4894       st->iso2022.mask = (CODING_CATEGORY_ISO_7_MASK |
4895                           CODING_CATEGORY_ISO_8_DESIGNATE_MASK |
4896                           CODING_CATEGORY_ISO_8_1_MASK |
4897                           CODING_CATEGORY_ISO_8_2_MASK |
4898                           CODING_CATEGORY_ISO_LOCK_SHIFT_MASK);
4899       st->iso2022.flags = 0;
4900       st->iso2022.high_byte_count = 0;
4901       st->iso2022.saw_single_shift = 0;
4902       st->iso2022.initted = 1;
4903     }
4904
4905   mask = st->iso2022.mask;
4906
4907   while (n--)
4908     {
4909       int c = *src++;
4910       if (c >= 0xA0)
4911         {
4912           mask &= ~CODING_CATEGORY_ISO_7_MASK;
4913           st->iso2022.high_byte_count++;
4914         }
4915       else
4916         {
4917           if (st->iso2022.high_byte_count && !st->iso2022.saw_single_shift)
4918             {
4919               if (st->iso2022.high_byte_count & 1)
4920                 /* odd number of high bytes; assume not iso-8-2 */
4921                 mask &= ~CODING_CATEGORY_ISO_8_2_MASK;
4922             }
4923           st->iso2022.high_byte_count = 0;
4924           st->iso2022.saw_single_shift = 0;
4925           if (c > 0x80)
4926             mask &= ~CODING_CATEGORY_ISO_7_MASK;
4927         }
4928       if (!(st->iso2022.flags & CODING_STATE_ESCAPE)
4929           && (BYTE_C0_P (c) || BYTE_C1_P (c)))
4930         { /* control chars */
4931           switch (c)
4932             {
4933               /* Allow and ignore control characters that you might
4934                  reasonably see in a text file */
4935             case '\r':
4936             case '\n':
4937             case '\t':
4938             case  7: /* bell */
4939             case  8: /* backspace */
4940             case 11: /* vertical tab */
4941             case 12: /* form feed */
4942             case 26: /* MS-DOS C-z junk */
4943             case 31: /* '^_' -- for info */
4944               goto label_continue_loop;
4945
4946             default:
4947               break;
4948             }
4949         }
4950
4951       if ((st->iso2022.flags & CODING_STATE_ESCAPE) || BYTE_C0_P (c)
4952           || BYTE_C1_P (c))
4953         {
4954           if (parse_iso2022_esc (Qnil, &st->iso2022.iso, c,
4955                                  &st->iso2022.flags, 0))
4956             {
4957               switch (st->iso2022.iso.esc)
4958                 {
4959                 case ISO_ESC_DESIGNATE:
4960                   mask &= ~CODING_CATEGORY_ISO_8_1_MASK;
4961                   mask &= ~CODING_CATEGORY_ISO_8_2_MASK;
4962                   break;
4963                 case ISO_ESC_LOCKING_SHIFT:
4964                   mask = CODING_CATEGORY_ISO_LOCK_SHIFT_MASK;
4965                   goto ran_out_of_chars;
4966                 case ISO_ESC_SINGLE_SHIFT:
4967                   mask &= ~CODING_CATEGORY_ISO_8_DESIGNATE_MASK;
4968                   st->iso2022.saw_single_shift = 1;
4969                   break;
4970                 default:
4971                   break;
4972                 }
4973             }
4974           else
4975             {
4976               mask = 0;
4977               goto ran_out_of_chars;
4978             }
4979         }
4980     label_continue_loop:;
4981     }
4982
4983  ran_out_of_chars:
4984
4985   return mask;
4986 }
4987
4988 static int
4989 postprocess_iso2022_mask (int mask)
4990 {
4991   /* #### kind of cheesy */
4992   /* If seven-bit ISO is allowed, then assume that the encoding is
4993      entirely seven-bit and turn off the eight-bit ones. */
4994   if (mask & CODING_CATEGORY_ISO_7_MASK)
4995     mask &= ~ (CODING_CATEGORY_ISO_8_DESIGNATE_MASK |
4996                CODING_CATEGORY_ISO_8_1_MASK |
4997                CODING_CATEGORY_ISO_8_2_MASK);
4998   return mask;
4999 }
5000
5001 /* If FLAGS is a null pointer or specifies right-to-left motion,
5002    output a switch-dir-to-left-to-right sequence to DST.
5003    Also update FLAGS if it is not a null pointer.
5004    If INTERNAL_P is set, we are outputting in internal format and
5005    need to handle the CSI differently. */
5006
5007 static void
5008 restore_left_to_right_direction (Lisp_Coding_System *codesys,
5009                                  unsigned_char_dynarr *dst,
5010                                  unsigned int *flags,
5011                                  int internal_p)
5012 {
5013   if (!flags || (*flags & CODING_STATE_R2L))
5014     {
5015       if (CODING_SYSTEM_ISO2022_SEVEN (codesys))
5016         {
5017           Dynarr_add (dst, ISO_CODE_ESC);
5018           Dynarr_add (dst, '[');
5019         }
5020       else if (internal_p)
5021         DECODE_ADD_BINARY_CHAR (ISO_CODE_CSI, dst);
5022       else
5023         Dynarr_add (dst, ISO_CODE_CSI);
5024       Dynarr_add (dst, '0');
5025       Dynarr_add (dst, ']');
5026       if (flags)
5027         *flags &= ~CODING_STATE_R2L;
5028     }
5029 }
5030
5031 /* If FLAGS is a null pointer or specifies a direction different from
5032    DIRECTION (which should be either CHARSET_RIGHT_TO_LEFT or
5033    CHARSET_LEFT_TO_RIGHT), output the appropriate switch-dir escape
5034    sequence to DST.  Also update FLAGS if it is not a null pointer.
5035    If INTERNAL_P is set, we are outputting in internal format and
5036    need to handle the CSI differently. */
5037
5038 static void
5039 ensure_correct_direction (int direction, Lisp_Coding_System *codesys,
5040                           unsigned_char_dynarr *dst, unsigned int *flags,
5041                           int internal_p)
5042 {
5043   if ((!flags || (*flags & CODING_STATE_R2L)) &&
5044       direction == CHARSET_LEFT_TO_RIGHT)
5045     restore_left_to_right_direction (codesys, dst, flags, internal_p);
5046   else if (!CODING_SYSTEM_ISO2022_NO_ISO6429 (codesys)
5047            && (!flags || !(*flags & CODING_STATE_R2L)) &&
5048            direction == CHARSET_RIGHT_TO_LEFT)
5049     {
5050       if (CODING_SYSTEM_ISO2022_SEVEN (codesys))
5051         {
5052           Dynarr_add (dst, ISO_CODE_ESC);
5053           Dynarr_add (dst, '[');
5054         }
5055       else if (internal_p)
5056         DECODE_ADD_BINARY_CHAR (ISO_CODE_CSI, dst);
5057       else
5058         Dynarr_add (dst, ISO_CODE_CSI);
5059       Dynarr_add (dst, '2');
5060       Dynarr_add (dst, ']');
5061       if (flags)
5062         *flags |= CODING_STATE_R2L;
5063     }
5064 }
5065
5066 /* Convert ISO2022-format data to internal format. */
5067
5068 static void
5069 decode_coding_iso2022 (Lstream *decoding, const unsigned char *src,
5070                        unsigned_char_dynarr *dst, unsigned int n)
5071 {
5072   struct decoding_stream *str = DECODING_STREAM_DATA (decoding);
5073   unsigned int flags  = str->flags;
5074   unsigned int ch     = str->ch;
5075   eol_type_t eol_type = str->eol_type;
5076 #ifdef ENABLE_COMPOSITE_CHARS
5077   unsigned_char_dynarr *real_dst = dst;
5078 #endif
5079   Lisp_Object coding_system;
5080
5081   XSETCODING_SYSTEM (coding_system, str->codesys);
5082
5083 #ifdef ENABLE_COMPOSITE_CHARS
5084   if (flags & CODING_STATE_COMPOSITE)
5085     dst = str->iso2022.composite_chars;
5086 #endif /* ENABLE_COMPOSITE_CHARS */
5087
5088   while (n--)
5089     {
5090       unsigned char c = *src++;
5091       if (flags & CODING_STATE_ESCAPE)
5092         {       /* Within ESC sequence */
5093           int retval = parse_iso2022_esc (coding_system, &str->iso2022,
5094                                           c, &flags, 1);
5095
5096           if (retval)
5097             {
5098               switch (str->iso2022.esc)
5099                 {
5100 #ifdef ENABLE_COMPOSITE_CHARS
5101                 case ISO_ESC_START_COMPOSITE:
5102                   if (str->iso2022.composite_chars)
5103                     Dynarr_reset (str->iso2022.composite_chars);
5104                   else
5105                     str->iso2022.composite_chars = Dynarr_new (unsigned_char);
5106                   dst = str->iso2022.composite_chars;
5107                   break;
5108                 case ISO_ESC_END_COMPOSITE:
5109                   {
5110                     Bufbyte comstr[MAX_EMCHAR_LEN];
5111                     Bytecount len;
5112                     Emchar emch = lookup_composite_char (Dynarr_atp (dst, 0),
5113                                                          Dynarr_length (dst));
5114                     dst = real_dst;
5115                     len = set_charptr_emchar (comstr, emch);
5116                     Dynarr_add_many (dst, comstr, len);
5117                     break;
5118                   }
5119 #endif /* ENABLE_COMPOSITE_CHARS */
5120
5121                 case ISO_ESC_LITERAL:
5122                   DECODE_ADD_BINARY_CHAR (c, dst);
5123                   break;
5124
5125                 default:
5126                   /* Everything else handled already */
5127                   break;
5128                 }
5129             }
5130
5131           /* Attempted error recovery. */
5132           if (str->iso2022.output_direction_sequence)
5133             ensure_correct_direction (flags & CODING_STATE_R2L ?
5134                                       CHARSET_RIGHT_TO_LEFT :
5135                                       CHARSET_LEFT_TO_RIGHT,
5136                                       str->codesys, dst, 0, 1);
5137           /* More error recovery. */
5138           if (!retval || str->iso2022.output_literally)
5139             {
5140               /* Output the (possibly invalid) sequence */
5141               int i;
5142               for (i = 0; i < str->iso2022.esc_bytes_index; i++)
5143                 DECODE_ADD_BINARY_CHAR (str->iso2022.esc_bytes[i], dst);
5144               flags &= CODING_STATE_ISO2022_LOCK;
5145               if (!retval)
5146                 n++, src--;/* Repeat the loop with the same character. */
5147               else
5148                 {
5149                   /* No sense in reprocessing the final byte of the
5150                      escape sequence; it could mess things up anyway.
5151                      Just add it now. */
5152                   DECODE_ADD_BINARY_CHAR (c, dst);
5153                 }
5154             }
5155           ch = 0;
5156         }
5157       else if (BYTE_C0_P (c) || BYTE_C1_P (c))
5158         { /* Control characters */
5159
5160           /***** Error-handling *****/
5161
5162           /* If we were in the middle of a character, dump out the
5163              partial character. */
5164           DECODE_OUTPUT_PARTIAL_CHAR (ch);
5165
5166           /* If we just saw a single-shift character, dump it out.
5167              This may dump out the wrong sort of single-shift character,
5168              but least it will give an indication that something went
5169              wrong. */
5170           if (flags & CODING_STATE_SS2)
5171             {
5172               DECODE_ADD_BINARY_CHAR (ISO_CODE_SS2, dst);
5173               flags &= ~CODING_STATE_SS2;
5174             }
5175           if (flags & CODING_STATE_SS3)
5176             {
5177               DECODE_ADD_BINARY_CHAR (ISO_CODE_SS3, dst);
5178               flags &= ~CODING_STATE_SS3;
5179             }
5180
5181           /***** Now handle the control characters. *****/
5182
5183           /* Handle CR/LF */
5184           DECODE_HANDLE_EOL_TYPE (eol_type, c, flags, dst);
5185
5186           flags &= CODING_STATE_ISO2022_LOCK;
5187
5188           if (!parse_iso2022_esc (coding_system, &str->iso2022, c, &flags, 1))
5189             DECODE_ADD_BINARY_CHAR (c, dst);
5190         }
5191       else
5192         {                       /* Graphic characters */
5193           Lisp_Object charset;
5194 #ifndef UTF2000
5195           Charset_ID lb;
5196 #endif
5197           int reg;
5198
5199           DECODE_HANDLE_EOL_TYPE (eol_type, c, flags, dst);
5200
5201           /* Now determine the charset. */
5202           reg = ((flags & CODING_STATE_SS2) ? 2
5203                  : (flags & CODING_STATE_SS3) ? 3
5204                  : !BYTE_ASCII_P (c) ? str->iso2022.register_right
5205                  : str->iso2022.register_left);
5206           charset = str->iso2022.charset[reg];
5207
5208           /* Error checking: */
5209           if (! CHARSETP (charset)
5210               || str->iso2022.invalid_designated[reg]
5211               || (((c & 0x7F) == ' ' || (c & 0x7F) == ISO_CODE_DEL)
5212                   && XCHARSET_CHARS (charset) == 94))
5213             /* Mrmph.  We are trying to invoke a register that has no
5214                or an invalid charset in it, or trying to add a character
5215                outside the range of the charset.  Insert that char literally
5216                to preserve it for the output. */
5217             {
5218               DECODE_OUTPUT_PARTIAL_CHAR (ch);
5219               DECODE_ADD_BINARY_CHAR (c, dst);
5220             }
5221
5222           else
5223             {
5224               /* Things are probably hunky-dorey. */
5225
5226               /* Fetch reverse charset, maybe. */
5227               if (((flags & CODING_STATE_R2L) &&
5228                    XCHARSET_DIRECTION (charset) == CHARSET_LEFT_TO_RIGHT)
5229                   ||
5230                   (!(flags & CODING_STATE_R2L) &&
5231                    XCHARSET_DIRECTION (charset) == CHARSET_RIGHT_TO_LEFT))
5232                 {
5233                   Lisp_Object new_charset =
5234                     XCHARSET_REVERSE_DIRECTION_CHARSET (charset);
5235                   if (!NILP (new_charset))
5236                     charset = new_charset;
5237                 }
5238
5239 #ifdef UTF2000
5240               if (XCHARSET_DIMENSION (charset) == 1)
5241                 {
5242                   DECODE_OUTPUT_PARTIAL_CHAR (ch);
5243                   DECODE_ADD_UCS_CHAR
5244                     (MAKE_CHAR (charset, c & 0x7F, 0), dst);
5245                 }
5246               else if (ch)
5247                 {
5248                   DECODE_ADD_UCS_CHAR
5249                     (MAKE_CHAR (charset, ch & 0x7F, c & 0x7F), dst);
5250                   ch = 0;
5251                 }
5252               else
5253                 ch = c;
5254 #else
5255               lb = XCHARSET_LEADING_BYTE (charset);
5256               switch (XCHARSET_REP_BYTES (charset))
5257                 {
5258                 case 1: /* ASCII */
5259                   DECODE_OUTPUT_PARTIAL_CHAR (ch);
5260                   Dynarr_add (dst, c & 0x7F);
5261                   break;
5262
5263                 case 2: /* one-byte official */
5264                   DECODE_OUTPUT_PARTIAL_CHAR (ch);
5265                   Dynarr_add (dst, lb);
5266                   Dynarr_add (dst, c | 0x80);
5267                   break;
5268
5269                 case 3: /* one-byte private or two-byte official */
5270                   if (XCHARSET_PRIVATE_P (charset))
5271                     {
5272                       DECODE_OUTPUT_PARTIAL_CHAR (ch);
5273                       Dynarr_add (dst, PRE_LEADING_BYTE_PRIVATE_1);
5274                       Dynarr_add (dst, lb);
5275                       Dynarr_add (dst, c | 0x80);
5276                     }
5277                   else
5278                     {
5279                       if (ch)
5280                         {
5281                           Dynarr_add (dst, lb);
5282                           Dynarr_add (dst, ch | 0x80);
5283                           Dynarr_add (dst, c | 0x80);
5284                           ch = 0;
5285                         }
5286                       else
5287                         ch = c;
5288                     }
5289                   break;
5290
5291                 default:        /* two-byte private */
5292                   if (ch)
5293                     {
5294                       Dynarr_add (dst, PRE_LEADING_BYTE_PRIVATE_2);
5295                       Dynarr_add (dst, lb);
5296                       Dynarr_add (dst, ch | 0x80);
5297                       Dynarr_add (dst, c | 0x80);
5298                       ch = 0;
5299                     }
5300                   else
5301                     ch = c;
5302                 }
5303 #endif
5304             }
5305
5306           if (!ch)
5307             flags &= CODING_STATE_ISO2022_LOCK;
5308         }
5309
5310     label_continue_loop:;
5311     }
5312
5313   if (flags & CODING_STATE_END)
5314     DECODE_OUTPUT_PARTIAL_CHAR (ch);
5315
5316   str->flags = flags;
5317   str->ch    = ch;
5318 }
5319
5320
5321 /***** ISO2022 encoder *****/
5322
5323 /* Designate CHARSET into register REG. */
5324
5325 static void
5326 iso2022_designate (Lisp_Object charset, unsigned char reg,
5327                    struct encoding_stream *str, unsigned_char_dynarr *dst)
5328 {
5329   static const char inter94[] = "()*+";
5330   static const char inter96[] = ",-./";
5331   unsigned int type;
5332   unsigned char final;
5333   Lisp_Object old_charset = str->iso2022.charset[reg];
5334
5335   str->iso2022.charset[reg] = charset;
5336   if (!CHARSETP (charset))
5337     /* charset might be an initial nil or t. */
5338     return;
5339   type = XCHARSET_TYPE (charset);
5340   final = XCHARSET_FINAL (charset);
5341   if (!str->iso2022.force_charset_on_output[reg] &&
5342       CHARSETP (old_charset) &&
5343       XCHARSET_TYPE (old_charset) == type &&
5344       XCHARSET_FINAL (old_charset) == final)
5345     return;
5346
5347   str->iso2022.force_charset_on_output[reg] = 0;
5348
5349   {
5350     charset_conversion_spec_dynarr *dyn =
5351       str->codesys->iso2022.output_conv;
5352
5353     if (dyn)
5354       {
5355         int i;
5356
5357         for (i = 0; i < Dynarr_length (dyn); i++)
5358           {
5359             struct charset_conversion_spec *spec = Dynarr_atp (dyn, i);
5360             if (EQ (charset, spec->from_charset))
5361                 charset = spec->to_charset;
5362           }
5363       }
5364   }
5365
5366   Dynarr_add (dst, ISO_CODE_ESC);
5367   switch (type)
5368     {
5369     case CHARSET_TYPE_94:
5370       Dynarr_add (dst, inter94[reg]);
5371       break;
5372     case CHARSET_TYPE_96:
5373       Dynarr_add (dst, inter96[reg]);
5374       break;
5375     case CHARSET_TYPE_94X94:
5376       Dynarr_add (dst, '$');
5377       if (reg != 0
5378           || !(CODING_SYSTEM_ISO2022_SHORT (str->codesys))
5379           || final < '@'
5380           || final > 'B')
5381         Dynarr_add (dst, inter94[reg]);
5382       break;
5383     case CHARSET_TYPE_96X96:
5384       Dynarr_add (dst, '$');
5385       Dynarr_add (dst, inter96[reg]);
5386       break;
5387     }
5388   Dynarr_add (dst, final);
5389 }
5390
5391 static void
5392 ensure_normal_shift (struct encoding_stream *str, unsigned_char_dynarr *dst)
5393 {
5394   if (str->iso2022.register_left != 0)
5395     {
5396       Dynarr_add (dst, ISO_CODE_SI);
5397       str->iso2022.register_left = 0;
5398     }
5399 }
5400
5401 static void
5402 ensure_shift_out (struct encoding_stream *str, unsigned_char_dynarr *dst)
5403 {
5404   if (str->iso2022.register_left != 1)
5405     {
5406       Dynarr_add (dst, ISO_CODE_SO);
5407       str->iso2022.register_left = 1;
5408     }
5409 }
5410
5411 /* Convert internally-formatted data to ISO2022 format. */
5412
5413 static void
5414 encode_coding_iso2022 (Lstream *encoding, const unsigned char *src,
5415                        unsigned_char_dynarr *dst, unsigned int n)
5416 {
5417   unsigned char charmask, c;
5418   unsigned char char_boundary;
5419   struct encoding_stream *str = ENCODING_STREAM_DATA (encoding);
5420   unsigned int flags          = str->flags;
5421   Emchar ch                   = str->ch;
5422   Lisp_Coding_System *codesys = str->codesys;
5423   eol_type_t eol_type         = CODING_SYSTEM_EOL_TYPE (str->codesys);
5424   int i;
5425   Lisp_Object charset;
5426   int half;
5427 #ifdef UTF2000
5428   unsigned int byte1, byte2;
5429 #endif
5430
5431 #ifdef ENABLE_COMPOSITE_CHARS
5432   /* flags for handling composite chars.  We do a little switcharoo
5433      on the source while we're outputting the composite char. */
5434   unsigned int saved_n = 0;
5435   const unsigned char *saved_src = NULL;
5436   int in_composite = 0;
5437 #endif /* ENABLE_COMPOSITE_CHARS */
5438
5439   char_boundary = str->iso2022.current_char_boundary;
5440   charset = str->iso2022.current_charset;
5441   half = str->iso2022.current_half;
5442
5443 #ifdef ENABLE_COMPOSITE_CHARS
5444  back_to_square_n:
5445 #endif
5446 #ifdef UTF2000
5447   while (n--)
5448     {
5449       c = *src++;
5450
5451       switch (char_boundary)
5452         {
5453         case 0:
5454           if ( c >= 0xfc )
5455             {
5456               ch = c & 0x01;
5457               char_boundary = 5;
5458             }
5459           else if ( c >= 0xf8 )
5460             {
5461               ch = c & 0x03;
5462               char_boundary = 4;
5463             }
5464           else if ( c >= 0xf0 )
5465             {
5466               ch = c & 0x07;
5467               char_boundary = 3;
5468             }
5469           else if ( c >= 0xe0 )
5470             {
5471               ch = c & 0x0f;
5472               char_boundary = 2;
5473             }
5474           else if ( c >= 0xc0 )
5475             {
5476               ch = c & 0x1f;
5477               char_boundary = 1;
5478             }
5479           else
5480             {
5481               ch = 0;
5482
5483               restore_left_to_right_direction (codesys, dst, &flags, 0);
5484               
5485               /* Make sure G0 contains ASCII */
5486               if ((c > ' ' && c < ISO_CODE_DEL) ||
5487                   !CODING_SYSTEM_ISO2022_NO_ASCII_CNTL (codesys))
5488                 {
5489                   ensure_normal_shift (str, dst);
5490                   iso2022_designate (Vcharset_ascii, 0, str, dst);
5491                 }
5492               
5493               /* If necessary, restore everything to the default state
5494                  at end-of-line */
5495               if (c == '\n' &&
5496                   !(CODING_SYSTEM_ISO2022_NO_ASCII_EOL (codesys)))
5497                 {
5498                   restore_left_to_right_direction (codesys, dst, &flags, 0);
5499
5500                   ensure_normal_shift (str, dst);
5501
5502                   for (i = 0; i < 4; i++)
5503                     {
5504                       Lisp_Object initial_charset =
5505                         CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, i);
5506                       iso2022_designate (initial_charset, i, str, dst);
5507                     }
5508                 }
5509               if (c == '\n')
5510                 {
5511                   if (eol_type != EOL_LF && eol_type != EOL_AUTODETECT)
5512                     Dynarr_add (dst, '\r');
5513                   if (eol_type != EOL_CR)
5514                     Dynarr_add (dst, c);
5515                 }
5516               else
5517                 {
5518                   if (CODING_SYSTEM_ISO2022_ESCAPE_QUOTED (codesys)
5519                       && fit_to_be_escape_quoted (c))
5520                     Dynarr_add (dst, ISO_CODE_ESC);
5521                   Dynarr_add (dst, c);
5522                 }
5523               char_boundary = 0;
5524             }
5525           break;
5526         case 1:
5527           ch = ( ch << 6 ) | ( c & 0x3f );
5528           
5529           char_boundary = 0;
5530           if ( (0x80 <= ch) && (ch <= 0x9f) )
5531             {
5532               charmask = (half == 0 ? 0x00 : 0x80);
5533           
5534               if (CODING_SYSTEM_ISO2022_ESCAPE_QUOTED (codesys)
5535                   && fit_to_be_escape_quoted (ch))
5536                 Dynarr_add (dst, ISO_CODE_ESC);
5537               /* you asked for it ... */
5538               Dynarr_add (dst, ch);
5539             }
5540           else
5541             {
5542               int reg;
5543
5544               BREAKUP_CHAR (ch, charset, byte1, byte2);
5545               ensure_correct_direction (XCHARSET_DIRECTION (charset),
5546                                         codesys, dst, &flags, 0);
5547
5548               /* Now determine which register to use. */
5549               reg = -1;
5550               for (i = 0; i < 4; i++)
5551                 {
5552                   if (EQ (charset, str->iso2022.charset[i]) ||
5553                       EQ (charset,
5554                           CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, i)))
5555                     {
5556                       reg = i;
5557                       break;
5558                     }
5559                 }
5560               
5561               if (reg == -1)
5562                 {
5563                   if (XCHARSET_GRAPHIC (charset) != 0)
5564                     {
5565                       if (!NILP (str->iso2022.charset[1]) &&
5566                           (!CODING_SYSTEM_ISO2022_SEVEN (codesys) ||
5567                            CODING_SYSTEM_ISO2022_LOCK_SHIFT (codesys)))
5568                         reg = 1;
5569                       else if (!NILP (str->iso2022.charset[2]))
5570                         reg = 2;
5571                       else if (!NILP (str->iso2022.charset[3]))
5572                         reg = 3;
5573                       else
5574                         reg = 0;
5575                     }
5576                   else
5577                     reg = 0;
5578                 }
5579               
5580               iso2022_designate (charset, reg, str, dst);
5581               
5582               /* Now invoke that register. */
5583               switch (reg)
5584                 {
5585                 case 0:
5586                   ensure_normal_shift (str, dst);
5587                   half = 0;
5588                   break;
5589                   
5590                 case 1:
5591                   if (CODING_SYSTEM_ISO2022_SEVEN (codesys))
5592                     {
5593                       ensure_shift_out (str, dst);
5594                       half = 0;
5595                     }
5596                   else
5597                     half = 1;
5598                   break;
5599                   
5600                 case 2:
5601                   if (CODING_SYSTEM_ISO2022_SEVEN (str->codesys))
5602                     {
5603                       Dynarr_add (dst, ISO_CODE_ESC);
5604                       Dynarr_add (dst, 'N');
5605                       half = 0;
5606                     }
5607                   else
5608                     {
5609                       Dynarr_add (dst, ISO_CODE_SS2);
5610                       half = 1;
5611                     }
5612                   break;
5613                   
5614                 case 3:
5615                   if (CODING_SYSTEM_ISO2022_SEVEN (str->codesys))
5616                     {
5617                       Dynarr_add (dst, ISO_CODE_ESC);
5618                       Dynarr_add (dst, 'O');
5619                       half = 0;
5620                     }
5621                   else
5622                     {
5623                       Dynarr_add (dst, ISO_CODE_SS3);
5624                       half = 1;
5625                     }
5626                   break;
5627                   
5628                 default:
5629                   abort ();
5630                 }
5631               
5632               charmask = (half == 0 ? 0x00 : 0x80);
5633               
5634               switch (XCHARSET_DIMENSION (charset))
5635                 {
5636                 case 1:
5637                   Dynarr_add (dst, byte1 | charmask);
5638                   break;
5639                 case 2:
5640                   Dynarr_add (dst, byte1 | charmask);
5641                   Dynarr_add (dst, byte2 | charmask);
5642                   break;
5643                 default:
5644                   abort ();
5645                 }
5646             }
5647           ch =0;
5648           break;
5649         default:
5650           ch = ( ch << 6 ) | ( c & 0x3f );
5651           char_boundary--;
5652         }
5653     }
5654 #else /* not UTF2000 */
5655
5656   while (n--)
5657     {
5658       c = *src++;
5659
5660       if (BYTE_ASCII_P (c))
5661         {               /* Processing ASCII character */
5662           ch = 0;
5663
5664           restore_left_to_right_direction (codesys, dst, &flags, 0);
5665
5666           /* Make sure G0 contains ASCII */
5667           if ((c > ' ' && c < ISO_CODE_DEL) ||
5668               !CODING_SYSTEM_ISO2022_NO_ASCII_CNTL (codesys))
5669             {
5670               ensure_normal_shift (str, dst);
5671               iso2022_designate (Vcharset_ascii, 0, str, dst);
5672             }
5673
5674           /* If necessary, restore everything to the default state
5675              at end-of-line */
5676           if (c == '\n' &&
5677               !(CODING_SYSTEM_ISO2022_NO_ASCII_EOL (codesys)))
5678             {
5679               restore_left_to_right_direction (codesys, dst, &flags, 0);
5680
5681               ensure_normal_shift (str, dst);
5682
5683               for (i = 0; i < 4; i++)
5684                 {
5685                   Lisp_Object initial_charset =
5686                     CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, i);
5687                   iso2022_designate (initial_charset, i, str, dst);
5688                 }
5689             }
5690           if (c == '\n')
5691             {
5692               if (eol_type != EOL_LF && eol_type != EOL_AUTODETECT)
5693                 Dynarr_add (dst, '\r');
5694               if (eol_type != EOL_CR)
5695                 Dynarr_add (dst, c);
5696             }
5697           else
5698             {
5699               if (CODING_SYSTEM_ISO2022_ESCAPE_QUOTED (codesys)
5700                   && fit_to_be_escape_quoted (c))
5701                 Dynarr_add (dst, ISO_CODE_ESC);
5702               Dynarr_add (dst, c);
5703             }
5704           char_boundary = 1;
5705         }
5706
5707       else if (BUFBYTE_LEADING_BYTE_P (c) || BUFBYTE_LEADING_BYTE_P (ch))
5708         { /* Processing Leading Byte */
5709           ch = 0;
5710           charset = CHARSET_BY_LEADING_BYTE (c);
5711           if (LEADING_BYTE_PREFIX_P(c))
5712             ch = c;
5713           else if (!EQ (charset, Vcharset_control_1)
5714 #ifdef ENABLE_COMPOSITE_CHARS
5715                    && !EQ (charset, Vcharset_composite)
5716 #endif
5717                    )
5718             {
5719               int reg;
5720
5721               ensure_correct_direction (XCHARSET_DIRECTION (charset),
5722                                         codesys, dst, &flags, 0);
5723
5724               /* Now determine which register to use. */
5725               reg = -1;
5726               for (i = 0; i < 4; i++)
5727                 {
5728                   if (EQ (charset, str->iso2022.charset[i]) ||
5729                       EQ (charset,
5730                           CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, i)))
5731                     {
5732                       reg = i;
5733                       break;
5734                     }
5735                 }
5736
5737               if (reg == -1)
5738                 {
5739                   if (XCHARSET_GRAPHIC (charset) != 0)
5740                     {
5741                       if (!NILP (str->iso2022.charset[1]) &&
5742                           (!CODING_SYSTEM_ISO2022_SEVEN (codesys) ||
5743                            CODING_SYSTEM_ISO2022_LOCK_SHIFT (codesys)))
5744                         reg = 1;
5745                       else if (!NILP (str->iso2022.charset[2]))
5746                         reg = 2;
5747                       else if (!NILP (str->iso2022.charset[3]))
5748                         reg = 3;
5749                       else
5750                         reg = 0;
5751                     }
5752                   else
5753                     reg = 0;
5754                 }
5755
5756               iso2022_designate (charset, reg, str, dst);
5757
5758               /* Now invoke that register. */
5759               switch (reg)
5760                 {
5761                 case 0:
5762                   ensure_normal_shift (str, dst);
5763                   half = 0;
5764                   break;
5765
5766                 case 1:
5767                   if (CODING_SYSTEM_ISO2022_SEVEN (codesys))
5768                     {
5769                       ensure_shift_out (str, dst);
5770                       half = 0;
5771                     }
5772                   else
5773                     half = 1;
5774                   break;
5775
5776                 case 2:
5777                   if (CODING_SYSTEM_ISO2022_SEVEN (str->codesys))
5778                     {
5779                       Dynarr_add (dst, ISO_CODE_ESC);
5780                       Dynarr_add (dst, 'N');
5781                       half = 0;
5782                     }
5783                   else
5784                     {
5785                       Dynarr_add (dst, ISO_CODE_SS2);
5786                       half = 1;
5787                     }
5788                   break;
5789
5790                 case 3:
5791                   if (CODING_SYSTEM_ISO2022_SEVEN (str->codesys))
5792                     {
5793                       Dynarr_add (dst, ISO_CODE_ESC);
5794                       Dynarr_add (dst, 'O');
5795                       half = 0;
5796                     }
5797                   else
5798                     {
5799                       Dynarr_add (dst, ISO_CODE_SS3);
5800                       half = 1;
5801                     }
5802                   break;
5803
5804                 default:
5805                   abort ();
5806                 }
5807             }
5808           char_boundary = 0;
5809         }
5810       else
5811         {                       /* Processing Non-ASCII character */
5812           charmask = (half == 0 ? 0x7F : 0xFF);
5813           char_boundary = 1;
5814           if (EQ (charset, Vcharset_control_1))
5815             {
5816               if (CODING_SYSTEM_ISO2022_ESCAPE_QUOTED (codesys)
5817                   && fit_to_be_escape_quoted (c))
5818                 Dynarr_add (dst, ISO_CODE_ESC);
5819               /* you asked for it ... */
5820               Dynarr_add (dst, c - 0x20);
5821             }
5822           else
5823             {
5824               switch (XCHARSET_REP_BYTES (charset))
5825                 {
5826                 case 2:
5827                   Dynarr_add (dst, c & charmask);
5828                   break;
5829                 case 3:
5830                   if (XCHARSET_PRIVATE_P (charset))
5831                     {
5832                       Dynarr_add (dst, c & charmask);
5833                       ch = 0;
5834                     }
5835                   else if (ch)
5836                     {
5837 #ifdef ENABLE_COMPOSITE_CHARS
5838                       if (EQ (charset, Vcharset_composite))
5839                         {
5840                           if (in_composite)
5841                             {
5842                               /* #### Bother! We don't know how to
5843                                  handle this yet. */
5844                               Dynarr_add (dst, '~');
5845                             }
5846                           else
5847                             {
5848                               Emchar emch = MAKE_CHAR (Vcharset_composite,
5849                                                        ch & 0x7F, c & 0x7F);
5850                               Lisp_Object lstr = composite_char_string (emch);
5851                               saved_n = n;
5852                               saved_src = src;
5853                               in_composite = 1;
5854                               src = XSTRING_DATA   (lstr);
5855                               n   = XSTRING_LENGTH (lstr);
5856                               Dynarr_add (dst, ISO_CODE_ESC);
5857                               Dynarr_add (dst, '0'); /* start composing */
5858                             }
5859                         }
5860                       else
5861 #endif /* ENABLE_COMPOSITE_CHARS */
5862                         {
5863                           Dynarr_add (dst, ch & charmask);
5864                           Dynarr_add (dst, c & charmask);
5865                         }
5866                       ch = 0;
5867                     }
5868                   else
5869                     {
5870                       ch = c;
5871                       char_boundary = 0;
5872                     }
5873                   break;
5874                 case 4:
5875                   if (ch)
5876                     {
5877                       Dynarr_add (dst, ch & charmask);
5878                       Dynarr_add (dst, c & charmask);
5879                       ch = 0;
5880                     }
5881                   else
5882                     {
5883                       ch = c;
5884                       char_boundary = 0;
5885                     }
5886                   break;
5887                 default:
5888                   abort ();
5889                 }
5890             }
5891         }
5892     }
5893 #endif /* not UTF2000 */
5894
5895 #ifdef ENABLE_COMPOSITE_CHARS
5896   if (in_composite)
5897     {
5898       n = saved_n;
5899       src = saved_src;
5900       in_composite = 0;
5901       Dynarr_add (dst, ISO_CODE_ESC);
5902       Dynarr_add (dst, '1'); /* end composing */
5903       goto back_to_square_n; /* Wheeeeeeeee ..... */
5904     }
5905 #endif /* ENABLE_COMPOSITE_CHARS */
5906
5907 #ifdef UTF2000
5908   if ( (char_boundary == 0) && flags & CODING_STATE_END)
5909 #else
5910   if (char_boundary && flags & CODING_STATE_END)
5911 #endif
5912     {
5913       restore_left_to_right_direction (codesys, dst, &flags, 0);
5914       ensure_normal_shift (str, dst);
5915       for (i = 0; i < 4; i++)
5916         {
5917           Lisp_Object initial_charset =
5918             CODING_SYSTEM_ISO2022_INITIAL_CHARSET (codesys, i);
5919           iso2022_designate (initial_charset, i, str, dst);
5920         }
5921     }
5922
5923   str->flags = flags;
5924   str->ch    = ch;
5925   str->iso2022.current_char_boundary = char_boundary;
5926   str->iso2022.current_charset = charset;
5927   str->iso2022.current_half = half;
5928
5929   /* Verbum caro factum est! */
5930 }
5931 #endif /* MULE */
5932 \f
5933 /************************************************************************/
5934 /*                     No-conversion methods                            */
5935 /************************************************************************/
5936
5937 /* This is used when reading in "binary" files -- i.e. files that may
5938    contain all 256 possible byte values and that are not to be
5939    interpreted as being in any particular decoding. */
5940 static void
5941 decode_coding_no_conversion (Lstream *decoding, const unsigned char *src,
5942                              unsigned_char_dynarr *dst, unsigned int n)
5943 {
5944   unsigned char c;
5945   struct decoding_stream *str = DECODING_STREAM_DATA (decoding);
5946   unsigned int flags  = str->flags;
5947   unsigned int ch     = str->ch;
5948   eol_type_t eol_type = str->eol_type;
5949
5950   while (n--)
5951     {
5952       c = *src++;
5953
5954       DECODE_HANDLE_EOL_TYPE (eol_type, c, flags, dst);
5955       DECODE_ADD_BINARY_CHAR (c, dst);
5956     label_continue_loop:;
5957     }
5958
5959   DECODE_HANDLE_END_OF_CONVERSION (flags, ch, dst);
5960
5961   str->flags = flags;
5962   str->ch    = ch;
5963 }
5964
5965 static void
5966 encode_coding_no_conversion (Lstream *encoding, const unsigned char *src,
5967                              unsigned_char_dynarr *dst, unsigned int n)
5968 {
5969   unsigned char c;
5970   struct encoding_stream *str = ENCODING_STREAM_DATA (encoding);
5971   unsigned int flags  = str->flags;
5972   unsigned int ch     = str->ch;
5973   eol_type_t eol_type = CODING_SYSTEM_EOL_TYPE (str->codesys);
5974 #ifdef UTF2000
5975   unsigned char char_boundary = str->iso2022.current_char_boundary;
5976 #endif
5977
5978   while (n--)
5979     {
5980       c = *src++;         
5981 #ifdef UTF2000
5982       switch (char_boundary)
5983         {
5984         case 0:
5985           if ( c >= 0xfc )
5986             {
5987               ch = c & 0x01;
5988               char_boundary = 5;
5989             }
5990           else if ( c >= 0xf8 )
5991             {
5992               ch = c & 0x03;
5993               char_boundary = 4;
5994             }
5995           else if ( c >= 0xf0 )
5996             {
5997               ch = c & 0x07;
5998               char_boundary = 3;
5999             }
6000           else if ( c >= 0xe0 )
6001             {
6002               ch = c & 0x0f;
6003               char_boundary = 2;
6004             }
6005           else if ( c >= 0xc0 )
6006             {
6007               ch = c & 0x1f;
6008               char_boundary = 1;
6009             }
6010           else
6011             {
6012               ch = 0;
6013
6014               if (c == '\n')
6015                 {
6016                   if (eol_type != EOL_LF && eol_type != EOL_AUTODETECT)
6017                     Dynarr_add (dst, '\r');
6018                   if (eol_type != EOL_CR)
6019                     Dynarr_add (dst, c);
6020                 }
6021               else
6022                 Dynarr_add (dst, c);
6023               char_boundary = 0;
6024             }
6025           break;
6026         case 1:
6027           ch = ( ch << 6 ) | ( c & 0x3f );
6028           Dynarr_add (dst, ch & 0xff);
6029           char_boundary = 0;
6030           break;
6031         default:
6032           ch = ( ch << 6 ) | ( c & 0x3f );
6033           char_boundary--;
6034         }
6035 #else /* not UTF2000 */
6036       if (c == '\n')
6037         {
6038           if (eol_type != EOL_LF && eol_type != EOL_AUTODETECT)
6039             Dynarr_add (dst, '\r');
6040           if (eol_type != EOL_CR)
6041             Dynarr_add (dst, '\n');
6042           ch = 0;
6043         }
6044       else if (BYTE_ASCII_P (c))
6045         {
6046           assert (ch == 0);
6047           Dynarr_add (dst, c);
6048         }
6049       else if (BUFBYTE_LEADING_BYTE_P (c))
6050         {
6051           assert (ch == 0);
6052           if (c == LEADING_BYTE_LATIN_ISO8859_1 ||
6053               c == LEADING_BYTE_CONTROL_1)
6054             ch = c;
6055           else
6056             Dynarr_add (dst, '~'); /* untranslatable character */
6057         }
6058       else
6059         {
6060           if (ch == LEADING_BYTE_LATIN_ISO8859_1)
6061             Dynarr_add (dst, c);
6062           else if (ch == LEADING_BYTE_CONTROL_1)
6063             {
6064               assert (c < 0xC0);
6065               Dynarr_add (dst, c - 0x20);
6066             }
6067           /* else it should be the second or third byte of an
6068              untranslatable character, so ignore it */
6069           ch = 0;
6070         }
6071 #endif /* not UTF2000 */
6072     }
6073
6074   str->flags = flags;
6075   str->ch    = ch;
6076 #ifdef UTF2000
6077   str->iso2022.current_char_boundary = char_boundary;
6078 #endif
6079 }
6080
6081 \f
6082
6083 /************************************************************************/
6084 /*                             Initialization                           */
6085 /************************************************************************/
6086
6087 void
6088 syms_of_file_coding (void)
6089 {
6090   INIT_LRECORD_IMPLEMENTATION (coding_system);
6091
6092   deferror (&Qcoding_system_error, "coding-system-error",
6093             "Coding-system error", Qio_error);
6094
6095   DEFSUBR (Fcoding_system_p);
6096   DEFSUBR (Ffind_coding_system);
6097   DEFSUBR (Fget_coding_system);
6098   DEFSUBR (Fcoding_system_list);
6099   DEFSUBR (Fcoding_system_name);
6100   DEFSUBR (Fmake_coding_system);
6101   DEFSUBR (Fcopy_coding_system);
6102   DEFSUBR (Fcoding_system_canonical_name_p);
6103   DEFSUBR (Fcoding_system_alias_p);
6104   DEFSUBR (Fcoding_system_aliasee);
6105   DEFSUBR (Fdefine_coding_system_alias);
6106   DEFSUBR (Fsubsidiary_coding_system);
6107
6108   DEFSUBR (Fcoding_system_type);
6109   DEFSUBR (Fcoding_system_doc_string);
6110 #ifdef MULE
6111   DEFSUBR (Fcoding_system_charset);
6112 #endif
6113   DEFSUBR (Fcoding_system_property);
6114
6115   DEFSUBR (Fcoding_category_list);
6116   DEFSUBR (Fset_coding_priority_list);
6117   DEFSUBR (Fcoding_priority_list);
6118   DEFSUBR (Fset_coding_category_system);
6119   DEFSUBR (Fcoding_category_system);
6120
6121   DEFSUBR (Fdetect_coding_region);
6122   DEFSUBR (Fdecode_coding_region);
6123   DEFSUBR (Fencode_coding_region);
6124 #ifdef MULE
6125   DEFSUBR (Fdecode_shift_jis_char);
6126   DEFSUBR (Fencode_shift_jis_char);
6127   DEFSUBR (Fdecode_big5_char);
6128   DEFSUBR (Fencode_big5_char);
6129 #ifndef UTF2000
6130   DEFSUBR (Fset_ucs_char);
6131   DEFSUBR (Fucs_char);
6132   DEFSUBR (Fset_char_ucs);
6133   DEFSUBR (Fchar_ucs);
6134 #endif /* not UTF2000 */
6135 #endif /* MULE */
6136   defsymbol (&Qcoding_systemp, "coding-system-p");
6137   defsymbol (&Qno_conversion, "no-conversion");
6138   defsymbol (&Qraw_text, "raw-text");
6139 #ifdef MULE
6140   defsymbol (&Qbig5, "big5");
6141   defsymbol (&Qshift_jis, "shift-jis");
6142   defsymbol (&Qucs4, "ucs-4");
6143   defsymbol (&Qutf8, "utf-8");
6144   defsymbol (&Qccl, "ccl");
6145   defsymbol (&Qiso2022, "iso2022");
6146 #endif /* MULE */
6147   defsymbol (&Qmnemonic, "mnemonic");
6148   defsymbol (&Qeol_type, "eol-type");
6149   defsymbol (&Qpost_read_conversion, "post-read-conversion");
6150   defsymbol (&Qpre_write_conversion, "pre-write-conversion");
6151
6152   defsymbol (&Qcr, "cr");
6153   defsymbol (&Qlf, "lf");
6154   defsymbol (&Qcrlf, "crlf");
6155   defsymbol (&Qeol_cr, "eol-cr");
6156   defsymbol (&Qeol_lf, "eol-lf");
6157   defsymbol (&Qeol_crlf, "eol-crlf");
6158 #ifdef MULE
6159   defsymbol (&Qcharset_g0, "charset-g0");
6160   defsymbol (&Qcharset_g1, "charset-g1");
6161   defsymbol (&Qcharset_g2, "charset-g2");
6162   defsymbol (&Qcharset_g3, "charset-g3");
6163   defsymbol (&Qforce_g0_on_output, "force-g0-on-output");
6164   defsymbol (&Qforce_g1_on_output, "force-g1-on-output");
6165   defsymbol (&Qforce_g2_on_output, "force-g2-on-output");
6166   defsymbol (&Qforce_g3_on_output, "force-g3-on-output");
6167   defsymbol (&Qno_iso6429, "no-iso6429");
6168   defsymbol (&Qinput_charset_conversion, "input-charset-conversion");
6169   defsymbol (&Qoutput_charset_conversion, "output-charset-conversion");
6170
6171   defsymbol (&Qshort, "short");
6172   defsymbol (&Qno_ascii_eol, "no-ascii-eol");
6173   defsymbol (&Qno_ascii_cntl, "no-ascii-cntl");
6174   defsymbol (&Qseven, "seven");
6175   defsymbol (&Qlock_shift, "lock-shift");
6176   defsymbol (&Qescape_quoted, "escape-quoted");
6177 #endif /* MULE */
6178   defsymbol (&Qencode, "encode");
6179   defsymbol (&Qdecode, "decode");
6180
6181 #ifdef MULE
6182   defsymbol (&coding_category_symbol[CODING_CATEGORY_SHIFT_JIS],
6183              "shift-jis");
6184   defsymbol (&coding_category_symbol[CODING_CATEGORY_BIG5],
6185              "big5");
6186   defsymbol (&coding_category_symbol[CODING_CATEGORY_UCS4],
6187              "ucs-4");
6188   defsymbol (&coding_category_symbol[CODING_CATEGORY_UTF8],
6189              "utf-8");
6190   defsymbol (&coding_category_symbol[CODING_CATEGORY_ISO_7],
6191              "iso-7");
6192   defsymbol (&coding_category_symbol[CODING_CATEGORY_ISO_8_DESIGNATE],
6193              "iso-8-designate");
6194   defsymbol (&coding_category_symbol[CODING_CATEGORY_ISO_8_1],
6195              "iso-8-1");
6196   defsymbol (&coding_category_symbol[CODING_CATEGORY_ISO_8_2],
6197              "iso-8-2");
6198   defsymbol (&coding_category_symbol[CODING_CATEGORY_ISO_LOCK_SHIFT],
6199              "iso-lock-shift");
6200 #endif /* MULE */
6201   defsymbol (&coding_category_symbol[CODING_CATEGORY_NO_CONVERSION],
6202              "no-conversion");
6203 }
6204
6205 void
6206 lstream_type_create_file_coding (void)
6207 {
6208   LSTREAM_HAS_METHOD (decoding, reader);
6209   LSTREAM_HAS_METHOD (decoding, writer);
6210   LSTREAM_HAS_METHOD (decoding, rewinder);
6211   LSTREAM_HAS_METHOD (decoding, seekable_p);
6212   LSTREAM_HAS_METHOD (decoding, flusher);
6213   LSTREAM_HAS_METHOD (decoding, closer);
6214   LSTREAM_HAS_METHOD (decoding, marker);
6215
6216   LSTREAM_HAS_METHOD (encoding, reader);
6217   LSTREAM_HAS_METHOD (encoding, writer);
6218   LSTREAM_HAS_METHOD (encoding, rewinder);
6219   LSTREAM_HAS_METHOD (encoding, seekable_p);
6220   LSTREAM_HAS_METHOD (encoding, flusher);
6221   LSTREAM_HAS_METHOD (encoding, closer);
6222   LSTREAM_HAS_METHOD (encoding, marker);
6223 }
6224
6225 void
6226 vars_of_file_coding (void)
6227 {
6228   int i;
6229
6230   fcd = xnew (struct file_coding_dump);
6231   dumpstruct (&fcd, &fcd_description);
6232
6233   /* Initialize to something reasonable ... */
6234   for (i = 0; i <= CODING_CATEGORY_LAST; i++)
6235     {
6236       fcd->coding_category_system[i] = Qnil;
6237       fcd->coding_category_by_priority[i] = i;
6238     }
6239
6240   Fprovide (intern ("file-coding"));
6241
6242   DEFVAR_LISP ("keyboard-coding-system", &Vkeyboard_coding_system /*
6243 Coding system used for TTY keyboard input.
6244 Not used under a windowing system.
6245 */ );
6246   Vkeyboard_coding_system = Qnil;
6247
6248   DEFVAR_LISP ("terminal-coding-system", &Vterminal_coding_system /*
6249 Coding system used for TTY display output.
6250 Not used under a windowing system.
6251 */ );
6252   Vterminal_coding_system = Qnil;
6253
6254   DEFVAR_LISP ("coding-system-for-read", &Vcoding_system_for_read /*
6255 Overriding coding system used when reading from a file or process.
6256 You should bind this variable with `let', but do not set it globally.
6257 If this is non-nil, it specifies the coding system that will be used
6258 to decode input on read operations, such as from a file or process.
6259 It overrides `buffer-file-coding-system-for-read',
6260 `insert-file-contents-pre-hook', etc.  Use those variables instead of
6261 this one for permanent changes to the environment.  */ );
6262   Vcoding_system_for_read = Qnil;
6263
6264   DEFVAR_LISP ("coding-system-for-write",
6265                &Vcoding_system_for_write /*
6266 Overriding coding system used when writing to a file or process.
6267 You should bind this variable with `let', but do not set it globally.
6268 If this is non-nil, it specifies the coding system that will be used
6269 to encode output for write operations, such as to a file or process.
6270 It overrides `buffer-file-coding-system', `write-region-pre-hook', etc.
6271 Use those variables instead of this one for permanent changes to the
6272 environment.  */ );
6273   Vcoding_system_for_write = Qnil;
6274
6275   DEFVAR_LISP ("file-name-coding-system", &Vfile_name_coding_system /*
6276 Coding system used to convert pathnames when accessing files.
6277 */ );
6278   Vfile_name_coding_system = Qnil;
6279
6280   DEFVAR_BOOL ("enable-multibyte-characters", &enable_multibyte_characters /*
6281 Non-nil means the buffer contents are regarded as multi-byte form
6282 of characters, not a binary code.  This affects the display, file I/O,
6283 and behaviors of various editing commands.
6284
6285 Setting this to nil does not do anything.
6286 */ );
6287   enable_multibyte_characters = 1;
6288 }
6289
6290 void
6291 complex_vars_of_file_coding (void)
6292 {
6293   staticpro (&Vcoding_system_hash_table);
6294   Vcoding_system_hash_table =
6295     make_lisp_hash_table (50, HASH_TABLE_NON_WEAK, HASH_TABLE_EQ);
6296
6297   the_codesys_prop_dynarr = Dynarr_new (codesys_prop);
6298   dumpstruct (&the_codesys_prop_dynarr, &codesys_prop_dynarr_description);
6299
6300 #define DEFINE_CODESYS_PROP(Prop_Type, Sym) do  \
6301 {                                               \
6302   struct codesys_prop csp;                      \
6303   csp.sym = (Sym);                              \
6304   csp.prop_type = (Prop_Type);                  \
6305   Dynarr_add (the_codesys_prop_dynarr, csp);    \
6306 } while (0)
6307
6308   DEFINE_CODESYS_PROP (CODESYS_PROP_ALL_OK,  Qmnemonic);
6309   DEFINE_CODESYS_PROP (CODESYS_PROP_ALL_OK,  Qeol_type);
6310   DEFINE_CODESYS_PROP (CODESYS_PROP_ALL_OK,  Qeol_cr);
6311   DEFINE_CODESYS_PROP (CODESYS_PROP_ALL_OK,  Qeol_crlf);
6312   DEFINE_CODESYS_PROP (CODESYS_PROP_ALL_OK,  Qeol_lf);
6313   DEFINE_CODESYS_PROP (CODESYS_PROP_ALL_OK,  Qpost_read_conversion);
6314   DEFINE_CODESYS_PROP (CODESYS_PROP_ALL_OK,  Qpre_write_conversion);
6315 #ifdef MULE
6316   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qcharset_g0);
6317   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qcharset_g1);
6318   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qcharset_g2);
6319   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qcharset_g3);
6320   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qforce_g0_on_output);
6321   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qforce_g1_on_output);
6322   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qforce_g2_on_output);
6323   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qforce_g3_on_output);
6324   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qshort);
6325   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qno_ascii_eol);
6326   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qno_ascii_cntl);
6327   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qseven);
6328   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qlock_shift);
6329   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qno_iso6429);
6330   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qescape_quoted);
6331   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qinput_charset_conversion);
6332   DEFINE_CODESYS_PROP (CODESYS_PROP_ISO2022, Qoutput_charset_conversion);
6333
6334   DEFINE_CODESYS_PROP (CODESYS_PROP_CCL,     Qencode);
6335   DEFINE_CODESYS_PROP (CODESYS_PROP_CCL,     Qdecode);
6336 #endif /* MULE */
6337   /* Need to create this here or we're really screwed. */
6338   Fmake_coding_system
6339     (Qraw_text, Qno_conversion,
6340      build_string ("Raw text, which means it converts only line-break-codes."),
6341      list2 (Qmnemonic, build_string ("Raw")));
6342
6343   Fmake_coding_system
6344     (Qbinary, Qno_conversion,
6345      build_string ("Binary, which means it does not convert anything."),
6346      list4 (Qeol_type, Qlf,
6347             Qmnemonic, build_string ("Binary")));
6348
6349 #ifdef UTF2000
6350   Fmake_coding_system
6351     (Qutf8, Qutf8,
6352      build_string ("Coding-system of ISO/IEC 10646 UTF-8."),
6353      list2 (Qmnemonic, build_string ("UTF8")));
6354 #endif
6355
6356   Fdefine_coding_system_alias (Qno_conversion, Qraw_text);
6357
6358   Fdefine_coding_system_alias (Qfile_name, Qbinary);
6359
6360   Fdefine_coding_system_alias (Qterminal, Qbinary);
6361   Fdefine_coding_system_alias (Qkeyboard, Qbinary);
6362
6363   /* Need this for bootstrapping */
6364   fcd->coding_category_system[CODING_CATEGORY_NO_CONVERSION] =
6365     Fget_coding_system (Qraw_text);
6366
6367 #ifdef UTF2000
6368   fcd->coding_category_system[CODING_CATEGORY_UTF8]
6369    = Fget_coding_system (Qutf8);
6370 #endif
6371
6372 #if defined(MULE) && !defined(UTF2000)
6373   {
6374     unsigned int i;
6375
6376     for (i = 0; i < 65536; i++)
6377       fcd->ucs_to_mule_table[i] = Qnil;
6378   }
6379   staticpro (&mule_to_ucs_table);
6380   mule_to_ucs_table = Fmake_char_table(Qgeneric);
6381 #endif /* defined(MULE) && !defined(UTF2000) */
6382 }