From 5b0be858da5f93a678e7665f67921f8e63559f5a Mon Sep 17 00:00:00 2001 From: Akira Kakuto Date: Tue, 3 Dec 2013 14:32:09 +0000 Subject: Support KANJI file name in (e)upTeX and XeTeX on Windows (from T. Tanaka) git-svn-id: svn://tug.org/texlive/trunk@32308 c570f23f-e606-0410-a88d-b1316a301751 --- Build/source/texk/kpathsea/ChangeLog | 5 ++ Build/source/texk/kpathsea/elt-dirs.c | 17 ++++--- Build/source/texk/kpathsea/knj.c | 81 ++++++++++++++++++++++++++++++++- Build/source/texk/kpathsea/knj.h | 15 ++++++ Build/source/texk/kpathsea/progname.c | 3 +- Build/source/texk/kpathsea/readable.c | 5 +- Build/source/texk/web2c/lib/ChangeLog | 5 ++ Build/source/texk/web2c/lib/openclose.c | 22 ++++++++- Build/source/texk/web2c/lib/texmfmp.c | 46 ++++++++++++++++++- 9 files changed, 187 insertions(+), 12 deletions(-) diff --git a/Build/source/texk/kpathsea/ChangeLog b/Build/source/texk/kpathsea/ChangeLog index c6ec4f39ed1..9ffda1014e1 100644 --- a/Build/source/texk/kpathsea/ChangeLog +++ b/Build/source/texk/kpathsea/ChangeLog @@ -1,3 +1,8 @@ +2013-12-03 TANAKA Takuji + + * elt-dirs.c, knj.c, knj.h, progname.c, readable.c: Support KANJI + file name in (e)upTeX and XeTeX on Windows. + 2013-09-22 Karl Berry * mktexlsr: output normal msgs to stdout, not stderr. diff --git a/Build/source/texk/kpathsea/elt-dirs.c b/Build/source/texk/kpathsea/elt-dirs.c index 7d61d850086..69544946928 100644 --- a/Build/source/texk/kpathsea/elt-dirs.c +++ b/Build/source/texk/kpathsea/elt-dirs.c @@ -104,7 +104,9 @@ static void expand_elt (kpathsea, str_llist_type *, string, unsigned); #ifdef WIN32 /* Shared across recursive calls, it acts like a stack. */ -static char dirname[MAX_PATH]; +static char dirname[MAX_PATH*2]; +static wchar_t dirnamew[MAX_PATH]; +static char *potname; #endif static void @@ -112,7 +114,7 @@ do_subdir (kpathsea kpse, str_llist_type *str_list_ptr, string elt, unsigned elt_length, string post) { #ifdef WIN32 - WIN32_FIND_DATA find_file_data; + WIN32_FIND_DATAW find_file_data; HANDLE hnd; int proceed; int nlinks = 2; @@ -131,7 +133,8 @@ do_subdir (kpathsea kpse, str_llist_type *str_list_ptr, string elt, #if defined (WIN32) strcpy(dirname, FN_STRING(name)); strcat(dirname, "/*.*"); /* "*.*" or "*" -- seems equivalent. */ - hnd = FindFirstFile(dirname, &find_file_data); + get_wstring_from_fsyscp(dirname, dirnamew); + hnd = FindFirstFileW(dirnamew, &find_file_data); if (hnd == INVALID_HANDLE_VALUE) { fn_free(&name); @@ -151,11 +154,13 @@ do_subdir (kpathsea kpse, str_llist_type *str_list_ptr, string elt, } proceed = 1; while (proceed) { - if (find_file_data.cFileName[0] != '.') { + if (find_file_data.cFileName[0] != L'.') { int links; /* Construct the potential subdirectory name. */ - fn_str_grow (&name, find_file_data.cFileName); + potname = get_fsyscp_from_wstring(find_file_data.cFileName, potname=NULL); + fn_str_grow (&name, potname); + free(potname); /* Maybe we have cached the leafness of this directory. The function will return 0 if unknown, @@ -197,7 +202,7 @@ do_subdir (kpathsea kpse, str_llist_type *str_list_ptr, string elt, } fn_shrink_to (&name, elt_length); } - proceed = FindNextFile (hnd, &find_file_data); + proceed = FindNextFileW (hnd, &find_file_data); } /* Update the leafness of name. */ kpathsea_dir_links(kpse, FN_STRING(name), nlinks); diff --git a/Build/source/texk/kpathsea/knj.c b/Build/source/texk/kpathsea/knj.c index bdf7d5cbf75..eeb1120e913 100644 --- a/Build/source/texk/kpathsea/knj.c +++ b/Build/source/texk/kpathsea/knj.c @@ -1,6 +1,7 @@ /* knj.c: check for 2-Byte Kanji (CP 932, SJIS) codes. Copyright 2010, 2011 Akira Kakuto. + Copyright 2013 TANAKA Takuji. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -16,8 +17,9 @@ along with this library; if not, see . */ #include +#include -int is_cp932_system; +int is_cp932_system, file_system_codepage; int isknj(int c) { @@ -48,3 +50,80 @@ int isknj2(int c) return(0); } } + +/* + Get wide string from multibyte string. +*/ +wchar_t * +get_wstring_from_mbstring(int cp, const char *mbstr, wchar_t *wstr) +{ + int len; + + len = MultiByteToWideChar(cp, 0, mbstr, -1, wstr, 0); + if (len==0) { + FATAL("cannot convert string to wide string"); + } + if (wstr==NULL) { + wstr = xmalloc(sizeof(wchar_t)*(len+1)); + } + len = MultiByteToWideChar(cp, 0, mbstr, -1, wstr, len+1); + if (len==0) { + FATAL("cannot convert multibyte string to wide string"); + } + return wstr; +} + +/* + Get multibyte string from wide string. +*/ +char * +get_mbstring_from_wstring(int cp, const wchar_t *wstr, char *mbstr) +{ + int len; + + len = WideCharToMultiByte(cp, 0, wstr, -1, mbstr, 0, NULL, NULL); + if (len==0) { + FATAL("cannot convert string to wide string"); + } + if (mbstr==NULL) { + mbstr = xmalloc(len+1); + } + len = WideCharToMultiByte(cp, 0, wstr, -1, mbstr, len+1, NULL, NULL); + if (len==0) { + FATAL("cannot convert wide string to multibyte string"); + } + return mbstr; +} + +/* + xfopen by file system codepage +*/ +FILE * +fsyscp_xfopen (const char *filename, const char *mode) +{ + FILE *f; + wchar_t *fnamew, modew[4]; +#if defined (KPSE_COMPAT_API) + kpathsea kpse; +#endif + assert(filename && mode); + + fnamew = get_wstring_from_fsyscp(filename, fnamew=NULL); + get_wstring_from_fsyscp(mode, modew); + f = _wfopen(fnamew, modew); + if (f == NULL) + FATAL_PERROR(filename); +#if defined (KPSE_COMPAT_API) + kpse = kpse_def; + if (KPATHSEA_DEBUG_P (KPSE_DEBUG_FOPEN)) { + DEBUGF_START (); + fprintf (stderr, "fsyscp_xfopen(%s [", filename); + WriteConsoleW( GetStdHandle( STD_ERROR_HANDLE ), fnamew, wcslen( fnamew ), NULL, NULL ); + fprintf (stderr, "], %s) => 0x%lx\n", mode, (unsigned long) f); + DEBUGF_END (); + } +#endif + free(fnamew); + + return f; +} diff --git a/Build/source/texk/kpathsea/knj.h b/Build/source/texk/kpathsea/knj.h index 8f1cd919687..0629213a309 100644 --- a/Build/source/texk/kpathsea/knj.h +++ b/Build/source/texk/kpathsea/knj.h @@ -1,6 +1,7 @@ /* knj.h: check for 2-Byte Kanji (CP 932, SJIS) codes. Copyright 2010, 2011 Akira Kakuto. + Copyright 2013 TANAKA Takuji. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -23,10 +24,15 @@ extern "C" { #endif extern KPSEDLL int is_cp932_system; +extern KPSEDLL int file_system_codepage; extern KPSEDLL int isknj(int c); extern KPSEDLL int isknj2(int c); +extern KPSEDLL wchar_t* get_wstring_from_mbstring(int cp, const char *mbstr, wchar_t *wstr); +extern KPSEDLL char* get_mbstring_from_wstring(int cp, const wchar_t *wstr, char *mbstr); +extern KPSEDLL FILE* fsyscp_xfopen(const char *filename, const char *mode); + #ifdef __cplusplus } #endif @@ -34,4 +40,13 @@ extern KPSEDLL int isknj2(int c); /* True if P points to a 2-Byte Kanji (CP 932, SJIS) code. */ #define IS_KANJI(p) is_cp932_system && isknj(*(p)) && isknj2(*(p+1)) +/* Get wide string from multibyte string in UTF-8 */ +#define get_wstring_from_utf8(mb,w) get_wstring_from_mbstring(CP_UTF8,mb,w) +/* Get multibyte string in UTF-8 from wide string */ +#define get_utf8_from_wstring(w,mb) get_mbstring_from_wstring(CP_UTF8,w,mb) +/* Get wide string from multibyte string in file system codepage */ +#define get_wstring_from_fsyscp(mb,w) get_wstring_from_mbstring(file_system_codepage,mb,w) +/* Get multibyte string in file system codepage from wide string */ +#define get_fsyscp_from_wstring(w,mb) get_mbstring_from_wstring(file_system_codepage,w,mb) + #endif /* not KPATHSEA_KNJ_H */ diff --git a/Build/source/texk/kpathsea/progname.c b/Build/source/texk/kpathsea/progname.c index ba43bd8679f..5952936579b 100644 --- a/Build/source/texk/kpathsea/progname.c +++ b/Build/source/texk/kpathsea/progname.c @@ -501,12 +501,13 @@ kpathsea_set_program_name (kpathsea kpse, const_string argv0, } #if defined(WIN32) - cp = GetOEMCP(); + cp = GetACP(); if (cp == 932 || cp == 936 || cp == 950) { is_cp932_system = cp; } else is_cp932_system = 0; + file_system_codepage = AreFileApisANSI() ? GetACP() : GetOEMCP(); #if defined(__MINGW32__) /* Set various info about user. Among many things, diff --git a/Build/source/texk/kpathsea/readable.c b/Build/source/texk/kpathsea/readable.c index d62957e5ba0..3e604cd9c05 100644 --- a/Build/source/texk/kpathsea/readable.c +++ b/Build/source/texk/kpathsea/readable.c @@ -40,7 +40,9 @@ static boolean READABLE(const_string fn, unsigned int st) { - if ((st = GetFileAttributes(fn)) != 0xFFFFFFFF) { + wchar_t *fnw; + fnw = get_wstring_from_fsyscp(fn, fnw=NULL); + if ((st = GetFileAttributesW(fnw)) != 0xFFFFFFFF) { /* succeeded */ errno = 0; } else { @@ -56,6 +58,7 @@ READABLE(const_string fn, unsigned int st) break; } } + if(fnw) free(fnw); return ((st != 0xFFFFFFFF) && !(st & FILE_ATTRIBUTE_DIRECTORY)); } diff --git a/Build/source/texk/web2c/lib/ChangeLog b/Build/source/texk/web2c/lib/ChangeLog index 3d19d8073b4..c81beaad816 100644 --- a/Build/source/texk/web2c/lib/ChangeLog +++ b/Build/source/texk/web2c/lib/ChangeLog @@ -1,3 +1,8 @@ +2013-12-03 TANAKA Takuji + + * openclose.c, texmfmp.c: Support KANJI file name in (e)upTeX and + XeTeX on Windows. + 2013-06-11 Peter Breitenlohner Update to e-pTeX and e-upTeX 130605 from Hironori Kitagawa. diff --git a/Build/source/texk/web2c/lib/openclose.c b/Build/source/texk/web2c/lib/openclose.c index 2620b8894bd..35301b5187c 100644 --- a/Build/source/texk/web2c/lib/openclose.c +++ b/Build/source/texk/web2c/lib/openclose.c @@ -57,7 +57,11 @@ recorder_start(void) recorder_name = temp; } +#if defined(WIN32) + recorder_file = fsyscp_xfopen(recorder_name, FOPEN_W_MODE); +#else recorder_file = xfopen(recorder_name, FOPEN_W_MODE); +#endif cwd = xgetcwd(); fprintf(recorder_file, "PWD %s\n", cwd); @@ -101,7 +105,7 @@ recorder_change_filename (string new_name) /* reopen the recorder file by FOPEN_A_MODE. */ #if defined(WIN32) - recorder_file = fopen (recorder_name, FOPEN_A_MODE); + recorder_file = fsyscp_xfopen (recorder_name, FOPEN_A_MODE); #endif if (temp) @@ -165,7 +169,11 @@ open_input (FILE **f_ptr, int filefmt, const_string fopen_mode) them from there. We only look for the name as-is. */ if (output_directory && !kpse_absolute_p (nameoffile+1, false)) { fname = concat3 (output_directory, DIR_SEP_STRING, nameoffile + 1); +#if defined(WIN32) + *f_ptr = fsyscp_xfopen (fname, fopen_mode); +#else *f_ptr = fopen (fname, fopen_mode); +#endif if (*f_ptr) { free (nameoffile); namelength = strlen (fname); @@ -182,7 +190,11 @@ open_input (FILE **f_ptr, int filefmt, const_string fopen_mode) /* A negative FILEFMT means don't use a path. */ if (filefmt < 0) { /* no_file_path, for BibTeX .aux files and MetaPost things. */ +#if defined(WIN32) + *f_ptr = fsyscp_xfopen(nameoffile + 1, fopen_mode); +#else *f_ptr = fopen(nameoffile + 1, fopen_mode); +#endif /* FIXME... fullnameoffile = xstrdup(nameoffile + 1); */ } else { /* The only exception to `must_exist' being true is \openin, for @@ -227,7 +239,11 @@ open_input (FILE **f_ptr, int filefmt, const_string fopen_mode) *f_ptr = nkf_open (nameoffile + 1, fopen_mode); } else #endif +#if defined(WIN32) + *f_ptr = fsyscp_xfopen (nameoffile + 1, fopen_mode); +#else *f_ptr = xfopen (nameoffile + 1, fopen_mode); +#endif } } } @@ -275,7 +291,11 @@ open_output (FILE **f_ptr, const_string fopen_mode) } /* Is the filename openable as given? */ +#if defined(WIN32) + *f_ptr = fsyscp_xfopen (fname, fopen_mode); +#else *f_ptr = fopen (fname, fopen_mode); +#endif if (!*f_ptr) { /* Can't open as given. Try the envvar. */ diff --git a/Build/source/texk/web2c/lib/texmfmp.c b/Build/source/texk/web2c/lib/texmfmp.c index 515d68b0b50..548012365e2 100644 --- a/Build/source/texk/web2c/lib/texmfmp.c +++ b/Build/source/texk/web2c/lib/texmfmp.c @@ -628,7 +628,9 @@ void maininit (int ac, string *av) { string main_input_file; - +#if (IS_upTeX || defined(XeTeX)) && defined(WIN32) + string enc; +#endif /* Save to pass along to topenin. */ argc = ac; argv = av; @@ -655,11 +657,51 @@ maininit (int ac, string *av) kpse_set_program_name (argv[0], NULL); initkanji (); #endif +#if defined(XeTeX) && defined(WIN32) + kpse_set_program_name (argv[0], NULL); +#endif +#if (IS_upTeX || defined(XeTeX)) && defined(WIN32) + enc = kpse_var_value("command_line_encoding"); + if (enc) { +#ifdef DEBUG + fprintf(stderr, "command_line_encoding (%s)\n", enc); +#endif /* DEBUG */ + if (!(strncmp(enc,"utf8",5) && strncmp(enc,"utf-8",6))) { + DWORD ret; + LPWSTR *argvw; + INT argcw, i; + string s; +#ifdef DEBUG + HANDLE hStderr; + hStderr = GetStdHandle( STD_ERROR_HANDLE ); +#endif /* DEBUG */ + file_system_codepage = CP_UTF8; + is_cp932_system = 0; + argvw = CommandLineToArgvW(GetCommandLineW(), &argcw); + argc = argcw; + argv = xmalloc(sizeof(char *)*(argcw+1)); + for (i=0; i