Commit a9ec30d3e792b2bfaf2cd6b54c4ccb74b3e2dada

Authored by Jürgen Knödlseder
1 parent b95148b4

Handle ~ sequences in gammalib::expand_env (#1580).

gammalib::expand_env replaces ~ or ~user by the user's home directory, ~+ by the value of the PWD environment variable and ~- by the value of the OLDPWD variable. If the user or the PWD or OLDPWD variable are not found, no replacement is done.
Update change-log.
ChangeLog
... ... @@ -3,6 +3,7 @@
3 3 * Version 1.0.0 released
4 4 =========================
5 5  
  6 + Handle ~ in filenames (#1580)
6 7 Perform __init__.py creation only in build step (#1569)
7 8 Remove access by name methods from GSkyRegions (#1564)
8 9 Resolve Python test problem on El Capitan (#1563)
... ...
... ... @@ -2,7 +2,7 @@ New Features and Important Changes in GammaLib 1.0.0
2 2  
3 3 Author(s) : Juergen Knoedlseder
4 4  
5   -19 November 2015
  5 +22 November 2015
6 6  
7 7  
8 8 1. Introduction
... ... @@ -82,7 +82,8 @@ where this access is needed (#1564):
82 82  
83 83 13. Support module
84 84 ------------------
85   -None
  85 +The gammalib::expand_env() function now handles ~, ~user, ~+ and ~- following the
  86 +logic implemented for the bash shell.
86 87  
87 88  
88 89 14. XML module
... ...
src/support/GTools.cpp
... ... @@ -35,6 +35,7 @@
35 35 #include <sys/select.h> // select() function
36 36 #include <sys/types.h>
37 37 #include <sys/socket.h> // recv() function
  38 +#include <pwd.h>
38 39 #include <cmath>
39 40 #include <cfloat>
40 41 #include <cctype>
... ... @@ -114,6 +115,12 @@ std::string gammalib::strip_chars(const std::string&amp; arg,
114 115 * ${\<name\>}, $(\<name\>) and $\<name\> (in the last case the terminating
115 116 * delimiter is either a / or a blank character or the end of the string).
116 117 * Environment variables occuring within single quotes (') are ignored.
  118 + * Environment variables that do not exist will be kept as specified.
  119 + *
  120 + * The method also replaces ~ or ~user by the user's home directory, ~+
  121 + * by the value of the PWD environment variable and ~- by the value of the
  122 + * OLDPWD variable. If the user or the PWD or OLDPWD variable are not found,
  123 + * no replacement is done.
117 124 *
118 125 * This function has been inspired by the function ape_util_expand_env_var
119 126 * from ape_util.c in the ape software developed at HEASARC.
... ... @@ -121,9 +128,9 @@ std::string gammalib::strip_chars(const std::string&amp; arg,
121 128 std::string gammalib::expand_env(const std::string& arg)
122 129 {
123 130 // Set environment variable delimiters
124   - static const char* begin_delim[] = { "$ENV{", "$ENV(", "${", "$(", "$" };
125   - static const char* end_delim[] = { "}", ")", "}", ")", "/" };
126   - static const int num_delim = 5;
  131 + static const char* begin_delim[] = { "$ENV{", "$ENV(", "${", "$(", "$", "~" };
  132 + static const char* end_delim[] = { "}", ")", "}", ")", "/", "/" };
  133 + static const int num_delim = 6;
127 134  
128 135 // Initialise result with argument
129 136 std::string result = arg;
... ... @@ -171,7 +178,7 @@ std::string gammalib::expand_env(const std::string&amp; arg)
171 178 if (begin_length > 0) {
172 179  
173 180 // Search for the termination delimiter of the environment
174   - // variable. There is a special case for delimiter 4:
  181 + // variable. There is a special case for delimiters 4 and 5:
175 182 // It has always an end_length of zero as the / is not a real
176 183 // delimiter, but just an indicator that the environment variable
177 184 // ends. Another indicator is a blank. If the end of the
... ... @@ -179,7 +186,7 @@ std::string gammalib::expand_env(const std::string&amp; arg)
179 186 size_t i_start = index + begin_length;
180 187 size_t i_end = i_start;
181 188 size_t end_length = 0;
182   - if (delim_idx == 4) {
  189 + if (delim_idx == 4 || delim_idx == 5) {
183 190 while (i_end < result.length() &&
184 191 result.compare(i_end, 1, "/") != 0 &&
185 192 result.compare(i_end, 1, " ") != 0) {
... ... @@ -196,22 +203,53 @@ std::string gammalib::expand_env(const std::string&amp; arg)
196 203  
197 204 // If termination delimiter has been found then expand the
198 205 // environment variable
199   - if (i_end < result.length() || delim_idx == 4) {
  206 + if (i_end < result.length() || delim_idx == 4 || delim_idx == 5) {
200 207  
201 208 // Extract environment variable name
202 209 std::string name = result.substr(i_start, i_end-i_start);
203 210 size_t name_length = name.length();
204 211  
205   - // Erase delimiters and environment variable
206   - result.erase(index, begin_length+name_length+end_length);
  212 + // Initialise pointer on environment variable
  213 + const char* env = NULL;
  214 +
  215 + // Handle ~
  216 + if (delim_idx == 5) {
  217 + if (name_length == 0) {
  218 + if ((env = std::getenv("HOME")) == NULL) {
  219 + struct passwd *pw = getpwuid(getuid());
  220 + if (pw != NULL) {
  221 + env = pw->pw_dir;
  222 + }
  223 + }
  224 + }
  225 + else {
  226 + if (name == "+") {
  227 + env = std::getenv("PWD");
  228 + }
  229 + else if (name == "-") {
  230 + env = std::getenv("OLDPWD");
  231 + }
  232 + else {
  233 + struct passwd *pw = getpwnam(name.c_str());
  234 + if (pw != NULL) {
  235 + env = pw->pw_dir;
  236 + }
  237 + }
  238 + }
  239 + }
207 240  
208   - // Get the environment variable from the operating system
209   - const char* env = std::getenv(name.c_str());
  241 + // ... otherwise get the environment variable
  242 + else {
  243 + env = std::getenv(name.c_str());
  244 + }
210 245  
211 246 // If the environment variable has been found then replace
212 247 // it by its value
213 248 if (env != NULL) {
214 249  
  250 + // Erase delimiters and environment variable
  251 + result.erase(index, begin_length+name_length+end_length);
  252 +
215 253 // Set replacement string and its length
216 254 std::string replace(env);
217 255 size_t replace_length = replace.length();
... ... @@ -224,6 +262,12 @@ std::string gammalib::expand_env(const std::string&amp; arg)
224 262  
225 263 } // endif: environment variable has been found
226 264  
  265 + // If no environment variable has been found then set
  266 + // index=i_end+1
  267 + else {
  268 + index = i_end + 1;
  269 + }
  270 +
227 271 } // endif: termination delimiter found
228 272  
229 273 // If no environment variable has been found then set index=i_end+1
... ...
test/test_GSupport.cpp
... ... @@ -170,14 +170,14 @@ void TestGSupport::test_expand_env(void)
170 170  
171 171 // Non existing environment variable within string
172 172 s_in = "My $(HOMEIXYZ) is my castle.";
173   - s_ref = "My is my castle.";
  173 + s_ref = "My $(HOMEIXYZ) is my castle.";
174 174 s_out = gammalib::expand_env(s_in);
175 175 test_assert(s_out == s_ref,"Non existing environment variable within string",
176 176 "Unexpected string \""+s_out+"\" (expected \""+s_ref+"\")");
177 177  
178 178 // Empty environment variable within string
179 179 s_in = "My $() is my castle.";
180   - s_ref = "My is my castle.";
  180 + s_ref = "My $() is my castle.";
181 181 s_out = gammalib::expand_env(s_in);
182 182 test_assert(s_out == s_ref,"Empty environment variable within string",
183 183 "Unexpected string \""+s_out+"\" (expected \""+s_ref+"\")");
... ... @@ -217,11 +217,19 @@ void TestGSupport::test_expand_env(void)
217 217 test_assert(s_out == s_ref,"$ENV{HOME}${HOME}$ENV(HOME)$(HOME) only string",
218 218 "Unexpected string \""+s_out+"\" (expected \""+s_ref+"\")");
219 219  
220   - // Debugging
221   - //std::cout << std::endl;
222   - //std::cout << s_in << std::endl;
223   - //std::cout << s_ref << std::endl;
224   - //std::cout << s_out << std::endl;
  220 + // Test ~
  221 + s_in = "My castle is ~";
  222 + s_ref = gammalib::expand_env("My castle is $(HOME)");
  223 + s_out = gammalib::expand_env(s_in);
  224 + test_assert(s_out == s_ref,"String with ~",
  225 + "Unexpected string \""+s_out+"\" (expected \""+s_ref+"\")");
  226 +
  227 + // Test ~+
  228 + s_in = "My castle is ~+";
  229 + s_ref = gammalib::expand_env("My castle is $(PWD)");
  230 + s_out = gammalib::expand_env(s_in);
  231 + test_assert(s_out == s_ref,"String with ~+",
  232 + "Unexpected string \""+s_out+"\" (expected \""+s_ref+"\")");
225 233  
226 234 // Exit test
227 235 return;
... ...