Sfoglia il codice sorgente

fix: WinAPI添加字符转换

添加WinAPI调用结果的修改
令字符串从ANSI字符集转换为UTF-8
SongZihuan 3 anni fa
parent
commit
89aeb0f5ab

+ 2 - 0
include/tool/file.h

@@ -15,4 +15,6 @@ AFUN_TOOL_EXPORT char *findPath(char *path, char *env, bool need_free);
 AFUN_TOOL_EXPORT char *getExedir(int dep);
 AFUN_TOOL_EXPORT uintmax_t getFileSize(char *path);
 AFUN_TOOL_EXPORT bool isCharUTF8(char *str);
+AFUN_TOOL_EXPORT FILE *fileOpen(char *path_, char *mode_);
+AFUN_TOOL_EXPORT int fileClose(FILE *file);
 #endif //AFUN_FILE_H

+ 1 - 1
include/tool/md5.h

@@ -13,6 +13,6 @@ typedef struct MD5_CTX MD5_CTX;
 AFUN_TOOL_EXPORT MD5_CTX *MD5Init(void);
 AFUN_TOOL_EXPORT void MD5Final(MD5_CTX *context, unsigned char digest[16]);
 AFUN_TOOL_EXPORT void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int input_len);
-AFUN_TOOL_EXPORT char *getFileMd5(const char *path);
+AFUN_TOOL_EXPORT char *getFileMd5(char *path);
 
 #endif //AFUN_MD5_H

+ 12 - 0
include/tool/stdio_.h

@@ -10,6 +10,18 @@ AFUN_TOOL_EXPORT bool fclear_stdin(void);
 #define CLEAR_STDIN(file) ((ferror(stdin) || feof(stdin)) && (clearerr(stdin), (ferror(stdin) || feof(stdin))))
 
 #ifdef aFunWIN32_NO_CYGWIN
+
+#ifdef _MSC_VER
+#pragma warning(disable : 5105)  // 关闭 5105 的警告输出 (Windows.h中使用)
+#endif
+#include <conio.h>
+#include <io.h>
+#include <Windows.h>
+
+AFUN_TOOL_EXPORT int convertMultiByte(char **dest, char *str, UINT from, UINT to);  // win32 特有函数
+AFUN_TOOL_EXPORT int convertWideByte(wchar_t **dest, char *str, UINT from);  // win32 特有函数
+AFUN_TOOL_EXPORT int convertFromWideByte(char **dest, wchar_t *str, UINT to);
+
 AFUN_TOOL_EXPORT int fgetc_stdin(void);
 AFUN_TOOL_EXPORT char *fgets_stdin_(char *buf, size_t len);
 AFUN_TOOL_EXPORT int fungetc_stdin(int ch);

+ 4 - 4
src/core/bytecode.c

@@ -38,7 +38,7 @@ int writeByteCode(af_Code *code, FilePath path) {
         return 3;
 
     int re = 1;
-    FILE *file = fopen(path, "wb");
+    FILE *file = fileOpen(path, "wb");
     if (file == NULL) {
         re = 2;
         goto RETURN_2;
@@ -55,7 +55,7 @@ int writeByteCode(af_Code *code, FilePath path) {
     }
 
 RETURN_:
-    fclose(file);
+    fileClose(file);
 RETURN_2:
     free(md5);
     return re;
@@ -66,7 +66,7 @@ int readByteCode(af_Code **code, FilePath path) {
         return 0;
 
     int re = 1;
-    FILE *file = fopen(path, "rb");
+    FILE *file = fileOpen(path, "rb");
     if (file == NULL)
         return 2;
 
@@ -109,6 +109,6 @@ RETURN_:
     free(head);
     free(md5str);
     free(code_md5);
-    fclose(file);
+    fileClose(file);
     return re;
 }

+ 2 - 2
src/core/core_init.c

@@ -57,7 +57,7 @@ bool aFunCoreInit(aFunCoreInitInfo *info) {
     char LANG_path[218] = {0};
     snprintf(LANG_path, 218, "%sLANG", lang_path);
 
-    FILE *LANG_file = fopen(LANG_path, "r");
+    FILE *LANG_file = fileOpen(LANG_path, "r");
     if (LANG_file != NULL) {
         char LANG[100] = {0};
         fgets(LANG, 100, LANG_file);
@@ -71,7 +71,7 @@ bool aFunCoreInit(aFunCoreInitInfo *info) {
             writeDebugLog(aFunCoreLogger, "aFunCore lang init success: %s", LANG_lib);
         else
             writeDebugLog(aFunCoreLogger, "aFunCore lang init failed: %s", LANG_lib);
-        fclose(LANG_file);
+        fileClose(LANG_file);
     } else
         HT_initaFunGetText(NULL);
     writeDebugLog(aFunCoreLogger, "aFunCore init success");

+ 5 - 3
src/core/lexical.c

@@ -395,7 +395,6 @@ af_TokenType getTokenFromLexical(char **text, af_Parser *parser) {
         }
 
         if (re == ERROR_TOKEN) {
-ERROR:
             tt = TK_ERROR;
             *text = NULL;
             break;
@@ -407,8 +406,11 @@ ERROR:
             continue;
         } else if (re == FINISH_TOKEN) {
             char *word = readWord(parser->lexical->last, parser->reader);
-            if (word == NULL)
-                goto ERROR;
+            if (word == NULL) {
+                tt = TK_ERROR;
+                *text = NULL;
+                break;
+            }
 
             tt = parser->lexical->token;
 

+ 2 - 2
src/core/parser.c

@@ -145,7 +145,7 @@ static size_t readFuncFile(struct readerDataFile *data, char *dest, size_t len,
 
 static void destructFile(struct readerDataFile *data) {
     if (data->file != NULL)
-        fclose(data->file);
+        fileClose(data->file);
 }
 
 static void initFileReader(af_Parser *parser, FILE *file, struct readerDataFile *data) {
@@ -154,7 +154,7 @@ static void initFileReader(af_Parser *parser, FILE *file, struct readerDataFile
 }
 
 af_Parser *makeParserByFile(FilePath path){
-    FILE *file = fopen(path, "rb");
+    FILE *file = fileOpen(path, "rb");
     if (file == NULL) {
         writeErrorLog(aFunCoreLogger, "File open error: %s", path);
         return NULL;

+ 75 - 19
src/tool/file.c

@@ -29,27 +29,53 @@
 #define	S_ISDIR(m)	(((m) & S_IFMT) == S_IFDIR)
 #endif
 
+#ifdef aFunWIN32_NO_CYGWIN
+typedef struct _stat64 aFun_stat;
+typedef wchar_t aFun_path;
+#else
+typedef struct stat aFun_stat;
+typedef char aFun_path;
+#endif
+
+static int get_stat(aFun_stat *stat_, char *path_){
+    aFun_path *tmp = NULL;
+    int re;
+#ifdef aFunWIN32_NO_CYGWIN
+    tmp = NULL;
+    if (convertWideByte(&tmp, path_, CP_UTF8) == 0)
+        return -1;
+    re = _wstat64(tmp, stat_);
+    free(tmp);  // 如果 path 为NULL, 则释放最新生成的 wchat_t
+#else
+    re = stat(path_, stat_);
+#endif
+    return re;
+}
+
 /*
  * 函数名: checkFile
  * 目标判断文件类型, 若是普通文件返回1, 若是文件夹返回2, 其他遇到错误返回0
  */
-int checkFile(char *path){
-    struct stat my_stat;
-    if (path == NULL || stat(path, &my_stat) != 0)
-        return 0;
-    if (S_ISREG(my_stat.st_mode))  // 普通文件
-        return 1;
-    else if (S_ISDIR(my_stat.st_mode))
-        return 2;
-    else
+int checkFile(char *path_){
+    if (path_ == NULL)
         return 0;
+
+    int re = 0;
+    aFun_stat stat;
+    if (get_stat(&stat, path_) != 0)
+        re = 0;
+    else if (S_ISREG(stat.st_mode))  // 普通文件
+        re = 1;
+    else if (S_ISDIR(stat.st_mode))
+        re = 2;
+    return re;
 }
 
 time_t getFileMTime(char *path) {
-    struct stat my_stat;
-    if (path == NULL || stat(path, &my_stat) != 0)
+    aFun_stat stat;
+    if (path == NULL || get_stat(&stat, path) != 0)
         return 0;
-    return my_stat.st_mtime;
+    return stat.st_mtime;
 }
 
 char *joinPath(char *path, char *name, char *suffix) {
@@ -184,26 +210,32 @@ char *findPath(char *path, char *env, bool need_free){
  * dep表示从可执行程序往回跳出的层数
  */
 char *getExedir(int dep) {
-    char exepath[218] = {0};
+    aFun_path exepath[218] = {0};
 #ifdef aFunWIN32_NO_CYGWIN
-    DWORD ret = GetModuleFileNameA(NULL, exepath, 217);  // 预留一位给NUL
-    if (ret == 0 || STR_LEN(exepath) == 0)
+    DWORD ret = GetModuleFileNameW(NULL, exepath, 217);  // 预留一位给NUL
+    if (ret == 0 || WSTR_LEN(exepath) == 0)
+        return NULL;
+    char *path = NULL;
+    if (convertFromWideByte(&path, exepath, CP_UTF8) == 0)
         return NULL;
+    char *re = getFilePath(path, dep + 1);
+    free(path);
+    return re;
 #else
     ssize_t ret =  readlink("/proc/self/exe", exepath, 217);  // 预留一位给NUL
     if (ret == -1 || STR_LEN(exepath) == 0)
         return NULL;
-#endif
     return getFilePath(exepath, dep + 1);
+#endif
 }
 
 uintmax_t getFileSize(char *path) {
-    struct stat statbuf;
+    aFun_stat stat;
     int ret;
-    ret = stat(path, &statbuf);
+    ret = get_stat(&stat, path);
     if(ret != 0)
         return 0;  // 获取失败。
-    return (uintmax_t)statbuf.st_size;  // 返回文件大小
+    return (uintmax_t)stat.st_size;  // 返回文件大小
 
 }
 
@@ -241,3 +273,27 @@ bool isCharUTF8(char *str) {
 
     return true;
 }
+
+FILE *fileOpen(char *path_, char *mode_) {
+    if (STR_LEN(mode_) >= 5)
+        return NULL;
+    FILE *file = NULL;
+#if aFunWIN32_NO_CYGWIN
+    wchar_t *path = NULL;
+    wchar_t mode[5];
+    if (convertWideByte(&path, path_, CP_UTF8) == 0)
+        return NULL;
+    for (int i = 0; i < 5; i++)
+        mode[i] = (wchar_t)mode_[i];  // ascii字符转换
+
+    _wfopen_s(&file, path, mode);
+    free(path);
+    return file;
+#else
+    return fopen(path_, mode_);
+#endif
+}
+
+int fileClose(FILE *file) {
+    return fclose(file);
+}

+ 5 - 4
src/tool/log.c

@@ -110,14 +110,15 @@ int initLogSystem(FilePath path, bool asyn){
     uintmax_t csv_size = getFileSize(csv_path);
     bool csv_head_write = (checkFile(csv_path) == 0);  // 文件不存在时才写入头部
 
-    log_factory.log = fopen(log_path, "a");
+    log_factory.log = fileOpen(log_path, "a");
     if (log_factory.log == NULL) {
+        perror("ERROR: ");
         printf("log_path = %s\n", log_path);
         pthread_mutex_unlock(MUTEX);
         return 0;
     }
 
-    log_factory.csv = fopen(csv_path, "a");
+    log_factory.csv = fileOpen(csv_path, "a");
     if (log_factory.csv == NULL) {
         pthread_mutex_unlock(MUTEX);
         return 0;
@@ -176,8 +177,8 @@ int destructLogSystem(void) {
             printf_stderr(0, "Logsystem destruct error.");
     }
 
-    fclose(log_factory.log);
-    fclose(log_factory.csv);
+    fileClose(log_factory.log);
+    fileClose(log_factory.csv);
     log_factory.log = NULL;
     log_factory.csv = NULL;
     log_factory.init = false;

+ 3 - 3
src/tool/md5.c

@@ -188,14 +188,14 @@ static void MD5Transform(unsigned int state[4], unsigned char block[64]) {
 }
 
 
-char *getFileMd5(const char *path) {
+char *getFileMd5(char *path) {
     FILE *fd;
 
     unsigned long ret;
     unsigned char data[READ_DATA_SIZE];
     unsigned char md5_value[MD5_SIZE];
 
-    if ((fd = fopen(path, "rb")) == NULL)
+    if ((fd = fileOpen(path, "rb")) == NULL)
         return NULL;
 
     char *md5str = calloc(MD5_STRING, sizeof(char));
@@ -207,7 +207,7 @@ char *getFileMd5(const char *path) {
             break;
     }
 
-    fclose(fd);
+    fileClose(fd);
     MD5Final(md5, md5_value);
 
     for(int i = 0; i < MD5_SIZE; i++)

+ 26 - 9
src/tool/stdio_.c

@@ -17,12 +17,6 @@
  */
 
 #ifdef aFunWIN32_NO_CYGWIN
-#ifdef _MSC_VER
-#pragma warning(disable : 5105)  // 关闭 5105 的警告输出 (Windows.h中使用)
-#endif
-#include <conio.h>
-#include <io.h>
-#include <Windows.h>
 // 获取CodePage, 并将内存中utf-8字符串转换为对应编码输出
 // cygwin环境下, 终端默认为uft-8
 
@@ -289,7 +283,7 @@ bool fclear_stdin(void) {
     return false;
 }
 
-static int convertMultiByte(char **dest, char *str, UINT from, UINT to) {
+int convertMultiByte(char **dest, char *str, UINT from, UINT to) {
     if (str == NULL || dest == NULL)
         return 0;
 
@@ -312,6 +306,30 @@ static int convertMultiByte(char **dest, char *str, UINT from, UINT to) {
     return re;
 }
 
+int convertWideByte(wchar_t **dest, char *str, UINT from) {
+    if (str == NULL || dest == NULL)
+        return 0;
+
+    int tmp_len = MultiByteToWideChar(from, 0, str, -1, 0, 0);
+    if (tmp_len == 0)
+        return 0;
+
+    *dest = calloc(tmp_len + 1, sizeof(wchar_t));
+    return MultiByteToWideChar(from, 0, str, -1, *dest, tmp_len);
+}
+
+int convertFromWideByte(char **dest, wchar_t *str, UINT to) {
+    if (str == NULL || dest == NULL)
+        return 0;
+
+    int dest_len = WideCharToMultiByte(to, 0, str, -1, NULL, 0, NULL, NULL);
+    if (dest_len == 0)
+        return 0;
+
+    *dest = calloc(dest_len + 1, sizeof(char));
+    return WideCharToMultiByte(to, 0, str, -1, *dest, dest_len, NULL, NULL);
+}
+
 int fgets_stdin(char **dest, int len) {
     int re = 0;
     if (!_isatty(_fileno(stdin))) {
@@ -380,8 +398,7 @@ int fputs_std_(char *str, FILE *std) {
     UINT code_page = GetConsoleCP();
     char *wstr = NULL;
     int re = EOF;
-    convertMultiByte(&wstr, str, CP_UTF8, code_page);
-    if (wstr != NULL) {
+    if (convertMultiByte(&wstr, str, CP_UTF8, code_page) == 0 || wstr != NULL) {
         re = fputs(wstr, std);
         free(wstr);
     }

+ 18 - 1
src/tool/time.c

@@ -31,10 +31,27 @@ char *getTime(time_t *t, char *format) {
     if (t == NULL)
         t = &tmp;
 
-    struct tm *lt;
     time (t);  // 获取时间戳
+#if aFunWIN32_NO_CYGWIN
+    struct tm lt;
+    if (localtime_s(&lt, t) != 0)
+        return NULL;
+    wchar_t time_str[100];
+    wchar_t *format_ = NULL;
+    if (convertWideByte(&format_, format, CP_UTF8) == 0)
+        return NULL;
+    wcsftime(time_str, 100, format_, &lt);
+    free(format_);
+
+    char *re = NULL;
+    if (convertFromWideByte(&re, time_str, CP_UTF8) == 0)
+        return NULL;
+    return re;
+#else
+    struct tm *lt = NULL;
     lt = localtime (t);  // 转为时间结构
     char time_str[100];
     strftime(time_str, 100, format, lt);
     return strCopy(time_str);
+#endif
 }

+ 2 - 2
test/src/syntactic.c

@@ -28,7 +28,7 @@ void test1(void) {
 
 void test2(void) {
     FilePath path = "./test.aun";
-    FILE *file = fopen(path, "wb");
+    FILE *file = fileOpen(path, "wb");
     if (file == NULL) {
         perror("File open error");
         exit(EXIT_FAILURE);
@@ -38,7 +38,7 @@ void test2(void) {
         fprintf(stderr, "File write error.\n");
         exit(EXIT_FAILURE);
     }
-    fclose(file);
+    fileClose(file);
 
     af_Parser *parser = makeParserByFile(path);
     af_Code *code = parserCode(parser);

+ 4 - 3
test/src/tool_byte.c

@@ -24,7 +24,7 @@ int main() {
 
     getEndian();
 
-    FILE *file = fopen("test.byte", "wb");
+    FILE *file = fileOpen("test.byte", "wb");
     if (file == NULL) {
         fprintf(stderr, "Can't not creat file: test.byte\n");
         return EXIT_FAILURE;
@@ -36,7 +36,7 @@ int main() {
     TEST_WRITE(byteWriteInt_64(file, test64), uint64_t);
     TEST_WRITE(byteWriteStr(file, testStr), str);
 
-    fclose(file);
+    fileClose(file);
 
     int8_t rtest8;
     int16_t rtest16;
@@ -44,7 +44,7 @@ int main() {
     int64_t rtest64;
     char *rtestStr;
 
-    file = fopen("test.byte", "rb");
+    file = fileOpen("test.byte", "rb");
     if (file == NULL) {
         fprintf(stderr, "Can't not read file: test.byte\n");
         return EXIT_FAILURE;
@@ -67,6 +67,7 @@ int main() {
     }
 
     free(rtestStr);
+    fileClose(file);
     printf("success.\n");
     return EXIT_SUCCESS;
 }