summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2022-07-29 16:45:46 -0400
committerpommicket <pommicket@gmail.com>2022-07-29 16:45:46 -0400
commit3f6c3bfd1bf2baebb49a68d3b463f6b414555d73 (patch)
tree93aa0932affac394bfd63bee556abed20a2d3075
parent12cc45bfcaa4c866f4509b6324a424048f3ddd29 (diff)
fixed non-ascii path handling on windows
-rw-r--r--filesystem-win.c51
-rw-r--r--main.c20
2 files changed, 45 insertions, 26 deletions
diff --git a/filesystem-win.c b/filesystem-win.c
index a16dc6b..dc17eaf 100644
--- a/filesystem-win.c
+++ b/filesystem-win.c
@@ -13,7 +13,11 @@ static FsType windows_file_attributes_to_type(DWORD attrs) {
}
FsType fs_path_type(char const *path) {
- return windows_file_attributes_to_type(GetFileAttributesA(path));
+ WCHAR wide_path[4100];
+ if (MultiByteToWideChar(CP_UTF8, 0, path, -1, wide_path, sizeof wide_path) == 0) {
+ return FS_NON_EXISTENT;
+ }
+ return windows_file_attributes_to_type(GetFileAttributesW(wide_path));
}
FsPermission fs_path_permission(char const *path) {
@@ -28,39 +32,46 @@ bool fs_file_exists(char const *path) {
}
FsDirectoryEntry **fs_list_directory(char const *dirname) {
- char file_pattern[256] = {0};
+ char file_pattern[1000] = {0};
FsDirectoryEntry **files = NULL;
- WIN32_FIND_DATA find_data;
+ WIN32_FIND_DATAW find_data;
HANDLE fhandle;
assert(*dirname);
sprintf_s(file_pattern, sizeof file_pattern, "%s%s*", dirname,
dirname[strlen(dirname) - 1] == PATH_SEPARATOR ? "" : PATH_SEPARATOR_STR);
- fhandle = FindFirstFileA(file_pattern, &find_data);
+ wchar_t wide_pattern[1024] = {0};
+ MultiByteToWideChar(CP_UTF8, 0, file_pattern, -1, wide_pattern, sizeof wide_pattern - 1);
+
+ fhandle = FindFirstFileW(wide_pattern, &find_data);
if (fhandle != INVALID_HANDLE_VALUE) {
// first, figure out number of files
int nfiles = 1, idx = 0;
- while (FindNextFile(fhandle, &find_data)) {
+ while (FindNextFileW(fhandle, &find_data)) {
++nfiles;
}
FindClose(fhandle);
// now, fill out files array
files = calloc(nfiles + 1, sizeof *files);
if (files) {
- fhandle = FindFirstFileA(file_pattern, &find_data);
+ fhandle = FindFirstFileW(wide_pattern, &find_data);
if (fhandle != INVALID_HANDLE_VALUE) {
do {
if (idx < nfiles) {
- const char *filename = find_data.cFileName;
- size_t len = strlen(filename);
- FsDirectoryEntry *entry = calloc(1, sizeof *entry + len + 1);
+ LPWSTR wide_filename = find_data.cFileName;
+ size_t wide_len = wcslen(wide_filename);
+ size_t cap = 4 * wide_len + 4;
+ FsDirectoryEntry *entry = calloc(1, sizeof *entry + cap);
+
+
if (entry) {
+ if (WideCharToMultiByte(CP_UTF8, 0, wide_filename, (int)wide_len, entry->name, (int)cap - 1, NULL, NULL) == 0)
+ break;
DWORD attrs = find_data.dwFileAttributes;
entry->type = windows_file_attributes_to_type(attrs);
- memcpy(entry->name, filename, len);
files[idx++] = entry;
} else break; // stop now
}
- } while (FindNextFile(fhandle, &find_data));
+ } while (FindNextFileW(fhandle, &find_data));
FindClose(fhandle);
}
}
@@ -69,7 +80,11 @@ FsDirectoryEntry **fs_list_directory(char const *dirname) {
}
int fs_mkdir(char const *path) {
- if (CreateDirectoryA(path, NULL)) {
+ WCHAR wide_path[4100];
+ if (MultiByteToWideChar(CP_UTF8, 0, path, -1, wide_path, sizeof wide_path) == 0)
+ return -1;
+
+ if (CreateDirectoryW(wide_path, NULL)) {
// directory created successfully
return 1;
} else {
@@ -82,12 +97,10 @@ int fs_mkdir(char const *path) {
int fs_get_cwd(char *buf, size_t buflen) {
assert(buf && buflen);
- DWORD pathlen = GetCurrentDirectory((DWORD)buflen, buf);
- if (pathlen == 0) {
- return -1;
- } else if (pathlen < buflen) { // it's confusing, but this is < and not <=
- return 1;
- } else {
+ wchar_t wide_path[4100];
+ DWORD wide_pathlen = GetCurrentDirectoryW(sizeof wide_path - 1, wide_path);
+ if (wide_pathlen == 0) return -1;
+ if (WideCharToMultiByte(CP_UTF8, 0, wide_path, (int)wide_pathlen, buf, (int)buflen, NULL, NULL) == 0)
return 0;
- }
+ return 1;
}
diff --git a/main.c b/main.c
index 2857869..791af49 100644
--- a/main.c
+++ b/main.c
@@ -245,17 +245,17 @@ INT WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
(void)hInstance; (void)hPrevInstance; (void)lpCmdLine; (void)nCmdShow;
int argc = 0;
LPWSTR* wide_argv = CommandLineToArgvW(GetCommandLineW(), &argc);
- char** argv = malloc(argc * sizeof *argv);
+ char** argv = calloc(argc + 1, sizeof *argv);
if (!argv) {
die("Out of memory.");
}
for (int i = 0; i < argc; i++) {
LPWSTR wide_arg = wide_argv[i];
int len = (int)wcslen(wide_arg);
- argv[i] = malloc(len + 1);
- if (!argv[i]) die("Out of memory.");
- for (int j = 0; j <= len; j++)
- argv[i][j] = (char)wide_arg[j];
+ int bufsz = len * 4 + 8;
+ argv[i] = calloc((size_t)bufsz, 1);
+ if (!argv[i]) die("Out of memory.");
+ WideCharToMultiByte(CP_UTF8, 0, wide_arg, len, argv[i], bufsz - 1, NULL, NULL);
}
LocalFree(wide_argv);
#else
@@ -281,7 +281,11 @@ int main(int argc, char **argv) {
#error "Unrecognized operating system."
#endif
- setlocale(LC_ALL, ""); // allow unicode
+ #if _WIN32
+ setlocale(LC_ALL, ".65001");
+ #else
+ setlocale(LC_ALL, "C.UTF-8");
+ #endif
// read command-line arguments
char const *starting_filename = NULL;
@@ -335,8 +339,10 @@ int main(int argc, char **argv) {
}
// on Windows, the global data directory is just the directory where the executable is.
+ WCHAR executable_wide_path[TED_PATH_MAX] = {0};
char executable_path[TED_PATH_MAX] = {0};
- if (GetModuleFileNameA(NULL, executable_path, sizeof executable_path) > 0) {
+ if (GetModuleFileNameW(NULL, executable_wide_path, sizeof executable_wide_path - 1) > 0) {
+ WideCharToMultiByte(CP_UTF8, 0, executable_wide_path, -1, executable_path, sizeof executable_path, NULL, NULL);
char *last_backslash = strrchr(executable_path, '\\');
if (last_backslash) {
*last_backslash = '\0';