/[emacs]/emacs/src/charset.c
ViewVC logotype

Diff of /emacs/src/charset.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.134 by lektu, Tue Feb 4 14:03:12 2003 UTC revision 1.134.6.1 by handa, Mon Sep 8 12:48:10 2003 UTC
# Line 1  Line 1 
1  /* Basic multilingual character support.  /* Basic character set support.
2     Copyright (C) 1995, 1997, 1998 Electrotechnical Laboratory, JAPAN.     Copyright (C) 1995, 97, 98, 2000, 2001 Electrotechnical Laboratory, JAPAN.
3     Licensed to the Free Software Foundation.       Licensed to the Free Software Foundation.
4     Copyright (C) 2001 Free Software Foundation, Inc.     Copyright (C) 2001 Free Software Foundation, Inc.
5       Copyright (C) 2003
6         National Institute of Advanced Industrial Science and Technology (AIST)
7         Registration Number H13PRO009
8    
9  This file is part of GNU Emacs.  This file is part of GNU Emacs.
10    
# Line 20  along with GNU Emacs; see the file COPYI Line 23  along with GNU Emacs; see the file COPYI
23  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24  Boston, MA 02111-1307, USA.  */  Boston, MA 02111-1307, USA.  */
25    
 /* At first, see the document in `charset.h' to understand the code in  
    this file.  */  
   
 #ifdef emacs  
26  #include <config.h>  #include <config.h>
 #endif  
27    
28  #include <stdio.h>  #include <stdio.h>
29    #include <unistd.h>
30  #ifdef emacs  #include <ctype.h>
   
31  #include <sys/types.h>  #include <sys/types.h>
32  #include "lisp.h"  #include "lisp.h"
33  #include "buffer.h"  #include "character.h"
34  #include "charset.h"  #include "charset.h"
 #include "composite.h"  
35  #include "coding.h"  #include "coding.h"
36  #include "disptab.h"  #include "disptab.h"
37    #include "buffer.h"
38    
39  #else  /* not emacs */  /*** GENERAL NOTES on CODED CHARACTER SETS (CHARSETS) ***
40    
41  #include "mulelib.h"    A coded character set ("charset" hereafter) is a meaningful
42      collection (i.e. language, culture, functionality, etc.) of
43      characters.  Emacs handles multiple charsets at once.  In Emacs Lisp
44      code, a charset is represented by a symbol.  In C code, a charset is
45      represented by its ID number or by a pointer to a struct charset.
46    
47      The actual information about each charset is stored in two places.
48      Lispy information is stored in the hash table Vcharset_hash_table as
49      a vector (charset attributes).  The other information is stored in
50      charset_table as a struct charset.
51    
52  #endif /* emacs */  */
53    
54  Lisp_Object Qcharset, Qascii, Qeight_bit_control, Qeight_bit_graphic;  /* List of all charsets.  This variable is used only from Emacs
55  Lisp_Object Qunknown;     Lisp.  */
56    Lisp_Object Vcharset_list;
57    
58  /* Declaration of special leading-codes.  */  /* Hash table that contains attributes of each charset.  Keys are
59  EMACS_INT leading_code_private_11; /* for private DIMENSION1 of 1-column */     charset symbols, and values are vectors of charset attributes.  */
60  EMACS_INT leading_code_private_12; /* for private DIMENSION1 of 2-column */  Lisp_Object Vcharset_hash_table;
 EMACS_INT leading_code_private_21; /* for private DIMENSION2 of 1-column */  
 EMACS_INT leading_code_private_22; /* for private DIMENSION2 of 2-column */  
   
 /* Declaration of special charsets.  The values are set by  
    Fsetup_special_charsets.  */  
 int charset_latin_iso8859_1;    /* ISO8859-1 (Latin-1) */  
 int charset_jisx0208_1978;      /* JISX0208.1978 (Japanese Kanji old set) */  
 int charset_jisx0208;           /* JISX0208.1983 (Japanese Kanji) */  
 int charset_katakana_jisx0201;  /* JISX0201.Kana (Japanese Katakana) */  
 int charset_latin_jisx0201;     /* JISX0201.Roman (Japanese Roman) */  
 int charset_big5_1;             /* Big5 Level 1 (Chinese Traditional) */  
 int charset_big5_2;             /* Big5 Level 2 (Chinese Traditional) */  
   
 Lisp_Object Qcharset_table;  
   
 /* A char-table containing information of each character set.  */  
 Lisp_Object Vcharset_table;  
   
 /* A vector of charset symbol indexed by charset-id.  This is used  
    only for returning charset symbol from C functions.  */  
 Lisp_Object Vcharset_symbol_table;  
61    
62  /* A list of charset symbols ever defined.  */  /* Table of struct charset.  */
63  Lisp_Object Vcharset_list;  struct charset *charset_table;
64    
65    static int charset_table_size;
66    int charset_table_used;
67    
68    Lisp_Object Qcharsetp;
69    
70    /* Special charset symbols.  */
71    Lisp_Object Qascii;
72    Lisp_Object Qeight_bit;
73    Lisp_Object Qiso_8859_1;
74    Lisp_Object Qunicode;
75    
76    /* The corresponding charsets.  */
77    int charset_ascii;
78    int charset_eight_bit;
79    int charset_iso_8859_1;
80    int charset_unicode;
81    
82    /* The other special charsets.  */
83    int charset_jisx0201_roman;
84    int charset_jisx0208_1978;
85    int charset_jisx0208;
86    
87    /* Value of charset attribute `charset-iso-plane'.  */
88    Lisp_Object Qgl, Qgr;
89    
90    /* Charset of unibyte characters.  */
91    int charset_unibyte;
92    
93    /* List of charsets ordered by the priority.  */
94    Lisp_Object Vcharset_ordered_list;
95    
96    /* Incremented everytime we change Vcharset_ordered_list.  This is
97       unsigned short so that it fits in Lisp_Int and never matches
98       -1.  */
99    unsigned short charset_ordered_list_tick;
100    
101  /* Vector of translation table ever defined.  /* List of iso-2022 charsets.  */
102     ID of a translation table is used to index this vector.  */  Lisp_Object Viso_2022_charset_list;
103  Lisp_Object Vtranslation_table_vector;  
104    /* List of emacs-mule charsets.  */
105  /* A char-table for characters which may invoke auto-filling.  */  Lisp_Object Vemacs_mule_charset_list;
106  Lisp_Object Vauto_fill_chars;  
107    struct charset *emacs_mule_charset[256];
 Lisp_Object Qauto_fill_chars;  
   
 /* Tables used by macros BYTES_BY_CHAR_HEAD and WIDTH_BY_CHAR_HEAD.  */  
 int bytes_by_char_head[256];  
 int width_by_char_head[256];  
108    
109  /* Mapping table from ISO2022's charset (specified by DIMENSION,  /* Mapping table from ISO2022's charset (specified by DIMENSION,
110     CHARS, and FINAL-CHAR) to Emacs' charset.  */     CHARS, and FINAL-CHAR) to Emacs' charset.  */
111  int iso_charset_table[2][2][128];  int iso_charset_table[ISO_MAX_DIMENSION][ISO_MAX_CHARS][ISO_MAX_FINAL];
112    
113  /* Variables used locally in the macro FETCH_MULTIBYTE_CHAR.  */  Lisp_Object Vcharset_map_directory;
 unsigned char *_fetch_multibyte_char_p;  
 int _fetch_multibyte_char_len;  
114    
115  /* Offset to add to a non-ASCII value when inserting it.  */  Lisp_Object Vchar_unified_charset_table;
 EMACS_INT nonascii_insert_offset;  
116    
117  /* Translation table for converting non-ASCII unibyte characters  /* Defined in chartab.c */
118     to multibyte codes, or nil.  */  extern void
119  Lisp_Object Vnonascii_translation_table;  map_char_table_for_charset P_ ((void (*c_function) (Lisp_Object, Lisp_Object),
120                                    Lisp_Object function, Lisp_Object table,
121                                    Lisp_Object arg, struct charset *charset,
122                                    unsigned from, unsigned to));
123    
124    #define CODE_POINT_TO_INDEX(charset, code)                              \
125      ((charset)->code_linear_p                                             \
126       ? (code) - (charset)->min_code                                       \
127       : (((charset)->code_space_mask[(code) >> 24] & 0x8)                  \
128          && ((charset)->code_space_mask[((code) >> 16) & 0xFF] & 0x4)      \
129          && ((charset)->code_space_mask[((code) >> 8) & 0xFF] & 0x2)       \
130          && ((charset)->code_space_mask[(code) & 0xFF] & 0x1))             \
131       ? (((((code) >> 24) - (charset)->code_space[12])                     \
132           * (charset)->code_space[11])                                     \
133          + (((((code) >> 16) & 0xFF) - (charset)->code_space[8])           \
134             * (charset)->code_space[7])                                    \
135          + (((((code) >> 8) & 0xFF) - (charset)->code_space[4])            \
136             * (charset)->code_space[3])                                    \
137          + (((code) & 0xFF) - (charset)->code_space[0])                    \
138          - ((charset)->char_index_offset))                                 \
139       : -1)
140    
141    
142    /* Convert the character index IDX to code-point CODE for CHARSET.
143       It is assumed that IDX is in a valid range.  */
144    
145    #define INDEX_TO_CODE_POINT(charset, idx)                                    \
146      ((charset)->code_linear_p                                                  \
147       ? (idx) + (charset)->min_code                                             \
148       : (idx += (charset)->char_index_offset,                                   \
149          (((charset)->code_space[0] + (idx) % (charset)->code_space[2])         \
150           | (((charset)->code_space[4]                                          \
151               + ((idx) / (charset)->code_space[3] % (charset)->code_space[6]))  \
152              << 8)                                                              \
153           | (((charset)->code_space[8]                                          \
154               + ((idx) / (charset)->code_space[7] % (charset)->code_space[10])) \
155              << 16)                                                             \
156           | (((charset)->code_space[12] + ((idx) / (charset)->code_space[11]))  \
157              << 24))))
158    
 /* List of all possible generic characters.  */  
 Lisp_Object Vgeneric_character_list;  
159    
160    
 void  
 invalid_character (c)  
      int c;  
 {  
   error ("Invalid character: 0%o, %d, 0x%x", c, c, c);  
 }  
161    
162  /* Parse string STR of length LENGTH and fetch information of a  /* Set to 1 to warn that a charset map is loaded and thus a buffer
163     character at STR.  Set BYTES to the byte length the character     text and a string data may be relocated.  */
164     occupies, CHARSET, C1, C2 to proper values of the character. */  int charset_map_loaded;
165    
166  #define SPLIT_MULTIBYTE_SEQ(str, length, bytes, charset, c1, c2)             \  struct charset_map_entries
167    do {                                                                       \  {
168      (c1) = *(str);                                                           \    struct {
169      (bytes) = BYTES_BY_CHAR_HEAD (c1);                                       \      unsigned from, to;
170      if ((bytes) == 1)                                                        \      int c;
171        (charset) = ASCII_BYTE_P (c1) ? CHARSET_ASCII : CHARSET_8_BIT_GRAPHIC; \    } entry[0x10000];
172      else if ((bytes) == 2)                                                   \    struct charset_map_entries *next;
173        {                                                                      \  };
174          if ((c1) == LEADING_CODE_8_BIT_CONTROL)                              \  
175            (charset) = CHARSET_8_BIT_CONTROL, (c1) = (str)[1] - 0x20;         \  /* Load the mapping information for CHARSET from ENTRIES.
176          else                                                                 \  
177            (charset) = (c1), (c1) = (str)[1] & 0x7F;                          \     If CONTROL_FLAG is 0, setup CHARSET->min_char and CHARSET->max_char.
178        }                                                                      \  
179      else if ((bytes) == 3)                                                   \     If CONTROL_FLAG is 1, setup CHARSET->min_char, CHARSET->max_char,
180        {                                                                      \     CHARSET->decoder, and CHARSET->encoder.
181          if ((c1) < LEADING_CODE_PRIVATE_11)                                  \  
182            (charset) = (c1), (c1) = (str)[1] & 0x7F, (c2) = (str)[2] & 0x7F;  \     If CONTROL_FLAG is 2, setup CHARSET->deunifier and
183          else                                                                 \     Vchar_unify_table.  If Vchar_unified_charset_table is non-nil,
184            (charset) = (str)[1], (c1) = (str)[2] & 0x7F;                      \     setup it too.  */
185        }                                                                      \  
186      else                                                                     \  static void
187        (charset) = (str)[1], (c1) = (str)[2] & 0x7F, (c2) = (str)[3] & 0x7F;  \  load_charset_map (charset, entries, n_entries, control_flag)
188    } while (0)    struct charset *charset;
189      struct charset_map_entries *entries;
190  /* 1 if CHARSET, C1, and C2 compose a valid character, else 0.    int n_entries;
191     Note that this intentionally allows invalid components, such    int control_flag;
192     as 0xA0 0xA0, because there exist many files that contain  {
193     such invalid byte sequences, especially in EUC-GB. */    Lisp_Object vec, table;
194  #define CHAR_COMPONENTS_VALID_P(charset, c1, c2)        \    unsigned max_code = CHARSET_MAX_CODE (charset);
195    ((charset) == CHARSET_ASCII                           \    int ascii_compatible_p = charset->ascii_compatible_p;
196     ? ((c1) >= 0 && (c1) <= 0x7F)                        \    int min_char, max_char, nonascii_min_char;
197     : ((charset) == CHARSET_8_BIT_CONTROL                \    int i;
198        ? ((c1) >= 0x80 && (c1) <= 0x9F)                  \    unsigned char *fast_map = charset->fast_map;
       : ((charset) == CHARSET_8_BIT_GRAPHIC             \  
          ? ((c1) >= 0x80 && (c1) <= 0xFF)               \  
          : (CHARSET_DIMENSION (charset) == 1            \  
             ? ((c1) >= 0x20 && (c1) <= 0x7F)            \  
             : ((c1) >= 0x20 && (c1) <= 0x7F             \  
                && (c2) >= 0x20 && (c2) <= 0x7F)))))  
   
 /* Store multi-byte form of the character C in STR.  The caller should  
    allocate at least 4-byte area at STR in advance.  Returns the  
    length of the multi-byte form.  If C is an invalid character code,  
    return -1.  */  
199    
200  int    if (n_entries <= 0)
201  char_to_string_1 (c, str)      return;
      int c;  
      unsigned char *str;  
 {  
   unsigned char *p = str;  
202    
203    if (c & CHAR_MODIFIER_MASK)   /* This includes the case C is negative.  */    if (control_flag > 0)
204      {      {
205        /* Multibyte character can't have a modifier bit.  */        int n = CODE_POINT_TO_INDEX (charset, max_code) + 1;
206        if (! SINGLE_BYTE_CHAR_P ((c & ~CHAR_MODIFIER_MASK)))  
207          return -1;        table = Fmake_char_table (Qnil, Qnil);
208          if (control_flag == 1)
209            vec = Fmake_vector (make_number (n), make_number (-1));
210          else if (! CHAR_TABLE_P (Vchar_unify_table))
211            Vchar_unify_table = Fmake_char_table (Qnil, Qnil);
212    
213          charset_map_loaded = 1;
214        }
215    
216        /* For Meta, Shift, and Control modifiers, we need special care.  */    min_char = max_char = entries->entry[0].c;
217        if (c & CHAR_META)    nonascii_min_char = MAX_CHAR;
218      for (i = 0; i < n_entries; i++)
219        {
220          unsigned from, to;
221          int from_index, to_index;
222          int from_c, to_c;
223          int idx = i % 0x10000;
224    
225          if (i > 0 && idx == 0)
226            entries = entries->next;
227          from = entries->entry[idx].from;
228          to = entries->entry[idx].to;
229          from_c = entries->entry[idx].c;
230          from_index = CODE_POINT_TO_INDEX (charset, from);
231          if (from == to)
232          {          {
233            /* Move the meta bit to the right place for a string.  */            to_index = from_index;
234            c = (c & ~CHAR_META) | 0x80;            to_c = from_c;
235          }          }
236        if (c & CHAR_SHIFT)        else
237          {          {
238            /* Shift modifier is valid only with [A-Za-z].  */            to_index = CODE_POINT_TO_INDEX (charset, to);
239            if ((c & 0377) >= 'A' && (c & 0377) <= 'Z')            to_c = from_c + (to_index - from_index);
             c &= ~CHAR_SHIFT;  
           else if ((c & 0377) >= 'a' && (c & 0377) <= 'z')  
             c = (c & ~CHAR_SHIFT) - ('a' - 'A');  
240          }          }
241        if (c & CHAR_CTL)        if (from_index < 0 || to_index < 0)
242            continue;
243    
244          if (control_flag < 2)
245          {          {
246            /* Simulate the code in lread.c.  */            int c;
           /* Allow `\C- ' and `\C-?'.  */  
           if (c == (CHAR_CTL | ' '))  
             c = 0;  
           else if (c == (CHAR_CTL | '?'))  
             c = 127;  
           /* ASCII control chars are made from letters (both cases),  
              as well as the non-letters within 0100...0137.  */  
           else if ((c & 0137) >= 0101 && (c & 0137) <= 0132)  
             c &= (037 | (~0177 & ~CHAR_CTL));  
           else if ((c & 0177) >= 0100 && (c & 0177) <= 0137)  
             c &= (037 | (~0177 & ~CHAR_CTL));  
         }  
247    
248        /* If C still has any modifier bits, just ignore it.  */            if (to_c > max_char)
249        c &= ~CHAR_MODIFIER_MASK;              max_char = to_c;
250      }            else if (from_c < min_char)
251                min_char = from_c;
252              if (ascii_compatible_p)
253                {
254                  if (! ASCII_BYTE_P (from_c))
255                    {
256                      if (from_c < nonascii_min_char)
257                        nonascii_min_char = from_c;
258                    }
259                  else if (! ASCII_BYTE_P (to_c))
260                    {
261                      nonascii_min_char = 0x80;
262                    }
263                }
264    
265    if (SINGLE_BYTE_CHAR_P (c))            for (c = from_c; c <= to_c; c++)
266      {              CHARSET_FAST_MAP_SET (c, fast_map);
267        if (ASCII_BYTE_P (c) || c >= 0xA0)  
268          *p++ = c;            if (control_flag == 1)
269                {
270                  unsigned code = from;
271    
272                  if (CHARSET_COMPACT_CODES_P (charset))
273                    while (1)
274                      {
275                        ASET (vec, from_index, make_number (from_c));
276                        if (NILP (CHAR_TABLE_REF (table, from_c)))
277                          CHAR_TABLE_SET (table, from_c, make_number (code));
278                        if (from_index == to_index)
279                          break;
280                        from_index++, from_c++;
281                        code = INDEX_TO_CODE_POINT (charset, from_index);
282                      }
283                  else
284                    for (; from_index <= to_index; from_index++, from_c++)
285                      {
286                        ASET (vec, from_index, make_number (from_c));
287                        if (NILP (CHAR_TABLE_REF (table, from_c)))
288                          CHAR_TABLE_SET (table, from_c, make_number (from_index));
289                      }
290                }
291            }
292        else        else
293          {          {
294            *p++ = LEADING_CODE_8_BIT_CONTROL;            unsigned code = from;
295            *p++ = c + 0x20;  
296              while (1)
297                {
298                  int c1 = DECODE_CHAR (charset, code);
299    
300                  if (c1 >= 0)
301                    {
302                      CHAR_TABLE_SET (table, from_c, make_number (c1));
303                      CHAR_TABLE_SET (Vchar_unify_table, c1, make_number (from_c));
304                      if (CHAR_TABLE_P (Vchar_unified_charset_table))
305                        CHAR_TABLE_SET (Vchar_unified_charset_table, c1,
306                                        CHARSET_NAME (charset));
307                    }
308                  if (from_index == to_index)
309                    break;
310                  from_index++, from_c++;
311                  code = INDEX_TO_CODE_POINT (charset, from_index);
312                }
313          }          }
314      }      }
   else if (CHAR_VALID_P (c, 0))  
     {  
       int charset, c1, c2;  
315    
316        SPLIT_CHAR (c, charset, c1, c2);    if (control_flag < 2)
317        {
318        if (charset >= LEADING_CODE_EXT_11)        CHARSET_MIN_CHAR (charset) = (ascii_compatible_p
319          *p++ = (charset < LEADING_CODE_EXT_12                                      ? nonascii_min_char : min_char);
320                  ? LEADING_CODE_PRIVATE_11        CHARSET_MAX_CHAR (charset) = max_char;
321                  : (charset < LEADING_CODE_EXT_21        if (control_flag == 1)
                    ? LEADING_CODE_PRIVATE_12  
                    : (charset < LEADING_CODE_EXT_22  
                       ? LEADING_CODE_PRIVATE_21  
                       : LEADING_CODE_PRIVATE_22)));  
       *p++ = charset;  
       if ((c1 > 0 && c1 < 32) || (c2 > 0 && c2 < 32))  
         return -1;  
       if (c1)  
322          {          {
323            *p++ = c1 | 0x80;            CHARSET_DECODER (charset) = vec;
324            if (c2 > 0)            CHARSET_ENCODER (charset) = table;
             *p++ = c2 | 0x80;  
325          }          }
326      }      }
327    else    else
328      return -1;      CHARSET_DEUNIFIER (charset) = table;
   
   return (p - str);  
329  }  }
330    
331    
332  /* Store multi-byte form of the character C in STR.  The caller should  /* Read a hexadecimal number (preceded by "0x") from the file FP while
333     allocate at least 4-byte area at STR in advance.  Returns the     paying attention to comment charcter '#'.  */
    length of the multi-byte form.  If C is an invalid character code,  
    signal an error.  
   
    Use macro `CHAR_STRING (C, STR)' instead of calling this function  
    directly if C can be an ASCII character.  */  
334    
335  int  static INLINE unsigned
336  char_to_string (c, str)  read_hex (fp, eof)
337       int c;       FILE *fp;
338       unsigned char *str;       int *eof;
339  {  {
340    int len;    int c;
341    len = char_to_string_1 (c, str);    unsigned n;
342    if (len == -1)  
343      invalid_character (c);    while ((c = getc (fp)) != EOF)
344    return len;      {
345          if (c == '#')
346            {
347              while ((c = getc (fp)) != EOF && c != '\n');
348            }
349          else if (c == '0')
350            {
351              if ((c = getc (fp)) == EOF || c == 'x')
352                break;
353            }
354        }
355      if (c == EOF)
356        {
357          *eof = 1;
358          return 0;
359        }
360      *eof = 0;
361      n = 0;
362      if (c == 'x')
363        while ((c = getc (fp)) != EOF && isxdigit (c))
364          n = ((n << 4)
365               | (c <= '9' ? c - '0' : c <= 'F' ? c - 'A' + 10 : c - 'a' + 10));
366      else
367        while ((c = getc (fp)) != EOF && isdigit (c))
368          n = (n * 10) + c - '0';
369      if (c != EOF)
370        ungetc (c, fp);
371      return n;
372  }  }
373    
374    
375  /* Return the non-ASCII character corresponding to multi-byte form at  /* Return a mapping vector for CHARSET loaded from MAPFILE.
376     STR of length LEN.  If ACTUAL_LEN is not NULL, store the byte     Each line of MAPFILE has this form
377     length of the multibyte form in *ACTUAL_LEN.          0xAAAA 0xCCCC
378       where 0xAAAA is a code-point and 0xCCCC is the corresponding
379       character code, or this form
380            0xAAAA-0xBBBB 0xCCCC
381       where 0xAAAA and 0xBBBB are code-points specifying a range, and
382       0xCCCC is the first character code of the range.
383    
384       The returned vector has this form:
385            [ CODE1 CHAR1 CODE2 CHAR2 .... ]
386       where CODE1 is a code-point or a cons of code-points specifying a
387       range.  */
388    
389    extern void add_to_log P_ ((char *, Lisp_Object, Lisp_Object));
390    
391    static void
392    load_charset_map_from_file (charset, mapfile, control_flag)
393         struct charset *charset;
394         Lisp_Object mapfile;
395         int control_flag;
396    {
397      unsigned min_code = CHARSET_MIN_CODE (charset);
398      unsigned max_code = CHARSET_MAX_CODE (charset);
399      int fd;
400      FILE *fp;
401      int eof;
402      Lisp_Object suffixes;
403      struct charset_map_entries *head, *entries;
404      int n_entries;
405    
406      suffixes = Fcons (build_string (".map"),
407                        Fcons (build_string (".TXT"), Qnil));
408    
409      fd = openp (Fcons (Vcharset_map_directory, Qnil), mapfile, suffixes,
410                  NULL, Qnil);
411      if (fd < 0
412          || ! (fp = fdopen (fd, "r")))
413        {
414          add_to_log ("Failure in loading charset map: %S", mapfile, Qnil);
415          return;
416        }
417    
418      head = entries = ((struct charset_map_entries *)
419                        alloca (sizeof (struct charset_map_entries)));
420      n_entries = 0;
421      eof = 0;
422      while (1)
423        {
424          unsigned from, to;
425          int c;
426          int idx;
427    
428          from = read_hex (fp, &eof);
429          if (eof)
430            break;
431          if (getc (fp) == '-')
432            to = read_hex (fp, &eof);
433          else
434            to = from;
435          c = (int) read_hex (fp, &eof);
436    
437     Use macros STRING_CHAR or STRING_CHAR_AND_LENGTH instead of calling        if (from < min_code || to > max_code || from > to || c > MAX_CHAR)
438     this function directly if you want ot handle ASCII characters as          continue;
    well.  */  
439    
440  int        if (n_entries > 0 && (n_entries % 0x10000) == 0)
441  string_to_char (str, len, actual_len)          {
442       const unsigned char *str;            entries->next = ((struct charset_map_entries *)
443       int len, *actual_len;                             alloca (sizeof (struct charset_map_entries)));
444  {            entries = entries->next;
445    int c, bytes, charset, c1, c2;          }
446          idx = n_entries % 0x10000;
447    SPLIT_MULTIBYTE_SEQ (str, len, bytes, charset, c1, c2);        entries->entry[idx].from = from;
448    c = MAKE_CHAR (charset, c1, c2);        entries->entry[idx].to = to;
449    if (actual_len)        entries->entry[idx].c = c;
450      *actual_len = bytes;        n_entries++;
451    return c;      }
452      fclose (fp);
453      close (fd);
454    
455      load_charset_map (charset, head, n_entries, control_flag);
456  }  }
457    
458  /* Return the length of the multi-byte form at string STR of length LEN.  static void
459     Use the macro MULTIBYTE_FORM_LENGTH instead.  */  load_charset_map_from_vector (charset, vec, control_flag)
460  int       struct charset *charset;
461  multibyte_form_length (str, len)       Lisp_Object vec;
462       const unsigned char *str;       int control_flag;
      int len;  
463  {  {
464    int bytes;    unsigned min_code = CHARSET_MIN_CODE (charset);
465      unsigned max_code = CHARSET_MAX_CODE (charset);
466      struct charset_map_entries *head, *entries;
467      int n_entries;
468      int len = ASIZE (vec);
469      int i;
470    
471    PARSE_MULTIBYTE_SEQ (str, len, bytes);    if (len % 2 == 1)
472    return bytes;      {
473  }        add_to_log ("Failure in loading charset map: %V", vec, Qnil);
474          return;
475        }
476    
477  /* Check multibyte form at string STR of length LEN and set variables    head = entries = ((struct charset_map_entries *)
478     pointed by CHARSET, C1, and C2 to charset and position codes of the                      alloca (sizeof (struct charset_map_entries)));
479     character at STR, and return 0.  If there's no multibyte character,    n_entries = 0;
480     return -1.  This should be used only in the macro SPLIT_STRING    for (i = 0; i < len; i += 2)
481     which checks range of STR in advance.  */      {
482          Lisp_Object val, val2;
483          unsigned from, to;
484          int c;
485          int idx;
486    
487          val = AREF (vec, i);
488          if (CONSP (val))
489            {
490              val2 = XCDR (val);
491              val = XCAR (val);
492              CHECK_NATNUM (val);
493              CHECK_NATNUM (val2);
494              from = XFASTINT (val);
495              to = XFASTINT (val2);
496            }
497          else
498            {
499              CHECK_NATNUM (val);
500              from = to = XFASTINT (val);
501            }
502          val = AREF (vec, i + 1);
503          CHECK_NATNUM (val);
504          c = XFASTINT (val);
505    
506  int        if (from < min_code || to > max_code || from > to || c > MAX_CHAR)
507  split_string (str, len, charset, c1, c2)          continue;
      const unsigned char *str;  
      unsigned char *c1, *c2;  
      int len, *charset;  
 {  
   register int bytes, cs, code1, code2 = -1;  
508    
509    SPLIT_MULTIBYTE_SEQ (str, len, bytes, cs, code1, code2);        if ((n_entries % 0x10000) == 0)
510    if (cs == CHARSET_ASCII)          {
511      return -1;            entries->next = ((struct charset_map_entries *)
512    *charset = cs;                             alloca (sizeof (struct charset_map_entries)));
513    *c1 = code1;            entries = entries->next;
514    *c2 = code2;          }
515    return 0;        idx = n_entries % 0x10000;
516          entries->entry[idx].from = from;
517          entries->entry[idx].to = to;
518          entries->entry[idx].c = c;
519          n_entries++;
520        }
521    
522      load_charset_map (charset, head, n_entries, control_flag);
523  }  }
524    
525  /* Return 1 iff character C has valid printable glyph.  static void
526     Use the macro CHAR_PRINTABLE_P instead.  */  load_charset (charset)
527  int       struct charset *charset;
 char_printable_p (c)  
      int c;  
528  {  {
529    int charset, c1, c2;    if (CHARSET_METHOD (charset) == CHARSET_METHOD_MAP_DEFERRED)
530        {
531    if (ASCII_BYTE_P (c))        Lisp_Object map;
     return 1;  
   else if (SINGLE_BYTE_CHAR_P (c))  
     return 0;  
   else if (c >= MAX_CHAR)  
     return 0;  
532    
533    SPLIT_CHAR (c, charset, c1, c2);        map = CHARSET_MAP (charset);
534    if (! CHARSET_DEFINED_P (charset))        if (STRINGP (map))
535      return 0;          load_charset_map_from_file (charset, map, 1);
536    if (CHARSET_CHARS (charset) == 94        else
537        ? c1 <= 32 || c1 >= 127          load_charset_map_from_vector (charset, map, 1);
538        : c1 < 32)        CHARSET_METHOD (charset) = CHARSET_METHOD_MAP;
539      return 0;      }
   if (CHARSET_DIMENSION (charset) == 2  
       && (CHARSET_CHARS (charset) == 94  
           ? c2 <= 32 || c2 >= 127  
           : c2 < 32))  
     return 0;  
   return 1;  
540  }  }
541    
542  /* Translate character C by translation table TABLE.  If C  
543     is negative, translate a character specified by CHARSET, C1, and C2  DEFUN ("charsetp", Fcharsetp, Scharsetp, 1, 1, 0,
544     (C1 and C2 are code points of the character).  If no translation is         doc: /* Return non-nil if and only if OBJECT is a charset.*/)
545     found in TABLE, return C.  */       (object)
546  int       Lisp_Object object;
 translate_char (table, c, charset, c1, c2)  
      Lisp_Object table;  
      int c, charset, c1, c2;  
547  {  {
548    Lisp_Object ch;    return (CHARSETP (object) ? Qt : Qnil);
549    int alt_charset, alt_c1, alt_c2, dimension;  }
550    
   if (c < 0) c = MAKE_CHAR (charset, (c1 & 0x7F) , (c2 & 0x7F));  
   if (!CHAR_TABLE_P (table)  
       || (ch = Faref (table, make_number (c)), !NATNUMP (ch)))  
     return c;  
   
   SPLIT_CHAR (XFASTINT (ch), alt_charset, alt_c1, alt_c2);  
   dimension = CHARSET_DIMENSION (alt_charset);  
   if ((dimension == 1 && alt_c1 > 0) || (dimension == 2 && alt_c2 > 0))  
     /* CH is not a generic character, just return it.  */  
     return XFASTINT (ch);  
   
   /* Since CH is a generic character, we must return a specific  
      charater which has the same position codes as C from CH.  */  
   if (charset < 0)  
     SPLIT_CHAR (c, charset, c1, c2);  
   if (dimension != CHARSET_DIMENSION (charset))  
     /* We can't make such a character because of dimension mismatch.  */  
     return c;  
   return MAKE_CHAR (alt_charset, c1, c2);  
 }  
   
 /* Convert the unibyte character C to multibyte based on  
    Vnonascii_translation_table or nonascii_insert_offset.  If they can't  
    convert C to a valid multibyte character, convert it based on  
    DEFAULT_NONASCII_INSERT_OFFSET which makes C a Latin-1 character.  */  
551    
552  int  void
553  unibyte_char_to_multibyte (c)  map_charset_chars (c_function, function, arg,
554       int c;                     charset, from, to)
555         void (*c_function) P_ ((Lisp_Object, Lisp_Object));
556         Lisp_Object function, arg;
557         struct charset *charset;
558         unsigned from, to;
559  {  {
560    if (c < 0400 && c >= 0200)    Lisp_Object range;
561      int partial;
562    
563      if (CHARSET_METHOD (charset) == CHARSET_METHOD_MAP_DEFERRED)
564        load_charset (charset);
565    
566      partial = (from > CHARSET_MIN_CODE (charset)
567                 || to < CHARSET_MAX_CODE (charset));
568    
569      if (CHARSET_UNIFIED_P (charset)
570          && CHAR_TABLE_P (CHARSET_DEUNIFIER (charset)))
571        {
572          map_char_table_for_charset (c_function, function,
573                                      CHARSET_DEUNIFIER (charset), arg,
574                                      partial ? charset : NULL, from, to);
575        }
576    
577      if (CHARSET_METHOD (charset) == CHARSET_METHOD_OFFSET)
578      {      {
579        int c_save = c;        int from_idx = CODE_POINT_TO_INDEX (charset, from);
580          int to_idx = CODE_POINT_TO_INDEX (charset, to);
581          int from_c = from_idx + CHARSET_CODE_OFFSET (charset);
582          int to_c = to_idx + CHARSET_CODE_OFFSET (charset);
583    
584        if (! NILP (Vnonascii_translation_table))        range = Fcons (make_number (from_c), make_number (to_c));
585          if (NILP (function))
586            (*c_function) (range, arg);
587          else
588            call2 (function, range, arg);
589        }
590      else if (CHARSET_METHOD (charset) == CHARSET_METHOD_MAP)
591        {
592          if (! CHAR_TABLE_P (CHARSET_ENCODER (charset)))
593            return;
594          if (CHARSET_ASCII_COMPATIBLE_P (charset) && from <= 127)
595          {          {
596            c = XINT (Faref (Vnonascii_translation_table, make_number (c)));            range = Fcons (make_number (from), make_number (to));
597            if (c >= 0400 && ! char_valid_p (c, 0))            if (to >= 128)
598              c = c_save + DEFAULT_NONASCII_INSERT_OFFSET;              XSETCAR (range, make_number (127));
599    
600              if (NILP (function))
601                (*c_function) (range, arg);
602              else
603                call2 (function, range, arg);
604          }          }
605        else if (c >= 0240 && nonascii_insert_offset > 0)        map_char_table_for_charset (c_function, function,
606                                      CHARSET_ENCODER (charset), arg,
607                                      partial ? charset : NULL, from, to);
608        }
609      else if (CHARSET_METHOD (charset) == CHARSET_METHOD_SUBSET)
610        {
611          Lisp_Object subset_info;
612          int offset;
613    
614          subset_info = CHARSET_SUBSET (charset);
615          charset = CHARSET_FROM_ID (XFASTINT (AREF (subset_info, 0)));
616          offset = XINT (AREF (subset_info, 3));
617          from -= offset;
618          if (from < XFASTINT (AREF (subset_info, 1)))
619            from = XFASTINT (AREF (subset_info, 1));
620          to -= offset;
621          if (to > XFASTINT (AREF (subset_info, 2)))
622            to = XFASTINT (AREF (subset_info, 2));
623          map_charset_chars (c_function, function, arg, charset, from, to);
624        }
625      else                          /* i.e. CHARSET_METHOD_SUPERSET */
626        {
627          Lisp_Object parents;
628    
629          for (parents = CHARSET_SUPERSET (charset); CONSP (parents);
630               parents = XCDR (parents))
631          {          {
632            c += nonascii_insert_offset;            int offset;
633            if (c < 0400 || ! char_valid_p (c, 0))            unsigned this_from, this_to;
634              c = c_save + DEFAULT_NONASCII_INSERT_OFFSET;  
635              charset = CHARSET_FROM_ID (XFASTINT (XCAR (XCAR (parents))));
636              offset = XINT (XCDR (XCAR (parents)));
637              this_from = from - offset;
638              this_to = to - offset;
639              if (this_from < CHARSET_MIN_CODE (charset))
640                this_from = CHARSET_MIN_CODE (charset);
641              if (this_to > CHARSET_MAX_CODE (charset))
642                this_to = CHARSET_MAX_CODE (charset);
643              map_charset_chars (c_function, function, arg, charset, from, to);
644          }          }
       else if (c >= 0240)  
         c = c_save + DEFAULT_NONASCII_INSERT_OFFSET;  
645      }      }
   return c;  
646  }  }
647    
648    DEFUN ("map-charset-chars", Fmap_charset_chars, Smap_charset_chars, 2, 5, 0,
649           doc: /* Call FUNCTION for all characters in CHARSET.
650    FUNCTION is called with an argument RANGE and the optional 3rd
651    argument ARG.
652    
653  /* Convert the multibyte character C to unibyte 8-bit character based  RANGE is a cons (FROM .  TO), where FROM and TO indicate a range of
654     on Vnonascii_translation_table or nonascii_insert_offset.  If  characters contained in CHARSET.
    REV_TBL is non-nil, it should be a reverse table of  
    Vnonascii_translation_table, i.e. what given by:  
      Fchar_table_extra_slot (Vnonascii_translation_table, make_number (0))  */  
655    
656  int  The optional 4th and 5th arguments FROM-CODE and TO-CODE specify the
657  multibyte_char_to_unibyte (c, rev_tbl)  range of code points of target characters.  */)
658       int c;       (function, charset, arg, from_code, to_code)
659       Lisp_Object rev_tbl;         Lisp_Object function, charset, arg, from_code, to_code;
660    {
661      struct charset *cs;
662      unsigned from, to;
663    
664      CHECK_CHARSET_GET_CHARSET (charset, cs);
665      if (NILP (from_code))
666        from = CHARSET_MIN_CODE (cs);
667      else
668        {
669          CHECK_NATNUM (from_code);
670          from = XINT (from_code);
671          if (from < CHARSET_MIN_CODE (cs))
672            from = CHARSET_MIN_CODE (cs);
673        }
674      if (NILP (to_code))
675        to = CHARSET_MAX_CODE (cs);
676      else
677        {
678          CHECK_NATNUM (to_code);
679          to = XINT (to_code);
680          if (to > CHARSET_MAX_CODE (cs))
681            to = CHARSET_MAX_CODE (cs);
682        }
683      map_charset_chars (NULL, function, arg, cs, from, to);
684      return Qnil;
685    }
686    
687    
688    /* Define a charset according to the arguments.  The Nth argument is
689       the Nth attribute of the charset (the last attribute `charset-id'
690       is not included).  See the docstring of `define-charset' for the
691       detail.  */
692    
693    DEFUN ("define-charset-internal", Fdefine_charset_internal,
694           Sdefine_charset_internal, charset_arg_max, MANY, 0,
695           doc: /* For internal use only.
696    usage: (define-charset-internal ...)  */)
697         (nargs, args)
698         int nargs;
699         Lisp_Object *args;
700  {  {
701    if (!SINGLE_BYTE_CHAR_P (c))    /* Charset attr vector.  */
702      Lisp_Object attrs;
703      Lisp_Object val;
704      unsigned hash_code;
705      struct Lisp_Hash_Table *hash_table = XHASH_TABLE (Vcharset_hash_table);
706      int i, j;
707      struct charset charset;
708      int id;
709      int dimension;
710      int new_definition_p;
711      int nchars;
712    
713      if (nargs != charset_arg_max)
714        return Fsignal (Qwrong_number_of_arguments,
715                        Fcons (intern ("define-charset-internal"),
716                               make_number (nargs)));
717    
718      attrs = Fmake_vector (make_number (charset_attr_max), Qnil);
719    
720      CHECK_SYMBOL (args[charset_arg_name]);
721      ASET (attrs, charset_name, args[charset_arg_name]);
722    
723      val = args[charset_arg_code_space];
724      for (i = 0, dimension = 0, nchars = 1; i < 4; i++)
725        {
726          int min_byte, max_byte;
727    
728          min_byte = XINT (Faref (val, make_number (i * 2)));
729          max_byte = XINT (Faref (val, make_number (i * 2 + 1)));
730          if (min_byte < 0 || min_byte > max_byte || max_byte >= 256)
731            error ("Invalid :code-space value");
732          charset.code_space[i * 4] = min_byte;
733          charset.code_space[i * 4 + 1] = max_byte;
734          charset.code_space[i * 4 + 2] = max_byte - min_byte + 1;
735          nchars *= charset.code_space[i * 4 + 2];
736          charset.code_space[i * 4 + 3] = nchars;
737          if (max_byte > 0)
738            dimension = i + 1;
739        }
740    
741      val = args[charset_arg_dimension];
742      if (NILP (val))
743        charset.dimension = dimension;
744      else
745      {      {
746        int c_save = c;        CHECK_NATNUM (val);
747          charset.dimension = XINT (val);
748          if (charset.dimension < 1 || charset.dimension > 4)
749            args_out_of_range_3 (val, make_number (1), make_number (4));
750        }
751    
752      charset.code_linear_p
753        = (charset.dimension == 1
754           || (charset.code_space[2] == 256
755               && (charset.dimension == 2
756                   || (charset.code_space[6] == 256
757                       && (charset.dimension == 3
758                           || charset.code_space[10] == 256)))));
759    
760      if (! charset.code_linear_p)
761        {
762          charset.code_space_mask = (unsigned char *) xmalloc (256);
763          bzero (charset.code_space_mask, 256);
764          for (i = 0; i < 4; i++)
765            for (j = charset.code_space[i * 4]; j <= charset.code_space[i * 4 + 1];
766                 j++)
767              charset.code_space_mask[j] |= (1 << i);
768        }
769    
770      charset.iso_chars_96 = charset.code_space[2] == 96;
771    
772      charset.min_code = (charset.code_space[0]
773                          | (charset.code_space[4] << 8)
774                          | (charset.code_space[8] << 16)
775                          | (charset.code_space[12] << 24));
776      charset.max_code = (charset.code_space[1]
777                          | (charset.code_space[5] << 8)
778                          | (charset.code_space[9] << 16)
779                          | (charset.code_space[13] << 24));
780      charset.char_index_offset = 0;
781    
782        if (! CHAR_TABLE_P (rev_tbl)    val = args[charset_arg_min_code];
783            && CHAR_TABLE_P (Vnonascii_translation_table))    if (! NILP (val))
784          rev_tbl = Fchar_table_extra_slot (Vnonascii_translation_table,      {
785                                            make_number (0));        unsigned code;
786        if (CHAR_TABLE_P (rev_tbl))  
787          {        if (INTEGERP (val))
788            Lisp_Object temp;          code = XINT (val);
           temp = Faref (rev_tbl, make_number (c));  
           if (INTEGERP (temp))  
             c = XINT (temp);  
           if (c >= 256)  
             c = (c_save & 0177) + 0200;  
         }  
789        else        else
790          {          {
791            if (nonascii_insert_offset > 0)            CHECK_CONS (val);
792              c -= nonascii_insert_offset;            CHECK_NUMBER_CAR (val);
793            if (c < 128 || c >= 256)            CHECK_NUMBER_CDR (val);
794              c = (c_save & 0177) + 0200;            code = (XINT (XCAR (val)) << 16) | (XINT (XCDR (val)));
795            }
796          if (code < charset.min_code
797              || code > charset.max_code)
798            args_out_of_range_3 (make_number (charset.min_code),
799                                 make_number (charset.max_code), val);
800          charset.char_index_offset = CODE_POINT_TO_INDEX (&charset, code);
801          charset.min_code = code;
802        }
803    
804      val = args[charset_arg_max_code];
805      if (! NILP (val))
806        {
807          unsigned code;
808    
809          if (INTEGERP (val))
810            code = XINT (val);
811          else
812            {
813              CHECK_CONS (val);
814              CHECK_NUMBER_CAR (val);
815              CHECK_NUMBER_CDR (val);
816              code = (XINT (XCAR (val)) << 16) | (XINT (XCDR (val)));
817          }          }
818          if (code < charset.min_code
819              || code > charset.max_code)
820            args_out_of_range_3 (make_number (charset.min_code),
821                                 make_number (charset.max_code), val);
822          charset.max_code = code;
823      }      }
824    
825    return c;    charset.compact_codes_p = charset.max_code < 0x1000000;
 }  
826    
827      val = args[charset_arg_invalid_code];
828  /* Update the table Vcharset_table with the given arguments (see the    if (NILP (val))
829     document of `define-charset' for the meaning of each argument).      {
830     Several other table contents are also updated.  The caller should        if (charset.min_code > 0)
831     check the validity of CHARSET-ID and the remaining arguments in          charset.invalid_code = 0;
832     advance.  */        else
833            {
834              XSETINT (val, charset.max_code + 1);
835              if (XINT (val) == charset.max_code + 1)
836                charset.invalid_code = charset.max_code + 1;
837              else
838                error ("Attribute :invalid-code must be specified");
839            }
840        }
841      else
842        {
843          CHECK_NATNUM (val);
844          charset.invalid_code = XFASTINT (val);
845        }
846    
847  void    val = args[charset_arg_iso_final];
848  update_charset_table (charset_id, dimension, chars, width, direction,    if (NILP (val))
849                        iso_final_char, iso_graphic_plane,      charset.iso_final = -1;
850                        short_name, long_name, description)    else
851       Lisp_Object charset_id, dimension, chars, width, direction;      {
852       Lisp_Object iso_final_char, iso_graphic_plane;        CHECK_NUMBER (val);
853       Lisp_Object short_name, long_name, description;        if (XINT (val) < '0' || XINT (val) > 127)
854  {          error ("Invalid iso-final-char: %d", XINT (val));
855    int charset = XINT (charset_id);        charset.iso_final = XINT (val);
   int bytes;  
   unsigned char leading_code_base, leading_code_ext;  
   
   if (NILP (CHARSET_TABLE_ENTRY (charset)))  
     CHARSET_TABLE_ENTRY (charset)  
       = Fmake_vector (make_number (CHARSET_MAX_IDX), Qnil);  
   
   if (NILP (long_name))  
     long_name = short_name;  
   if (NILP (description))  
     description = long_name;  
   
   /* Get byte length of multibyte form, base leading-code, and  
      extended leading-code of the charset.  See the comment under the  
      title "GENERAL NOTE on CHARACTER SET (CHARSET)" in charset.h.  */  
   bytes = XINT (dimension);  
   if (charset < MIN_CHARSET_PRIVATE_DIMENSION1)  
     {  
       /* Official charset, it doesn't have an extended leading-code.  */  
       if (charset != CHARSET_ASCII && charset != CHARSET_8_BIT_GRAPHIC)  
         bytes += 1; /* For a base leading-code.  */  
       leading_code_base = charset;  
       leading_code_ext = 0;  
856      }      }
857    
858      val = args[charset_arg_iso_revision];
859      if (NILP (val))
860        charset.iso_revision = -1;
861    else    else
862      {      {
863        /* Private charset.  */        CHECK_NUMBER (val);
864        bytes += 2; /* For base and extended leading-codes.  */        if (XINT (val) > 63)
865        leading_code_base          args_out_of_range (make_number (63), val);
866          = (charset < LEADING_CODE_EXT_12        charset.iso_revision = XINT (val);
867             ? LEADING_CODE_PRIVATE_11      }
            : (charset < LEADING_CODE_EXT_21  
               ? LEADING_CODE_PRIVATE_12  
               : (charset < LEADING_CODE_EXT_22  
                  ? LEADING_CODE_PRIVATE_21  
                  : LEADING_CODE_PRIVATE_22)));  
       leading_code_ext = charset;  
       if (BYTES_BY_CHAR_HEAD (leading_code_base) != bytes)  
         error ("Invalid dimension for the charset-ID %d", charset);  
     }  
   
   CHARSET_TABLE_INFO (charset, CHARSET_ID_IDX) = charset_id;  
   CHARSET_TABLE_INFO (charset, CHARSET_BYTES_IDX) = make_number (bytes);  
   CHARSET_TABLE_INFO (charset, CHARSET_DIMENSION_IDX) = dimension;  
   CHARSET_TABLE_INFO (charset, CHARSET_CHARS_IDX) = chars;  
   CHARSET_TABLE_INFO (charset, CHARSET_WIDTH_IDX) = width;  
   CHARSET_TABLE_INFO (charset, CHARSET_DIRECTION_IDX) = direction;  
   CHARSET_TABLE_INFO (charset, CHARSET_LEADING_CODE_BASE_IDX)  
     = make_number (leading_code_base);  
   CHARSET_TABLE_INFO (charset, CHARSET_LEADING_CODE_EXT_IDX)  
     = make_number (leading_code_ext);  
   CHARSET_TABLE_INFO (charset, CHARSET_ISO_FINAL_CHAR_IDX) = iso_final_char;  
   CHARSET_TABLE_INFO (charset, CHARSET_ISO_GRAPHIC_PLANE_IDX)  
     = iso_graphic_plane;  
   CHARSET_TABLE_INFO (charset, CHARSET_SHORT_NAME_IDX) = short_name;  
   CHARSET_TABLE_INFO (charset, CHARSET_LONG_NAME_IDX) = long_name;  
   CHARSET_TABLE_INFO (charset, CHARSET_DESCRIPTION_IDX) = description;  
   CHARSET_TABLE_INFO (charset, CHARSET_PLIST_IDX) = Qnil;  
868    
869    {    val = args[charset_arg_emacs_mule_id];
870      /* If we have already defined a charset which has the same    if (NILP (val))
871         DIMENSION, CHARS and ISO-FINAL-CHAR but the different      charset.emacs_mule_id = -1;
872         DIRECTION, we must update the entry REVERSE-CHARSET of both    else
873         charsets.  If there's no such charset, the value of the entry      {
874         is set to nil.  */        CHECK_NATNUM (val);
875      int i;        if ((XINT (val) > 0 && XINT (val) <= 128) || XINT (val) >= 256)
876            error ("Invalid emacs-mule-id: %d", XINT (val));
877      for (i = 0; i <= MAX_CHARSET; i++)        charset.emacs_mule_id = XINT (val);
878        if (!NILP (CHARSET_TABLE_ENTRY (i)))      }
879          {  
880            if (CHARSET_DIMENSION (i) == XINT (dimension)    charset.ascii_compatible_p = ! NILP (args[charset_arg_ascii_compatible_p]);
881                && CHARSET_CHARS (i) == XINT (chars)  
882                && CHARSET_ISO_FINAL_CHAR (i) == XINT (iso_final_char)    charset.supplementary_p = ! NILP (args[charset_arg_supplementary_p]);
883                && CHARSET_DIRECTION (i) != XINT (direction))  
884      charset.unified_p = 0;
885    
886      bzero (charset.fast_map, sizeof (charset.fast_map));
887    
888      if (! NILP (args[charset_arg_code_offset]))
889        {
890          val = args[charset_arg_code_offset];
891          CHECK_NUMBER (val);
892    
893          charset.method = CHARSET_METHOD_OFFSET;
894          charset.code_offset = XINT (val);
895    
896          i = CODE_POINT_TO_INDEX (&charset, charset.min_code);
897          charset.min_char = i + charset.code_offset;
898          i = CODE_POINT_TO_INDEX (&charset, charset.max_code);
899          charset.max_char = i + charset.code_offset;
900          if (charset.max_char > MAX_CHAR)
901            error ("Unsupported max char: %d", charset.max_char);
902    
903          i = (charset.min_char >> 7) << 7;
904          for (; i < 0x10000 && i <= charset.max_char; i += 128)
905            CHARSET_FAST_MAP_SET (i, charset.fast_map);
906          i = (i >> 12) << 12;
907          for (; i <= charset.max_char; i += 0x1000)
908            CHARSET_FAST_MAP_SET (i, charset.fast_map);
909        }
910      else if (! NILP (args[charset_arg_map]))
911        {
912          val = args[charset_arg_map];
913          ASET (attrs, charset_map, val);
914          if (STRINGP (val))
915            load_charset_map_from_file (&charset, val, 0);
916          else
917            load_charset_map_from_vector (&charset, val, 0);
918          charset.method = CHARSET_METHOD_MAP_DEFERRED;
919        }
920      else if (! NILP (args[charset_arg_subset]))
921        {
922          Lisp_Object parent;
923          Lisp_Object parent_min_code, parent_max_code, parent_code_offset;
924          struct charset *parent_charset;
925    
926          val = args[charset_arg_subset];
927          parent = Fcar (val);
928          CHECK_CHARSET_GET_CHARSET (parent, parent_charset);
929          parent_min_code = Fnth (make_number (1), val);
930          CHECK_NATNUM (parent_min_code);
931          parent_max_code = Fnth (make_number (2), val);
932          CHECK_NATNUM (parent_max_code);
933          parent_code_offset = Fnth (make_number (3), val);
934          CHECK_NUMBER (parent_code_offset);
935          val = Fmake_vector (make_number (4), Qnil);
936          ASET (val, 0, make_number (parent_charset->id));
937          ASET (val, 1, parent_min_code);
938          ASET (val, 2, parent_max_code);
939          ASET (val, 3, parent_code_offset);
940          ASET (attrs, charset_subset, val);
941    
942          charset.method = CHARSET_METHOD_SUBSET;
943          /* Here, we just copy the parent's fast_map.  It's not accurate,
944             but at least it works for quickly detecting which character
945             DOESN'T belong to this charset.  */
946          for (i = 0; i < 190; i++)
947            charset.fast_map[i] = parent_charset->fast_map[i];
948    
949          /* We also copy these for parents.  */
950          charset.min_char = parent_charset->min_char;
951          charset.max_char = parent_charset->max_char;
952        }
953      else if (! NILP (args[charset_arg_superset]))
954        {
955          val = args[charset_arg_superset];
956          charset.method = CHARSET_METHOD_SUPERSET;
957          val = Fcopy_sequence (val);
958          ASET (attrs, charset_superset, val);
959    
960          charset.min_char = MAX_CHAR;
961          charset.max_char = 0;
962          for (; ! NILP (val); val = Fcdr (val))
963            {
964              Lisp_Object elt, car_part, cdr_part;
965              int this_id, offset;
966              struct charset *this_charset;
967    
968              elt = Fcar (val);
969              if (CONSP (elt))
970                {
971                  car_part = XCAR (elt);
972                  cdr_part = XCDR (elt);
973                  CHECK_CHARSET_GET_ID (car_part, this_id);
974                  CHECK_NUMBER (cdr_part);
975                  offset = XINT (cdr_part);
976                }
977              else
978              {              {
979                CHARSET_TABLE_INFO (charset, CHARSET_REVERSE_CHARSET_IDX)                CHECK_CHARSET_GET_ID (elt, this_id);
980                  = make_number (i);                offset = 0;
               CHARSET_TABLE_INFO (i, CHARSET_REVERSE_CHARSET_IDX) = charset_id;  
               break;  
981              }              }
982              XSETCAR (val, Fcons (make_number (this_id), make_number (offset)));
983    
984              this_charset = CHARSET_FROM_ID (this_id);
985              if (charset.min_char > this_charset->min_char)
986                charset.min_char = this_charset->min_char;
987              if (charset.max_char < this_charset->max_char)
988                charset.max_char = this_charset->max_char;
989              for (i = 0; i < 190; i++)
990                charset.fast_map[i] |= this_charset->fast_map[i];
991          }          }
992      if (i > MAX_CHARSET)      }
993        /* No such a charset.  */    else
994        CHARSET_TABLE_INFO (charset, CHARSET_REVERSE_CHARSET_IDX)      error ("None of :code-offset, :map, :parents are specified");
         = make_number (-1);  
   }  
995    
996    if (charset != CHARSET_ASCII && charset != CHARSET_8_BIT_GRAPHIC    val = args[charset_arg_unify_map];
997        && charset < MIN_CHARSET_PRIVATE_DIMENSION1)    if (! NILP (val) && !STRINGP (val))
998        CHECK_VECTOR (val);
999      ASET (attrs, charset_unify_map, val);
1000    
1001      CHECK_LIST (args[charset_arg_plist]);
1002      ASET (attrs, charset_plist, args[charset_arg_plist]);
1003    
1004      charset.hash_index = hash_lookup (hash_table, args[charset_arg_name],
1005                                        &hash_code);
1006      if (charset.hash_index >= 0)
1007        {
1008          new_definition_p = 0;
1009          id = XFASTINT (CHARSET_SYMBOL_ID (args[charset_arg_name]));
1010          HASH_VALUE (hash_table, charset.hash_index) = attrs;
1011        }
1012      else
1013      {      {
1014        bytes_by_char_head[leading_code_base] = bytes;        charset.hash_index = hash_put (hash_table, args[charset_arg_name], attrs,
1015        width_by_char_head[leading_code_base] = XINT (width);                                       hash_code);
1016          if (charset_table_used == charset_table_size)
1017            {
1018              struct charset *new_table
1019                = (struct charset *) xmalloc (sizeof (struct charset)
1020                                              * (charset_table_size + 16));
1021              bcopy (charset_table, new_table,
1022                     sizeof (struct charset) * charset_table_size);
1023              charset_table_size += 16;
1024              charset_table = new_table;
1025            }
1026          id = charset_table_used++;
1027          new_definition_p = 1;
1028        }
1029    
1030      ASET (attrs, charset_id, make_number (id));
1031      charset.id = id;
1032      charset_table[id] = charset;
1033    
1034      if (charset.iso_final >= 0)
1035        {
1036          ISO_CHARSET_TABLE (charset.dimension, charset.iso_chars_96,
1037                             charset.iso_final) = id;
1038          if (new_definition_p)
1039            Viso_2022_charset_list = nconc2 (Viso_2022_charset_list,
1040                                             Fcons (make_number (id), Qnil));
1041          if (ISO_CHARSET_TABLE (1, 0, 'J') == id)
1042            charset_jisx0201_roman = id;
1043          else if (ISO_CHARSET_TABLE (2, 0, '@') == id)
1044            charset_jisx0208_1978 = id;
1045          else if (ISO_CHARSET_TABLE (2, 0, 'B') == id)
1046            charset_jisx0208 = id;
1047        }
1048            
1049      if (charset.emacs_mule_id >= 0)
1050        {
1051          emacs_mule_charset[charset.emacs_mule_id] = CHARSET_FROM_ID (id);
1052          if (charset.emacs_mule_id < 0xA0)
1053            emacs_mule_bytes[charset.emacs_mule_id] = charset.dimension + 1;
1054          if (new_definition_p)
1055            Vemacs_mule_charset_list = nconc2 (Vemacs_mule_charset_list,
1056                                               Fcons (make_number (id), Qnil));
1057        }
1058    
1059      if (new_definition_p)
1060        {
1061          Vcharset_list = Fcons (args[charset_arg_name], Vcharset_list);
1062          Vcharset_ordered_list = nconc2 (Vcharset_ordered_list,
1063                                          Fcons (make_number (id), Qnil));
1064          charset_ordered_list_tick++;
1065        }
1066    
1067        /* Update table emacs_code_class.  */    return Qnil;
       emacs_code_class[charset] = (bytes == 2  
                                    ? EMACS_leading_code_2  
                                    : (bytes == 3  
                                       ? EMACS_leading_code_3  
                                       : EMACS_leading_code_4));  
     }  
   
   /* Update table iso_charset_table.  */  
   if (XINT (iso_final_char) >= 0  
       && ISO_CHARSET_TABLE (dimension, chars, iso_final_char) < 0)  
     ISO_CHARSET_TABLE (dimension, chars, iso_final_char) = charset;  
1068  }  }
1069    
 #ifdef emacs  
1070    
1071  /* Return charset id of CHARSET_SYMBOL, or return -1 if CHARSET_SYMBOL  /* Same as Fdefine_charset_internal but arguments are more convenient
1072     is invalid.  */     to call from C (typically in syms_of_charset).  This can define a
1073  int     charset of `offset' method only.  Return the ID of the new
1074  get_charset_id (charset_symbol)     charset.  */
1075       Lisp_Object charset_symbol;  
1076    static int
1077    define_charset_internal (name, dimension, code_space, min_code, max_code,
1078                             iso_final, iso_revision, emacs_mule_id,
1079                             ascii_compatible, supplementary,
1080                             code_offset)
1081         Lisp_Object name;
1082         int dimension;
1083         unsigned char *code_space;
1084         unsigned min_code, max_code;
1085         int iso_final, iso_revision, emacs_mule_id;
1086         int ascii_compatible, supplementary;
1087         int code_offset;
1088  {  {
1089      Lisp_Object args[charset_arg_max];
1090      Lisp_Object plist[14];
1091    Lisp_Object val;    Lisp_Object val;
1092    int charset;    int i;
1093    
1094    /* This originally used a ?: operator, but reportedly the HP-UX    args[charset_arg_name] = name;
1095       compiler version HP92453-01 A.10.32.22 miscompiles that.  */    args[charset_arg_dimension] = make_number (dimension);
1096    if (SYMBOLP (charset_symbol)    val = Fmake_vector (make_number (8), make_number (0));
1097        && VECTORP (val = Fget (charset_symbol, Qcharset))    for (i = 0; i < 8; i++)
1098        && CHARSET_VALID_P (charset =      ASET (val, i, make_number (code_space[i]));
1099                            XINT (XVECTOR (val)->contents[CHARSET_ID_IDX])))    args[charset_arg_code_space] = val;
1100      return charset;    args[charset_arg_min_code] = make_number (min_code);
1101    else    args[charset_arg_max_code] = make_number (max_code);
1102      return -1;    args[charset_arg_iso_final]
1103        = (iso_final < 0 ? Qnil : make_number (iso_final));
1104      args[charset_arg_iso_revision] = make_number (iso_revision);
1105      args[charset_arg_emacs_mule_id]
1106        = (emacs_mule_id < 0 ? Qnil : make_number (emacs_mule_id));
1107      args[charset_arg_ascii_compatible_p] = ascii_compatible ? Qt : Qnil;
1108      args[charset_arg_supplementary_p] = supplementary ? Qt : Qnil;
1109      args[charset_arg_invalid_code] = Qnil;
1110      args[charset_arg_code_offset] = make_number (code_offset);
1111      args[charset_arg_map] = Qnil;
1112      args[charset_arg_subset] = Qnil;
1113      args[charset_arg_superset] = Qnil;
1114      args[charset_arg_unify_map] = Qnil;
1115    
1116      plist[0] = intern (":name");
1117      plist[1] = args[charset_arg_name];
1118      plist[2] = intern (":dimension");
1119      plist[3] = args[charset_arg_dimension];
1120      plist[4] = intern (":code-space");
1121      plist[5] = args[charset_arg_code_space];
1122      plist[6] = intern (":iso-final-char");
1123      plist[7] = args[charset_arg_iso_final];
1124      plist[8] = intern (":emacs-mule-id");
1125      plist[9] = args[charset_arg_emacs_mule_id];
1126      plist[10] = intern (":ascii-compatible-p");
1127      plist[11] = args[charset_arg_ascii_compatible_p];
1128      plist[12] = intern (":code-offset");
1129      plist[13] = args[charset_arg_code_offset];
1130    
1131      args[charset_arg_plist] = Flist (14, plist);
1132      Fdefine_charset_internal (charset_arg_max, args);
1133    
1134      return XINT (CHARSET_SYMBOL_ID (name));
1135    }
1136    
1137    
1138    DEFUN ("define-charset-alias", Fdefine_charset_alias,
1139           Sdefine_charset_alias, 2, 2, 0,
1140           doc: /* Define ALIAS as an alias for charset CHARSET.  */)
1141         (alias, charset)
1142         Lisp_Object alias, charset;
1143    {
1144      Lisp_Object attr;
1145    
1146      CHECK_CHARSET_GET_ATTR (charset, attr);
1147      Fputhash (alias, attr, Vcharset_hash_table);
1148      Vcharset_list = Fcons (alias, Vcharset_list);
1149      return Qnil;
1150  }  }
1151    
1152  /* Return an identification number for a new private charset of  
1153     DIMENSION and WIDTH.  If there's no more room for the new charset,  DEFUN ("unibyte-charset", Funibyte_charset, Sunibyte_charset, 0, 0, 0,
1154     return 0.  */         doc: /* Return the unibyte charset (set by `set-unibyte-charset').  */)
1155  Lisp_Object       ()
 get_new_private_charset_id (dimension, width)  
      int dimension, width;  
1156  {  {
1157    int charset, from, to;    return CHARSET_NAME (CHARSET_FROM_ID (charset_unibyte));
1158    }
1159    
1160    if (dimension == 1)  
1161      {  DEFUN ("set-unibyte-charset", Fset_unibyte_charset, Sset_unibyte_charset,
1162        from = LEADING_CODE_EXT_11;         1, 1, 0,
1163        to = LEADING_CODE_EXT_21;         doc: /* Set the unibyte charset to CHARSET.
1164      }  This determines how unibyte/multibyte conversion is done.  See also
1165    else  function `unibyte-charset'.  */)
1166         (charset)
1167         Lisp_Object charset;
1168    {
1169      struct charset *cs;
1170      int i, c;
1171    
1172      CHECK_CHARSET_GET_CHARSET (charset, cs);
1173      if (! cs->ascii_compatible_p
1174          || cs->dimension != 1)
1175        error ("Inappropriate unibyte charset: %s", SDATA (SYMBOL_NAME (charset)));
1176      charset_unibyte = cs->id;
1177      for (i = 128; i < 256; i++)
1178      {      {
1179        from = LEADING_CODE_EXT_21;        c = DECODE_CHAR (cs, i);
1180        to = LEADING_CODE_EXT_MAX + 1;        unibyte_to_multibyte_table[i] = (c < 0 ? BYTE8_TO_CHAR (i) : c);
1181      }      }
1182    
1183    for (charset = from; charset < to; charset++)    return Qnil;
1184      if (!CHARSET_DEFINED_P (charset)) break;  }
1185    
1186    
1187    return make_number (charset < to ? charset : 0);  DEFUN ("charset-plist", Fcharset_plist, Scharset_plist, 1, 1, 0,
1188           doc: /* Return the property list of CHARSET.  */)
1189         (charset)
1190         Lisp_Object charset;
1191    {
1192      Lisp_Object attrs;
1193    
1194      CHECK_CHARSET_GET_ATTR (charset, attrs);
1195      return CHARSET_ATTR_PLIST (attrs);
1196  }  }
1197    
1198  DEFUN ("define-charset", Fdefine_charset, Sdefine_charset, 3, 3, 0,  
1199         doc: /* Define CHARSET-ID as the identification number of CHARSET with INFO-VECTOR.  DEFUN ("set-charset-plist", Fset_charset_plist, Sset_charset_plist, 2, 2, 0,
1200  If CHARSET-ID is nil, it is decided automatically, which means CHARSET is         doc: /* Set CHARSET's property list to PLIST.  */)
1201   treated as a private charset.       (charset, plist)
1202  INFO-VECTOR is a vector of the format:       Lisp_Object charset, plist;
1203     [DIMENSION CHARS WIDTH DIRECTION ISO-FINAL-CHAR ISO-GRAPHIC-PLANE  {
1204      SHORT-NAME LONG-NAME DESCRIPTION]    Lisp_Object attrs;
1205  The meanings of each elements is as follows:  
1206  DIMENSION (integer) is the number of bytes to represent a character: 1 or 2.    CHECK_CHARSET_GET_ATTR (charset, attrs);
1207  CHARS (integer) is the number of characters in a dimension: 94 or 96.    CHARSET_ATTR_PLIST (attrs) = plist;
1208  WIDTH (integer) is the number of columns a character in the charset    return plist;
 occupies on the screen: one of 0, 1, and 2.  
   
 DIRECTION (integer) is the rendering direction of characters in the  
 charset when rendering.  If 0, render from left to right, else  
 render from right to left.  
   
 ISO-FINAL-CHAR (character) is the final character of the  
 corresponding ISO 2022 charset.  
 It may be -1 if the charset is internal use only.  
   
 ISO-GRAPHIC-PLANE (integer) is the graphic plane to be invoked  
 while encoding to variants of ISO 2022 coding system, one of the  
 following: 0/graphic-plane-left(GL), 1/graphic-plane-right(GR).  
 It may be -1 if the charset is internal use only.  
   
 SHORT-NAME (string) is the short name to refer to the charset.  
   
 LONG-NAME (string) is the long name to refer to the charset.  
   
 DESCRIPTION (string) is the description string of the charset.  */)  
        (charset_id, charset_symbol, info_vector)  
      Lisp_Object charset_id, charset_symbol, info_vector;  
 {  
   Lisp_Object *vec;  
   
   if (!NILP (charset_id))  
     CHECK_NUMBER (charset_id);  
   CHECK_SYMBOL (charset_symbol);  
   CHECK_VECTOR (info_vector);  
   
   if (! NILP (charset_id))  
     {  
       if (! CHARSET_VALID_P (XINT (charset_id)))  
         error ("Invalid CHARSET: %d", XINT (charset_id));  
       else if (CHARSET_DEFINED_P (XINT (charset_id)))  
         error ("Already defined charset: %d", XINT (charset_id));  
     }  
   
   vec = XVECTOR (info_vector)->contents;  
   if (XVECTOR (info_vector)->size != 9  
       || !INTEGERP (vec[0]) || !(XINT (vec[0]) == 1 || XINT (vec[0]) == 2)  
       || !INTEGERP (vec[1]) || !(XINT (vec[1]) == 94 || XINT (vec[1]) == 96)  
       || !INTEGERP (vec[2]) || !(XINT (vec[2]) == 1 || XINT (vec[2]) == 2)  
       || !INTEGERP (vec[3]) || !(XINT (vec[3]) == 0 || XINT (vec[3]) == 1)  
       || !INTEGERP (vec[4])  
       || !(XINT (vec[4]) == -1 || (XINT (vec[4]) >= '0' && XINT (vec[4]) <= '~'))  
       || !INTEGERP (vec[5])  
       || !(XINT (vec[5]) == -1 || XINT (vec[5]) == 0 || XINT (vec[5]) == 1)  
       || !STRINGP (vec[6])  
       || !STRINGP (vec[7])  
       || !STRINGP (vec[8]))  
     error ("Invalid info-vector argument for defining charset %s",  
            SDATA (SYMBOL_NAME (charset_symbol)));  
   
   if (NILP (charset_id))  
     {  
       charset_id = get_new_private_charset_id (XINT (vec[0]), XINT (vec[2]));  
       if (XINT (charset_id) == 0)  
         error ("There's no room for a new private charset %s",  
                SDATA (SYMBOL_NAME (charset_symbol)));  
     }  
   
   update_charset_table (charset_id, vec[0], vec[1], vec[2], vec[3],  
                         vec[4], vec[5], vec[6], vec[7], vec[8]);  
   Fput (charset_symbol, Qcharset, CHARSET_TABLE_ENTRY (XINT (charset_id)));  
   CHARSET_SYMBOL (XINT (charset_id)) = charset_symbol;  
   Vcharset_list = Fcons (charset_symbol, Vcharset_list);  
   Fupdate_coding_systems_internal ();  
   return Qnil;  
1209  }  }
1210    
1211  DEFUN ("generic-character-list", Fgeneric_character_list,  
1212         Sgeneric_character_list, 0, 0, 0,  DEFUN ("unify-charset", Funify_charset, Sunify_charset, 1, 3, 0,
1213         doc: /* Return a list of all possible generic characters.         doc: /* Unify characters of CHARSET with Unicode.
1214  It includes a generic character for a charset not yet defined.  */)  This means reading the relevant file and installing the table defined
1215       ()  by CHARSET's `:unify-map' property.
1216    
1217    Optional second arg UNIFY-MAP is a file name string or a vector.  It has
1218    the same meaning as the `:unify-map' attribute in the function
1219    `define-charset' (which see).
1220    
1221    Optional third argument DEUNIFY, if non-nil, means to de-unify CHARSET.  */)
1222         (charset, unify_map, deunify)
1223         Lisp_Object charset, unify_map, deunify;
1224  {  {
1225    return Vgeneric_character_list;    int id;
1226      struct charset *cs;
1227    
1228      CHECK_CHARSET_GET_ID (charset, id);
1229      cs = CHARSET_FROM_ID (id);
1230      if (CHARSET_METHOD (cs) == CHARSET_METHOD_MAP_DEFERRED)
1231        load_charset (cs);
1232      if (NILP (deunify)
1233          ? CHARSET_UNIFIED_P (cs) && ! NILP (CHARSET_DEUNIFIER (cs))
1234          : ! CHARSET_UNIFIED_P (cs))
1235        return Qnil;
1236    
1237      CHARSET_UNIFIED_P (cs) = 0;
1238      if (NILP (deunify))
1239        {
1240          if (CHARSET_METHOD (cs) != CHARSET_METHOD_OFFSET)
1241            error ("Can't unify charset: %s", SDATA (SYMBOL_NAME (charset)));
1242          if (NILP (unify_map))
1243            unify_map = CHARSET_UNIFY_MAP (cs);
1244          if (STRINGP (unify_map))
1245            load_charset_map_from_file (cs, unify_map, 2);
1246          else if (VECTORP (unify_map))
1247            load_charset_map_from_vector (cs, unify_map, 2);
1248          else if (NILP (unify_map))
1249            error ("No unify-map for charset");
1250          else
1251            error ("Bad unify-map arg");
1252          CHARSET_UNIFIED_P (cs) = 1;
1253        }
1254      else if (CHAR_TABLE_P (Vchar_unify_table))
1255        {
1256          int min_code = CHARSET_MIN_CODE (cs);
1257          int max_code = CHARSET_MAX_CODE (cs);
1258          int min_char = DECODE_CHAR (cs, min_code);
1259          int max_char = DECODE_CHAR (cs, max_code);
1260    
1261          char_table_set_range (Vchar_unify_table, min_char, max_char, Qnil);
1262        }
1263    
1264      return Qnil;
1265  }  }
1266    
1267  DEFUN ("get-unused-iso-final-char", Fget_unused_iso_final_char,  DEFUN ("get-unused-iso-final-char", Fget_unused_iso_final_char,
1268         Sget_unused_iso_final_char, 2, 2, 0,         Sget_unused_iso_final_char, 2, 2, 0,
1269         doc: /* Return an unsed ISO's final char for a charset of DIMENISION and CHARS.         doc: /*
1270    Return an unsed ISO final char for a charset of DIMENISION and CHARS.
1271  DIMENSION is the number of bytes to represent a character: 1 or 2.  DIMENSION is the number of bytes to represent a character: 1 or 2.
1272  CHARS is the number of characters in a dimension: 94 or 96.  CHARS is the number of characters in a dimension: 94 or 96.
1273    
# Line 744  return nil.  */) Line 1281  return nil.  */)
1281    
1282    CHECK_NUMBER (dimension);    CHECK_NUMBER (dimension);
1283    CHECK_NUMBER (chars);    CHECK_NUMBER (chars);
1284    if (XINT (dimension) != 1 && XINT (dimension) != 2)    if (XINT (dimension) != 1 && XINT (dimension) != 2 && XINT (dimension) != 3)
1285      error ("Invalid charset dimension %d, it should be 1 or 2",      args_out_of_range_3 (dimension, make_number (1), make_number (3));
            XINT (dimension));  
1286    if (XINT (chars) != 94 && XINT (chars) != 96)    if (XINT (chars) != 94 && XINT (chars) != 96)
1287      error ("Invalid charset chars %d, it should be 94 or 96",      args_out_of_range_3 (chars, make_number (94), make_number (96));
            XINT (chars));  
1288    for (final_char = '0'; final_char <= '?'; final_char++)    for (final_char = '0'; final_char <= '?'; final_char++)
1289      {      if (ISO_CHARSET_TABLE (XINT (dimension), XINT (chars), final_char) < 0)
1290        if (ISO_CHARSET_TABLE (dimension, chars, make_number (final_char)) < 0)        break;
         break;  
     }  
1291    return (final_char <= '?' ? make_number (final_char) : Qnil);    return (final_char <= '?' ? make_number (final_char) : Qnil);
1292  }  }
1293    
1294  DEFUN ("declare-equiv-charset", Fdeclare_equiv_charset, Sdeclare_equiv_charset,  static void
1295         4, 4, 0,  check_iso_charset_parameter (dimension, chars, final_char)
1296         doc: /* Declare a charset of DIMENSION, CHARS, FINAL-CHAR is the same as CHARSET.       Lisp_Object dimension, chars, final_char;
 CHARSET should be defined by `defined-charset' in advance.  */)  
      (dimension, chars, final_char, charset_symbol)  
      Lisp_Object dimension, chars, final_char, charset_symbol;  
1297  {  {
1298    int charset;    CHECK_NATNUM (dimension);
1299      CHECK_NATNUM (chars);
1300      CHECK_NATNUM (final_char);
1301    
1302    CHECK_NUMBER (dimension);    if (XINT (dimension) > 3)
1303    CHECK_NUMBER (chars);      error ("Invalid DIMENSION %d, it should be 1, 2, or 3", XINT (dimension));
   CHECK_NUMBER (final_char);  
   CHECK_SYMBOL (charset_symbol);  
   
   if (XINT (dimension) != 1 && XINT (dimension) != 2)  
     error ("Invalid DIMENSION %d, it should be 1 or 2", XINT (dimension));  
1304    if (XINT (chars) != 94 && XINT (chars) != 96)    if (XINT (chars) != 94 && XINT (chars) != 96)
1305      error ("Invalid CHARS %d, it should be 94 or 96", XINT (chars));      error ("Invalid CHARS %d, it should be 94 or 96", XINT (chars));
1306    if (XINT (final_char) < '0' || XFASTINT (final_char) > '~')    if (XINT (final_char) < '0' || XINT (final_char) > '~')
1307      error ("Invalid FINAL-CHAR %c, it should be `0'..`~'", XINT (chars));      error ("Invalid FINAL-CHAR %c, it should be `0'..`~'", XINT (chars));
1308    if ((charset = get_charset_id (charset_symbol)) < 0)  }
1309      error ("Invalid charset %s", SDATA (SYMBOL_NAME (charset_symbol)));  
1310    
1311    DEFUN ("declare-equiv-charset", Fdeclare_equiv_charset, Sdeclare_equiv_charset,
1312           4, 4, 0,
1313           doc: /*
1314    Declare a charset of DIMENSION, CHARS, FINAL-CHAR is the same as CHARSET.
1315    CHARSET should be defined by `define-charset' in advance.  */)
1316         (dimension, chars, final_char, charset)
1317         Lisp_Object dimension, chars, final_char, charset;
1318    {
1319      int id;
1320    
1321    ISO_CHARSET_TABLE (dimension, chars, final_char) = charset;    CHECK_CHARSET_GET_ID (charset, id);
1322      check_iso_charset_parameter (dimension, chars, final_char);
1323    
1324      ISO_CHARSET_TABLE (XINT (dimension), XINT (chars), XINT (final_char)) = id;
1325    return Qnil;    return Qnil;
1326  }  }
1327    
1328    
1329  /* Return information about charsets in the text at PTR of NBYTES  /* Return information about charsets in the text at PTR of NBYTES
1330     bytes, which are NCHARS characters.  The value is:     bytes, which are NCHARS characters.  The value is:
1331    
1332          0: Each character is represented by one byte.  This is always          0: Each character is represented by one byte.  This is always
1333             true for unibyte text.             true for a unibyte string.  For a multibyte string, true if
1334          1: No charsets other than ascii eight-bit-control,             it contains only ASCII characters.
            eight-bit-graphic, and latin-1 are found.  
         2: Otherwise.  
1335    
1336     In addition, if CHARSETS is nonzero, for each found charset N, set          1: No charsets other than ascii, control-1, and latin-1 are
1337     CHARSETS[N] to 1.  For that, callers should allocate CHARSETS             found.
1338     (MAX_CHARSET + 1 elements) in advance.  It may lookup a translation  
1339     table TABLE if supplied.  For invalid charsets, set CHARSETS[1] to          2: Otherwise.
1340     1 (note that there's no charset whose ID is 1).  */  */
1341    
1342  int  int
1343  find_charset_in_text (ptr, nchars, nbytes, charsets, table)  string_xstring_p (string)
1344       const unsigned char *ptr;       Lisp_Object string;
      int nchars, nbytes, *charsets;  
      Lisp_Object table;  
1345  {  {
1346    if (nchars == nbytes)    const unsigned char *p = SDATA (string);
1347      {    const unsigned char *endp = p + SBYTES (string);
1348        if (charsets && nbytes > 0)    struct charset *charset;
         {  
           const unsigned char *endp = ptr + nbytes;  
           int maskbits = 0;  
1349    
1350            while (ptr < endp && maskbits != 7)    if (SCHARS (string) == SBYTES (string))
1351              {      return 0;
               maskbits |= (*ptr < 0x80 ? 1 : *ptr < 0xA0 ? 2 : 4);  
               ptr++;  
             }  
1352    
1353            if (maskbits & 1)    charset = CHARSET_FROM_ID (charset_iso_8859_1);
1354              charsets[CHARSET_ASCII] = 1;    while (p < endp)
           if (maskbits & 2)  
             charsets[CHARSET_8_BIT_CONTROL] = 1;  
           if (maskbits & 4)  
             charsets[CHARSET_8_BIT_GRAPHIC] = 1;  
         }  
       return 0;  
     }  
   else  
1355      {      {
1356        int return_val = 1;        int c = STRING_CHAR_ADVANCE (p);
       int bytes, charset, c1, c2;  
1357    
1358        if (! CHAR_TABLE_P (table))        /* Fixme: comparison of unsigned expression < 0 is always false */
1359          table = Qnil;        if (ENCODE_CHAR (charset, c) < 0)
1360            return 2;
1361        }
1362      return 1;
1363    }
1364    
       while (nchars-- > 0)  
         {  
           SPLIT_MULTIBYTE_SEQ (ptr, len, bytes, charset, c1, c2);  
           ptr += bytes;  
1365    
1366            if (!CHARSET_DEFINED_P (charset))  /* Find charsets in the string at PTR of NCHARS and NBYTES.
1367              charset = 1;  
1368            else if (! NILP (table))     CHARSETS is a vector.  Each element is a cons of CHARSET and
1369       FOUND-FLAG.  CHARSET is a charset id, and FOUND-FLAG is nil or t.
1370       FOUND-FLAG t (or nil) means that the corresponding charset is
1371       already found (or not yet found).
1372    
1373       It may lookup a translation table TABLE if supplied.  */
1374    
1375    static void
1376    find_charsets_in_text (ptr, nchars, nbytes, charsets, table)
1377         const unsigned char *ptr;
1378         int nchars, nbytes;
1379         Lisp_Object charsets, table;
1380    {
1381      const unsigned char *pend = ptr + nbytes;
1382      int ncharsets = ASIZE (charsets);
1383    
1384      if (nchars == nbytes)
1385        return;
1386    
1387      while (ptr < pend)
1388        {
1389          int c = STRING_CHAR_ADVANCE (ptr);
1390          int i;
1391          int all_found = 1;
1392          Lisp_Object elt;
1393    
1394          if (!NILP (table))
1395            c = translate_char (table, c);
1396          for (i = 0; i < ncharsets; i++)
1397            {
1398              elt = AREF (charsets, i);
1399              if (NILP (XCDR (elt)))
1400              {              {
1401                int c = translate_char (table, -1, charset, c1, c2);                struct charset *charset = CHARSET_FROM_ID (XINT (XCAR (elt)));
               if (c >= 0)  
                 charset = CHAR_CHARSET (c);  
             }  
1402    
1403            if (return_val == 1                if (ENCODE_CHAR (charset, c) != CHARSET_INVALID_CODE (charset))
1404                && charset != CHARSET_ASCII                  XSETCDR (elt, Qt);
1405                && charset != CHARSET_8_BIT_CONTROL                else
1406                && charset != CHARSET_8_BIT_GRAPHIC                  all_found = 0;
1407                && charset != charset_latin_iso8859_1)              }
             return_val = 2;  
   
           if (charsets)  
             charsets[charset] = 1;  
           else if (return_val == 2)  
             break;  
1408          }          }
1409        return return_val;        if (all_found)
1410            break;
1411      }      }
1412  }  }
1413    
1414    /* Fixme: returns nil for unibyte.  */
1415  DEFUN ("find-charset-region", Ffind_charset_region, Sfind_charset_region,  DEFUN ("find-charset-region", Ffind_charset_region, Sfind_charset_region,
1416         2, 3, 0,         2, 3, 0,
1417         doc: /* Return a list of charsets in the region between BEG and END.         doc: /* Return a list of charsets in the region between BEG and END.
1418  BEG and END are buffer positions.  BEG and END are buffer positions.
1419  Optional arg TABLE if non-nil is a translation table to look up.  Optional arg TABLE if non-nil is a translation table to look up.
1420    
 If the region contains invalid multibyte characters,  
 `unknown' is included in the returned list.  
   
1421  If the current buffer is unibyte, the returned list may contain  If the current buffer is unibyte, the returned list may contain
1422  only `ascii', `eight-bit-control', and `eight-bit-graphic'.  */)  only `ascii', `eight-bit-control', and `eight-bit-graphic'.  */)
1423       (beg, end, table)       (beg, end, table)
1424       Lisp_Object beg, end, table;       Lisp_Object beg, end, table;
1425  {  {
1426    int charsets[MAX_CHARSET + 1];    Lisp_Object charsets;
1427    int from, from_byte, to, stop, stop_byte, i;    int from, from_byte, to, stop, stop_byte, i;
1428    Lisp_Object val;    Lisp_Object val;
1429    
# Line 898  only `ascii', `eight-bit-control', and ` Line 1441  only `ascii', `eight-bit-control', and `
1441    
1442    from_byte = CHAR_TO_BYTE (from);    from_byte = CHAR_TO_BYTE (from);
1443    
1444    bzero (charsets, (MAX_CHARSET + 1) * sizeof (int));    charsets = Fmake_vector (make_number (charset_table_used), Qnil);
1445      for (i = 0; i < charset_table_used; i++)
1446        ASET (charsets, i, Fcons (make_number (i), Qnil));
1447    
1448    while (1)    while (1)
1449      {      {
1450        find_charset_in_text (BYTE_POS_ADDR (from_byte), stop - from,        find_charsets_in_text (BYTE_POS_ADDR (from_byte), stop - from,
1451                              stop_byte - from_byte, charsets, table);                               stop_byte - from_byte, charsets, table);
1452        if (stop < to)        if (stop < to)
1453          {          {
1454            from = stop, from_byte = stop_byte;            from = stop, from_byte = stop_byte;
# Line 913  only `ascii', `eight-bit-control', and ` Line 1459  only `ascii', `eight-bit-control', and `
1459      }      }
1460    
1461    val = Qnil;    val = Qnil;
1462    if (charsets[1])    for (i = charset_table_used - 1; i >= 0; i--)
1463      val = Fcons (Qunknown, val);      if (!NILP (XCDR (AREF (charsets, i))))
1464    for (i = MAX_CHARSET; i >= MIN_CHARSET_OFFICIAL_DIMENSION1; i--)        val = Fcons (CHARSET_NAME (charset_table + i), val);
     if (charsets[i])  
       val = Fcons (CHARSET_SYMBOL (i), val);  
   if (charsets[0])  
     val = Fcons (Qascii, val);  
1465    return val;    return val;
1466  }  }
1467    
1468    /* Fixme: returns nil for unibyte.  */
1469  DEFUN ("find-charset-string", Ffind_charset_string, Sfind_charset_string,  DEFUN ("find-charset-string", Ffind_charset_string, Sfind_charset_string,
1470         1, 2, 0,         1, 2, 0,
1471         doc: /* Return a list of charsets in STR.         doc: /* Return a list of charsets in STR.
1472  Optional arg TABLE if non-nil is a translation table to look up.  Optional arg TABLE if non-nil is a translation table to look up.
1473    
 If the string contains invalid multibyte characters,  
 `unknown' is included in the returned list.  
   
1474  If STR is unibyte, the returned list may contain  If STR is unibyte, the returned list may contain
1475  only `ascii', `eight-bit-control', and `eight-bit-graphic'.  */)  only `ascii', `eight-bit-control', and `eight-bit-graphic'. */)
1476       (str, table)       (str, table)
1477       Lisp_Object str, table;       Lisp_Object str, table;
1478  {  {
1479    int charsets[MAX_CHARSET + 1];    Lisp_Object charsets;
1480    int i;    int i;
1481    Lisp_Object val;    Lisp_Object val;
1482    
1483    CHECK_STRING (str);    CHECK_STRING (str);
1484    
1485    bzero (charsets, (MAX_CHARSET + 1) * sizeof (int));    charsets = Fmake_vector (make_number (charset_table_used), Qnil);
1486    find_charset_in_text (SDATA (str), SCHARS (str),    for (i = 0; i < charset_table_used; i++)
1487                          SBYTES (str), charsets, table);      ASET (charsets, i, Fcons (make_number (i), Qnil));
1488      find_charsets_in_text (SDATA (str), SCHARS (str), SBYTES (str),
1489                             charsets, table);
1490    
1491    val = Qnil;    val = Qnil;
1492    if (charsets[1])    for (i = charset_table_used - 1; i >= 0; i--)
1493      val = Fcons (Qunknown, val);      if (!NILP (XCDR (AREF (charsets, i))))
1494    for (i = MAX_CHARSET; i >= MIN_CHARSET_OFFICIAL_DIMENSION1; i--)        val = Fcons (CHARSET_NAME (charset_table + i), val);
     if (charsets[i])  
       val = Fcons (CHARSET_SYMBOL (i), val);  
   if (charsets[0])  
     val = Fcons (Qascii, val);  
1495    return val;    return val;
1496  }  }
1497    
1498    
 DEFUN ("make-char-internal", Fmake_char_internal, Smake_char_internal, 1, 3, 0,  
        doc: /* Return a character made from arguments.  
 Internal use only.  */)  
      (charset, code1, code2)  
      Lisp_Object charset, code1, code2;  
 {  
   int charset_id, c1, c2;  
   
   CHECK_NUMBER (charset);  
   charset_id = XINT (charset);  
   if (!CHARSET_DEFINED_P (charset_id))  
     error ("Invalid charset ID: %d", XINT (charset));  
1499    
1500    if (NILP (code1))  /* Return a character correponding to the code-point CODE of
1501      c1 = 0;     CHARSET.  */
1502    else  
1503      {  int
1504        CHECK_NUMBER (code1);  decode_char (charset, code)
1505        c1 = XINT (code1);       struct charset *charset;
1506      }       unsigned code;
1507    if (NILP (code2))  {
1508      c2 = 0;    int c, char_index;
1509    else    enum charset_method method = CHARSET_METHOD (charset);
1510    
1511      if (code < CHARSET_MIN_CODE (charset) || code > CHARSET_MAX_CODE (charset))
1512        return -1;
1513    
1514      if (method == CHARSET_METHOD_MAP_DEFERRED)
1515      {      {
1516        CHECK_NUMBER (code2);        load_charset (charset);
1517        c2 = XINT (code2);        method = CHARSET_METHOD (charset);
1518      }      }
1519    
1520    if (charset_id == CHARSET_ASCII)    if (method == CHARSET_METHOD_SUBSET)
1521      {      {
1522        if (c1 < 0 || c1 > 0x7F)        Lisp_Object subset_info;
         goto invalid_code_posints;  
       return make_number (c1);  
     }  
   else if (charset_id == CHARSET_8_BIT_CONTROL)  
     {  
       if (NILP (code1))  
         c1 = 0x80;  
       else if (c1 < 0x80 || c1 > 0x9F)  
         goto invalid_code_posints;  
       return make_number (c1);  
     }  
   else if (charset_id == CHARSET_8_BIT_GRAPHIC)  
     {  
       if (NILP (code1))  
         c1 = 0xA0;  
       else if (c1 < 0xA0 || c1 > 0xFF)  
         goto invalid_code_posints;  
       return make_number (c1);  
     }  
   else if (c1 < 0 || c1 > 0xFF || c2 < 0 || c2 > 0xFF)  
     goto invalid_code_posints;  
   c1 &= 0x7F;  
   c2 &= 0x7F;  
   if (c1 == 0  
       ? c2 != 0  
       : (c2 == 0  
          ? !CHAR_COMPONENTS_VALID_P (charset_id, c1, 0x20)  
          : !CHAR_COMPONENTS_VALID_P (charset_id, c1, c2)))  
     goto invalid_code_posints;  
   return make_number (MAKE_CHAR (charset_id, c1, c2));  
1523    
1524   invalid_code_posints:        subset_info = CHARSET_SUBSET (charset);
1525    error ("Invalid code points for charset ID %d: %d %d", charset_id, c1, c2);        charset = CHARSET_FROM_ID (XFASTINT (AREF (subset_info, 0)));
1526  }        code -= XINT (AREF (subset_info, 3));
1527          if (code < XFASTINT (AREF (subset_info, 1))
1528              || code > XFASTINT (AREF (subset_info, 2)))
1529            c = -1;
1530          else
1531            c = DECODE_CHAR (charset, code);
1532        }
1533      else if (method == CHARSET_METHOD_SUPERSET)
1534        {
1535          Lisp_Object parents;
1536    
1537  DEFUN ("split-char", Fsplit_char, Ssplit_char, 1, 1, 0,        parents = CHARSET_SUPERSET (charset);
1538         doc: /* Return list of charset and one or two position-codes of CHAR.        c = -1;
1539  If CHAR is invalid as a character code,        for (; CONSP (parents); parents = XCDR (parents))
1540  return a list of symbol `unknown' and CHAR.  */)          {
1541       (ch)            int id = XINT (XCAR (XCAR (parents)));
1542       Lisp_Object ch;            int code_offset = XINT (XCDR (XCAR (parents)));
1543  {            unsigned this_code = code - code_offset;
   int c, charset, c1, c2;  
1544    
1545    CHECK_NUMBER (ch);            charset = CHARSET_FROM_ID (id);
1546    c = XFASTINT (ch);            if ((c = DECODE_CHAR (charset, this_code)) >= 0)
1547    if (!CHAR_VALID_P (c, 1))              break;
1548      return Fcons (Qunknown, Fcons (ch, Qnil));          }
1549    SPLIT_CHAR (XFASTINT (ch), charset, c1, c2);      }
1550    return (c2 >= 0    else
1551            ? Fcons (CHARSET_SYMBOL (charset),      {
1552                     Fcons (make_number (c1), Fcons (make_number (c2), Qnil)))        char_index = CODE_POINT_TO_INDEX (charset, code);
1553            : Fcons (CHARSET_SYMBOL (charset), Fcons (make_number (c1), Qnil)));        if (char_index < 0)
1554  }          return -1;
1555    
1556  DEFUN ("char-charset", Fchar_charset, Schar_charset, 1, 1, 0,        if (method == CHARSET_METHOD_MAP)
1557         doc: /* Return charset of CHAR.  */)          {
1558       (ch)            Lisp_Object decoder;
      Lisp_Object ch;  
 {  
   CHECK_NUMBER (ch);  
1559    
1560    return CHARSET_SYMBOL (CHAR_CHARSET (XINT (ch)));            decoder = CHARSET_DECODER (charset);
1561  }            if (! VECTORP (decoder))
1562                return -1;
1563              c = XINT (AREF (decoder, char_index));
1564            }
1565          else
1566            {
1567              c = char_index + CHARSET_CODE_OFFSET (charset);
1568            }
1569        }
1570    
1571  DEFUN ("charset-after", Fcharset_after, Scharset_after, 0, 1, 0,    if (CHARSET_UNIFIED_P (charset)
1572         doc: /* Return charset of a character in the current buffer at position POS.        && c >= 0)
1573  If POS is nil, it defauls to the current point.      {
1574  If POS is out of range, the value is nil.  */)        MAYBE_UNIFY_CHAR (c);
1575       (pos)      }
      Lisp_Object pos;  
 {  
   Lisp_Object ch;  
   int charset;  
1576    
1577    ch = Fchar_after (pos);    return c;
   if (! INTEGERP (ch))  
     return ch;  
   charset = CHAR_CHARSET (XINT (ch));  
   return CHARSET_SYMBOL (charset);  
1578  }  }
1579    
1580  DEFUN ("iso-charset", Fiso_charset, Siso_charset, 3, 3, 0,  /* Variable used temporarily by the macro ENCODE_CHAR.  */
1581         doc: /* Return charset of ISO's specification DIMENSION, CHARS, and FINAL-CHAR.  Lisp_Object charset_work;
   
 ISO 2022's designation sequence (escape sequence) distinguishes charsets  
 by their DIMENSION, CHARS, and FINAL-CHAR,  
 where as Emacs distinguishes them by charset symbol.  
 See the documentation of the function `charset-info' for the meanings of  
 DIMENSION, CHARS, and FINAL-CHAR.  */)  
      (dimension, chars, final_char)  
      Lisp_Object dimension, chars, final_char;  
 {  
   int charset;  
   
   CHECK_NUMBER (dimension);  
   CHECK_NUMBER (chars);  
   CHECK_NUMBER (final_char);  
   
   if ((charset = ISO_CHARSET_TABLE (dimension, chars, final_char)) < 0)  
     return Qnil;  
   return CHARSET_SYMBOL (charset);  
 }  
1582    
1583  /* If GENERICP is nonzero, return nonzero iff C is a valid normal or  /* Return a code-point of CHAR in CHARSET.  If CHAR doesn't belong to
1584     generic character.  If GENERICP is zero, return nonzero iff C is a     CHARSET, return CHARSET_INVALID_CODE (CHARSET).  If STRICT is true,
1585     valid normal character.  Do not call this function directly,     use CHARSET's strict_max_char instead of max_char.  */
1586     instead use macro CHAR_VALID_P.  */  
1587  int  unsigned
1588  char_valid_p (c, genericp)  encode_char (charset, c)
1589       int c, genericp;       struct charset *charset;
1590         int c;
1591  {  {
1592    int charset, c1, c2;    unsigned code;
1593      enum charset_method method = CHARSET_METHOD (charset);
1594    
1595    if (c < 0 || c >= MAX_CHAR)    if (CHARSET_UNIFIED_P (charset))
     return 0;  
   if (SINGLE_BYTE_CHAR_P (c))  
     return 1;  
   SPLIT_CHAR (c, charset, c1, c2);  
   if (genericp)  
1596      {      {
1597        if (c1)        Lisp_Object deunifier, deunified;
1598          {  
1599            if (c2 <= 0) c2 = 0x20;        deunifier = CHARSET_DEUNIFIER (charset);
1600          }        if (! CHAR_TABLE_P (deunifier))
       else  
1601          {          {
1602            if (c2 <= 0) c1 = c2 = 0x20;            Funify_charset (CHARSET_NAME (charset), Qnil, Qnil);
1603              deunifier = CHARSET_DEUNIFIER (charset);
1604          }          }
1605          deunified = CHAR_TABLE_REF (deunifier, c);
1606          if (! NILP (deunified))
1607            c = XINT (deunified);
1608      }      }
   return (CHARSET_DEFINED_P (charset)  
           && CHAR_COMPONENTS_VALID_P (charset, c1, c2));  
 }  
1609    
1610  DEFUN ("char-valid-p", Fchar_valid_p, Schar_valid_p, 1, 2, 0,    if (method == CHARSET_METHOD_SUBSET)
1611         doc: /* Return t if OBJECT is a valid normal character.      {
1612  If optional arg GENERICP is non-nil, also return t if OBJECT is        Lisp_Object subset_info;
1613  a valid generic character.  */)        struct charset *this_charset;
      (object, genericp)  
      Lisp_Object object, genericp;  
 {  
   if (! NATNUMP (object))  
     return Qnil;  
   return (CHAR_VALID_P (XFASTINT (object), !NILP (genericp)) ? Qt : Qnil);  
 }  
1614    
1615  DEFUN ("unibyte-char-to-multibyte", Funibyte_char_to_multibyte,        subset_info = CHARSET_SUBSET (charset);
1616         Sunibyte_char_to_multibyte, 1, 1, 0,        this_charset = CHARSET_FROM_ID (XFASTINT (AREF (subset_info, 0)));
1617         doc: /* Convert the unibyte character CH to multibyte character.        code = ENCODE_CHAR (this_charset, c);
1618  The conversion is done based on `nonascii-translation-table' (which see)        if (code == CHARSET_INVALID_CODE (this_charset)
1619   or `nonascii-insert-offset' (which see).  */)            || code < XFASTINT (AREF (subset_info, 1))
1620       (ch)            || code > XFASTINT (AREF (subset_info, 2)))
1621       Lisp_Object ch;          return CHARSET_INVALID_CODE (charset);
1622  {        code += XINT (AREF (subset_info, 3));
1623    int c;        return code;
1624        }
1625    
1626    CHECK_NUMBER (ch);    if (method == CHARSET_METHOD_SUPERSET)
1627    c = XINT (ch);      {
1628    if (c < 0 || c >= 0400)        Lisp_Object parents;
     error ("Invalid unibyte character: %d", c);  
   c = unibyte_char_to_multibyte (c);  
   if (c < 0)  
     error ("Can't convert to multibyte character: %d", XINT (ch));  
   return make_number (c);  
 }  
1629    
1630  DEFUN ("multibyte-char-to-unibyte", Fmultibyte_char_to_unibyte,        parents = CHARSET_SUPERSET (charset);
1631         Smultibyte_char_to_unibyte, 1, 1, 0,        for (; CONSP (parents); parents = XCDR (parents))
1632         doc: /* Convert the multibyte character CH to unibyte character.          {
1633  The conversion is done based on `nonascii-translation-table' (which see)            int id = XINT (XCAR (XCAR (parents)));
1634   or `nonascii-insert-offset' (which see).  */)            int code_offset = XINT (XCDR (XCAR (parents)));
1635       (ch)            struct charset *this_charset = CHARSET_FROM_ID (id);
      Lisp_Object ch;  
 {  
   int c;  
1636    
1637    CHECK_NUMBER (ch);            code = ENCODE_CHAR (this_charset, c);
1638    c = XINT (ch);            if (code != CHARSET_INVALID_CODE (this_charset))
1639    if (! CHAR_VALID_P (c, 0))              return code + code_offset;
1640      error ("Invalid multibyte character: %d", c);          }
1641    c = multibyte_char_to_unibyte (c, Qnil);        return CHARSET_INVALID_CODE (charset);
1642    if (c < 0)      }
     error ("Can't convert to unibyte character: %d", XINT (ch));  
   return make_number (c);  
 }  
1643    
1644  DEFUN ("char-bytes", Fchar_bytes, Schar_bytes, 1, 1, 0,    if (! CHARSET_FAST_MAP_REF ((c), charset->fast_map)
1645         doc: /* Return 1 regardless of the argument CHAR.  */)        || c < CHARSET_MIN_CHAR (charset) || c > CHARSET_MAX_CHAR (charset))
1646       (ch)      return CHARSET_INVALID_CODE (charset);
      Lisp_Object ch;  
 {  
   CHECK_NUMBER (ch);  
   return make_number (1);  
 }  
1647    
1648  /* Return how many bytes C will occupy in a multibyte buffer.    if (method == CHARSET_METHOD_MAP_DEFERRED)
1649     Don't call this function directly, instead use macro CHAR_BYTES.  */      {
1650  int        load_charset (charset);
1651  char_bytes (c)        method = CHARSET_METHOD (charset);
1652       int c;      }
 {  
   int charset;  
1653    
1654    if (ASCII_BYTE_P (c) || (c & ~((1 << CHARACTERBITS) -1)))    if (method == CHARSET_METHOD_MAP)
1655      return 1;      {
1656    if (SINGLE_BYTE_CHAR_P (c) && c >= 0xA0)        Lisp_Object encoder;
1657      return 1;        Lisp_Object val;
1658    
1659    charset = CHAR_CHARSET (c);        encoder = CHARSET_ENCODER (charset);
1660    return (CHARSET_DEFINED_P (charset) ? CHARSET_BYTES (charset) : 1);        if (! CHAR_TABLE_P (CHARSET_ENCODER (charset)))
1661            return CHARSET_INVALID_CODE (charset);
1662          val = CHAR_TABLE_REF (encoder, c);
1663          if (NILP (val))
1664            return CHARSET_INVALID_CODE (charset);
1665          code = XINT (val);
1666          if (! CHARSET_COMPACT_CODES_P (charset))
1667            code = INDEX_TO_CODE_POINT (charset, code);
1668        }
1669      else                          /* method == CHARSET_METHOD_OFFSET */
1670        {
1671          code = c - CHARSET_CODE_OFFSET (charset);
1672          code = INDEX_TO_CODE_POINT (charset, code);
1673        }
1674    
1675      return code;
1676  }  }
1677    
 /* Return the width of character of which multi-byte form starts with  
    C.  The width is measured by how many columns occupied on the  
    screen when displayed in the current buffer.  */  
   
 #define ONE_BYTE_CHAR_WIDTH(c)                                          \  
   (c < 0x20                                                             \  
    ? (c == '\t'                                                         \  
       ? XFASTINT (current_buffer->tab_width)                            \  
       : (c == '\n' ? 0 : (NILP (current_buffer->ctl_arrow) ? 4 : 2)))   \  
    : (c < 0x7f                                                          \  
       ? 1                                                               \  
       : (c == 0x7F                                                      \  
          ? (NILP (current_buffer->ctl_arrow) ? 4 : 2)                   \  
          : ((! NILP (current_buffer->enable_multibyte_characters)       \  
              && BASE_LEADING_CODE_P (c))                                \  
             ? WIDTH_BY_CHAR_HEAD (c)                                    \  
             : 4))))  
   
 DEFUN ("char-width", Fchar_width, Schar_width, 1, 1, 0,  
        doc: /* Return width of CHAR when displayed in the current buffer.  
 The width is measured by how many columns it occupies on the screen.  
 Tab is taken to occupy `tab-width' columns.  */)  
      (ch)  
      Lisp_Object ch;  
 {  
   Lisp_Object val, disp;  
   int c;  
   struct Lisp_Char_Table *dp = buffer_display_table ();  
1678    
1679    CHECK_NUMBER (ch);  DEFUN ("decode-char", Fdecode_char, Sdecode_char, 2, 3, 0,
1680           doc: /* Decode the pair of CHARSET and CODE-POINT into a character.
1681    Return nil if CODE-POINT is not valid in CHARSET.
1682    
1683    c = XINT (ch);  CODE-POINT may be a cons (HIGHER-16-BIT-VALUE . LOWER-16-BIT-VALUE).
1684    
1685    /* Get the way the display table would display it.  */  Optional argument RESTRICTION specifies a way to map the pair of CCS
1686    disp = dp ? DISP_CHAR_VECTOR (dp, c) : Qnil;  and CODE-POINT to a chracter.   Currently not supported and just ignored.  */)
1687      (charset, code_point, restriction)
1688         Lisp_Object charset, code_point, restriction;
1689    {
1690      int c, id;
1691      unsigned code;
1692      struct charset *charsetp;
1693    
1694    if (VECTORP (disp))    CHECK_CHARSET_GET_ID (charset, id);
1695      XSETINT (val, XVECTOR (disp)->size);    if (CONSP (code_point))
1696    else if (SINGLE_BYTE_CHAR_P (c))      {
1697      XSETINT (val, ONE_BYTE_CHAR_WIDTH (c));        CHECK_NATNUM_CAR (code_point);
1698          CHECK_NATNUM_CDR (code_point);
1699          code = (XINT (XCAR (code_point)) << 16) | (XINT (XCDR (code_point)));
1700        }
1701    else    else
1702      {      {
1703        int charset = CHAR_CHARSET (c);        CHECK_NATNUM (code_point);
1704          code = XINT (code_point);
       XSETFASTINT (val, CHARSET_WIDTH (charset));  
1705      }      }
1706    return val;    charsetp = CHARSET_FROM_ID (id);
1707      c = DECODE_CHAR (charsetp, code);
1708      return (c >= 0 ? make_number (c) : Qnil);
1709  }  }
1710    
 /* Return width of string STR of length LEN when displayed in the  
    current buffer.  The width is measured by how many columns it  
    occupies on the screen.  */  
1711    
1712  int  DEFUN ("encode-char", Fencode_char, Sencode_char, 2, 3, 0,
1713  strwidth (str, len)         doc: /* Encode the character CH into a code-point of CHARSET.
1714       unsigned char *str;  Return nil if CHARSET doesn't include CH.
1715       int len;  
1716  {  Optional argument RESTRICTION specifies a way to map CHAR to a
1717    return c_string_width (str, len, -1, NULL, NULL);  code-point in CCS.  Currently not supported and just ignored.  */)
1718         (ch, charset, restriction)
1719         Lisp_Object ch, charset, restriction;
1720    {
1721      int id;
1722      unsigned code;
1723      struct charset *charsetp;
1724    
1725      CHECK_CHARSET_GET_ID (charset, id);
1726      CHECK_NATNUM (ch);
1727      charsetp = CHARSET_FROM_ID (id);
1728      code = ENCODE_CHAR (charsetp, XINT (ch));
1729      if (code == CHARSET_INVALID_CODE (charsetp))
1730        return Qnil;
1731      if (code > 0x7FFFFFF)
1732        return Fcons (make_number (code >> 16), make_number (code & 0xFFFF));
1733      return make_number (code);
1734  }  }
1735    
 /* Return width of string STR of length LEN when displayed in the  
    current buffer.  The width is measured by how many columns it  
    occupies on the screen.  If PRECISION > 0, return the width of  
    longest substring that doesn't exceed PRECISION, and set number of  
    characters and bytes of the substring in *NCHARS and *NBYTES  
    respectively.  */  
1736    
1737  int  DEFUN ("make-char", Fmake_char, Smake_char, 1, 5, 0,
1738  c_string_width (str, len, precision, nchars, nbytes)         doc:
1739       const unsigned char *str;         /* Return a character of CHARSET whose position codes are CODEn.
      int len, precision, *nchars, *nbytes;  
 {  
   int i = 0, i_byte = 0;  
   int width = 0;  
   int chars;  
   struct Lisp_Char_Table *dp = buffer_display_table ();  
1740    
1741    while (i_byte < len)  CODE1 through CODE4 are optional, but if you don't supply sufficient
1742      {  position codes, it is assumed that the minimum code in each dimension
1743        int bytes, thiswidth;  is specified.  */)
1744        Lisp_Object val;       (charset, code1, code2, code3, code4)
1745         Lisp_Object charset, code1, code2, code3, code4;
1746    {
1747      int id, dimension;
1748      struct charset *charsetp;
1749      unsigned code;
1750      int c;
1751    
1752        if (dp)    CHECK_CHARSET_GET_ID (charset, id);
1753          {    charsetp = CHARSET_FROM_ID (id);
           int c = STRING_CHAR_AND_LENGTH (str + i_byte, len - i_byte, bytes);  
1754    
1755            chars = 1;    dimension = CHARSET_DIMENSION (charsetp);
1756            val = DISP_CHAR_VECTOR (dp, c);    if (NILP (code1))
1757            if (VECTORP (val))      code = (CHARSET_ASCII_COMPATIBLE_P (charsetp)
1758              thiswidth = XVECTOR (val)->size;              ? 0 : CHARSET_MIN_CODE (charsetp));
1759      else
1760        {
1761          CHECK_NATNUM (code1);
1762          if (XFASTINT (code1) >= 0x100)
1763            args_out_of_range (make_number (0xFF), code1);
1764          code = XFASTINT (code1);
1765    
1766          if (dimension > 1)
1767            {
1768              code <<= 8;
1769              if (NILP (code2))
1770                code |= charsetp->code_space[(dimension - 2) * 4];
1771            else            else
1772              thiswidth = ONE_BYTE_CHAR_WIDTH (str[i_byte]);              {
1773          }                CHECK_NATNUM (code2);
1774        else                if (XFASTINT (code2) >= 0x100)
1775          {                  args_out_of_range (make_number (0xFF), code2);
1776            chars = 1;                code |= XFASTINT (code2);
1777            PARSE_MULTIBYTE_SEQ (str + i_byte, len - i_byte, bytes);              }
           thiswidth = ONE_BYTE_CHAR_WIDTH (str[i_byte]);  
         }  
1778    
1779        if (precision > 0            if (dimension > 2)
1780            && (width + thiswidth > precision))              {
1781          {                code <<= 8;
1782            *nchars = i;                if (NILP (code3))
1783            *nbytes = i_byte;                  code |= charsetp->code_space[(dimension - 3) * 4];
1784            return width;                else
1785                    {
1786                      CHECK_NATNUM (code3);
1787                      if (XFASTINT (code3) >= 0x100)
1788                        args_out_of_range (make_number (0xFF), code3);
1789                      code |= XFASTINT (code3);
1790                    }
1791    
1792                  if (dimension > 3)
1793                    {
1794                      code <<= 8;
1795                      if (NILP (code4))
1796                        code |= charsetp->code_space[0];
1797                      else
1798                        {
1799                          CHECK_NATNUM (code4);
1800                          if (XFASTINT (code4) >= 0x100)
1801                            args_out_of_range (make_number (0xFF), code4);
1802                          code |= XFASTINT (code4);
1803                        }
1804                    }
1805                }
1806          }          }
       i++;  
       i_byte += bytes;  
       width += thiswidth;  
   }  
   
   if (precision > 0)  
     {  
       *nchars = i;  
       *nbytes = i_byte;  
1807      }      }
1808    
1809    return width;    if (CHARSET_ISO_FINAL (charsetp) >= 0)
1810        code &= 0x7F7F7F7F;
1811      c = DECODE_CHAR (charsetp, code);
1812      if (c < 0)
1813        error ("Invalid code(s)");
1814      return make_number (c);
1815  }  }
1816    
 /* Return width of Lisp string STRING when displayed in the current  
    buffer.  The width is measured by how many columns it occupies on  
    the screen while paying attention to compositions.  If PRECISION >  
    0, return the width of longest substring that doesn't exceed  
    PRECISION, and set number of characters and bytes of the substring  
    in *NCHARS and *NBYTES respectively.  */  
1817    
1818  int  /* Return the first charset in CHARSET_LIST that contains C.
1819  lisp_string_width (string, precision, nchars, nbytes)     CHARSET_LIST is a list of charset IDs.  If it is nil, use
1820       Lisp_Object string;     Vcharset_ordered_list.  */
1821       int precision, *nchars, *nbytes;  
1822    struct charset *
1823    char_charset (c, charset_list, code_return)
1824         int c;
1825         Lisp_Object charset_list;
1826         unsigned *code_return;
1827  {  {
1828    int len = SCHARS (string);    if (NILP (charset_list))
1829    int len_byte = SBYTES (string);      charset_list = Vcharset_ordered_list;
   const unsigned char *str = SDATA (string);  
   int i = 0, i_byte = 0;  
   int width = 0;  
   struct Lisp_Char_Table *dp = buffer_display_table ();  
1830    
1831    while (i < len)    while (CONSP (charset_list))
1832      {      {
1833        int chars, bytes, thiswidth;        struct charset *charset = CHARSET_FROM_ID (XINT (XCAR (charset_list)));
1834        Lisp_Object val;        unsigned code = ENCODE_CHAR (charset, c);
       int cmp_id;  
       int ignore, end;  
   
       if (find_composition (i, -1, &ignore, &end, &val, string)  
           && ((cmp_id = get_composition_id (i, i_byte, end - i, val, string))  
               >= 0))  
         {  
           thiswidth = composition_table[cmp_id]->width;  
           chars = end - i;  
           bytes = string_char_to_byte (string, end) - i_byte;  
         }  
       else if (dp)  
         {  
           int c = STRING_CHAR_AND_LENGTH (str + i_byte, len - i_byte, bytes);  
1835    
1836            chars = 1;        if (code != CHARSET_INVALID_CODE (charset))
           val = DISP_CHAR_VECTOR (dp, c);  
           if (VECTORP (val))  
             thiswidth = XVECTOR (val)->size;  
           else  
             thiswidth = ONE_BYTE_CHAR_WIDTH (str[i_byte]);  
         }  
       else  
1837          {          {
1838            chars = 1;            if (code_return)
1839            PARSE_MULTIBYTE_SEQ (str + i_byte, len_byte - i_byte, bytes);              *code_return = code;
1840            thiswidth = ONE_BYTE_CHAR_WIDTH (str[i_byte]);            return charset;
1841          }          }
1842          charset_list = XCDR (charset_list);
       if (precision > 0  
           && (width + thiswidth > precision))  
         {  
           *nchars = i;  
           *nbytes = i_byte;  
           return width;  
         }  
       i += chars;  
       i_byte += bytes;  
       width += thiswidth;  
   }  
   
   if (precision > 0)  
     {  
       *nchars = i;  
       *nbytes = i_byte;  
1843      }      }
1844      return NULL;
   return width;  
1845  }  }
1846    
 DEFUN ("string-width", Fstring_width, Sstring_width, 1, 1, 0,  
        doc: /* Return width of STRING when displayed in the current buffer.  
 Width is measured by how many columns it occupies on the screen.  
 When calculating width of a multibyte character in STRING,  
 only the base leading-code is considered; the validity of  
 the following bytes is not checked.  Tabs in STRING are always  
 taken to occupy `tab-width' columns.  */)  
      (str)  
      Lisp_Object str;  
 {  
   Lisp_Object val;  
   
   CHECK_STRING (str);  
   XSETFASTINT (val, lisp_string_width (str, -1, NULL, NULL));  
   return val;  
 }  
1847    
1848  DEFUN ("char-direction", Fchar_direction, Schar_direction, 1, 1, 0,  /* Fixme: `unknown' can't happen now?  */
1849         doc: /* Return the direction of CHAR.  DEFUN ("split-char", Fsplit_char, Ssplit_char, 1, 1, 0,
1850  The returned value is 0 for left-to-right and 1 for right-to-left.  */)         doc: /*Return list of charset and one to three position-codes of CHAR.
1851    If CHAR is invalid as a character code, return a list `(unknown CHAR)'.  */)
1852       (ch)       (ch)
1853       Lisp_Object ch;       Lisp_Object ch;
1854  {  {
1855    int charset;    struct charset *charset;
1856      int c, dimension;
1857    CHECK_NUMBER (ch);    unsigned code;
1858    charset = CHAR_CHARSET (XFASTINT (ch));    Lisp_Object val;
   if (!CHARSET_DEFINED_P (charset))  
     invalid_character (XINT (ch));  
   return CHARSET_TABLE_INFO (charset, CHARSET_DIRECTION_IDX);  
 }  
   
 DEFUN ("chars-in-region", Fchars_in_region, Schars_in_region, 2, 2, 0,  
        doc: /* Return number of characters between BEG and END.  */)  
      (beg, end)  
      Lisp_Object beg, end;  
 {  
   int from, to;  
   
   CHECK_NUMBER_COERCE_MARKER (beg);  
   CHECK_NUMBER_COERCE_MARKER (end);  
1859    
1860    from = min (XFASTINT (beg), XFASTINT (end));    CHECK_CHARACTER (ch);
1861    to = max (XFASTINT (beg), XFASTINT (end));    c = XFASTINT (ch);
1862      charset = CHAR_CHARSET (c);
1863      if (! charset)
1864        return Fcons (intern ("unknown"), Fcons (ch, Qnil));
1865    
1866    return make_number (to - from);    code = ENCODE_CHAR (charset, c);
1867      if (code == CHARSET_INVALID_CODE (charset))
1868        abort ();
1869      dimension = CHARSET_DIMENSION (charset);
1870      val = (dimension == 1 ? Fcons (make_number (code), Qnil)
1871             : dimension == 2 ? Fcons (make_number (code >> 8),
1872                                       Fcons (make_number (code & 0xFF), Qnil))
1873             : Fcons (make_number (code >> 16),
1874                      Fcons (make_number ((code >> 8) & 0xFF),
1875                             Fcons (make_number (code & 0xFF), Qnil))));
1876      return Fcons (CHARSET_NAME (charset), val);
1877  }  }
1878    
 /* Return the number of characters in the NBYTES bytes at PTR.  
    This works by looking at the contents and checking for multibyte sequences.  
    However, if the current buffer has enable-multibyte-characters = nil,  
    we treat each byte as a character.  */  
1879    
1880  int  DEFUN ("char-charset", Fchar_charset, Schar_charset, 1, 1, 0,
1881  chars_in_text (ptr, nbytes)         doc: /* Return the charset of highest priority that contains CHAR.  */)
1882       const unsigned char *ptr;       (ch)
1883       int nbytes;       Lisp_Object ch;
1884  {  {
1885    /* current_buffer is null at early stages of Emacs initialization.  */    struct charset *charset;
   if (current_buffer == 0  
       || NILP (current_buffer->enable_multibyte_characters))  
     return nbytes;  
1886    
1887    return multibyte_chars_in_text (ptr, nbytes);    CHECK_CHARACTER (ch);
1888      charset = CHAR_CHARSET (XINT (ch));
1889      return (CHARSET_NAME (charset));
1890  }  }
1891    
 /* Return the number of characters in the NBYTES bytes at PTR.  
    This works by looking at the contents and checking for multibyte sequences.  
    It ignores enable-multibyte-characters.  */  
1892    
1893  int  DEFUN ("charset-after", Fcharset_after, Scharset_after, 0, 1, 0,
1894  multibyte_chars_in_text (ptr, nbytes)         doc: /*
1895       const unsigned char *ptr;  Return charset of a character in the current buffer at position POS.
1896       int nbytes;  If POS is nil, it defauls to the current point.
1897    If POS is out of range, the value is nil.  */)
1898         (pos)
1899         Lisp_Object pos;
1900  {  {
1901    const unsigned char *endp;    Lisp_Object ch;
1902    int chars, bytes;    struct charset *charset;
1903    
1904    endp = ptr + nbytes;    ch = Fchar_after (pos);
1905    chars = 0;    if (! INTEGERP (ch))
1906        return ch;
1907      charset = CHAR_CHARSET (XINT (ch));
1908      return (CHARSET_NAME (charset));
1909    }
1910    
   while (ptr < endp)  
     {  
       PARSE_MULTIBYTE_SEQ (ptr, endp - ptr, bytes);  
       ptr += bytes;  
       chars++;  
     }  
1911    
1912    return chars;  DEFUN ("iso-charset", Fiso_charset, Siso_charset, 3, 3, 0,
1913  }         doc: /*
1914    Return charset of ISO's specification DIMENSION, CHARS, and FINAL-CHAR.
1915    
1916  /* Parse unibyte text at STR of LEN bytes as multibyte text, and  ISO 2022's designation sequence (escape sequence) distinguishes charsets
1917     count the numbers of characters and bytes in it.  On counting  by their DIMENSION, CHARS, and FINAL-CHAR,
1918     bytes, pay attention to the fact that 8-bit characters in the range  where as Emacs distinguishes them by charset symbol.
1919     0x80..0x9F are represented by 2 bytes in multibyte text.  */  See the documentation of the function `charset-info' for the meanings of
1920  void  DIMENSION, CHARS, and FINAL-CHAR.  */)
1921  parse_str_as_multibyte (str, len, nchars, nbytes)       (dimension, chars, final_char)
1922       const unsigned char *str;       Lisp_Object dimension, chars, final_char;
      int len, *nchars, *nbytes;  
1923  {  {
1924    const unsigned char *endp = str + len;    int id;
   int n, chars = 0, bytes = 0;  
1925    
1926    while (str < endp)    check_iso_charset_parameter (dimension, chars, final_char);
1927      {    id = ISO_CHARSET_TABLE (XFASTINT (dimension), XFASTINT (chars),
1928        if (UNIBYTE_STR_AS_MULTIBYTE_P (str, endp - str, n))                            XFASTINT (final_char));
1929          str += n, bytes += n;    return (id >= 0 ? CHARSET_NAME (CHARSET_FROM_ID (id)) : Qnil);
       else  
         str++, bytes += 2;  
       chars++;  
     }  
   *nchars = chars;  
   *nbytes = bytes;  
   return;  
1930  }  }
1931    
 /* Arrange unibyte text at STR of NBYTES bytes as multibyte text.  
    It actually converts only 8-bit characters in the range 0x80..0x9F  
    that don't contruct multibyte characters to multibyte forms.  If  
    NCHARS is nonzero, set *NCHARS to the number of characters in the  
    text.  It is assured that we can use LEN bytes at STR as a work  
    area and that is enough.  Return the number of bytes of the  
    resulting text.  */  
1932    
1933  int  DEFUN ("clear-charset-maps", Fclear_charset_maps, Sclear_charset_maps,
1934  str_as_multibyte (str, len, nbytes, nchars)         0, 0, 0,
1935       unsigned char *str;         doc: /*
1936       int len, nbytes, *nchars;  Clear encoder and decoder of charsets that are loaded from mapfiles.  */)
1937  {       ()
1938    unsigned char *p = str, *endp = str + nbytes;  {
1939    unsigned char *to;    int i;
1940    int chars = 0;    struct charset *charset;
1941    int n;    Lisp_Object attrs;
1942    
1943    while (p < endp && UNIBYTE_STR_AS_MULTIBYTE_P (p, endp - p, n))    for (i = 0; i < charset_table_used; i++)
     p += n, chars++;  
   if (nchars)  
     *nchars = chars;  
   if (p == endp)  
     return nbytes;  
   
   to = p;  
   nbytes = endp - p;  
   endp = str + len;  
   safe_bcopy (p, endp - nbytes, nbytes);  
   p = endp - nbytes;  
   while (p < endp)  
1944      {      {
1945        if (UNIBYTE_STR_AS_MULTIBYTE_P (p, endp - p, n))        charset = CHARSET_FROM_ID (i);
1946          {        attrs = CHARSET_ATTRIBUTES (charset);
1947            while (n--)  
1948              *to++ = *p++;        if (CHARSET_METHOD (charset) == CHARSET_METHOD_MAP)
         }  
       else  
1949          {          {
1950            *to++ = LEADING_CODE_8_BIT_CONTROL;            CHARSET_ATTR_DECODER (attrs) = Qnil;
1951            *to++ = *p++ + 0x20;            CHARSET_ATTR_ENCODER (attrs) = Qnil;
1952              CHARSET_METHOD (charset) = CHARSET_METHOD_MAP_DEFERRED;
1953          }          }
       chars++;  
     }  
   if (nchars)  
     *nchars = chars;  
   return (to - str);  
 }  
1954    
1955  /* Parse unibyte string at STR of LEN bytes, and return the number of        if (CHARSET_UNIFIED_P (charset))
1956     bytes it may ocupy when converted to multibyte string by          CHARSET_ATTR_DEUNIFIER (attrs) = Qnil;
1957     `str_to_multibyte'.  */      }
   
 int  
 parse_str_to_multibyte (str, len)  
      unsigned char *str;  
      int len;  
 {  
   unsigned char *endp = str + len;  
   int bytes;  
   
   for (bytes = 0; str < endp; str++)  
     bytes += (*str < 0x80 || *str >= 0xA0) ? 1 : 2;  
   return bytes;  
 }  
   
 /* Convert unibyte text at STR of NBYTES bytes to multibyte text  
    that contains the same single-byte characters.  It actually  
    converts all 8-bit characters to multibyte forms.  It is assured  
    that we can use LEN bytes at STR as a work area and that is  
    enough.  */  
1958    
1959  int    if (CHAR_TABLE_P (Vchar_unified_charset_table))
 str_to_multibyte (str, len, bytes)  
      unsigned char *str;  
      int len, bytes;  
 {  
   unsigned char *p = str, *endp = str + bytes;  
   unsigned char *to;  
   
   while (p < endp && (*p < 0x80 || *p >= 0xA0)) p++;  
   if (p == endp)  
     return bytes;  
   to = p;  
   bytes = endp - p;  
   endp = str + len;  
   safe_bcopy (p, endp - bytes, bytes);  
   p = endp - bytes;  
   while (p < endp)  
1960      {      {
1961        if (*p < 0x80 || *p >= 0xA0)        Foptimize_char_table (Vchar_unified_charset_table);
1962          *to++ = *p++;        Vchar_unify_table = Vchar_unified_charset_table;
1963        else        Vchar_unified_charset_table = Qnil;
         *to++ = LEADING_CODE_8_BIT_CONTROL, *to++ = *p++ + 0x20;  
1964      }      }
   return (to - str);  
 }  
1965    
1966  /* Arrange multibyte text at STR of LEN bytes as a unibyte text.  It    return Qnil;
1967     actually converts only 8-bit characters in the range 0x80..0x9F to  }
    unibyte forms.  */  
1968    
1969  int  DEFUN ("charset-priority-list", Fcharset_priority_list,
1970  str_as_unibyte (str, bytes)         Scharset_priority_list, 0, 1, 0,
1971       unsigned char *str;         doc: /* Return the list of charsets ordered by priority.
1972       int bytes;  HIGHESTP non-nil means just return the highest priority one.  */)
1973         (highestp)
1974         Lisp_Object highestp;
1975  {  {
1976    unsigned char *p = str, *endp = str + bytes;    Lisp_Object val = Qnil, list = Vcharset_ordered_list;
   unsigned char *to = str;  
1977    
1978    while (p < endp && *p != LEADING_CODE_8_BIT_CONTROL) p++;    if (!NILP (highestp))
1979    to = p;      return CHARSET_NAME (CHARSET_FROM_ID (XINT (Fcar (list))));
1980    while (p < endp)  
1981      while (!NILP (list))
1982      {      {
1983        if (*p == LEADING_CODE_8_BIT_CONTROL)        val = Fcons (CHARSET_NAME (CHARSET_FROM_ID (XINT (XCAR (list)))), val);
1984          *to++ = *(p + 1) - 0x20, p += 2;        list = XCDR (list);
       else  
         *to++ = *p++;  
1985      }      }
1986    return (to - str);    return Fnreverse (val);
1987  }  }
1988    
1989    DEFUN ("set-charset-priority", Fset_charset_priority, Sset_charset_priority,
1990  DEFUN ("string", Fstring, Sstring, 0, MANY, 0,         1, MANY, 0,
1991    doc: /* Concatenate all the argument characters and make the result a string.         doc: /* Assign higher priority to the charsets given as arguments.
1992  usage: (string &rest CHARACTERS)  */)  usage: (set-charset-priority &rest charsets)  */)
1993       (n, args)         (nargs, args)
1994       int n;       int nargs;
1995       Lisp_Object *args;       Lisp_Object *args;
1996  {  {
1997    int i;    Lisp_Object new_head, old_list, arglist[2];
1998    unsigned char *buf = (unsigned char *) alloca (MAX_MULTIBYTE_LENGTH * n);    int i, id;
   unsigned char *p = buf;  
   int c;  
   int multibyte = 0;  
1999    
2000    for (i = 0; i < n; i++)    old_list = Fcopy_sequence (Vcharset_ordered_list);
2001      new_head = Qnil;
2002      for (i = 0; i < nargs; i++)
2003      {      {
2004        CHECK_NUMBER (args[i]);        CHECK_CHARSET_GET_ID (args[i], id);
2005        if (!multibyte && !SINGLE_BYTE_CHAR_P (XFASTINT (args[i])))        if (! NILP (Fmemq (make_number (id), old_list)))
2006          multibyte = 1;          {
2007              old_list = Fdelq (make_number (id), old_list);
2008              new_head = Fcons (make_number (id), new_head);
2009            }
2010      }      }
2011      arglist[0] = Fnreverse (new_head);
2012      arglist[1] = old_list;
2013      Vcharset_ordered_list = Fnconc (2, arglist);
2014      charset_ordered_list_tick++;
2015    
2016    for (i = 0; i < n; i++)    for (old_list = Vcharset_ordered_list, new_head = Qnil;
2017           CONSP (old_list); old_list = XCDR (old_list))
2018      {      {
2019        c = XINT (args[i]);        if (! NILP (Fmemq (XCAR (old_list), Viso_2022_charset_list)))
2020        if (multibyte)          new_head = Fcons (XCAR (old_list), new_head);
         p += CHAR_STRING (c, p);  
       else  
         *p++ = c;  
2021      }      }
2022      Viso_2022_charset_list = Fnreverse (new_head);
2023    
2024    return make_string_from_bytes (buf, n, p - buf);    return Qnil;
2025  }  }
2026    
2027  #endif /* emacs */  DEFUN ("charset-id-internal", Fcharset_id_internal, Scharset_id_internal,
2028           0, 1, 0,
2029  int         doc: /* Internal use only.
2030  charset_id_internal (charset_name)  Return charset identification number of CHARSET.  */)
2031       char *charset_name;       (charset)
2032         Lisp_Object charset;
2033  {  {
2034    Lisp_Object val;    int id;
   
   val= Fget (intern (charset_name), Qcharset);  
   if (!VECTORP (val))  
     error ("Charset %s is not defined", charset_name);  
2035    
2036    return (XINT (XVECTOR (val)->contents[0]));    CHECK_CHARSET_GET_ID (charset, id);
2037      return make_number (id);
2038  }  }
2039    
2040  DEFUN ("setup-special-charsets", Fsetup_special_charsets,  
2041         Ssetup_special_charsets, 0, 0, 0, doc: /* Internal use only.  */)  void
2042       ()  init_charset ()
2043  {  {
2044    charset_latin_iso8859_1 = charset_id_internal ("latin-iso8859-1");  
   charset_jisx0208_1978 = charset_id_internal ("japanese-jisx0208-1978");  
   charset_jisx0208 = charset_id_internal ("japanese-jisx0208");  
   charset_katakana_jisx0201 = charset_id_internal ("katakana-jisx0201");  
   charset_latin_jisx0201 = charset_id_internal ("latin-jisx0201");  
   charset_big5_1 = charset_id_internal ("chinese-big5-1");  
   charset_big5_2 = charset_id_internal ("chinese-big5-2");  
   return Qnil;  
2045  }  }
2046    
2047    
2048  void  void
2049  init_charset_once ()  init_charset_once ()
2050  {  {
2051    int i, j, k;    int i, j, k;
2052    
2053    staticpro (&Vcharset_table);    for (i = 0; i < ISO_MAX_DIMENSION; i++)
2054    staticpro (&Vcharset_symbol_table);      for (j = 0; j < ISO_MAX_CHARS; j++)
2055    staticpro (&Vgeneric_character_list);        for (k = 0; k < ISO_MAX_FINAL; k++)
2056            iso_charset_table[i][j][k] = -1;
   /* This has to be done here, before we call Fmake_char_table.  */  
   Qcharset_table = intern ("charset-table");  
   staticpro (&Qcharset_table);  
   
   /* Intern this now in case it isn't already done.  
      Setting this variable twice is harmless.  
      But don't staticpro it here--that is done in alloc.c.  */  
   Qchar_table_extra_slots = intern ("char-table-extra-slots");  
   
   /* Now we are ready to set up this property, so we can  
      create the charset table.  */  
   Fput (Qcharset_table, Qchar_table_extra_slots, make_number (0));  
   Vcharset_table = Fmake_char_table (Qcharset_table, Qnil);  
   
   Qunknown = intern ("unknown");  
   staticpro (&Qunknown);  
   Vcharset_symbol_table = Fmake_vector (make_number (MAX_CHARSET + 1),  
                                         Qunknown);  
   
   /* Setup tables.  */  
   for (i = 0; i < 2; i++)  
     for (j = 0; j < 2; j++)  
       for (k = 0; k < 128; k++)  
         iso_charset_table [i][j][k] = -1;  
2057    
2058    for (i = 0; i < 256; i++)    for (i = 0; i < 256; i++)
2059      bytes_by_char_head[i] = 1;      emacs_mule_charset[i] = NULL;
2060    bytes_by_char_head[LEADING_CODE_PRIVATE_11] = 3;  
2061    bytes_by_char_head[LEADING_CODE_PRIVATE_12] = 3;    charset_jisx0201_roman = -1;
2062    bytes_by_char_head[LEADING_CODE_PRIVATE_21] = 4;    charset_jisx0208_1978 = -1;
2063    bytes_by_char_head[LEADING_CODE_PRIVATE_22] = 4;    charset_jisx0208 = -1;
2064    
2065    for (i = 0; i < 128; i++)    for (i = 0; i < 128; i++)
2066      width_by_char_head[i] = 1;      unibyte_to_multibyte_table[i] = i;
2067    for (; i < 256; i++)    for (; i < 256; i++)
2068      width_by_char_head[i] = 4;      unibyte_to_multibyte_table[i] = BYTE8_TO_CHAR (i);
   width_by_char_head[LEADING_CODE_PRIVATE_11] = 1;  
   width_by_char_head[LEADING_CODE_PRIVATE_12] = 2;  
   width_by_char_head[LEADING_CODE_PRIVATE_21] = 1;  
   width_by_char_head[LEADING_CODE_PRIVATE_22] = 2;  
   
   {  
     Lisp_Object val;  
   
     val = Qnil;  
     for (i = 0x81; i < 0x90; i++)  
       val = Fcons (make_number ((i - 0x70) << 7), val);  
     for (; i < 0x9A; i++)  
       val = Fcons (make_number ((i - 0x8F) << 14), val);  
     for (i = 0xA0; i < 0xF0; i++)  
       val = Fcons (make_number ((i - 0x70) << 7), val);  
     for (; i < 0xFF; i++)  
       val = Fcons (make_number ((i - 0xE0) << 14), val);  
     Vgeneric_character_list = Fnreverse (val);  
   }  
   
   nonascii_insert_offset = 0;  
   Vnonascii_translation_table = Qnil;  
2069  }  }
2070    
2071  #ifdef emacs  #ifdef emacs
# Line 1770  init_charset_once () Line 2073  init_charset_once ()
2073  void  void
2074  syms_of_charset ()  syms_of_charset ()
2075  {  {
2076    Qcharset = intern ("charset");    char *p;
2077    staticpro (&Qcharset);  
2078      DEFSYM (Qcharsetp, "charsetp");
2079    
2080      DEFSYM (Qascii, "ascii");
2081      DEFSYM (Qunicode, "unicode");
2082      DEFSYM (Qeight_bit, "eight-bit");
2083      DEFSYM (Qiso_8859_1, "iso-8859-1");
2084    
2085      DEFSYM (Qgl, "gl");
2086      DEFSYM (Qgr, "gr");
2087    
2088      p = (char *) xmalloc (30000);
2089    
2090    Qascii = intern ("ascii");    staticpro (&Vcharset_ordered_list);
2091    staticpro (&Qascii);    Vcharset_ordered_list = Qnil;
2092    
2093    Qeight_bit_control = intern ("eight-bit-control");    staticpro (&Viso_2022_charset_list);
2094    staticpro (&Qeight_bit_control);    Viso_2022_charset_list = Qnil;
2095    
2096    Qeight_bit_graphic = intern ("eight-bit-graphic");    staticpro (&Vemacs_mule_charset_list);
2097    staticpro (&Qeight_bit_graphic);    Vemacs_mule_charset_list = Qnil;
   
   /* Define special charsets ascii, eight-bit-control, and  
      eight-bit-graphic.  */  
   update_charset_table (make_number (CHARSET_ASCII),  
                         make_number (1), make_number (94),  
                         make_number (1),  
                         make_number (0),  
                         make_number ('B'),  
                         make_number (0),  
                         build_string ("ASCII"),  
                         Qnil,   /* same as above */  
                         build_string ("ASCII (ISO646 IRV)"));  
   CHARSET_SYMBOL (CHARSET_ASCII) = Qascii;  
   Fput (Qascii, Qcharset, CHARSET_TABLE_ENTRY (CHARSET_ASCII));  
   
   update_charset_table (make_number (CHARSET_8_BIT_CONTROL),  
                         make_number (1), make_number (96),  
                         make_number (4),  
                         make_number (0),  
                         make_number (-1),  
                         make_number (-1),  
                         build_string ("8-bit control code (0x80..0x9F)"),  
                         Qnil,   /* same as above */  
                         Qnil);  /* same as above */  
   CHARSET_SYMBOL (CHARSET_8_BIT_CONTROL) = Qeight_bit_control;  
   Fput (Qeight_bit_control, Qcharset,  
         CHARSET_TABLE_ENTRY (CHARSET_8_BIT_CONTROL));  
   
   update_charset_table (make_number (CHARSET_8_BIT_GRAPHIC),  
                         make_number (1), make_number (96),  
                         make_number (4),  
                         make_number (0),  
                         make_number (-1),  
                         make_number (-1),  
                         build_string ("8-bit graphic char (0xA0..0xFF)"),  
                         Qnil,   /* same as above */  
                         Qnil);  /* same as above */  
   CHARSET_SYMBOL (CHARSET_8_BIT_GRAPHIC) = Qeight_bit_graphic;  
   Fput (Qeight_bit_graphic, Qcharset,  
         CHARSET_TABLE_ENTRY (CHARSET_8_BIT_GRAPHIC));  
   
   Qauto_fill_chars = intern ("auto-fill-chars");  
   staticpro (&Qauto_fill_chars);  
   Fput (Qauto_fill_chars, Qchar_table_extra_slots, make_number (0));  
2098    
2099    defsubr (&Sdefine_charset);    staticpro (&Vcharset_hash_table);
2100    defsubr (&Sgeneric_character_list);    {
2101        Lisp_Object args[2];
2102        args[0] = QCtest;
2103        args[1] = Qeq;
2104        Vcharset_hash_table = Fmake_hash_table (2, args);
2105      }
2106    
2107      charset_table_size = 128;
2108      charset_table = ((struct charset *)
2109                       xmalloc (sizeof (struct charset) * charset_table_size));
2110      charset_table_used = 0;
2111    
2112      staticpro (&Vchar_unified_charset_table);
2113      Vchar_unified_charset_table = Fmake_char_table (Qnil, make_number (-1));
2114    
2115      defsubr (&Scharsetp);
2116      defsubr (&Smap_charset_chars);
2117      defsubr (&Sdefine_charset_internal);
2118      defsubr (&Sdefine_charset_alias);
2119      defsubr (&Sunibyte_charset);
2120      defsubr (&Sset_unibyte_charset);
2121      defsubr (&Scharset_plist);
2122      defsubr (&Sset_charset_plist);
2123      defsubr (&Sunify_charset);
2124    defsubr (&Sget_unused_iso_final_char);    defsubr (&Sget_unused_iso_final_char);
2125    defsubr (&Sdeclare_equiv_charset);    defsubr (&Sdeclare_equiv_charset);
2126    defsubr (&Sfind_charset_region);    defsubr (&Sfind_charset_region);
2127    defsubr (&Sfind_charset_string);    defsubr (&Sfind_charset_string);
2128    defsubr (&Smake_char_internal);    defsubr (&Sdecode_char);
2129      defsubr (&Sencode_char);
2130    defsubr (&Ssplit_char);    defsubr (&Ssplit_char);
2131      defsubr (&Smake_char);
2132    defsubr (&Schar_charset);    defsubr (&Schar_charset);
2133    defsubr (&Scharset_after);    defsubr (&Scharset_after);
2134    defsubr (&Siso_charset);    defsubr (&Siso_charset);
2135    defsubr (&Schar_valid_p);    defsubr (&Sclear_charset_maps);
2136    defsubr (&Sunibyte_char_to_multibyte);    defsubr (&Scharset_priority_list);
2137    defsubr (&Smultibyte_char_to_unibyte);    defsubr (&Sset_charset_priority);
2138    defsubr (&Schar_bytes);    defsubr (&Scharset_id_internal);
2139    defsubr (&Schar_width);  
2140    defsubr (&Sstring_width);    DEFVAR_LISP ("charset-map-directory", &Vcharset_map_directory,
2141    defsubr (&Schar_direction);                 doc: /* Directory of charset map files that come with GNU Emacs.
2142    defsubr (&Schars_in_region);  The default value is sub-directory "charsets" of `data-directory'.  */);
2143    defsubr (&Sstring);    Vcharset_map_directory = Fexpand_file_name (build_string ("charsets"),
2144    defsubr (&Ssetup_special_charsets);                                                Vdata_directory);
2145    
2146    DEFVAR_LISP ("charset-list", &Vcharset_list,    DEFVAR_LISP ("charset-list", &Vcharset_list,
2147                 doc: /* List of charsets ever defined.  */);                 doc: /* List of all charsets ever defined.  */);
2148    Vcharset_list = Fcons (Qascii, Fcons (Qeight_bit_control,    Vcharset_list = Qnil;
2149                                          Fcons (Qeight_bit_graphic, Qnil)));  
2150      charset_ascii
2151    DEFVAR_LISP ("translation-table-vector",  &Vtranslation_table_vector,      = define_charset_internal (Qascii, 1, "\x00\x7F\x00\x00\x00\x00",
2152                 doc: /* Vector of cons cell of a symbol and translation table ever defined.                                 0, 127, 'B', -1, 0, 1, 0, 0);
2153  An ID of a translation table is an index of this vector.  */);    charset_iso_8859_1
2154    Vtranslation_table_vector = Fmake_vector (make_number (16), Qnil);      = define_charset_internal (Qiso_8859_1, 1, "\x00\xFF\x00\x00\x00\x00",
2155                                   0, 255, -1, -1, -1, 1, 0, 0);
2156    DEFVAR_INT ("leading-code-private-11", &leading_code_private_11,    charset_unicode
2157                doc: /* Leading-code of private TYPE9N charset of column-width 1.  */);      = define_charset_internal (Qunicode, 3, "\x00\xFF\x00\xFF\x00\x10",
2158    leading_code_private_11 = LEADING_CODE_PRIVATE_11;                                 0, MAX_UNICODE_CHAR, -1, 0, -1, 1, 0, 0);
2159      charset_eight_bit
2160    DEFVAR_INT ("leading-code-private-12", &leading_code_private_12,      = define_charset_internal (Qeight_bit, 1, "\x80\xFF\x00\x00\x00\x00",
2161                doc: /* Leading-code of private TYPE9N charset of column-width 2.  */);                                 128, 255, -1, 0, -1, 0, 0,
2162    leading_code_private_12 = LEADING_CODE_PRIVATE_12;                                 MAX_5_BYTE_CHAR + 1);
   
   DEFVAR_INT ("leading-code-private-21", &leading_code_private_21,  
               doc: /* Leading-code of private TYPE9Nx9N charset of column-width 1.  */);  
   leading_code_private_21 = LEADING_CODE_PRIVATE_21;  
   
   DEFVAR_INT ("leading-code-private-22", &leading_code_private_22,  
               doc: /* Leading-code of private TYPE9Nx9N charset of column-width 2.  */);  
   leading_code_private_22 = LEADING_CODE_PRIVATE_22;  
   
   DEFVAR_INT ("nonascii-insert-offset", &nonascii_insert_offset,  
               doc: /* Offset for converting non-ASCII unibyte codes 0240...0377 to multibyte.  
 This is used for converting unibyte text to multibyte,  
 and for inserting character codes specified by number.  
   
 This serves to convert a Latin-1 or similar 8-bit character code  
 to the corresponding Emacs multibyte character code.  
 Typically the value should be (- (make-char CHARSET 0) 128),  
 for your choice of character set.  
 If `nonascii-translation-table' is non-nil, it overrides this variable.  */);  
   nonascii_insert_offset = 0;  
   
   DEFVAR_LISP ("nonascii-translation-table", &Vnonascii_translation_table,  
                doc: /* Translation table to convert non-ASCII unibyte codes to multibyte.  
 This is used for converting unibyte text to multibyte,  
 and for inserting character codes specified by number.  
   
 Conversion is performed only when multibyte characters are enabled,  
 and it serves to convert a Latin-1 or similar 8-bit character code  
 to the corresponding Emacs character code.  
   
 If this is nil, `nonascii-insert-offset' is used instead.  
 See also the docstring of `make-translation-table'.  */);  
   Vnonascii_translation_table = Qnil;  
   
   DEFVAR_LISP ("auto-fill-chars", &Vauto_fill_chars,  
                doc: /* A char-table for characters which invoke auto-filling.  
 Such characters have value t in this table.  */);  
   Vauto_fill_chars = Fmake_char_table (Qauto_fill_chars, Qnil);  
   CHAR_TABLE_SET (Vauto_fill_chars, make_number (' '), Qt);  
   CHAR_TABLE_SET (Vauto_fill_chars, make_number ('\n'), Qt);  
2163  }  }
2164    
2165  #endif /* emacs */  #endif /* emacs */

Legend:
Removed from v.1.134  
changed lines
  Added in v.1.134.6.1

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26