Merge pull request #785 from DrLynix/unicode-file-operations-win32

Unicode file functions for Windows
This commit is contained in:
Tom van Dijck 2017-05-25 08:44:19 -07:00 committed by GitHub
commit 235d364756
8 changed files with 191 additions and 10 deletions

View File

@ -18,6 +18,9 @@
#include "lauxlib.h"
#include "lualib.h"
#if defined(LUA_WIN)
#include <windows.h>
#endif
#define IO_INPUT 1
@ -177,8 +180,29 @@ static int io_tostring (lua_State *L) {
static int io_open (lua_State *L) {
const char *filename = luaL_checkstring(L, 1);
const char *mode = luaL_optstring(L, 2, "r");
#if defined(LUA_WIN)
wchar_t wide_path[4096];
if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, wide_path, 4096) == 0)
{
lua_pushstring(L, "unable to encode path");
return lua_error(L);
}
wchar_t wide_mode[64];
if (MultiByteToWideChar(CP_UTF8, 0, mode, -1, wide_mode, 64) == 0)
{
lua_pushstring(L, "unable to encode open mode");
return lua_error(L);
}
#endif
FILE **pf = newfile(L);
#if defined(LUA_WIN)
*pf = _wfopen(wide_path, wide_mode);
#else
*pf = fopen(filename, mode);
#endif
return (*pf == NULL) ? pushresult(L, 0, filename) : 1;
}

51
src/host/os_remove.c Normal file
View File

@ -0,0 +1,51 @@
/**
* \file os_rmdir.c
* \brief Remove a subdirectory.
* \author Copyright (c) 2002-2013 Jason Perkins and the Premake project
*/
#include "premake.h"
#if PLATFORM_WINDOWS
int os_remove(lua_State* L)
{
const char* filename = luaL_checkstring(L, 1);
wchar_t wide_path[PATH_MAX];
if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, wide_path, PATH_MAX) == 0)
{
lua_pushstring(L, "unable to encode path");
return lua_error(L);
}
if (DeleteFileW(wide_path))
{
lua_pushboolean(L, 1);
return 1;
}
else
{
DWORD err = GetLastError();
char unicodeErr[512];
LPWSTR messageBuffer = NULL;
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR) &messageBuffer, 0, NULL) != 0)
{
if (WideCharToMultiByte(CP_UTF8, 0, messageBuffer, -1, unicodeErr, sizeof(unicodeErr), NULL, NULL) == 0)
strcpy(unicodeErr, "failed to translate error message");
LocalFree(messageBuffer);
}
else
strcpy(unicodeErr, "failed to get error message");
lua_pushnil(L);
lua_pushfstring(L, "%s: %s", filename, unicodeErr);
lua_pushinteger(L, err);
return 3;
}
}
#endif

59
src/host/os_rename.c Normal file
View File

@ -0,0 +1,59 @@
/**
* \file os_rmdir.c
* \brief Remove a subdirectory.
* \author Copyright (c) 2002-2013 Jason Perkins and the Premake project
*/
#include "premake.h"
#if PLATFORM_WINDOWS
int os_rename(lua_State* L)
{
const char *fromname = luaL_checkstring(L, 1);
const char *toname = luaL_checkstring(L, 2);
wchar_t wide_frompath[PATH_MAX];
if (MultiByteToWideChar(CP_UTF8, 0, fromname, -1, wide_frompath, PATH_MAX) == 0)
{
lua_pushstring(L, "unable to encode source path");
return lua_error(L);
}
wchar_t wide_topath[PATH_MAX];
if (MultiByteToWideChar(CP_UTF8, 0, toname, -1, wide_topath, PATH_MAX) == 0)
{
lua_pushstring(L, "unable to encode dest path");
return lua_error(L);
}
if (MoveFileExW(wide_frompath, wide_topath, MOVEFILE_COPY_ALLOWED))
{
lua_pushboolean(L, 1);
return 1;
}
else
{
DWORD err = GetLastError();
char unicodeErr[512];
LPWSTR messageBuffer = NULL;
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR) &messageBuffer, 0, NULL) != 0)
{
if (WideCharToMultiByte(CP_UTF8, 0, messageBuffer, -1, unicodeErr, sizeof(unicodeErr), NULL, NULL) == 0)
strcpy(unicodeErr, "failed to translate error message");
LocalFree(messageBuffer);
}
else
strcpy(unicodeErr, "failed to get error message");
lua_pushnil(L);
lua_pushfstring(L, "%s: %s", fromname, unicodeErr);
lua_pushinteger(L, err);
return 3;
}
}
#endif

View File

@ -10,10 +10,24 @@
int os_stat(lua_State* L)
{
struct stat s;
const char* filename = luaL_checkstring(L, 1);
#if PLATFORM_WINDOWS
struct _stat64i32 s;
wchar_t wide_filename[PATH_MAX];
if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, wide_filename, PATH_MAX) == 0)
{
lua_pushstring(L, "unable to encode source path");
return lua_error(L);
}
if (_wstat(wide_filename, &s) != 0)
#else
struct stat s;
if (stat(filename, &s) != 0)
#endif
{
lua_pushnil(L);
switch (errno)
@ -24,14 +38,14 @@ int os_stat(lua_State* L)
case ENOENT:
lua_pushfstring(L, "'%s' was not found", filename);
break;
default:
default:
lua_pushfstring(L, "An unknown error %d occured while accessing '%s'", errno, filename);
break;
}
return 2;
}
lua_newtable(L);
lua_pushstring(L, "mtime");

View File

@ -19,12 +19,22 @@
static int compare_file(const char* content, size_t length, const char* dst)
{
FILE* file = fopen(dst, "rb");
FILE* file;
size_t size;
size_t read;
char buffer[4096];
size_t num;
#if PLATFORM_WINDOWS
wchar_t wide_path[PATH_MAX];
if (MultiByteToWideChar(CP_UTF8, 0, dst, -1, wide_path, PATH_MAX) == 0)
return FALSE;
file = _wfopen(wide_path, L"rb");
#else
file = fopen(dst, "rb");
#endif
if (file == NULL)
{
return FALSE;
@ -81,8 +91,16 @@ int os_writefile_ifnotequal(lua_State* L)
return 1;
}
#if PLATFORM_WINDOWS
wchar_t wide_path[PATH_MAX];
if (MultiByteToWideChar(CP_UTF8, 0, dst, -1, wide_path, PATH_MAX) == 0)
return FALSE;
file = _wfopen(wide_path, L"wb");
#else
file = fopen(dst, "wb");
#endif
if (file != NULL)
{
fwrite(content, 1, length, file);

View File

@ -8,6 +8,11 @@
#include <ctype.h>
#include <string.h>
// isspace custom version (visual c++'s one doesn't like utf8 characters)
static int is_space(char c)
{
return (c >= 9 && c <= 13) || c == 32;
}
static void* normalize_substring(const char* str, const char* endPtr, char* writePtr) {
const char* const source = str;
@ -93,7 +98,7 @@ int path_normalize(lua_State* L)
const char* endPtr;
// skip leading white spaces
while (*readPtr && isspace(*readPtr)) {
while (*readPtr && is_space(*readPtr)) {
++readPtr;
}
@ -106,14 +111,14 @@ int path_normalize(lua_State* L)
}
// find the end of sub path
while (*endPtr && !isspace(*endPtr)) {
while (*endPtr && !is_space(*endPtr)) {
++endPtr;
}
writePtr = normalize_substring(readPtr, endPtr, writePtr);
// skip any white spaces between sub paths
while (*endPtr && isspace(*endPtr)) {
while (*endPtr && is_space(*endPtr)) {
*(writePtr++) = *(endPtr++);
}
@ -121,7 +126,7 @@ int path_normalize(lua_State* L)
}
// skip any trailing white spaces
while (isspace(*(--endPtr))) {
while (is_space(*(--endPtr))) {
--writePtr;
}

View File

@ -74,6 +74,11 @@ static const luaL_Reg os_functions[] = {
{ "matchnext", os_matchnext },
{ "matchstart", os_matchstart },
{ "mkdir", os_mkdir },
#if PLATFORM_WINDOWS
// utf8 functions for Windows (assuming posix already handle utf8)
{"remove", os_remove },
{"rename", os_rename },
#endif
{ "pathsearch", os_pathsearch },
{ "realpath", os_realpath },
{ "rmdir", os_rmdir },

View File

@ -120,6 +120,11 @@ int os_matchstart(lua_State* L);
int os_mkdir(lua_State* L);
int os_pathsearch(lua_State* L);
int os_realpath(lua_State* L);
#if PLATFORM_WINDOWS
// utf8 versions
int os_remove(lua_State* L);
int os_rename(lua_State* L);
#endif
int os_rmdir(lua_State* L);
int os_stat(lua_State* L);
int os_uuid(lua_State* L);