#include "PlaceholderParser.hpp" #include #include #include #include #ifdef _MSC_VER #include // provides **_environ #else #include // provides **environ #endif #ifdef __APPLE__ #include #undef environ #define environ (*_NSGetEnviron()) #else #ifdef _MSC_VER #define environ _environ #else extern char **environ; #endif #endif namespace Slic3r { PlaceholderParser::PlaceholderParser() { this->set("version", SLIC3R_VERSION); this->apply_env_variables(); this->update_timestamp(); } void PlaceholderParser::update_timestamp() { 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; this->set("timestamp", ss.str()); } 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); } // 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. void PlaceholderParser::apply_config(const DynamicPrintConfig &config) { for (const t_config_option_key &opt_key : config.keys()) { const ConfigOptionDef* def = config.def()->get(opt_key); if (def->multiline || opt_key == "post_process") continue; const ConfigOption* opt = config.option(opt_key); const ConfigOptionVectorBase* optv = dynamic_cast(opt); if (optv != nullptr && opt_key != "bed_shape") { // set placeholders for options with multiple values this->set(opt_key, optv->vserialize()); } else if (const ConfigOptionPoint* optp = dynamic_cast(opt)) { this->set(opt_key, optp->serialize()); Pointf val = *optp; this->set(opt_key + "_X", val.x); this->set(opt_key + "_Y", val.y); } else { // set single-value placeholders this->set(opt_key, opt->serialize()); } } } void PlaceholderParser::apply_env_variables() { 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); } } } void PlaceholderParser::set(const std::string &key, const std::string &value) { m_single[key] = value; m_multiple.erase(key); } void PlaceholderParser::set(const std::string &key, int value) { std::ostringstream ss; ss << value; this->set(key, ss.str()); } 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 values) { m_single.erase(key); if (values.empty()) m_multiple.erase(key); else m_multiple[key] = values; } std::string PlaceholderParser::process(std::string str, unsigned int current_extruder_id) const { 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(); } } // 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 &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; } } // 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; } } return str; } }