From 3476b6f37c28a1b22c8e4af0724f2c94199bcd82 Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Mon, 25 Mar 2013 15:04:20 -0400
Subject: core: adding ability to set config params and save config file.

Saving over-writes ~/.gnuradio/config.conf with all sections/options.

Save new prefs file with "gr.prefs().save()".

Can also view all prefs: "print gr.prefs().to_string()"
---
 gnuradio-core/src/lib/general/gr_prefs.cc | 194 +++++++++++++++++++++++++++---
 gnuradio-core/src/lib/general/gr_prefs.h  |  52 +++++++-
 gnuradio-core/src/lib/general/gr_prefs.i  |  33 +++--
 3 files changed, 239 insertions(+), 40 deletions(-)

(limited to 'gnuradio-core/src')

diff --git a/gnuradio-core/src/lib/general/gr_prefs.cc b/gnuradio-core/src/lib/general/gr_prefs.cc
index 5d9544f112..8a79c3335f 100644
--- a/gnuradio-core/src/lib/general/gr_prefs.cc
+++ b/gnuradio-core/src/lib/general/gr_prefs.cc
@@ -1,6 +1,6 @@
 /* -*- c++ -*- */
 /*
- * Copyright 2006 Free Software Foundation, Inc.
+ * Copyright 2006,2013 Free Software Foundation, Inc.
  *
  * This file is part of GNU Radio
  *
@@ -75,17 +75,18 @@ gr_prefs::_sys_prefs_filenames()
   fs::directory_iterator diritr(dir);
   while(diritr != fs::directory_iterator()) {
     fs::path p = *diritr++;
-    fnames.push_back(p.string());
+    if(p.extension() != ".swp")
+      fnames.push_back(p.string());
   }
   std::sort(fnames.begin(), fnames.end());
 
-  // Find if there is a ~/.gnuradio/config file and add this to the
-  // beginning of the file list to override any preferences in the
+  // Find if there is a ~/.gnuradio/config.conf file and add this to
+  // the end of the file list to override any preferences in the
   // installed path config files.
   fs::path homedir = fs::path(gr_appdata_path());
   homedir = homedir/".gnuradio/config.conf";
   if(fs::exists(homedir)) {
-    fnames.insert(fnames.begin(), homedir.string());
+    fnames.push_back(homedir.string());
   }    
 
   return fnames;
@@ -94,6 +95,8 @@ gr_prefs::_sys_prefs_filenames()
 void
 gr_prefs::_read_files()
 {
+  std::string config;
+
   std::vector<std::string> filenames = _sys_prefs_filenames();
   std::vector<std::string>::iterator sitr;
   char tmp[1024];
@@ -108,14 +111,89 @@ gr_prefs::_read_files()
 	size_t hash = t.find("#");
 
 	// Use hash marks at the end of each segment as a delimiter
-	d_configs += t.substr(0, hash) + '#';
+	config += t.substr(0, hash) + '#';
       }
     }
     fin.close();
   }
 
-  // Remove all whitespace
-  d_configs.erase(std::remove_if(d_configs.begin(), d_configs.end(), ::isspace), d_configs.end());
+  // Remove all whitespace.
+  config.erase(std::remove_if(config.begin(), config.end(), ::isspace), config.end());
+
+  // Convert the string into a map
+  _convert_to_map(config);
+}
+
+void
+gr_prefs::_convert_to_map(const std::string &conf)
+{
+  // Convert the string into an map of maps
+  // Map is structured as {section name: map of options}
+  // And options map is simply: {option name: option value}
+  std::string sub = conf;
+  size_t sec_start = sub.find("[");
+  while(sec_start != std::string::npos) {
+    sub = sub.substr(sec_start);
+    
+    size_t sec_end = sub.find("]");
+    if(sec_end == std::string::npos)
+      throw std::runtime_error("Config file error: Mismatched section label.\n");
+   
+    std::string sec = sub.substr(1, sec_end-1);
+    size_t next_sec_start = sub.find("[", sec_end);
+    std::string subsec = sub.substr(sec_end+1, next_sec_start-sec_end-2);
+
+    std::transform(sec.begin(), sec.end(), sec.begin(), ::tolower);
+
+    std::map<std::string, std::string> options_map = d_config_map[sec];
+    size_t next_opt = 0;
+    size_t next_val = 0;
+    next_opt = subsec.find("#");
+    while(next_opt < subsec.size()-1) {
+      next_val = subsec.find("=", next_opt);
+      std::string option = subsec.substr(next_opt+1, next_val-next_opt-1);
+      
+      next_opt = subsec.find("#", next_val);
+      std::string value = subsec.substr(next_val+1, next_opt-next_val-1);
+
+      std::transform(option.begin(), option.end(), option.begin(), ::tolower);
+      options_map[option] = value;
+    }
+
+    d_config_map[sec] = options_map;
+
+    sec_start = sub.find("[", sec_end);
+  }
+}
+
+std::string
+gr_prefs::to_string()
+{
+  gr_config_map_itr sections;
+  gr_config_map_elem_itr options;
+  std::stringstream s;
+
+  for(sections = d_config_map.begin(); sections != d_config_map.end(); sections++) {
+    s << "[" << sections->first << "]" << std::endl;
+    for(options = sections->second.begin(); options != sections->second.end(); options++) {
+      s << options->first << " = " << options->second << std::endl;
+    }
+    s << std::endl;
+  }
+
+  return s.str();
+}
+
+void
+gr_prefs::save()
+{
+  std::string conf = to_string();
+
+  fs::path homedir = fs::path(gr_appdata_path());
+  homedir = homedir/".gnuradio/config.conf";
+  fs::ofstream fout(homedir);
+  fout << conf;
+  fout.close();
 }
 
 char *
@@ -134,8 +212,9 @@ gr_prefs::option_to_env(std::string section, std::string option)
 bool
 gr_prefs::has_section(const std::string &section)
 {
-  size_t t = d_configs.find("[" + section + "]#");
-  return t != std::string::npos;
+  std::string s = section;
+  std::transform(section.begin(), section.end(), s.begin(), ::tolower);
+  return d_config_map.count(s) > 0;
 }
 
 bool
@@ -145,9 +224,14 @@ gr_prefs::has_option(const std::string &section, const std::string &option)
     return true;
 
   if(has_section(section)) {
-    size_t sec = d_configs.find("[" + section + "]#");
-    size_t opt = d_configs.find("#" + option + "=", sec);
-    return opt != std::string::npos;
+    std::string s = section;
+    std::transform(section.begin(), section.end(), s.begin(), ::tolower);
+
+    std::string o = option;
+    std::transform(option.begin(), option.end(), o.begin(), ::tolower);
+
+    gr_config_map_itr sec = d_config_map.find(s);
+    return sec->second.count(o) > 0;
   }
   else {
     return false;
@@ -163,21 +247,38 @@ gr_prefs::get_string(const std::string &section, const std::string &option,
     return std::string(env);
 
   if(has_option(section, option)) {
-    std::string optname = "#" + option + "=";
-    size_t sec = d_configs.find("[" + section + "]#");
-    size_t opt = d_configs.find(optname, sec);
+    std::string s = section;
+    std::transform(section.begin(), section.end(), s.begin(), ::tolower);
 
-    size_t start = opt + optname.size();
-    size_t end = d_configs.find("#", start);
-    size_t len = end - start;
+    std::string o = option;
+    std::transform(option.begin(), option.end(), o.begin(), ::tolower);
 
-    return d_configs.substr(start, len);
+    gr_config_map_itr sec = d_config_map.find(s);
+    gr_config_map_elem_itr opt = sec->second.find(o);
+    return opt->second;
   }
   else {
     return default_val;
   }
 }
 
+void
+gr_prefs::set_string(const std::string &section, const std::string &option,
+                     const std::string &val)
+{
+  std::string s = section;
+  std::transform(section.begin(), section.end(), s.begin(), ::tolower);
+
+  std::string o = option;
+  std::transform(option.begin(), option.end(), o.begin(), ::tolower);
+
+  std::map<std::string, std::string> opt_map = d_config_map[s];
+
+  opt_map[o] = val;
+
+  d_config_map[s] = opt_map;
+}
+
 bool
 gr_prefs::get_bool(const std::string &section, const std::string &option, bool default_val)
 {
@@ -199,6 +300,24 @@ gr_prefs::get_bool(const std::string &section, const std::string &option, bool d
   }
 }
 
+void
+gr_prefs::set_bool(const std::string &section, const std::string &option, bool val)
+{
+  std::string s = section;
+  std::transform(section.begin(), section.end(), s.begin(), ::tolower);
+
+  std::string o = option;
+  std::transform(option.begin(), option.end(), o.begin(), ::tolower);
+
+  std::map<std::string, std::string> opt_map = d_config_map[s];
+
+  std::stringstream sstr;
+  sstr << (val == true);
+  opt_map[o] = sstr.str();
+
+  d_config_map[s] = opt_map;
+}
+
 long
 gr_prefs::get_long(const std::string &section, const std::string &option, long default_val)
 {
@@ -217,6 +336,24 @@ gr_prefs::get_long(const std::string &section, const std::string &option, long d
   }
 }
 
+void
+gr_prefs::set_long(const std::string &section, const std::string &option, long val)
+{
+  std::string s = section;
+  std::transform(section.begin(), section.end(), s.begin(), ::tolower);
+
+  std::string o = option;
+  std::transform(option.begin(), option.end(), o.begin(), ::tolower);
+
+  std::map<std::string, std::string> opt_map = d_config_map[s];
+
+  std::stringstream sstr;
+  sstr << val;
+  opt_map[o] = sstr.str();
+
+  d_config_map[s] = opt_map;
+}
+
 double
 gr_prefs::get_double(const std::string &section, const std::string &option, double default_val)
 {
@@ -235,3 +372,20 @@ gr_prefs::get_double(const std::string &section, const std::string &option, doub
   }
 }
 
+void
+gr_prefs::set_double(const std::string &section, const std::string &option, double val)
+{
+  std::string s = section;
+  std::transform(section.begin(), section.end(), s.begin(), ::tolower);
+
+  std::string o = option;
+  std::transform(option.begin(), option.end(), o.begin(), ::tolower);
+
+  std::map<std::string, std::string> opt_map = d_config_map[s];
+
+  std::stringstream sstr;
+  sstr << val;
+  opt_map[o] = sstr.str();
+
+  d_config_map[s] = opt_map;
+}
diff --git a/gnuradio-core/src/lib/general/gr_prefs.h b/gnuradio-core/src/lib/general/gr_prefs.h
index 68957faab9..4e11d04c5b 100644
--- a/gnuradio-core/src/lib/general/gr_prefs.h
+++ b/gnuradio-core/src/lib/general/gr_prefs.h
@@ -1,6 +1,6 @@
 /* -*- c++ -*- */
 /*
- * Copyright 2006 Free Software Foundation, Inc.
+ * Copyright 2006,2013 Free Software Foundation, Inc.
  *
  * This file is part of GNU Radio
  *
@@ -19,13 +19,20 @@
  * the Free Software Foundation, Inc., 51 Franklin Street,
  * Boston, MA 02110-1301, USA.
  */
+
 #ifndef INCLUDED_GR_PREFS_H
 #define INCLUDED_GR_PREFS_H
 
 #include <gr_core_api.h>
 #include <string>
+#include <map>
 #include <gruel/thread.h>
 
+typedef std::map< std::string, std::map<std::string, std::string> > gr_config_map_t;
+typedef std::map< std::string, std::map<std::string, std::string> >::iterator gr_config_map_itr;
+typedef std::map<std::string, std::string> gr_config_map_elem_t;
+typedef std::map<std::string, std::string>::iterator gr_config_map_elem_itr;
+
 /*!
  * \brief Base class for representing user preferences a la windows INI files.
  * \ingroup misc
@@ -43,6 +50,18 @@ public:
   gr_prefs();
   virtual ~gr_prefs();
 
+  /*!
+   * \brief Returns the configuration options as a string.
+   */
+  std::string to_string();
+
+  /*!
+   * \brief Saves the configuration settings to ${HOME}/.gnuradio/config.conf.
+   *
+   * WARNING: this will overwrite your current config.conf file.
+   */
+  void save();
+
   /*!
    * \brief Does \p section exist?
    */
@@ -60,6 +79,13 @@ public:
 				       const std::string &option,
 				       const std::string &default_val);
 
+  /*!
+   * \brief Set or add a string \p option to \p section with value \p val.
+   */
+  virtual void set_string(const std::string &section,
+                          const std::string &option,
+                          const std::string &val);
+
   /*!
    * \brief If option exists and value can be converted to bool, return it; else default_val.
    */
@@ -67,6 +93,13 @@ public:
 			const std::string &option,
 			bool default_val);
 
+  /*!
+   * \brief Set or add a bool \p option to \p section with value \p val.
+   */
+  virtual void set_bool(const std::string &section,
+			const std::string &option,
+			bool val);
+
   /*!
    * \brief If option exists and value can be converted to long, return it; else default_val.
    */
@@ -74,6 +107,13 @@ public:
 			const std::string &option,
 			long default_val);
 
+  /*!
+   * \brief Set or add a long \p option to \p section with value \p val.
+   */
+  virtual void set_long(const std::string &section,
+			const std::string &option,
+			long val);
+
   /*!
    * \brief If option exists and value can be converted to double, return it; else default_val.
    */
@@ -81,14 +121,22 @@ public:
 			    const std::string &option,
 			    double default_val);
 
+  /*!
+   * \brief Set or add a double \p option to \p section with value \p val.
+   */
+  virtual void set_double(const std::string &section,
+                          const std::string &option,
+                          double val);
+
  protected:
   virtual std::vector<std::string> _sys_prefs_filenames();
   virtual void _read_files();
+  virtual void _convert_to_map(const std::string &conf);
   virtual char * option_to_env(std::string section, std::string option);
 
  private:
   gruel::mutex d_mutex;
-  std::string d_configs;
+  gr_config_map_t d_config_map;
 };
 
 
diff --git a/gnuradio-core/src/lib/general/gr_prefs.i b/gnuradio-core/src/lib/general/gr_prefs.i
index b21d47f3b0..adf567a135 100644
--- a/gnuradio-core/src/lib/general/gr_prefs.i
+++ b/gnuradio-core/src/lib/general/gr_prefs.i
@@ -28,42 +28,39 @@ public:
 
   virtual ~gr_prefs();
 
-  /*!
-   * \brief Does \p section exist?
-   */
+  std::string to_string();
+  void save();
+
   virtual bool has_section(const std::string &section);
 
-  /*!
-   * \brief Does \p option exist?
-   */
   virtual bool has_option(const std::string &section, const std::string &option);
 
-  /*!
-   * \brief If option exists return associated value; else default_val.
-   */
   virtual const std::string get_string(const std::string &section,
 				       const std::string &option,
 				       const std::string &default_val);
+  virtual void set_string(const std::string &section,
+                          const std::string &option,
+                          const std::string &val);
 
-  /*!
-   * \brief If option exists and value can be converted to bool, return it; else default_val.
-   */
   virtual bool get_bool(const std::string &section,
 			const std::string &option,
 			bool default_val);
+  virtual void set_bool(const std::string &section,
+			const std::string &option,
+			bool val);
 
-  /*!
-   * \brief If option exists and value can be converted to long, return it; else default_val.
-   */
   virtual long get_long(const std::string &section,
 			const std::string &option,
 			long default_val);
+  virtual void set_long(const std::string &section,
+			const std::string &option,
+			long val);
 
-  /*!
-   * \brief If option exists and value can be converted to double, return it; else default_val.
-   */
   virtual double get_double(const std::string &section,
 			    const std::string &option,
 			    double default_val);
+  virtual void set_double(const std::string &section,
+                          const std::string &option,
+                          double val);
 };
 
-- 
cgit v1.2.3