summaryrefslogtreecommitdiff
path: root/Build/source/texk/ptexenc/ptexenc.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/ptexenc/ptexenc.c')
-rw-r--r--Build/source/texk/ptexenc/ptexenc.c660
1 files changed, 660 insertions, 0 deletions
diff --git a/Build/source/texk/ptexenc/ptexenc.c b/Build/source/texk/ptexenc/ptexenc.c
new file mode 100644
index 00000000000..f9e8f165527
--- /dev/null
+++ b/Build/source/texk/ptexenc/ptexenc.c
@@ -0,0 +1,660 @@
+/*
+ * KANJI Code conversion routines.
+ */
+
+#include <kpathsea/config.h>
+#include <kpathsea/c-memstr.h>
+#include <kpathsea/variable.h>
+#include <kpathsea/readable.h>
+
+#include <ptexenc/c-auto.h>
+#include <ptexenc/ptexenc.h>
+#include <ptexenc/kanjicnv.h>
+#include <ptexenc/unicode.h>
+#include <ptexenc/unicode-jp.h>
+
+#include <ctype.h>
+
+#define ENC_UNKNOWN 0
+#define ENC_JIS 1
+#define ENC_EUC 2
+#define ENC_SJIS 3
+#define ENC_UTF8 4
+
+#define ESC '\033'
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#else
+#include <limits.h>
+#endif /* HAVE_SYS_PARAM_H */
+#ifndef NOFILE
+#define NOFILE OPEN_MAX
+#endif
+
+char *ptexenc_version_string = "ptetex " PTEXENC_VERSION;
+
+static int file_enc = ENC_UNKNOWN;
+static int internal_enc = ENC_UNKNOWN;
+static int terminal_enc = ENC_UNKNOWN;
+
+
+static string enc_to_string(int enc)
+{
+ switch (enc) {
+ case ENC_JIS: return "jis";
+ case ENC_EUC: return "euc";
+ case ENC_SJIS: return "sjis";
+ case ENC_UTF8: return "utf8";
+ default: return "?";
+ }
+}
+
+static int string_to_enc(string str)
+{
+ if (str == NULL) return ENC_UNKNOWN;
+ if (strcasecmp(str, "default")== 0) return DEFAULT_KANJI_ENC;
+ if (strcasecmp(str, "jis") == 0) return ENC_JIS;
+ if (strcasecmp(str, "euc") == 0) return ENC_EUC;
+ if (strcasecmp(str, "sjis") == 0) return ENC_SJIS;
+ if (strcasecmp(str, "utf8") == 0) return ENC_UTF8;
+ return -1; /* error */
+}
+
+static int get_default_enc(void)
+{
+ /* kpse_var_value("PTEX_KANJI_ENC") aborts
+ if 'kpse_program_name' is empty. It typically occurs
+ when 'ptex' and 'jmpost' print version messages. */
+ string var = getenv("PTEX_KANJI_ENC");
+ int enc = string_to_enc(var);
+ if (enc < 0) {
+ fprintf(stderr, "Warning: Unknown environment value "
+ "PTEX_KANJI_ENC='%s'\n", var);
+ } else if (enc != ENC_UNKNOWN) {
+ return enc;
+ }
+ return DEFAULT_KANJI_ENC;
+}
+
+static void set_file_enc(int enc)
+{
+ file_enc = enc;
+}
+
+static void set_internal_enc(int enc)
+{
+ if (enc == ENC_SJIS) internal_enc = ENC_SJIS;
+ else /* EUC, JIS, UTF8 */ internal_enc = ENC_EUC;
+}
+
+static int get_file_enc(void)
+{
+ if (file_enc == ENC_UNKNOWN) set_file_enc(get_default_enc());
+ return file_enc;
+}
+
+static int get_internal_enc(void)
+{
+ if (internal_enc == ENC_UNKNOWN) set_internal_enc(get_default_enc());
+ return internal_enc;
+}
+
+int get_terminal_enc(void)
+{
+ if (terminal_enc == ENC_UNKNOWN) {
+ char lang[16]; /* enough large space */
+ char *s = getenv("LC_ALL");
+ if (s == NULL) s = getenv("LC_MESSAGES");
+ if (s == NULL) s = getenv("LANG");
+ if (s == NULL) s = getenv("LANGUAGE");
+ if (s == NULL) s = "";
+ if (strrchr(s, '.') != NULL) s = strrchr(s, '.') + 1;
+ strncpy(lang, s, sizeof(lang) - 1);
+ lang[sizeof(lang) - 1] = '\0';
+ if (strcasecmp(lang, "euc") == 0) terminal_enc = ENC_EUC;
+ else if (strcasecmp(lang, "eucJP")== 0) terminal_enc = ENC_EUC;
+ else if (strcasecmp(lang, "ujis") == 0) terminal_enc = ENC_EUC;
+ else if (strcasecmp(lang, "sjis") == 0) terminal_enc = ENC_SJIS;
+ else if (strcasecmp(lang, "utf8") == 0) terminal_enc = ENC_UTF8;
+ else if (strcasecmp(lang, "UTF-8")== 0) terminal_enc = ENC_UTF8;
+ else if (strcasecmp(lang, "jis") == 0) terminal_enc = ENC_JIS;
+ else if (strcasecmp(lang, "ISO-2022-JP")== 0) terminal_enc = ENC_JIS;
+ else terminal_enc = get_file_enc();
+ }
+ return terminal_enc;
+}
+
+string get_enc_string(void)
+{
+ static char buffer[20]; /* enough large space */
+
+ if (get_file_enc() == get_internal_enc()) {
+ return enc_to_string(get_file_enc());
+ } else {
+ sprintf(buffer, "%s.%s",
+ enc_to_string(get_file_enc()),
+ enc_to_string(get_internal_enc()));
+ return buffer;
+ }
+}
+
+boolean set_enc_string(string file_str, string internal_str)
+{
+ int file = string_to_enc(file_str);
+ int internal = string_to_enc(internal_str);
+
+ if (file < 0 || internal < 0) return false; /* error */
+ if (file != ENC_UNKNOWN) { set_file_enc(file); nkf_disable(); }
+ if (internal != ENC_UNKNOWN) set_internal_enc(internal);
+ return true;
+}
+
+boolean is_internalSJIS(void)
+{
+ return (internal_enc == ENC_SJIS);
+}
+
+
+/* check char range (kanji 1st) */
+boolean iskanji1(int c)
+{
+ if (is_internalSJIS()) return isSJISkanji1(c);
+ /* EUC */ return isEUCkanji1(c);
+}
+
+/* check char range (kanji 2nd) */
+boolean iskanji2(int c)
+{
+ if (is_internalSJIS()) return isSJISkanji2(c);
+ /* EUC */ return isEUCkanji2(c);
+}
+
+/* multi-byte char length in s[pos] */
+int multistrlen(string s, int len, int pos)
+{
+ s += pos; len -= pos;
+ if (len < 2) return 1;
+ if (is_internalSJIS()) {
+ if (isSJISkanji1(s[0]) && isSJISkanji2(s[1])) return 2;
+ } else { /* EUC */
+ if (isEUCkanji1(s[0]) && isEUCkanji2(s[1])) return 2;
+ }
+ return 1;
+}
+
+/* buffer (EUC/SJIS/UTF-8) to internal (EUC/SJIS) code conversion */
+long fromBUFF(string s, int len, int pos)
+{
+ s += pos; len -= pos;
+ if (len < 2) return s[0];
+ if (is_internalSJIS()) {
+ if (isSJISkanji1(s[0]) && isSJISkanji2(s[1])) return HILO(s[0], s[1]);
+ } else { /* EUC */
+ if (isEUCkanji1(s[0]) && isEUCkanji2(s[1])) return HILO(s[0], s[1]);
+ }
+ return s[0];
+}
+
+/* internal (EUC/SJIS) to buffer (EUC/SJIS) code conversion */
+long toBUFF(long kcode)
+{
+ return kcode;
+}
+
+
+/* JIS to internal (EUC/SJIS) code conversion */
+long fromJIS(long kcode)
+{
+ if (is_internalSJIS()) return JIStoSJIS(kcode);
+ /* EUC */ return JIStoEUC(kcode);
+}
+
+/* internal (EUC/SJIS) to JIS code conversion */
+long toJIS(long kcode)
+{
+ if (is_internalSJIS()) return SJIStoJIS(kcode);
+ /* EUC */ return EUCtoJIS(kcode);
+}
+
+
+/* EUC to internal (EUC/SJIS) code conversion */
+long fromEUC(long kcode)
+{
+ if (is_internalSJIS()) return fromJIS(EUCtoJIS(kcode));
+ /* EUC */ return kcode;
+}
+
+/* internal (EUC/SJIS) to EUC code conversion */
+static long toEUC(long kcode)
+{
+ if (is_internalSJIS()) return JIStoEUC(toJIS(kcode));
+ /* EUC */ return kcode;
+
+}
+
+
+/* SJIS to internal (EUC/SJIS) code conversion */
+long fromSJIS(long kcode)
+{
+ if (is_internalSJIS()) return kcode;
+ /* EUC */ return fromJIS(SJIStoJIS(kcode));
+}
+
+/* internal (EUC/SJIS) to SJIS code conversion */
+static long toSJIS(long kcode)
+{
+ if (is_internalSJIS()) return kcode;
+ /* EUC */ return JIStoSJIS(toJIS(kcode));
+}
+
+
+/* KUTEN to internal (EUC/SJIS) code conversion */
+long fromKUTEN(long kcode)
+{
+ return fromJIS(KUTENtoJIS(kcode));
+}
+
+
+/* UCS to internal (EUC/SJIS) code conversion */
+static long fromUCS(long kcode)
+{
+ kcode = UCS2toJIS(kcode);
+ if (kcode == 0) return 0;
+ return fromJIS(kcode);
+}
+
+/* internal (EUC/SJIS) to UCS code conversion */
+static long toUCS(long kcode)
+{
+ return JIStoUCS2(toJIS(kcode));
+}
+
+/* internal (EUC/SJIS) to 'enc' code conversion */
+static long toENC(long kcode, int enc)
+{
+ switch (enc) {
+ case ENC_UTF8: return UCStoUTF8(toUCS(kcode));
+ case ENC_JIS: return toJIS(kcode);
+ case ENC_EUC: return toEUC(kcode);
+ case ENC_SJIS: return toSJIS(kcode);
+ default:
+ fprintf(stderr, "toENC: unknown enc (%d).\n", enc);
+ return 0;
+ }
+}
+
+
+
+#define KANJI_IN LONG(0, ESC, '$', 'B')
+#define KANJI_OUT LONG(0, ESC, '(', 'B')
+
+static int put_multibyte(long c, FILE *fp) {
+ if (BYTE1(c) != 0 && putc(BYTE1(c), fp) == EOF) return EOF;
+ if (BYTE2(c) != 0 && putc(BYTE2(c), fp) == EOF) return EOF;
+ if (BYTE3(c) != 0 && putc(BYTE3(c), fp) == EOF) return EOF;
+ /* always */ return putc(BYTE4(c), fp);
+}
+
+/* putc() with code conversion */
+int putc2(int c, FILE *fp)
+{
+ static int inkanji[NOFILE]; /* 0: not in Kanji
+ 1: in JIS Kanji and first byte is in c1[]
+ -1: in JIS Kanji and c1[] is empty */
+ static unsigned char c1[NOFILE];
+ const int fd = fileno(fp);
+ int ret = c, output_enc;
+
+ if (fp == stdout || fp == stderr) output_enc = get_terminal_enc();
+ else output_enc = get_file_enc();
+
+ if (inkanji[fd] > 0) { /* KANJI 2nd */
+ ret = put_multibyte(toENC(HILO(c1[fd], c), output_enc), fp);
+ inkanji[fd] = -1;
+ } else if (iskanji1(c)) { /* KANJI 1st */
+ if (inkanji[fd] == 0 && output_enc == ENC_JIS) {
+ ret = put_multibyte(KANJI_IN, fp);
+ }
+ c1[fd] = c;
+ inkanji[fd] = 1;
+ } else { /* ASCII */
+ if (inkanji[fd] < 0 && output_enc == ENC_JIS) {
+ ret = put_multibyte(KANJI_OUT, fp);
+ }
+ ret = putc(c, fp);
+ inkanji[fd] = 0;
+ }
+ return ret;
+}
+
+/* fputs() with code conversion */
+int fputs2(const char *s, FILE *fp)
+{
+ while (*s != '\0') {
+ int ret = putc2((unsigned char)*s, fp);
+ if (ret == EOF) return EOF;
+ s++;
+ }
+ return 1;
+}
+
+
+static struct unget_st {
+ int size;
+ int buff[4];
+} ungetbuff[NOFILE];
+
+int getc4(FILE *fp)
+{
+ struct unget_st *p = &ungetbuff[fileno(fp)];
+
+ if (p->size == 0) return getc(fp);
+ return p->buff[--p->size];
+}
+
+int ungetc4(int c, FILE *fp)
+{
+ struct unget_st *p = &ungetbuff[fileno(fp)];
+
+ if (p->size >= 4) return EOF;
+ return p->buff[p->size++] = c;
+}
+
+
+static string buffer;
+static long first, last;
+static boolean combin_voiced_sound(boolean semi)
+{
+ int i;
+
+ if (last-2 < first) return false;
+ if (multistrlen(buffer,last,last-2) != 2) return false;
+ i = toUCS(fromBUFF(buffer,last,last-2));
+ i = get_voiced_sound(i, semi);
+ if (i == 0) return false;
+ i = toBUFF(fromUCS(i));
+ buffer[last-2] = HI(i);
+ buffer[last-1] = LO(i);
+ return true;
+}
+
+static void write_multibyte(long i)
+{
+ if (BYTE1(i) != 0) buffer[last++] = BYTE1(i);
+ if (BYTE2(i) != 0) buffer[last++] = BYTE2(i);
+ /* always */ buffer[last++] = BYTE3(i);
+ /* always */ buffer[last++] = BYTE4(i);
+}
+
+static void write_hex(int i)
+{
+ sprintf(buffer + last, "^^%02x", i);
+ last += 4;
+}
+
+/* getc() with check of broken encoding of UTF-8 */
+static int getcUTF8(FILE *fp)
+{
+ int c = getc4(fp);
+
+ if (isUTF8(2,2,c)) return c;
+ ungetc4(c, fp);
+ return EOF;
+}
+
+static void get_utf8(int i, FILE *fp)
+{
+ long u = 0, j;
+ int i2 = EOF, i3 = EOF, i4 = EOF;
+
+ switch (UTF8length(i)) {
+ case 2:
+ i2 = getcUTF8(fp); if (i2 == EOF) break;
+ u = UTF8BtoUCS(i, i2);
+ break;
+ case 3:
+ i2 = getcUTF8(fp); if (i2 == EOF) break;
+ i3 = getcUTF8(fp); if (i3 == EOF) break;
+ u = UTF8CtoUCS(i, i2, i3);
+ if (u == U_BOM) return; /* just ignore */
+ if (u == U_VOICED && combin_voiced_sound(false)) return;
+ if (u == U_SEMI_VOICED && combin_voiced_sound(true)) return;
+ break;
+ case 4:
+ i2 = getcUTF8(fp); if (i2 == EOF) break;
+ i3 = getcUTF8(fp); if (i3 == EOF) break;
+ i4 = getcUTF8(fp); if (i4 == EOF) break;
+ u = UTF8DtoUCS(i, i2, i3, i4);
+ break;
+ default:
+ u = U_REPLACEMENT_CHARACTER;
+ break;
+ }
+
+ j = toBUFF(fromUCS(u));
+ if (j == 0) { /* can't represent (typically umlaut o in EUC) */
+ write_hex(i);
+ if (i2 != EOF) write_hex(i2);
+ if (i3 != EOF) write_hex(i3);
+ if (i4 != EOF) write_hex(i4);
+ } else {
+ write_multibyte(j);
+ }
+}
+
+static void get_euc(int i, FILE *fp)
+{
+ int j = getc4(fp);
+
+ if (isEUCkanji2(j)) {
+ write_multibyte(toBUFF(fromEUC(HILO(i,j))));
+ } else {
+ buffer[last++] = i;
+ ungetc4(j, fp);
+ }
+}
+
+static void get_sjis(int i, FILE *fp)
+{
+ int j = getc4(fp);
+
+ if (isSJISkanji2(j)) {
+ write_multibyte(toBUFF(fromSJIS(HILO(i,j))));
+ } else {
+ buffer[last++] = i;
+ ungetc4(j, fp);
+ }
+}
+
+static boolean is_tail(long *c, FILE *fp)
+{
+ if (*c == EOF) return true;
+ if (*c == '\n') return true;
+ if (*c == '\r') {
+ int d = getc4(fp);
+ if (d == '\n') *c = d;
+ else ungetc4(d, fp);
+ return true;
+ }
+ return false;
+}
+
+#define MARK_LEN 4
+/* if stream begins with BOM + 7bit char */
+static boolean isUTF8Nstream(FILE *fp)
+{
+ int i;
+ int c[MARK_LEN];
+ int bom_u[MARK_LEN] = { 0xEF, 0xBB, 0xBF, 0x7E };
+ int bom_l[MARK_LEN] = { 0xEF, 0xBB, 0xBF, 0 };
+
+ for (i=0; i<MARK_LEN; i++) {
+ c[i] = getc4(fp);
+ if (!(bom_l[i] <= c[i] && c[i] <= bom_u[i])) {
+ do { ungetc4(c[i], fp); } while (--i>0);
+ return false;
+ }
+ }
+ ungetc4(c[MARK_LEN-1], fp);
+ return true;
+}
+
+static int infile_enc[NOFILE]; /* ENC_UNKNOWN (=0): not determined
+ other: determined */
+
+/* input line with encoding conversion */
+long input_line2(FILE *fp, string buff, long pos,
+ const long buffsize, int *lastchar)
+{
+ long i;
+ static boolean injis = false;
+ const int fd = fileno(fp);
+
+ if (infile_enc[fd] == ENC_UNKNOWN) { /* just after opened */
+ if (isUTF8Nstream(fp)) infile_enc[fd] = ENC_UTF8;
+ else infile_enc[fd] = get_file_enc();
+ }
+ buffer = buff;
+ first = last = pos;
+
+ while (last < buffsize-30 && (i=getc4(fp)) != EOF && i!='\n' && i!='\r') {
+ /* 30 is enough large size for one char */
+ /* attention: 4 times of write_hex() eats 16byte */
+ if (i == ESC) {
+ if ((i=getc4(fp)) == '$') { /* ESC '$' (Kanji-in) */
+ i = getc4(fp);
+ if (i == '@' || i == 'B') {
+ injis = true;
+ } else { /* broken Kanji-in */
+ buffer[last++] = ESC;
+ buffer[last++] = '$';
+ if (is_tail(&i, fp)) break;
+ buffer[last++] = i;
+ }
+ } else if (i == '(') { /* ESC '(' (Kanji-out) */
+ i = getc4(fp);
+ if (i == 'J' || i == 'B' || i == 'H') {
+ injis = false;
+ } else { /* broken Kanji-out */
+ buffer[last++] = ESC;
+ buffer[last++] = '(';
+ if (is_tail(&i, fp)) break;
+ buffer[last++] = i;
+ }
+ } else { /* broken ESC */
+ buffer[last++] = ESC;
+ if (is_tail(&i, fp)) break;
+ buffer[last++] = i;
+ }
+ } else { /* rather than ESC */
+ if (injis) { /* in JIS */
+ long j = getc4(fp);
+ if (is_tail(&j, fp)) {
+ buffer[last++] = i;
+ i = j;
+ break;
+ } else { /* JIS encoding */
+ i = fromJIS(HILO(i,j));
+ if (i == 0) i = fromUCS(U_REPLACEMENT_CHARACTER);
+ write_multibyte(toBUFF(i));
+ }
+ } else { /* normal */
+ if (infile_enc[fd] == ENC_SJIS && isSJISkanji1(i)) {
+ get_sjis(i, fp);
+ } else if (infile_enc[fd] == ENC_EUC && isEUCkanji1(i)) {
+ get_euc(i, fp);
+ } else if (infile_enc[fd] == ENC_UTF8 && UTF8length(i) > 1) {
+ get_utf8(i, fp);
+ } else {
+ buffer[last++] = i;
+ }
+ }
+ }
+ }
+
+ buffer[last] = '\0';
+ if (i == EOF || i == '\n' || i == '\r') injis = false;
+ if (lastchar != NULL) *lastchar = i;
+ return last;
+}
+
+
+/* only for pbibtex */
+long input_line3(FILE *fp, string buff, long pos, const long buffsize)
+{
+ int i;
+ long last;
+
+ last = input_line2(fp, buff, pos, buffsize, &i);
+ if (i == EOF && pos == last) return -1;
+ if (i != EOF && i != '\n' && i != '\r') return -1;
+ return last;
+}
+
+
+static string in_filter = NULL;
+static FILE *piped_fp[NOFILE];
+static int piped_num = 0;
+
+void nkf_disable(void)
+{
+ in_filter = "";
+}
+
+#ifdef NKF_TEST
+#include <stdlib.h>
+static void nkf_check(void)
+{
+ if (piped_num > 0) {
+ fprintf(stderr, "nkf_check: %d nkf_open() did not closed.\n",
+ piped_num);
+ } else {
+ fprintf(stderr, "nkf_check: nkf_open() OK.\n");
+ }
+}
+#endif /* NKF_TEST */
+
+/* 'mode' must be read */
+FILE *nkf_open(const char *path, const char *mode) {
+ char buff[PATH_MAX * 2 + 20]; /* 20 is enough gaps */
+ FILE *fp;
+
+ if (in_filter == NULL) {
+ in_filter = kpse_var_value("PTEX_IN_FILTER");
+ if (in_filter == NULL || strcasecmp(in_filter, "no") == 0) {
+ nkf_disable();
+ }
+#ifdef NKF_TEST
+ atexit(nkf_check);
+#endif /* NKF_TEST */
+ }
+
+ if (in_filter[0] == '\0') return fopen(path, mode);
+ path = kpse_readable_file(path);
+ if (path == NULL) return NULL; /* can't read */
+
+ sprintf(buff, "%.*s < '%.*s'", PATH_MAX, in_filter, PATH_MAX, path);
+ /* fprintf(stderr, "\n`%s`", buff); */
+ fp = popen(buff , "r");
+ if (piped_num < NOFILE) piped_fp[piped_num++] = fp;
+ return fp;
+}
+
+/* we must close in stack order (FILO) or in queue order (FIFO) */
+int nkf_close(FILE *fp) {
+ infile_enc[fileno(fp)] = ENC_UNKNOWN;
+ if (piped_num > 0) {
+ if (fp == piped_fp[piped_num-1]) { /* for FILO */
+ piped_num--;
+ return pclose(fp);
+ }
+ if (fp == piped_fp[0]) { /* for FIFO */
+ int i;
+ piped_num--;
+ for (i=0; i<piped_num; i++) piped_fp[i] = piped_fp[i+1];
+ return pclose(fp);
+ }
+ }
+ return fclose(fp);
+}