Kaynağa Gözat

feat: 支持文件读取

支持打开和关闭文件
支持读取和写入文件

link #7
SongZihuan 4 yıl önce
ebeveyn
işleme
bb0c4fd503

+ 56 - 0
VirtulMathCore/file/file_.c

@@ -0,0 +1,56 @@
+#include "__virtualmath.h"
+
+/**
+ * @param dir 文件地址
+ * @return 0-错误, 1-普通文件, 2-目录
+ */
+int checkFileReadble(char *dir){
+    struct stat my_stat;
+    int status;
+    if (dir == NULL)
+        return 3;
+    status = stat(dir, &my_stat);
+    if (status != 0)
+        return 3;
+    else if (S_ISREG(my_stat.st_mode))  // 普通文件
+        return 1;
+    else if (S_ISDIR(my_stat.st_mode))
+        return 2;
+    else
+        return 3;
+}
+
+char *splitDir(char * dir){
+    char *slash = NULL;
+    char *point = NULL;
+    char *return_char = NULL;
+
+#ifdef __unix__
+    if (dir[memStrlen(dir) - 1] == '/')
+#else
+    if (dir[memStrlen(dir) - 1] == '\\')
+#endif  // __unix__
+    { dir[memStrlen(dir) - 1] = NUL; }
+
+#ifdef __unix__
+    if ((slash = strrchr(dir, '/'))  == NULL)
+#else
+        if ((slash = strchr(dir, '\\'))  == NULL)
+#endif  // __unix__
+    { slash = dir; }
+    else
+        slash ++;
+
+    if ((point = strchr(dir, '.'))  != NULL)
+        *point = 0;
+
+    return_char = memStrcpy(slash);
+    if (point != NULL)
+        *point = '.';
+    if (!isalpha(*return_char) && *return_char != '_')
+        return_char = memStrcat("_", return_char, false, true);
+    for (char *tmp = return_char; *tmp != 0;tmp++)
+        if (!isalnum(*tmp) &&'_' != *tmp)
+            *tmp = '_';
+    return return_char;
+}

+ 2 - 0
VirtulMathCore/include/inter.h

@@ -26,6 +26,7 @@ struct Inter{
         struct LinkValue *str;
         struct LinkValue *bool_;
         struct LinkValue *pass_;
+        struct LinkValue *file;
         struct LinkValue *tuple;
         struct LinkValue *list;
         struct LinkValue *dict;
@@ -58,6 +59,7 @@ struct Inter{
         wchar_t *var_str_prefix;
         wchar_t *var_num_prefix;
         wchar_t *var_bool_prefix;
+        wchar_t *var_file_prefix;
         wchar_t *var_none;
         wchar_t *var_pass;
         wchar_t *var_class_prefix;

+ 8 - 7
VirtulMathCore/include/mem.h

@@ -11,6 +11,7 @@ void *memRealloc(void *old, size_t size);
 char *memStrcpy(const char *str);
 wchar_t *memWidecpy(const wchar_t *str);
 wchar_t *memWideCharcpy(wchar_t *str, size_t nsize, bool free_old, bool write, ...);
+wchar_t *memWideExpansion(wchar_t *str, size_t nsize, bool free_old);
 char *memStrcatIter(char *base, bool free_base, ...);
 char *memStrcat(char *first, char *second, bool free_first, bool free_last);
 wchar_t *memWidecat(wchar_t *first, wchar_t *second, bool free_first, bool free_last);
@@ -19,12 +20,12 @@ wchar_t *memWiderev(wchar_t *str);
 char *memWcsToStr(wchar_t *wcs, bool free_old);
 wchar_t *memStrToWcs(char *str, bool free_old);
 
-#define memFree(p) ((p)=((p) != NULL ? (free(p), NULL) : NULL))
-#define eqString(str1, str2) (!strcmp(str1, str2))
-#define eqWide(wid1, wid2) (!wcscmp(wid1, wid2))
-#define memString(size) (char *)memCalloc(size + 1, sizeof(char))
-#define memWide(size) (wchar_t *)memCalloc(size + 1, sizeof(wchar_t))
-#define memStrlen(p) (((p) == NULL) ? 0 :strlen(p))
-#define memWidelen(p) (((p) == NULL) ? 0 :wcslen(p))
+#define memFree(p) ((p)=((p) != NULL ? (free((p)), NULL) : NULL))
+#define eqString(str1, str2) (!strcmp((str1), (str2)))
+#define eqWide(wid1, wid2) (!wcscmp((wid1), (wid2)))
+#define memString(size) (char *)memCalloc((size) + 1, sizeof(char))
+#define memWide(size) (wchar_t *)memCalloc((size) + 1, sizeof(wchar_t))
+#define memStrlen(p) (((p) == NULL) ? 0 :strlen((p)))
+#define memWidelen(p) (((p) == NULL) ? 0 :wcslen((p)))
 
 #endif //VIRTUALMATH_MEM_H

+ 1 - 0
VirtulMathCore/include/ofunc.h

@@ -15,6 +15,7 @@
 #include "listiter.h"
 #include "dictiter.h"
 #include "error_.h"
+#include "file_.h"
 
 struct Argument;
 struct VarList;

+ 9 - 0
VirtulMathCore/include/value.h

@@ -48,6 +48,7 @@ enum ValueType {
     V_obj=7,
     V_bool=8,
     V_ell=9,
+    V_file=10,
 };
 
 struct Number {
@@ -102,6 +103,13 @@ struct Bool{
     bool bool_;
 };
 
+struct File{
+    FILE *file;
+    char *path;  // 文件路径
+    char *mode;  // 模式
+    bool is_std;
+};
+
 struct Value{
     enum ValueType type;
 
@@ -118,6 +126,7 @@ struct Value{
         struct List list;
         struct Dict dict;
         struct Bool bool_;
+        struct File file;
     } data;
 
     struct Value *gc_next;

+ 11 - 1
VirtulMathCore/memory/mem.c

@@ -56,6 +56,16 @@ wchar_t *memWideCharcpy(wchar_t *str, size_t nsize, bool free_old, bool write, .
     return tmp;
 }
 
+wchar_t *memWideExpansion(wchar_t *str, size_t nsize, bool free_old) {
+    size_t base_len = memWidelen(str);
+    wchar_t *tmp = memWide(base_len + nsize);
+    if (base_len != 0)
+        wcscpy(tmp, str);
+    if (free_old)
+        memFree(str);
+    return tmp;
+}
+
 char *memStrcatIter(char *base, bool free_base, ...) {
     va_list ap;
     va_start(ap, free_base);
@@ -99,7 +109,7 @@ wchar_t *memWidecat(wchar_t *first, wchar_t *second, bool free_first, bool free_
         free_last = false;
     }
 
-    wchar_t *new = memWideCharcpy(first, memWidelen(second), false, false);
+    wchar_t *new = memWideExpansion(first, memWidelen(second), false);
     if (second != NULL)
         wcscat(new, second);
 

+ 5 - 0
VirtulMathCore/ofunc/include/file_.h

@@ -0,0 +1,5 @@
+#ifndef VIRTUALMATH_FILE__H
+#define VIRTUALMATH_FILE__H
+void makeBaseFile(Inter *inter);
+void registeredFile(R_FUNC);
+#endif //VIRTUALMATH_FILE__H

+ 0 - 1
VirtulMathCore/ofunc/src/error_.c

@@ -1,6 +1,5 @@
 #include "__ofunc.h"
 
-
 static LinkValue *makeException(LinkValue *father, Inter *inter){
     LinkValue *exc = makeBaseChildClass(father, inter);
     gc_addStatementLink(&exc->gc_status);

+ 204 - 0
VirtulMathCore/ofunc/src/file_.c

@@ -0,0 +1,204 @@
+#include "__ofunc.h"
+
+static void setFunctionData(Value *value, LinkValue *cls, Inter *inter) {
+    value->data.function.function_data.pt_type = inter->data.default_pt_type;
+    value->data.function.function_data.cls = cls;
+    value->data.function.function_data.run = false;
+}
+
+ResultType file_new(O_FUNC){
+    LinkValue *value = NULL;
+    ArgumentParser ap[] = {{.type=only_value, .must=1, .long_arg=false},
+                           {.must=-1}};
+    int status = 1;
+    setResultCore(result);
+    arg = parserValueArgument(ap, arg, &status, NULL);
+    if (status != 1) {
+        setResultError(E_ArgumentException, FEW_ARG, LINEFILE, true, CNEXT_NT);
+        return R_error;
+    }
+
+    value = make_new(inter, belong, ap[0].value);
+    value->value->type = V_file;
+    value->value->data.file.is_std = true;
+    value->value->data.file.path = NULL;
+    value->value->data.file.mode = NULL;
+    value->value->data.file.file = NULL;
+
+    run_init(value, arg, LINEFILE, CNEXT_NT);
+    return result->type;
+}
+
+ResultType file_init(O_FUNC){
+    ArgumentParser ap[] = {{.type=only_value, .must=1, .long_arg=false},
+                           {.type=name_value, .must=0, .name=L"file", .long_arg=false},
+                           {.type=name_value, .must=0, .name=L"mode", .long_arg=false},
+                           {.must=-1}};
+    LinkValue *file;
+    char *path;
+    char *mode;
+    setResultCore(result);
+    parserArgumentUnion(ap, arg, CNEXT_NT);
+    if (!CHECK_RESULT(result)) {
+        return result->type;
+    }
+    freeResult(result);
+
+    if ((file = ap[0].value)->value->type != V_file) {
+        setResultError(E_TypeException, INSTANCE_ERROR(file), LINEFILE, true, CNEXT_NT);
+        return R_error;
+    }
+
+    if (ap[1].value->value == NULL) {
+        setResult(result, inter);
+        return result->type;
+    } else if (ap[1].value->value->type != V_str) {
+        setResultError(E_TypeException, ONLY_ACC(file, str), LINEFILE, true, CNEXT_NT);
+        return R_error;
+    } else
+        path = memWcsToStr(ap[1].value->value->data.str.str, false);
+
+    if (ap[2].value != NULL && ap[2].value->value->type == V_str)
+        mode = memWcsToStr(ap[2].value->value->data.str.str, false);
+    else
+        mode = memStrcpy("r");
+
+    if (checkFileReadble(path) != 1) {
+        setResultError(E_TypeException, L"File is not readable", LINEFILE, true, CNEXT_NT);
+        return R_error;
+    }
+    file->value->data.file.path = path;
+    file->value->data.file.mode = mode;
+    file->value->data.file.is_std = false;
+    file->value->data.file.file = fopen(path, mode);
+
+    setResult(result, inter);
+    return result->type;
+}
+
+ResultType file_read(O_FUNC){
+    ArgumentParser ap[] = {{.type=only_value, .must=1, .long_arg=false},
+                           {.type=name_value, .must=0, .name=L"n", .long_arg=false},
+                           {.must=-1}};
+    LinkValue *file;
+    wchar_t *tmp = NULL;
+    setResultCore(result);
+    parserArgumentUnion(ap, arg, CNEXT_NT);
+    if (!CHECK_RESULT(result)) {
+        return result->type;
+    }
+    freeResult(result);
+
+    if ((file = ap[0].value)->value->type != V_file || file->value->data.file.file == NULL) {
+        setResultError(E_TypeException, INSTANCE_ERROR(file), LINEFILE, true, CNEXT_NT);
+        return R_error;
+    }
+
+    if (ap[1].value != NULL) {
+        size_t n;
+        wint_t ch;
+        if (ap[1].value->value->type != V_num) {
+            setResultError(E_TypeException, ONLY_ACC(n, num), LINEFILE, true, CNEXT_NT);
+            return R_error;
+        }
+
+        n = ap[1].value->value->data.num.num;
+        tmp = memWide(n);
+        for (int count=0; count < n && (ch = getwc(file->value->data.file.file)) != WEOF; count++)
+            tmp[count] = ch;
+    } else {
+        size_t n = 0;
+        size_t step = 50;
+        wint_t ch;
+        tmp = NULL;
+        for (int count=1; (ch = getwc(file->value->data.file.file)) != WEOF; count++) {
+            if (count > n) {
+                n += step;
+                tmp = memWideExpansion(tmp, n, true);
+            }
+            tmp[count - 1] = ch;
+        }
+    }
+
+    makeStringValue(tmp, LINEFILE, CNEXT_NT);
+    memFree(tmp);
+    return result->type;
+}
+
+ResultType file_write(O_FUNC){
+    ArgumentParser ap[] = {{.type=only_value, .must=1, .long_arg=false},
+                           {.type=name_value, .must=1, .name=L"str", .long_arg=false},
+                           {.must=-1}};
+    LinkValue *file;
+    setResultCore(result);
+    parserArgumentUnion(ap, arg, CNEXT_NT);
+    if (!CHECK_RESULT(result)) {
+        return result->type;
+    }
+    freeResult(result);
+
+    if ((file = ap[0].value)->value->type != V_file || file->value->data.file.file == NULL) {
+        setResultError(E_TypeException, INSTANCE_ERROR(file), LINEFILE, true, CNEXT_NT);
+        return R_error;
+    }
+
+    if (ap[1].value->value->type != V_str) {
+        setResultError(E_TypeException, ONLY_ACC(str, str), LINEFILE, true, CNEXT_NT);
+        return R_error;
+    }
+
+    fprintf(file->value->data.file.file, "%ls", ap[1].value->value->data.str.str);
+    setResult(result, inter);
+    return result->type;
+}
+
+ResultType file_close(O_FUNC){
+    ArgumentParser ap[] = {{.type=only_value, .must=1, .long_arg=false},
+                           {.must=-1}};
+    LinkValue *file;
+    setResultCore(result);
+    parserArgumentUnion(ap, arg, CNEXT_NT);
+    if (!CHECK_RESULT(result)) {
+        return result->type;
+    }
+    freeResult(result);
+
+    if ((file = ap[0].value)->value->type != V_file || file->value->data.file.file == NULL) {
+        setResultError(E_TypeException, INSTANCE_ERROR(file), LINEFILE, true, CNEXT_NT);
+        return R_error;
+    }
+
+    if (file->value->data.file.is_std) {
+        setResultError(E_TypeException, L"stream cannot be closed", LINEFILE, true, CNEXT_NT);
+        return R_error;
+    }
+
+    fclose(file->value->data.file.file);
+    file->value->data.file.file = NULL;
+    memFree(file->value->data.file.path);
+    memFree(file->value->data.file.mode);
+    file->value->data.file.is_std = true;
+
+    setResult(result, inter);
+    return result->type;
+}
+
+void registeredFile(R_FUNC){
+    LinkValue *object = inter->data.file;
+    NameFunc tmp[] = {{L"read", file_read, object_free_},
+                      {L"write", file_write, object_free_},
+                      {L"close", file_close, object_free_},
+                      {inter->data.object_new, file_new, class_free_},
+                      {inter->data.object_init, file_init, object_free_},
+                      {NULL, NULL}};
+    gc_addTmpLink(&object->gc_status);
+    addBaseClassVar(L"file", object, belong, inter);
+    iterBaseClassFunc(tmp, object, CFUNC_CORE(inter->var_list));
+    gc_freeTmpLink(&object->gc_status);
+}
+
+void makeBaseFile(Inter *inter){
+    LinkValue *file = makeBaseChildClass(inter->data.vobject, inter);
+    gc_addStatementLink(&file->gc_status);
+    inter->data.file = file;
+}

+ 1 - 0
VirtulMathCore/ofunc/src/pass.c

@@ -13,6 +13,7 @@ ResultType pass_new(O_FUNC){
     }
     value = make_new(inter, belong, ap[0].value);
     value->value->type = V_ell;
+
     run_init(value, arg, LINEFILE, CNEXT_NT);
     return result->type;
 }

+ 5 - 0
VirtulMathCore/ofunc/src/sys.c

@@ -136,6 +136,10 @@ ResultType vm_quit(O_FUNC){
     return R_error;
 }
 
+ResultType vm_open(O_FUNC){
+    return callBackCore(inter->data.file, arg, LINEFILE, 0, CNEXT_NT);
+}
+
 ResultType vm_exec(O_FUNC){
     ArgumentParser ap[] = {{.type=name_value, .name=L"cm", .must=1, .long_arg=false},
                            {.type=name_value, .name=L"var", .must=0, .long_arg=false},
@@ -236,6 +240,7 @@ void registeredSysFunction(R_FUNC){
                       {L"disnowrun", vm_disnowrun, free_},
                       {L"quit", vm_quit, free_},
                       {L"exec", vm_exec, free_},
+                      {L"open", vm_open, free_},
                       {NULL, NULL}};
     iterBaseNameFunc(tmp, belong, CFUNC_CORE(var_list));
 }

+ 2 - 0
VirtulMathCore/src/__run.c

@@ -86,6 +86,8 @@ wchar_t *getNameFromValue(Value *value, struct Inter *inter) {
             return memWidecpy(inter->data.var_none);
         case V_ell:
             return memWidecpy(inter->data.var_pass);
+        case V_file:
+            return memWidecat(inter->data.var_file_prefix, memStrToWcs(value->data.file.path, false), false, true);
         case V_class:{
             size_t len = memWidelen(inter->data.var_class_prefix) + 20;  // 预留20个字节给指针
             wchar_t *name = memWide(len);

+ 5 - 2
VirtulMathCore/src/inter.c

@@ -55,9 +55,10 @@ Inter *makeInter(char *out, char *error_, char *in, LinkValue *belong) {
 void setBaseInterData(struct Inter *inter){
     inter->data.var_str_prefix = setName("str_");
     inter->data.var_num_prefix = setName("num_");
-    inter->data.var_none = setName("V_none");
+    inter->data.var_file_prefix = setName("file_");
+    inter->data.var_none = setName("none");
     inter->data.var_pass = setName("ellipsis");
-    inter->data.var_bool_prefix = setName("V_bool");
+    inter->data.var_bool_prefix = setName("bool_");
     inter->data.var_class_prefix = setName("class_");
     inter->data.var_object_prefix = setName("obj_");
     inter->data.object_init = setName("__init__");
@@ -97,6 +98,7 @@ void freeBaseInterData(struct Inter *inter){
     gc_freeStatementLink(&inter->data.bool_->gc_status);
     gc_freeStatementLink(&inter->data.function->gc_status);
     gc_freeStatementLink(&inter->data.pass_->gc_status);
+    gc_freeStatementLink(&inter->data.file->gc_status);
     gc_freeStatementLink(&inter->data.tuple->gc_status);
     gc_freeStatementLink(&inter->data.list->gc_status);
     gc_freeStatementLink(&inter->data.dict->gc_status);
@@ -129,6 +131,7 @@ void freeBaseInterData(struct Inter *inter){
 
     memFree(inter->data.var_num_prefix);
     memFree(inter->data.var_str_prefix);
+    memFree(inter->data.var_file_prefix);
     memFree(inter->data.var_object_prefix);
     memFree(inter->data.var_class_prefix);
     memFree(inter->data.var_bool_prefix);

+ 2 - 0
VirtulMathCore/src/ofunc.c

@@ -11,6 +11,7 @@ static Registered base_func_list[] = {registeredVObject,
                                       registeredListIter,
                                       registeredDictIter,
                                       registeredExcIter,
+                                      registeredFile,
 
                                       registeredSysFunction,
                                       registeredIOFunction,
@@ -46,6 +47,7 @@ void registeredFunctionName(Inter *inter, LinkValue *belong){
     makeBaseListIter(inter);
     makeBaseDictIter(inter);
     makeExcIter(inter);
+    makeBaseFile(inter);
 
     makeBaseStr(inter);
     presetting(inter);

+ 12 - 1
VirtulMathCore/src/value.c

@@ -204,6 +204,12 @@ void freeValue(Value **value) {
         case V_str:
             memFree(free_value->data.str.str);
             break;
+        case V_file:
+            memFree(free_value->data.file.mode);
+            memFree(free_value->data.file.path);
+            if (!free_value->data.file.is_std)
+                fclose(free_value->data.file.file);
+            break;
         case V_func: {
             freeParameter(free_value->data.function.pt, true);
             freeStatement(free_value->data.function.function);
@@ -417,7 +423,6 @@ void setResultError(BaseErrorType type, wchar_t *error_message, fline line, char
             exc = inter->data.base_exc;
         freeResult(result);
         callException(exc, error_message, line, file, CNEXT_NT);
-        printf("result is %p hhh\n", result->value);
     }
     else
         result->error = connectError(makeError(NULL, NULL, line, file), result->error);
@@ -646,6 +651,12 @@ void printValue(Value *value, FILE *debug, bool print_father, bool print_in) {
         case V_str:
             fprintf(debug, "'%ls'", value->data.str.str);
             break;
+        case V_file:
+            if (print_father)
+                fprintf(debug, "(file %s)", value->data.file.path);
+            else
+                fprintf(debug, "(file %s on %p)", value->data.file.path, value);
+            break;
         case V_func:
             if (print_father)
                 fprintf(debug, "func");