diff --git a/.gitignore b/.gitignore index d1a7c86..3b234ec 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,11 @@ .vs/ +.idea/ x64/ cmake-build-debug/ -*.pdb.idea/ cmake-build-release/ cmake-build-debug-mingw/ +*.pdb + +lcui-quick-start.zip +package-lock.json +-g/ \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 35eb1dd..61b903a 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,5 +2,6 @@ + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e8ce51..0872886 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,9 @@ cmake_minimum_required(VERSION 3.27) PROJECT(JsonParser C) set(CMAKE_C_STANDARD 17) + +find_package(Iconv REQUIRED) + add_library(jsonParserLib core/Json.h core/parser/parser.h @@ -19,7 +22,7 @@ add_library(jsonParserLib core/utils/utf2gbk/UTF2GBK.c core/utils/utf2gbk/UTF2GBK.h ) -target_link_libraries(jsonParserLib PRIVATE iconv) +target_link_libraries(jsonParserLib PRIVATE Iconv::Iconv) add_executable(json cli/main.c diff --git a/cli/main.c b/cli/main.c index f8ff664..52a36cf 100644 --- a/cli/main.c +++ b/cli/main.c @@ -6,78 +6,69 @@ #include "Json.h" -// 结构体用于存储命令行参数的值 +// 缁撴瀯浣撶敤浜庡瓨鍌ㄥ懡浠よ鍙傛暟鐨勫 struct CommandLineArgs { - FILE* input; // 输入流 - FILE* output; // 输出流 - int compress; // 是否压缩 - int format; // 是否格式化 - int utf8Text; // 是否为utf-8 文本 是则需资源回收时删除中间文件 - char* convertCacheFilePath; // 为utf-8文本时转换为gbk格式时生成的临时文件 - char* outputFilePath; // 需要输出文件路径, 当为utf-8文本时用于转换回utf-8文本 - + FILE* input; // 杈撳叆娴 + FILE* output; // 杈撳嚭娴 + int compress; // 鏄惁鍘嬬缉 + int format; // 鏄惁鏍煎紡鍖 + // int utf8Text; // 鏄惁涓簎tf-8 鏂囨湰 鏄垯闇璧勬簮鍥炴敹鏃跺垹闄や腑闂存枃浠 + // char* convertCacheFilePath; // 涓簎tf-8鏂囨湰鏃惰浆鎹负gbk鏍煎紡鏃剁敓鎴愮殑涓存椂鏂囦欢 + // char* outputFilePath; // 闇瑕佽緭鍑烘枃浠惰矾寰勶紝 褰撲负utf-8鏂囨湰鏃剁敤浜庤浆鎹㈠洖utf-8鏂囨湰 }; -// 函数声明 +// 鍑芥暟澹版槑 struct CommandLineArgs parseCommandLineArgs(int argc, char* argv[]); int main(const int argc, char* argv[]) { - // setlocale(LC_ALL, ""); // 设置本地化环境以支持宽字符 + // setlocale(LC_ALL, ""); // 璁剧疆鏈湴鍖栫幆澧冧互鏀寔瀹藉瓧绗 const struct CommandLineArgs args = parseCommandLineArgs(argc, argv); - // 设置输入输出流 - // 默认为标准输入输出 + // 璁剧疆杈撳叆杈撳嚭娴 + // 榛樿涓烘爣鍑嗚緭鍏ヨ緭鍑 setInputStream(args.input); - setOutputStream(args.output); - - //解析Json + setOutputStream(args.output); + + //瑙f瀽Json const struct JsonVal* json = parseValue(); - if (args.compress) { - printJsonVal(json); - } - else if (args.format) { - printfJsonVal(json, 0); - } + if (args.compress) { printJsonVal(json); } + else if (args.format) { printfJsonVal(json, 0); } //destoryJsonVal(json); - if (args.input != stdin) { - fclose(args.input); - } + if (args.input != stdin) { fclose(args.input); } if (args.output != stdout) { fclose(args.output); - if(args.utf8Text) { - convertGbkToUtf8(args.output); - } + // if (args.utf8Text) { convertGbkToUtf8(args.output); } } - return 0; + return 0; } -// 函数定义:解析命令行参数 +// 鍑芥暟瀹氫箟锛氳В鏋愬懡浠よ鍙傛暟 struct CommandLineArgs parseCommandLineArgs(int argc, char* argv[]) { struct CommandLineArgs args; - // 初始化结构体成员 + // 鍒濆鍖栫粨鏋勪綋鎴愬憳 args.input = stdin; args.output = stdout; args.compress = 0; args.format = 1; - args.utf8Text = 0; - args.convertCacheFilePath = ""; - // 标记是否已经出现了--format或--compress + // args.utf8Text = 0; + // args.convertCacheFilePath = "__cache.json"; + // 鏍囪鏄惁宸茬粡鍑虹幇浜--format鎴--compress int formatSeen = 0; int compressSeen = 0; - // 解析命令行参数 + // 瑙f瀽鍛戒护琛屽弬鏁 for (int i = 1; i < argc; ++i) { if (strcmp(argv[i], "--output") == 0 || strcmp(argv[i], "-of") == 0) { - // 指定输出流 + // 鎸囧畾杈撳嚭娴 if (i + 1 < argc) { printf("Output: %s\n", argv[i + 1]); args.output = fopen(argv[i + 1], "w"); - args.outputFilePath = argv[i+1]; + // args.outputFilePath = argv[i + 1]; if (args.output == NULL) { perror("Error opening output file"); exit(EXIT_FAILURE); } - i++; // 跳过下一个参数,因为它是文件路径 + i++; // 璺宠繃涓嬩竴涓弬鏁帮紝鍥犱负瀹冩槸鏂囦欢璺緞 } else { fprintf(stderr, "Error: --output option requires a file path.\n"); @@ -85,22 +76,22 @@ struct CommandLineArgs parseCommandLineArgs(int argc, char* argv[]) { } } else if (strcmp(argv[i], "--input") == 0 || strcmp(argv[i], "-if") == 0) { - // 指定输入流 + // 鎸囧畾杈撳叆娴 if (i + 1 < argc) { - FILE* f = fopen(argv[i + 1], "r"); - args.convertCacheFilePath = "__cache.json"; - if(isUtf8(f)) { - printf("INFO: Is UTF-8 Text\n"); - args.input = convertUtf8ToGbk(f,args.convertCacheFilePath); - args.utf8Text = 1; - }else { - args.input = fopen(argv[i + 1], "r"); - } + args.input = fopen(argv[i + 1], "r"); + // FILE* f = fopen(argv[i + 1], "r"); + + // if (isUtf8(f)) { + // printf("INFO: Is UTF-8 Text\n"); + // args.input = convertUtf8ToGbk(f); + // args.utf8Text = 1; + // } + // else { args.input = fopen(argv[i + 1], "r"); } if (args.input == NULL) { perror("Error opening input file"); exit(EXIT_FAILURE); } - i++; // 跳过下一个参数,因为它是文件路径 + i++; // 璺宠繃涓嬩竴涓弬鏁帮紝鍥犱负瀹冩槸鏂囦欢璺緞 } else { fprintf(stderr, "Error: --input option requires a file path.\n"); @@ -108,7 +99,7 @@ struct CommandLineArgs parseCommandLineArgs(int argc, char* argv[]) { } } else if (strcmp(argv[i], "--compress") == 0 || strcmp(argv[i], "-c") == 0) { - // 压缩格式输出Json + // 鍘嬬缉鏍煎紡杈撳嚭Json if (formatSeen) { fprintf(stderr, "Error: --compress and --format cannot be used together.\n"); exit(EXIT_FAILURE); @@ -118,7 +109,7 @@ struct CommandLineArgs parseCommandLineArgs(int argc, char* argv[]) { compressSeen = 1; } else if (strcmp(argv[i], "--format") == 0 || strcmp(argv[i], "-f") == 0) { - // 格式化输出Json + // 鏍煎紡鍖栬緭鍑篔son if (compressSeen) { fprintf(stderr, "Error: --compress and --format cannot be used together.\n"); exit(EXIT_FAILURE); @@ -127,23 +118,23 @@ struct CommandLineArgs parseCommandLineArgs(int argc, char* argv[]) { formatSeen = 1; } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { - printf("用法:json [选项]...\n"); - printf("从输入中解析和格式化JSON数据,可选择压缩或格式化输出。\n\n"); + printf("鐢ㄦ硶锛歫son [閫夐」]...\n"); + printf("浠庤緭鍏ヤ腑瑙f瀽鍜屾牸寮忓寲JSON鏁版嵁锛屽彲閫夋嫨鍘嬬缉鎴栨牸寮忓寲杈撳嚭銆俓n\n"); - printf("长选项的强制性参数对于短选项也是强制性的。\n"); - printf(" -if, --input 指定输入文件(默认为标准输入)\n"); - printf(" -of, --output 指定输出文件(默认为标准输出)\n"); - printf(" -f, --format 使用树形缩进输出格式化的JSON\n"); - printf(" -c, --compress 输出压缩的JSON\n"); - printf(" -h, --help 显示此帮助并退出\n\n"); + printf("闀块夐」鐨勫己鍒舵у弬鏁板浜庣煭閫夐」涔熸槸寮哄埗鎬х殑銆俓n"); + printf(" -if, --input 鎸囧畾杈撳叆鏂囦欢锛堥粯璁や负鏍囧噯杈撳叆锛塡n"); + printf(" -of, --output 鎸囧畾杈撳嚭鏂囦欢锛堥粯璁や负鏍囧噯杈撳嚭锛塡n"); + printf(" -f, --format 浣跨敤鏍戝舰缂╄繘杈撳嚭鏍煎紡鍖栫殑JSON\n"); + printf(" -c, --compress 杈撳嚭鍘嬬缉鐨凧SON\n"); + printf(" -h, --help 鏄剧ず姝ゅ府鍔╁苟閫鍑篭n\n"); - printf("示例:\n"); + printf("绀轰緥锛歕n"); printf(" json -if input.json -of output.json -f\n"); printf(" json --input=input.json --output=output.json --compress\n\n"); - printf("如果未指定输入或输出文件,则程序将默认使用标准输入或标准输出。\n\n"); + printf("濡傛灉鏈寚瀹氳緭鍏ユ垨杈撳嚭鏂囦欢锛屽垯绋嬪簭灏嗛粯璁や娇鐢ㄦ爣鍑嗚緭鍏ユ垨鏍囧噯杈撳嚭銆俓n\n"); - printf("注意:--compress 和 --format 选项不能同时使用。\n"); + printf("娉ㄦ剰锛--compress 鍜 --format 閫夐」涓嶈兘鍚屾椂浣跨敤銆俓n"); exit(0); } else { @@ -153,4 +144,4 @@ struct CommandLineArgs parseCommandLineArgs(int argc, char* argv[]) { } return args; -} \ No newline at end of file +} diff --git a/core/parser/parser.c b/core/parser/parser.c index a23c23e..fcdcdd3 100644 --- a/core/parser/parser.c +++ b/core/parser/parser.c @@ -30,7 +30,7 @@ struct JsonVal* parseValue() { ungetc(c, f); return parseNumber(); } - if (c == '"' || c == '\'') return parseString(); + if (c == '"' || c == '\'') return parseString(c); fprintf( stderr, "Unexcepted token %c at %llu", @@ -39,12 +39,12 @@ struct JsonVal* parseValue() { exit(1); } -struct JsonString* parseStringToStr() { +struct JsonString* parseStringToStr(char token) { char c; struct JsonString* str = JsonString_New(); const size_t pos = ftell(f) / sizeof(char); - while ((c = fgetc(f)) && c != EOF && c != '"' && c != '\'') { + while ((c = fgetc(f)) && c != EOF && c != token) { if (c == '\\') { c = fgetc(f); if (c == EOF) { @@ -75,15 +75,15 @@ struct JsonString* parseStringToStr() { else { JsonStringPushBackChar(c, str); } } - if (c != '"' && c != '\'') { - fprintf(stderr, "Expected character \" or ', but got EOF.\tString value parse begin with %llu\n", pos); + if (c != token) { + fprintf(stderr, "Expected character %c, but got EOF.\tString value parse begin with %llu\n", token, pos); exit(1); } return str; } -struct JsonVal* parseString() { - struct JsonString* str = parseStringToStr(); +struct JsonVal* parseString(char token) { + struct JsonString* str = parseStringToStr(token); struct JsonVal* res = malloc(sizeof(struct JsonVal)); if (res == NULL) { @@ -234,7 +234,7 @@ struct JsonVal* parseObject() { while ((c = fgetc(f)) != EOF && c != '}') { if (c == ' ' || c == '\n' || c == '\r' || c == ',') continue; - if (c == '"' || c == '\'') keyVal = parseStringToStr(); + if (c == '"' || c == '\'') keyVal = parseStringToStr(c); else if (c == ':') { const struct JsonVal* Val = parseValue(); diff --git a/core/parser/parser.h b/core/parser/parser.h index 6f45355..6ec4360 100644 --- a/core/parser/parser.h +++ b/core/parser/parser.h @@ -3,7 +3,7 @@ void setInputStream(FILE* stream); -struct JsonVal* parseString(); +struct JsonVal* parseString(char token); struct JsonVal* parseNumber(); struct JsonVal* parseBool(); struct JsonVal* parseNull(); diff --git a/core/utils/utf2gbk/UTF2GBK.c b/core/utils/utf2gbk/UTF2GBK.c index 1954c41..3cf9f9e 100644 --- a/core/utils/utf2gbk/UTF2GBK.c +++ b/core/utils/utf2gbk/UTF2GBK.c @@ -1,17 +1,21 @@ +#define _POSIX_C_SOURCE 200112L + #include #include #include #include +#include + +#define BUFFER_SIZE 4096 -FILE* convertUtf8ToGbk(FILE* input, const char* outputFileName) { +FILE* convertUtf8ToGbk(FILE* input) { iconv_t cd; + FILE* output = tmpfile(); cd = iconv_open("GBK", "UTF-8"); if (cd == (iconv_t)-1) { perror("iconv_open"); exit(EXIT_FAILURE); } - - FILE* output = fopen(outputFileName, "w"); if (output == NULL) { perror("fopen"); exit(EXIT_FAILURE); @@ -39,9 +43,9 @@ FILE* convertUtf8ToGbk(FILE* input, const char* outputFileName) { iconv_close(cd); fclose(input); - fclose(output); + rewind(output); - return fopen(outputFileName, "r"); + return output; } void convertGbkToUtf8(FILE* file) { @@ -92,9 +96,9 @@ void convertGbkToUtf8(FILE* file) { iconv_close(cd); // Reopen the original file for writing - file = fopen("converted_file.txt", "w"); + file = freopen("converted_file.txt", "w", stdout); if (file == NULL) { - perror("fopen"); + perror("freopen"); exit(EXIT_FAILURE); } @@ -109,26 +113,21 @@ void convertGbkToUtf8(FILE* file) { int isUtf8(FILE* file) { - rewind(file); // 灏嗘枃浠舵寚閽堝畾浣嶅埌鏂囦欢寮澶 - + // 鑾峰彇褰撳墠鏂囦欢鎸囬拡浣嶇疆 + long originalPosition = ftell(file); + int res = 0; // 璇诲彇鏂囦欢鐨勫墠涓変釜瀛楄妭 char bom[3]; size_t bytesRead = fread(bom, 1, 3, file); - - // 濡傛灉鏂囦欢灏忎簬3涓瓧鑺傦紝杩斿洖0 - if (bytesRead < 3) { - rewind(file); - return 0; - } + fseek(file, originalPosition, SEEK_SET); + fwrite(bom, 1, bytesRead, file); // 鍒ゆ柇鏄惁涓篣TF-8 without BOM缂栫爜 if (bom[0] == (char)0xEF && bom[1] == (char)0xBB && bom[2] == (char)0xBF) { // 鏂囦欢鍖呭惈BOM锛屼笉鏄疷TF-8 without BOM缂栫爜 - rewind(file); - return 0; + res = 0; } else { - // 鏂囦欢涓嶅寘鍚獴OM锛屽彲鑳芥槸UTF-8 without BOM缂栫爜 - rewind(file); - return 1; + res = 1; } -} \ No newline at end of file + return res; +} diff --git a/core/utils/utf2gbk/UTF2GBK.h b/core/utils/utf2gbk/UTF2GBK.h index dc2a017..c53f639 100644 --- a/core/utils/utf2gbk/UTF2GBK.h +++ b/core/utils/utf2gbk/UTF2GBK.h @@ -4,6 +4,6 @@ #pragma once #include -FILE* convertUtf8ToGbk(FILE* input, const char* outputFileName); +FILE* convertUtf8ToGbk(FILE* input); void convertGbkToUtf8(FILE* input); int isUtf8(FILE* file); \ No newline at end of file