diff --git a/Makefile.am b/Makefile.am index e04fa400..9563e12a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -128,6 +128,7 @@ noinst_HEADERS = \ src/bin/write/mod_xlsx.h \ src/bin/write/module.h \ src/bin/write/module_util.h \ + src/bin/util/main.h \ src/bin/util/file_format.h \ src/bin/util/quote_and_escape.h \ src/bin/util/readstat_dta_days.h \ diff --git a/VS17/ReadStat_App/ReadStat_App.vcxproj b/VS17/ReadStat_App/ReadStat_App.vcxproj index 775a1606..b89f422f 100644 --- a/VS17/ReadStat_App/ReadStat_App.vcxproj +++ b/VS17/ReadStat_App/ReadStat_App.vcxproj @@ -57,6 +57,7 @@ + diff --git a/VS17/ReadStat_App/ReadStat_App.vcxproj.filters b/VS17/ReadStat_App/ReadStat_App.vcxproj.filters index 15473541..155fe62f 100644 --- a/VS17/ReadStat_App/ReadStat_App.vcxproj.filters +++ b/VS17/ReadStat_App/ReadStat_App.vcxproj.filters @@ -131,6 +131,9 @@ Header Files + + Header Files + Header Files diff --git a/src/bin/extract_metadata.c b/src/bin/extract_metadata.c index f60131f9..1560f381 100644 --- a/src/bin/extract_metadata.c +++ b/src/bin/extract_metadata.c @@ -9,6 +9,7 @@ #include "util/readstat_dta_days.h" #include "util/quote_and_escape.h" #include "util/file_format.h" +#include "util/main.h" #include "extract_metadata.h" #include "write/json/write_missing_values.h" #include "write/json/write_value_labels.h" @@ -303,7 +304,7 @@ cleanup: readstat_parser_free(parser); return ret; } -int main(int argc, char *argv[]) { +int portable_main(int argc, char *argv[]) { if (argc != 3) { printf("Usage: %s \n", argv[0]); return 1; diff --git a/src/bin/readstat.c b/src/bin/readstat.c index f55da6a4..62a02809 100644 --- a/src/bin/readstat.c +++ b/src/bin/readstat.c @@ -44,6 +44,7 @@ int gettimeofday(struct timeval* t, void* timezone) #endif #include "util/file_format.h" +#include "util/main.h" #if defined _MSC_VER #define unlink _unlink @@ -480,7 +481,7 @@ static int dump_file(const char *input_filename) { return 0; } -int main(int argc, char** argv) { +int portable_main(int argc, char** argv) { char *input_filename = NULL; char *catalog_filename = NULL; char *output_filename = NULL; diff --git a/src/bin/util/main.h b/src/bin/util/main.h new file mode 100644 index 00000000..04143718 --- /dev/null +++ b/src/bin/util/main.h @@ -0,0 +1,70 @@ +#include +#include + + +// True main for all platforms +int portable_main(int argc, char *argv[]); + + +#if defined _WIN32 +#include + // Standard way of decoding wide-string command-line arguments on Windows. + // Call portable_main with UTF-8 strings. + int main(int unused_argc, char *unused_argv[]) { + int argc; + int ret = 1; + wchar_t** utf16_argv = NULL; + char** utf8_argv = NULL; + + // Manual standard argument decoding needed since wmain is not supported by MinGW by default. + utf16_argv = CommandLineToArgvW(GetCommandLineW(), &argc); + + if(utf16_argv == NULL) { + fprintf(stderr, "Fatal error: command line argument extraction failure\n"); + goto cleanup; + } + + utf8_argv = calloc(argc, sizeof(char*)); + + for (int i=0; i #include +#include #if !defined(_MSC_VER) # include #endif +#if defined _WIN32 +# include +#endif #include "readstat.h" #include "readstat_io_unistd.h" @@ -24,8 +28,35 @@ #endif +int open_with_unicode(const char *path, int options) +{ +#if defined _WIN32 + const int buffer_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0); + + if(buffer_size <= 0) + return -1; + + wchar_t* wpath = malloc((buffer_size + 1) * sizeof(wchar_t)); + const int res = MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, buffer_size); + wpath[buffer_size] = 0; + + if(res <= 0) + { + free(wpath); + return -1; + } + + int fd = _wopen(wpath, options); + + free(wpath); + return fd; +#else + return open(path, options); +#endif +} + int unistd_open_handler(const char *path, void *io_ctx) { - int fd = open(path, UNISTD_OPEN_OPTIONS); + int fd = open_with_unicode(path, UNISTD_OPEN_OPTIONS); ((unistd_io_ctx_t*) io_ctx)->fd = fd; return fd; }