summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Huwald <jh@sotun.de>2014-02-16 19:56:04 (GMT)
committerJan Huwald <jh@sotun.de>2014-02-16 19:56:04 (GMT)
commit7de7b1618c85d21d3f737d0981f8ae3784ac1036 (patch)
tree6a1cdfe882f7ff764a78c27ac4a18a9cf4865c0d
parent8f87168174e6c883260d613494082ffe791c767e (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.h2
-rw-r--r--src/mainwin.cc12
-rw-r--r--src/openscad.cc102
-rw-r--r--src/printutils.cc16
-rw-r--r--src/printutils.h11
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();
contact: Jan Huwald // Impressum