aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/utils/paths.cpp
diff options
context:
space:
mode:
authorBen Hilburn <ben.hilburn@ettus.com>2015-01-27 16:07:43 -0800
committerBen Hilburn <ben.hilburn@ettus.com>2015-01-27 16:07:43 -0800
commit75d519706b9b0956307a6a4bdc53c36376f19f03 (patch)
treeb2d2144c31c3ea04167ef7e3d1b14f7477c158cf /host/lib/utils/paths.cpp
parent8d0d0d01c0a2a5ed1a01da4360226a64ab8117bc (diff)
downloaduhd-75d519706b9b0956307a6a4bdc53c36376f19f03.tar.gz
uhd-75d519706b9b0956307a6a4bdc53c36376f19f03.tar.bz2
uhd-75d519706b9b0956307a6a4bdc53c36376f19f03.zip
Merging new UHD_IMAGES_DIR utilities and bug fixes.
Also includes NI-USRP Windows Registry Key fixes.
Diffstat (limited to 'host/lib/utils/paths.cpp')
-rw-r--r--host/lib/utils/paths.cpp306
1 files changed, 270 insertions, 36 deletions
diff --git a/host/lib/utils/paths.cpp b/host/lib/utils/paths.cpp
index 3e2bea1c6..e304555bd 100644
--- a/host/lib/utils/paths.cpp
+++ b/host/lib/utils/paths.cpp
@@ -16,37 +16,77 @@
//
#include <uhd/config.hpp>
+#include <uhd/exception.hpp>
+#include <uhd/transport/nirio/nifpga_lvbitx.h>
#include <uhd/utils/paths.hpp>
-#include <boost/tokenizer.hpp>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/bind.hpp>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
-#include <boost/bind.hpp>
+#include <boost/format.hpp>
+#include <boost/regex.hpp>
+#include <boost/tokenizer.hpp>
+
+#include <cstdio>
#include <cstdlib>
+#include <fstream>
+#include <iostream>
+#include <streambuf>
#include <string>
#include <vector>
-#include <cstdlib> //getenv
-#include <cstdio> //P_tmpdir
+
#ifdef BOOST_MSVC
#define USE_GET_TEMP_PATH
#include <windows.h> //GetTempPath
#endif
+#ifdef USE_NIUSRP_WINREG_KEY
+#define NIUSRP_WINREG_KEY "[HKLM\\Software\\National Instruments\\NI-USRP\\DriverBitfilesDir]"
+#endif
+
namespace fs = boost::filesystem;
-/***********************************************************************
- * Get a list of paths for an environment variable
- **********************************************************************/
-static std::string get_env_var(const std::string &var_name, const std::string &def_val = ""){
- const char *var_value_ptr = std::getenv(var_name.c_str());
- return (var_value_ptr == NULL)? def_val : var_value_ptr;
-}
+/*! Get the value of an environment variable.
+ *
+ * The returned std::string is the full environment variable string, and thus
+ * may actually contain multiple fields in the string with delimiters.
+ *
+ * \param var_name The name of the variable to search for.
+ * \param default_val A default string value to use if the path isn't found.
+ * \returns The string value of the environment variable.
+ */
+static std::string get_env_var(const std::string &var_name,
+ const std::string &default_val = "") {
-static std::vector<fs::path> get_env_paths(const std::string &var_name){
+ std::string env_result = default_val;
+ char *env_var_str = NULL;
-/***********************************************************************
- * Determine the paths separator
- **********************************************************************/
+ /* Some versions of MinGW don't expose `_dupenv_s` */
+#if defined(UHD_PLATFORM_WIN32) && !defined(__MINGW32__)
+ size_t len;
+ errno_t err = _dupenv_s(&env_var_str, &len, var_name.c_str());
+ if((not err) and (env_var_str != NULL))
+ env_result = std::string(env_var_str);
+ free(env_var_str);
+#else
+ env_var_str = std::getenv(var_name.c_str());
+ if(env_var_str != NULL)
+ env_result = std::string(env_var_str);
+#endif
+ return env_result;
+}
+
+/*! Get a vector of paths from an environment variable.
+ *
+ * Reads an environment variable, which should contain a list of paths, and
+ * returns a vector of those paths in the form of strings.
+ *
+ * \param var_name The environment variable name to read.
+ * \returns The vector of paths from the environment variable.
+ */
+static std::vector<std::string> get_env_paths(const std::string &var_name){
#ifdef UHD_PLATFORM_WIN32
static const std::string env_path_sep = ";";
#else
@@ -59,40 +99,45 @@ static std::vector<fs::path> get_env_paths(const std::string &var_name){
std::string var_value = get_env_var(var_name);
- //convert to filesystem path, filter blank paths
- std::vector<fs::path> paths;
- if (var_value.empty()) return paths; //FIXME boost tokenizer throws w/ blank strings on some platforms
+ std::vector<std::string> paths;
+
+ //convert to full filesystem path, filter blank paths
+ if (var_value.empty()) return paths;
BOOST_FOREACH(const std::string &path_string, path_tokenizer(var_value)){
if (path_string.empty()) continue;
- paths.push_back(fs::system_complete(path_string));
+ paths.push_back(fs::system_complete(path_string).string());
}
+
return paths;
}
-/***********************************************************************
- * Get a list of special purpose paths
- **********************************************************************/
-std::string uhd::get_pkg_path(void)
-{
- return get_env_var("UHD_PKG_PATH", UHD_PKG_PATH);
-}
+/*! Expand a tilde character to the $HOME path.
+ *
+ * The path passed to this function must start with the tilde character in order
+ * for this function to work properly. If it does not, it will simply return the
+ * original path. The $HOME environment variable must exist.
+ *
+ * \param path The path starting with the tilde character
+ * \returns The same path with the tilde expanded to contents of $HOME.
+ */
+static std::string expand_home_directory(std::string path) {
+ boost::trim(path);
-std::vector<fs::path> get_image_paths(void){
- std::vector<fs::path> paths = get_env_paths("UHD_IMAGE_PATH");
- paths.push_back(fs::path(uhd::get_pkg_path()) / "share" / "uhd" / "images");
- return paths;
-}
+ if(path.empty() || (path[0] != '~')) {
+ return path;
+ }
-std::vector<fs::path> get_module_paths(void){
- std::vector<fs::path> paths = get_env_paths("UHD_MODULE_PATH");
- paths.push_back(fs::path(uhd::get_pkg_path()) / UHD_LIB_DIR / "uhd" / "modules");
- paths.push_back(fs::path(uhd::get_pkg_path()) / "share" / "uhd" / "modules");
- return paths;
+ std::string user_home_path = get_env_var("HOME");
+ path.replace(0, 1, user_home_path);
+
+ return path;
}
/***********************************************************************
* Implement the functions in paths.hpp
**********************************************************************/
+
+
std::string uhd::get_tmp_path(void){
const char *tmp_path = NULL;
@@ -136,3 +181,192 @@ std::string uhd::get_app_path(void){
return uhd::get_tmp_path();
}
+
+std::string uhd::get_pkg_path(void) {
+ return get_env_var("UHD_PKG_PATH", UHD_PKG_PATH);
+}
+
+std::vector<fs::path> uhd::get_module_paths(void){
+ std::vector<fs::path> paths;
+
+ std::vector<std::string> env_paths = get_env_paths("UHD_MODULE_PATH");
+ BOOST_FOREACH(std::string &str_path, env_paths) {
+ paths.push_back(str_path);
+ }
+
+ paths.push_back(fs::path(uhd::get_pkg_path()) / UHD_LIB_DIR / "uhd" / "modules");
+ paths.push_back(fs::path(uhd::get_pkg_path()) / "share" / "uhd" / "modules");
+
+ return paths;
+}
+
+#ifdef UHD_PLATFORM_WIN32
+#include <windows.h>
+/*!
+ * On Windows, query the system registry for the UHD images install path.
+ * If the key isn't found in the registry, an empty string is returned.
+ * \param registry_key_path The registry key to look for.
+ * \return The images path, formatted for windows.
+ */
+std::string _get_images_path_from_registry(const std::string& registry_key_path) {
+ boost::smatch reg_key_match;
+ //If a substring in the search path is enclosed in [] (square brackets) then it is interpreted as a registry path
+ if (not boost::regex_search(registry_key_path, reg_key_match, boost::regex("\\[(.+)\\](.*)", boost::regex::icase)))
+ return std::string();
+ std::string reg_key_path = std::string(reg_key_match[1].first, reg_key_match[1].second);
+ std::string path_suffix = std::string(reg_key_match[2].first, reg_key_match[2].second);
+
+ //Split the registry path into parent, key-path and value.
+ boost::smatch reg_parent_match;
+ if (not boost::regex_search(reg_key_path, reg_parent_match, boost::regex("^(.+?)\\\\(.+)\\\\(.+)$", boost::regex::icase)))
+ return std::string();
+ std::string reg_parent = std::string(reg_parent_match[1].first, reg_parent_match[1].second);
+ std::string reg_path = std::string(reg_parent_match[2].first, reg_parent_match[2].second);
+ std::string reg_val_name = std::string(reg_parent_match[3].first, reg_parent_match[3].second);
+
+ HKEY hkey_parent = HKEY_LOCAL_MACHINE;
+ if (reg_parent == "HKEY_LOCAL_MACHINE") hkey_parent = HKEY_LOCAL_MACHINE;
+ else if (reg_parent == "HKEY_CURRENT_USER") hkey_parent = HKEY_CURRENT_USER;
+ else if (reg_parent == "HKEY_CLASSES_ROOT") hkey_parent = HKEY_CLASSES_ROOT;
+ else if (reg_parent == "HKEY_CURRENT_CONFIG") hkey_parent = HKEY_CURRENT_CONFIG;
+ else if (reg_parent == "HKEY_USERS") hkey_parent = HKEY_CURRENT_USER;
+
+ TCHAR value_buff[1024];
+ DWORD value_buff_size = 1024*sizeof(TCHAR);
+
+ //Get a handle to the key location
+ HKEY hkey_location;
+ if (RegOpenKeyExA(hkey_parent, reg_path.c_str(), NULL, KEY_QUERY_VALUE, &hkey_location) != ERROR_SUCCESS)
+ return std::string();
+
+ //Query key value
+ DWORD dw_type = REG_SZ;
+ if(RegQueryValueExA(hkey_location, reg_val_name.c_str(), NULL, &dw_type, (LPBYTE)value_buff, &value_buff_size) == ERROR_SUCCESS) {
+ RegCloseKey(hkey_location);
+ if (value_buff_size >= 1024*sizeof(TCHAR)) {
+ return std::string();
+ } else {
+ std::string return_value(value_buff, value_buff_size-1); //value_buff_size includes the null terminator
+ return_value += path_suffix;
+ return return_value;
+ }
+ } else {
+ return std::string();
+ }
+}
+#endif /*UHD_PLATFORM_WIN32*/
+
+std::string uhd::get_images_dir(const std::string search_paths) {
+
+ /* This function will check for the existence of directories in this
+ * order:
+ *
+ * 1) `UHD_IMAGES_DIR` environment variable
+ * 2) Any paths passed to this function via `search_paths' (may contain
+ * Windows registry keys)
+ * 3) `UHD package path` / share / uhd / images
+ */
+
+ std::string possible_dir;
+
+ /* We will start by looking for a path indicated by the `UHD_IMAGES_DIR`
+ * environment variable. */
+ std::vector<std::string> env_paths = get_env_paths("UHD_IMAGES_DIR");
+ BOOST_FOREACH(possible_dir, env_paths) {
+ if (fs::is_directory(fs::path(possible_dir))) {
+ return possible_dir;
+ }
+ }
+
+ /* On Windows systems, we may need to modify the `search_paths` parameter
+ * (see below). Making a local copy for const correctness. */
+ std::string _search_paths = search_paths;
+
+#ifdef USE_NIUSRP_WINREG_KEY
+ _search_paths = std::string(NIUSRP_WINREG_KEY) + "," + search_paths;
+#endif
+
+ /* Now we will parse and attempt to qualify the paths in the `search_paths`
+ * parameter. If this is Windows, we will check the system registry for
+ * these strings. */
+ if (!_search_paths.empty()) {
+ std::vector<std::string> search_paths_vector;
+
+ boost::split(search_paths_vector, _search_paths, boost::is_any_of(",;"));
+ BOOST_FOREACH(std::string& search_path, search_paths_vector) {
+
+ boost::algorithm::trim(search_path);
+ if (search_path.empty()) continue;
+
+#ifdef UHD_PLATFORM_WIN32
+ possible_dir = _get_images_path_from_registry(search_path);
+ if (possible_dir.empty()) {
+ //Could not read from the registry due to missing key, invalid
+ //values, etc Just use the search path. The is_directory check
+ //will fail if this is a registry path and we will move on to
+ //the next item in the list.
+ possible_dir = search_path;
+ }
+#else
+ possible_dir = expand_home_directory(search_path);
+#endif
+
+ if (fs::is_directory(fs::path(possible_dir))) {
+ return possible_dir;
+ }
+ }
+ }
+
+ /* Finally, check for the default UHD images installation path. */
+ fs::path pkg_path = fs::path(uhd::get_pkg_path()) / "share" / "uhd" / "images";
+ if (fs::is_directory(pkg_path)) {
+ return pkg_path.string();
+ } else {
+ /* No luck. Return an empty string. */
+ return std::string("");
+ }
+}
+
+std::string uhd::find_image_path(const std::string &image_name, const std::string search_paths){
+ /* If a path was provided on the command-line or as a hint from the caller,
+ * we default to that. */
+ if (fs::exists(image_name)){
+ return fs::system_complete(image_name).string();
+ }
+
+ /* Otherwise, look for the image in the images directory. */
+ std::string images_dir = get_images_dir(search_paths);
+ if (!images_dir.empty()) {
+ fs::path image_path = fs::path(images_dir) / image_name;
+ if (fs::exists(image_path)) {
+ return image_path.string();
+ } else {
+ throw uhd::io_error(
+ "Could not find the image '" + image_name + "' in the image directory " + images_dir
+ + "\nFor more information regarding image paths, please refer to the UHD manual.");
+ }
+ }
+
+ /* If we made it this far, then we didn't find anything. */
+ throw uhd::io_error("Could not find path for image: " + image_name
+ + "\n\n"
+ + "Using images directory: " + images_dir
+ + "\n\n"
+ + "Set the environment variable 'UHD_IMAGES_DIR' appropriately or"
+ + " follow the below instructions to download the images package."
+ + "\n\n"
+ + uhd::print_utility_error("uhd_images_downloader.py"));
+}
+
+std::string uhd::find_utility(std::string name) {
+ return fs::path(fs::path(uhd::get_pkg_path()) / UHD_LIB_DIR / "uhd" / "utils" / name)
+ .string();
+}
+
+std::string uhd::print_utility_error(std::string name){
+ #ifdef UHD_PLATFORM_WIN32
+ return "As an Administrator, please run:\n\n\"" + find_utility(name) + "\"";
+ #else
+ return "Please run:\n\n \"" + find_utility(name) + "\"";
+ #endif
+}