2014-05-06 08:07:18 +00:00
|
|
|
#include "PlaceholderParser.hpp"
|
2015-12-08 10:01:12 +00:00
|
|
|
#include <cstring>
|
2014-11-09 19:41:27 +00:00
|
|
|
#include <ctime>
|
|
|
|
#include <iomanip>
|
|
|
|
#include <sstream>
|
2016-08-21 19:46:17 +00:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
#include <stdlib.h> // provides **_environ
|
|
|
|
#else
|
|
|
|
#include <unistd.h> // provides **environ
|
|
|
|
#endif
|
2015-07-01 15:56:38 +00:00
|
|
|
|
2016-04-11 10:04:54 +00:00
|
|
|
#ifdef __APPLE__
|
|
|
|
#include <crt_externs.h>
|
|
|
|
#undef environ
|
|
|
|
#define environ (*_NSGetEnviron())
|
|
|
|
#else
|
2016-08-21 19:46:17 +00:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
#define environ _environ
|
|
|
|
#else
|
|
|
|
extern char **environ;
|
|
|
|
#endif
|
2016-04-11 10:04:54 +00:00
|
|
|
#endif
|
2014-05-06 08:07:18 +00:00
|
|
|
|
|
|
|
namespace Slic3r {
|
|
|
|
|
|
|
|
PlaceholderParser::PlaceholderParser()
|
|
|
|
{
|
2015-07-01 17:35:22 +00:00
|
|
|
this->set("version", SLIC3R_VERSION);
|
2015-07-01 15:56:38 +00:00
|
|
|
this->apply_env_variables();
|
2014-11-09 19:41:27 +00:00
|
|
|
this->update_timestamp();
|
|
|
|
}
|
|
|
|
|
2017-07-31 13:42:55 +00:00
|
|
|
void PlaceholderParser::update_timestamp()
|
2014-11-09 19:41:27 +00:00
|
|
|
{
|
|
|
|
time_t rawtime;
|
|
|
|
time(&rawtime);
|
|
|
|
struct tm* timeinfo = localtime(&rawtime);
|
|
|
|
|
|
|
|
{
|
|
|
|
std::ostringstream ss;
|
|
|
|
ss << (1900 + timeinfo->tm_year);
|
|
|
|
ss << std::setw(2) << std::setfill('0') << (1 + timeinfo->tm_mon);
|
|
|
|
ss << std::setw(2) << std::setfill('0') << timeinfo->tm_mday;
|
|
|
|
ss << "-";
|
|
|
|
ss << std::setw(2) << std::setfill('0') << timeinfo->tm_hour;
|
|
|
|
ss << std::setw(2) << std::setfill('0') << timeinfo->tm_min;
|
|
|
|
ss << std::setw(2) << std::setfill('0') << timeinfo->tm_sec;
|
2015-05-02 19:43:22 +00:00
|
|
|
this->set("timestamp", ss.str());
|
2014-11-09 19:41:27 +00:00
|
|
|
}
|
2015-05-02 19:43:22 +00:00
|
|
|
this->set("year", 1900 + timeinfo->tm_year);
|
|
|
|
this->set("month", 1 + timeinfo->tm_mon);
|
|
|
|
this->set("day", timeinfo->tm_mday);
|
|
|
|
this->set("hour", timeinfo->tm_hour);
|
|
|
|
this->set("minute", timeinfo->tm_min);
|
|
|
|
this->set("second", timeinfo->tm_sec);
|
2014-05-06 08:07:18 +00:00
|
|
|
}
|
|
|
|
|
2017-07-31 13:42:55 +00:00
|
|
|
// Scalar configuration values are stored into m_single,
|
|
|
|
// vector configuration values are stored into m_multiple.
|
|
|
|
// All vector configuration values stored into the PlaceholderParser
|
|
|
|
// are expected to be addressed by the extruder ID, therefore
|
|
|
|
// if a vector configuration value is addressed without an index,
|
|
|
|
// a current extruder ID is used.
|
2015-12-07 18:39:49 +00:00
|
|
|
void PlaceholderParser::apply_config(const DynamicPrintConfig &config)
|
2014-06-13 13:32:11 +00:00
|
|
|
{
|
2017-07-31 13:42:55 +00:00
|
|
|
for (const t_config_option_key &opt_key : config.keys()) {
|
2017-10-17 14:01:18 +00:00
|
|
|
const ConfigOptionDef* def = config.def()->get(opt_key);
|
2017-07-31 13:42:55 +00:00
|
|
|
if (def->multiline || opt_key == "post_process")
|
|
|
|
continue;
|
|
|
|
|
2015-12-07 18:39:49 +00:00
|
|
|
const ConfigOption* opt = config.option(opt_key);
|
2017-07-31 13:42:55 +00:00
|
|
|
const ConfigOptionVectorBase* optv = dynamic_cast<const ConfigOptionVectorBase*>(opt);
|
|
|
|
if (optv != nullptr && opt_key != "bed_shape") {
|
2015-05-02 19:43:22 +00:00
|
|
|
// set placeholders for options with multiple values
|
2015-12-07 18:39:49 +00:00
|
|
|
this->set(opt_key, optv->vserialize());
|
2015-05-02 19:43:22 +00:00
|
|
|
} else if (const ConfigOptionPoint* optp = dynamic_cast<const ConfigOptionPoint*>(opt)) {
|
2015-12-07 18:39:49 +00:00
|
|
|
this->set(opt_key, optp->serialize());
|
2015-05-02 19:43:22 +00:00
|
|
|
Pointf val = *optp;
|
2015-12-07 18:39:49 +00:00
|
|
|
this->set(opt_key + "_X", val.x);
|
|
|
|
this->set(opt_key + "_Y", val.y);
|
2015-05-02 19:43:22 +00:00
|
|
|
} else {
|
2014-06-13 13:32:11 +00:00
|
|
|
// set single-value placeholders
|
2015-12-07 18:39:49 +00:00
|
|
|
this->set(opt_key, opt->serialize());
|
2014-06-13 13:32:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-31 13:42:55 +00:00
|
|
|
void PlaceholderParser::apply_env_variables()
|
2015-07-01 15:56:38 +00:00
|
|
|
{
|
|
|
|
for (char** env = environ; *env; env++) {
|
|
|
|
if (strncmp(*env, "SLIC3R_", 7) == 0) {
|
|
|
|
std::stringstream ss(*env);
|
|
|
|
std::string key, value;
|
|
|
|
std::getline(ss, key, '=');
|
|
|
|
ss >> value;
|
|
|
|
|
|
|
|
this->set(key, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-03 16:28:22 +00:00
|
|
|
void PlaceholderParser::set(const std::string &key, const std::string &value)
|
2014-11-09 19:41:27 +00:00
|
|
|
{
|
2017-07-31 13:42:55 +00:00
|
|
|
m_single[key] = value;
|
|
|
|
m_multiple.erase(key);
|
2014-11-09 19:41:27 +00:00
|
|
|
}
|
|
|
|
|
2017-05-03 16:28:22 +00:00
|
|
|
void PlaceholderParser::set(const std::string &key, int value)
|
2014-06-13 13:32:11 +00:00
|
|
|
{
|
2015-05-02 19:43:22 +00:00
|
|
|
std::ostringstream ss;
|
|
|
|
ss << value;
|
|
|
|
this->set(key, ss.str());
|
2014-06-13 13:32:11 +00:00
|
|
|
}
|
|
|
|
|
2017-05-03 16:28:22 +00:00
|
|
|
void PlaceholderParser::set(const std::string &key, unsigned int value)
|
|
|
|
{
|
|
|
|
std::ostringstream ss;
|
|
|
|
ss << value;
|
|
|
|
this->set(key, ss.str());
|
|
|
|
}
|
|
|
|
|
|
|
|
void PlaceholderParser::set(const std::string &key, double value)
|
|
|
|
{
|
|
|
|
std::ostringstream ss;
|
|
|
|
ss << value;
|
|
|
|
this->set(key, ss.str());
|
|
|
|
}
|
|
|
|
|
|
|
|
void PlaceholderParser::set(const std::string &key, std::vector<std::string> values)
|
2014-06-13 13:32:11 +00:00
|
|
|
{
|
2017-07-31 13:42:55 +00:00
|
|
|
m_single.erase(key);
|
|
|
|
if (values.empty())
|
|
|
|
m_multiple.erase(key);
|
|
|
|
else
|
|
|
|
m_multiple[key] = values;
|
2015-07-01 17:35:22 +00:00
|
|
|
}
|
|
|
|
|
2017-07-31 13:42:55 +00:00
|
|
|
std::string PlaceholderParser::process(std::string str, unsigned int current_extruder_id) const
|
2015-07-01 17:35:22 +00:00
|
|
|
{
|
2017-07-31 13:42:55 +00:00
|
|
|
char key[2048];
|
|
|
|
|
|
|
|
// Replace extruder independent single options, like [foo].
|
|
|
|
for (const auto &key_value : m_single) {
|
|
|
|
sprintf(key, "[%s]", key_value.first.c_str());
|
|
|
|
const std::string &replace = key_value.second;
|
|
|
|
for (size_t i = 0; (i = str.find(key, i)) != std::string::npos;) {
|
|
|
|
str.replace(i, key_value.first.size() + 2, replace);
|
|
|
|
i += replace.size();
|
|
|
|
}
|
2015-07-01 17:35:22 +00:00
|
|
|
}
|
2017-07-31 13:42:55 +00:00
|
|
|
|
|
|
|
// Replace extruder dependent single options with the value for the active extruder.
|
|
|
|
// For example, [temperature] will be replaced with the current extruder temperature.
|
|
|
|
for (const auto &key_value : m_multiple) {
|
|
|
|
sprintf(key, "[%s]", key_value.first.c_str());
|
|
|
|
const std::string &replace = key_value.second[(current_extruder_id < key_value.second.size()) ? current_extruder_id : 0];
|
|
|
|
for (size_t i = 0; (i = str.find(key, i)) != std::string::npos;) {
|
|
|
|
str.replace(i, key_value.first.size() + 2, replace);
|
|
|
|
i += replace.size();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Replace multiple options like [foo_0].
|
|
|
|
for (const auto &key_value : m_multiple) {
|
|
|
|
sprintf(key, "[%s_", key_value.first.c_str());
|
|
|
|
const std::vector<std::string> &values = key_value.second;
|
|
|
|
for (size_t i = 0; (i = str.find(key, i)) != std::string::npos;) {
|
|
|
|
size_t k = str.find(']', i + key_value.first.size() + 2);
|
|
|
|
if (k != std::string::npos) {
|
|
|
|
// Parse the key index and the closing bracket.
|
|
|
|
++ k;
|
|
|
|
int idx = 0;
|
|
|
|
if (sscanf(str.c_str() + i + key_value.first.size() + 2, "%d]", &idx) == 1 && idx >= 0) {
|
|
|
|
if (idx >= int(values.size()))
|
|
|
|
idx = 0;
|
|
|
|
str.replace(i, k - i, values[idx]);
|
|
|
|
i += values[idx].size();
|
|
|
|
continue;
|
|
|
|
}
|
2015-07-01 17:35:22 +00:00
|
|
|
}
|
2017-07-31 13:42:55 +00:00
|
|
|
// The key does not match the pattern [foo_%d]. Skip just [foo_.] with the hope that there was a missing ']',
|
|
|
|
// so an opening '[' may be found somewhere before the position k.
|
|
|
|
i += key_value.first.size() + 3;
|
2015-05-02 19:43:22 +00:00
|
|
|
}
|
2014-06-13 13:32:11 +00:00
|
|
|
}
|
2015-07-01 17:35:22 +00:00
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2014-05-06 08:07:18 +00:00
|
|
|
}
|