diff --git a/src/nasal_codegen.h b/src/nasal_codegen.h index 2eb44f3..ab742c9 100644 --- a/src/nasal_codegen.h +++ b/src/nasal_codegen.h @@ -60,7 +60,9 @@ private: "__pipe", "__fork", "__waitpid", "__chdir", "__environ", "__getcwd", "__getenv", // subprocess - "__subprocess_run" + "__subprocess_popen", + "__subprocess_pclose", + "__subprocess_read_stdout" }; // file mapper for file -> index diff --git a/src/natives/subprocess.cpp b/src/natives/subprocess.cpp index 0e999a3..16161bd 100644 --- a/src/natives/subprocess.cpp +++ b/src/natives/subprocess.cpp @@ -1,13 +1,62 @@ #include "natives/subprocess.h" +#include + namespace nasal { -var builtin_subprocess_run(context* ctx, gc* ngc) { - return nil; +const auto subprocess_object_name = "subprocess"; + +void subprocess_destructor(void* ptr) { + pclose(static_cast(ptr)); +} + +var builtin_subprocess_popen(context* ctx, gc* ngc) { + auto command = ctx->localr[1]; + if (!command.is_str()) { + return nas_err("subprocess::popen", "expect a string as the command"); + } + + auto fd = popen(command.str().c_str(), "r"); + if (fd == nullptr) { + return nas_err("subprocess::popen", "failed to create sub-process"); + } + + var ret = ngc->alloc(vm_type::vm_ghost); + ret.ghost().set(subprocess_object_name, subprocess_destructor, nullptr, fd); + return ret; +} + +var builtin_subprocess_pclose(context* ctx, gc* ngc) { + auto fd = ctx->localr[1]; + if (!fd.object_check(subprocess_object_name)) { + return nas_err("subprocess::pclose", "not a valid subprocess"); + } + auto res = pclose(static_cast(fd.ghost().pointer)); + fd.ghost().pointer = nullptr; + fd.ghost().clear(); + return var::num(res); +} + +var builtin_subprocess_read_stdout(context* ctx, gc* ngc) { + auto fd = ctx->localr[1]; + if (!fd.object_check(subprocess_object_name)) { + return nas_err("subprocess::pclose", "not a valid subprocess"); + } + char buffer[1025]; + auto res = ngc->alloc(vm_type::vm_str); + while(fgets( + buffer, + sizeof(buffer)-1, + static_cast(fd.ghost().pointer))!=nullptr) { + res.str() += buffer; + } + return res; } nasal_builtin_table subprocess_native[] = { - {"__subprocess_run", builtin_subprocess_run}, + {"__subprocess_popen", builtin_subprocess_popen}, + {"__subprocess_pclose", builtin_subprocess_pclose}, + {"__subprocess_read_stdout", builtin_subprocess_read_stdout}, {nullptr, nullptr} }; diff --git a/src/natives/subprocess.h b/src/natives/subprocess.h index f1a2680..23029a4 100644 --- a/src/natives/subprocess.h +++ b/src/natives/subprocess.h @@ -6,8 +6,11 @@ namespace nasal { -var builtin_subprocess_run(context*, gc*); +void subprocess_destructor(void*); +var builtin_subprocess_popen(context*, gc*); +var builtin_subprocess_pclose(context*, gc*); +var builtin_subprocess_read_stdout(context*, gc*); extern nasal_builtin_table subprocess_native[]; } \ No newline at end of file diff --git a/std/subprocess.nas b/std/subprocess.nas index b418896..e82cf8b 100644 --- a/std/subprocess.nas +++ b/std/subprocess.nas @@ -1,3 +1,11 @@ -var run = func() { - return __subprocess_run(); +var popen = func(cmd) { + return __subprocess_popen(cmd); +} + +var pclose = func(subproc) { + return __subprocess_pclose(subproc); +} + +var read = func(subproc) { + return __subprocess_read_stdout(subproc); } \ No newline at end of file diff --git a/test/watchdog.nas b/test/watchdog.nas index e0e2a9f..5c3c32b 100644 --- a/test/watchdog.nas +++ b/test/watchdog.nas @@ -3,62 +3,113 @@ use std.os; use std.io; use std.unix; +use std.subprocess; + +runtime.windows.set_utf8_output(); + var os_time = func() { - return "\e[33;1m["~os.time()~"]\e[0m "; + return "\e[33;1m[" ~ os.time() ~ "]\e[0m "; } + var err_hd = func() { return "\e[91;1m[error]\e[0m "; } + var info_hd = func() { return "\e[96;1m[info]\e[0m "; } + var modified_hd = func() { return "\e[92;1m[modified]\e[0m "; } + var usage = func() { - println(os_time(),info_hd(),"\e[1musage: nasal watchdog.nas [\"argv\"]\e[0m"); + println( + os_time(), + info_hd(), + "\e[1musage: nasal watchdog.nas [\"argv\"]\e[0m" + ); } -var argv=runtime.argv(); +var argv = runtime.argv(); if (size(argv)<1) { - println(os_time(),err_hd(),"\e[1mneed correct file path to watch\e[0m"); - usage(); - exit(-1); -} -var filename=argv[0]; -if (!io.exists(filename)) { - println(os_time(),err_hd(),"\e[1mfile <",filename,"> does not exist\e[0m"); + println( + os_time(), + err_hd(), + "\e[1mneed correct file path to watch\e[0m" + ); usage(); exit(-1); } -var args=[]; +var filename = argv[0]; +if (!io.exists(filename)) { + println( + os_time(), + err_hd(), + "\e[1mfile <", + filename, + "> does not exist\e[0m" + ); + usage(); + exit(-1); +} + +var args = []; if (size(argv)==2) { - println(os_time(),info_hd(),"\e[1mwith argument(s) ",argv[1],"\e[0m"); - args=split(" ",argv[1]); + println( + os_time(), + info_hd(), + "\e[1mwith argument(s) ", + argv[1], + "\e[0m" + ); + args = split(" ", argv[1]); } var modified_time = io.fstat(filename).st_mtime; -println(os_time(),info_hd(),"\e[1mwatching ",filename," ..\e[0m"); +println(os_time(), info_hd(), "\e[1mwatching ", filename, " ..\e[0m"); while(1) { unix.sleep(5); if (!io.exists(filename)) { - println(os_time(),err_hd(),"\e[1mfile <",filename,"> does not exist\e[0m"); + println( + os_time(), + err_hd(), + "\e[1mfile <", + filename, + "> does not exist\e[0m" + ); break; } + var latest_modified_time = io.fstat(filename).st_mtime; if (latest_modified_time!=modified_time) { - modified_time=latest_modified_time; - println(os_time(),modified_hd(),"\e[1m",filename,"\e[0m"); - var cmd=(os.platform()=="windows"?"":"./")~"nasal "~filename; - foreach(var i;args) - cmd~=" "~i; - println(os_time(),info_hd(),"\e[1mexecuting command \"",cmd,"\"\e[0m"); - var ret=system(cmd); - if (ret!=0) { - println(os_time(),err_hd(),"\e[1mprocess returned ",ret,"\e[0m"); - } else { - println(os_time(),info_hd(),"\e[1mprocess returned ",ret,"\e[0m"); + modified_time = latest_modified_time; + println(os_time(), modified_hd(), "\e[1m", filename, "\e[0m"); + + var cmd = (os.platform()=="windows"?"":"./") ~ "nasal " ~ filename; + foreach(var i; args) { + cmd ~= " " ~ i; } + cmd ~= " 2>&1"; + println( + os_time(), + info_hd(), + "\e[1mexecuting command \"", + cmd, + "\"\e[0m" + ); + + var subproc = subprocess.popen(cmd); + var stdout_info = subprocess.read(subproc); + var ret = subprocess.pclose(subproc); + if (size(stdout_info)>0) { + println(stdout_info); + } + println( + os_time(), + ret!=0? err_hd():info_hd(), + "\e[1mprocess returned " ~ ret ~ "\e[0m" + ); } } \ No newline at end of file