Browse Source

refactor & feat: code支持写入到文件

SongZihuan 3 years ago
parent
commit
2ddd0b572f

+ 15 - 8
include/core/code.hpp

@@ -20,7 +20,7 @@ namespace aFuncore {
     typedef class Code Code;
     class Code {
         CodeType type;
-        char perfix=NUL;
+        char prefix=NUL;
 
         union {
             char *element;  // union 内不使用 std::string
@@ -35,9 +35,9 @@ namespace aFuncore {
         Code *next = nullptr;;
         Code *prev = nullptr;;
 
-    public:
         aFuntool::FileLine line;
         aFuntool::FilePath file;
+    public:
 
         explicit Code(FileLine line, ConstFilePath file="");
         Code (const std::string &element, aFuntool::FileLine line, aFuntool::ConstFilePath file="", char prefix=NUL);
@@ -45,21 +45,28 @@ namespace aFuncore {
         ~Code();
 
         Code *connect(Code *code);
-        void destruct();
-        void display();
-        void displayAll();
+        void destructAll();
+        void display() const;
+        void displayAll() const;
+        bool write_v1(FILE *f, bool debug=false) const;
+        bool writeAll_v1(FILE *f, bool debug=false) const;
+        Code *read_v1(FILE *f, bool debug=false, int8_t read_type=code_element, bool to_son=false);
+        bool readAll_v1(FILE *f, bool debug=false);
+
 
         [[nodiscard]] CodeType getType() const {return type;}
-        [[nodiscard]] char getPrefix() const {return perfix;}
+        [[nodiscard]] char getPrefix() const {return prefix;}
 
-        [[nodiscard]] const char *getElement() const {if (type != code_element) throw aFuncore::AttributesError("Code.Element"); return element;}
-        [[nodiscard]] BlockType getBlockType() const {if (type != code_block) throw aFuncore::AttributesError("Code.BlockType"); return block_type;}
+        [[nodiscard]] const char *getElement() const {if (type != code_element) return ""; return element;}
+        [[nodiscard]] BlockType getBlockType() const {if (type != code_block) return block_p; return block_type;}
         [[nodiscard]] Code *getSon() const {if (type != code_block) return nullptr; return son;}
 
         [[nodiscard]] Code *toNext() const {return next;}
         [[nodiscard]] Code *toPrev() const {return prev;}
         [[nodiscard]] Code *toFather() const {return father;}
 
+        [[nodiscard]] aFuntool::FileLine getFileLine() const {return line;}
+        [[nodiscard]] aFuntool::StringFilePath getFilePath() const {return file;}
     };
 }
 

+ 3 - 2
include/tool/macro.hpp

@@ -21,8 +21,9 @@
 
 namespace aFuntool {
     typedef uint32_t FileLine;  // 文件行号
-    typedef std::string FilePath;  // 文件路径
-    typedef const std::string &ConstFilePath;  // 文件路径
+    typedef char *FilePath;  // 文件路径  (用于多处内存存储场景)
+    typedef std::string StringFilePath;  // 文件路径  (用于单处内存存储场景)
+    typedef const std::string &ConstFilePath;  // 文件路径  (用于参数)
 }
 
 #endif //AFUN_MACRO_HPP

+ 4 - 1
include/tool/mem.hpp

@@ -13,7 +13,7 @@
 /* 取代calloc函数 */
 namespace aFuntool {
     template <typename T>
-    static void *safeFree(T *&ptr) {if (ptr != nullptr) free((void *)ptr); ptr = nullptr; return nullptr;}
+    static void *safeFree(T *ptr) {if (ptr != nullptr) free((void *)ptr); return nullptr;}
 
     static void *safeCalloc(size_t n, size_t size){
         void *re = calloc(n, size);
@@ -31,7 +31,10 @@ namespace aFuntool {
     }
 }
 
+#ifndef MEM_NOT_DEFINE
+#define free(p) (safeFree((p)))
 #define calloc(n, obj) (obj *)(aFuntool::safeCalloc(n, sizeof(obj)))
 #define calloc_size(n, size) (aFuntool::safeCalloc(n, size))
+#endif
 
 #endif  // AFUN_MEM_HPP

+ 278 - 35
src/core/code.cpp

@@ -3,16 +3,34 @@
 using namespace aFuncore;
 using namespace aFuntool;
 
-Code::Code(FileLine line, ConstFilePath file){
+/**
+ * 创建 `start` 代码块
+ * @param line
+ * @param file
+ */
+Code::Code(FileLine line, ConstFilePath file){  // NOLINT 不初始化 element, block_type, son
     this->type = code_start;
-    this->file = file;
+    if (file.empty())
+        this->file = nullptr;
+    else
+        this->file = strCopy(file.c_str());
     this->line = line;
 }
 
-aFuncore::Code::Code(const std::string &element, FileLine line, ConstFilePath file, char prefix){
+/**
+ * 创建 `element` 代码块
+ * @param element
+ * @param line
+ * @param file
+ * @param prefix
+ */
+aFuncore::Code::Code(const std::string &element, FileLine line, ConstFilePath file, char prefix){  // NOLINT 不初始化 block_type, son
     this->type=code_element;
-    this->perfix = prefix;
-    this->file = file;
+    this->prefix = prefix;
+    if (file.empty())
+        this->file = nullptr;
+    else
+        this->file = strCopy(file.c_str());
     this->line = line;
 
     if (!isCharUTF8(element)) {
@@ -22,10 +40,21 @@ aFuncore::Code::Code(const std::string &element, FileLine line, ConstFilePath fi
         this->element = strCopy(element.c_str());
 }
 
-Code::Code(BlockType block_type, Code *son, FileLine line, ConstFilePath file, char prefix){
+/**
+ * 创建 `block` 代码块
+ * @param block_type
+ * @param son
+ * @param line
+ * @param file
+ * @param prefix
+ */
+Code::Code(BlockType block_type, Code *son, FileLine line, ConstFilePath file, char prefix){  // NOLINT 不出时候 element
     this->type=code_block;
-    this->perfix = prefix;
-    this->file = file;
+    this->prefix = prefix;
+    if (file.empty())
+        this->file = nullptr;
+    else
+        this->file = strCopy(file.c_str());
     this->line = line;
 
     this->block_type = block_type;
@@ -37,9 +66,15 @@ Code::Code(BlockType block_type, Code *son, FileLine line, ConstFilePath file, c
 
 Code::~Code(){
     if (type == code_element)
-        safeFree(element);
+        free(element);
+    free(file);
 }
 
+/**
+ * 连结代码块
+ * @param code
+ * @return
+ */
 Code *Code::connect(Code *code){
     Code *tmp = this;
     while (tmp->next != nullptr)
@@ -50,64 +85,272 @@ Code *Code::connect(Code *code){
         return tmp;
     }
 
+    Code *father_ = tmp->father;
     tmp->next = code;
     code->prev = tmp;
-    while (code->next != nullptr)
+    while (code->next != nullptr) {
         code = code->next;
+        code->father = father_;
+    }
     return code;
 }
 
-void Code::destruct(){
+/**
+ * 删除自己以及其子、兄代码块
+ */
+void Code::destructAll(){
     if (this->type != code_start) {
         errorLog(aFunCoreLogger, "Code delete did not with `start`");
         return;
     }
 
     Code *tmp = this;
-    while (tmp->next != nullptr || tmp->father != nullptr) {
-        if (tmp->type == code_element || tmp->son == nullptr)
+    Code *next_tmp;
+    while (tmp != nullptr) {
+        if (tmp->type != code_block || tmp->son == nullptr) {
+            if (tmp->next == nullptr) {
+                if (tmp->father == nullptr)
+                    next_tmp = nullptr;
+                else {
+                    next_tmp = tmp->father;
+                    next_tmp->son = nullptr;
+                }
+            } else
+                next_tmp = tmp->next;
             delete tmp;
-        else {
+            tmp = next_tmp;
+        } else
             tmp = tmp->son;
-            tmp->father->son = nullptr;
-            continue;
-        }
-
-        if (tmp->next == nullptr)
-            tmp = tmp->father;
-        else
-            tmp = tmp->next;
-
     }
     delete tmp;
 }
 
-void Code::display(){
-    printf_stdout(0, "%c[father: %p] type=%d %p", perfix == NUL ? '=' : perfix, father, type, this);
+/**
+ * 显式代码块内容
+ */
+void Code::display() const {
+    printf_stdout(0, "%c[father: %p] type=%d %p", prefix == NUL ? '-' : prefix, father, type, this);
     if (type == code_element)
-        printf_stdout(0, "element: %s\n", element);
+        printf_stdout(0, " element: %s\n", element);
+    else if (type == code_block)
+        printf_stdout(0, " block: '%c' son: %p\n", block_type, son);
     else
-        printf_stdout(0, "block: %c son: %p\n", block_type, son);
+        printf_stdout(0, "\n");
 }
 
-void Code::displayAll(){
+/**
+ * 显式自己以及其子、兄代码块
+ */
+void Code::displayAll() const {
     if (this->type != code_start) {
         errorLog(aFunCoreLogger, "Code dsplay all did not with `start`");
         return;
     }
 
-    Code *tmp = this;
-    while (tmp->next != nullptr || tmp->father != nullptr) {
+    const Code *tmp = this;
+    while (tmp != nullptr) {
         tmp->display();
         if (tmp->type == code_block && tmp->son != nullptr){
             tmp = tmp->son;
             continue;
         }
 
-        if (tmp->next == nullptr)
-            tmp = tmp->father->next;
-        else
+        if (tmp->next == nullptr) {
+            do {
+                tmp = tmp->father;
+            } while(tmp != nullptr && tmp->next == nullptr);
+            if (tmp == nullptr)
+                break;
             tmp = tmp->next;
+        } else
+            tmp = tmp->next;
+    }
+}
+
+#define Done(write) do{if(!(write)){return false;}}while(0)
+
+/**
+ * 将code写入到文件中 (版本: 1)
+ * @param f
+ * @param debug 是否记录 debug 信息
+ * @return
+ */
+bool Code::write_v1(FILE *f, bool debug) const{
+    switch (type) {
+        case code_element:
+            Done(byteWriteInt(f, (int8_t)code_element));
+            Done(byteWriteInt(f, (int8_t)prefix));
+            Done(byteWriteStr(f, element));
+            break;
+        case code_block:
+            if (son == nullptr)
+                Done(byteWriteInt(f, (int8_t)4));  // 空 block 标注为 4
+            else
+                Done(byteWriteInt(f, (int8_t) code_block));
+            Done(byteWriteInt(f, (int8_t)prefix));
+            Done(byteWriteInt(f, (int8_t)block_type));
+            break;
+        default:
+            break;
+
+    }
+    if (debug) {
+        Done(byteWriteInt(f, (int16_t)line));
+        Done(byteWriteStr(f, file));
     }
-    tmp->display();
-}
+    return true;
+}
+
+/**
+ * 将的子、兄code写入到文件中 (版本: 1)
+ * 注意: 不包括自己(`start`)
+ * @param f
+ * @param debug
+ * @return
+ */
+bool Code::writeAll_v1(FILE *f, bool debug) const{
+    if (this->type != code_start) {
+        errorLog(aFunCoreLogger, "Code write all did not with `start`");
+        return false;
+    }
+
+    const Code *tmp = this;
+    while (tmp != nullptr) {
+        Done(tmp->write_v1(f, debug));
+        if (tmp->type == code_block && tmp->son != nullptr){
+            tmp = tmp->son;
+            continue;
+        }
+
+        if (tmp->next == nullptr) {
+            do {
+                tmp = tmp->father;
+                Done(byteWriteInt(f, (int8_t)3));
+            } while(tmp != nullptr && tmp->next == nullptr);
+            if (tmp == nullptr)
+                break;
+            tmp = tmp->next;
+        } else
+            tmp = tmp->next;
+    }
+    Done(byteWriteInt(f, (int8_t)0));
+    return true;
+}
+
+/**
+ * 读取文件中的code (版本: 1)
+ * @param f
+ * @param debug 文件是否包含 debug 信息
+ * @return
+ */
+bool Code::readAll_v1(FILE *f, bool debug) {
+    if (this->type != code_start) {
+        errorLog(aFunCoreLogger, "Code read all did not with `start`");
+        return false;
+    }
+
+    Code *father_ = nullptr;
+    Code *next_ = this;
+    const Code *tmp = this;
+    while (tmp != nullptr) {
+        int8_t type_ = NUL;
+        Done(byteReadInt(f, &type_));
+        switch (type_) {
+            case 0:
+                goto RETURN;
+            case 3:
+                if (next_ == nullptr) {
+                    errorLog(aFunCoreLogger, "Code read all error");
+                    return false;
+                }
+                next_ = next_->father;
+                break;
+            default: {
+                Code *ret;
+                if (next_ == nullptr && father_ != nullptr)
+                    ret = father_->read_v1(f, debug, type_, true);
+                else if (next_ != nullptr)
+                    ret = next_->read_v1(f, debug, type_, false);
+                else {
+                    errorLog(aFunCoreLogger, "Code read all error");
+                    return false;
+                }
+
+                if (ret == nullptr) {
+                    errorLog(aFunCoreLogger, "Code read error");
+                    return false;
+                } else if (type_ == code_block) {
+                    next_ = nullptr;
+                    father_ = ret;
+                } else {
+                    next_ = ret;
+                    father_ = nullptr;
+                }
+                break;
+            }
+        }
+    }
+RETURN:
+    return true;
+}
+
+#undef Done
+#define Done(write) do{if(!(write)){return nullptr;}}while(0)
+
+/**
+ * 读取 code 并拼接到 next 或 son 中 (版本: 1)
+ * @param f
+ * @param debug 文件是否包含 debug 信息
+ * @param read_type 读取类型
+ * @param to_son 若位true则拼接到son, 否则拼接到next
+ * @return
+ */
+Code *Code::read_v1(FILE *f, bool debug, int8_t read_type, bool to_son) {
+    Code *ret;
+    switch (read_type) {
+        case code_element: {
+            int8_t prefix_ = NUL;
+            std::string element_;
+            Done(byteReadInt(f, &prefix_));
+            Done(byteReadStr(f, element_));
+            ret = new Code(element_, 0, "", char(prefix_));
+            break;
+        }
+        case 4:
+        case code_block: {
+            int8_t prefix_ = NUL;
+            int8_t block_type = NUL;
+            Done(byteReadInt(f, &prefix_));
+            Done(byteReadInt(f, &block_type));
+            ret = new Code(BlockType(block_type), nullptr, 0, "", char(prefix_));
+            break;
+        }
+        default:
+            errorLog(aFunCoreLogger, "Read code with error type.");
+            return nullptr;
+    }
+
+    if (debug) {
+        int16_t line_ = NUL;
+        char *file_ = nullptr;
+        Done(byteReadInt(f, &line_));
+        Done(byteReadStr(f, file_));
+        ret->line = line;
+        if (strlen(file) != 0)
+            ret->file = strCopy(file);
+    }
+
+    if (to_son) {
+        if (type != code_block || son != nullptr) {
+            errorLog(aFunCoreLogger, "Read son with error type.");
+            delete ret;
+            return nullptr;
+        }
+        ret->father = this;
+        son = ret;
+    } else
+        connect(ret);
+    return ret;
+}
+
+#undef Done

+ 10 - 0
src/tool/byte.cpp

@@ -124,6 +124,11 @@ bool aFuntool::byteReadStr(FILE *file, char *&str) {
     if (!byteReadInt<uint16_t>(file, &len))
         return false;
 
+    if (len == 0) {
+        str = nullptr;
+        return true;
+    }
+
     str = calloc(len + 1, char);
     return fread(str, sizeof(char), len, file) == len;
 }
@@ -136,6 +141,11 @@ bool aFuntool::byteReadStr(FILE *file, std::string &str) {
     if (!byteReadInt<uint16_t>(file, &len))
         return false;
 
+    if (len == 0) {
+        str = "";
+        return true;
+    }
+
     char *tmp = calloc(len + 1, char);
     size_t ret = fread(tmp, sizeof(char), len, file);
     str = tmp;

+ 5 - 3
src/tool/string.cpp

@@ -26,10 +26,12 @@ char *aFuntool::charToStr(char ch) {
 }
 
 char *aFuntool::strCopy(const char *str){
-    char *tmp = NEW_STR(STR_LEN(str));
-    if (str != nullptr)
+    if (str != nullptr) {
+        char *tmp = NEW_STR(STR_LEN(str));
         strcpy(tmp, str);
-    return tmp;
+        return tmp;
+    }
+    return nullptr;
 }
 
 

+ 2 - 1
test/src/CMakeLists.txt

@@ -26,4 +26,5 @@ add_new_test(tool_hash COMMAND "$<TARGET_FILE:tool_hash>")
 add_new_test(tool_utf COMMAND "$<TARGET_FILE:tool_utf>")
 set_test_label(tool tool_mem tool_byte tool_dlc tool_regex tool_md5 tool_utf)
 
-add_new_test(core_init COMMAND "$<TARGET_FILE:core_init>")
+add_new_test(core_init COMMAND "$<TARGET_FILE:core_init>")
+add_new_test(core_code COMMAND "$<TARGET_FILE:core_code>")

+ 28 - 0
test/src/core_code.cpp

@@ -0,0 +1,28 @@
+#include "code.hpp"
+using namespace aFuncore;
+using namespace aFuntool;
+
+int main() {
+    Code *start = new Code(1, "test.aun");
+    start->connect(new Code("Test", 1))->connect(new Code(block_p, new Code(block_p, new Code("Test2", 2), 2), 2));
+    start->displayAll();
+
+    getEndian();
+
+    FILE *file = fileOpen("text.aun", "wb");
+    start->writeAll_v1(file);
+    fileClose(file);
+
+    start->destructAll();
+    start = new Code(1, "test.aun");
+
+    file = fileOpen("text.aun", "rb");
+    start->readAll_v1(file);
+    fileClose(file);
+
+    printf("writr: \n");
+    start->displayAll();
+    start->destructAll();
+
+    return 0;
+}

+ 4 - 1
test/src/tool_md5.cpp

@@ -8,7 +8,10 @@ int main(int argc, char **argv) {
     char *file_path = argv[2];
     char *my_md5 = getFileMd5(file_path);
 
-    if (!strcmp(my_md5, md5_answer))
+    bool ret = !strcmp(my_md5, md5_answer);
+    free(my_md5);
+
+    if (ret)
         return 0;
     return 1;  // 不相等, 表示错误
 }

+ 2 - 1
test/src/tool_utf.cpp

@@ -9,6 +9,7 @@ int main(int argc, char **argv) {
 
     setlocale(LC_ALL, "");
 
+#ifdef aFunWIN32_NO_CYGWIN
     convertWideByte(&tmp, tmp3, CP_UTF8);
 
     std::wcout << tmp << std::endl;
@@ -25,6 +26,6 @@ int main(int argc, char **argv) {
     for (int i = 0; i < strlen(tmp3); i++)
         printf("%x ", (unsigned int)tmp3[i]);
     printf("\n");
-
+#endif
     return 0;
 }