session: Add support for input format options (-I cmdline parameter)
authorGerhard Sittig <gerhard.sittig@gmx.net>
Sun, 25 Jun 2017 17:40:14 +0000 (19:40 +0200)
committerUwe Hermann <uwe@hermann-uwe.de>
Tue, 27 Jun 2017 11:19:46 +0000 (13:19 +0200)
The previous implementation supported the selection of an input format
by means of the -I command line option. This commit extends the feature
by adding support for colon separated input format options similar to
sigrok-cli.

This allows users to open files from the command line which previously
became only available after filling in dialogs, and resulted in errors
in the absence of options. Here is an example of how to use the option:

  $ pulseview -I csv:header:first-channel=2 -i filename.csv

This fixes bug #951.

pv/session.cpp
pv/session.hpp

index aa528d191fe6750958bd2cbf8491fe8bb35383d0..516e1acd5ad6ff1e6b52a277f97c042e28e37872 100644 (file)
@@ -434,26 +434,76 @@ void Session::set_default_device()
        set_device((iter == devices.end()) ? devices.front() : *iter);
 }
 
        set_device((iter == devices.end()) ? devices.front() : *iter);
 }
 
+/**
+ * Convert generic options to data types that are specific to InputFormat.
+ *
+ * @param[in] user_spec vector of tokenized words, string format
+ * @param[in] fmt_opts input format's options, result of InputFormat::options()
+ *
+ * @return map of options suitable for InputFormat::create_input()
+ */
+map<string, Glib::VariantBase>
+Session::input_format_options(vector<string> user_spec,
+               map<string, shared_ptr<Option>> fmt_opts)
+{
+       map<string, Glib::VariantBase> result;
+
+       for (auto entry : user_spec) {
+               /*
+                * Split key=value specs. Accept entries without separator
+                * (for simplified boolean specifications).
+                */
+               string key, val;
+               size_t pos = entry.find("=");
+               if (pos == std::string::npos) {
+                       key = entry;
+                       val = "";
+               } else {
+                       key = entry.substr(0, pos);
+                       val = entry.substr(pos + 1);
+               }
+
+               /*
+                * Skip user specifications that are not a member of the
+                * format's set of supported options. Have the text input
+                * spec converted to the required input format specific
+                * data type.
+                */
+               auto found = fmt_opts.find(key);
+               if (found == fmt_opts.end())
+                       continue;
+               shared_ptr<Option> opt = found->second;
+               result[key] = opt->parse_string(val);
+       }
+
+       return result;
+}
+
 void Session::load_init_file(const string &file_name, const string &format)
 {
        shared_ptr<InputFormat> input_format;
 void Session::load_init_file(const string &file_name, const string &format)
 {
        shared_ptr<InputFormat> input_format;
+       map<string, Glib::VariantBase> input_opts;
 
        if (!format.empty()) {
                const map<string, shared_ptr<InputFormat> > formats =
                        device_manager_.context()->input_formats();
 
        if (!format.empty()) {
                const map<string, shared_ptr<InputFormat> > formats =
                        device_manager_.context()->input_formats();
+               auto user_opts = pv::util::split_string(format, ":");
+               string user_name = user_opts.front();
+               user_opts.erase(user_opts.begin());
                const auto iter = find_if(formats.begin(), formats.end(),
                        [&](const pair<string, shared_ptr<InputFormat> > f) {
                const auto iter = find_if(formats.begin(), formats.end(),
                        [&](const pair<string, shared_ptr<InputFormat> > f) {
-                               return f.first == format; });
+                               return f.first == user_name; });
                if (iter == formats.end()) {
                        main_bar_->session_error(tr("Error"),
                                tr("Unexpected input format: %s").arg(QString::fromStdString(format)));
                        return;
                }
                if (iter == formats.end()) {
                        main_bar_->session_error(tr("Error"),
                                tr("Unexpected input format: %s").arg(QString::fromStdString(format)));
                        return;
                }
-
                input_format = (*iter).second;
                input_format = (*iter).second;
+               input_opts = input_format_options(user_opts,
+                       input_format->options());
        }
 
        }
 
-       load_file(QString::fromStdString(file_name), input_format);
+       load_file(QString::fromStdString(file_name), input_format, input_opts);
 }
 
 void Session::load_file(QString file_name,
 }
 
 void Session::load_file(QString file_name,
index c7e1699bbac1193342e35e81df919be33b7fcfe6..c4f2bed83324779c0593b9d05635c9288c188f32 100644 (file)
@@ -55,11 +55,14 @@ class Device;
 class InputFormat;
 class Logic;
 class Meta;
 class InputFormat;
 class Logic;
 class Meta;
+class Option;
 class OutputFormat;
 class Packet;
 class Session;
 }  // namespace sigrok
 
 class OutputFormat;
 class Packet;
 class Session;
 }  // namespace sigrok
 
+using sigrok::Option;
+
 namespace pv {
 
 class DeviceManager;
 namespace pv {
 
 class DeviceManager;
@@ -179,6 +182,10 @@ private:
        shared_ptr<data::SignalBase> signalbase_from_channel(
                shared_ptr<sigrok::Channel> channel) const;
 
        shared_ptr<data::SignalBase> signalbase_from_channel(
                shared_ptr<sigrok::Channel> channel) const;
 
+       static map<string, Glib::VariantBase> input_format_options(
+               vector<string> user_spec,
+               map<string, shared_ptr<Option>> fmt_opts);
+
 private:
        void sample_thread_proc(function<void (const QString)> error_handler);
 
 private:
        void sample_thread_proc(function<void (const QString)> error_handler);