diff options
author | Jan Huwald <jh@sotun.de> | 2014-02-16 19:56:04 (GMT) |
---|---|---|
committer | Jan Huwald <jh@sotun.de> | 2014-02-16 19:56:04 (GMT) |
commit | 7de7b1618c85d21d3f737d0981f8ae3784ac1036 (patch) | |
tree | 6a1cdfe882f7ff764a78c27ac4a18a9cf4865c0d | |
parent | 8f87168174e6c883260d613494082ffe791c767e (diff) |
allow writing to standard output from command line, update output handler to lambda
- cmdline can output to a file or cout
- output handler uses lambda instead of function pointer
- this allows removing Echostream with a one-liner
-rw-r--r-- | src/MainWindow.h | 2 | ||||
-rw-r--r-- | src/mainwin.cc | 12 | ||||
-rw-r--r-- | src/openscad.cc | 102 | ||||
-rw-r--r-- | src/printutils.cc | 16 | ||||
-rw-r--r-- | src/printutils.h | 11 |
5 files changed, 62 insertions, 81 deletions
diff --git a/src/MainWindow.h b/src/MainWindow.h index bc98e21..b6b8bfe 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -85,7 +85,7 @@ private: bool maybeSave(); bool checkEditorModified(); QString dumpCSGTree(AbstractNode *root); - static void consoleOutput(const std::string &msg, void *userdata); + void consoleOutput(const std::string &msg); void loadViewSettings(); void loadDesignSettings(); void saveBackup(); diff --git a/src/mainwin.cc b/src/mainwin.cc index 90db4c8..645d313 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -2115,23 +2115,21 @@ void MainWindow::quit() #endif } -void MainWindow::consoleOutput(const std::string &msg, void *userdata) +void MainWindow::consoleOutput(const std::string &msg) { // Invoke the append function in the main thread in case the output - // originates in a worker thread. - MainWindow *thisp = static_cast<MainWindow*>(userdata); - QMetaObject::invokeMethod(thisp->console, "append", Qt::QueuedConnection, - Q_ARG(QString, QString::fromLocal8Bit(msg.c_str()))); + // originates in a worker thread. + QMetaObject::invokeMethod(console, "append", Qt::QueuedConnection, Q_ARG(QString, QString::fromLocal8Bit(msg.c_str()))); } void MainWindow::setCurrentOutput() { - set_output_handler(&MainWindow::consoleOutput, this); + set_output_handler([&](std::string msg) { this->consoleOutput(msg); }); } void MainWindow::clearCurrentOutput() { - set_output_handler(NULL, NULL); + set_output_handler(default_outputhandler); } void MainWindow::openCSGSettingsChanged() diff --git a/src/openscad.cc b/src/openscad.cc index 4d4943b..b815ead 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -95,21 +95,6 @@ using boost::optional; string commandline_commands; string currentdir; -class Echostream : public std::ofstream -{ -public: - Echostream( const char * filename ) : std::ofstream( filename ) { - set_output_handler( &Echostream::output, this ); - } - static void output( const string &msg, void *userdata ) { - Echostream *thisp = static_cast<Echostream*>(userdata); - *thisp << msg << "\n"; - } - ~Echostream() { - this->close(); - } -}; - static void help(const char *progname, vector<po::options_description> options) { std::ostringstream ss; @@ -231,7 +216,7 @@ int cmdline(optional<string> action, optional<string> output_file, fs::path fparent; FileModule *root_module; AbstractNode *root_node; - std::ofstream fstream; + std::ostream *output_stream; // list of actions to be performed, indexed by filename suffix map<string, function<int(void)>> actions{ @@ -239,29 +224,29 @@ int cmdline(optional<string> action, optional<string> output_file, {"stl", [&] { root_N = cgalevaluator->evaluateCGALMesh(*tree.root()); if (!assert_root_3d_simple(root_N)) return 1; - export_stl(&root_N, fstream); + export_stl(&root_N, *output_stream); return 0; }}, {"off", [&] { root_N = cgalevaluator->evaluateCGALMesh(*tree.root()); if (!assert_root_3d_simple(root_N)) return 1; - export_off(&root_N, fstream); + export_off(&root_N, *output_stream); return 0; }}, {"dxf", [&] { root_N = cgalevaluator->evaluateCGALMesh(*tree.root()); if (!assert_root_2d(root_N)) return 1; - export_dxf(&root_N, fstream); + export_dxf(&root_N, *output_stream); return 0; }}, {"png", [&] { switch (renderer) { case Render::CGAL: root_N = cgalevaluator->evaluateCGALMesh(*tree.root()); - export_png_with_cgal(&root_N, camera, fstream); + export_png_with_cgal(&root_N, camera, *output_stream); break; case Render::THROWNTOGETHER: - export_png_with_throwntogether(tree, camera, fstream); + export_png_with_throwntogether(tree, camera, *output_stream); break; case Render::OPENCSG: - export_png_with_opencsg(tree, camera, fstream); + export_png_with_opencsg(tree, camera, *output_stream); break; } return 0; }}, @@ -277,20 +262,20 @@ int cmdline(optional<string> action, optional<string> output_file, shared_ptr<CSGTerm> root_raw_term = csgRenderer.evaluateCSGTerm(*root_node, highlight_terms, background_terms); if (!root_raw_term) { - fstream << "No top-level CSG object\n"; + *output_stream << "No top-level CSG object\n"; } else { - fstream << root_raw_term->dump() << "\n"; + *output_stream << root_raw_term->dump() << "\n"; } return 0; }}, #endif {"csg", [&] { fs::current_path(fparent); // Force exported filenames to be relative to document path - fstream << tree.getString(*root_node) << "\n"; + *output_stream << tree.getString(*root_node) << "\n"; return 0; }}, {"ast", [&] { fs::current_path(fparent); // Force exported filenames to be relative to document path - fstream << root_module->dump("", "") << "\n"; + *output_stream << root_module->dump("", "") << "\n"; return 0; }} }; @@ -310,11 +295,25 @@ int cmdline(optional<string> action, optional<string> output_file, if (!output_file) output_file = filename + "." + *action; - // Open the output file early if it is an echo stream - unique_ptr<Echostream> echostream; - string temp_output_file = *output_file + "~"; + // Open output stream. If it refers to a file, use a temporary + // file first. Filename "-" refers to standard output + std::ofstream output_file_stream; + optional<string> temp_output_file; + if (*output_file == "-") { + output_stream = &(std::cout); + } else { + temp_output_file = *output_file + "~"; + output_file_stream.open(*temp_output_file, (*action == "png") ? std::ios::binary : std::ios::out); + if (!output_file_stream.is_open()) { + PRINTB("Can't open file \"%s\" for export", *temp_output_file); + return 1; + } + output_stream = &output_file_stream; + } + + // Open an echo stream early if (*action == "echo") - echostream.reset(new Echostream(temp_output_file.c_str())); + set_output_handler([&](string msg) { *output_stream << msg << "\n"; }); // Init parser, top_con const string application_path = boosty::stringy(boosty::absolute(boost::filesystem::path(application_name).parent_path())); @@ -367,14 +366,12 @@ int cmdline(optional<string> action, optional<string> output_file, AbstractNode::resetIndexCounter(); absolute_root_node = root_module->instantiate(&top_ctx, &root_inst, NULL); - // Do we have an explicit root node (! modifier)? if (!(root_node = find_root_tag(absolute_root_node))) root_node = absolute_root_node; tree.setRoot(root_node); - // Write dependencies if required if (deps_output_file) { if (!set<string>{"stl", "off", "dxf", "png"}.count(*action)) { @@ -388,37 +385,28 @@ int cmdline(optional<string> action, optional<string> output_file, } } - // Open output file late to catch errors before writing anything to disk - if (*action != "echo") { - fstream.open(temp_output_file, (*action == "png") ? std::ios::binary : std::ios::out); - if (!fstream.is_open()) { - PRINTB("Can't open file \"%s\" for export", temp_output_file); - return 1; - } - } - // Call the intended action auto ret = actions[*action](); // Commit the file if succesfull, delete it otherwise. - if (!ret) { - // Success - if (rename(temp_output_file.c_str(), output_file->c_str())) { - PRINTB("Can't rename \"%s\" to \"%s\"", temp_output_file % *output_file); - return 1; - } - }else{ - // Failure - if (remove(temp_output_file.c_str())) { - PRINTB("Can't remove \"%s\"", temp_output_file); - return 1; + if (temp_output_file) { + if (!ret) { + // Success + if (rename(temp_output_file->c_str(), output_file->c_str())) { + PRINTB("Can't rename \"%s\" to \"%s\"", *temp_output_file % *output_file); + return 1; + } + }else{ + // Failure + if (remove(temp_output_file->c_str())) { + PRINTB("Can't remove \"%s\"", *temp_output_file); + return 1; + } } - fstream.close(); } // Clean up delete root_node; - fstream.close(); return ret; } @@ -548,7 +536,7 @@ int gui(const vector<string> &inputFiles, const fs::path &original_path, int arg int main(int argc, char **argv) { #ifdef Q_OS_MAC - set_output_handler(CocoaUtils::nslog, NULL); + set_output_handler(CocoaUtils::nslog); #endif #ifdef ENABLE_CGAL // Causes CGAL errors to abort directly instead of throwing exceptions @@ -561,7 +549,7 @@ int main(int argc, char **argv) optional<string> output_file, deps_output_file; - po::options_description opt_actions("Actions (pick one, or none to start the gui)"); + po::options_description opt_actions("Actions (pick none to start the gui)"); opt_actions.add_options() ("o,o", po::value<string>(), "output file; \"-\" writes to standart output; file extensions determines action unless specified by -a:\n" " .stl .off .dxf .csg - export geometry\n" @@ -673,7 +661,7 @@ int main(int argc, char **argv) NodeDumper dumper(nodecache); int rc; - if (output_file) { // cmd-line mode + if (output_file || optstr("action")) { // cmd-line mode if (!inputFiles.size()) help(); rc = cmdline(optstr("action"), output_file, optstr("d"), inputFiles[0], camera, renderer, original_path, argv[0]); } else if (QtUseGUI()) { diff --git a/src/printutils.cc b/src/printutils.cc index 37092fa..a8192ca 100644 --- a/src/printutils.cc +++ b/src/printutils.cc @@ -3,13 +3,13 @@ #include <stdio.h> std::list<std::string> print_messages_stack; -OutputHandlerFunc *outputhandler = NULL; -void *outputhandler_data = NULL; +std::function<void(std::string)> default_outputhandler = [](std::string msg) { + fprintf(stderr, "%s\n", msg.c_str()); +}; +std::function<void(std::string)> outputhandler = default_outputhandler; -void set_output_handler(OutputHandlerFunc *newhandler, void *userdata) -{ +void set_output_handler(std::function<void(std::string)> newhandler) { outputhandler = newhandler; - outputhandler_data = userdata; } void print_messages_push() @@ -44,11 +44,7 @@ void PRINT(const std::string &msg) void PRINT_NOCACHE(const std::string &msg) { if (msg.empty()) return; - if (!outputhandler) { - fprintf(stderr, "%s\n", msg.c_str()); - } else { - outputhandler(msg, outputhandler_data); - } + outputhandler(msg); } std::string two_digit_exp_format( std::string doublestr ) diff --git a/src/printutils.h b/src/printutils.h index 18aadde..723bf1e 100644 --- a/src/printutils.h +++ b/src/printutils.h @@ -1,16 +1,15 @@ #ifndef PRINTUTILS_H_ #define PRINTUTILS_H_ -#include <string> -#include <list> +#include <functional> #include <iostream> +#include <list> +#include <string> #include <boost/format.hpp> -typedef void (OutputHandlerFunc)(const std::string &msg, void *userdata); -extern OutputHandlerFunc *outputhandler; -extern void *outputhandler_data; +extern std::function<void(std::string)> outputhandler, default_outputhandler; -void set_output_handler(OutputHandlerFunc *newhandler, void *userdata); +void set_output_handler(std::function<void(std::string)>); extern std::list<std::string> print_messages_stack; void print_messages_push(); |