tue_config
resolve_functions.cpp
Go to the documentation of this file.
1 #include "resolve_functions.h"
2 
3 #include <vector>
4 #include <ros/package.h>
5 #include <stdlib.h> /* getenv */
6 
7 #include <tue/filesystem/path.h>
8 
9 #include <iostream>
10 #include <iterator>
11 
12 namespace tue
13 {
14 
15 namespace config
16 {
17 
19 {
23 };
24 
25 // ----------------------------------------------------------------------------------------------------
26 
28 {
29  output = "$(";
30  for (auto it = args.cbegin(); it != args.cend(); ++it)
31  {
32  if (it != args.cbegin())
33  output += " ";
34  output += *it;
35  }
36  output += ")";
37 }
38 
39 // ----------------------------------------------------------------------------------------------------
40 
42 {
43  if (args[0] == "rospkg" && args.size() == 2)
44  {
45  if (!config.rospkg)
47 
48  result = ros::package::getPath(args[1]);
49  if (result.empty())
50  {
51  error << "ROS package '" << args[1] << "' unknown.";
52  return resolveResult::failed;
53  }
54 
56  }
57  else if (args[0] == "env" && (args.size() == 2 || args.size() == 3))
58  {
59  if (!config.env)
61 
62  char* env_value;
63  env_value = getenv(args[1].c_str());
64  if (env_value == nullptr)
65  {
66  if (args.size() == 3)
67  {
68  // Default value
69  result = args[2];
71  }
72 
73  error << "Environment variable '" << args[1] << "' unknown.";
74  return resolveResult::failed;
75  }
76 
77  result = env_value;
79  }
80  else if (args[0] == "file" && args.size() == 2)
81  {
82  if (!config.file)
84 
85  const std::string& filename = args[1];
86  if (filename[0] == '/')
87  {
88  result = filename;
90  }
91 
93  if (parent_path.string().empty())
94  result = filename;
95  else
96  result = parent_path.join(filename).string();
97 
99  }
100 
101  error << "Unknown resolve function: '" << args[0] << "' with " << args.size() - 1 << " arguments.";
102 
103  return resolveResult::failed;
104 }
105 
106 // ----------------------------------------------------------------------------------------------------
107 
109 {
111  args.push_back("");
112 
113  bool inner_function_skipped = false;
114 
115  for(; i < str.size();)
116  {
117  char c = str[i];
118 
119  if (c == '$' && (i + 1) < str.size() && str[i + 1] == '(')
120  {
121  // Skip "$("
122  i += 2;
123 
124  std::string arg;
125  resolveResult result = parseResolveFunction(str, source, i, arg, error, config);
126  if (result == resolveResult::failed)
127  return resolveResult::failed;
128  else if (result == resolveResult::skipped)
129  inner_function_skipped = true;
130 
131  args.back() += arg;
132  continue;
133  }
134  else if (c == ')')
135  {
136  ++i;
137 
138  // Check if last argument is empty. If so, remove it
139  if (args.back().empty())
140  args.pop_back();
141 
142  // Check if args are empty. Is so, return false
143  if (args.empty())
144  {
145  error << "Empty resolve function.";
146  return resolveResult::failed;
147  }
148 
149  resolveResult result_code = executeResolvefunction(args, source, result, error, config);
150  if (result_code == resolveResult::skipped)
151  {
152  argsToString(args, result);
153  return result_code;
154  }
155 
156  if (inner_function_skipped)
157  {
158  std::string resolved_args;
159  argsToString(args, resolved_args);
160  error << "Inner resolve function skipped, but not this one: " << resolved_args << ".";
161  return resolveResult::failed;
162  }
163 
164  return result_code;
165  }
166  else if (c == ' ')
167  {
168  if (!args.back().empty())
169  args.push_back("");
170  ++i;
171  }
172  else
173  {
174  args.back() += c;
175  ++i;
176  }
177  }
178 
179  error << "Missing ')'.";
180  return resolveResult::failed;
181 }
182 
183 // ----------------------------------------------------------------------------------------------------
184 
185 bool resolve(const std::string& str, const std::string& source, std::string& result, std::stringstream& error, const ResolveConfig& config)
186 {
187  // Easy way out when nothing needs to be resolved
188  if (config.AllFalse())
189  {
190  result = str;
191  return true;
192  }
193 
194  std::size_t i = 0;
195  while(i < str.size())
196  {
197  std::size_t i_sign = str.find("$(", i);
198  if (i_sign == std::string::npos)
199  {
200  result += str.substr(i);
201  return true;
202  }
203 
204  result += str.substr(i, i_sign - i);
205 
206  // Skip until after "$("
207  i = i_sign + 2;
208 
209  std::string subresult;
210  if (!parseResolveFunction(str, source, i, subresult, error, config)) // failed: 0
211  return false;
212 
213  result += subresult;
214  }
215 
216  return true;
217 }
218 
219 }
220 
221 }
222 
std::string
tue::filesystem::Path
vector
std::string::find
T find(T... args)
std::vector::size
T size(T... args)
iterator
std::stringstream
std::vector::back
T back(T... args)
tue::config::argsToString
void argsToString(const std::vector< std::string > &args, std::string &output)
Definition: resolve_functions.cpp:27
iostream
tue::config::resolveResult
resolveResult
Definition: resolve_functions.cpp:18
tue::config::failed
@ failed
Definition: resolve_functions.cpp:20
std::vector::push_back
T push_back(T... args)
tue::config::resolve
bool resolve(const std::string &str, const std::string &source, std::string &result, std::stringstream &error, const ResolveConfig &config)
Definition: resolve_functions.cpp:185
std::vector::pop_back
T pop_back(T... args)
std::string::substr
T substr(T... args)
path.h
tue::config::parseResolveFunction
resolveResult parseResolveFunction(const std::string &str, const std::string &source, std::size_t &i, std::string &result, std::stringstream &error, const ResolveConfig &config)
Definition: resolve_functions.cpp:108
std::vector::cbegin
T cbegin(T... args)
tue::config::success
@ success
Definition: resolve_functions.cpp:21
std::string::empty
T empty(T... args)
tue::filesystem::Path::string
const std::string & string() const
std::size_t
tue::config::ResolveConfig
Class to config the resolve behaviour of a loader.
Definition: resolve_config.h:16
tue::filesystem::Path::parentPath
Path parentPath() const
std::vector::cend
T cend(T... args)
tue::config::skipped
@ skipped
Definition: resolve_functions.cpp:22
tue::config::executeResolvefunction
resolveResult executeResolvefunction(const std::vector< std::string > &args, const std::string &source, std::string &result, std::stringstream &error, const ResolveConfig &config)
Definition: resolve_functions.cpp:41
tue
tue::filesystem::Path::join
Path join(const Path &path) const
resolve_functions.h
config
tue::config::ReaderWriter config
Definition: sdf_gtest.cpp:9