Przeglądaj źródła

feat: Linux支持aFunlang支持捕获中断

SongZihuan 3 lat temu
rodzic
commit
88a3d61a3d
7 zmienionych plików z 42 dodań i 22 usunięć
  1. 2 0
      include/tool/stdio_.h
  2. 3 2
      src/core/code.c
  3. 3 3
      src/core/parser.c
  4. 14 4
      src/main.c
  5. 1 1
      src/runtime/aFunlang.c
  6. 1 2
      src/tool/log.c
  7. 18 10
      src/tool/stdio_.c

+ 2 - 0
include/tool/stdio_.h

@@ -5,6 +5,8 @@
 AFUN_TOOL_EXPORT int fgets_stdin(char **dest, int len);
 AFUN_TOOL_EXPORT bool checkStdin(void);
 
+#define CLEAR_FERROR(file) (ferror(file) && (clearerr(file), ferror(file)))  /* 出现错误后尝试修复, 并再次检查 */
+
 #ifdef aFunWIN32_NO_CYGWIN
 AFUN_TOOL_EXPORT int fgetchar_stdin(void);
 AFUN_TOOL_EXPORT int fungec_stdin(int ch);

+ 3 - 2
src/core/code.c

@@ -278,7 +278,8 @@ bool writeAllCode(af_Code *bt, FILE *file) {
     for (NULL; bt != NULL; bt = bt->next) {
         if (!writeCode(bt, file))
             goto RETURN_FALSE;
-        if (ferror(stdin))
+
+        if (CLEAR_FERROR(stdin))
             goto RETURN_FALSE;
 
         Done(byteWriteUint_8(file, (bt->next == NULL)));  // 记录是否为最后一位
@@ -331,7 +332,7 @@ bool readAllCode(af_Code **bt, FilePath path, FILE *file) {
     for (NULL; true;bt = &((*bt)->next)) {
         if(!readCode(bt, file))
             goto RETURN_FALSE;
-        if (ferror(stdin))
+        if (CLEAR_FERROR(stdin))
             goto RETURN_FALSE;
 
         uint8_t last;

+ 3 - 3
src/core/parser.c

@@ -118,7 +118,7 @@ static size_t readFuncFile(struct readerDataFile *data, char *dest, size_t len,
     }
 
     size_t len_r =  fread(dest, sizeof(char), len, data->file);
-    if (ferror(data->file) || feof(data->file))  // ferror在feof前执行
+    if (CLEAR_FERROR(data->file) || feof(data->file))  // ferror在feof前执行
         *read_end = true;
     return len_r;
 }
@@ -207,8 +207,8 @@ static void destructStdin(struct readerDataStdin *data) {
 }
 
 af_Parser *makeParserByStdin(ParserStdinInterruptFunc *interrupt){
-    if (ferror(stdin))
-        clearerr(stdin);
+    if (CLEAR_FERROR(stdin))
+        return NULL;
 
     DLC_SYMBOL(readerFunc) read_func = MAKE_SYMBOL(readFuncStdin, readerFunc);
     DLC_SYMBOL(destructReaderFunc) destruct = MAKE_SYMBOL(destructStdin, destructReaderFunc);

+ 14 - 4
src/main.c

@@ -180,9 +180,14 @@ static int mainRun(ff_FFlags *ff) {
         /* 进入命令行模式 */
         env = creatAFunEnvironment(0, NULL);
         printWelcomeInfo();
-        do
+        do {
+            if (CLEAR_FERROR(stdin) || feof(stdin)) {
+                writeErrorLog(aFunlangLogger, "stdin error/eof");
+                exit_code = -1;
+                break;
+            }
             exit_code = runCodeFromStdin("stdin", stdin_interrupt, env);
-        while (isCoreExit(env) != 1);
+        } while (isCoreExit(env) != 1);  // exit_code == -1 表示stdin出现错误
     } else {
         env = creatAFunEnvironment(argc - 1, argv + 1);
         exit_code = runCodeFromFile(argv[0], true, 0, env);
@@ -278,9 +283,14 @@ static int mainCL(ff_FFlags *ff) {
 
     if (command_line && isCoreExit(env) != 1) {
         printWelcomeInfo();
-        do
+        do {
+            if (CLEAR_FERROR(stdin) || feof(stdin)) {
+                writeErrorLog(aFunlangLogger, "stdin error/eof");
+                exit_code = -1;
+                break;
+            }
             exit_code = runCodeFromStdin("stdin", stdin_interrupt, env);
-        while (isCoreExit(env) != 1);
+        } while (isCoreExit(env) != 1);
     }
 
     if (exit_code != 0)

+ 1 - 1
src/runtime/aFunlang.c

@@ -141,7 +141,7 @@ int runCodeFromFileSource(FilePath file, bool save_afb, FilePath save_path, int
  * 目标: 运行stdin的程序 (源码形式)
  */
 int runCodeFromStdin(char *name, ParserStdinInterruptFunc *interrupt, af_Environment *env){
-    if (env == NULL || ferror(stdin) || feof(stdin) || !aFunInit_mark)  // ferror在feof前执行
+    if (env == NULL || CLEAR_FERROR(stdin) || feof(stdin) || !aFunInit_mark)  // ferror在feof前执行
         return -1;
 
     if (name == NULL)

+ 1 - 2
src/tool/log.c

@@ -160,8 +160,7 @@ static int writeLog_(Logger *logger, bool pc, LogLevel level, char *file, int li
         return 2;
     if (!log_factory.init || log_factory.log == NULL)
         return 1;
-    if (ferror(log_factory.log))
-        clearerr(log_factory.log);
+    CLEAR_FERROR(log_factory.log);
 
     // 输出 head 信息
     time_t t = 0;

+ 18 - 10
src/tool/stdio_.c

@@ -159,25 +159,33 @@ int fgets_stdin(char **dest, int len) {
  * 目标: 检查stdin缓冲区是否有内容
  * 有内容则返回true
  * 无内容则返回false
+ *
+ * 参考自: https://gist.github.com/SuperH-0630/a4190b89d21c349a8d6882ca71453ae6
  */
-bool checkStdin(void) {
+bool checkStdin(void){
+    bool re = false;
+
     struct termios oldt, newt;
-    int ch;
-    int oldf;
     tcgetattr(STDIN_FILENO, &oldt);
     newt = oldt;
     newt.c_lflag &= ~(ICANON | ECHO);
     tcsetattr(STDIN_FILENO, TCSANOW, &newt);
-    oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
+
+    int oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
     fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
-    ch = getchar();
-    tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
-    fcntl(STDIN_FILENO, F_SETFL, oldf);
-    if(ch != EOF) {
+
+    int ch = fgetc(stdin);
+    CLEAR_FERROR(stdin);
+
+    if (ch != EOF) {
         ungetc(ch, stdin);
-        return 1;
+        re = true;
     }
-    return 0;
+
+    fcntl(STDIN_FILENO, F_SETFL, oldf);
+    tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
+
+    return re;
 }
 
 #endif