Clean up code

Use tabs for indenting to make someone happy...
This commit is contained in:
johan 2013-08-13 20:10:19 +02:00
parent 463e7626b9
commit a04af1242c
6 changed files with 297 additions and 270 deletions

View File

@ -12,23 +12,23 @@ LINK_DIRECTORIES(${LINK_DIRECTORIES} ${CMAKE_FIND_ROOT_PATH}/lib/arm-linux-gnuea
include_directories(${QT_INCLUDES}) include_directories(${QT_INCLUDES})
set(hyperion-remote_HEADERS set(hyperion-remote_HEADERS
CustomParameter.h CustomParameter.h
Connection.h Connection.h
ColorTransformValues.h) ColorTransformValues.h)
set(hyperion-remote_SOURCES set(hyperion-remote_SOURCES
hyperion-remote.cpp hyperion-remote.cpp
Connection.cpp) Connection.cpp)
add_executable(hyperion-remote add_executable(hyperion-remote
${hyperion-remote_HEADERS} ${hyperion-remote_HEADERS}
${hyperion-remote_SOURCES}) ${hyperion-remote_SOURCES})
qt4_use_modules(hyperion-remote qt4_use_modules(hyperion-remote
Core Core
Gui Gui
Network) Network)
target_link_libraries(hyperion-remote target_link_libraries(hyperion-remote
hyperion-utils hyperion-utils
getoptPlusPlus) getoptPlusPlus)

View File

@ -1,8 +1,9 @@
#pragma once #pragma once
/// Simple structure to contain the values of a color transformation
struct ColorTransformValues struct ColorTransformValues
{ {
double valueRed; double valueRed;
double valueGreen; double valueGreen;
double valueBlue; double valueBlue;
}; };

View File

@ -1,113 +1,116 @@
// stl includes
#include <stdexcept> #include <stdexcept>
// hyperion-remote includes
#include "Connection.h" #include "Connection.h"
Connection::Connection(const std::string & a, bool printJson) : Connection::Connection(const std::string & a, bool printJson) :
_printJson(printJson), _printJson(printJson),
_socket() _socket()
{ {
QString address(a.c_str()); QString address(a.c_str());
QStringList parts = address.split(":"); QStringList parts = address.split(":");
if (parts.size() != 2) if (parts.size() != 2)
{ {
throw std::runtime_error(QString("Wrong address: unable to parse address (%1)").arg(address).toStdString()); throw std::runtime_error(QString("Wrong address: unable to parse address (%1)").arg(address).toStdString());
} }
bool ok; bool ok;
uint16_t port = parts[1].toUShort(&ok); uint16_t port = parts[1].toUShort(&ok);
if (!ok) if (!ok)
{ {
throw std::runtime_error(QString("Wrong address: Unable to parse the port number (%1)").arg(parts[1]).toStdString()); throw std::runtime_error(QString("Wrong address: Unable to parse the port number (%1)").arg(parts[1]).toStdString());
} }
_socket.connectToHost(parts[0], port); _socket.connectToHost(parts[0], port);
if (!_socket.waitForConnected()) if (!_socket.waitForConnected())
{ {
throw std::runtime_error("Unable to connect to host"); throw std::runtime_error("Unable to connect to host");
} }
} }
Connection::~Connection() Connection::~Connection()
{ {
_socket.close(); _socket.close();
} }
bool Connection::setColor(QColor color, int priority, int duration) bool Connection::setColor(QColor color, int priority, int duration)
{ {
std::cout << "Set color to " << color.red() << " " << color.green() << " " << color.blue() << std::endl; std::cout << "Set color to " << color.red() << " " << color.green() << " " << color.blue() << std::endl;
sendMessage("Set color message"); sendMessage("Set color message");
return false; return false;
} }
bool Connection::setImage(QImage image, int priority, int duration) bool Connection::setImage(QImage image, int priority, int duration)
{ {
std::cout << "Set image has size: " << image.width() << "x" << image.height() << std::endl; std::cout << "Set image has size: " << image.width() << "x" << image.height() << std::endl;
return false; return false;
} }
bool Connection::listPriorities() bool Connection::listPriorities()
{ {
std::cout << "List priority channels" << std::endl; std::cout << "List priority channels" << std::endl;
return false; return false;
} }
bool Connection::clear(int priority) bool Connection::clear(int priority)
{ {
std::cout << "Clear priority channel " << priority << std::endl; std::cout << "Clear priority channel " << priority << std::endl;
return false; return false;
} }
bool Connection::clearAll() bool Connection::clearAll()
{ {
std::cout << "Clear all priority channels" << std::endl; std::cout << "Clear all priority channels" << std::endl;
return false; return false;
} }
bool Connection::setTransform(ColorTransformValues *threshold, ColorTransformValues *gamma, ColorTransformValues *blacklevel, ColorTransformValues *whitelevel) bool Connection::setTransform(ColorTransformValues *threshold, ColorTransformValues *gamma, ColorTransformValues *blacklevel, ColorTransformValues *whitelevel)
{ {
std::cout << "Set color transforms" << std::endl; std::cout << "Set color transforms" << std::endl;
return false; return false;
} }
bool Connection::sendMessage(const Json::Value & message) Json::Value Connection::sendMessage(const Json::Value & message)
{ {
// rpint if requested // print command if requested
if (_printJson) if (_printJson)
{ {
std::cout << "Command: " << message << std::endl; std::cout << "Command: " << message << std::endl;
} }
// serialize message // serialize message
Json::FastWriter jsonWriter; Json::FastWriter jsonWriter;
std::string serializedMessage = jsonWriter.write(message); std::string serializedMessage = jsonWriter.write(message);
// write message // write message
_socket.write(serializedMessage.c_str()); _socket.write(serializedMessage.c_str());
if (!_socket.waitForBytesWritten()) if (!_socket.waitForBytesWritten())
{ {
throw std::runtime_error("Error while writing data to host"); throw std::runtime_error("Error while writing data to host");
} }
// receive reply // receive reply
if (!_socket.waitForReadyRead()) if (!_socket.waitForReadyRead())
{ {
throw std::runtime_error("Error while reading data from host"); throw std::runtime_error("Error while reading data from host");
} }
char data[1024 * 100]; char data[1024 * 100];
uint64_t count = _socket.read(data, sizeof(data)); uint64_t count = _socket.read(data, sizeof(data));
std::string serializedReply(data, count); std::string serializedReply(data, count);
Json::Reader jsonReader; Json::Reader jsonReader;
Json::Value reply; Json::Value reply;
if (!jsonReader.parse(serializedReply, reply)) if (!jsonReader.parse(serializedReply, reply))
{ {
throw std::runtime_error("Error while parsing reply:" + serializedReply); throw std::runtime_error("Error while parsing reply:" + serializedReply);
} }
if (_printJson) // print reply if requested
{ if (_printJson)
std::cout << "Reply:" << reply << std::endl; {
} std::cout << "Reply:" << reply << std::endl;
}
return true; return reply;
} }

View File

@ -1,33 +1,51 @@
#pragma once #pragma once
// stl includes
#include <string> #include <string>
// Qt includes
#include <QColor> #include <QColor>
#include <QImage> #include <QImage>
#include <QTcpSocket> #include <QTcpSocket>
// jsoncpp includes
#include <json/json.h> #include <json/json.h>
// hyperion-remote includes
#include "ColorTransformValues.h" #include "ColorTransformValues.h"
/// Connection class to setup an connection to the hyperion server and execute commands
class Connection class Connection
{ {
public: public:
Connection(const std::string & address, bool printJson); Connection(const std::string & address, bool printJson);
~Connection(); ~Connection();
bool setColor(QColor color, int priority, int duration); /// Set all leds to the specified color
bool setImage(QImage image, int priority, int duration); bool setColor(QColor color, int priority, int duration);
bool listPriorities();
bool clear(int priority); /// Set the leds according to the given image (assume the image is stretched to the display size)
bool clearAll(); bool setImage(QImage image, int priority, int duration);
bool setTransform(ColorTransformValues * threshold, ColorTransformValues * gamma, ColorTransformValues * blacklevel, ColorTransformValues * whitelevel);
/// Retrieve a list of all occupied priority channels
bool listPriorities();
/// Clear the given priority channel
bool clear(int priority);
/// Clear all priority channels
bool clearAll();
/// Set the color transform of the leds
/// Note that providing a NULL will leave the settings on the server unchanged
bool setTransform(ColorTransformValues * threshold, ColorTransformValues * gamma, ColorTransformValues * blacklevel, ColorTransformValues * whitelevel);
private: private:
bool sendMessage(const Json::Value & message); /// Send a json command message and receive its reply
Json::Value sendMessage(const Json::Value & message);
private: private:
bool _printJson; bool _printJson;
QTcpSocket _socket; QTcpSocket _socket;
}; };

View File

@ -1,97 +1,102 @@
#pragma once #pragma once
// Qt includes
#include <QColor> #include <QColor>
#include <QImage> #include <QImage>
// getoptPlusPLus includes
#include <getoptPlusPlus/getoptpp.h> #include <getoptPlusPlus/getoptpp.h>
// hyperion-remote includes
#include "ColorTransformValues.h" #include "ColorTransformValues.h"
typedef vlofgren::PODParameter<QColor> ColorParameter; typedef vlofgren::PODParameter<QColor> ColorParameter;
typedef vlofgren::PODParameter<QImage> ImageParameter; typedef vlofgren::PODParameter<QImage> ImageParameter;
typedef vlofgren::PODParameter<ColorTransformValues> TransformParameter; typedef vlofgren::PODParameter<ColorTransformValues> TransformParameter;
namespace vlofgren { namespace vlofgren {
template<> template<>
QColor ColorParameter::validate(const std::string& s) throw (Parameter::ParameterRejected) QColor ColorParameter::validate(const std::string& s) throw (Parameter::ParameterRejected)
{ {
// Check if we can create the color by name // Check if we can create the color by name
QColor color(s.c_str()); QColor color(s.c_str());
if (color.isValid()) if (color.isValid())
{ {
return color; return color;
} }
// check if we can create the color by hex RRGGBB value // check if we can create the color by hex RRGGBB value
if (s.length() == 6 && isxdigit(s[0]) && isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) && isxdigit(s[4]) && isxdigit(s[5])) if (s.length() == 6 && isxdigit(s[0]) && isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) && isxdigit(s[4]) && isxdigit(s[5]))
{ {
bool ok = true; bool ok = true;
int rgb[3]; int rgb[3];
for (int i = 0; i < 3 && ok; ++i) for (int i = 0; i < 3 && ok; ++i)
{ {
QString colorComponent(s.substr(2*i, 2).c_str()); QString colorComponent(s.substr(2*i, 2).c_str());
rgb[i] = colorComponent.toInt(&ok, 16); rgb[i] = colorComponent.toInt(&ok, 16);
} }
// check if all components parsed succesfully // check if all components parsed succesfully
if (ok) if (ok)
{ {
color.setRgb(rgb[0], rgb[1], rgb[2]); color.setRgb(rgb[0], rgb[1], rgb[2]);
return color; return color;
} }
} }
std::stringstream errorMessage; std::stringstream errorMessage;
errorMessage << "Invalid color. A color is specified by a six lettered RRGGBB hex value or one of the following names:"; errorMessage << "Invalid color. A color is specified by a six lettered RRGGBB hex value or one of the following names:";
foreach (const QString & colorname, QColor::colorNames()) { foreach (const QString & colorname, QColor::colorNames()) {
errorMessage << "\n " << colorname.toStdString(); errorMessage << "\n " << colorname.toStdString();
} }
throw Parameter::ParameterRejected(errorMessage.str()); throw Parameter::ParameterRejected(errorMessage.str());
return color; return color;
} }
template<> template<>
QImage ImageParameter::validate(const std::string& s) throw (Parameter::ParameterRejected) QImage ImageParameter::validate(const std::string& s) throw (Parameter::ParameterRejected)
{ {
QImage image(s.c_str()); QImage image(s.c_str());
if (image.isNull()) if (image.isNull())
{ {
std::stringstream errorMessage; std::stringstream errorMessage;
errorMessage << "File " << s << " could not be opened as an image"; errorMessage << "File " << s << " could not be opened as an image";
throw Parameter::ParameterRejected(errorMessage.str()); throw Parameter::ParameterRejected(errorMessage.str());
} }
return image; return image;
} }
template<> template<>
ColorTransformValues TransformParameter::validate(const std::string& s) throw (Parameter::ParameterRejected) ColorTransformValues TransformParameter::validate(const std::string& s) throw (Parameter::ParameterRejected)
{ {
ColorTransformValues transform; ColorTransformValues transform;
// s should be split in 3 parts // s should be split in 3 parts
// seperators are either a ',' or a space // seperators are either a ',' or a space
QStringList components = QString(s.c_str()).split(" ", QString::SkipEmptyParts); QStringList components = QString(s.c_str()).split(" ", QString::SkipEmptyParts);
if (components.size() == 3) if (components.size() == 3)
{ {
bool ok1, ok2, ok3; bool ok1, ok2, ok3;
transform.valueRed = components[0].toDouble(&ok1); transform.valueRed = components[0].toDouble(&ok1);
transform.valueGreen = components[1].toDouble(&ok2); transform.valueGreen = components[1].toDouble(&ok2);
transform.valueBlue = components[2].toDouble(&ok3); transform.valueBlue = components[2].toDouble(&ok3);
if (ok1 && ok2 && ok3) if (ok1 && ok2 && ok3)
{ {
return transform; return transform;
} }
} }
std::stringstream errorMessage; std::stringstream errorMessage;
errorMessage << "Argument " << s << " can not be parsed to 3 double values"; errorMessage << "Argument " << s << " can not be parsed to 3 double values";
throw Parameter::ParameterRejected(errorMessage.str()); throw Parameter::ParameterRejected(errorMessage.str());
return transform; return transform;
} }
} }

View File

@ -1,137 +1,137 @@
// stl includes
#include <initializer_list> #include <initializer_list>
// Qt includes
#include <QCoreApplication> #include <QCoreApplication>
// getoptPlusPLus includes
#include <getoptPlusPlus/getoptpp.h> #include <getoptPlusPlus/getoptpp.h>
// hyperion-remote include
#include "CustomParameter.h" #include "CustomParameter.h"
#include "Connection.h" #include "Connection.h"
using namespace vlofgren; using namespace vlofgren;
/// Count the number of true values in a list of booleans
int count(std::initializer_list<bool> values) int count(std::initializer_list<bool> values)
{ {
int count = 0; int count = 0;
for (auto& value : values) { for (bool value : values) {
if (value) if (value)
count++; count++;
} }
return count; return count;
} }
int main(int argc, char * argv[]) int main(int argc, char * argv[])
{ {
QCoreApplication app(argc, argv); QCoreApplication app(argc, argv);
try try
{ {
// some settings // some default settings
QString defaultServerAddress = "localhost:19444"; QString defaultServerAddress = "localhost:19444";
int defaultPriority = 100; int defaultPriority = 100;
OptionsParser optionParser("Simple application to send a command to hyperion using the Json interface"); // create the option parser and initialize all parameters
ParameterSet & parameters = optionParser.getParameters(); OptionsParser optionParser("Simple application to send a command to hyperion using the Json interface");
StringParameter & argAddress = parameters.add<StringParameter> ('a', "address" , QString("Set the address of the hyperion server [default: %1]").arg(defaultServerAddress).toAscii().constData()); ParameterSet & parameters = optionParser.getParameters();
IntParameter & argPriority = parameters.add<IntParameter> ('p', "priority" , QString("Use to the provided priority channel (the lower the number, the higher the priority) [default: %1]").arg(defaultPriority).toAscii().constData()); StringParameter & argAddress = parameters.add<StringParameter> ('a', "address" , QString("Set the address of the hyperion server [default: %1]").arg(defaultServerAddress).toAscii().constData());
IntParameter & argDuration = parameters.add<IntParameter> ('d', "duration" , "Specify how long the leds should be switched on in millseconds [default: infinity]"); IntParameter & argPriority = parameters.add<IntParameter> ('p', "priority" , QString("Use to the provided priority channel (the lower the number, the higher the priority) [default: %1]").arg(defaultPriority).toAscii().constData());
ColorParameter & argColor = parameters.add<ColorParameter> ('c', "color" , "Set all leds to a constant color (either RRGGBB hex value or a color name)"); IntParameter & argDuration = parameters.add<IntParameter> ('d', "duration" , "Specify how long the leds should be switched on in millseconds [default: infinity]");
ImageParameter & argImage = parameters.add<ImageParameter> ('i', "image" , "Set the leds to the colors according to the given image file"); ColorParameter & argColor = parameters.add<ColorParameter> ('c', "color" , "Set all leds to a constant color (either RRGGBB hex value or a color name)");
SwitchParameter<> & argList = parameters.add<SwitchParameter<> >('l', "list" , "List all priority channels which are in use"); ImageParameter & argImage = parameters.add<ImageParameter> ('i', "image" , "Set the leds to the colors according to the given image file");
SwitchParameter<> & argClear = parameters.add<SwitchParameter<> >('x', "clear" , "Clear data for the priority channel provided by the -p option"); SwitchParameter<> & argList = parameters.add<SwitchParameter<> >('l', "list" , "List all priority channels which are in use");
SwitchParameter<> & argClearAll = parameters.add<SwitchParameter<> >(0x0, "clear-all" , "Clear data for all priority channels"); SwitchParameter<> & argClear = parameters.add<SwitchParameter<> >('x', "clear" , "Clear data for the priority channel provided by the -p option");
TransformParameter & argGamma = parameters.add<TransformParameter>('g', "gamma" , "Set the gamma of the leds (requires 3 values)"); SwitchParameter<> & argClearAll = parameters.add<SwitchParameter<> >(0x0, "clear-all" , "Clear data for all priority channels");
TransformParameter & argThreshold = parameters.add<TransformParameter>('t', "threshold" , "Set the threshold of the leds (requires 3 space seperated values between 0.0 and 1.0)"); TransformParameter & argGamma = parameters.add<TransformParameter>('g', "gamma" , "Set the gamma of the leds (requires 3 values)");
TransformParameter & argBlacklevel = parameters.add<TransformParameter>('b', "blacklevel", "Set the blacklevel of the leds (requires 3 space seperated values which are normally between 0.0 and 1.0)"); TransformParameter & argThreshold = parameters.add<TransformParameter>('t', "threshold" , "Set the threshold of the leds (requires 3 space seperated values between 0.0 and 1.0)");
TransformParameter & argWhitelevel = parameters.add<TransformParameter>('w', "whitelevel", "Set the whitelevel of the leds (requires 3 space seperated values which are normally between 0.0 and 1.0)"); TransformParameter & argBlacklevel = parameters.add<TransformParameter>('b', "blacklevel", "Set the blacklevel of the leds (requires 3 space seperated values which are normally between 0.0 and 1.0)");
SwitchParameter<> & argPrint = parameters.add<SwitchParameter<> >(0x0, "print" , "Print the json input and output messages on stdout"); TransformParameter & argWhitelevel = parameters.add<TransformParameter>('w', "whitelevel", "Set the whitelevel of the leds (requires 3 space seperated values which are normally between 0.0 and 1.0)");
SwitchParameter<> & argHelp = parameters.add<SwitchParameter<> >('h', "help" , "Show this help message and exit"); SwitchParameter<> & argPrint = parameters.add<SwitchParameter<> >(0x0, "print" , "Print the json input and output messages on stdout");
SwitchParameter<> & argHelp = parameters.add<SwitchParameter<> >('h', "help" , "Show this help message and exit");
argAddress.setDefault(defaultServerAddress.toStdString()); // set the default values
argPriority.setDefault(defaultPriority); argAddress.setDefault(defaultServerAddress.toStdString());
argDuration.setDefault(-1); argPriority.setDefault(defaultPriority);
argDuration.setDefault(-1);
// parse the options // parse all options
optionParser.parse(argc, const_cast<const char **>(argv)); optionParser.parse(argc, const_cast<const char **>(argv));
// check if we need to display the usage // check if we need to display the usage. exit if we do.
if (argHelp.isSet()) if (argHelp.isSet())
{ {
optionParser.usage(); optionParser.usage();
return 0; return 0;
} }
// check if a color transform is set // check if at least one of the available color transforms is set
bool colorTransform = argThreshold.isSet() || argGamma.isSet() || argBlacklevel.isSet() || argWhitelevel.isSet(); bool colorTransform = argThreshold.isSet() || argGamma.isSet() || argBlacklevel.isSet() || argWhitelevel.isSet();
// check if exactly one command was given // check that exactly one command was given
int commandCount = count({argColor.isSet(), argImage.isSet(), argList.isSet(), argClear.isSet(), argClearAll.isSet(), colorTransform}); int commandCount = count({argColor.isSet(), argImage.isSet(), argList.isSet(), argClear.isSet(), argClearAll.isSet(), colorTransform});
if (commandCount != 1) if (commandCount != 1)
{ {
if (commandCount == 0) std::cerr << (commandCount == 0 ? "No command found." : "Multiple commands found.") << " Provide exactly one of the following options:" << std::endl;
{ std::cerr << " " << argColor.usageLine() << std::endl;
std::cerr << "No command found. Provide one of the following options:" << std::endl; std::cerr << " " << argImage.usageLine() << std::endl;
} std::cerr << " " << argList.usageLine() << std::endl;
else std::cerr << " " << argClear.usageLine() << std::endl;
{ std::cerr << " " << argClearAll.usageLine() << std::endl;
std::cerr << "Multiple commands found. Provide one of the following options:" << std::endl; std::cerr << "or one or more of the available color transformations:" << std::endl;
} std::cerr << " " << argThreshold.usageLine() << std::endl;
std::cerr << " " << argColor.usageLine() << std::endl; std::cerr << " " << argGamma.usageLine() << std::endl;
std::cerr << " " << argImage.usageLine() << std::endl; std::cerr << " " << argBlacklevel.usageLine() << std::endl;
std::cerr << " " << argList.usageLine() << std::endl; std::cerr << " " << argWhitelevel.usageLine() << std::endl;
std::cerr << " " << argClear.usageLine() << std::endl; return 1;
std::cerr << " " << argClearAll.usageLine() << std::endl; }
std::cerr << "or one or more of the color transformations:" << std::endl;
std::cerr << " " << argThreshold.usageLine() << std::endl;
std::cerr << " " << argGamma.usageLine() << std::endl;
std::cerr << " " << argBlacklevel.usageLine() << std::endl;
std::cerr << " " << argWhitelevel.usageLine() << std::endl;
return 1;
}
// create the connection // create the connection to the hyperion server
Connection connection(argAddress.getValue(), argPrint.isSet()); Connection connection(argAddress.getValue(), argPrint.isSet());
// now execute the given command // now execute the given command
if (argColor.isSet()) if (argColor.isSet())
{ {
connection.setColor(argColor.getValue(), argPriority.getValue(), argDuration.getValue()); connection.setColor(argColor.getValue(), argPriority.getValue(), argDuration.getValue());
} }
else if (argImage.isSet()) else if (argImage.isSet())
{ {
connection.setImage(argImage.getValue(), argPriority.getValue(), argDuration.getValue()); connection.setImage(argImage.getValue(), argPriority.getValue(), argDuration.getValue());
} }
else if (argList.isSet()) else if (argList.isSet())
{ {
connection.listPriorities(); connection.listPriorities();
} }
else if (argClear.isSet()) else if (argClear.isSet())
{ {
connection.clear(argPriority.getValue()); connection.clear(argPriority.getValue());
} }
else if (argClearAll.isSet()) else if (argClearAll.isSet())
{ {
connection.clearAll(); connection.clearAll();
} }
else if (colorTransform) else if (colorTransform)
{ {
ColorTransformValues threshold = argThreshold.getValue(); ColorTransformValues threshold = argThreshold.getValue();
ColorTransformValues gamma = argGamma.getValue(); ColorTransformValues gamma = argGamma.getValue();
ColorTransformValues blacklevel = argBlacklevel.getValue(); ColorTransformValues blacklevel = argBlacklevel.getValue();
ColorTransformValues whitelevel = argWhitelevel.getValue(); ColorTransformValues whitelevel = argWhitelevel.getValue();
connection.setTransform( connection.setTransform(
argThreshold.isSet() ? &threshold : nullptr, argThreshold.isSet() ? &threshold : nullptr,
argGamma.isSet() ? &gamma : nullptr, argGamma.isSet() ? &gamma : nullptr,
argBlacklevel.isSet() ? &blacklevel : nullptr, argBlacklevel.isSet() ? &blacklevel : nullptr,
argWhitelevel.isSet() ? &whitelevel : nullptr); argWhitelevel.isSet() ? &whitelevel : nullptr);
} }
} }
catch (const std::runtime_error & e) catch (const std::runtime_error & e)
{ {
std::cerr << e.what() << std::endl; // An error occured. Display error and quit
return 1; std::cerr << e.what() << std::endl;
} return 1;
}
return 0; return 0;
} }