summaryrefslogtreecommitdiff
path: root/src/xlibi18n/lcCT.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xlibi18n/lcCT.c')
-rw-r--r--src/xlibi18n/lcCT.c1581
1 files changed, 983 insertions, 598 deletions
diff --git a/src/xlibi18n/lcCT.c b/src/xlibi18n/lcCT.c
index 5dd2ddcc..fcaca229 100644
--- a/src/xlibi18n/lcCT.c
+++ b/src/xlibi18n/lcCT.c
@@ -31,70 +31,107 @@
* Modifier: Takanori Tateno FUJITSU LIMITED
*
*/
+/*
+ * 2000
+ * Modifier: Ivan Pascal The XFree86 Project
+ * Modifier: Bruno Haible The XFree86 Project
+ */
+/* $XFree86: xc/lib/X11/lcCT.c,v 3.27 2002/10/08 23:31:35 dawes Exp $ */
#include "Xlibint.h"
#include "XlcPubI.h"
#include <X11/Xos.h>
#include <stdio.h>
-typedef struct _StateRec {
- XlcCharSet charset;
- XlcCharSet GL_charset;
- XlcCharSet GR_charset;
- XlcCharSet ext_seg_charset;
- int ext_seg_left;
-} StateRec, *State;
+/* ====================== Built-in Character Sets ====================== */
+
+/*
+ * Static representation of a character set that can be used in Compound Text.
+ */
typedef struct _CTDataRec {
- char *name;
- char *encoding; /* Compound Text encoding */
+ const char *name;
+ const char *ct_sequence; /* Compound Text encoding, ESC sequence */
} CTDataRec, *CTData;
-typedef struct _CTInfoRec {
- XlcCharSet charset;
- int encoding_len;
- char *encoding; /* Compound Text encoding */
- int ext_segment_len;
- char *ext_segment; /* extended segment */
- struct _CTInfoRec *next;
-} CTInfoRec, *CTInfo;
-
static CTDataRec default_ct_data[] =
{
- { "ISO8859-1:GL", "\033(B" },
- { "ISO8859-1:GR", "\033-A" },
- { "ISO8859-2:GR", "\033-B" },
- { "ISO8859-3:GR", "\033-C" },
- { "ISO8859-4:GR", "\033-D" },
- { "ISO8859-7:GR", "\033-F" },
- { "ISO8859-6:GR", "\033-G" },
- { "ISO8859-8:GR", "\033-H" },
- { "ISO8859-5:GR", "\033-L" },
- { "ISO8859-9:GR", "\033-M" },
- { "ISO8859-10:GR", "\033-V" },
- { "JISX0201.1976-0:GL", "\033(J" },
- { "JISX0201.1976-0:GR", "\033)I" },
-
- { "GB2312.1980-0:GL", "\033$(A" },
- { "GB2312.1980-0:GR", "\033$)A" },
- { "JISX0208.1983-0:GL", "\033$(B" },
- { "JISX0208.1983-0:GR", "\033$)B" },
- { "KSC5601.1987-0:GL", "\033$(C" },
- { "KSC5601.1987-0:GR", "\033$)C" },
-#ifdef notdef
- { "JISX0212.1990-0:GL", "\033$(D" },
- { "JISX0212.1990-0:GR", "\033$)D" },
- { "CNS11643.1986-1:GL", "\033$(G" },
- { "CNS11643.1986-1:GR", "\033$)G" },
- { "CNS11643.1986-2:GL", "\033$(H" },
- { "CNS11643.1986-2:GR", "\033$)H" },
+ /* */
+ /* X11 registry name MIME name ISO-IR ESC sequence */
+ /* */
+
+ /* Registered character sets with one byte per character */
+ { "ISO8859-1:GL", /* US-ASCII 6 */ "\033(B" },
+ { "ISO8859-1:GR", /* ISO-8859-1 100 */ "\033-A" },
+ { "ISO8859-2:GR", /* ISO-8859-2 101 */ "\033-B" },
+ { "ISO8859-3:GR", /* ISO-8859-3 109 */ "\033-C" },
+ { "ISO8859-4:GR", /* ISO-8859-4 110 */ "\033-D" },
+ { "ISO8859-5:GR", /* ISO-8859-5 144 */ "\033-L" },
+ { "ISO8859-6:GR", /* ISO-8859-6 127 */ "\033-G" },
+ { "ISO8859-7:GR", /* ISO-8859-7 126 */ "\033-F" },
+ { "ISO8859-8:GR", /* ISO-8859-8 138 */ "\033-H" },
+ { "ISO8859-9:GR", /* ISO-8859-9 148 */ "\033-M" },
+ { "ISO8859-10:GR", /* ISO-8859-10 157 */ "\033-V" },
+ { "ISO8859-11:GR", /* ISO-8859-11 166 */ "\033-T" },
+ { "ISO8859-13:GR", /* ISO-8859-13 179 */ "\033-Y" },
+ { "ISO8859-14:GR", /* ISO-8859-14 199 */ "\033-_" },
+ { "ISO8859-15:GR", /* ISO-8859-15 203 */ "\033-b" },
+ { "ISO8859-16:GR", /* ISO-8859-16 226 */ "\033-f" },
+ { "JISX0201.1976-0:GL", /* ISO-646-JP 14 */ "\033(J" },
+ { "JISX0201.1976-0:GR", "\033)I" },
+#if 0
+ { "TIS620-0:GR", /* TIS-620 166 */ "\033-T" },
#endif
- { "TIS620.2533-1:GR", "\033-T"},
- { "ISO10646-1", "\033%B"},
- /* Non-Standard Character Set Encodings */
- { "KOI8-R:GR", "\033%/1\200\210koi8-r\002"},
- { "FCD8859-15:GR", "\033%/1\200\213fcd8859-15\002"},
-} ;
+
+ /* Registered character sets with two byte per character */
+ { "GB2312.1980-0:GL", /* GB_2312-80 58 */ "\033$(A" },
+ { "GB2312.1980-0:GR", /* GB_2312-80 58 */ "\033$)A" },
+ { "JISX0208.1983-0:GL", /* JIS_X0208-1983 87 */ "\033$(B" },
+ { "JISX0208.1983-0:GR", /* JIS_X0208-1983 87 */ "\033$)B" },
+ { "JISX0208.1990-0:GL", /* JIS_X0208-1990 168 */ "\033$(B" },
+ { "JISX0208.1990-0:GR", /* JIS_X0208-1990 168 */ "\033$)B" },
+ { "JISX0212.1990-0:GL", /* JIS_X0212-1990 159 */ "\033$(D" },
+ { "JISX0212.1990-0:GR", /* JIS_X0212-1990 159 */ "\033$)D" },
+ { "KSC5601.1987-0:GL", /* KS_C_5601-1987 149 */ "\033$(C" },
+ { "KSC5601.1987-0:GR", /* KS_C_5601-1987 149 */ "\033$)C" },
+ { "CNS11643.1986-1:GL", /* CNS 11643-1992 pl.1 171 */ "\033$(G" },
+ { "CNS11643.1986-1:GR", /* CNS 11643-1992 pl.1 171 */ "\033$)G" },
+ { "CNS11643.1986-2:GL", /* CNS 11643-1992 pl.2 172 */ "\033$(H" },
+ { "CNS11643.1986-2:GR", /* CNS 11643-1992 pl.2 172 */ "\033$)H" },
+ { "CNS11643.1992-3:GL", /* CNS 11643-1992 pl.3 183 */ "\033$(I" },
+ { "CNS11643.1992-3:GR", /* CNS 11643-1992 pl.3 183 */ "\033$)I" },
+ { "CNS11643.1992-4:GL", /* CNS 11643-1992 pl.4 184 */ "\033$(J" },
+ { "CNS11643.1992-4:GR", /* CNS 11643-1992 pl.4 184 */ "\033$)J" },
+ { "CNS11643.1992-5:GL", /* CNS 11643-1992 pl.5 185 */ "\033$(K" },
+ { "CNS11643.1992-5:GR", /* CNS 11643-1992 pl.5 185 */ "\033$)K" },
+ { "CNS11643.1992-6:GL", /* CNS 11643-1992 pl.6 186 */ "\033$(L" },
+ { "CNS11643.1992-6:GR", /* CNS 11643-1992 pl.6 186 */ "\033$)L" },
+ { "CNS11643.1992-7:GL", /* CNS 11643-1992 pl.7 187 */ "\033$(M" },
+ { "CNS11643.1992-7:GR", /* CNS 11643-1992 pl.7 187 */ "\033$)M" },
+
+ /* Registered encodings with a varying number of bytes per character */
+ { "ISO10646-1", /* UTF-8 196 */ "\033%G" },
+
+ /* Encodings without ISO-IR assigned escape sequence must be
+ defined in XLC_LOCALE files, using "\033%/1" or "\033%/2". */
+
+ /* Backward compatibility with XFree86 3.x */
+ { "ISO8859-14:GR", "\033%/1" },
+ { "ISO8859-15:GR", "\033%/1" },
+ /* For use by utf8 -> ctext */
+ { "BIG5-0:GLGR", "\033%/2"},
+ /* used by Emacs, but not backed by ISO-IR */
+ { "BIG5-E0:GL", "\033$(0" },
+ { "BIG5-E0:GR", "\033$)0" },
+ { "BIG5-E1:GL", "\033$(1" },
+ { "BIG5-E1:GR", "\033$)1" },
+
+};
+
+/* We represent UTF-8 as an XlcGLGR charset, not in extended segments. */
+#define UTF8_IN_EXTSEQ 0
+
+/* ======================= Parsing ESC Sequences ======================= */
#define XctC0 0x0000
#define XctHT 0x0009
@@ -104,6 +141,7 @@ static CTDataRec default_ct_data[] =
#define XctC1 0x0080
#define XctCSI 0x009b
#define XctGR 0x00a0
+#define XctSTX 0x0002
#define XctCntrlFunc 0x0023
#define XctMB 0x0024
@@ -122,268 +160,282 @@ static CTDataRec default_ct_data[] =
#define XctGL94MB 0x2428
#define XctGR94MB 0x2429
#define XctExtSeg 0x252f
-#define XctOtherSeg 0x2f00
-
-#define XctESCSeq 0x1b00
-#define XctCSISeq 0x9b00
-
-#define SKIP_I(str) while (*(str) >= 0x20 && *(str) <= 0x2f) (str)++;
-#define SKIP_P(str) while (*(str) >= 0x30 && *(str) <= 0x3f) (str)++;
-
-typedef struct {
- XlcSide side;
- int char_size;
- int set_size;
- int ext_seg_length;
- int version;
- CTInfo ct_info;
-} CTParseRec, *CTParse;
-
-CTDataRec *default_ct_data_list()
-{
- return(default_ct_data);
-}
-
-size_t default_ct_data_list_num()
-{
- size_t num = sizeof(default_ct_data) / sizeof(CTDataRec);
- return(num);
-}
-
-static CTInfo ct_list = NULL;
-
-static CTInfo
-_XlcGetCTInfoFromEncoding(encoding, length)
- register char *encoding;
- register int length;
-{
- register CTInfo ct_info;
-
- for (ct_info = ct_list; ct_info; ct_info = ct_info->next) {
- if (length >= ct_info->encoding_len) {
- if (ct_info->ext_segment) {
- if (!strncmp(ct_info->encoding, encoding, 4) &&
- !strncmp(ct_info->ext_segment, encoding + 6,
- ct_info->ext_segment_len))
- return ct_info;
- } else if (!strncmp(ct_info->encoding, encoding,
- ct_info->encoding_len)) {
- return ct_info;
- }
- }
- }
-
- return (CTInfo) NULL;
-}
+#define XctReturn 0x2540
+/*
+ * Parses the header of a Compound Text segment, i.e. the charset designator.
+ * The string starts at *text and has *length bytes.
+ * Return value is one of:
+ * 0 (no valid charset designator),
+ * XctGL94, XctGR94, XctGR96, XctGL94MB, XctGR94MB,
+ * XctLeftToRight, XctRightToLeft, XctDirectionEnd,
+ * XctExtSeg, XctOtherCoding, XctReturn, XctIgnoreExt, XctNotIgnoreExt.
+ * If the return value is not 0, *text is incremented and *length decremented,
+ * to point past the charset designator. If the return value is one of
+ * XctGL94, XctGR94, XctGR96, XctGL94MB, XctGR94MB,
+ * XctExtSeg, XctOtherCoding, XctIgnoreExt, XctNotIgnoreExt,
+ * *final_byte is set to the "final byte" of the charset designator.
+ */
static unsigned int
-_XlcParseCT(parse, text, length)
- register CTParse parse;
- char **text;
- int *length;
+_XlcParseCT(
+ const char **text,
+ int *length,
+ unsigned char *final_byte)
{
unsigned int ret = 0;
unsigned char ch;
- register unsigned char *str = (unsigned char *) *text;
+ const unsigned char *str = (const unsigned char *) *text;
- bzero((char *) parse, sizeof(CTParseRec));
+ *final_byte = 0;
+ if (*length < 1)
+ return 0;
switch (ch = *str++) {
- case XctESC:
- if (*str == XctOtherCoding && *(str + 1) == XctNonStandard
- && *(str + 2) >= 0x30 && *(str + 2) <= 0x3f && *length >= 6) {
-
- /* non-standard encodings */
- parse->side = XlcGLGR;
- parse->set_size = 0;
- str += 2;
- if (*str <= 0x34) {
- parse->char_size = *str - 0x30;
- if (parse->char_size == 0) parse->char_size = 1;
- ret = XctExtSeg;
- parse->ct_info = _XlcGetCTInfoFromEncoding(*text, *length);
- } else
- ret = XctOtherSeg;
- str++;
- parse->ext_seg_length = (*str - 128) * 128 + *(str + 1) - 128;
- str += 2;
-
- goto done;
- } else if (*str == XctCntrlFunc && *length >= 4 &&
- *(str + 1) >= 0x20 && *(str + 1) <= 0x2f &&
- (*(str + 2) == XctIgnoreExt ||
- *(str + 2) == XctNotIgnoreExt)) {
-
- /* ignore extension or not */
- str++;
- parse->version = *str++ - 0x20;
- ret = *str++;
-
- goto done;
- }
-
- if (*str == XctMB) { /* multiple-byte sets */
- parse->char_size = 2;
- str++;
- } else
- parse->char_size = 1;
-
- switch (*str) {
- case XctGL94:
- parse->side = XlcGL;
- parse->set_size = 94;
- ret = (parse->char_size == 1) ? XctGL94 : XctGL94MB;
- break;
- case XctGR94:
- parse->side = XlcGR;
- parse->set_size = 94;
- ret = (parse->char_size == 1) ? XctGR94 : XctGR94MB;
- break;
- case XctGR96:
- if (parse->char_size == 1) {
- parse->side = XlcGR;
- parse->set_size = 96;
- ret = XctGR96;
- }
- break;
- }
- if (ret) {
- str++;
- if (*str >= 0x24 && *str <= 0x2f) { /* non-standard */
- ret = 0;
- str++;
- }
- }
-
- SKIP_I(str)
-
- if (ret && *str < 0x40) /* non-standard */
- ret = 0;
-
- if (*str < 0x30 || *str > 0x7e || (char *) str - *text >= *length)
- break;
-
- if (ret == 0)
- ret = XctESCSeq;
- else {
- if (parse->char_size == 2) {
- if (*str >= 0x70)
- parse->char_size = 4;
- else if (*str >= 0x60)
- parse->char_size = 3;
- }
- parse->ct_info = _XlcGetCTInfoFromEncoding(*text, *length);
- }
- str++;
- goto done;
- case XctCSI:
+ case XctESC:
+ if (*length < 2)
+ return 0;
+ switch (ch = *str++) {
+ case XctOtherCoding: /* % */
+ if (*length < 3)
+ return 0;
+ ch = *str++;
+ if (ch == XctNonStandard) { /* / */
+ if (*length < 4)
+ return 0;
+ ret = XctExtSeg;
+ ch = *str++;
+ } else if (ch == '@') {
+ ret = XctReturn;
+ } else {
+ ret = XctOtherCoding;
+ }
+ *final_byte = ch;
+ break;
+
+ case XctCntrlFunc: /* # */
+ if (*length < 4)
+ return 0;
+ *final_byte = *str++;
+ switch (*str++) {
+ case XctIgnoreExt: /* 0 */
+ ret = XctIgnoreExt;
+ break;
+ case XctNotIgnoreExt: /* 1 */
+ ret = XctNotIgnoreExt;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+ break;
+
+ case XctMB: /* $ */
+ if (*length < 4)
+ return 0;
+ ch = *str++;
+ switch (ch) {
+ case XctGL94: /* ( */
+ ret = XctGL94MB;
+ break;
+ case XctGR94: /* ) */
+ ret = XctGR94MB;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+ *final_byte = *str++;
+ break;
+
+ case XctGL94: /* ( */
+ if (*length < 3)
+ return 0;
+ ret = XctGL94;
+ *final_byte = *str++;
+ break;
+ case XctGR94: /* ) */
+ if (*length < 3)
+ return 0;
+ ret = XctGR94;
+ *final_byte = *str++;
+ break;
+ case XctGR96: /* - */
+ if (*length < 3)
+ return 0;
+ ret = XctGR96;
+ *final_byte = *str++;
+ break;
+ }
+ break;
+ case XctCSI:
/* direction */
- if (*str == XctLeftToRight && *(str + 1) == XctDirection) {
- ret = XctLeftToRight;
- str += 2;
- goto done;
- } else if (*str == XctRightToLeft && *(str + 1) == XctDirection) {
- ret = XctRightToLeft;
- str += 2;
- goto done;
- } else if (*str == XctDirectionEnd) {
- ret = XctDirectionEnd;
- str++;
- goto done;
- }
+ if (*length < 2)
+ return 0;
+ switch (*str++) {
+ case XctLeftToRight:
+ if (*length < 3)
+ return 0;
+ if (*str++ == XctDirection)
+ ret = XctLeftToRight;
+ break;
+ case XctRightToLeft:
+ if (*length < 3)
+ return 0;
+ if (*str++ == XctDirection)
+ ret = XctRightToLeft;
+ break;
+ case XctDirectionEnd:
+ ret = XctDirectionEnd;
+ break;
+ }
+ break;
+ }
- SKIP_P(str)
- SKIP_I(str)
+ if (ret) {
+ *length -= (const char *) str - *text;
+ *text = (const char *) str;
+ }
+ return ret;
+}
- if (*str < 0x40 && *str > 0x7e)
- break;
+/*
+ * Fills into a freshly created XlcCharSet the fields that can be inferred
+ * from the ESC sequence. These are side, char_size, set_size.
+ * Returns True if the charset can be used with Compound Text.
+ *
+ * Used by _XlcCreateDefaultCharSet.
+ */
+Bool
+_XlcParseCharSet(
+ XlcCharSet charset)
+{
+ unsigned int type;
+ unsigned char final_byte;
+ const char *ptr = charset->ct_sequence;
+ int length;
+ int char_size;
+
+ if (*ptr == '\0')
+ return False;
- ret = XctCSISeq;
- str++;
- goto done;
- }
+ length = strlen(ptr);
- if (ch & 0x80) {
- if (ch < 0xa0)
- ret = XctC1;
- else
- ret = XctGR;
- } else {
- if (ch == XctHT || ch == XctNL)
- ret = ch;
- else if (ch < 0x20)
- ret = XctC0;
- else
- ret = XctGL;
+ type = _XlcParseCT(&ptr, &length, &final_byte);
+
+ /* Check for validity and determine char_size.
+ char_size = 0 means varying number of bytes per character. */
+ switch (type) {
+ case XctGL94:
+ case XctGR94:
+ case XctGR96:
+ char_size = 1;
+ break;
+ case XctGL94MB:
+ case XctGR94MB:
+ char_size = (final_byte < 0x60 ? 2 : final_byte < 0x70 ? 3 : 4);
+ break;
+ case XctExtSeg:
+ char_size = final_byte - '0';
+ if (!(char_size >= 0 && char_size <= 4))
+ return False;
+ break;
+ case XctOtherCoding:
+ char_size = 0;
+ break;
+ default:
+ return False;
}
- return ret;
+ charset->char_size = char_size;
+
+ /* Fill in other values. */
+ switch (type) {
+ case XctGL94:
+ case XctGL94MB:
+ charset->side = XlcGL;
+ charset->set_size = 94;
+ break;
+ case XctGR94:
+ case XctGR94MB:
+ charset->side = XlcGR;
+ charset->set_size = 94;
+ break;
+ case XctGR96:
+ charset->side = XlcGR;
+ charset->set_size = 96;
+ break;
+ case XctExtSeg:
+ case XctOtherCoding:
+ charset->side = XlcGLGR;
+ charset->set_size = 0;
+ break;
+ }
+ return True;
+}
-done:
- *length -= (char *) str - *text;
- *text = (char *) str;
- return ret;
-}
+/* =============== Management of the List of Character Sets =============== */
-XlcCharSet
-_XlcAddCT(name, encoding)
- char *name;
- char *encoding;
-{
- CTInfo ct_info;
+/*
+ * Representation of a character set that can be used for Compound Text,
+ * at run time.
+ * Note: This information is not contained in the XlcCharSet, because
+ * multiple ESC sequences may be used for the same XlcCharSet.
+ */
+typedef struct _CTInfoRec {
XlcCharSet charset;
- CTParseRec parse;
- char *ct_ptr = encoding;
- int length;
+ const char *ct_sequence; /* Compound Text ESC sequence */
unsigned int type;
+ unsigned char final_byte;
+ /* If type == XctExtSeg: */
+ const char *ext_segment; /* extended segment name, then '\002' */
+ int ext_segment_len; /* length of above, including final '\002' */
- length = strlen(encoding);
+ struct _CTInfoRec *next;
+} CTInfoRec, *CTInfo;
- switch (type = _XlcParseCT(&parse, &ct_ptr, &length)) {
- case XctExtSeg:
- case XctGL94:
- case XctGL94MB:
- case XctGR94:
- case XctGR94MB:
- case XctGR96:
- if (parse.ct_info) /* existed */
- return parse.ct_info->charset;
- break;
- default:
- return (XlcCharSet) NULL;
- }
+/*
+ * List of character sets that can be used for Compound Text,
+ * Includes all that are listed in default_ct_data, but more can be added
+ * at runtime through _XlcAddCT.
+ */
+static CTInfo ct_list = NULL;
+static CTInfo *ct_list_end = &ct_list;
- charset = _XlcCreateDefaultCharSet(name, encoding);
- if (charset == NULL)
- return (XlcCharSet) NULL;
- _XlcAddCharSet(charset);
+/*
+ * Returns a Compound Text info record for an ESC sequence.
+ * The first part of the ESC sequence has already been parsed into 'type'
+ * and 'final_byte'. The remainder starts at 'text', at least 'text_len'
+ * bytes (only used if type == XctExtSeg).
+ */
+static CTInfo
+_XlcGetCTInfo(
+ unsigned int type,
+ unsigned char final_byte,
+ const char *text,
+ int text_len)
+{
+ CTInfo ct_info;
- ct_info = (CTInfo) Xmalloc(sizeof(CTInfoRec));
- if (ct_info == NULL)
- return (XlcCharSet) NULL;
-
- ct_info->charset = charset;
- ct_info->encoding = charset->ct_sequence;
- ct_info->encoding_len = strlen(ct_info->encoding);
- if (type == XctExtSeg) {
- ct_info->ext_segment = ct_info->encoding + 6;
- ct_info->ext_segment_len = strlen(ct_info->ext_segment);
- } else {
- ct_info->ext_segment = NULL;
- ct_info->ext_segment_len = 0;
- }
- ct_info->next = ct_list;
- ct_list = ct_info;
+ for (ct_info = ct_list; ct_info; ct_info = ct_info->next)
+ if (ct_info->type == type
+ && ct_info->final_byte == final_byte
+ && (type != XctExtSeg
+ || (text_len >= ct_info->ext_segment_len
+ && memcmp(text, ct_info->ext_segment,
+ ct_info->ext_segment_len) == 0)))
+ return ct_info;
- return charset;
+ return (CTInfo) NULL;
}
+/* Returns the Compound Text info for a given XlcCharSet.
+ Returns NULL if none is found. */
static CTInfo
-_XlcGetCTInfoFromCharSet(charset)
- register XlcCharSet charset;
+_XlcGetCTInfoFromCharSet(
+ XlcCharSet charset)
{
- register CTInfo ct_info;
+ CTInfo ct_info;
for (ct_info = ct_list; ct_info; ct_info = ct_info->next)
if (ct_info->charset == charset)
@@ -392,244 +444,445 @@ _XlcGetCTInfoFromCharSet(charset)
return (CTInfo) NULL;
}
-Bool
-_XlcParseCharSet(charset)
- XlcCharSet charset;
+/* Creates a new XlcCharSet, given its name (including side suffix) and
+ Compound Text ESC sequence (normally at most 4 bytes), and makes it
+ eligible for Compound Text processing. */
+XlcCharSet
+_XlcAddCT(
+ const char *name,
+ const char *ct_sequence)
{
- CTParseRec parse;
- char *ptr, *bufp, buf[BUFSIZ];
+ CTInfo ct_info, existing_info;
+ XlcCharSet charset;
+ const char *ct_ptr;
int length;
+ unsigned int type;
+ unsigned char final_byte;
- if (charset->ct_sequence == NULL)
- return False;
-
- ptr = charset->ct_sequence;
- length = strlen(ptr);
-
- (void) _XlcParseCT(&parse, &ptr, &length);
-
- if (charset->name) {
- charset->xrm_name = XrmStringToQuark(charset->name);
-
- if ((length = strlen (charset->name)) < sizeof buf) bufp = buf;
- else bufp = Xmalloc (length + 1);
-
- if (bufp == NULL) return False;
- strcpy(bufp, charset->name);
- if ((ptr = strchr(bufp, ':')))
- *ptr = '\0';
- charset->xrm_encoding_name = XrmStringToQuark(bufp);
- if (bufp != buf) Xfree (bufp);
- charset->encoding_name = XrmQuarkToString(charset->xrm_encoding_name);
+ charset = _XlcGetCharSet(name);
+ if (charset != NULL) {
+ /* Even if the charset already exists, it is OK to register a second
+ Compound Text sequence for it. */
} else {
- charset->xrm_name = 0;
- charset->encoding_name = NULL;
- charset->xrm_encoding_name = 0;
+ /* Attempt to create the charset. */
+ charset = _XlcCreateDefaultCharSet(name, ct_sequence);
+ if (charset == NULL)
+ return (XlcCharSet) NULL;
+ _XlcAddCharSet(charset);
}
- charset->side = parse.side;
- charset->char_size = parse.char_size;
- charset->set_size = parse.set_size;
+ /* Allocate a CTinfo record. */
+ length = strlen(ct_sequence);
+ ct_info = (CTInfo) Xmalloc(sizeof(CTInfoRec) + length+1);
+ if (ct_info == NULL)
+ return charset;
- return True;
-}
+ ct_info->charset = charset;
+ ct_info->ct_sequence = strcpy((char *) (ct_info + 1), ct_sequence);
-static void init_converter();
+ /* Parse the Compound Text sequence. */
+ ct_ptr = ct_sequence;
+ type = _XlcParseCT(&ct_ptr, &length, &final_byte);
-Bool
-_XlcInitCTInfo()
-{
- register XlcCharSet charset;
- register CTData ct_data;
- register int num;
+ ct_info->type = type;
+ ct_info->final_byte = final_byte;
- if (ct_list == NULL) {
- num = sizeof(default_ct_data) / sizeof(CTDataRec);
- for (ct_data = default_ct_data; num-- > 0; ct_data++) {
- charset = _XlcAddCT(ct_data->name, ct_data->encoding);
- if (charset == NULL)
- continue;
- }
- init_converter();
+ switch (type) {
+ case XctGL94:
+ case XctGR94:
+ case XctGR96:
+ case XctGL94MB:
+ case XctGR94MB:
+ case XctOtherCoding:
+ ct_info->ext_segment = NULL;
+ ct_info->ext_segment_len = 0;
+ break;
+ case XctExtSeg: {
+ /* By convention, the extended segment name is the encoding_name
+ in lowercase. */
+ const char *q = charset->encoding_name;
+ int n = strlen(q);
+ char *p;
+
+ /* Ensure ct_info->ext_segment_len <= 0x3fff - 6. */
+ if (n > 0x3fff - 6 - 1) {
+ Xfree(ct_info);
+ return charset;
+ }
+ p = (char *) Xmalloc(n+1);
+ if (p == NULL) {
+ Xfree(ct_info);
+ return charset;
+ }
+ ct_info->ext_segment = p;
+ ct_info->ext_segment_len = n+1;
+ for ( ; n > 0; p++, q++, n--)
+ *p = (*q >= 'A' && *q <= 'Z' ? *q - 'A' + 'a' : *q);
+ *p = XctSTX;
+ break;
+ }
+ default:
+ Xfree(ct_info);
+ return (XlcCharSet) NULL;
}
- return True;
+ /* Insert it into the list, if not already present. */
+ existing_info =
+ _XlcGetCTInfo(type, ct_info->final_byte,
+ ct_info->ext_segment, ct_info->ext_segment_len);
+ if (existing_info == NULL) {
+ /* Insert it at the end. If there are duplicates CTinfo entries
+ for the same XlcCharSet, we want the first (standard) one to
+ override the second (user defined) one. */
+ ct_info->next = *ct_list_end;
+ *ct_list_end = ct_info;
+ } else {
+ if (existing_info->charset != charset
+ /* We have a conflict, with one exception: JISX0208.1983-0 and
+ JISX0208.1990-0 are the same for all practical purposes. */
+ && !(strncmp(existing_info->charset->name, "JISX0208", 8) == 0
+ && strncmp(charset->name, "JISX0208", 8) == 0)) {
+ fprintf(stderr,
+ "Xlib: charsets %s and %s have the same CT sequence\n",
+ charset->name, existing_info->charset->name);
+ if (strcmp(charset->ct_sequence, ct_sequence) == 0)
+ charset->ct_sequence = "";
+ }
+ Xfree(ct_info);
+ }
+
+ return charset;
}
-static int
-_XlcCheckCTSequence(state, ctext, ctext_len)
- State state;
- char **ctext;
- int *ctext_len;
+/* ========== Converters String <--> CharSet <--> Compound Text ========== */
+
+/*
+ * Structure representing the parse state of a Compound Text string.
+ */
+typedef struct _StateRec {
+ XlcCharSet charset; /* The charset of the current segment */
+ XlcCharSet GL_charset; /* The charset responsible for 0x00..0x7F */
+ XlcCharSet GR_charset; /* The charset responsible for 0x80..0xFF */
+ XlcCharSet Other_charset; /* != NULL if currently in an other segment */
+ int ext_seg_left; /* > 0 if currently in an extended segment */
+} StateRec, *State;
+
+
+/* Subroutine for parsing an ESC sequence. */
+
+typedef enum {
+ resOK, /* Charset saved in 'state', sequence skipped */
+ resNotInList, /* Charset not found, sequence skipped */
+ resNotCTSeq /* EscSeq not recognized, pointers not changed */
+} CheckResult;
+
+static CheckResult
+_XlcCheckCTSequence(
+ State state,
+ const char **ctext,
+ int *ctext_len)
{
XlcCharSet charset;
- CTParseRec parse;
CTInfo ct_info;
- int length;
+ const char *tmp_ctext = *ctext;
+ int tmp_ctext_len = *ctext_len;
+ unsigned int type;
+ unsigned char final_byte;
+ int ext_seg_left = 0;
- _XlcParseCT(&parse, ctext, ctext_len);
-
- ct_info = parse.ct_info;
- if (parse.ext_seg_length > 0) { /* XctExtSeg or XctOtherSeg */
- if (ct_info) {
- length = ct_info->ext_segment_len;
- *ctext += length;
- *ctext_len -= length;
- state->ext_seg_left = parse.ext_seg_length - length;
- state->ext_seg_charset = ct_info->charset;
- } else {
- state->ext_seg_left = parse.ext_seg_length;
- state->ext_seg_charset = NULL;
- }
- } else if (ct_info) {
- if ((charset = ct_info->charset)) {
- if (charset->side == XlcGL)
- state->GL_charset = charset;
- else if (charset->side == XlcGR)
- state->GR_charset = charset;
- }
+ /* Check for validity. */
+ type = _XlcParseCT(&tmp_ctext, &tmp_ctext_len, &final_byte);
+
+ switch (type) {
+ case XctGL94:
+ case XctGR94:
+ case XctGR96:
+ case XctGL94MB:
+ case XctGR94MB:
+ case XctOtherCoding:
+ *ctext = tmp_ctext;
+ *ctext_len = tmp_ctext_len;
+ break;
+ case XctReturn:
+ *ctext = tmp_ctext;
+ *ctext_len = tmp_ctext_len;
+ state->Other_charset = NULL;
+ return resOK;
+ case XctExtSeg:
+ if (tmp_ctext_len > 2
+ && (tmp_ctext[0] & 0x80) && (tmp_ctext[0] & 0x80)) {
+ unsigned int msb = tmp_ctext[0] & 0x7f;
+ unsigned int lsb = tmp_ctext[1] & 0x7f;
+ ext_seg_left = (msb << 7) + lsb;
+ if (ext_seg_left <= tmp_ctext_len - 2) {
+ *ctext = tmp_ctext + 2;
+ *ctext_len = tmp_ctext_len - 2;
+ break;
+ }
+ }
+ return resNotCTSeq;
+ default:
+ return resNotCTSeq;
}
- return 0;
+ ct_info = _XlcGetCTInfo(type, final_byte, *ctext, ext_seg_left);
+
+ if (ct_info) {
+ charset = ct_info->charset;
+ state->ext_seg_left = ext_seg_left;
+ if (type == XctExtSeg) {
+ state->charset = charset;
+ /* Skip past the extended segment name and the separator. */
+ *ctext += ct_info->ext_segment_len;
+ *ctext_len -= ct_info->ext_segment_len;
+ state->ext_seg_left -= ct_info->ext_segment_len;
+ } else if (type == XctOtherCoding) {
+ state->Other_charset = charset;
+ } else {
+ if (charset->side == XlcGL) {
+ state->GL_charset = charset;
+ } else if (charset->side == XlcGR) {
+ state->GR_charset = charset;
+ } else {
+ state->GL_charset = charset;
+ state->GR_charset = charset;
+ }
+ }
+ return resOK;
+ } else {
+ state->ext_seg_left = 0;
+ if (type == XctExtSeg) {
+ /* Skip the entire extended segment. */
+ *ctext += ext_seg_left;
+ *ctext_len -= ext_seg_left;
+ }
+ return resNotInList;
+ }
}
-
static void
-init_state(conv)
- XlcConv conv;
+init_state(
+ XlcConv conv)
{
State state = (State) conv->state;
- static XlcCharSet GL_charset = NULL;
- static XlcCharSet GR_charset = NULL;
+ static XlcCharSet default_GL_charset = NULL;
+ static XlcCharSet default_GR_charset = NULL;
- if (GL_charset == NULL) {
- GL_charset = _XlcGetCharSet("ISO8859-1:GL");
- GR_charset = _XlcGetCharSet("ISO8859-1:GR");
+ if (default_GL_charset == NULL) {
+ default_GL_charset = _XlcGetCharSet("ISO8859-1:GL");
+ default_GR_charset = _XlcGetCharSet("ISO8859-1:GR");
}
- state->GL_charset = state->charset = GL_charset;
- state->GR_charset = GR_charset;
- state->ext_seg_charset = NULL;
+ /* The initial state is ISO-8859-1 on both sides. */
+ state->GL_charset = state->charset = default_GL_charset;
+ state->GR_charset = default_GR_charset;
+
+ state->Other_charset = NULL;
+
state->ext_seg_left = 0;
}
+/* from XlcNCompoundText to XlcNCharSet */
+
static int
-cttocs(conv, from, from_left, to, to_left, args, num_args)
- XlcConv conv;
- XPointer *from;
- int *from_left;
- XPointer *to;
- int *to_left;
- XPointer *args;
- int num_args;
+cttocs(
+ XlcConv conv,
+ XPointer *from,
+ int *from_left,
+ XPointer *to,
+ int *to_left,
+ XPointer *args,
+ int num_args)
{
- register State state = (State) conv->state;
- register unsigned char ch;
- int length;
+ State state = (State) conv->state;
XlcCharSet charset = NULL;
- char *ctptr, *bufptr;
+ const char *ctptr;
+ char *bufptr;
int ctext_len, buf_len;
+ int unconv_num = 0;
- ctptr = *((char **) from);
- bufptr = *((char **) to);
+ ctptr = (const char *) *from;
+ bufptr = (char *) *to;
ctext_len = *from_left;
buf_len = *to_left;
while (ctext_len > 0 && buf_len > 0) {
- if (state->ext_seg_left > 0) {
- length = min(state->ext_seg_left, ctext_len);
- length = min(length, buf_len);
-
- ctext_len -= length;
- state->ext_seg_left -= length;
-
- if (state->ext_seg_charset) {
- charset = state->ext_seg_charset;
- buf_len -= length;
- if (charset->side == XlcGL) {
- while (length-- > 0)
- *bufptr++ = *ctptr++ & 0x7f;
- } else if (charset->side == XlcGR) {
- while (length-- > 0)
- *bufptr++ = *ctptr++ | 0x80;
- } else {
- while (length-- > 0)
- *bufptr++ = *ctptr++;
- }
-
- if (state->ext_seg_left < 1)
- state->ext_seg_charset = NULL;
- }
- break;
- }
- ch = *((unsigned char *) ctptr);
- if (ch == 0x1b || ch == 0x9b) {
- length = _XlcCheckCTSequence(state, &ctptr, &ctext_len);
- if (length < 0)
- return -1;
- if (state->ext_seg_left > 0 && charset)
- break;
- } else {
- if (charset) {
- if (charset != (ch & 0x80 ? state->GR_charset :
- state->GL_charset))
- break;
- } else
- charset = ch & 0x80 ? state->GR_charset : state->GL_charset;
-
- if ((ch < 0x20 && ch != '\0' && ch != '\n' && ch != '\t') ||
- (ch >= 0x80 && ch < 0xa0))
- return -1;
-
- *bufptr++ = *ctptr++;
- ctext_len--;
- buf_len--;
- }
+ if (state->ext_seg_left == 0) {
+ /* Not in the middle of an extended segment; look at next byte. */
+ unsigned char ch = *ctptr;
+ XlcCharSet ch_charset;
+
+ if (ch == XctESC) {
+ CheckResult ret =
+ _XlcCheckCTSequence(state, &ctptr, &ctext_len);
+ if (ret == resOK)
+ /* state has been modified. */
+ continue;
+ if (ret == resNotInList) {
+ /* XXX Just continue with previous charset. */
+ unconv_num++;
+ continue;
+ }
+ } else if (ch == XctCSI) {
+ /* XXX Simply ignore the XctLeftToRight, XctRightToLeft,
+ XctDirectionEnd sequences for the moment. */
+ unsigned char dummy;
+ if (_XlcParseCT(&ctptr, &ctext_len, &dummy)) {
+ unconv_num++;
+ continue;
+ }
+ }
+
+ /* Find the charset which is responsible for this byte. */
+ ch_charset = (state->Other_charset != NULL ? state->Other_charset :
+ (ch & 0x80 ? state->GR_charset : state->GL_charset));
+
+ /* Set the charset of this run, or continue the current run,
+ or stop the current run. */
+ if (charset) {
+ if (charset != ch_charset)
+ break;
+ } else {
+ state->charset = charset = ch_charset;
+ }
+
+ /* We don't want to split a character into multiple pieces. */
+ if (buf_len < 6) {
+ if (charset->char_size > 0) {
+ if (buf_len < charset->char_size)
+ break;
+ } else {
+ /* char_size == 0 is tricky. The code here is good only
+ for valid UTF-8 input. */
+ if (charset->ct_sequence[0] == XctESC
+ && charset->ct_sequence[1] == XctOtherCoding
+ && charset->ct_sequence[2] == 'G') {
+ int char_size = (ch < 0xc0 ? 1 :
+ ch < 0xe0 ? 2 :
+ ch < 0xf0 ? 3 :
+ ch < 0xf8 ? 4 :
+ ch < 0xfc ? 5 :
+ 6);
+ if (buf_len < char_size)
+ break;
+ }
+ }
+ }
+
+ *bufptr++ = *ctptr++;
+ ctext_len--;
+ buf_len--;
+ } else {
+ /* Copy as much as possible from the current extended segment
+ to the buffer. */
+ int char_size;
+
+ /* Set the charset of this run, or continue the current run,
+ or stop the current run. */
+ if (charset) {
+ if (charset != state->charset)
+ break;
+ } else {
+ charset = state->charset;
+ }
+
+ char_size = charset->char_size;
+
+ if (state->ext_seg_left <= buf_len || char_size > 0) {
+ int n = (state->ext_seg_left <= buf_len
+ ? state->ext_seg_left
+ : (buf_len / char_size) * char_size);
+ memcpy(bufptr, ctptr, n);
+ ctptr += n; ctext_len -= n;
+ bufptr += n; buf_len -= n;
+ state->ext_seg_left -= n;
+ } else {
+#if UTF8_IN_EXTSEQ
+ /* char_size == 0 is tricky. The code here is good only
+ for valid UTF-8 input. */
+ if (strcmp(charset->name, "ISO10646-1") == 0) {
+ unsigned char ch = *ctptr;
+ int char_size = (ch < 0xc0 ? 1 :
+ ch < 0xe0 ? 2 :
+ ch < 0xf0 ? 3 :
+ ch < 0xf8 ? 4 :
+ ch < 0xfc ? 5 :
+ 6);
+ int i;
+ if (buf_len < char_size)
+ break;
+ /* A small loop is faster than calling memcpy. */
+ for (i = char_size; i > 0; i--)
+ *bufptr++ = *ctptr++;
+ ctext_len -= char_size;
+ buf_len -= char_size;
+ state->ext_seg_left -= char_size;
+ } else
+#endif
+ {
+ /* Here ctext_len >= state->ext_seg_left > buf_len.
+ We may be splitting a character into multiple pieces.
+ Oh well. */
+ int n = buf_len;
+ memcpy(bufptr, ctptr, n);
+ ctptr += n; ctext_len -= n;
+ bufptr += n; buf_len -= n;
+ state->ext_seg_left -= n;
+ }
+ }
+ }
}
- if (charset)
- state->charset = charset;
+ /* 'charset' is the charset for the current run. In some cases,
+ 'state->charset' contains the charset for the next run. Therefore,
+ return 'charset'.
+ 'charset' may still be NULL only if no output was produced. */
if (num_args > 0)
- *((XlcCharSet *) args[0]) = state->charset;
+ *((XlcCharSet *) args[0]) = charset;
- *from_left -= ctptr - *((char **) from);
+ *from_left -= ctptr - *((const char **) from);
*from = (XPointer) ctptr;
*to_left -= bufptr - *((char **) to);
*to = (XPointer) bufptr;
- return 0;
+ return unconv_num;
}
+/* from XlcNCharSet to XlcNCompoundText */
+
static int
-cstoct(conv, from, from_left, to, to_left, args, num_args)
- XlcConv conv;
- XPointer *from;
- int *from_left;
- XPointer *to;
- int *to_left;
- XPointer *args;
- int num_args;
+cstoct(
+ XlcConv conv,
+ XPointer *from,
+ int *from_left,
+ XPointer *to,
+ int *to_left,
+ XPointer *args,
+ int num_args)
{
State state = (State) conv->state;
XlcSide side;
- unsigned char min_ch, max_ch;
- register unsigned char ch;
- int length;
+ unsigned char min_ch = 0, max_ch = 0;
+ int length, unconv_num;
CTInfo ct_info;
XlcCharSet charset;
- char *csptr, *ctptr;
+ const char *csptr;
+ char *ctptr;
int csstr_len, ct_len;
+ char *ext_segment_start;
+ int char_size;
+ /* One argument is required, of type XlcCharSet. */
if (num_args < 1)
return -1;
-
- csptr = *((char **) from);
+
+ csptr = *((const char **) from);
ctptr = *((char **) to);
csstr_len = *from_left;
ct_len = *to_left;
-
+
charset = (XlcCharSet) args[0];
ct_info = _XlcGetCTInfoFromCharSet(charset);
@@ -637,74 +890,170 @@ cstoct(conv, from, from_left, to, to_left, args, num_args)
return -1;
side = charset->side;
+ length = strlen(ct_info->ct_sequence);
+
+ ext_segment_start = NULL;
+
+ if (ct_info->type == XctOtherCoding) {
+ /* Output the Escape sequence for switching to the charset, and
+ reserve room now for the XctReturn sequence at the end. */
+ if (ct_len < length + 3)
+ return -1;
+
+ memcpy(ctptr, ct_info->ct_sequence, length);
+ ctptr += length;
+ ct_len -= length + 3;
+ } else
+ /* Test whether the charset is already active. */
+ if (((side == XlcGR || side == XlcGLGR)
+ && charset != state->GR_charset)
+ || ((side == XlcGL || side == XlcGLGR)
+ && charset != state->GL_charset)) {
+
+ /* Output the Escape sequence for switching to the charset. */
+ if (ct_info->type == XctExtSeg) {
+ if (ct_len < length + 2 + ct_info->ext_segment_len)
+ return -1;
+
+ memcpy(ctptr, ct_info->ct_sequence, length);
+ ctptr += length;
+ ct_len -= length;
+
+ ctptr += 2;
+ ct_len -= 2;
+ ext_segment_start = ctptr;
+
+ /* The size of an extended segment must fit in 14 bits. */
+ if (ct_len > 0x3fff)
+ ct_len = 0x3fff;
+
+ memcpy(ctptr, ct_info->ext_segment, ct_info->ext_segment_len);
+ ctptr += ct_info->ext_segment_len;
+ ct_len -= ct_info->ext_segment_len;
+ } else {
+ if (ct_len < length)
+ return -1;
+
+ memcpy(ctptr, ct_info->ct_sequence, length);
+ ctptr += length;
+ ct_len -= length;
+ }
+ }
- if (ct_info->ext_segment) {
- if (charset != state->ext_seg_charset && state->ext_seg_left < 1) {
- length = ct_info->encoding_len;
- if (ct_len < length)
- return -1;
- strcpy(ctptr, ct_info->encoding);
- ctptr[4] = ((ct_info->ext_segment_len + csstr_len) / 128) | 0x80;
- ctptr[5] = ((ct_info->ext_segment_len + csstr_len) % 128) | 0x80;
- ctptr += length;
- ct_len -= length;
- state->ext_seg_left = csstr_len;
- }
- length = min(state->ext_seg_left, csstr_len);
- state->ext_seg_left -= length;
-
- if (side == XlcGL) {
- while (length-- > 0)
- *ctptr++ = *csptr++ & 0x7f;
- } else if (side == XlcGR) {
- while (length-- > 0)
- *ctptr++ = *csptr++ | 0x80;
- } else {
- while (length-- > 0)
- *ctptr++ = *csptr++;
- }
- state->ext_seg_charset = (state->ext_seg_left > 0) ? charset : NULL;
- } else {
- if ((side == XlcGR && charset != state->GR_charset) ||
- (side == XlcGL && charset != state->GL_charset)) {
-
- ct_len -= ct_info->encoding_len;
- if (ct_len < 0)
- return -1;
- strcpy(ctptr, ct_info->encoding);
- ctptr += ct_info->encoding_len;
- }
-
- min_ch = 0x20;
- max_ch = 0x7f;
-
- if (charset->set_size == 94) {
- max_ch--;
+ /* If the charset has side GL or GR, prepare remapping the characters
+ to the correct side. */
+ if (charset->set_size) {
+ min_ch = 0x20;
+ max_ch = 0x7f;
+ if (charset->set_size == 94) {
+ max_ch--;
if (charset->char_size > 1 || side == XlcGR)
min_ch++;
- }
+ }
+ }
+ /* Actually copy the contents. */
+ unconv_num = 0;
+ char_size = charset->char_size;
+ if (char_size == 1) {
while (csstr_len > 0 && ct_len > 0) {
- ch = *((unsigned char *) csptr++) & 0x7f;
- if (ch < min_ch || ch > max_ch)
- if (ch != 0x00 && ch != 0x09 && ch != 0x0a && ch != 0x1b)
- continue; /* XXX */
+ if (charset->set_size) {
+ /* The CompoundText specification says that the only
+ control characters allowed are 0x09, 0x0a, 0x1b, 0x9b.
+ Therefore here we eliminate other control characters. */
+ unsigned char ch = *((unsigned char *) csptr) & 0x7f;
+ if (!((ch >= min_ch && ch <= max_ch)
+ || (side == XlcGL
+ && (ch == 0x00 || ch == 0x09 || ch == 0x0a))
+ || ((side == XlcGL || side == XlcGR)
+ && (ch == 0x1b)))) {
+ csptr++;
+ csstr_len--;
+ unconv_num++;
+ continue;
+ }
+ }
+
if (side == XlcGL)
- *ctptr++ = ch & 0x7f;
+ *ctptr++ = *csptr++ & 0x7f;
else if (side == XlcGR)
- *ctptr++ = ch | 0x80;
+ *ctptr++ = *csptr++ | 0x80;
else
- *ctptr++ = ch;
+ *ctptr++ = *csptr++;
csstr_len--;
ct_len--;
}
- if (side == XlcGR)
- state->GR_charset = charset;
- else if (side == XlcGL)
- state->GL_charset = charset;
+ } else if (char_size > 1) {
+ while (csstr_len >= char_size && ct_len >= char_size) {
+ if (side == XlcGL) {
+ int i;
+ for (i = char_size; i > 0; i--)
+ *ctptr++ = *csptr++ & 0x7f;
+ } else if (side == XlcGR) {
+ int i;
+ for (i = char_size; i > 0; i--)
+ *ctptr++ = *csptr++ | 0x80;
+ } else {
+ int i;
+ for (i = char_size; i > 0; i--)
+ *ctptr++ = *csptr++;
+ }
+ csstr_len -= char_size;
+ ct_len -= char_size;
+ }
+ } else {
+ /* char_size = 0. The code here is good only for valid UTF-8 input. */
+ if ((charset->ct_sequence[0] == XctESC
+ && charset->ct_sequence[1] == XctOtherCoding
+ && charset->ct_sequence[2] == 'G')
+#if UTF8_IN_EXTSEQ
+ || strcmp(charset->name, "ISO10646-1") == 0
+#endif
+ ) {
+ while (csstr_len > 0 && ct_len > 0) {
+ unsigned char ch = * (unsigned char *) csptr;
+ int char_size = (ch < 0xc0 ? 1 :
+ ch < 0xe0 ? 2 :
+ ch < 0xf0 ? 3 :
+ ch < 0xf8 ? 4 :
+ ch < 0xfc ? 5 :
+ 6);
+ int i;
+ if (!(csstr_len >= char_size && ct_len >= char_size))
+ break;
+ for (i = char_size; i > 0; i--)
+ *ctptr++ = *csptr++;
+ csstr_len -= char_size;
+ ct_len -= char_size;
+ }
+ } else {
+ while (csstr_len > 0 && ct_len > 0) {
+ *ctptr++ = *csptr++;
+ csstr_len--;
+ ct_len--;
+ }
+ }
}
- *from_left -= csptr - *((char **) from);
+ if (ct_info->type == XctOtherCoding) {
+ /* Terminate with an XctReturn sequence. */
+ ctptr[0] = XctESC;
+ ctptr[1] = XctOtherCoding;
+ ctptr[2] = '@';
+ ctptr += 3;
+ } else if (ext_segment_start != NULL) {
+ /* Backpatch the extended segment's length. */
+ int ext_segment_length = ctptr - ext_segment_start;
+ *(ext_segment_start - 2) = (ext_segment_length >> 7) | 0x80;
+ *(ext_segment_start - 1) = (ext_segment_length & 0x7f) | 0x80;
+ } else {
+ if (side == XlcGR || side == XlcGLGR)
+ state->GR_charset = charset;
+ if (side == XlcGL || side == XlcGLGR)
+ state->GL_charset = charset;
+ }
+
+ *from_left -= csptr - *((const char **) from);
*from = (XPointer) csptr;
*to_left -= ctptr - *((char **) to);
@@ -713,22 +1062,25 @@ cstoct(conv, from, from_left, to, to_left, args, num_args)
return 0;
}
+/* from XlcNString to XlcNCharSet */
+
static int
-strtocs(conv, from, from_left, to, to_left, args, num_args)
- XlcConv conv;
- XPointer *from;
- int *from_left;
- XPointer *to;
- int *to_left;
- XPointer *args;
- int num_args;
+strtocs(
+ XlcConv conv,
+ XPointer *from,
+ int *from_left,
+ XPointer *to,
+ int *to_left,
+ XPointer *args,
+ int num_args)
{
State state = (State) conv->state;
- register char *src, *dst;
+ const char *src;
+ char *dst;
unsigned char side;
- register int length;
+ int length;
- src = (char *) *from;
+ src = (const char *) *from;
dst = (char *) *to;
length = min(*from_left, *to_left);
@@ -737,46 +1089,54 @@ strtocs(conv, from, from_left, to, to_left, args, num_args)
while (side == (*((unsigned char *) src) & 0x80) && length-- > 0)
*dst++ = *src++;
- *from_left -= src - (char *) *from;
+ *from_left -= src - (const char *) *from;
*from = (XPointer) src;
*to_left -= dst - (char *) *to;
*to = (XPointer) dst;
if (num_args > 0)
- *((XlcCharSet *)args[0]) = side ? state->GR_charset : state->GL_charset;
+ *((XlcCharSet *)args[0]) = (side ? state->GR_charset : state->GL_charset);
return 0;
}
+/* from XlcNCharSet to XlcNString */
+
static int
-cstostr(conv, from, from_left, to, to_left, args, num_args)
- XlcConv conv;
- XPointer *from;
- int *from_left;
- XPointer *to;
- int *to_left;
- XPointer *args;
- int num_args;
+cstostr(
+ XlcConv conv,
+ XPointer *from,
+ int *from_left,
+ XPointer *to,
+ int *to_left,
+ XPointer *args,
+ int num_args)
{
State state = (State) conv->state;
- char *csptr, *string_ptr;
+ const char *csptr;
+ char *string_ptr;
int csstr_len, str_len;
unsigned char ch;
int unconv_num = 0;
- if (num_args < 1 || (state->GL_charset != (XlcCharSet) args[0] &&
- state->GR_charset != (XlcCharSet) args[0]))
+ /* This converter can only convert from ISO8859-1:GL and ISO8859-1:GR. */
+ if (num_args < 1
+ || !((XlcCharSet) args[0] == state->GL_charset
+ || (XlcCharSet) args[0] == state->GR_charset))
return -1;
- csptr = *((char **) from);
+ csptr = *((const char **) from);
string_ptr = *((char **) to);
csstr_len = *from_left;
str_len = *to_left;
- while (csstr_len-- > 0 && str_len > 0) {
+ while (csstr_len > 0 && str_len > 0) {
ch = *((unsigned char *) csptr++);
- if ((ch < 0x20 && ch != 0x00 && ch != 0x09 && ch != 0x0a) ||
- ch == 0x7f || ((ch & 0x80) && ch < 0xa0)) {
+ csstr_len--;
+ /* Citing ICCCM: "STRING as a type specifies the ISO Latin-1 character
+ set plus the control characters TAB and NEWLINE." */
+ if ((ch < 0x20 && ch != 0x00 && ch != 0x09 && ch != 0x0a)
+ || (ch >= 0x7f && ch < 0xa0)) {
unconv_num++;
continue;
}
@@ -784,7 +1144,7 @@ cstostr(conv, from, from_left, to, to_left, args, num_args)
str_len--;
}
- *from_left -= csptr - *((char **) from);
+ *from_left -= csptr - *((const char **) from);
*from = (XPointer) csptr;
*to_left -= string_ptr - *((char **) to);
@@ -794,116 +1154,141 @@ cstostr(conv, from, from_left, to, to_left, args, num_args)
}
-static void
-close_converter(conv)
- XlcConv conv;
-{
- if (conv->state)
- Xfree((char *) conv->state);
-
- Xfree((char *) conv);
-}
-
static XlcConv
-create_conv(methods)
- XlcConvMethods methods;
+create_conv(
+ XlcConvMethods methods)
{
- register XlcConv conv;
+ XlcConv conv;
- conv = (XlcConv) Xmalloc(sizeof(XlcConvRec));
+ conv = (XlcConv) Xmalloc(sizeof(XlcConvRec) + sizeof(StateRec));
if (conv == NULL)
return (XlcConv) NULL;
- conv->state = (XPointer) Xmalloc(sizeof(StateRec));
- if (conv->state == NULL)
- goto err;
-
+ conv->state = (XPointer) &conv[1];
+
conv->methods = methods;
init_state(conv);
return conv;
+}
-err:
- close_converter(conv);
-
- return (XlcConv) NULL;
+static void
+close_converter(
+ XlcConv conv)
+{
+ /* conv->state is allocated together with conv, free both at once. */
+ Xfree((char *) conv);
}
+
static XlcConvMethodsRec cttocs_methods = {
close_converter,
cttocs,
init_state
-} ;
+};
static XlcConv
-open_cttocs(from_lcd, from_type, to_lcd, to_type)
- XLCd from_lcd;
- char *from_type;
- XLCd to_lcd;
- char *to_type;
+open_cttocs(
+ XLCd from_lcd,
+ const char *from_type,
+ XLCd to_lcd,
+ const char *to_type)
{
return create_conv(&cttocs_methods);
}
+
static XlcConvMethodsRec cstoct_methods = {
close_converter,
cstoct,
init_state
-} ;
+};
static XlcConv
-open_cstoct(from_lcd, from_type, to_lcd, to_type)
- XLCd from_lcd;
- char *from_type;
- XLCd to_lcd;
- char *to_type;
+open_cstoct(
+ XLCd from_lcd,
+ const char *from_type,
+ XLCd to_lcd,
+ const char *to_type)
{
return create_conv(&cstoct_methods);
}
+
static XlcConvMethodsRec strtocs_methods = {
close_converter,
strtocs,
init_state
-} ;
+};
static XlcConv
-open_strtocs(from_lcd, from_type, to_lcd, to_type)
- XLCd from_lcd;
- char *from_type;
- XLCd to_lcd;
- char *to_type;
+open_strtocs(
+ XLCd from_lcd,
+ const char *from_type,
+ XLCd to_lcd,
+ const char *to_type)
{
return create_conv(&strtocs_methods);
}
+
static XlcConvMethodsRec cstostr_methods = {
close_converter,
cstostr,
init_state
-} ;
+};
static XlcConv
-open_cstostr(from_lcd, from_type, to_lcd, to_type)
- XLCd from_lcd;
- char *from_type;
- XLCd to_lcd;
- char *to_type;
+open_cstostr(
+ XLCd from_lcd,
+ const char *from_type,
+ XLCd to_lcd,
+ const char *to_type)
{
return create_conv(&cstostr_methods);
}
-static void
-init_converter()
+
+/* =========================== Initialization =========================== */
+
+Bool
+_XlcInitCTInfo()
{
- _XlcSetConverter((XLCd) NULL, XlcNCompoundText, (XLCd) NULL, XlcNCharSet,
- open_cttocs);
- _XlcSetConverter((XLCd) NULL, XlcNString, (XLCd) NULL, XlcNCharSet,
- open_strtocs);
-
- _XlcSetConverter((XLCd) NULL, XlcNCharSet, (XLCd) NULL, XlcNCompoundText,
- open_cstoct);
- _XlcSetConverter((XLCd) NULL, XlcNCharSet, (XLCd) NULL, XlcNString,
- open_cstostr);
+ if (ct_list == NULL) {
+ CTData ct_data;
+ int num;
+ XlcCharSet charset;
+
+ /* Initialize ct_list. */
+
+ num = sizeof(default_ct_data) / sizeof(CTDataRec);
+ for (ct_data = default_ct_data; num > 0; ct_data++, num--) {
+ charset = _XlcAddCT(ct_data->name, ct_data->ct_sequence);
+ if (charset == NULL)
+ continue;
+ if (strncmp(charset->ct_sequence, "\x1b\x25\x2f", 3) != 0)
+ charset->source = CSsrcStd;
+ else
+ charset->source = CSsrcXLC;
+ }
+
+ /* Register CompoundText and CharSet converters. */
+
+ _XlcSetConverter((XLCd) NULL, XlcNCompoundText,
+ (XLCd) NULL, XlcNCharSet,
+ open_cttocs);
+ _XlcSetConverter((XLCd) NULL, XlcNString,
+ (XLCd) NULL, XlcNCharSet,
+ open_strtocs);
+
+ _XlcSetConverter((XLCd) NULL, XlcNCharSet,
+ (XLCd) NULL, XlcNCompoundText,
+ open_cstoct);
+ _XlcSetConverter((XLCd) NULL, XlcNCharSet,
+ (XLCd) NULL, XlcNString,
+ open_cstostr);
+ }
+
+ return True;
}