+ int older = OLDER_RECORD_P (table);
+ Lisp_Object cpt2 = make_byte_table (ret, older);
+ Lisp_Object cpt3 = make_byte_table (ret, older);
+ Lisp_Object cpt4 = make_byte_table (ret, older);
+
+ XBYTE_TABLE(cpt4)->property[(unsigned char)code] = value;
+ XBYTE_TABLE(cpt3)->property[(unsigned char)(code >> 8)] = cpt4;
+ XBYTE_TABLE(cpt2)->property[(unsigned char)(code >> 16)] = cpt3;
+ cpt1->property[(unsigned char)(code >> 24)] = cpt2;
+ }
+}
+
+
+Lisp_Object Vcharacter_attribute_table;
+Lisp_Object Vcharacter_name_table;
+Lisp_Object Vcharacter_ideographic_radical_table;
+Lisp_Object Vcharacter_ideographic_strokes_table;
+Lisp_Object Vcharacter_total_strokes_table;
+Lisp_Object Vcharacter_decomposition_table;
+Lisp_Object Vcharacter_composition_table;
+Lisp_Object Vcharacter_variant_table;
+
+Lisp_Object Qname;
+Lisp_Object Qideographic_radical, Qideographic_strokes;
+Lisp_Object Qtotal_strokes;
+Lisp_Object Q_decomposition;
+Lisp_Object Qucs;
+Lisp_Object Q_ucs;
+Lisp_Object Qcompat;
+Lisp_Object Qisolated;
+Lisp_Object Qinitial;
+Lisp_Object Qmedial;
+Lisp_Object Qfinal;
+Lisp_Object Qvertical;
+Lisp_Object QnoBreak;
+Lisp_Object Qfraction;
+Lisp_Object Qsuper;
+Lisp_Object Qsub;
+Lisp_Object Qcircle;
+Lisp_Object Qsquare;
+Lisp_Object Qwide;
+Lisp_Object Qnarrow;
+Lisp_Object Qsmall;
+Lisp_Object Qfont;
+
+Emchar to_char_id (Lisp_Object v, char* err_msg, Lisp_Object err_arg);
+
+Lisp_Object put_char_ccs_code_point (Lisp_Object character,
+ Lisp_Object ccs, Lisp_Object value);
+Lisp_Object remove_char_ccs (Lisp_Object character, Lisp_Object ccs);
+
+Lisp_Object put_char_attribute (Lisp_Object character,
+ Lisp_Object attribute, Lisp_Object value);
+Lisp_Object remove_char_attribute (Lisp_Object character,
+ Lisp_Object attribute);
+
+
+Emchar
+to_char_id (Lisp_Object v, char* err_msg, Lisp_Object err_arg)
+{
+ if (INTP (v))
+ return XINT (v);
+ if (CHARP (v))
+ return XCHAR (v);
+ else if (EQ (v, Qcompat))
+ return -1;
+ else if (EQ (v, Qisolated))
+ return -2;
+ else if (EQ (v, Qinitial))
+ return -3;
+ else if (EQ (v, Qmedial))
+ return -4;
+ else if (EQ (v, Qfinal))
+ return -5;
+ else if (EQ (v, Qvertical))
+ return -6;
+ else if (EQ (v, QnoBreak))
+ return -7;
+ else if (EQ (v, Qfraction))
+ return -8;
+ else if (EQ (v, Qsuper))
+ return -9;
+ else if (EQ (v, Qsub))
+ return -10;
+ else if (EQ (v, Qcircle))
+ return -11;
+ else if (EQ (v, Qsquare))
+ return -12;
+ else if (EQ (v, Qwide))
+ return -13;
+ else if (EQ (v, Qnarrow))
+ return -14;
+ else if (EQ (v, Qsmall))
+ return -15;
+ else if (EQ (v, Qfont))
+ return -16;
+ else
+ signal_simple_error (err_msg, err_arg);
+}
+
+DEFUN ("get-composite-char", Fget_composite_char, 1, 1, 0, /*
+Return character corresponding with list.
+*/
+ (list))
+{
+ Lisp_Object table = Vcharacter_composition_table;
+ Lisp_Object rest = list;
+
+ while (CONSP (rest))
+ {
+ Lisp_Object v = Fcar (rest);
+ Lisp_Object ret;
+ Emchar c = to_char_id (v, "Invalid value for composition", list);
+
+ ret = get_char_id_table (c, table);
+
+ rest = Fcdr (rest);
+ if (NILP (rest))
+ {
+ if (!CHAR_ID_TABLE_P (ret))
+ return ret;
+ else
+ return Qt;
+ }
+ else if (!CONSP (rest))
+ break;
+ else if (CHAR_ID_TABLE_P (ret))
+ table = ret;
+ else
+ signal_simple_error ("Invalid table is found with", list);
+ }
+ signal_simple_error ("Invalid value for composition", list);
+}
+
+DEFUN ("char-variants", Fchar_variants, 1, 1, 0, /*
+Return variants of CHARACTER.
+*/
+ (character))
+{
+ CHECK_CHAR (character);
+ return Fcopy_list (get_char_id_table (XCHAR (character),
+ Vcharacter_variant_table));
+}
+
+DEFUN ("char-attribute-alist", Fchar_attribute_alist, 1, 1, 0, /*
+Return the alist of attributes of CHARACTER.
+*/
+ (character))
+{
+ Lisp_Object alist, ret;
+
+ CHECK_CHAR (character);
+ alist = Fcopy_alist (get_char_id_table (XCHAR (character),
+ Vcharacter_attribute_table));
+
+ ret = get_char_id_table (XCHAR (character), Vcharacter_name_table);
+ if (!NILP (ret))
+ alist = Fcons (Fcons (Qname, ret), alist);
+
+ ret = get_char_id_table (XCHAR (character),
+ Vcharacter_ideographic_radical_table);
+ if (!NILP (ret))
+ alist = Fcons (Fcons (Qideographic_radical, ret), alist);
+
+ ret = get_char_id_table (XCHAR (character),
+ Vcharacter_ideographic_strokes_table);
+ if (!NILP (ret))
+ alist = Fcons (Fcons (Qideographic_strokes, ret), alist);
+
+ ret = get_char_id_table (XCHAR (character), Vcharacter_total_strokes_table);
+ if (!NILP (ret))
+ alist = Fcons (Fcons (Qtotal_strokes, ret), alist);
+
+ ret = get_char_id_table (XCHAR (character),
+ Vcharacter_decomposition_table);
+ if (!NILP (ret))
+ alist = Fcons (Fcons (Q_decomposition, ret), alist);
+
+ return alist;
+}
+
+DEFUN ("get-char-attribute", Fget_char_attribute, 2, 2, 0, /*
+Return the value of CHARACTER's ATTRIBUTE.
+*/
+ (character, attribute))
+{
+ Lisp_Object ccs;
+
+ CHECK_CHAR (character);
+ if (!NILP (ccs = Ffind_charset (attribute)))
+ {
+ Lisp_Object encoding_table = XCHARSET_ENCODING_TABLE (ccs);
+
+ if (CHAR_ID_TABLE_P (encoding_table))
+ return get_char_id_table (XCHAR (character), encoding_table);
+ else
+ return Qnil;
+ }
+ else if (EQ (attribute, Qname))
+ {
+ return get_char_id_table (XCHAR (character), Vcharacter_name_table);
+ }
+ else if (EQ (attribute, Qideographic_radical))
+ {
+ return get_char_id_table (XCHAR (character),
+ Vcharacter_ideographic_radical_table);
+ }
+ else if (EQ (attribute, Qideographic_strokes))
+ {
+ return get_char_id_table (XCHAR (character),
+ Vcharacter_ideographic_strokes_table);
+ }
+ else if (EQ (attribute, Qtotal_strokes))
+ {
+ return get_char_id_table (XCHAR (character),
+ Vcharacter_total_strokes_table);
+ }
+ else if (EQ (attribute, Q_decomposition))
+ {
+ return get_char_id_table (XCHAR (character),
+ Vcharacter_decomposition_table);
+ }
+ else
+ {
+ Lisp_Object ret
+ = get_char_id_table (XCHAR (character), Vcharacter_attribute_table);
+
+ if (EQ (ret, Qnil))
+ return Qnil;
+ else
+ return Fcdr (Fassq (attribute, ret));
+ }
+}
+
+DEFUN ("put-char-attribute", Fput_char_attribute, 3, 3, 0, /*
+Store CHARACTER's ATTRIBUTE with VALUE.
+*/
+ (character, attribute, value))
+{
+ Lisp_Object ccs;
+
+ CHECK_CHAR (character);
+ ccs = Ffind_charset (attribute);
+ if (!NILP (ccs))
+ {
+ return put_char_ccs_code_point (character, ccs, value);
+ }
+ else if (EQ (attribute, Qname))
+ {
+ CHECK_STRING (value);
+ put_char_id_table (XCHAR (character), value, Vcharacter_name_table);
+ return value;
+ }
+ else if (EQ (attribute, Qideographic_radical))
+ {
+ CHECK_INT (value);
+ put_char_id_table (XCHAR (character), value,
+ Vcharacter_ideographic_radical_table);
+ return value;
+ }
+ else if (EQ (attribute, Qideographic_strokes))
+ {
+ CHECK_INT (value);
+ put_char_id_table (XCHAR (character), value,
+ Vcharacter_ideographic_strokes_table);
+ return value;
+ }
+ else if (EQ (attribute, Qtotal_strokes))
+ {
+ CHECK_INT (value);
+ put_char_id_table (XCHAR (character), value,
+ Vcharacter_total_strokes_table);
+ return value;
+ }
+ else if (EQ (attribute, Q_decomposition))
+ {
+ Lisp_Object seq;
+
+ if (!CONSP (value))
+ signal_simple_error ("Invalid value for ->decomposition",
+ value);
+
+ if (CONSP (Fcdr (value)))
+ {
+ Lisp_Object rest = value;
+ Lisp_Object table = Vcharacter_composition_table;
+ size_t len;
+ int i = 0;
+
+ GET_EXTERNAL_LIST_LENGTH (rest, len);
+ seq = make_older_vector (len, Qnil);
+
+ while (CONSP (rest))
+ {
+ Lisp_Object v = Fcar (rest);
+ Lisp_Object ntable;
+ Emchar c
+ = to_char_id (v, "Invalid value for ->decomposition", value);
+
+ if (c < 0)
+ XVECTOR_DATA(seq)[i++] = v;
+ else
+ XVECTOR_DATA(seq)[i++] = make_char (c);
+ rest = Fcdr (rest);
+ if (!CONSP (rest))
+ {
+ put_char_id_table (c, character, table);
+ break;
+ }
+ else
+ {
+ ntable = get_char_id_table (c, table);
+ if (!CHAR_ID_TABLE_P (ntable))
+ {
+ ntable
+ = make_char_id_table (Qnil, OLDER_RECORD_P (table));
+ put_char_id_table (c, ntable, table);
+ }
+ table = ntable;
+ }
+ }
+ }
+ else
+ {
+ Lisp_Object v = Fcar (value);
+
+ if (INTP (v))
+ {
+ Emchar c = XINT (v);
+ Lisp_Object ret
+ = get_char_id_table (c, Vcharacter_variant_table);
+
+ if (NILP (Fmemq (v, ret)))
+ {
+ put_char_id_table (c, Fcons (character, ret),
+ Vcharacter_variant_table);
+ }
+ }
+ seq = make_older_vector (1, v);
+ }
+ put_char_id_table (XCHAR (character), seq,
+ Vcharacter_decomposition_table);
+ return value;
+ }
+ else if (EQ (attribute, Q_ucs))
+ {
+ Lisp_Object ret;
+ Emchar c;
+
+ if (!INTP (value))
+ signal_simple_error ("Invalid value for ->ucs", value);
+
+ c = XINT (value);
+
+ ret = get_char_id_table (c, Vcharacter_variant_table);
+ if (NILP (Fmemq (character, ret)))
+ {
+ put_char_id_table (c, Fcons (character, ret),
+ Vcharacter_variant_table);
+ }
+ }
+ return put_char_attribute (character, attribute, value);
+}
+
+DEFUN ("remove-char-attribute", Fremove_char_attribute, 2, 2, 0, /*
+Remove CHARACTER's ATTRIBUTE.
+*/
+ (character, attribute))
+{
+ Lisp_Object ccs;
+
+ CHECK_CHAR (character);
+ ccs = Ffind_charset (attribute);
+ if (!NILP (ccs))
+ {
+ return remove_char_ccs (character, ccs);
+ }
+ return remove_char_attribute (character, attribute);
+}
+
+INLINE_HEADER int CHARSET_BYTE_SIZE (Lisp_Charset* cs);
+INLINE_HEADER int
+CHARSET_BYTE_SIZE (Lisp_Charset* cs)
+{
+ /* ad-hoc method for `ascii' */
+ if ((CHARSET_CHARS (cs) == 94) &&
+ (CHARSET_BYTE_OFFSET (cs) != 33))
+ return 128 - CHARSET_BYTE_OFFSET (cs);
+ else
+ return CHARSET_CHARS (cs);
+}
+
+#define XCHARSET_BYTE_SIZE(ccs) CHARSET_BYTE_SIZE (XCHARSET (ccs))
+
+int decoding_table_check_elements (Lisp_Object v, int dim, int ccs_len);
+int
+decoding_table_check_elements (Lisp_Object v, int dim, int ccs_len)
+{
+ int i;
+
+ if (XVECTOR_LENGTH (v) > ccs_len)
+ return -1;
+
+ for (i = 0; i < XVECTOR_LENGTH (v); i++)
+ {
+ Lisp_Object c = XVECTOR_DATA(v)[i];
+
+ if (!NILP (c) && !CHARP (c))
+ {
+ if (VECTORP (c))
+ {
+ int ret = decoding_table_check_elements (c, dim - 1, ccs_len);
+ if (ret)
+ return ret;
+ }
+ else
+ return -2;
+ }
+ }
+ return 0;
+}
+
+INLINE_HEADER void
+decoding_table_remove_char (Lisp_Object v, int dim, int byte_offset,
+ int code_point);
+INLINE_HEADER void
+decoding_table_remove_char (Lisp_Object v, int dim, int byte_offset,
+ int code_point)
+{
+ int i = -1;
+
+ while (dim > 0)
+ {
+ Lisp_Object nv;
+
+ dim--;
+ i = ((code_point >> (8 * dim)) & 255) - byte_offset;
+ nv = XVECTOR_DATA(v)[i];
+ if (!VECTORP (nv))
+ break;
+ v = nv;
+ }
+ if (i >= 0)
+ XVECTOR_DATA(v)[i] = Qnil;
+}
+
+INLINE_HEADER void
+decoding_table_put_char (Lisp_Object v, int dim, int byte_offset,
+ int code_point, Lisp_Object character);
+INLINE_HEADER void
+decoding_table_put_char (Lisp_Object v, int dim, int byte_offset,
+ int code_point, Lisp_Object character)
+{
+ int i = -1;
+ Lisp_Object nv;
+ int ccs_len = XVECTOR_LENGTH (v);
+
+ while (dim > 0)
+ {
+ dim--;
+ i = ((code_point >> (8 * dim)) & 255) - byte_offset;
+ nv = XVECTOR_DATA(v)[i];
+ if (dim > 0)
+ {
+ if (!VECTORP (nv))
+ nv = (XVECTOR_DATA(v)[i] = make_older_vector (ccs_len, Qnil));
+ v = nv;
+ }
+ else
+ break;
+ }
+ XVECTOR_DATA(v)[i] = character;
+}
+
+Lisp_Object
+put_char_ccs_code_point (Lisp_Object character,
+ Lisp_Object ccs, Lisp_Object value)
+{
+ Lisp_Object encoding_table;
+
+ if (!EQ (XCHARSET_NAME (ccs), Qucs)
+ || (XCHAR (character) != XINT (value)))
+ {
+ Lisp_Object v = XCHARSET_DECODING_TABLE (ccs);
+ int dim = XCHARSET_DIMENSION (ccs);
+ int ccs_len = XCHARSET_BYTE_SIZE (ccs);
+ int byte_offset = XCHARSET_BYTE_OFFSET (ccs);
+ int code_point;
+
+ if (CONSP (value))
+ { /* obsolete representation: value must be a list of bytes */
+ Lisp_Object ret = Fcar (value);
+ Lisp_Object rest;
+
+ if (!INTP (ret))
+ signal_simple_error ("Invalid value for coded-charset", value);
+ code_point = XINT (ret);
+ if (XCHARSET_GRAPHIC (ccs) == 1)
+ code_point &= 0x7F;
+ rest = Fcdr (value);
+ while (!NILP (rest))
+ {
+ int j;
+
+ if (!CONSP (rest))
+ signal_simple_error ("Invalid value for coded-charset",
+ value);
+ ret = Fcar (rest);
+ if (!INTP (ret))
+ signal_simple_error ("Invalid value for coded-charset",
+ value);
+ j = XINT (ret);
+ if (XCHARSET_GRAPHIC (ccs) == 1)
+ j &= 0x7F;
+ code_point = (code_point << 8) | j;
+ rest = Fcdr (rest);
+ }
+ value = make_int (code_point);
+ }
+ else if (INTP (value))
+ {
+ code_point = XINT (value);
+ if (XCHARSET_GRAPHIC (ccs) == 1)
+ {
+ code_point &= 0x7F7F7F7F;
+ value = make_int (code_point);
+ }
+ }
+ else
+ signal_simple_error ("Invalid value for coded-charset", value);
+
+ if (VECTORP (v))
+ {
+ Lisp_Object cpos = Fget_char_attribute (character, ccs);
+ if (!NILP (cpos))
+ {
+ decoding_table_remove_char (v, dim, byte_offset, XINT (cpos));
+ }
+ }
+ else
+ {
+ XCHARSET_DECODING_TABLE (ccs)
+ = v = make_older_vector (ccs_len, Qnil);
+ }
+
+ decoding_table_put_char (v, dim, byte_offset, code_point, character);
+ }
+ if (NILP (encoding_table = XCHARSET_ENCODING_TABLE (ccs)))
+ {
+ XCHARSET_ENCODING_TABLE (ccs)
+ = encoding_table = make_char_id_table (Qnil, -1);
+ }
+ put_char_id_table (XCHAR (character), value, encoding_table);
+ return Qt;
+}
+
+Lisp_Object
+remove_char_ccs (Lisp_Object character, Lisp_Object ccs)
+{
+ Lisp_Object decoding_table = XCHARSET_DECODING_TABLE (ccs);
+ Lisp_Object encoding_table = XCHARSET_ENCODING_TABLE (ccs);
+
+ if (VECTORP (decoding_table))
+ {
+ Lisp_Object cpos = Fget_char_attribute (character, ccs);
+
+ if (!NILP (cpos))
+ {
+ decoding_table_remove_char (decoding_table,
+ XCHARSET_DIMENSION (ccs),
+ XCHARSET_BYTE_OFFSET (ccs),
+ XINT (cpos));
+ }
+ }
+ if (CHAR_ID_TABLE_P (encoding_table))
+ {
+ put_char_id_table (XCHAR (character), Qnil, encoding_table);
+ }
+ return Qt;
+}
+
+Lisp_Object
+put_char_attribute (Lisp_Object character, Lisp_Object attribute,
+ Lisp_Object value)
+{
+ Emchar char_id = XCHAR (character);
+ Lisp_Object ret = get_char_id_table (char_id, Vcharacter_attribute_table);
+ Lisp_Object cell;
+
+ cell = Fassq (attribute, ret);
+
+ if (NILP (cell))
+ {
+ ret = Fcons (Fcons (attribute, value), ret);