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.c1059
1 files changed, 1059 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..91cb4fa6f5a
--- /dev/null
+++ b/Build/source/texk/ptexenc/ptexenc.c
@@ -0,0 +1,1059 @@
+/*
+ * KANJI Code conversion routines.
+ */
+
+#include <kpathsea/config.h>
+#include <kpathsea/c-memstr.h>
+#include <kpathsea/variable.h>
+#include <kpathsea/readable.h>
+#include <kpathsea/c-limits.h>
+#include <kpathsea/c-pathmx.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 ENC_UPTEX 5
+
+static int default_kanji_enc;
+static boolean UPTEX_enabled;
+static boolean prior_file_enc = false;
+
+#define ESC '\033'
+
+#ifndef NOFILE
+# ifndef OPEN_MAX
+# define OPEN_MAX 132 /* sup_max_in_open(127) +alpha */
+# endif
+# define NOFILE OPEN_MAX
+#endif
+
+const char *ptexenc_version_string = PTEXENCVERSION;
+#if defined(WIN32)
+FILE *Poptr;
+int infile_enc_auto;
+#else
+static int infile_enc_auto = 1;
+#endif
+
+static int file_enc = ENC_UNKNOWN;
+static int internal_enc = ENC_UNKNOWN;
+static int terminal_enc = ENC_UNKNOWN;
+
+const_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";
+ case ENC_UPTEX: if (UPTEX_enabled) return "uptex";
+ default: return "?";
+ }
+}
+
+static int string_to_enc(const_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;
+ if (UPTEX_enabled && strcasecmp(str, "uptex") == 0) return ENC_UPTEX;
+
+ if (strcasecmp(str, "BINARY") == 0) return ENC_JIS;
+ if (strcasecmp(str, "ISO-2022-JP") == 0) return ENC_JIS;
+ if (strcasecmp(str, "EUC-JP") == 0) return ENC_EUC;
+ if (strcasecmp(str, "Shift_JIS") == 0) return ENC_SJIS;
+ if (strcasecmp(str, "UTF-8") == 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)
+{
+ if (enc == ENC_UPTEX) file_enc = ENC_UTF8;
+ else /* rest */ file_enc = enc;
+}
+
+static void set_internal_enc(int enc)
+{
+ if (enc == ENC_SJIS) internal_enc = ENC_SJIS;
+ else if (UPTEX_enabled && enc == ENC_UPTEX) internal_enc = ENC_UPTEX;
+ 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;
+}
+
+int get_internal_enc(void)
+{
+ if (internal_enc == ENC_UNKNOWN) set_internal_enc(get_default_enc());
+ return internal_enc;
+}
+
+static int get_terminal_enc(void)
+{
+ if (terminal_enc == ENC_UNKNOWN) {
+ char lang[16]; /* enough large space */
+ const 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;
+}
+
+/* enable/disable UPTEX */
+void enable_UPTEX (boolean enable)
+{
+ UPTEX_enabled = enable;
+ if (enable) {
+ default_kanji_enc = ENC_UPTEX;
+ internal_enc = ENC_UPTEX;
+ } else {
+#ifdef WIN32
+ default_kanji_enc = ENC_UTF8;
+ internal_enc = ENC_SJIS;
+#else
+ default_kanji_enc = ENC_UTF8;
+ internal_enc = ENC_EUC;
+#endif
+ }
+}
+
+void set_prior_file_enc(void)
+{
+ prior_file_enc = true;
+}
+
+const_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(const_string file_str, const_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);
+#if !defined(WIN32)
+ infile_enc_auto = 0;
+ nkf_disable();
+#endif
+ }
+ if (internal != ENC_UNKNOWN) set_internal_enc(internal);
+ return true;
+}
+
+boolean is_internalSJIS(void)
+{
+ return (internal_enc == ENC_SJIS);
+}
+
+boolean is_internalEUC(void)
+{
+ return (internal_enc == ENC_EUC);
+}
+
+boolean is_internalUPTEX(void)
+{
+ return (internal_enc == ENC_UPTEX);
+}
+
+
+/* check char range */
+boolean ismultichr (int length, int nth, int c)
+{
+ if (is_internalUPTEX()) return isUTF8(length, nth, c);
+ if (length == 2) {
+ if (nth == 1) {
+ if (is_internalSJIS()) return isSJISkanji1(c);
+ /* EUC */ return isEUCkanji1(c);
+ } else if (nth == 2) {
+ if (is_internalSJIS()) return isSJISkanji2(c);
+ /* EUC */ return isEUCkanji2(c);
+ }
+ }
+ if ((length == 3 || length == 4) &&
+ (0 < nth && nth <= length)) return false;
+ fprintf(stderr, "ismultichr: unexpected param length=%d, nth=%d\n",
+ length, nth);
+ return false;
+}
+
+/* check char range (kanji 1st) */
+boolean iskanji1(int c)
+{
+ if (is_internalUPTEX()) return (isUTF8(2,1,c) ||
+ isUTF8(3,1,c) ||
+ isUTF8(4,1,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(unsigned char *s, int len, int pos)
+{
+ s += pos; len -= pos;
+ if (is_internalUPTEX()) {
+ int ret = UTF8Slength(s, len);
+ if (ret < 0) return 1;
+ return ret;
+ }
+ 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;
+}
+
+/* with not so strict range check */
+int multibytelen (int first_byte)
+{
+ if (is_internalUPTEX()) {
+ return UTF8length(first_byte);
+ } else if (is_internalSJIS()) {
+ if (isSJISkanji1(first_byte)) return 2;
+ } else { /* EUC */
+ if (isEUCkanji1(first_byte)) return 2;
+ }
+ return 1;
+}
+
+/* buffer (EUC/SJIS/UTF-8) to internal (EUC/SJIS/UPTEX) code conversion */
+long fromBUFF(unsigned char *s, int len, int pos)
+{
+ s += pos; len -= pos;
+ if (is_internalUPTEX()) {
+ if (UTF8Slength(s, len) < 0) return s[0];
+ return UCStoUPTEX(UTF8StoUCS(s));
+ }
+ 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/UPTEX) to buffer (EUC/SJIS/UTF-8) code conversion */
+long toBUFF(long kcode)
+{
+ if (is_internalUPTEX()) kcode = UCStoUTF8(UPTEXtoUCS(kcode));
+ return kcode;
+}
+
+/* DVI (JIS/UCS) to internal (EUC/SJIS/UPTEX) code conversion */
+long fromDVI (long kcode)
+{
+ if (is_internalUPTEX()) return UCStoUPTEX(kcode);
+ if (is_internalSJIS()) return JIStoSJIS(kcode);
+ /* EUC */ return JIStoEUC(kcode);
+}
+
+/* internal (EUC/SJIS/UPTEX) to DVI (JIS/UCS) code conversion */
+long toDVI (long kcode)
+{
+ if (is_internalUPTEX()) return UPTEXtoUCS(kcode);
+ if (is_internalSJIS()) return SJIStoJIS(kcode);
+ /* EUC */ return EUCtoJIS(kcode);
+}
+
+/* JIS to internal (EUC/SJIS/UPTEX) code conversion */
+long fromJIS(long kcode)
+{
+ if (is_internalUPTEX()) return UCStoUPTEX(JIStoUCS2(kcode));
+ if (is_internalSJIS()) return JIStoSJIS(kcode);
+ /* EUC */ return JIStoEUC(kcode);
+}
+
+/* internal (EUC/SJIS/UPTEX) to JIS code conversion */
+long toJIS(long kcode)
+{
+ if (is_internalUPTEX()) return UCS2toJIS(UPTEXtoUCS(kcode));
+ if (is_internalSJIS()) return SJIStoJIS(kcode);
+ /* EUC */ return EUCtoJIS(kcode);
+}
+
+
+/* EUC to internal (EUC/SJIS/UPTEX) code conversion */
+long fromEUC(long kcode)
+{
+ if (!is_internalUPTEX() && !is_internalSJIS()) return kcode;
+ return fromJIS(EUCtoJIS(kcode));
+}
+
+/* internal (EUC/SJIS/UPTEX) to EUC code conversion */
+static long toEUC(long kcode)
+{
+ if (!is_internalUPTEX() && !is_internalSJIS()) return kcode;
+ return JIStoEUC(toJIS(kcode));
+}
+
+
+/* SJIS to internal (EUC/SJIS/UPTEX) code conversion */
+long fromSJIS(long kcode)
+{
+ if (is_internalSJIS()) return kcode;
+ return fromJIS(SJIStoJIS(kcode));
+}
+
+/* internal (EUC/SJIS/UPTEX) to SJIS code conversion */
+static long toSJIS(long kcode)
+{
+ if (is_internalSJIS()) return kcode;
+ return JIStoSJIS(toJIS(kcode));
+}
+
+
+/* KUTEN to internal (EUC/SJIS/UPTEX) code conversion */
+long fromKUTEN(long kcode)
+{
+ return fromJIS(KUTENtoJIS(kcode));
+}
+
+
+/* UCS to internal (EUC/SJIS/UPTEX) code conversion */
+long fromUCS(long kcode)
+{
+ if (is_internalUPTEX()) return UCStoUPTEX(kcode);
+ kcode = UCS2toJIS(kcode);
+ if (kcode == 0) return 0;
+ return fromJIS(kcode);
+}
+
+/* internal (EUC/SJIS/UPTEX) to UCS code conversion */
+long toUCS(long kcode)
+{
+ if (is_internalUPTEX()) return UPTEXtoUCS(kcode);
+ return JIStoUCS2(toJIS(kcode));
+}
+
+/* internal (EUC/SJIS/UPTEX) to UTF-8 code conversion */
+static long toUTF8 (long kcode)
+{
+ return UCStoUTF8(toUCS(kcode));
+}
+
+/* internal (EUC/SJIS/UPTEX) to 'enc' code conversion */
+static long toENC(long kcode, int enc)
+{
+ switch (enc) {
+ case ENC_UTF8: return toUTF8(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) {
+#ifdef WIN32
+ const int fd = fileno(fp);
+
+ if ((fd == fileno(stdout) || fd == fileno(stderr)) && _isatty(fd)) {
+ HANDLE hStdout;
+ DWORD ret, wclen;
+ UINT cp;
+ wchar_t buff[2];
+ char str[4];
+ int mblen;
+
+ if (fd == fileno(stdout))
+ hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ else
+ hStdout = GetStdHandle(STD_ERROR_HANDLE);
+
+ mblen=0;
+ if (BYTE1(c) != 0) str[mblen++]=BYTE1(c);
+ if (BYTE2(c) != 0) str[mblen++]=BYTE2(c);
+ if (BYTE3(c) != 0) str[mblen++]=BYTE3(c);
+ /* always */ str[mblen++]=BYTE4(c);
+
+#define CP_UTF8 65001
+
+ cp = CP_UTF8;
+ if (MultiByteToWideChar(cp, 0, str, mblen, buff, 2) == 0)
+ return EOF;
+
+ wclen = mblen > 3 ? 2 : 1;
+ if (WriteConsoleW(hStdout, buff, wclen, &ret, NULL) == 0)
+ return EOF;
+
+ return BYTE4(c);
+ }
+#endif
+
+ 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);
+}
+
+static int flush (unsigned char *buff, int num, FILE *fp)
+{
+ int i, ret = EOF;
+
+ /* fprintf(stderr, "putc2: unexpected chars. ( ");
+ for (i=0; i<num; i++) fprintf(stderr, "%02X ", buff[i]);
+ fprintf(stderr, ")\n");
+ */
+ for (i=0; i<num; i++) ret = putc(buff[i], fp);
+ return ret;
+}
+
+/* putc() with code conversion */
+int putc2(int c, FILE *fp)
+{
+ static int num[NOFILE];
+ /* 0 : not in Kanji
+ 1..4 : in JIS Kanji and num[] bytes are in store[][]
+ -1 : in JIS Kanji and store[][] is empty */
+ static unsigned char store[NOFILE][4];
+ const int fd = fileno(fp);
+ int ret = c, output_enc;
+
+#ifdef WIN32
+ if ((fp == stdout || fp == stderr) && (_isatty(fd) || !prior_file_enc)) {
+ output_enc = ENC_UTF8;
+ } else
+ output_enc = get_file_enc();
+#else
+ if ((fp == stdout || fp == stderr) && !prior_file_enc) {
+ output_enc = get_terminal_enc();
+ } else
+ output_enc = get_file_enc();
+#endif
+ if (num[fd] > 0) { /* multi-byte char */
+ if (is_internalUPTEX() && iskanji1(c)) { /* error */
+ ret = flush(store[fd], num[fd], fp);
+ num[fd] = 0;
+ }
+ store[fd][num[fd]] = c;
+ num[fd]++;
+ if (multistrlen(store[fd], num[fd], 0) == num[fd]) {
+ long i = fromBUFF(store[fd], num[fd], 0);
+ ret = put_multibyte(toENC(i, output_enc), fp);
+ num[fd] = -1;
+ } else if ((is_internalUPTEX() && num[fd] == 4) ||
+ (!is_internalUPTEX() && num[fd] == 2)) { /* error */
+ ret = flush(store[fd], num[fd], fp);
+ num[fd] = -1;
+ }
+ } else if (iskanji1(c)) { /* first multi-byte char */
+ if (num[fd] == 0 && output_enc == ENC_JIS) {
+ ret = put_multibyte(KANJI_IN, fp);
+ }
+ store[fd][0] = c;
+ num[fd] = 1;
+ } else { /* ASCII */
+ if (num[fd] < 0 && output_enc == ENC_JIS) {
+ put_multibyte(KANJI_OUT, fp);
+ }
+ ret = putc(c, fp);
+ num[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];
+
+static int getc4(FILE *fp)
+{
+ struct unget_st *p = &ungetbuff[fileno(fp)];
+
+ if (p->size == 0)
+#ifdef WIN32
+ {
+ const int fd = fileno(fp);
+ HANDLE hStdin;
+ DWORD ret;
+ wchar_t wc[2];
+ long c;
+ static wchar_t wcbuf = L'\0';
+
+ if (!(fd == fileno(stdin) && _isatty(fd) && is_internalUPTEX()))
+ return getc(fp);
+
+ hStdin = GetStdHandle(STD_INPUT_HANDLE);
+ if (wcbuf) {
+ wc[0] = wcbuf;
+ wcbuf = L'\0';
+ }
+ else if (ReadConsoleW(hStdin, wc, 1, &ret, NULL) == 0)
+ return EOF;
+ if (0xd800<=wc[0] && wc[0]<0xdc00) {
+ if (ReadConsoleW(hStdin, wc+1, 1, &ret, NULL) == 0)
+ return EOF;
+ if (0xdc00<=wc[1] && wc[1]<0xe000) {
+ c = UTF16StoUTF32(wc[0], wc[1]);
+ } else {
+ wcbuf = wc[1];
+ c = U_REPLACEMENT_CHARACTER; /* illegal upper surrogate pair */
+ }
+ } else if (0xdc00<=wc[0] && wc[0]<0xe000) {
+ c = U_REPLACEMENT_CHARACTER; /* illegal lower surrogate pair */
+ } else {
+ c = wc[0];
+ }
+ c = UCStoUTF8(c);
+ /* always */ p->buff[p->size++]=BYTE4(c);
+ if (BYTE3(c) != 0) p->buff[p->size++]=BYTE3(c);
+ if (BYTE2(c) != 0) p->buff[p->size++]=BYTE2(c);
+ if (BYTE1(c) != 0) p->buff[p->size++]=BYTE1(c);
+ }
+#else
+ return getc(fp);
+#endif
+ return p->buff[--p->size];
+}
+
+static 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 unsigned char *buffer;
+static long first, last;
+static boolean combin_voiced_sound(boolean semi)
+{
+ int i, mblen;
+
+ mblen = is_internalUPTEX() ? 3 : 2;
+ if (last-mblen < first) return false;
+ if (multistrlen(buffer,last,last-mblen) != mblen) return false;
+ i = toUCS(fromBUFF(buffer,last,last-mblen));
+ i = get_voiced_sound(i, semi);
+ if (i == 0) return false;
+ i = toBUFF(fromUCS(i));
+ if (BYTE2(i) != 0) buffer[last-3] = BYTE2(i);
+ /* always */ buffer[last-2] = BYTE3(i);
+ /* always */ buffer[last-1] = BYTE4(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((char *) 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 = (u != 0) ? toBUFF(fromUCS(u)) : 0;
+ 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, unsigned char *buff, long pos,
+ const long buffsize, int *lastchar)
+{
+ long i = 0;
+ static boolean injis = false;
+ const int fd = fileno(fp);
+
+ if (infile_enc[fd] == ENC_UNKNOWN) { /* just after opened */
+ ungetbuff[fd].size = 0;
+ 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 */
+#ifdef WIN32
+ if (i == 0x1a && first == last &&
+ fd == fileno(stdin) && _isatty(fd)) { /* Ctrl+Z on console */
+ i = EOF;
+ break;
+ } else
+#endif
+ 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;
+ }
+ }
+ }
+ }
+
+ if (i != EOF || first != last) buffer[last] = '\0';
+ if (i == EOF || i == '\n' || i == '\r') injis = false;
+ if (lastchar != NULL) *lastchar = i;
+
+ return last;
+}
+
+/* set encode of stdin if fp = NULL */
+boolean setinfileenc(FILE *fp, const char *str)
+{
+ int enc;
+ enc = string_to_enc(str);
+ if (enc < 0) return false;
+ infile_enc[fileno(fp)] = enc;
+ return true;
+}
+
+boolean setstdinenc(const char *str)
+{
+ int enc;
+ enc = string_to_enc(str);
+ if (enc < 0) return false;
+ infile_enc[fileno(stdin)] = enc;
+ return true;
+}
+
+#ifdef WIN32
+void clear_infile_enc(FILE *fp)
+{
+ infile_enc[fileno(fp)] = ENC_UNKNOWN;
+}
+#else /* !WIN32 */
+static const_string in_filter = NULL;
+static FILE *piped_fp[NOFILE];
+static int piped_num = 0;
+
+void nkf_disable(void)
+{
+ in_filter = "";
+}
+
+#ifdef NKF_TEST
+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 */
+ char *name;
+ 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);
+ name = xstrdup(path);
+ if (kpse_readable_file(name) == NULL) {
+ free(name);
+ return NULL; /* can't read */
+ }
+
+ sprintf(buff, "%.*s < '%.*s'", PATH_MAX, in_filter, PATH_MAX, path);
+ free(name);
+ /* 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);
+}
+
+#define break_if_bad_utf8_second(k) if ((k<0x80)||(k>0xBF)) { i--; k='\0'; break; }
+unsigned char *ptenc_from_utf8_string_to_internal_enc(const unsigned char *is)
+{
+ int i;
+ long u = 0, j, len;
+ int i1, i2, i3, i4;
+ unsigned char *buf, *buf_bak;
+ long first_bak, last_bak;
+
+ if (terminal_enc != ENC_UTF8 || is_internalUPTEX()) return NULL;
+ buf_bak = buffer;
+ first_bak = first;
+ last_bak = last;
+
+ len = strlen(is)+1;
+ buffer = buf = xmalloc(len);
+ first = last = 0;
+
+ for (i=0; i<strlen(is); i++) {
+ i1 = is[i]; i2 = i3 = i4 = '\0';
+ switch (UTF8length(i1)) {
+ case 1:
+ buffer[last++] = i1; /* ASCII */
+ if (i1 == '\0') goto end;
+ continue;
+ case 2:
+ i2 = is[++i]; break_if_bad_utf8_second(i2);
+ u = UTF8BtoUCS(i1, i2);
+ break;
+ case 3:
+ i2 = is[++i]; break_if_bad_utf8_second(i2);
+ i3 = is[++i]; break_if_bad_utf8_second(i3);
+ u = UTF8CtoUCS(i1, i2, i3);
+ if (u == U_BOM) continue; /* just ignore */
+ if (u == U_VOICED && combin_voiced_sound(false)) continue;
+ if (u == U_SEMI_VOICED && combin_voiced_sound(true)) continue;
+ break;
+ case 4:
+ i2 = is[++i]; break_if_bad_utf8_second(i2);
+ i3 = is[++i]; break_if_bad_utf8_second(i3);
+ i4 = is[++i]; break_if_bad_utf8_second(i4);
+ u = UTF8DtoUCS(i1, i2, i3, i4);
+ break;
+ default:
+ u = U_REPLACEMENT_CHARACTER;
+ break;
+ }
+
+ j = (u != 0) ? toBUFF(fromUCS(u)) : 0;
+ if (j == 0) { /* can't represent in EUC/SJIS */
+ if (last+16>=len) buffer = buf = xrealloc(buffer, len=last+64);
+ write_hex(i1);
+ if (i2 != '\0') write_hex(i2);
+ if (i3 != '\0') write_hex(i3);
+ if (i4 != '\0') write_hex(i4);
+ } else {
+ write_multibyte(j);
+ }
+ }
+ buffer[last] = '\0';
+ end:
+ buffer = buf_bak;
+ first = first_bak;
+ last = last_bak;
+ return buf;
+}
+
+unsigned char *ptenc_from_internal_enc_string_to_utf8(const unsigned char *is)
+{
+ int i;
+ long u = 0, len;
+ int i1 = EOF, i2 = EOF;
+ unsigned char *buf, *buf_bak;
+ long first_bak, last_bak;
+
+ if (terminal_enc != ENC_UTF8 || is_internalUPTEX()) return NULL;
+ buf_bak = buffer;
+ first_bak = first;
+ last_bak = last;
+
+ len = strlen(is)+1;
+ buffer = buf = xmalloc(len*1.5);
+ first = last = 0;
+
+ for (i=0; i<strlen(is); i++) {
+ i1 = is[i];
+ switch (multibytelen(i1)) {
+ case 1:
+ buffer[last++] = i1; /* ASCII */
+ if (i1 == '\0') goto end;
+ continue;
+ case 2:
+ i2 = is[++i]; if (i2 == '\0') break;
+ u = JIStoUCS2(toJIS(HILO(i1,i2)));
+ break;
+ default:
+ u = U_REPLACEMENT_CHARACTER;
+ break;
+ }
+
+ write_multibyte(UCStoUTF8(u));
+ }
+ buffer[last] = '\0';
+ end:
+ buffer = buf_bak;
+ first = first_bak;
+ last = last_bak;
+ return buf;
+}
+
+int ptenc_get_command_line_args(int *p_ac, char ***p_av)
+{
+ int i, argc;
+ char **argv;
+
+ get_terminal_enc();
+ if (terminal_enc == ENC_UTF8 && !is_internalUPTEX()) {
+ argc = *p_ac;
+ argv = xmalloc(sizeof(char *)*(argc+1));
+ for (i=0; i<argc; i++) {
+ argv[i] = ptenc_from_utf8_string_to_internal_enc((*p_av)[i]);
+#ifdef DEBUG
+ fprintf(stderr, "Commandline arguments %d:(%s)\n", i, argv[i]);
+#endif /* DEBUG */
+ }
+ argv[argc] = NULL;
+ *p_av = argv;
+ return terminal_enc;
+ }
+ return 0;
+}
+
+#endif /* !WIN32 */