From c831208d8cb363ecffb278e3b2f4a4218cbb04de Mon Sep 17 00:00:00 2001 From: npwoods Date: Sun, 16 Oct 2022 14:04:19 -0400 Subject: Added support for specifying volume attributes in 'floptool flopcreate' (#9590) An example command line: flopcreate vdk coco_rawdsk_os9_35 newdisk.vdk -name mycooldisk -creation_date "1999-02-28 13:23:47" Attributes are identified on the command line prefixed with '-'; if this is not the preferred syntax this can be changed. Implementing this also forced a change to fs::meta_value where the various as_*() calls can now be called without respect to which type the fs::meta_value is; this is necessary so that floptool code doesn't need to "own" parsing of the various types of fs::meta_value. And with this change, fs::meta_value::to_string() is now replaced by fs::meta_value::as_string() --- src/lib/formats/fsmeta.cpp | 61 +++++++++++++++++++++++++++++++++++++++++++++- src/lib/formats/fsmeta.h | 16 ++++++------ src/tools/floptool.cpp | 38 ++++++++++++++++++++++++++--- 3 files changed, 103 insertions(+), 12 deletions(-) diff --git a/src/lib/formats/fsmeta.cpp b/src/lib/formats/fsmeta.cpp index d10064bb162..3e97725c621 100644 --- a/src/lib/formats/fsmeta.cpp +++ b/src/lib/formats/fsmeta.cpp @@ -35,6 +35,16 @@ const char *meta_data::entry_name(meta_name name) return ""; } +std::optional meta_data::from_entry_name(const char *name) +{ + for (int i = 0; i <= (int)meta_name::max; i++) + { + if (!strcmp(name, entry_name((meta_name)i))) + return (meta_name)i; + } + return {}; +} + template struct overloaded : Ts... { using Ts::operator()...; }; template overloaded(Ts...) -> overloaded; @@ -51,7 +61,41 @@ meta_type meta_value::type() const return *result; } -std::string meta_value::to_string() const +util::arbitrary_datetime meta_value::as_date() const +{ + util::arbitrary_datetime result = { 0, }; + + std::visit( + overloaded + { + [&result](const std::string &s) + { + sscanf(s.c_str(), "%d-%d-%d %d:%d:%d", &result.year, &result.month, &result.day_of_month, &result.hour, &result.minute, &result.second); + }, + [&result](const util::arbitrary_datetime &dt) { result = dt; }, + [](std::uint64_t) { /* nonsensical */ }, + [](bool) { /* nonsensical */ } + }, value); + + return result; +} + +bool meta_value::as_flag() const +{ + bool result = false; + + std::visit( + overloaded + { + [&result](const std::string &s) { result = !s.empty() && s != "f"; }, + [&result](bool b) { result = b; }, + [](std::uint64_t) { /* nonsensical */ }, + [](const util::arbitrary_datetime &) { /* nonsensical */ } + }, value); + return result; +} + +std::string meta_value::as_string() const { std::string result; std::visit( @@ -69,4 +113,19 @@ std::string meta_value::to_string() const return result; } +uint64_t meta_value::as_number() const +{ + uint64_t result = 0; + + std::visit(overloaded + { + [&result](const std::string &s) { result = std::stoull(s); }, + [&result](uint64_t i) { result = i; }, + [](const util::arbitrary_datetime &) { /* nonsensical */ }, + [](bool) { /* nonsensical */ } + }, value); + return result; +} + + } // namespace fs diff --git a/src/lib/formats/fsmeta.h b/src/lib/formats/fsmeta.h index af709534c55..0f6baf20133 100644 --- a/src/lib/formats/fsmeta.h +++ b/src/lib/formats/fsmeta.h @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -36,7 +37,8 @@ enum class meta_name { ascii_flag, owner_id, attributes, - oem_name + oem_name, + max = oem_name }; enum class meta_type { @@ -49,8 +51,6 @@ enum class meta_type { class meta_value { public: meta_type type() const; - std::string to_string() const; - static meta_value from_string(meta_type type, std::string value); meta_value() { value = false; } meta_value(std::string &&str) { value = std::move(str); } @@ -63,10 +63,10 @@ public: meta_value(uint64_t num) { value = num; } meta_value(util::arbitrary_datetime dt) { value = dt; } - util::arbitrary_datetime as_date() const { return *std::get_if(&value); } - bool as_flag() const { return *std::get_if(&value); } - uint64_t as_number() const { return *std::get_if(&value); } - std::string as_string() const { return *std::get_if(&value); } + util::arbitrary_datetime as_date() const; + bool as_flag() const; + uint64_t as_number() const; + std::string as_string() const; private: std::variant value; @@ -77,6 +77,7 @@ public: std::unordered_map meta; static const char *entry_name(meta_name name); + static std::optional from_entry_name(const char *name); bool has(meta_name name) const { return meta.find(name) != meta.end(); } bool empty() const { return meta.empty(); } @@ -85,6 +86,7 @@ public: void set(meta_name name, meta_value &&val) { meta[name] = std::move(val); } void set(meta_name name, std::string &&str) { set(name, meta_value(std::move(str))); } void set(meta_name name, std::string_view str) { set(name, meta_value(str)); } + void set(meta_name name, const char *str) { set(name, meta_value(str)); } void set(meta_name name, bool b) { set(name, meta_value(b)); } void set(meta_name name, int32_t num) { set(name, meta_value(num)); } void set(meta_name name, uint32_t num) { set(name, meta_value(num)); } diff --git a/src/tools/floptool.cpp b/src/tools/floptool.cpp index eaf43d0861e..d680118944d 100644 --- a/src/tools/floptool.cpp +++ b/src/tools/floptool.cpp @@ -227,8 +227,39 @@ static int flopconvert(int argc, char *argv[]) return 0; } +static fs::meta_data extract_meta_data(int &argc, char *argv[]) +{ + fs::meta_data result; + + int new_argc = 0; + for (int i = 0; i < argc; i++) + { + std::optional attrname; + if (argv[i][0] == '-' && i < argc - 1) + attrname = fs::meta_data::from_entry_name(&argv[i][1]); + + if (attrname) + { + // we found a metadata variable; set it + result.set(*attrname, argv[i + 1]); + i++; + } + else + { + // we didn't; update argv + argv[new_argc++] = argv[i]; + } + } + + // we're done; update the argument count + argc = new_argc; + return result; +} + static int flopcreate(int argc, char *argv[]) { + fs::meta_data meta = extract_meta_data(argc, argv); + if(argc!=5) { fprintf(stderr, "Incorrect number of arguments.\n\n"); display_usage(argv[0]); @@ -255,7 +286,6 @@ static int flopcreate(int argc, char *argv[]) return 1; } - fs::meta_data meta; image_handler ih; ih.set_on_disk_path(argv[4]); @@ -281,7 +311,7 @@ static void dir_scan(fs::filesystem_t *fs, u32 depth, const std::vectorsecond; - std::string val = c.m_meta.get(m.m_name).to_string(); + std::string val = c.m_meta.get(m.m_name).as_string(); if(slot == 0) val = head + "dir " + val; entries[id][slot] = val; @@ -296,7 +326,7 @@ static void dir_scan(fs::filesystem_t *fs, u32 depth, const std::vectorsecond; - std::string val = c.m_meta.get(m.m_name).to_string(); + std::string val = c.m_meta.get(m.m_name).as_string(); if(slot == 0) val = head + "file " + val; entries[id][slot] = val; @@ -318,7 +348,7 @@ static int generic_dir(image_handler &ih) if(!vmeta.empty()) { std::string vinf = "Volume:"; for(const auto &e : vmetad) - vinf += util::string_format(" %s=%s", fs::meta_data::entry_name(e.m_name), vmeta.get(e.m_name).to_string()); + vinf += util::string_format(" %s=%s", fs::meta_data::entry_name(e.m_name), vmeta.get(e.m_name).as_string()); printf("%s\n\n", vinf.c_str()); } -- cgit v1.2.3