summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:48:57 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:48:57 +0000
commit84208ce0135c0376208346d20a76add90d52aae4 (patch)
treedca4ed09085fca4e70c618e96caa84ec3b42b3cc
Initial revisionXORG-STABLE
-rw-r--r--charset.c491
-rw-r--r--charset.h71
-rw-r--r--iso2022.c929
-rw-r--r--iso2022.h94
-rw-r--r--locale.c5
-rw-r--r--luit.c593
-rw-r--r--luit.h31
-rw-r--r--luit.man221
-rw-r--r--other.c246
-rw-r--r--other.h63
-rw-r--r--parser.c211
-rw-r--r--parser.h35
-rw-r--r--sys.c457
-rw-r--r--sys.h33
14 files changed, 3480 insertions, 0 deletions
diff --git a/charset.c b/charset.c
new file mode 100644
index 0000000..e262689
--- /dev/null
+++ b/charset.c
@@ -0,0 +1,491 @@
+/*
+Copyright (c) 2001 by Juliusz Chroboczek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+/* $XFree86: xc/programs/luit/charset.c,v 1.7 2003/02/24 01:10:25 dawes Exp $ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <X11/fonts/fontenc.h>
+#include "other.h"
+#include "charset.h"
+#include "parser.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+static unsigned int
+IdentityRecode(unsigned int n, CharsetPtr self)
+{
+ return n;
+}
+
+static int
+IdentityReverse(unsigned int n, CharsetPtr self)
+{
+#define IS_GL(n) ((n) >= 0x20 && (n) < 0x80)
+ switch(self->type) {
+ case T_94:
+ case T_96:
+ if (IS_GL(n)) return n; else return -1;
+ case T_128:
+ if (n < 0x80) return n; else return -1;
+ case T_9494:
+ case T_9696:
+ if(IS_GL(n>>8) && IS_GL(n&0xFF))
+ return n;
+ else
+ return -1;
+ case T_94192:
+ if(IS_GL(n>>8) && IS_GL(n&0x7F))
+ return n;
+ else
+ return -1;
+ default:
+ abort();
+ }
+#undef IS_GL
+}
+
+static int
+NullReverse(unsigned int n, CharsetPtr self)
+{
+ return -1;
+}
+
+CharsetRec Unknown94Charset =
+{ "Unknown (94)", T_94, 0, IdentityRecode, NullReverse, 0, 0};
+CharsetRec Unknown96Charset =
+{ "Unknown (96)", T_96, 0, IdentityRecode, NullReverse, 0, 0};
+CharsetRec Unknown9494Charset =
+{ "Unknown (94x94)", T_9494, 0, IdentityRecode, NullReverse, 0, 0};
+CharsetRec Unknown9696Charset =
+{ "Unknown (96x96)", T_9696, 0, IdentityRecode, NullReverse, 0, 0};
+
+typedef struct _FontencCharset {
+ char *name;
+ int type;
+ unsigned char final;
+ char *xlfd;
+ int shift;
+ FontMapPtr mapping;
+ FontMapReversePtr reverse;
+} FontencCharsetRec, *FontencCharsetPtr;
+
+FontencCharsetRec fontencCharsets[] = {
+ {"ISO 646 (1973)", T_94, '@', "iso646.1973-0", 0x00, 0, 0},
+ {"ASCII", T_94, 'B', "iso8859-1", 0x00, 0, 0},
+ {"JIS X 0201:GL", T_94, 'J', "jisx0201.1976-0", 0x00, 0, 0},
+ {"JIS X 0201:GR", T_94, 'I', "jisx0201.1976-0", 0x80, 0, 0},
+ {"DEC Special", T_94, '0', "dec-special", 0x00, 0, 0},
+ {"DEC Technical", T_94, '>', "dec-dectech", 0x00, 0, 0},
+
+ {"ISO 8859-1", T_96, 'A', "iso8859-1", 0x80, 0, 0},
+ {"ISO 8859-2", T_96, 'B', "iso8859-2", 0x80, 0, 0},
+ {"ISO 8859-3", T_96, 'C', "iso8859-3", 0x80, 0, 0},
+ {"ISO 8859-4", T_96, 'D', "iso8859-4", 0x80, 0, 0},
+ {"ISO 8859-5", T_96, 'L', "iso8859-5", 0x80, 0, 0},
+ {"ISO 8859-6", T_96, 'G', "iso8859-6", 0x80, 0, 0},
+ {"ISO 8859-7", T_96, 'F', "iso8859-7", 0x80, 0, 0},
+ {"ISO 8859-8", T_96, 'H', "iso8859-8", 0x80, 0, 0},
+ {"ISO 8859-9", T_96, 'M', "iso8859-9", 0x80, 0, 0},
+ {"ISO 8859-10", T_96, 'V', "iso8859-10", 0x80, 0, 0},
+ {"ISO 8859-11", T_96, 'T', "iso8859-11", 0x80, 0, 0},
+ {"TIS 620", T_96, 'T', "iso8859-11", 0x80, 0, 0},
+ {"ISO 8859-13", T_96, 'Y', "iso8859-13", 0x80, 0, 0},
+ {"ISO 8859-14", T_96, '_', "iso8859-14", 0x80, 0, 0},
+ {"ISO 8859-15", T_96, 'b', "iso8859-15", 0x80, 0, 0},
+ {"ISO 8859-16", T_96, 'f', "iso8859-16", 0x80, 0, 0},
+ {"KOI8-E", T_96, '@', "koi8-e", 0x80, 0, 0},
+ {"TCVN", T_96, 'Z', "tcvn-0", 0x80, 0, 0},
+
+ {"GB 2312", T_9494, 'A', "gb2312.1980-0", 0x0000, 0, 0},
+ {"JIS X 0208", T_9494, 'B', "jisx0208.1990-0", 0x0000, 0, 0},
+ {"KSC 5601", T_9494, 'C', "ksc5601.1987-0", 0x0000, 0, 0},
+ {"JIS X 0212", T_9494, 'D', "jisx0212.1990-0", 0x0000, 0, 0},
+
+ {"GB 2312", T_9696, 'A', "gb2312.1980-0", 0x0000, 0, 0},
+ {"JIS X 0208", T_9696, 'B', "jisx0208.1990-0", 0x0000, 0, 0},
+ {"KSC 5601", T_9696, 'C', "ksc5601.1987-0", 0x0000, 0, 0},
+ {"JIS X 0212", T_9696, 'D', "jisx0212.1990-0", 0x0000, 0, 0},
+
+ {"KOI8-R", T_128, 0, "koi8-r", 0x80, 0, 0},
+ {"KOI8-U", T_128, 0, "koi8-u", 0x80, 0, 0},
+ {"KOI8-RU", T_128, 0, "koi8-ru", 0x80, 0, 0},
+ {"CP 1252", T_128, 0, "microsoft-cp1252", 0x80, 0, 0},
+ {"CP 1251", T_128, 0, "microsoft-cp1251", 0x80, 0, 0},
+ {"CP 1250", T_128, 0, "microsoft-cp1250", 0x80, 0, 0},
+
+ {"Big 5", T_94192, 0, "big5.eten-0", 0x8000, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0}
+};
+
+typedef struct _OtherCharset {
+ char *name;
+ int (*init)(OtherStatePtr);
+ unsigned int (*mapping)(unsigned int, OtherStatePtr);
+ unsigned int (*reverse)(unsigned int, OtherStatePtr);
+ int (*stack)(unsigned char, OtherStatePtr);
+} OtherCharsetRec, *OtherCharsetPtr;
+
+OtherCharsetRec otherCharsets[] = {
+ {"GBK", init_gbk, mapping_gbk, reverse_gbk, stack_gbk},
+ {"UTF-8", init_utf8, mapping_utf8, reverse_utf8, stack_utf8},
+ {"SJIS", init_sjis, mapping_sjis, reverse_sjis, stack_sjis},
+ {0, 0, 0, 0, 0}
+};
+
+static int
+compare(char *s, char *t)
+{
+ while(*s || *t) {
+ if(*s && (isspace(*s) || *s == '-' || *s == '_'))
+ s++;
+ else if(*t && (isspace(*t) || *t == '-' || *t == '_'))
+ t++;
+ else if(*s && *t && tolower(*s) == tolower(*t)) {
+ s++;
+ t++;
+ } else
+ return 1;
+ }
+ return 0;
+}
+
+static unsigned int
+FontencCharsetRecode(unsigned int n, CharsetPtr self)
+{
+ FontencCharsetPtr fc = (FontencCharsetPtr)(self->data);
+
+ return FontEncRecode(n + fc->shift, fc->mapping);
+}
+
+static int
+FontencCharsetReverse(unsigned int i, CharsetPtr self)
+{
+ FontencCharsetPtr fc = (FontencCharsetPtr)(self->data);
+ int n;
+
+ n = fc->reverse->reverse(i, fc->reverse->data);
+ if(n == 0 || n < fc->shift)
+ return -1;
+ else
+ n -= fc->shift;
+
+#define IS_GL(n) ((n) >= 0x20 && (n) < 0x80)
+ switch(self->type) {
+ case T_94: case T_96:
+ if (IS_GL(n)) return n; else return -1;
+ break;
+ case T_128:
+ if (n < 0x80) return n; else return -1;
+ case T_9494: case T_9696:
+ if(IS_GL(n>>8) && IS_GL(n&0xFF))
+ return n;
+ else
+ return -1;
+ break;
+ case T_94192:
+ if(IS_GL(n>>8) && IS_GL(n&0x7F))
+ return n;
+ else
+ return -1;
+ break;
+ default:
+ abort();
+ }
+#undef IS_GL
+}
+
+
+static CharsetPtr cachedCharsets = NULL;
+
+static CharsetPtr
+getCachedCharset(unsigned char final, int type, char *name)
+{
+ CharsetPtr c;
+ for(c = cachedCharsets; c; c = c->next) {
+ if(((c->type == type && c->final == final) ||
+ (name && !compare(c->name, name))) &&
+ (c->type != T_FAILED))
+ return c;
+ }
+ return NULL;
+}
+
+static void
+cacheCharset(CharsetPtr c) {
+ c->next = cachedCharsets;
+ cachedCharsets = c;
+}
+
+static CharsetPtr
+getFontencCharset(unsigned char final, int type, char *name)
+{
+ FontencCharsetPtr fc;
+ CharsetPtr c;
+ FontMapPtr mapping;
+ FontMapReversePtr reverse;
+
+ fc = fontencCharsets;
+ while(fc->name) {
+ if(((fc->type == type && fc->final == final) ||
+ (name && !compare(fc->name, name))) &&
+ (fc->type != T_FAILED))
+ break;
+ fc++;
+ }
+
+ if(!fc->name)
+ return NULL;
+
+ c = malloc(sizeof(CharsetRec));
+ if(c == NULL)
+ return NULL;
+
+ mapping = FontEncMapFind(fc->xlfd, FONT_ENCODING_UNICODE, -1, -1, NULL);
+ if(!mapping) {
+ fc->type = T_FAILED;
+ return NULL;
+ }
+
+ reverse = FontMapReverse(mapping);
+ if(!reverse) {
+ fc->type = T_FAILED;
+ return NULL;
+ }
+
+ fc->mapping = mapping;
+ fc->reverse = reverse;
+
+ c->name = fc->name;
+ c->type = fc->type;
+ c->final = fc->final;
+ c->recode = FontencCharsetRecode;
+ c->reverse = FontencCharsetReverse;
+ c->data = fc;
+
+ cacheCharset(c);
+ return c;
+}
+
+static CharsetPtr
+getOtherCharset(char *name)
+{
+ OtherCharsetPtr fc;
+ CharsetPtr c;
+ OtherStatePtr s;
+
+ fc = otherCharsets;
+ while(fc->name) {
+ if(name && !compare(fc->name, name))
+ break;
+ fc++;
+ }
+
+ if(!fc->name)
+ return NULL;
+
+ c = malloc(sizeof(CharsetRec));
+ if(c == NULL)
+ return NULL;
+
+ s = malloc(sizeof(OtherState));
+ if(s == NULL) {
+ free(c);
+ return NULL;
+ }
+
+ c->name = fc->name;
+ c->type = T_OTHER;
+ c->final = 0;
+ c->data = fc;
+ c->other_recode = fc->mapping;
+ c->other_reverse = fc->reverse;
+ c->other_stack = fc->stack;
+ c->other_aux = s;
+
+ if(!fc->init(s)) {
+ c->type = T_FAILED;
+ return NULL;
+ }
+
+ cacheCharset(c);
+ return c;
+}
+
+CharsetPtr
+getUnknownCharset(int type)
+{
+ switch(type) {
+ case T_94: return &Unknown94Charset;
+ case T_96: return &Unknown96Charset;
+ case T_9494: return &Unknown9494Charset;
+ case T_9696: return &Unknown9696Charset;
+ default: return &Unknown94Charset;
+ }
+}
+
+CharsetPtr
+getCharset(unsigned char final, int type)
+{
+ CharsetPtr c;
+
+ c = getCachedCharset(final, type, NULL);
+ if(c)
+ return c;
+
+ c = getFontencCharset(final, type, NULL);
+ if(c)
+ return c;
+
+ return getUnknownCharset(type);
+}
+
+CharsetPtr
+getCharsetByName(char *name)
+{
+ CharsetPtr c;
+
+ if(name == NULL)
+ return getUnknownCharset(T_94);
+
+ c = getCachedCharset(0, 0, name);
+ if(c)
+ return c;
+
+ c = getFontencCharset(0, 0, name);
+ if(c)
+ return c;
+
+ c = getOtherCharset(name);
+ if(c)
+ return c;
+
+ return getUnknownCharset(T_94);
+}
+
+LocaleCharsetRec localeCharsets[] = {
+ { "C", 0, 2, "ASCII", NULL, "ISO 8859-1", NULL, NULL},
+ { "POSIX", 0, 2, "ASCII", NULL, "ISO 8859-1", NULL, NULL},
+ { "ISO8859-1", 0, 2, "ASCII", NULL, "ISO 8859-1", NULL, NULL},
+ { "ISO8859-2", 0, 2, "ASCII", NULL, "ISO 8859-2", NULL, NULL},
+ { "ISO8859-3", 0, 2, "ASCII", NULL, "ISO 8859-3", NULL, NULL},
+ { "ISO8859-4", 0, 2, "ASCII", NULL, "ISO 8859-4", NULL, NULL},
+ { "ISO8859-5", 0, 2, "ASCII", NULL, "ISO 8859-5", NULL, NULL},
+ { "ISO8859-6", 0, 2, "ASCII", NULL, "ISO 8859-6", NULL, NULL},
+ { "ISO8859-7", 0, 2, "ASCII", NULL, "ISO 8859-7", NULL, NULL},
+ { "ISO8859-8", 0, 2, "ASCII", NULL, "ISO 8859-8", NULL, NULL},
+ { "ISO8859-9", 0, 2, "ASCII", NULL, "ISO 8859-9", NULL, NULL},
+ { "ISO8859-10", 0, 2, "ASCII", NULL, "ISO 8859-10", NULL, NULL},
+ { "ISO8859-11", 0, 2, "ASCII", NULL, "ISO 8859-11", NULL, NULL},
+ { "TIS620", 0, 2, "ASCII", NULL, "ISO 8859-11", NULL, NULL},
+ { "ISO8859-13", 0, 2, "ASCII", NULL, "ISO 8859-13", NULL, NULL},
+ { "ISO8859-14", 0, 2, "ASCII", NULL, "ISO 8859-14", NULL, NULL},
+ { "ISO8859-15", 0, 2, "ASCII", NULL, "ISO 8859-15", NULL, NULL},
+ { "ISO8859-16", 0, 2, "ASCII", NULL, "ISO 8859-16", NULL, NULL},
+ { "KOI8-R", 0, 2, "ASCII", NULL, "KOI8-R", NULL, NULL},
+ { "CP1251", 0, 2, "ASCII", NULL, "CP 1251", NULL, NULL},
+ { "TCVN", 0, 2, "ASCII", NULL, "TCVN", NULL, NULL},
+ { "eucCN", 0, 1, "ASCII", "GB 2312", NULL, NULL, NULL},
+ { "GB2312", 0, 1, "ASCII", "GB 2312", NULL, NULL, NULL},
+ { "eucJP", 0, 1, "ASCII", "JIS X 0208", "JIS X 0201:GR", "JIS X 0212", NULL},
+ { "eucKR", 0, 1, "ASCII", "KSC 5601", NULL, NULL, NULL},
+ { "eucCN", 0, 1, "ASCII", "GB 2312", NULL, NULL, NULL},
+ { "Big5", 0, 1, "ASCII", "Big 5", NULL, NULL, NULL},
+ { "gbk", 0, 1, NULL, NULL, NULL, NULL, "GBK"},
+ { "UTF-8", 0, 1, NULL, NULL, NULL, NULL, "UTF-8"},
+ { "SJIS", 0, 1, NULL, NULL, NULL, NULL, "SJIS"},
+ { 0, 0, 0, 0, 0, 0, 0}
+};
+
+void
+reportCharsets()
+{
+ LocaleCharsetPtr p;
+ FontencCharsetPtr q;
+ printf("Known locale encodings:\n\n");
+ for(p = localeCharsets; p->name; p++) {
+ if(p->other) {
+ printf(" %s (non-ISO-2022 encoding)\n", p->other);
+ continue;
+ }
+ printf(" %s: GL -> G%d, GR -> G%d", p->name, p->gl, p->gr);
+ if(p->g0) printf(", G0: %s", p->g0);
+ if(p->g1) printf(", G1: %s", p->g1);
+ if(p->g2) printf(", G2: %s", p->g2);
+ if(p->g3) printf(", G3: %s", p->g3);
+ printf("\n");
+ }
+
+ printf("\n\nKnown charsets (not all may be available):\n\n");
+ for(q = fontencCharsets; q->name; q++)
+ printf(" %s%s\n",
+ q->name, q->final?" (ISO 2022)":"");
+}
+
+int
+getLocaleState(char *locale, char *charset,
+ int *gl_return, int *gr_return,
+ CharsetPtr *g0_return, CharsetPtr *g1_return,
+ CharsetPtr *g2_return, CharsetPtr *g3_return,
+ CharsetPtr *other_return)
+{
+ char *resolved = 0;
+ LocaleCharsetPtr p;
+
+ if(!charset) {
+ resolved = resolveLocale(locale);
+ if(!resolved)
+ return -1;
+ charset = strrchr(resolved, '.');
+ if(charset)
+ charset++;
+ else
+ charset = resolved;
+ }
+
+ for(p = localeCharsets; p->name; p++) {
+ if(compare(p->name, charset) == 0)
+ break;
+ }
+
+ if(p->name == NULL) {
+ if (resolved != 0)
+ free(resolved);
+ return -1;
+ }
+
+ *gl_return = p->gl;
+ *gr_return = p->gr;
+ *g0_return = getCharsetByName(p->g0);
+ *g1_return = getCharsetByName(p->g1);
+ *g2_return = getCharsetByName(p->g2);
+ *g3_return = getCharsetByName(p->g3);
+ if(p->other)
+ *other_return = getCharsetByName(p->other);
+ else
+ *other_return = NULL;
+ return 0;
+}
+
diff --git a/charset.h b/charset.h
new file mode 100644
index 0000000..bff6d3a
--- /dev/null
+++ b/charset.h
@@ -0,0 +1,71 @@
+/*
+Copyright (c) 2001 by Juliusz Chroboczek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+/* $XFree86: xc/programs/luit/charset.h,v 1.4 2002/10/17 01:06:09 dawes Exp $ */
+
+#define T_FAILED 0
+#define T_94 1
+#define T_96 2
+#define T_128 3
+#define T_9494 4
+#define T_9696 5
+/* Big 5 */
+#define T_94192 6
+#define T_OTHER 7
+
+/* True for charsets that pass control chars unchanged, at least in
+ the first byte */
+#define CHARSET_REGULAR(c) ((c)->type != T_128)
+
+typedef struct _Charset {
+ char *name;
+ int type;
+ unsigned char final;
+ unsigned int (*recode)(unsigned int, struct _Charset *self);
+ int (*reverse)(unsigned int, struct _Charset *self);
+ void *data;
+ int (*other_stack)(unsigned char c, OtherStatePtr aux);
+ OtherState *other_aux;
+ unsigned int (*other_recode)(unsigned int c, OtherStatePtr aux);
+ unsigned int (*other_reverse)(unsigned int c, OtherStatePtr aux);
+ struct _Charset *next;
+} CharsetRec, *CharsetPtr;
+
+typedef struct _LocaleCharset {
+ char *name;
+ int gl;
+ int gr;
+ char *g0;
+ char *g1;
+ char *g2;
+ char *g3;
+ char *other;
+} LocaleCharsetRec, *LocaleCharsetPtr;
+
+CharsetPtr getUnknownCharset(int);
+CharsetPtr getCharset(unsigned char, int);
+CharsetPtr getCharsetByName(char*);
+void reportCharsets(void);
+int getLocaleState(char *locale, char *charset,
+ int *gl_return, int *gr_return,
+ CharsetPtr *g0_return, CharsetPtr *g1_return,
+ CharsetPtr *g2_return, CharsetPtr *g3_return,
+ CharsetPtr *other_return);
diff --git a/iso2022.c b/iso2022.c
new file mode 100644
index 0000000..0b9a9e4
--- /dev/null
+++ b/iso2022.c
@@ -0,0 +1,929 @@
+/*
+Copyright (c) 2001 by Juliusz Chroboczek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+/* $XFree86: xc/programs/luit/iso2022.c,v 1.9 2002/12/08 20:19:49 dickey Exp $ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <X11/fonts/fontenc.h>
+#include "luit.h"
+#include "sys.h"
+#include "other.h"
+#include "charset.h"
+#include "iso2022.h"
+
+#define BUFFERED_INPUT_SIZE 4
+unsigned char buffered_input[BUFFERED_INPUT_SIZE];
+int buffered_input_count = 0;
+
+static void
+FatalError(char *f, ...)
+{
+ va_list args;
+ va_start(args, f);
+ vfprintf(stderr, f, args);
+ va_end(args);
+ exit(1);
+}
+
+static void
+ErrorF(char *f, ...)
+{
+ va_list args;
+ va_start(args, f);
+ vfprintf(stderr, f, args);
+ va_end(args);
+}
+
+#define OUTBUF_FREE(is, count) ((is)->outbuf_count + (count) <= BUFFER_SIZE)
+#define OUTBUF_MAKE_FREE(is, fd, count) \
+ if(!OUTBUF_FREE((is), (count))) outbuf_flush((is), (fd))
+
+
+static void
+outbuf_flush(Iso2022Ptr is, int fd)
+{
+ int rc;
+ int i = 0;
+
+ if(olog >= 0)
+ write(olog, is->outbuf, is->outbuf_count);
+
+ while(i < is->outbuf_count) {
+ rc = write(fd, is->outbuf + i, is->outbuf_count - i);
+ if(rc > 0) {
+ i += rc;
+ } else {
+ if(rc < 0 && errno == EINTR)
+ continue;
+ else if((rc == 0) || ((rc < 0) && (errno == EAGAIN))) {
+ waitForOutput(fd);
+ continue;
+ } else
+ break;
+ }
+ }
+ is->outbuf_count = 0;
+}
+
+static void
+outbufOne(Iso2022Ptr is, int fd, unsigned c)
+{
+ OUTBUF_MAKE_FREE(is, fd, 1);
+ is->outbuf[is->outbuf_count++] = c;
+}
+
+/* Discards null codepoints */
+static void
+outbufUTF8(Iso2022Ptr is, int fd, unsigned c)
+{
+ if(c == 0)
+ return;
+
+ if(c <= 0x7F) {
+ OUTBUF_MAKE_FREE(is, fd, 1);
+ is->outbuf[is->outbuf_count++] = c;
+ } else if(c <= 0x7FF) {
+ OUTBUF_MAKE_FREE(is, fd, 2);
+ is->outbuf[is->outbuf_count++] = 0xC0 | ((c >> 6) & 0x1F);
+ is->outbuf[is->outbuf_count++] = 0x80 | (c & 0x3F);
+ } else {
+ OUTBUF_MAKE_FREE(is, fd, 3);
+ is->outbuf[is->outbuf_count++] = 0xE0 | ((c >> 12) & 0x0F);
+ is->outbuf[is->outbuf_count++] = 0x80 | ((c >> 6) & 0x3F);
+ is->outbuf[is->outbuf_count++] = 0x80 | (c & 0x3F);
+ }
+}
+
+static void
+buffer(Iso2022Ptr is, char c)
+{
+ if(is->buffered == NULL) {
+ is->buffered = malloc(10);
+ if(is->buffered == NULL)
+ FatalError("Couldn't allocate buffered.\n");
+ is->buffered_len = 10;
+ }
+
+ if(is->buffered_count >= is->buffered_len) {
+ is->buffered = realloc(is->buffered, 2 * is->buffered_len + 1);
+ if(is->buffered == NULL) {
+ FatalError("Couldn't grow buffered.\n");
+ }
+ is->buffered_len = 2 * is->buffered_len + 1;
+ }
+
+ is->buffered[is->buffered_count++] = c;
+}
+
+static void
+outbuf_buffered_carefully(Iso2022Ptr is, int fd)
+{
+ /* This should never happen in practice */
+ int i = 0;
+
+ while(i < is->buffered_count) {
+ OUTBUF_MAKE_FREE(is, fd, 1);
+ is->outbuf[is->outbuf_count++] = is->buffered[i++];
+ }
+ is->buffered_count = 0;
+}
+
+static void
+outbuf_buffered(Iso2022Ptr is, int fd)
+{
+ if(is->buffered_count > BUFFER_SIZE)
+ outbuf_buffered_carefully(is, fd);
+
+ OUTBUF_MAKE_FREE(is, fd, is->buffered_count);
+ memcpy(is->outbuf + is->outbuf_count, is->buffered, is->buffered_count);
+ is->outbuf_count += is->buffered_count;
+ is->buffered_count = 0;
+}
+
+static void
+discard_buffered(Iso2022Ptr is)
+{
+ is->buffered_count = 0;
+}
+
+Iso2022Ptr
+allocIso2022(void)
+{
+ Iso2022Ptr is;
+ is = malloc(sizeof(Iso2022Rec));
+ if(!is)
+ return NULL;
+ is->glp = is->grp = NULL;
+ G0(is) = G1(is) = G2(is) = G3(is) = OTHER(is) = NULL;
+
+ is->parserState = P_NORMAL;
+ is->shiftState = S_NORMAL;
+
+ is->inputFlags = IF_EIGHTBIT | IF_SS | IF_SSGR;
+ is->outputFlags = OF_SS | OF_LS | OF_SELECT;
+
+ is->buffered = NULL;
+ is->buffered_len = 0;
+ is->buffered_count = 0;
+
+ is->buffered_ku = -1;
+
+ is->outbuf = malloc(BUFFER_SIZE);
+ if(!is->outbuf) {
+ free(is);
+ return NULL;
+ }
+ is->outbuf_count = 0;
+
+ return is;
+}
+
+void
+destroyIso2022(Iso2022Ptr is)
+{
+ if(is->buffered)
+ free(is->buffered);
+ if(is->outbuf)
+ free(is->outbuf);
+ free(is);
+}
+
+static int
+identifyCharset(Iso2022Ptr i, CharsetPtr *p)
+{
+ if(p == &G0(i))
+ return 0;
+ else if(p == &G1(i))
+ return 1;
+ else if(p == &G2(i))
+ return 2;
+ else if(p == &G3(i))
+ return 3;
+ else
+ abort();
+}
+
+void
+reportIso2022(Iso2022Ptr i)
+{
+ if(OTHER(i) != NULL) {
+ fprintf(stderr, "%s, non-ISO-2022 encoding.\n", OTHER(i)->name);
+ return;
+ }
+ fprintf(stderr, "G0 is %s, ", G0(i)->name);
+ fprintf(stderr, "G1 is %s, ", G1(i)->name);
+ fprintf(stderr, "G2 is %s, ", G2(i)->name);
+ fprintf(stderr, "G3 is %s.\n", G3(i)->name);
+ fprintf(stderr, "GL is G%d, ", identifyCharset(i, i->glp));
+ fprintf(stderr, "GR is G%d.\n", identifyCharset(i, i->grp));
+}
+
+int
+initIso2022(char *locale, char *charset, Iso2022Ptr i)
+{
+ int gl = 0, gr = 2;
+ CharsetPtr g0 = NULL, g1 = NULL, g2 = NULL, g3 = NULL, other = NULL;
+ int rc;
+
+ rc = getLocaleState(locale, charset, &gl, &gr, &g0, &g1, &g2, &g3, &other);
+ if(rc < 0) {
+ if(charset)
+ ErrorF("Warning: couldn't find charset %s; "
+ "using ISO 8859-1.\n", charset);
+ else
+ ErrorF("Warning: couldn't find charset data for locale %s; "
+ "using ISO 8859-1.\n", locale);
+ }
+
+ if(g0)
+ G0(i) = g0;
+ else
+ G0(i) = getCharsetByName("ASCII");
+
+ if(g1)
+ G1(i) = g1;
+ else
+ G1(i) = getUnknownCharset(T_94);
+
+ if(g2)
+ G2(i) = g2;
+ else
+ G2(i) = getCharsetByName("ISO 8859-1");
+
+ if(g3)
+ G3(i) = g3;
+ else
+ G3(i) = getUnknownCharset(T_94);
+
+ if(other)
+ OTHER(i) = other;
+ else
+ OTHER(i) = NULL;
+
+ i->glp = &i->g[gl];
+ i->grp = &i->g[gr];
+ return 0;
+}
+
+int
+mergeIso2022(Iso2022Ptr d, Iso2022Ptr s)
+{
+ if(G0(d) == NULL)
+ G0(d) = G0(s);
+ if(G1(d) == NULL)
+ G1(d) = G1(s);
+ if(G2(d) == NULL)
+ G2(d) = G2(s);
+ if(G3(d) == NULL)
+ G3(d) = G3(s);
+ if(OTHER(d) == NULL)
+ OTHER(d) = OTHER(s);
+ if(d->glp == NULL)
+ d->glp = &(d->g[identifyCharset(s, s->glp)]);
+ if(d->grp == NULL)
+ d->grp = &(d->g[identifyCharset(s, s->grp)]);
+ return 0;
+}
+
+static int
+utf8Count(unsigned char c)
+{
+ /* All return values must be less than BUFFERED_INPUT_SIZE */
+ if((c & 0x80) == 0)
+ return 1;
+ else if((c & 0x40) == 0)
+ return 1; /* incorrect UTF-8 */
+ else if((c & 0x60) == 0x40)
+ return 2;
+ else if((c & 0x70) == 0x60)
+ return 3;
+ else if((c & 0x78) == 0x70)
+ return 4;
+ else
+ return 1;
+}
+
+static int
+fromUtf8(unsigned char *b)
+{
+ if((b[0] & 0x80) == 0)
+ return b[0];
+ else if((b[0] & 0x40) == 0)
+ return -1; /* incorrect UTF-8 */
+ else if((b[0] & 0x60) == 0x40)
+ return ((b[0] & 0x1F) << 6) | (b[1] & 0x3F);
+ else if((b[0] & 0x70) == 0x60)
+ return ((b[0] & 0x0F) << 12)
+ | ((b[1] & 0x3F) << 6)
+ | (b[2] & 0x3F);
+ else if((b[0] & 0x78) == 0x70)
+ return ((b[0] & 0x03) << 18)
+ | ((b[1] & 0x3F) << 12)
+ | ((b[2] & 0x3F) << 6)
+ | ((b[3] & 0x3F));
+ else
+ return -1;
+}
+
+void
+copyIn(Iso2022Ptr is, int fd, unsigned char *buf, int count)
+{
+ unsigned char *c;
+ int codepoint, rem;
+
+ c = buf;
+ rem = count;
+
+#define NEXT do {c++; rem--;} while(0)
+
+ while(rem) {
+ codepoint = -1;
+ if(is->parserState == P_ESC) {
+ assert(buffered_input_count == 0);
+ codepoint = *c;
+ NEXT;
+ if(*c == CSI_7)
+ is->parserState = P_CSI;
+ else if(IS_FINAL_ESC(codepoint))
+ is->parserState = P_NORMAL;
+ } else if(is->parserState == P_CSI) {
+ assert(buffered_input_count == 0);
+ codepoint = *c;
+ NEXT;
+ if(IS_FINAL_CSI(codepoint))
+ is->parserState = P_NORMAL;
+ } else if(!(*c & 0x80)) {
+ if(buffered_input_count > 0) {
+ buffered_input_count = 0;
+ continue;
+ } else {
+ codepoint = *c;
+ NEXT;
+ if(codepoint == ESC)
+ is->parserState = P_ESC;
+ }
+ } else if((*c & 0x40)) {
+ if(buffered_input_count > 0) {
+ buffered_input_count = 0;
+ continue;
+ } else {
+ buffered_input[buffered_input_count] = *c;
+ buffered_input_count++;
+ NEXT;
+ }
+ } else {
+ if(buffered_input_count <= 0) {
+ buffered_input_count = 0;
+ NEXT;
+ continue;
+ } else {
+ buffered_input[buffered_input_count] = *c;
+ buffered_input_count++;
+ NEXT;
+ if(buffered_input_count >= utf8Count(buffered_input[0])) {
+ codepoint = fromUtf8(buffered_input);
+ buffered_input_count = 0;
+ if(codepoint == CSI)
+ is->parserState = P_CSI;
+ }
+ }
+ }
+#undef NEXT
+
+ if(codepoint >= 0) {
+ int i;
+ unsigned char obuf[4];
+#define WRITE_1(i) do {obuf[0]=(i); write(fd, obuf, 1);} while(0)
+#define WRITE_2(i) do \
+ {obuf[0]=((i)>>8)&0xFF; obuf[1]=(i)&0xFF; write(fd, obuf, 2);} \
+ while(0)
+#define WRITE_3(i) do \
+ {obuf[0]=((i)>>16)&0xFF; obuf[1]=((i)>>8)&0xFF; obuf[2]=(i)&0xFF; \
+ write(fd, obuf, 3);} \
+ while(0)
+#define WRITE_4(i) do \
+ {obuf[0]=((i)>>24)&0xFF; obuf[1]=((i)>>16)&0xFF; obuf[2]=((i)>>8)&0xFF; \
+ obuf[3]=(i)&0xFF; write(fd, obuf, 4);} \
+ while(0)
+#define WRITE_1_P_8bit(p, i) \
+ {obuf[0]=(p); obuf[1]=(i); write(fd, obuf, 2);}
+#define WRITE_1_P_7bit(p, i) \
+ {obuf[0]=ESC; obuf[1]=(p)-0x40; obuf[2]=(i); write(fd, obuf, 3);}
+#define WRITE_1_P(p,i) do \
+ {if(is->inputFlags & IF_EIGHTBIT) \
+ WRITE_1_P_8bit(p,i) else \
+ WRITE_1_P_7bit(p,i) } \
+ while(0)
+#define WRITE_2_P_8bit(p, i) \
+ {obuf[0]=(p); obuf[1]=((i)>>8)&0xFF; obuf[2]=(i)&0xFF; write(fd, obuf, 3);}
+#define WRITE_2_P_7bit(p, i) \
+ {obuf[0]=ESC; obuf[1]=(p)-0x40; obuf[2]=((i)>>8)&0xFF; obuf[3]=(i)&0xFF; \
+ write(fd, obuf, 4);}
+#define WRITE_2_P(p,i) do \
+ {if(is->inputFlags & IF_EIGHTBIT) \
+ WRITE_2_P_8bit(p,i) else \
+ WRITE_2_P_7bit(p,i)} \
+ while(0)
+#define WRITE_1_P_S(p,i,s) do \
+ {obuf[0]=(p); obuf[1]=(i)&0xFF; obuf[2]=(s); write(fd, obuf, 3);} \
+ while(0)
+#define WRITE_2_P_S(p,i,s) do \
+ {obuf[0]=(p); obuf[1]=(((i)>>8)&0xFF); obuf[2]=(i)&0xFF; obuf[3]=(s); \
+ write(fd, obuf, 4);} \
+ while(0)
+
+ if(codepoint < 0x20 ||
+ (OTHER(is) == NULL && CHARSET_REGULAR(GR(is)) &&
+ (codepoint >= 0x80 && codepoint < 0xA0))) {
+ WRITE_1(codepoint);
+ continue;
+ }
+ if(OTHER(is) != NULL) {
+ unsigned int c;
+ c = OTHER(is)->other_reverse(codepoint, OTHER(is)->other_aux);
+ if(c>>24) WRITE_4(c);
+ else if (c>>16) WRITE_3(c);
+ else if (c>>8) WRITE_2(c);
+ else if (c) WRITE_1(c);
+ continue;
+ }
+ i = (GL(is)->reverse)(codepoint, GL(is));
+ if(i >= 0) {
+ switch(GL(is)->type) {
+ case T_94: case T_96: case T_128:
+ if(i >= 0x20)
+ WRITE_1(i);
+ break;
+ case T_9494: case T_9696: case T_94192:
+ if(i >= 0x2020)
+ WRITE_2(i);
+ break;
+ default:
+ abort();
+ }
+ continue;
+ }
+ if(is->inputFlags & IF_EIGHTBIT) {
+ i = GR(is)->reverse(codepoint, GR(is));
+ if(i >= 0) {
+ switch(GR(is)->type) {
+ case T_94: case T_96: case T_128:
+ /* we allow C1 characters if T_128 in GR */
+ WRITE_1(i | 0x80);
+ break;
+ case T_9494: case T_9696:
+ WRITE_2(i | 0x8080);
+ break;
+ case T_94192:
+ WRITE_2(i | 0x8000);
+ break;
+ default:
+ abort();
+ }
+ continue;
+ }
+ }
+ if(is->inputFlags & IF_SS) {
+ i = G2(is)->reverse(codepoint, G2(is));
+ if(i >= 0) {
+ switch(GR(is)->type) {
+ case T_94: case T_96: case T_128:
+ if(i >= 0x20) {
+ if((is->inputFlags & IF_EIGHTBIT) &&
+ (is->inputFlags & IF_SSGR))
+ i |= 0x80;
+ WRITE_1_P(SS2, i);
+ }
+ break;
+ case T_9494: case T_9696:
+ if(i >= 0x2020) {
+ if((is->inputFlags & IF_EIGHTBIT) &&
+ (is->inputFlags & IF_SSGR))
+ i |= 0x8080;
+ WRITE_2_P(SS2, i);
+ }
+ break;
+ case T_94192:
+ if(i >= 0x2020) {
+ if((is->inputFlags & IF_EIGHTBIT) &&
+ (is->inputFlags & IF_SSGR))
+ i |= 0x8000;
+ WRITE_2_P(SS2, i);
+ }
+ break;
+ default:
+ abort();
+ }
+ continue;
+ }
+ }
+ if(is->inputFlags & IF_SS) {
+ i = G3(is)->reverse(codepoint, G3(is));
+ switch(GR(is)->type) {
+ case T_94: case T_96: case T_128:
+ if(i >= 0x20) {
+ if((is->inputFlags & IF_EIGHTBIT) &&
+ (is->inputFlags & IF_SSGR))
+ i |= 0x80;
+ WRITE_1_P(SS3, i);
+ }
+ break;
+ case T_9494: case T_9696:
+ if(i >= 0x2020) {
+ if((is->inputFlags & IF_EIGHTBIT) &&
+ (is->inputFlags & IF_SSGR))
+ i |= 0x8080;
+ WRITE_2_P(SS3, i);
+ }
+ break;
+ case T_94192:
+ if(i >= 0x2020) {
+ if((is->inputFlags & IF_EIGHTBIT) &&
+ (is->inputFlags & IF_SSGR))
+ i |= 0x8000;
+ WRITE_2_P(SS3, i);
+ }
+ break;
+ default:
+ abort();
+ }
+ continue;
+ }
+ if(is->inputFlags & IF_LS) {
+ i = GR(is)->reverse(codepoint, GR(is));
+ if(i >= 0) {
+ switch(GR(is)->type) {
+ case T_94: case T_96: case T_128:
+ WRITE_1_P_S(LS1, i, LS0);
+ break;
+ case T_9494: case T_9696:
+ WRITE_2_P_S(LS1, i, LS0);
+ break;
+ case T_94192:
+ WRITE_2_P_S(LS1, i, LS0);
+ break;
+ default:
+ abort();
+ }
+ continue;
+ }
+ }
+#undef WRITE_1
+#undef WRITE_2
+#undef WRITE_1_P
+#undef WRITE_1_P_7bit
+#undef WRITE_1_P_8bit
+#undef WRITE_2_P
+#undef WRITE_2_P_7bit
+#undef WRITE_2_P_8bit
+ }
+ }
+}
+
+void
+copyOut(Iso2022Ptr is, int fd, unsigned char *buf, int count)
+{
+ unsigned char *s = buf;
+
+ if(ilog >= 0)
+ write(ilog, buf, count);
+
+ while(s < buf + count) {
+ switch(is->parserState) {
+ case P_NORMAL:
+ resynch:
+ if(is->buffered_ku < 0) {
+ if(*s == ESC) {
+ buffer(is, *s++);
+ is->parserState = P_ESC;
+ } else if(OTHER(is) != NULL) {
+ int c = OTHER(is)->other_stack(*s, OTHER(is)->other_aux);
+ if(c >= 0) {
+ outbufUTF8(is, fd, OTHER(is)->other_recode(c, OTHER(is)->other_aux));
+ is->shiftState = S_NORMAL;
+ }
+ s++;
+ } else if(*s == CSI && CHARSET_REGULAR(GR(is))) {
+ buffer(is, *s++);
+ is->parserState = P_CSI;
+ } else if((*s == SS2 || *s == SS3 || *s == LS0 || *s == LS1) &&
+ CHARSET_REGULAR(GR(is))) {
+ buffer(is, *s++);
+ terminate(is, fd);
+ is->parserState = P_NORMAL;
+ } else if (*s <= 0x20 && is->shiftState == S_NORMAL) {
+ /* Pass through C0 when GL is not regular */
+ outbufOne(is, fd, *s);
+ s++;
+ } else {
+ CharsetPtr charset;
+ unsigned char code = 0;
+ if(*s <= 0x7F) {
+ switch(is->shiftState) {
+ case S_NORMAL: charset = GL(is); break;
+ case S_SS2: charset = G2(is); break;
+ case S_SS3: charset = G3(is); break;
+ default: abort();
+ }
+ code = *s;
+ } else {
+ switch(is->shiftState) {
+ case S_NORMAL: charset = GR(is); break;
+ case S_SS2: charset = G2(is); break;
+ case S_SS3: charset = G3(is); break;
+ default: abort();
+ }
+ code = *s - 0x80;
+ }
+
+ switch(charset->type) {
+ case T_94:
+ if(code >= 0x21 && code <= 0x7E)
+ outbufUTF8(is, fd, charset->recode(code, charset));
+ else
+ outbufUTF8(is, fd, *s);
+ s++;
+ is->shiftState = S_NORMAL;
+ break;
+ case T_96:
+ if(code >= 0x20)
+ outbufUTF8(is, fd, charset->recode(code, charset));
+ else
+ outbufUTF8(is, fd, *s);
+ is->shiftState = S_NORMAL;
+ s++;
+ break;
+ case T_128:
+ outbufUTF8(is, fd, charset->recode(code, charset));
+ is->shiftState = S_NORMAL;
+ s++;
+ break;
+ default:
+ /* First byte of a multibyte sequence */
+ is->buffered_ku = *s;
+ s++;
+ }
+ }
+ } else { /* buffered_ku */
+ CharsetPtr charset;
+ unsigned char ku_code;
+ unsigned code = 0;
+ if(is->buffered_ku <= 0x7F) {
+ switch(is->shiftState) {
+ case S_NORMAL: charset = GL(is); break;
+ case S_SS2: charset = G2(is); break;
+ case S_SS3: charset = G3(is); break;
+ default: abort();
+ }
+ ku_code = is->buffered_ku;
+ if(*s < 0x80)
+ code = *s;
+ } else {
+ switch(is->shiftState) {
+ case S_NORMAL: charset = GR(is); break;
+ case S_SS2: charset = G2(is); break;
+ case S_SS3: charset = G3(is); break;
+ default: abort();
+ }
+ ku_code = is->buffered_ku - 0x80;
+ if(*s >= 0x80)
+ code = *s - 0x80;
+ }
+ switch(charset->type) {
+ case T_94:
+ case T_96:
+ case T_128:
+ abort();
+ break;
+ case T_9494:
+ if(code >= 0x21 && code <= 0x7E) {
+ outbufUTF8(is, fd,
+ charset->recode(ku_code << 8 | code,
+ charset));
+ is->buffered_ku = -1;
+ is->shiftState = S_NORMAL;
+ } else {
+ is->buffered_ku = -1;
+ is->shiftState = S_NORMAL;
+ goto resynch;
+ }
+ s++;
+ break;
+ case T_9696:
+ if(code >= 0x20) {
+ outbufUTF8(is, fd,
+ charset->recode(ku_code << 8 | code,
+ charset));
+ is->buffered_ku = -1;
+ is->shiftState = S_NORMAL;
+ } else {
+ is->buffered_ku = -1;
+ is->shiftState = S_NORMAL;
+ goto resynch;
+ }
+ s++;
+ break;
+ case T_94192:
+ /* Use *s, not code */
+ if(((*s >= 0x21) && (*s <= 0x7E)) ||
+ ((*s >= 0xA1) && (*s <= 0xFE))) {
+ outbufUTF8(is, fd,
+ charset->recode(ku_code << 8 | *s,
+ charset));
+ is->buffered_ku = -1;
+ is->shiftState = S_NORMAL;
+ } else {
+ is->buffered_ku = -1;
+ is->shiftState = S_NORMAL;
+ goto resynch;
+ }
+ s++;
+ break;
+ default:
+ abort();
+ }
+ }
+ break;
+ case P_ESC:
+ assert(is->buffered_ku == -1);
+ if(*s == CSI_7) {
+ buffer(is, *s++);
+ is->parserState = P_CSI;
+ } else if(IS_FINAL_ESC(*s)) {
+ buffer(is, *s++);
+ terminate(is, fd);
+ is->parserState = P_NORMAL;
+ } else {
+ buffer(is, *s++);
+ }
+ break;
+ case P_CSI:
+ if(IS_FINAL_CSI(*s)) {
+ buffer(is, *s++);
+ terminate(is, fd);
+ is->parserState = P_NORMAL;
+ } else {
+ buffer(is, *s++);
+ }
+ break;
+ default:
+ abort();
+ }
+ }
+ outbuf_flush(is, fd);
+}
+
+void terminate(Iso2022Ptr is, int fd)
+{
+ if(is->outputFlags & OF_PASSTHRU) {
+ outbuf_buffered(is, fd);
+ return;
+ }
+
+ switch(is->buffered[0]) {
+ case SS2:
+ if(is->outputFlags & OF_SS)
+ is->shiftState = S_SS2;
+ discard_buffered(is);
+ return;
+ case SS3:
+ if(is->outputFlags & OF_SS)
+ is->shiftState = S_SS3;
+ discard_buffered(is);
+ return;
+ case LS0:
+ if(is->outputFlags & OF_LS)
+ is->glp = &G0(is);
+ discard_buffered(is);
+ return;
+ case LS1:
+ if(is->outputFlags & OF_LS)
+ is->glp = &G1(is);
+ discard_buffered(is);
+ return;
+ case ESC:
+ assert(is->buffered_count >= 2);
+ switch(is->buffered[1]) {
+ case SS2_7:
+ if(is->outputFlags & OF_SS)
+ is->shiftState = S_SS2;
+ discard_buffered(is);
+ return;
+ case SS3_7:
+ if(is->outputFlags & OF_SS)
+ is->shiftState = S_SS3;
+ discard_buffered(is);
+ return;
+ case LS2_7:
+ if(is->outputFlags & OF_SS)
+ is->glp = &G2(is);
+ discard_buffered(is);
+ return;
+ case LS3_7:
+ if(is->outputFlags & OF_LS)
+ is->glp = &G3(is);
+ discard_buffered(is);
+ return;
+ case LS1R_7:
+ if(is->outputFlags & OF_LS)
+ is->grp = &G1(is);
+ discard_buffered(is);
+ return;
+ case LS2R_7:
+ if(is->outputFlags & OF_LS)
+ is->grp = &G2(is);
+ discard_buffered(is);
+ return;
+ case LS3R_7:
+ if(is->outputFlags & OF_LS)
+ is->grp = &G3(is);
+ discard_buffered(is);
+ return;
+ default:
+ terminateEsc(is, fd, is->buffered + 1, is->buffered_count - 1);
+ }
+ return;
+ default:
+ outbuf_buffered(is, fd);
+ }
+}
+
+void
+terminateEsc(Iso2022Ptr is, int fd, unsigned char *s_start, int count)
+{
+ CharsetPtr charset;
+
+ /* ISO 2022 doesn't allow 2C, but Emacs/MULE uses it in 7-bit
+ mode */
+
+ if((s_start[0] == 0x28 || s_start[0] == 0x29 ||
+ s_start[0] == 0x2A || s_start[0] == 0x2B ||
+ s_start[0] == 0x2C || s_start[0] == 0x2D ||
+ s_start[0] == 0x2E || s_start[0] == 0x2F) &&
+ count >= 2) {
+ if(is->outputFlags & OF_SELECT) {
+ if(s_start[0] <= 0x2B)
+ charset = getCharset(s_start[1], T_94);
+ else
+ charset = getCharset(s_start[1], T_96);
+ switch(s_start[0]) {
+ case 0x28: case 0x2C: G0(is) = charset; break;
+ case 0x29: case 0x2D: G1(is) = charset; break;
+ case 0x2A: case 0x2E: G2(is) = charset; break;
+ case 0x2B: case 0x2F: G3(is) = charset; break;
+ }
+ }
+ discard_buffered(is);
+ } else if(s_start[0] == 0x24 && count == 2) {
+ if(is->outputFlags & OF_SELECT) {
+ charset = getCharset(s_start[1], T_9494);
+ G0(is) = charset;
+ }
+ discard_buffered(is);
+ } else if(s_start[0] == 0x24 && count >=2 &&
+ (s_start[1] == 0x28 || s_start[1] == 0x29 ||
+ s_start[1] == 0x2A || s_start[1] == 0x2B ||
+ s_start[1] == 0x2D || s_start[1] == 0x2E ||
+ s_start[1] == 0x2F) &&
+ count >= 3) {
+ if(is->outputFlags & OF_SELECT) {
+ if(s_start[1] <= 0x2B)
+ charset = getCharset(s_start[2], T_9494);
+ else
+ charset = getCharset(s_start[2], T_9696);
+ switch(s_start[1]) {
+ case 0x28: G0(is) = charset; break;
+ case 0x29: case 0x2D: G1(is) = charset; break;
+ case 0x2A: case 0x2E: G2(is) = charset; break;
+ case 0x2B: case 0x2F: G3(is) = charset; break;
+ }
+ }
+ discard_buffered(is);
+ } else
+ outbuf_buffered(is, fd);
+}
diff --git a/iso2022.h b/iso2022.h
new file mode 100644
index 0000000..9b50117
--- /dev/null
+++ b/iso2022.h
@@ -0,0 +1,94 @@
+/*
+Copyright (c) 2001 by Juliusz Chroboczek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+/* $XFree86: xc/programs/luit/iso2022.h,v 1.5 2002/10/17 01:06:09 dawes Exp $ */
+
+#define ESC 0x1B
+#define CSI 0x9B
+#define CSI_7 '['
+#define SS2 0x8E
+#define SS2_7 0x4E
+#define SS3 0x8F
+#define SS3_7 0x4F
+#define LS0 0x0F
+#define LS1 0x0E
+#define LS2_7 0x6E
+#define LS3_7 0x6F
+#define LS1R_7 0x7E
+#define LS2R_7 0x7D
+#define LS3R_7 0x7C
+
+#define IS_FINAL_ESC(x) (((x) & 0xF0 ) != 0x20)
+#define IS_FINAL_CSI(x) (((x) & 0xF0 ) != 0x20 && (((x) & 0xF0 ) != 0x30))
+
+#define P_NORMAL 0
+#define P_ESC 1
+#define P_CSI 2
+
+#define S_NORMAL 0
+#define S_SS2 1
+#define S_SS3 2
+
+#define IF_SS 1
+#define IF_LS 2
+#define IF_EIGHTBIT 4
+#define IF_SSGR 8
+
+#define OF_SS 1
+#define OF_LS 2
+#define OF_SELECT 4
+#define OF_PASSTHRU 8
+
+typedef struct _Iso2022 {
+ CharsetPtr *glp, *grp;
+ CharsetPtr g[4];
+ CharsetPtr other;
+ int parserState;
+ int shiftState;
+ int inputFlags;
+ int outputFlags;
+ unsigned char *buffered;
+ int buffered_len;
+ int buffered_count;
+ int buffered_ku;
+ unsigned char *outbuf;
+ int outbuf_count;
+} Iso2022Rec, *Iso2022Ptr;
+
+#define GL(i) (*(i)->glp)
+#define GR(i) (*(i)->grp)
+#define G0(i) ((i)->g[0])
+#define G1(i) ((i)->g[1])
+#define G2(i) ((i)->g[2])
+#define G3(i) ((i)->g[3])
+#define OTHER(i) ((i)->other)
+
+#define BUFFER_SIZE 512
+
+Iso2022Ptr allocIso2022(void);
+void destroyIso2022(Iso2022Ptr);
+int initIso2022(char *, char *, Iso2022Ptr);
+int mergeIso2022(Iso2022Ptr, Iso2022Ptr);
+void reportIso2022(Iso2022Ptr);
+void terminate(Iso2022Ptr, int);
+void terminateEsc(Iso2022Ptr, int, unsigned char*, int);
+void copyIn(Iso2022Ptr, int, unsigned char*, int);
+void copyOut(Iso2022Ptr, int, unsigned char*, int);
diff --git a/locale.c b/locale.c
new file mode 100644
index 0000000..fe070d8
--- /dev/null
+++ b/locale.c
@@ -0,0 +1,5 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "locale.h"
diff --git a/luit.c b/luit.c
new file mode 100644
index 0000000..41db6ff
--- /dev/null
+++ b/luit.c
@@ -0,0 +1,593 @@
+/*
+Copyright (c) 2001 by Juliusz Chroboczek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+/* $XFree86: xc/programs/luit/luit.c,v 1.10 2003/02/24 01:10:25 dawes Exp $ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+
+#ifdef SVR4
+#include <stropts.h>
+#endif
+
+#include <X11/fonts/fontenc.h>
+#include "luit.h"
+#include "sys.h"
+#include "other.h"
+#include "charset.h"
+#include "iso2022.h"
+
+static Iso2022Ptr inputState = NULL, outputState = NULL;
+
+static char *child_argv0 = NULL;
+static char *locale_name = NULL;
+int ilog = -1;
+int olog = -1;
+int verbose = 0;
+int converter = 0;
+int exitOnChild = 0;
+
+volatile int sigwinch_queued = 0;
+volatile int sigchld_queued = 0;
+
+static int convert(int, int);
+static int condom(int, char**);
+
+static void
+ErrorF(char *f, ...)
+{
+ va_list args;
+ va_start(args, f);
+ vfprintf(stderr, f, args);
+ va_end(args);
+}
+
+static void
+FatalError(char *f, ...)
+{
+ va_list args;
+ va_start(args, f);
+ vfprintf(stderr, f, args);
+ va_end(args);
+ exit(1);
+}
+
+
+static void
+help(void)
+{
+ fprintf(stderr,
+ "luit\n"
+ " [ -h ] [ -list ] [ -v ] [ -argv0 name ]\n"
+ " [ -gl gn ] [-gr gk] "
+ "[ -g0 set ] [ -g1 set ] "
+ "[ -g2 set ] [ -g3 set ]\n"
+ " [ -encoding encoding ] "
+ "[ +oss ] [ +ols ] [ +osl ] [ +ot ]\n"
+ " [ -kgl gn ] [-kgr gk] "
+ "[ -kg0 set ] [ -kg1 set ] "
+ "[ -kg2 set ] [ -kg3 set ]\n"
+ " [ -k7 ] [ +kss ] [ +kssgr ] [ -kls ]\n"
+ " [ -c ] [ -x ] [ -ilog filename ] [ -olog filename ] [ -- ]\n"
+ " [ program [ args ] ]\n");
+
+}
+
+
+static int
+parseOptions(int argc, char **argv)
+{
+ int i = 1;
+ while(i < argc) {
+ if(argv[i][0] != '-' && argv[i][0] != '+') {
+ break;
+ } else if(!strcmp(argv[i], "--")) {
+ i++;
+ break;
+ } else if(!strcmp(argv[i], "-v")) {
+ verbose++;
+ i++;
+ } else if(!strcmp(argv[i], "-h")) {
+ help();
+ exit(0);
+ } else if(!strcmp(argv[i], "-list")) {
+ reportCharsets();
+ exit(0);
+ } else if(!strcmp(argv[i], "+oss")) {
+ outputState->outputFlags &= ~OF_SS;
+ i++;
+ } else if(!strcmp(argv[i], "+ols")) {
+ outputState->outputFlags &= ~OF_LS;
+ i++;
+ } else if(!strcmp(argv[i], "+osl")) {
+ outputState->outputFlags &= ~OF_SELECT;
+ i++;
+ } else if(!strcmp(argv[i], "+ot")) {
+ outputState->outputFlags = OF_PASSTHRU;
+ i++;
+ } else if(!strcmp(argv[i], "-k7")) {
+ inputState->inputFlags &= ~IF_EIGHTBIT;
+ i++;
+ } else if(!strcmp(argv[i], "+kss")) {
+ inputState->inputFlags &= ~IF_SS;
+ i++;
+ } else if(!strcmp(argv[1], "+kssgr")) {
+ inputState->inputFlags &= ~IF_SSGR;
+ i++;
+ } else if(!strcmp(argv[i], "-kls")) {
+ inputState->inputFlags |= IF_LS;
+ i++;
+ } else if(!strcmp(argv[i], "-g0")) {
+ if(i + 1 >= argc)
+ FatalError("-g0 requires an argument\n");
+ G0(outputState) = getCharsetByName(argv[i + 1]);
+ i += 2;
+ } else if(!strcmp(argv[i], "-g1")) {
+ if(i + 1 >= argc)
+ FatalError("-g1 requires an argument\n");
+ G1(outputState) = getCharsetByName(argv[i + 1]);
+ i += 2;
+ } else if(!strcmp(argv[i], "-g2")) {
+ if(i + 1 >= argc)
+ FatalError("-g2 requires an argument\n");
+ G2(outputState) = getCharsetByName(argv[i + 1]);
+ i += 2;
+ } else if(!strcmp(argv[i], "-g3")) {
+ if(i + 1 >= argc)
+ FatalError("-g3 requires an argument\n");
+ G3(outputState) = getCharsetByName(argv[i + 1]);
+
+ i += 2;
+ } else if(!strcmp(argv[i], "-gl")) {
+ int j;
+ if(i + 1 >= argc)
+ FatalError("-gl requires an argument\n");
+ if(strlen(argv[i + 1]) != 2 ||
+ argv[i + 1][0] != 'g')
+ j = -1;
+ else
+ j = argv[i + 1][1] - '0';
+ if(j < 0 || j > 3)
+ FatalError("The argument of -gl "
+ "should be one of g0 through g3,\n"
+ "not %s\n", argv[i + 1]);
+ else
+ outputState->glp = &outputState->g[j];
+ i += 2;
+ } else if(!strcmp(argv[i], "-gr")) {
+ int j;
+ if(i + 1 >= argc)
+ FatalError("-gr requires an argument\n");
+ if(strlen(argv[i + 1]) != 2 ||
+ argv[i + 1][0] != 'g')
+ j = -1;
+ else
+ j = argv[i + 1][1] - '0';
+ if(j < 0 || j > 3)
+ FatalError("The argument of -gl "
+ "should be one of g0 through g3,\n"
+ "not %s\n", argv[i + 1]);
+ else
+ outputState->grp = &outputState->g[j];
+ i += 2;
+ } else if(!strcmp(argv[i], "-kg0")) {
+ if(i + 1 >= argc)
+ FatalError("-kg0 requires an argument\n");
+ G0(inputState) = getCharsetByName(argv[i + 1]);
+ i += 2;
+ } else if(!strcmp(argv[i], "-kg1")) {
+ if(i + 1 >= argc)
+ FatalError("-kg1 requires an argument\n");
+ G1(inputState) = getCharsetByName(argv[i + 1]);
+ i += 2;
+ } else if(!strcmp(argv[i], "-kg2")) {
+ if(i + 1 >= argc)
+ FatalError("-kg2 requires an argument\n");
+ G2(inputState) = getCharsetByName(argv[i + 1]);
+ i += 2;
+ } else if(!strcmp(argv[i], "-kg3")) {
+ if(i + 1 >= argc)
+ FatalError("-kg3 requires an argument\n");
+ G3(inputState) = getCharsetByName(argv[i + 1]);
+
+ i += 2;
+ } else if(!strcmp(argv[i], "-kgl")) {
+ int j;
+ if(i + 1 >= argc)
+ FatalError("-kgl requires an argument\n");
+ if(strlen(argv[i + 1]) != 2 ||
+ argv[i + 1][0] != 'g')
+ j = -1;
+ else
+ j = argv[i + 1][1] - '0';
+ if(j < 0 || j > 3)
+ FatalError("The argument of -kgl "
+ "should be one of g0 through g3,\n"
+ "not %s\n", argv[i + 1]);
+ else
+ inputState->glp = &inputState->g[j];
+ i += 2;
+ } else if(!strcmp(argv[i], "-kgr")) {
+ int j;
+ if(i + 1 >= argc)
+ FatalError("-kgl requires an argument\n");
+ if(strlen(argv[i + 1]) != 2 ||
+ argv[i + 1][0] != 'g')
+ j = -1;
+ else
+ j = argv[i + 1][1] - '0';
+ if(j < 0 || j > 3)
+ FatalError("The argument of -kgl "
+ "should be one of g0 through g3,\n"
+ "not %s\n", argv[i + 1]);
+ else
+ inputState->grp = &inputState->g[j];
+ i += 2;
+ } else if(!strcmp(argv[i], "-argv0")) {
+ if(i + 1 >= argc)
+ FatalError("-argv0 requires an argument\n");
+ child_argv0 = argv[i + 1];
+ i += 2;
+ } else if(!strcmp(argv[i], "-x")) {
+ exitOnChild = 1;
+ i++;
+ } else if(!strcmp(argv[i], "-c")) {
+ converter = 1;
+ i++;
+ } else if(!strcmp(argv[i], "-ilog")) {
+ if(i + 1 >= argc)
+ FatalError("-ilog requires an argument\n");
+ ilog = open(argv[i + 1], O_WRONLY | O_CREAT | O_TRUNC, 0777);
+ if(ilog < 0) {
+ perror("Couldn't open input log");
+ exit(1);
+ }
+ i += 2;
+ } else if(!strcmp(argv[i], "-olog")) {
+ if(i + 1 >= argc)
+ FatalError("-olog requires an argument\n");
+ olog = open(argv[i + 1], O_WRONLY | O_CREAT | O_TRUNC, 0777);
+ if(olog < 0) {
+ perror("Couldn't open output log");
+ exit(1);
+ }
+ i += 2;
+ } else if(!strcmp(argv[i], "-encoding")) {
+ int rc;
+ if(i + 1 >= argc)
+ FatalError("-encoding requires an argument\n");
+ rc = initIso2022(NULL, argv[i + 1], outputState);
+ if(rc < 0)
+ FatalError("Couldn't init output state\n");
+ i += 2;
+ } else {
+ FatalError("Unknown option %s\n", argv[i]);
+ }
+ }
+ return i;
+}
+
+static int
+parseArgs(int argc, char **argv, char *argv0,
+ char **path_return, char ***argv_return)
+{
+ char *path = NULL;
+ char **child_argv = NULL;
+
+ if(argc <= 0) {
+ char *shell;
+ shell = getenv("SHELL");
+ if(shell) {
+ path = malloc(strlen(shell) + 1);
+ if(!path)
+ goto bail;
+ strcpy(path, shell);
+ } else {
+ path = malloc(strlen("/bin/sh") + 1);
+ if(!path)
+ goto bail;
+ strcpy(path, "/bin/sh");
+ }
+ child_argv = malloc(2 * sizeof(char*));
+ if(!child_argv)
+ goto bail;
+ if(argv0)
+ child_argv[0] = argv0;
+ else
+ child_argv[0] = my_basename(path);
+ child_argv[1] = NULL;
+ } else {
+ path = malloc(strlen(argv[0]) + 1);
+ if(!path)
+ goto bail;
+ strcpy(path, argv[0]);
+ child_argv = malloc((argc + 1) * sizeof(char*));
+ if(!child_argv) {
+ goto bail;
+ }
+ if(child_argv0)
+ child_argv[0] = argv0;
+ else
+ child_argv[0] = my_basename(argv[0]);
+ memcpy(child_argv + 1, argv + 1, (argc - 1) * sizeof(char*));
+ child_argv[argc] = NULL;
+ }
+
+ *path_return = path;
+ *argv_return = child_argv;
+ return 0;
+
+ bail:
+ if(path)
+ free(path);
+ if(argv)
+ free(argv);
+ return -1;
+}
+
+
+int
+main(int argc, char **argv)
+{
+ int rc;
+ int i;
+ char *l;
+
+ l = setlocale(LC_ALL, "");
+ if(!l)
+ ErrorF("Warning: couldn't set locale.\n");
+
+ inputState = allocIso2022();
+ if(!inputState)
+ FatalError("Couldn't create input state\n");
+
+ outputState = allocIso2022();
+ if(!outputState)
+ FatalError("Couldn't create output state\n");
+
+ if(l) {
+ locale_name = setlocale(LC_CTYPE, NULL);
+ } else {
+ locale_name = getenv("LC_ALL");
+ if(locale_name == NULL) {
+ locale_name = getenv("LC_CTYPE");
+ if(locale_name == NULL) {
+ locale_name = getenv("LANG");
+ }
+ }
+ }
+
+ if(locale_name == NULL) {
+ ErrorF("Couldn't get locale name -- using C\n");
+ locale_name = "C";
+ }
+
+ rc = initIso2022(locale_name, NULL, outputState);
+ if(rc < 0)
+ FatalError("Couldn't init output state\n");
+
+ i = parseOptions(argc, argv);
+ if(i < 0)
+ FatalError("Couldn't parse options\n");
+
+ rc = mergeIso2022(inputState, outputState);
+ if(rc < 0)
+ FatalError("Couldn't init input state\n");
+
+ if(converter)
+ return convert(0, 1);
+ else
+ return condom(argc - i, argv + i);
+}
+
+static int
+convert(int ifd, int ofd)
+{
+ int rc, i;
+ unsigned char buf[BUFFER_SIZE];
+
+ rc = droppriv();
+ if(rc < 0) {
+ perror("Couldn't drop priviledges");
+ exit(1);
+ }
+
+ while(1) {
+ i = read(ifd, buf, BUFFER_SIZE);
+ if(i <= 0) {
+ if(i < 0) {
+ perror("Read error");
+ exit(1);
+ }
+ break;
+ }
+ copyOut(outputState, ofd, buf, i);
+ }
+ return 0;
+}
+
+
+static int
+condom(int argc, char **argv)
+{
+ int pty;
+ int pid;
+ char *line;
+ char *path;
+ char **child_argv;
+ int rc;
+
+ rc = parseArgs(argc, argv, child_argv0,
+ &path, &child_argv);
+ if(rc < 0)
+ FatalError("Couldn't parse arguments\n");
+
+ rc = allocatePty(&pty, &line);
+ if(rc < 0) {
+ perror("Couldn't allocate pty");
+ exit(1);
+ }
+
+ rc = droppriv();
+ if(rc < 0) {
+ perror("Couldn't drop priviledges");
+ exit(1);
+ }
+
+ pid = fork();
+ if(pid < 0) {
+ perror("Couldn't fork");
+ exit(1);
+ }
+
+ if(pid == 0) {
+ close(pty);
+ child(line, path, child_argv);
+ } else {
+ free(child_argv);
+ free(path);
+ free(line);
+ parent(pid, pty);
+ }
+
+ return 0;
+}
+
+void
+child(char *line, char *path, char **argv)
+{
+ int tty;
+ int pgrp;
+
+ close(0);
+ close(1);
+ close(2);
+ pgrp = setsid();
+ if(pgrp < 0) {
+ kill(getppid(), SIGABRT);
+ exit(1);
+ }
+
+ tty = openTty(line);
+ if(tty < 0) {
+ kill(getppid(), SIGABRT);
+ exit(1);
+ }
+
+ if(tty != 0)
+ dup2(tty, 0);
+ if(tty != 1)
+ dup2(tty, 1);
+ if(tty != 2)
+ dup2(tty, 2);
+
+ if(tty > 2)
+ close(tty);
+
+ execvp(path, argv);
+ perror("Couldn't exec");
+ exit(1);
+}
+
+static void
+sigwinchHandler(int sig) {
+ sigwinch_queued = 1;
+}
+
+static void
+sigchldHandler(int sig)
+{
+ sigchld_queued = 1;
+}
+
+void
+parent(int pid, int pty)
+{
+ unsigned char buf[BUFFER_SIZE];
+ int i;
+ int val;
+ int rc;
+
+ if(verbose) {
+ reportIso2022(outputState);
+ }
+
+#ifdef SIGWINCH
+ installHandler(SIGWINCH, sigwinchHandler);
+#endif
+ installHandler(SIGCHLD, sigchldHandler);
+
+ rc = setRawTermios();
+ if(rc < 0)
+ FatalError("Couldn't set terminal to raw\n");
+
+ val = fcntl(0, F_GETFL, 0);
+ if(val >= 0) {
+ fcntl(0, F_SETFL, val | O_NONBLOCK);
+ }
+ val = fcntl(pty, F_GETFL, 0);
+ if(val >= 0) {
+ fcntl(pty, F_SETFL, val | O_NONBLOCK);
+ }
+
+ setWindowSize(0, pty);
+
+ for(;;) {
+ rc = waitForInput(0, pty);
+
+ if(sigwinch_queued) {
+ sigwinch_queued = 0;
+ setWindowSize(0, pty);
+ }
+
+ if(sigchld_queued && exitOnChild)
+ break;
+
+ if(rc > 0) {
+ if(rc & 2) {
+ i = read(pty, buf, BUFFER_SIZE);
+ if((i == 0) || ((i < 0) && (errno != EAGAIN)))
+ break;
+ if(i > 0)
+ copyOut(outputState, 0, buf, i);
+ }
+ if(rc & 1) {
+ i = read(0, buf, BUFFER_SIZE);
+ if((i == 0) || ((i < 0) && (errno != EAGAIN)))
+ break;
+ if(i > 0)
+ copyIn(inputState, pty, buf, i);
+ }
+ }
+ }
+
+ restoreTermios();
+}
diff --git a/luit.h b/luit.h
new file mode 100644
index 0000000..695751e
--- /dev/null
+++ b/luit.h
@@ -0,0 +1,31 @@
+/*
+Copyright (c) 2001 by Juliusz Chroboczek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+extern int iso2022;
+extern int verbose;
+extern int sevenbit;
+extern int ilog;
+extern int olog;
+
+void child(char*, char*, char**);
+void parent(int, int);
+
diff --git a/luit.man b/luit.man
new file mode 100644
index 0000000..a97da6d
--- /dev/null
+++ b/luit.man
@@ -0,0 +1,221 @@
+.\" $XFree86: xc/programs/luit/luit.man,v 1.7 2003/02/24 01:10:25 dawes Exp $
+.TH LUIT 1 __vendorversion__
+.SH NAME
+luit \- Locale and ISO\ 2022 support for Unicode terminals
+.SH SYNOPSIS
+.B luit
+[
+.I options
+] [
+.B \-\-
+] [
+.I program
+[
+.I args
+] ]
+.SH DESCRIPTION
+.B Luit
+is a filter that can be run between an arbitrary application and a
+UTF-8 terminal emulator. It will convert application output from the
+locale's encoding into UTF-8, and convert terminal input from UTF-8
+into the locale's encoding.
+
+An application may also request switching to a different output
+encoding using ISO\ 2022 and ISO\ 6429 escape sequences. Use of this
+feature is discouraged: multilingual applications should be modified
+to directly generate UTF-8 instead.
+
+.B Luit
+is usually invoked transparently by the terminal emulator. For
+information about running
+.B luit
+from the command line, see EXAMPLES below.
+.SH OPTIONS
+.TP
+.B \-h
+Display some summary help and quit.
+.TP
+.B \-list
+List the supported charsets and encodings, then quit.
+.TP
+.B \-v
+Be verbose.
+.TP
+.B \-c
+Function as a simple converter from standard input to standard output.
+.TP
+.B \-x
+Exit as soon as the child dies. This may cause
+.B luit
+to loose data at the end of the child's output.
+.TP
+.BI \-argv0 " name"
+Set the child's name (as passed in argv[0]).
+.TP
+.BI \-encoding " encoding"
+Set up
+.B luit
+to use
+.I encoding
+rather than the current locale's encoding.
+.TP
+.B +oss
+Disable interpretation of single shifts in application output.
+.TP
+.B +ols
+Disable interpretation of locking shifts in application output.
+.TP
+.B +osl
+Disable interpretation of character set selection sequences in
+application output.
+.TP
+.B +ot
+Disable interpretation of all sequences and pass all sequences in
+application output to the terminal unchanged. This may lead to
+interesting results.
+.TP
+.B \-k7
+Generate seven-bit characters for keyboard input.
+.TP
+.B +kss
+Disable generation of single-shifts for keyboard input.
+.TP
+.B +kssgr
+Use GL codes after a single shift for keyboard input. By default, GR
+codes are generated after a single shift when generating eight-bit
+keyboard input.
+.TP
+.B \-kls
+Generate locking shifts (SO/SI) for keyboard input.
+.TP
+.BI \-gl " gn"
+Set the initial assignment of GL. The argument should be one of
+.BR g0 ,
+.BR g1 ,
+.B g2
+or
+.BR g3 .
+The default depends on the locale, but is usually
+.BR g0 .
+.TP
+.BI \-gr " gk"
+Set the initial assignment of GR. The default depends on the locale,
+and is usually
+.B g2
+except for EUC locales, where it is
+.BR g1 .
+.TP
+.BI \-g0 " charset"
+Set the charset initially selected in G0. The default depends on
+the locale, but is usually
+.BR ASCII .
+.TP
+.BI \-g1 " charset"
+Set the charset initially selected in G1. The default depends on the
+locale.
+.TP
+.BI \-g2 " charset"
+Set the charset initially selected in G2. The default depends on the
+locale.
+.TP
+.BI \-g3 " charset"
+Set the charset initially selected in G3. The default depends on the
+locale.
+.TP
+.BI \-ilog " filename"
+Log into
+.I filename
+all the bytes received from the child.
+.TP
+.BI \-olog " filename"
+Log into
+.I filename
+all the bytes sent to the terminal emulator.
+.TP
+.B \-\-
+End of options.
+.SH EXAMPLES
+The most typical use of
+.B luit
+is to adapt an instance of
+.B XTerm
+to the locale's encoding. Current versions of
+.B XTerm
+invoke
+.B luit
+automatically when it is needed. If you are using an older release of
+.BR XTerm ,
+or a different terminal emulator, you may invoke
+.B luit
+manually:
+.IP
+$ xterm \-u8 \-e luit
+.PP
+If you are running in a UTF-8 locale but need to access a remote
+machine that doesn't support UTF-8,
+.B luit
+can adapt the remote output to your terminal:
+.IP
+$ LC_ALL=fr_FR luit ssh legacy-machine
+.PP
+.B Luit
+is also useful with applications that hard-wire an encoding that is
+different from the one normally used on the system or want to use
+legacy escape sequences for multilingual output. In particular,
+versions of
+.B Emacs
+that do not speak UTF-8 well can use
+.B luit
+for multilingual output:
+.IP
+$ luit -encoding 'ISO 8859-1' emacs -nw
+.PP
+And then, in
+.BR Emacs ,
+.IP
+M-x set-terminal-coding-system RET iso-2022-8bit-ss2 RET
+.PP
+.SH FILES
+.TP
+.B __projectroot__/lib/X11/fonts/encodings/encodings.dir
+The system-wide encodings directory.
+.TP
+.B __projectroot__/lib/X11/locale/locale.alias
+The file mapping locales to locale encodings.
+.SH SECURITY
+On systems with SVR4 (``Unix-98'') ptys (Linux version 2.2 and later,
+SVR4),
+.B luit
+should be run as the invoking user.
+
+On systems without SVR4 (``Unix-98'') ptys (notably BSD variants),
+running
+.B luit
+as an ordinary user will leave the tty world-writable; this is a
+security hole, and luit will generate a warning (but still accept to
+run). A possible solution is to make
+.B luit
+suid root;
+.B luit
+should drop privileges sufficiently early to make this safe. However,
+the startup code has not been exhaustively audited, and the author
+takes no responsibility for any resulting security issues.
+
+.B Luit
+will refuse to run if it is installed setuid and the underlying system
+does not have POSIX saved ids.
+.SH BUGS
+None of this complexity should be necessary. Stateless UTF-8
+throughout the system is the way to go.
+
+Charsets with a non-trivial intermediary byte are not yet supported.
+
+Selecting alternate sets of control characters is not supported and
+will never be.
+.SH SEE ALSO
+xterm(1), unicode(7), utf-8(7), charsets(7).
+.I Character Code Structure and Extension Techniques (ISO\ 2022, ECMA-35).
+.I Control Functions for Coded Character Sets (ISO\ 6429, ECMA-48).
+.SH AUTHOR
+Luit was written by Juliusz Chroboczek <jch@xfree86.org> for the
+XFree86 project.
diff --git a/other.c b/other.c
new file mode 100644
index 0000000..dff2243
--- /dev/null
+++ b/other.c
@@ -0,0 +1,246 @@
+/*
+Copyright (c) 2002 by Tomohiro KUBOTA
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+/* $XFree86: xc/programs/luit/other.c,v 1.1 2002/10/17 01:06:09 dawes Exp $ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <X11/fonts/fontenc.h>
+#include "other.h"
+#include "charset.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#define EURO_10646 0x20AC
+
+int
+init_gbk(OtherStatePtr s)
+{
+ s->gbk.mapping =
+ FontEncMapFind("gbk-0", FONT_ENCODING_UNICODE, -1, -1, NULL);
+ if(!s->gbk.mapping) return 0;
+
+ s->gbk.reverse = FontMapReverse(s->gbk.mapping);
+ if(!s->gbk.reverse) return 0;
+
+ s->gbk.buf = -1;
+ return 1;
+}
+
+unsigned int
+mapping_gbk(unsigned int n, OtherStatePtr s)
+{
+ unsigned int r;
+ if(n < 128) return n;
+ if(n == 128) return EURO_10646;
+ r = FontEncRecode(n, s->gbk.mapping);
+ return r;
+}
+
+unsigned int
+reverse_gbk(unsigned int n, OtherStatePtr s)
+{
+ if(n < 128) return n;
+ if(n == EURO_10646) return 128;
+ return s->gbk.reverse->reverse(n, s->gbk.reverse->data);
+}
+
+int
+stack_gbk(unsigned char c, OtherStatePtr s)
+{
+ if(s->gbk.buf < 0) {
+ if(c < 129) return c;
+ s->gbk.buf = c;
+ return -1;
+ } else {
+ int b;
+ if(c < 0x40 || c == 0x7F) {
+ s->gbk.buf = -1;
+ return c;
+ }
+ if(s->gbk.buf < 0xFF && c < 0xFF)
+ b = (s->gbk.buf << 8) + c;
+ else
+ b = -1;
+ s->gbk.buf = -1;
+ return b;
+ }
+}
+
+int
+init_utf8(OtherStatePtr s)
+{
+ s->utf8.buf_ptr = 0;
+ return 1;
+}
+
+unsigned int
+mapping_utf8(unsigned int n, OtherStatePtr s)
+{
+ return n;
+}
+
+unsigned int
+reverse_utf8(unsigned int n, OtherStatePtr s)
+{
+ if(n < 0x80)
+ return n;
+ if(n < 0x800)
+ return 0xC080 + ((n&0x7C0)<<2) + (n&0x3F);
+ if(n < 0x10000)
+ return 0xE08080 + ((n&0xF000)<<4) + ((n&0xFC0)<<2) + (n&0x3F);
+ return 0xF0808080 + ((n&0x1C0000)<<6) + ((n&0x3F000)<<4) +
+ ((n&0xFC0)<<2) + (n&0x3F);
+}
+
+int
+stack_utf8(unsigned char c, OtherStatePtr s)
+{
+ int u;
+
+ if(c < 0x80) {
+ s->utf8.buf_ptr = 0;
+ return c;
+ }
+ if(s->utf8.buf_ptr == 0) {
+ if((c & 0x40) == 0) return -1;
+ s->utf8.buf[s->utf8.buf_ptr++] = c;
+ if((c & 0x60) == 0x40) s->utf8.len = 2;
+ else if((c & 0x70) == 0x60) s->utf8.len = 3;
+ else if((c & 0x78) == 0x70) s->utf8.len = 4;
+ else s->utf8.buf_ptr = 0;
+ return -1;
+ }
+ if((c & 0x40) != 0) {
+ s->utf8.buf_ptr = 0;
+ return -1;
+ }
+ s->utf8.buf[s->utf8.buf_ptr++] = c;
+ if(s->utf8.buf_ptr < s->utf8.len) return -1;
+ switch(s->utf8.len) {
+ case 2:
+ u = ((s->utf8.buf[0] & 0x1F) << 6) | (s->utf8.buf[1] & 0x3F);
+ s->utf8.buf_ptr = 0;
+ if(u < 0x80) return -1; else return u;
+ case 3:
+ u = ((s->utf8.buf[0] & 0x0F) << 12)
+ | ((s->utf8.buf[1] & 0x3F) << 6)
+ | (s->utf8.buf[2] & 0x3F);
+ s->utf8.buf_ptr = 0;
+ if(u < 0x800) return -1; else return u;
+ case 4:
+ u = ((s->utf8.buf[0] & 0x03) << 18)
+ | ((s->utf8.buf[1] & 0x3F) << 12)
+ | ((s->utf8.buf[2] & 0x3F) << 6)
+ | ((s->utf8.buf[3] & 0x3F));
+ s->utf8.buf_ptr = 0;
+ if(u < 0x10000) return -1; else return u;
+ }
+ s->utf8.buf_ptr = 0;
+ return -1;
+}
+
+
+#define HALFWIDTH_10646 0xFF61
+#define YEN_SJIS 0x5C
+#define YEN_10646 0x00A5
+#define OVERLINE_SJIS 0x7E
+#define OVERLINE_10646 0x203E
+
+int
+init_sjis(OtherStatePtr s)
+{
+ s->sjis.x0208mapping =
+ FontEncMapFind("jisx0208.1990-0", FONT_ENCODING_UNICODE, -1, -1, NULL);
+ if(!s->sjis.x0208mapping) return 0;
+
+ s->sjis.x0208reverse = FontMapReverse(s->sjis.x0208mapping);
+ if(!s->sjis.x0208reverse) return 0;
+
+ s->sjis.x0201mapping =
+ FontEncMapFind("jisx0201.1976-0", FONT_ENCODING_UNICODE, -1, -1, NULL);
+ if(!s->sjis.x0201mapping) return 0;
+
+ s->sjis.x0201reverse = FontMapReverse(s->sjis.x0201mapping);
+ if(!s->sjis.x0201reverse) return 0;
+
+ s->sjis.buf = -1;
+ return 1;
+}
+
+unsigned int
+mapping_sjis(unsigned int n, OtherStatePtr s)
+{
+ unsigned int j1, j2, s1, s2;
+ if(n == YEN_SJIS) return YEN_10646;
+ if(n == OVERLINE_SJIS) return OVERLINE_10646;
+ if(n < 0x80) return n;
+ if(n >= 0xA0 && n <= 0xDF) return FontEncRecode(n, s->sjis.x0201mapping);
+ s1 = ((n>>8)&0xFF);
+ s2 = (n&0xFF);
+ j1 = (s1 << 1) - (s1 <= 0x9F ? 0xE0 : 0x160) - (s2 < 0x9F ? 1 : 0);
+ j2 = s2 - 0x1F - (s2 >= 0x7F ? 1 : 0) - (s2 >= 0x9F ? 0x5E : 0);
+ return FontEncRecode((j1<<8) + j2, s->sjis.x0208mapping);
+}
+
+unsigned int
+reverse_sjis(unsigned int n, OtherStatePtr s)
+{
+ unsigned int j, j1, j2, s1, s2;
+ if(n == YEN_10646) return YEN_SJIS;
+ if(n == OVERLINE_10646) return OVERLINE_SJIS;
+ if(n < 0x80) return n;
+ if(n >= HALFWIDTH_10646)
+ return s->sjis.x0201reverse->reverse(n, s->sjis.x0201reverse->data);
+ j = s->sjis.x0208reverse->reverse(n, s->sjis.x0208reverse->data);
+ j1 = ((j>>8)&0xFF);
+ j2 = (j&0xFF);
+ s1 = ((j1 - 1) >> 1) + ((j1 <= 0x5E) ? 0x71 : 0xB1);
+ s2 = j2 + ((j1 & 1) ? ((j2 < 0x60) ? 0x1F : 0x20) : 0x7E);
+ return (s1<<8) + s2;
+}
+
+int
+stack_sjis(unsigned char c, OtherStatePtr s)
+{
+ if(s->sjis.buf < 0) {
+ if(c < 128 || (c >= 0xA0 && c <= 0xDF)) return c;
+ s->sjis.buf = c;
+ return -1;
+ } else {
+ int b;
+ if(c < 0x40 || c == 0x7F) {
+ s->sjis.buf = -1;
+ return c;
+ }
+ if(s->sjis.buf < 0xFF && c < 0xFF)
+ b = (s->sjis.buf << 8) + c;
+ else
+ b = -1;
+ s->sjis.buf = -1;
+ return b;
+ }
+}
+
diff --git a/other.h b/other.h
new file mode 100644
index 0000000..ef659c7
--- /dev/null
+++ b/other.h
@@ -0,0 +1,63 @@
+/*
+Copyright (c) 2002 by Tomohiro KUBOTA
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+/* $XFree86: xc/programs/luit/other.h,v 1.1 2002/10/17 01:06:09 dawes Exp $ */
+
+typedef struct {
+ FontMapPtr mapping;
+ FontMapReversePtr reverse;
+ int buf;
+} aux_gbk;
+
+typedef struct {
+ unsigned char buf[4];
+ int buf_ptr, len;
+} aux_utf8;
+
+typedef struct {
+ FontMapPtr x0208mapping;
+ FontMapPtr x0201mapping;
+ FontMapReversePtr x0208reverse;
+ FontMapReversePtr x0201reverse;
+ int buf;
+} aux_sjis;
+
+typedef union {
+ aux_gbk gbk;
+ aux_utf8 utf8;
+ aux_sjis sjis;
+} OtherState, *OtherStatePtr;
+
+int init_gbk(OtherStatePtr);
+unsigned int mapping_gbk(unsigned int, OtherStatePtr);
+unsigned int reverse_gbk(unsigned int, OtherStatePtr);
+int stack_gbk(unsigned char, OtherStatePtr);
+
+int init_utf8(OtherStatePtr);
+unsigned int mapping_utf8(unsigned int, OtherStatePtr);
+unsigned int reverse_utf8(unsigned int, OtherStatePtr);
+int stack_utf8(unsigned char, OtherStatePtr);
+
+int init_sjis(OtherStatePtr);
+unsigned int mapping_sjis(unsigned int, OtherStatePtr);
+unsigned int reverse_sjis(unsigned int, OtherStatePtr);
+int stack_sjis(unsigned char, OtherStatePtr);
+
diff --git a/parser.c b/parser.c
new file mode 100644
index 0000000..6734fb2
--- /dev/null
+++ b/parser.c
@@ -0,0 +1,211 @@
+/*
+Copyright (c) 2001 by Juliusz Chroboczek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+/* $XFree86: xc/programs/luit/parser.c,v 1.2 2002/09/18 17:11:50 tsi Exp $ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "parser.h"
+
+static char keyword[MAX_KEYWORD_LENGTH];
+
+static void
+skipEndOfLine(FILE *f, int c)
+{
+ if(c == 0)
+ c = getc(f);
+
+ for(;;)
+ if(c <= 0 || c == '\n')
+ return;
+ else
+ c = getc(f);
+}
+
+static int
+drainWhitespace(FILE *f, int c)
+{
+ if(c == 0)
+ c = getc(f);
+
+ while (c == '#' || c == ' ' || c == '\t') {
+ if(c <= 0)
+ return 0;
+ if(c == '#') {
+ skipEndOfLine(f, c);
+ return '\n';
+ }
+ c = getc(f);
+ }
+
+ return c;
+}
+
+static int
+getString(FILE *f, int string_end, int *c_return)
+{
+ int i = 0;
+ int c;
+
+ c = getc(f);
+ while(c > 0) {
+ if(c == string_end)
+ break;
+ if(c == '\\') {
+ c = getc(f);
+ if(c == '\n')
+ continue;
+ }
+ keyword[i++] = c;
+ if(i >= MAX_KEYWORD_LENGTH)
+ return TOK_ERROR;
+ c = getc(f);
+ }
+
+ if(c <= 0)
+ return TOK_ERROR;
+ keyword[i] = '\0';
+ *c_return = c;
+ return TOK_KEYWORD;
+}
+
+static int
+getToken(FILE *f, int c, int parse_assignments, int *c_return)
+{
+ int i;
+ c = drainWhitespace(f, c);
+
+ if(c < 0)
+ return TOK_EOF;
+ if(c == '\n') {
+ *c_return = 0;
+ return TOK_EOL;
+ }
+
+ if(parse_assignments && c == '=') {
+ *c_return = 0;
+ return TOK_EQUALS;
+ }
+
+ if(c == '\'' || c == '"')
+ return getString(f, c, c_return);
+
+ i = 0;
+ while(c > 0 && c != ' ' && c != '\t' && c != '\n') {
+ if(c == '\\') {
+ c = getc(f);
+ if(c == '\n')
+ continue;
+ }
+ keyword[i++] = c;
+ if(i >= MAX_KEYWORD_LENGTH)
+ return TOK_ERROR;
+ c = getc(f);
+ if(parse_assignments && c == '=')
+ break;
+ }
+
+ *c_return = c<0?0:c;
+ keyword[i] = '\0';
+ return TOK_KEYWORD;
+}
+
+
+/* Can parse both the old and new formats for locale.alias */
+static int
+parseTwoTokenLine(FILE *f, char *first, char *second)
+{
+ int c = 0;
+ int tok;
+
+ again:
+
+ tok = getToken(f, c, 0, &c);
+ if(tok == TOK_EOF)
+ return -1;
+ else if(tok == TOK_EOL)
+ goto again;
+ else if(tok == TOK_KEYWORD) {
+ int len = strlen(keyword);
+ if(keyword[len - 1] == ':')
+ keyword[len - 1] = '\0';
+ strcpy(first, keyword);
+ } else
+ return -2;
+
+ tok = getToken(f, c, 0, &c);
+ if(tok == TOK_KEYWORD) {
+ strcpy(second, keyword);
+ } else
+ return -2;
+
+ tok = getToken(f, c, 0, &c);
+ if(tok != TOK_EOL)
+ return -2;
+
+ return 0;
+}
+
+char *
+resolveLocale(char *locale)
+{
+ FILE *f;
+ char first[MAX_KEYWORD_LENGTH], second[MAX_KEYWORD_LENGTH];
+ char *resolved = NULL;
+ int rc;
+
+ f = fopen(LOCALE_ALIAS_FILE, "r");
+ if(f == NULL)
+ goto bail;
+
+ do {
+ rc = parseTwoTokenLine(f, first, second);
+ if(rc < -1)
+ goto bail;
+ if(!strcmp(first, locale)) {
+ resolved = malloc(strlen(second) + 1);
+ if(resolved == NULL)
+ goto bail;
+ strcpy(resolved, second);
+ break;
+ }
+ } while(rc >= 0);
+
+ if(resolved == NULL) {
+ resolved = malloc(strlen(locale) + 1);
+ if(resolved == NULL)
+ goto bail;
+ strcpy(resolved, locale);
+ }
+
+ fclose(f);
+
+ return resolved;
+
+ bail:
+ if(f != NULL)
+ fclose(f);
+ if(resolved != NULL)
+ free(resolved);
+ return NULL;
+}
diff --git a/parser.h b/parser.h
new file mode 100644
index 0000000..6fceb50
--- /dev/null
+++ b/parser.h
@@ -0,0 +1,35 @@
+/*
+Copyright (c) 2001 by Juliusz Chroboczek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef LOCALE_ALIAS_FILE
+#define LOCALE_ALIAS_FILE "/usr/X11R6/lib/X11/locale/locale.alias"
+#endif
+
+#define MAX_KEYWORD_LENGTH 1024
+
+#define TOK_ERROR (-2)
+#define TOK_EOF (-1)
+#define TOK_EOL 0
+#define TOK_EQUALS 1
+#define TOK_KEYWORD 2
+
+char *resolveLocale(char *locale);
diff --git a/sys.c b/sys.c
new file mode 100644
index 0000000..051deb7
--- /dev/null
+++ b/sys.c
@@ -0,0 +1,457 @@
+/*
+Copyright (c) 2001 by Juliusz Chroboczek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+/* $XFree86: xc/programs/luit/sys.c,v 1.7 2002/01/07 20:38:30 dawes Exp $ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <termios.h>
+#include <signal.h>
+#include <errno.h>
+
+#ifdef SVR4
+#define HAVE_POLL
+#endif
+
+#ifndef HAVE_POLL
+#ifndef _MINIX
+#define HAVE_SELECT
+#endif
+#endif
+
+#ifdef HAVE_POLL
+#include <sys/poll.h>
+#undef HAVE_SELECT
+#endif
+
+#ifdef __QNX__
+#include <sys/select.h>
+#endif
+
+
+#if (defined(__GLIBC__) && \
+ (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1))) || \
+ defined(SVR4)
+#define HAVE_GRANTPT
+#endif
+
+#ifdef __GLIBC__
+#include <pty.h>
+#endif
+
+#ifdef SVR4
+#include <stropts.h>
+#endif
+
+#include "sys.h"
+
+static int saved_tio_valid = 0;
+static struct termios saved_tio;
+
+
+#ifdef HAVE_POLL
+int
+waitForOutput(int fd)
+{
+ struct pollfd pfd[1];
+ int rc;
+
+ pfd[0].fd = fd;
+ pfd[0].events = POLLOUT;
+ pfd[0].revents = 0;
+
+ rc = poll(pfd, 1, -1);
+ if(rc < 0)
+ return -1;
+
+ if(pfd[0].revents & POLLOUT)
+ return 1;
+
+ return 0;
+}
+
+int
+waitForInput(int fd1, int fd2)
+{
+ struct pollfd pfd[2];
+ int ret, rc;
+
+ pfd[0].fd = fd1;
+ pfd[1].fd = fd2;
+ pfd[0].events = pfd[1].events = POLLIN;
+ pfd[0].revents = pfd[1].revents = 0;
+
+ rc = poll(pfd, 2, -1);
+ if(rc < 0)
+ return -1;
+
+ ret = 0;
+ if(pfd[0].revents & POLLIN)
+ ret |= 1;
+ if(pfd[1].revents & POLLIN)
+ ret |= 2;
+ return ret;
+}
+#endif
+
+#ifdef HAVE_SELECT
+int
+waitForOutput(int fd)
+{
+ fd_set fds;
+ int rc;
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ rc = select(FD_SETSIZE, NULL, &fds, NULL, NULL);
+ if(rc < 0)
+ return -1;
+
+ if(FD_ISSET(fd, &fds))
+ return 1;
+
+ return 0;
+}
+
+int
+waitForInput(int fd1, int fd2)
+{
+ fd_set fds;
+ int ret, rc;
+
+ FD_ZERO(&fds);
+ FD_SET(fd1, &fds);
+ FD_SET(fd2, &fds);
+ rc = select(FD_SETSIZE, &fds, NULL, NULL, NULL);
+ if(rc < 0)
+ return -1;
+
+ ret = 0;
+ if(FD_ISSET(fd1, &fds))
+ ret |= 1;
+ if(FD_ISSET(fd2, &fds))
+ ret |= 2;
+ return ret;
+}
+#endif
+
+#ifndef HAVE_POLL
+#ifndef HAVE_SELECT
+/* Busy looping implementation */
+int
+waitForOutput(int fd)
+{
+ return 1;
+}
+
+int
+waitForInput(int fd1, int fd2)
+{
+ return 1|2;
+}
+#endif
+#endif
+
+
+int
+setWindowSize(int sfd, int dfd)
+{
+#ifdef TIOCGWINSZ
+ int rc;
+ struct winsize ws;
+ rc = ioctl(sfd, TIOCGWINSZ, (char*)&ws);
+ if(rc < 0)
+ return -1;
+ rc = ioctl(dfd, TIOCSWINSZ, (char*)&ws);
+ if(rc < 0)
+ return -1;
+#endif
+ return 0;
+}
+
+int
+installHandler(int signum, void (*handler)(int))
+{
+ struct sigaction sa;
+ sigset_t ss;
+ int rc;
+
+ sigemptyset(&ss);
+
+ sa.sa_handler = handler;
+ sa.sa_mask = ss;
+ sa.sa_flags = 0;
+ rc = sigaction(signum, &sa, NULL);
+ return rc;
+}
+
+int
+saveTermios(void)
+{
+ int rc;
+ rc = tcgetattr(0, &saved_tio);
+ if(rc >= 0)
+ saved_tio_valid = 1;
+ return rc;
+}
+
+int
+restoreTermios(void)
+{
+ if(!saved_tio_valid)
+ return -1;
+ return tcsetattr(0, TCSAFLUSH, &saved_tio);
+}
+
+int
+setRawTermios(void)
+{
+ struct termios tio;
+ int rc;
+
+ if(!saved_tio_valid)
+ saveTermios();
+ rc = tcgetattr(0, &tio);
+ if(rc < 0)
+ return rc;
+ tio.c_lflag &= ~(ECHO|ICANON|ISIG);
+ tio.c_iflag &= ~(ICRNL|IXOFF|IXON|ISTRIP);
+#ifdef ONLCR
+ tio.c_oflag &= ~ONLCR;
+#endif
+#ifdef OCRNL
+ tio.c_oflag &= ~OCRNL;
+#endif
+#ifdef ONOCR
+ tio.c_oflag &= ~ONOCR;
+#endif
+
+#ifdef VMIN
+ tio.c_cc[VMIN] = 0;
+ tio.c_cc[VTIME] = 0;
+#endif
+ rc = tcsetattr(0, TCSAFLUSH, &tio);
+ if(rc < 0)
+ return rc;
+ return 0;
+}
+
+
+char *
+my_basename(char *path)
+{
+ char *p;
+
+ p = strrchr(path, '/');
+ if(!p)
+ p = path;
+ else
+ p++;
+ return p;
+}
+
+static int
+fix_pty_perms(char *line)
+{
+ int rc;
+ struct stat s;
+ int uid = getuid(), gid = getgid();
+
+ rc = stat(line, &s);
+ if(rc < 0)
+ return -1;
+ if(s.st_uid != uid || s.st_gid != gid) {
+ rc = chown(line, getuid(), getgid());
+ if(rc < 0) {
+ fprintf(stderr,
+ "Warning: could not change ownership of tty -- "
+ "pty is insecure!\n");
+ return 0;
+ }
+ }
+ if((s.st_mode & 0777) != (S_IRUSR | S_IWUSR | S_IWGRP)) {
+ rc = chmod(line, S_IRUSR | S_IWUSR | S_IWGRP);
+ if (rc < 0) {
+ fprintf(stderr,
+ "Warning: could not change permissions of tty -- "
+ "pty is insecure!\n");
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int
+allocatePty(int *pty_return, char **line_return)
+{
+ char name[12], *line = NULL;
+ int pty = -1;
+ char *name1 = "pqrstuvwxyzPQRST", *name2 = "0123456789abcdef";
+ char *p1, *p2;
+
+#ifdef HAVE_GRANTPT
+ char *temp_line;
+ int rc;
+
+ pty = open("/dev/ptmx", O_RDWR);
+ if(pty < 0)
+ goto bsd;
+
+ rc = grantpt(pty);
+ if(rc < 0) {
+ close(pty);
+ goto bsd;
+ }
+
+ rc = unlockpt(pty);
+ if(rc < 0) {
+ close(pty);
+ goto bsd;
+ }
+
+ temp_line = ptsname(pty);
+ if(!temp_line) {
+ close(pty);
+ goto bsd;
+ }
+ line = malloc(strlen(temp_line) + 1);
+ if(!line) {
+ close(pty);
+ return -1;
+ }
+ strcpy(line, temp_line);
+
+ fix_pty_perms(line);
+
+ *pty_return = pty;
+ *line_return = line;
+ return 0;
+
+ bsd:
+#endif /* HAVE_GRANTPT */
+
+ strcpy(name, "/dev/pty??");
+ for(p1 = name1; *p1; p1++) {
+ name[8] = *p1;
+ for(p2 = name2; *p2; p2++) {
+ name[9] = *p2;
+ pty = open(name, O_RDWR);
+ if(pty >= 0)
+ goto found;
+ if(errno == ENOENT)
+ goto bail;
+ else
+ continue;
+ }
+ }
+
+ goto bail;
+
+ found:
+ line = malloc(strlen(name));
+ strcpy(line, name);
+ line[5] = 't';
+ fix_pty_perms(line);
+ *pty_return = pty;
+ *line_return = line;
+ return 0;
+
+ bail:
+ if(pty >= 0)
+ close(pty);
+ if(line)
+ free(line);
+ return -1;
+}
+
+int
+openTty(char *line)
+{
+ int rc;
+ int tty = -1;
+
+ tty = open(line, O_RDWR | O_NOCTTY);
+
+ if(tty < 0)
+ goto bail;
+
+#ifdef TIOCSCTTY
+ rc = ioctl(tty, TIOCSCTTY, (char *)0);
+ if(rc < 0) {
+ goto bail;
+ }
+#endif
+
+#ifdef SVR4
+ rc = ioctl(tty, I_PUSH, "ptem");
+ if(rc < 0)
+ goto bail;
+
+ rc = ioctl(tty, I_PUSH, "ldterm");
+ if(rc < 0)
+ goto bail;
+
+ rc = ioctl(tty, I_PUSH, "ttcompat");
+ if(rc < 0)
+ goto bail;
+#endif
+
+ return tty;
+
+ bail:
+ if(tty >= 0)
+ close(tty);
+ return -1;
+}
+
+#ifdef _POSIX_SAVED_IDS
+int
+droppriv()
+{
+ int rc;
+ rc = setuid(getuid());
+ if(rc < 0)
+ return rc;
+ return setgid(getgid());
+}
+#else
+int
+droppriv()
+{
+ int uid = getuid();
+ int euid = geteuid();
+ int gid = getgid();
+ int egid = getegid();
+
+ if(uid != euid || gid != egid) {
+ errno = ENOSYS;
+ return -1;
+ }
+ return 0;
+}
+#endif
diff --git a/sys.h b/sys.h
new file mode 100644
index 0000000..f9cb086
--- /dev/null
+++ b/sys.h
@@ -0,0 +1,33 @@
+/*
+Copyright (c) 2001 by Juliusz Chroboczek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+int waitForOutput(int fd);
+int waitForInput(int fd1, int fd2);
+int setWindowSize(int sfd, int dfd);
+int installHandler(int signum, void (*handler)(int));
+int saveTermios(void);
+int restoreTermios(void);
+int setRawTermios(void);
+char *my_basename(char *path);
+int allocatePty(int *pty_return, char **line_return);
+int openTty(char *line);
+int droppriv(void);