Переглянути джерело

update: 调整import的访问机制, 允许直接import动态库

import可以直接导入动态库, 自动添加后缀和前缀
运行环境写入inter中, 不需要使用getcwd获取
import新模块的时候会自动调整inter的运行环境

link #17
SongZihuan 4 роки тому
батько
коміт
0aaa092561

+ 3 - 1
main.c

@@ -2,6 +2,8 @@
 
 int main(int argc, char *argv[]) {
     Inter *inter = NULL;
+    char arr_cwd[200];
+    getcwd(arr_cwd, 200);
 
 #ifdef DEBUG
     setbuf(stdout, NULL);  // debug模式下关闭缓冲区以尽快输出信息便于debug
@@ -21,7 +23,7 @@ int main(int argc, char *argv[]) {
         return 2;
 
     initVirtualMath(args.locale);
-    inter = makeInter(args.out_file, args.error_file, args.in_file, NULL);
+    inter = makeInter(args.out_file, args.error_file, args.in_file, arr_cwd, NULL);
     runCodeFile(inter, argv + optind);  // 从文件中运行代码
     if (args.run_commandLine)
         runCodeStdin(inter, HelloString);  // 从stdin中运行代码

+ 1 - 0
src/virtualmath.c

@@ -15,6 +15,7 @@ void runCodeFile(Inter *inter, char *file[]) {
                 continue;
         }
         if (runParser(*file, inter, false, &pst)) {
+            changeInterEnv(*file, true, inter);  // 设置运行环境
             globalIterStatement(&result, inter, pst, true);
             if (result.type == R_error) {
                 printError(&result, inter, args.p_clock);

+ 2 - 0
vmcore/include/__macro.h

@@ -38,9 +38,11 @@
 #ifdef __linux__
 #define SEP "/"
 #define SEP_CH '/'
+#define SHARED_MARK ".so"
 #else
 #define SEP "\\"
 #define SEP_CH '\\'
+#define SHARED_MARK ".dll"
 #endif
 
 #define MD5_SIZE (16)

+ 0 - 1
vmcore/include/clib.h

@@ -5,5 +5,4 @@
 struct Inter;
 struct LinkValue;
 void importClibCore(char *file, struct LinkValue *belong, FUNC_CORE);
-bool checkCLib(char **file);
 #endif //VIRTUALMATH_CLIB_H

+ 4 - 2
vmcore/include/inter.h

@@ -142,6 +142,7 @@ struct Inter{
         bool opt_folding;  // 表达式折叠[on]
         bool cyc_folding;  // 在循环内部自动打开折叠
         bool func_folding;  // 在函数内部自动打开
+        char *env;  // 执行目录
     } data;
 };
 
@@ -150,18 +151,19 @@ typedef struct Statement Statement;
 typedef enum ResultType ResultType;
 typedef struct ClibInfo ClibInfo;
 
-Inter *makeInter(char *out, char *error_, char *in, LinkValue *belong);
+Inter *makeInter(char *out, char *error_, char *in, char *env, LinkValue *belong);
 void freeInter(Inter *inter, bool show_gc);
 void setBaseInterData(struct Inter *inter);
 void runCodeStdin(Inter *inter, char *hello_string);
 void runCodeFile(Inter *inter, char *file[]);
 bool runParser(char *code_file, Inter *inter, bool is_one, Statement **st);
 void mergeInter(Inter *new, Inter *base);
-Inter *deriveInter(LinkValue *belong, Inter *inter);
+Inter *deriveInter(char *env, LinkValue *belong, Inter *inter);
 
 ClibInfo *makeClibInfo();
 void makeClibInfoToInter(void *dl, Inter *inter);
 ClibInfo *freeClibInfo(ClibInfo *info);
 void freeClibInfoFromInter(Inter *inter);
+void changeInterEnv(char *env, bool split, Inter *inter);
 
 #endif //VIRTUALMATH_INTER_H

+ 0 - 44
vmcore/ofunc/clib/manager.c

@@ -1,49 +1,5 @@
 #include "__virtualmath.h"
 
-#define CHECK_CLIB(path, dl) ((dl = dlopen(path, RTLD_NOW)) != NULL) && (dlsym(dl, "registered") != NULL)
-
-bool checkCLib(char **file) {
-    char *lib_file = strncmp(*file, "libvm", 5) == 0 ? memStrcpy(*file) : memStrcatIter("libvm", false, *file, ".so", NULL);
-    bool return_ = false;
-    void *tmp_dl;
-
-    char arr_cwd[200];
-    char *p_cwd = NULL;
-    getcwd(arr_cwd, 200);
-    p_cwd = memStrcatIter(arr_cwd, false, SEP, lib_file, NULL);  // 以NULL结尾表示结束
-    if (CHECK_CLIB(p_cwd, tmp_dl)) {
-        return_ = true;
-        dlclose(tmp_dl);
-    }
-    memFree(p_cwd);
-
-
-    if (!return_) {
-        char *path = memStrcpy(getenv("VIRTUALMATHPATH"));
-        for (char *tmp = strtok(path, ";"), *new_dir; tmp != NULL; tmp = strtok(NULL, ";")) {
-            if (*(tmp + (memStrlen(tmp) - 1)) != SEP_CH)
-                new_dir = memStrcatIter(tmp, false, SEP, lib_file, NULL);  // 以NULL结尾表示结束
-            else
-                new_dir = memStrcat(tmp, lib_file, false, false);
-
-            if (CHECK_CLIB(new_dir, tmp_dl)) {
-                return_ = true;
-                dlclose(tmp_dl);
-            }
-            memFree(new_dir);
-        }
-        memFree(path);
-    }
-
-    if (return_) {
-        memFree(*file);
-        *file = lib_file;
-    } else
-        memFree(lib_file);
-    return return_;
-}
-#undef CHECK_CLIB
-
 void importClibCore(char *file, struct LinkValue *belong, FUNC_CORE){
     void *dl;
     Registered reg;

+ 18 - 3
vmcore/src/inter.c

@@ -1,12 +1,13 @@
 #include "__virtualmath.h"
 
-Inter *makeInter(char *out, char *error_, char *in, LinkValue *belong) {
+Inter *makeInter(char *out, char *error_, char *in, char *env, LinkValue *belong) {
     Inter *tmp = memCalloc(1, sizeof(Inter));
     tmp->base = NULL;
     tmp->link_base = NULL;
     tmp->hash_base = NULL;
     tmp->base_var = NULL;
     tmp->package = NULL;
+    tmp->data.env = memStrcpy(env);
 
     setBaseInterData(tmp);
     tmp->var_list = makeVarList(tmp, true, NULL);
@@ -158,6 +159,7 @@ void freeBaseInterData(struct Inter *inter){
         fclose(inter->data.inter_stderr);
     if (!inter->data.is_stdin)
         fclose(inter->data.inter_stdin);
+    memFree(inter->data.env);
 }
 
 void freeInter(Inter *inter, bool show_gc) {
@@ -229,8 +231,8 @@ void mergeInter(Inter *new, Inter *base){
     memFree(new);
 }
 
-Inter *deriveInter(LinkValue *belong, Inter *inter) {
-    Inter *import_inter = makeInter(NULL, NULL, NULL, belong);
+Inter *deriveInter(char *env, LinkValue *belong, Inter *inter) {
+    Inter *import_inter = makeInter(NULL, NULL, NULL, env, belong);
     import_inter->data.inter_stdout = inter->data.inter_stdout;
     import_inter->data.inter_stderr = inter->data.inter_stderr;
     import_inter->data.inter_stdin = inter->data.inter_stdin;
@@ -267,6 +269,19 @@ void freeClibInfoFromInter(Inter *inter) {
         PASS;
 }
 
+void changeInterEnv(char *env, bool split, Inter *inter) {
+    char *bak;
+    if (split) {
+        bak = strrchr(env, SEP_CH);
+        *bak = NUL;
+    }
+
+    memFree(inter->data.env);
+    inter->data.env = memStrcpy(env);
+    if (split)
+        *bak = SEP_CH;
+}
+
 #if DEBUG
 /* ***********************DEBUG 专用函数*********************************** */
 

+ 94 - 41
vmcore/src/runfile.c

@@ -1,4 +1,5 @@
 #include "__run.h"
+#define CHECK_CLIB(path, dl) ((dl = dlopen(path, RTLD_NOW)) != NULL) && (dlsym(dl, "registered") != NULL)
 
 bool importRunParser(ParserMessage *pm, fline line, char *file, Statement *run_st, FUNC_NT) {
     setResultCore(result);
@@ -13,7 +14,7 @@ bool importRunParser(ParserMessage *pm, fline line, char *file, Statement *run_s
     return CHECK_RESULT(result);
 }
 
-int isAbsolutePath(const char *path) {
+int isAbsolutePath(const char *path) {  // 检查路径模式
     switch (*path) {
         case ':':
             return 1;
@@ -26,83 +27,134 @@ int isAbsolutePath(const char *path) {
     }
 }
 
-static bool isExist(char **path, bool is_ab, char *file) {
-    char *backup = is_ab ? memStrcpy((*path) + 1) : memStrcpy(*path);
+static bool isExist(char **path, bool is_ab, char *file) {  // is_ab 参数参见 isAbsolutePath
+    char *backup = is_ab ? memStrcpy((*path) + 1) : memStrcpy(*path);  // 是否跳过第一个字符
     int status;
-    if ((status = checkFileReadble(backup)) != 3 || (status = checkFileReadble(backup = memStrcat(backup, ".vm", true, false))) != 3) {
-        memFree(*path);
+    if ((status = checkFileReadble(backup)) != 3) {
+        memFree(*path);  // 若文件存在则替换文件路径
         *path = backup;
-        if (status == 2) {
-            if (file == NULL)
-                return false;
-            if ((*path)[memStrlen(*path) - 1] != SEP_CH)
-                *path = memStrcat(*path, SEP, true, false);
-            *path = memStrcat(*path, file, true, false);
+        if (status == 2) {  // 如果是文件夹
+            if (file == NULL)  // file 表示路径后缀
+                return false;  // 无路径后缀则返回false
+            if ((*path)[memStrlen(*path) - 1] != SEP_CH)  // 检查path最后一个字符是否为分隔符
+                *path = memStrcat(*path, SEP, true, false);  // 拼接路径
+            *path = memStrcat(*path, file, true, false);  // 拼接路径
             return isExist(path, false, NULL);
         } else
             return true;
+    } else if (checkFileReadble(backup = memStrcat(backup, ".vm", true, false)) == 1) {
+        memFree(*path);  // 若文件存在则替换文件路径
+        *path = backup;
+        return true;
     }
     memFree(backup);
     return false;
 }
 
+#define GOTO_RETURN(num) do{return_num = num; goto return_;}while(0)
+#define CHECK_TYPE(file) do { \
+    void *dl; \
+    if (CHECK_CLIB(file, dl)) { \
+        GOTO_RETURN(2);  /* return 2 表示clib模式 */ \
+    } else \
+        GOTO_RETURN(1);  /* return 1 表示.vm模式 */  \
+    goto return_; \
+}while(0)
+
 int checkFileDir(char **file_dir, FUNC) {
+    int return_num;
+    char *arr_cwd = inter->data.env;
+    char *lib_file = strncmp(*file_dir, "lib", 3) == 0 ? memStrcpy(*file_dir) : memStrcat("libvm", *file_dir, false, false);  // 自动增加libvm前缀
+    if (strstr(lib_file, SHARED_MARK) == NULL)
+        lib_file = memStrcat(lib_file, SHARED_MARK, true, false);
+
     switch (isAbsolutePath(*file_dir)) {
-        case 1:
+        case 1:  // 表示输入的一定是绝对路径
             if (isExist(file_dir, true, "__init__.vm"))
-                return 1;
+                CHECK_TYPE(*file_dir);
             goto error_;
-        case 2:
+        case 2:  // 表示仅为clib
             goto clib;
-        case 3:
+        case 3:  // 表示一定是全局包
             goto path;
         default:
             break;
     }
 
     if (isExist(file_dir, false, "__init__.vm"))
-        return 1;
+        CHECK_TYPE(*file_dir);
+
     {
-        char arr_cwd[200];
-        char *p_cwd = NULL;
-        getcwd(arr_cwd, 200);
-        p_cwd = memStrcatIter(arr_cwd, false, SEP, *file_dir, NULL);  // 以NULL结尾表示结束
+        char *p_cwd = memStrcatIter(arr_cwd, false, SEP, *file_dir, NULL);  // 以NULL结尾表示结束
         if (isExist(&p_cwd, false, "__init__.vm")) {
             memFree(*file_dir);
-            *file_dir = p_cwd;
-            return 1;
+            *file_dir = p_cwd;  // p_cwd 不需要释放
+            GOTO_RETURN(1);
         }
         memFree(p_cwd);
     }
 
-    path: {
-    char *path = memStrcpy(getenv("VIRTUALMATHPATH"));
-    for (char *tmp = strtok(path, ";"), *new_dir; tmp != NULL; tmp = strtok(NULL, ";")) {
-        if (*(tmp + (memStrlen(tmp) - 1)) != SEP_CH)
-            new_dir = memStrcatIter(tmp, false, SEP, *file_dir, NULL);  // 以NULL结尾表示结束
-        else
-            new_dir = memStrcat(tmp, *file_dir, false, false);
-
-        if (isExist(&new_dir, false, "__init__.vm")) {
+    {
+        void *tmp_dl;
+        char *p_cwd = memStrcatIter(arr_cwd, false, SEP, lib_file, NULL);  // 以NULL结尾表示结束
+        if (CHECK_CLIB(p_cwd, tmp_dl)) {
             memFree(*file_dir);
-            *file_dir = new_dir;
-            return 1;
+            *file_dir = p_cwd;  // p_cwd 不需要释放
+            GOTO_RETURN(2);
         }
-        memFree(new_dir);
+        memFree(p_cwd);
+    }
 
+    path: {
+        char *path = memStrcpy(getenv("VIRTUALMATHPATH"));  // 因为 strtok 需要修改path, 所以path不能重复使用
+        for (char *tmp = strtok(path, ";"), *new_dir; tmp != NULL; tmp = strtok(NULL, ";")) {
+            if (*(tmp + (memStrlen(tmp) - 1)) != SEP_CH)
+                new_dir = memStrcatIter(tmp, false, SEP, *file_dir, NULL);  // 以NULL结尾表示结束
+            else
+                new_dir = memStrcat(tmp, *file_dir, false, false);
+            if (isExist(&new_dir, false, "__init__.vm")) {
+                memFree(*file_dir);
+                *file_dir = new_dir;
+                memFree(path);  // 释放path
+                GOTO_RETURN(1);
+            }
+            memFree(new_dir);
+        }
+        memFree(path);
     }
-    memFree(path);
-}
 
-    clib:
-    if (checkCLib(file_dir))  // 检查是否为 clib
-        return 2;
+    clib: {
+        void *tmp_dl;
+        char *path = memStrcpy(getenv("VIRTUALMATHPATH"));  // 因为 strtok 需要修改path, 所以path不能重复使用
+        for (char *tmp = strtok(path, ";"), *new_dir; tmp != NULL; tmp = strtok(NULL, ";")) {
+            if (*(tmp + (memStrlen(tmp) - 1)) != SEP_CH)
+                new_dir = memStrcatIter(tmp, false, SEP, lib_file, NULL);  // 以NULL结尾表示结束
+            else
+                new_dir = memStrcat(tmp, lib_file, false, false);
+            if (CHECK_CLIB(new_dir, tmp_dl)) {
+                dlclose(tmp_dl);
+                memFree(path);
+                memFree(*file_dir);
+                *file_dir = new_dir;
+                GOTO_RETURN(2);
+            }
+            memFree(new_dir);
+        }
+        memFree(path);
+    }
 
     error_:
+    memFree(lib_file);
     setResultErrorSt(E_ImportException, L"import/include file is not readable", true, st, CNEXT_NT);
-    return 0;
+    return 0;  // return 0 表示文件不存在
+
+    return_:
+    memFree(lib_file);
+    return return_num;
 }
 
+#undef CHECK_TYPE
+
 ResultType includeFile(FUNC) {
     Statement *new_st = NULL;
     ParserMessage *pm = NULL;
@@ -201,7 +253,8 @@ static bool getPackage(LinkValue **imp_value, char *md5_str, char *split, int st
     if (is_lock || (pg = checkPackage(inter->package, md5_str, split)) == NULL) {
         setResultCore(result);
         *is_new = true;
-        imp_inter = deriveInter(belong, inter);
+        imp_inter = deriveInter(inter->data.env, belong, inter);
+        changeInterEnv(*path, true, imp_inter);  // 设置运行环境
         pg = makeObject(inter, imp_inter->var_list, copyVarList(var_list, false, inter), true, NULL);
         if (!is_lock)
             inter->package = makePackage(pg, md5_str, split, inter->package);  // 只有当不是保护读入或私密读入的时才可以记录