diff --git a/resources/profiles/PrusaResearch.idx b/resources/profiles/PrusaResearch.idx new file mode 100644 index 000000000..28f17f10a --- /dev/null +++ b/resources/profiles/PrusaResearch.idx @@ -0,0 +1,13 @@ +# This is an example configuration version index. +# The index contains version numbers +min_slic3r_version =1.39.0 +0.2.0-alpha "some test comment" +max_slic3r_version= 1.39.4 +0.1.0 another test comment + +# some empty lines + +# version without a comment +min_slic3r_version = 1.0.0 +max_slic3r_version = 1.1.0 +0.0.1 diff --git a/xs/src/semver/semver.c b/xs/src/semver/semver.c index 29bc1868d..599217f89 100644 --- a/xs/src/semver/semver.c +++ b/xs/src/semver/semver.c @@ -200,7 +200,7 @@ semver_parse_version (const char *str, semver_t *ver) { slice = next + 1; } - return 0; + return (index == 3) ? 0 : -1; } static int diff --git a/xs/src/slic3r/Config/Snapshot.cpp b/xs/src/slic3r/Config/Snapshot.cpp index 9fabbe013..eeb5b6ac5 100644 --- a/xs/src/slic3r/Config/Snapshot.cpp +++ b/xs/src/slic3r/Config/Snapshot.cpp @@ -57,6 +57,7 @@ void Snapshot::load_ini(const std::string &path) // Parse snapshot.ini std::string group_name_vendor = "Vendor:"; std::string key_filament = "filament"; + std::string key_prefix_model = "model_"; for (auto §ion : tree) { if (section.first == "snapshot") { // Parse the common section. @@ -107,10 +108,7 @@ void Snapshot::load_ini(const std::string &path) VendorConfig vc; vc.name = section.first.substr(group_name_vendor.size()); for (auto &kvp : section.second) { - if (boost::starts_with(kvp.first, "model_")) { - //model:MK2S = 0.4;xxx - //model:MK3 = 0.4;xxx - } else if (kvp.first == "version" || kvp.first == "min_slic3r_version" || kvp.first == "max_slic3r_version") { + if (kvp.first == "version" || kvp.first == "min_slic3r_version" || kvp.first == "max_slic3r_version") { // Version of the vendor specific config bundle bundled with this snapshot. auto semver = Semver::parse(kvp.second.data()); if (! semver) @@ -121,8 +119,16 @@ void Snapshot::load_ini(const std::string &path) vc.min_slic3r_version = *semver; else vc.max_slic3r_version = *semver; - } + } else if (boost::starts_with(kvp.first, key_prefix_model) && kvp.first.size() > key_prefix_model.size()) { + // Parse the printer variants installed for the current model. + auto &set_variants = vc.models_variants_installed[kvp.first.substr(key_prefix_model.size())]; + std::vector variants; + if (unescape_strings_cstyle(kvp.second.data(), variants)) + for (auto &variant : variants) + set_variants.insert(std::move(variant)); + } } + this->vendor_configs.emplace_back(std::move(vc)); } } } @@ -155,6 +161,14 @@ void Snapshot::save_ini(const std::string &path) c << "version = " << vc.version.to_string() << std::endl; c << "min_slic3r_version = " << vc.min_slic3r_version.to_string() << std::endl; c << "max_slic3r_version = " << vc.max_slic3r_version.to_string() << std::endl; + // Export installed printer models and their variants. + for (const auto &model : vc.models_variants_installed) { + if (model.second.size() == 0) + continue; + const std::vector variants(model.second.begin(), model.second.end()); + const auto escaped = escape_strings_cstyle(variants); + c << "model_" << model.first << " = " << escaped << std::endl; + } } c.close(); } diff --git a/xs/src/slic3r/Config/Version.cpp b/xs/src/slic3r/Config/Version.cpp index cc961829d..95b3caf1a 100644 --- a/xs/src/slic3r/Config/Version.cpp +++ b/xs/src/slic3r/Config/Version.cpp @@ -40,12 +40,13 @@ inline std::string unquote_value(char *value, char *end, const std::string &path if (value == end) { // Empty string is a valid string. } else if (*value == '"') { - if (++ value < -- end || *end != '"') + if (++ value > -- end || *end != '"') throw file_parser_error("String not enquoted correctly", path, idx_line); *end = 0; if (! unescape_string_cstyle(value, svalue)) throw file_parser_error("Invalid escape sequence inside a quoted string", path, idx_line); - } + } else + svalue.assign(value, end); return svalue; } @@ -55,12 +56,13 @@ inline std::string unquote_version_comment(char *value, char *end, const std::st if (value == end) { // Empty string is a valid string. } else if (*value == '"') { - if (++ value < -- end || *end != '"') + if (++ value > -- end || *end != '"') throw file_parser_error("Version comment not enquoted correctly", path, idx_line); *end = 0; if (! unescape_string_cstyle(value, svalue)) throw file_parser_error("Invalid escape sequence inside a quoted version comment", path, idx_line); - } + } else + svalue.assign(value, end); return svalue; } @@ -77,41 +79,55 @@ size_t Index::load(const boost::filesystem::path &path) ++ idx_line; // Skip the initial white spaces. char *key = left_trim(const_cast(line.data())); + if (*key == '#') + // Skip a comment line. + continue; // Right trim the line. char *end = right_trim(key); + if (key == end) + // Skip an empty line. + continue; // Keyword may only contain alphanumeric characters. Semantic version may in addition contain "+.-". char *key_end = key; - bool maybe_semver = false; - for (;; ++ key) { - if (strchr("+.-", *key) != nullptr) - maybe_semver = true; - else if (! std::isalnum(*key)) - break; + bool maybe_semver = true; + for (; *key_end != 0; ++ key_end) { + if (std::isalnum(*key_end) || strchr("+.-", *key_end) != nullptr) { + // It may be a semver. + } else if (*key_end == '_') { + // Cannot be a semver, but it may be a key. + maybe_semver = false; + } else + // End of semver or keyword. + break; } - if (*key != 0 && *key != ' ' && *key != '\t' && *key != '=') + if (*key_end != 0 && *key_end != ' ' && *key_end != '\t' && *key_end != '=') throw file_parser_error("Invalid keyword or semantic version", path, idx_line); - *key_end = 0; + char *value = left_trim(key_end); + bool key_value_pair = *value == '='; + if (key_value_pair) + value = left_trim(value + 1); + *key_end = 0; boost::optional semver; if (maybe_semver) semver = Semver::parse(key); - char *value = left_trim(key_end); - if (*value == '=') { + if (key_value_pair) { if (semver) - throw file_parser_error("Key cannot be a semantic version", path, idx_line); + throw file_parser_error("Key cannot be a semantic version", path, idx_line);\ // Verify validity of the key / value pair. - std::string svalue = unquote_value(left_trim(++ value), end, path.string(), idx_line); - if (key == "min_sic3r_version" || key == "max_slic3r_version") { + std::string svalue = unquote_value(value, end, path.string(), idx_line); + if (strcmp(key, "min_slic3r_version") == 0 || strcmp(key, "max_slic3r_version") == 0) { if (! svalue.empty()) - semver = Semver::parse(key); + semver = Semver::parse(svalue); if (! semver) throw file_parser_error(std::string(key) + " must referece a valid semantic version", path, idx_line); - if (key == "min_sic3r_version") + if (strcmp(key, "min_slic3r_version") == 0) ver.min_slic3r_version = *semver; else ver.max_slic3r_version = *semver; } else { // Ignore unknown keys, as there may come new keys in the future. } + continue; } if (! semver) throw file_parser_error("Invalid semantic version", path, idx_line); diff --git a/xs/src/slic3r/Utils/Semver.hpp b/xs/src/slic3r/Utils/Semver.hpp index 8aa8cc53f..bd8e9b758 100644 --- a/xs/src/slic3r/Utils/Semver.hpp +++ b/xs/src/slic3r/Utils/Semver.hpp @@ -55,9 +55,9 @@ public: Semver(const Semver &other) : ver(other.ver) { if (other.ver.metadata != nullptr) - std::strcpy(ver.metadata, other.ver.metadata); + ver.metadata = strdup(other.ver.metadata); if (other.ver.prerelease != nullptr) - std::strcpy(ver.prerelease, other.ver.prerelease); + ver.prerelease = strdup(other.ver.prerelease); } Semver &operator=(Semver &&other) @@ -73,8 +73,10 @@ public: { ::semver_free(&ver); ver = other.ver; - if (other.ver.metadata != nullptr) { std::strcpy(ver.metadata, other.ver.metadata); } - if (other.ver.prerelease != nullptr) { std::strcpy(ver.prerelease, other.ver.prerelease); } + if (other.ver.metadata != nullptr) + ver.metadata = strdup(other.ver.metadata); + if (other.ver.prerelease != nullptr) + ver.prerelease = strdup(other.ver.prerelease); return *this; }