diff --git a/include/device.hpp b/include/device.hpp index 212802b..c1c0231 100644 --- a/include/device.hpp +++ b/include/device.hpp @@ -8,8 +8,6 @@ #include "command.hpp" #include -void sh(std::string const& string); - class Device { public: @@ -34,7 +32,6 @@ public: std::vector connectCommands; std::vector disconnectCommands; - std::thread thread; pid_t thread_pid; private: static void loop(Device* dev); @@ -42,4 +39,6 @@ private: extern std::vector device_list; +void clean_devices(); + #endif //DEVICE_HPP diff --git a/include/system.hpp b/include/system.hpp index 88319b6..a68fe70 100644 --- a/include/system.hpp +++ b/include/system.hpp @@ -5,10 +5,16 @@ #define LIST_COMMAND "aseqdump -l | tail -n +2 | cut -c10-42 | tr -s ' '" #define LIST_EXTENDED_COMMAND "aseqdump -l | tail -n +2 | cut -c-42" +#include + extern int announce_thread_pid; +void kill_all(); + void device_check(); void announce_loop(); +void filetime_loop(std::string filepath); + #endif //SYSTEM_HPP diff --git a/src/device.cpp b/src/device.cpp index 9e1405b..3cbc0f2 100644 --- a/src/device.cpp +++ b/src/device.cpp @@ -5,6 +5,7 @@ #include #include #include + #include #include "log.hpp" @@ -40,11 +41,6 @@ static bool _isNum(char a) return (a>='0' && a<='9'); } -void sh(std::string const& string) -{ - system(string.c_str()); -} - Device::Device() { busy=false; @@ -63,8 +59,7 @@ bool Device::start_loop() if(this->busy) return false; this->busy = true; - this->thread = std::thread(Device::loop, this); - this->thread.detach(); + std::thread(Device::loop, this).detach(); return true; } @@ -295,7 +290,7 @@ void Device::run_signal(char* buff) { std::string command="code=" + strval + ";"; command += dequote(it.shell); - std::thread(sh, command).detach(); + std::thread(ztd::sh, command, true).detach(); } } else @@ -372,7 +367,7 @@ void Device::run_signal(char* buff) + ";channel=" + std::to_string(channel) + ";velocity=" + std::to_string(value) + ";"; command += dequote(it.shell); - std::thread(sh, command).detach(); + std::thread(ztd::sh, command, true).detach(); } } } @@ -399,7 +394,7 @@ void Device::run_signal(char* buff) else command += std::to_string((long int) result); command += ";" + dequote(it.shell); - std::thread(sh, command).detach(); + std::thread(ztd::sh, command, true).detach(); } } } @@ -425,7 +420,7 @@ void Device::run_signal(char* buff) else command += std::to_string((long int) result); command += ";" + dequote(it.shell); - std::thread(sh, command).detach(); + std::thread(ztd::sh, command, true).detach(); } } } // if type @@ -447,7 +442,7 @@ void Device::loop(Device* dev) for( auto it : dev->connectCommands ) { - std::thread(sh, dequote(it.shell)).detach(); + std::thread(ztd::sh, dequote(it.shell), true).detach(); } while (getline(&buff, &buff_size, stream) > 0) @@ -457,7 +452,7 @@ void Device::loop(Device* dev) for( auto it : dev->disconnectCommands ) { - std::thread(sh, dequote(it.shell)).detach(); + std::thread(ztd::sh, dequote(it.shell), true).detach(); } log("Device '" + dev->name + "' disconnected\n"); @@ -466,3 +461,12 @@ void Device::loop(Device* dev) dev->thread_pid=-1; free(buff); } + +void clean_devices() +{ + for(auto it : device_list) + { + delete it; + } + device_list.clear(); +} diff --git a/src/main.cpp b/src/main.cpp index 05408de..0c7dc3c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,7 +14,7 @@ #include #include -#define VERSION_STRING "v1.2" +#define VERSION_STRING "v1.3" ztd::option_set options; @@ -59,8 +59,7 @@ void cleanup() void stop(int ret) { - if(announce_thread_pid>0) - kill(announce_thread_pid, SIGINT); + kill_all(); exit(ret); } @@ -69,12 +68,59 @@ void inthandler(int dummy) stop(0); } +void load_filedat(ztd::filedat& file, bool from_stdin, std::string const& path) +{ + if(from_stdin) + { + log("Loading map from stdin\n"); + file.import_stdin(); + } + else + { + file.setFilePath(path); + log("Loading map file '" + path + "'\n"); + if(options.find("zfd")->activated) + { + file.import_file(); + } + else if(options.find("mim")->activated) + { + file.data() = mimtochk(file_strimport(path)); + } + else + { + std::string filestr=file_strimport(path); + if(is_mim(filestr)) + { + file.data() = mimtochk(filestr); + } + else + { + file.import_file(); + } + } + } +} + +void load_commands(ztd::chunkdat const& data) +{ + clean_devices(); + for(int i=0 ; iimport_chunk(data[i]); + device_list.push_back(newDevice); + log("Loaded "+std::to_string(newDevice->nb_command)+" commands for device '"+newDevice->name+"'\n"); + } +} + int main(int argc, char* argv[]) { signal(SIGINT, inthandler); signal(SIGCHLD, SIG_IGN); //not expecting returns from child processes bool piped=false; + bool autoreload=true; if (!isatty(fileno(stdin))) piped = true; @@ -98,6 +144,7 @@ int main(int argc, char* argv[]) options.add(ztd::option('z',"zfd", false, "Read file in zfd format")); options.add(ztd::option('o',"output", true, "Output the resulting zfd map to file. - for stdout", "file")); options.add(ztd::option("aligner", true, "String to use for aligning output map format. Default \\t", "string")); + options.add(ztd::option("no-reload", false, "Disable auto reloading when file changes are detected")); options.add(ztd::option("\rIf no file format is specified, the program will try to guess the format")); // options.add(ztd::option('i',"interactive", false, "Start in interactive mode")); @@ -146,12 +193,12 @@ int main(int argc, char* argv[]) } if( options.find('L')->activated ) { - sh("aseqdump -l"); + ztd::sh("aseqdump -l", true); stop(0); } if( options.find('l')->activated ) { - sh(LIST_COMMAND); + ztd::sh(LIST_COMMAND, true); stop(0); } @@ -168,6 +215,10 @@ int main(int argc, char* argv[]) } //behavioral options + if( options.find("no-reload")->activated ) + { + autoreload=false; + } if( options.find("no-log")->activated ) { log_on=false; @@ -181,6 +232,7 @@ int main(int argc, char* argv[]) //no argument: display help ztd::filedat file; bool no_arg=false; + std::string filepath; if (arg.size() <= 0 || arg[0] == "") { no_arg=true; @@ -192,42 +244,16 @@ int main(int argc, char* argv[]) } else { - file.setFilePath(arg[0]); + filepath=arg[0]; } //main processing try { - if(no_arg) - { - log("Loading map from stdin\n"); - file.import_stdin(); - } - else - { - log("Loading map file '" + arg[0] + "'\n"); - if(options.find("zfd")->activated) - { - file.import_file(); - } - else if(options.find("mim")->activated) - { - file.data() = mimtochk(file_strimport(arg[0])); - } - else - { - std::string filestr=file_strimport(arg[0]); - if(is_mim(filestr)) - { - file.data() = mimtochk(filestr); - } - else - { - file.import_file(); - } - } - } + //load + load_filedat(file, no_arg, filepath); + //output if(options.find('o')->activated) { if(options.find('o')->argument == "-") { @@ -240,17 +266,39 @@ int main(int argc, char* argv[]) return 0; } //create commands - for(int i=0 ; iimport_chunk(file[i]); - device_list.push_back(newDevice); - log("Loaded "+std::to_string(newDevice->nb_command)+" commands for device '"+newDevice->name+"'\n"); - } + load_commands(file.data()); + + autoreload = autoreload && !no_arg; //main loop log("Starting scan for devices\n"); + if(autoreload) + std::thread(filetime_loop, filepath).detach(); announce_loop(); + ztd::chunkdat bak_data = file.data(); + while(autoreload) + { + log("Reloading file\n"); + try + { + load_filedat(file, false, filepath); + load_commands(file.data()); + bak_data = file.data(); + } + catch (ztd::format_error& e) + { + ztd::printFormatException(e); + log("Reloading old config\n"); + load_commands(bak_data); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << std::endl; + log("Reloading old config\n"); + load_commands(bak_data); + } + announce_loop(); + } } catch (ztd::format_error& e) { diff --git a/src/system.cpp b/src/system.cpp index 447e350..47dd4f3 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -3,6 +3,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -13,6 +17,17 @@ int announce_thread_pid = 0; +void kill_all() +{ + if(announce_thread_pid>0) + kill(announce_thread_pid, SIGINT); + for(auto it : device_list) + { + if(it->thread_pid>0) + kill(it->thread_pid, SIGINT); + } +} + void device_check() { char* buff = NULL; @@ -86,3 +101,20 @@ void announce_loop() if(buff != NULL) free(buff); } + +void filetime_loop(std::string filepath) +{ + struct stat attrib; + stat(filepath.c_str(), &attrib); + time_t last_time=attrib.st_ctime; + while(true) + { + stat(filepath.c_str(), &attrib); + if(attrib.st_ctime > last_time) + { + kill_all(); + last_time = attrib.st_ctime; + } + sleep(1); + } +}