DDS  ver. 3.4
MiscUtils.h
Go to the documentation of this file.
1 // Copyright 2014 GSI, Inc. All rights reserved.
2 //
3 // a set of general helpers
4 //
5 #ifndef MISCUTILS_H
6 #define MISCUTILS_H
7 
8 #include "wordexp.h"
9 // STD
10 #include <algorithm>
11 #include <iostream>
12 // BOOST
13 #include <boost/filesystem.hpp>
14 #include <boost/process.hpp>
15 
21 namespace MiscCommon
22 {
29  {
30  protected:
32  {
33  }
35  {
36  }
37 
38  private:
39  NONCopyable(const NONCopyable&);
40  const NONCopyable& operator=(const NONCopyable&);
41  };
42 
43  class NullType
44  {
45  };
52  {
53  public:
55  : m_unset(false)
56  {
57  }
58  auto_setenv(const std::string& _VarName, const std::string& _NewValue)
59  : m_unset(false)
60  {
61  m_sVarName = _VarName;
62  m_sNewValue = _NewValue;
63 
64  char* chTmp = getenv(m_sVarName.c_str());
65  if (chTmp)
66  m_sOldValue = chTmp;
67  else
68  m_unset = true;
69  // TODO: check error code
70  setenv(m_sVarName.c_str(), m_sNewValue.c_str(), 1);
71  }
73  {
74  unset();
75  }
76 
77  public:
78  void set(const std::string& _VarName, const std::string& _NewValue)
79  {
80  unset();
81 
82  m_sVarName = _VarName;
83  m_sNewValue = _NewValue;
84 
85  char* chTmp = getenv(m_sVarName.c_str());
86  if (chTmp)
87  m_sOldValue = chTmp;
88  else
89  m_unset = true;
90  // TODO: check error code
91  setenv(m_sVarName.c_str(), m_sNewValue.c_str(), 1);
92  }
93  void unset()
94  {
95  if (m_unset)
96  {
97  m_unset = false;
98  unsetenv(m_sVarName.c_str());
99  return;
100  }
101 
102  if (!m_sVarName.empty())
103  {
104  m_sVarName.clear();
105  setenv(m_sVarName.c_str(), m_sOldValue.c_str(), 1);
106  }
107  }
108 
109  private:
110  std::string m_sVarName;
111  std::string m_sNewValue;
112  std::string m_sOldValue;
113  bool m_unset;
114  };
115 
124  template <typename _T>
125  _T* smart_append(_T* _pString, const typename _T::value_type _ItemToAdd)
126  {
127  if (!_pString)
128  return _pString;
129 
130  if (_pString->empty() || (*_pString)[_pString->size() - 1] != _ItemToAdd)
131  _pString->push_back(_ItemToAdd);
132 
133  return _pString;
134  }
135 
144  template <typename _T>
145  _T& trim_right(_T* _pString, const typename _T::value_type& _chWhat)
146  {
147  return _pString->erase(_pString->find_last_not_of(_chWhat) + 1);
148  }
149 
158  template <typename _T>
159  _T& trim_left(_T* _pString, const typename _T::value_type& _chWhat)
160  {
161  return _pString->erase(0, _pString->find_first_not_of(_chWhat));
162  }
163 
172  template <typename _T>
173  _T& trim(_T* _pString, const typename _T::value_type& _chWhat)
174  {
175  return trim_right(&trim_left(_pString, _chWhat), _chWhat);
176  }
177 
187  template <typename _T>
188  _T& replace(_T* _pString, const _T& _what, const _T& _with)
189  {
190  typename _T::size_type pos = 0;
191  typename _T::size_type withLen = _with.length();
192  typename _T::size_type whatLen = _what.length();
193  while ((pos = _pString->find(_what, pos)) != _T::npos)
194  {
195  _pString->replace(pos, _what.length(), _with);
196  if (withLen > whatLen)
197  pos += withLen - whatLen + 1;
198  }
199  return (*_pString);
200  }
201 
202  // HACK: because of the bug in gcc 3.3 we need to use this nasty ToLower and ToUpper instead of direct calls of
203  // tolower (tolower.. is inline in this version
204  // of std lib)...
205  struct ToLower
206  {
207  char operator()(char c) const
208  {
209  return std::tolower(c);
210  }
211  };
212  struct ToUpper
213  {
214  char operator()(char c) const
215  {
216  return std::toupper(c);
217  }
218  };
219  struct IsDigit : std::unary_function<int, int>
220  {
221  int operator()(int c) const
222  {
223  return std::isdigit(c);
224  }
225  };
226 
234  template <typename _T>
235  _T& to_upper(_T& _str)
236  {
237  std::transform(_str.begin(), _str.end(), _str.begin(), ToUpper());
238  return _str;
239  }
240 
248  template <typename _T>
249  _T& to_lower(_T& _str)
250  {
251  std::transform(_str.begin(), _str.end(), _str.begin(), ToLower());
252  return _str;
253  }
254 
255  inline void parseExe(const std::string& _exeStr,
256  const std::string& _exePrefix,
257  std::string& _filePath,
258  std::string& _filename,
259  std::string& _cmdStr)
260  {
261  // wordexp will always fail with WRDE_SYNTAX if you have set the SIGCHLD signal to be ignored like so:
262  // signal(SIGCHLD, SIG_IGN). A library may be doing this without your knowledge. Presumably the implementation
263  // of wordexp on OS X actually spawns a shell as a child process to do the parsing. The solution is to call
264  // signal(SIGCHLD, SIG_DFL) before wordexp. You can restore signal(SIGCHLD, SIG_IGN) afterward.
265  boost::process::posix::sighandler_t old_sig = signal(SIGCHLD, SIG_IGN);
266  signal(SIGCHLD, SIG_DFL);
267 
268  // Expand the string for the program to extract exe name and command line arguments
269  wordexp_t result;
270  int err = wordexp(_exeStr.c_str(), &result, 0);
271 
272  // restore old signal
273  signal(SIGCHLD, old_sig);
274 
275  switch (err)
276  {
277  case 0:
278  {
279  _filePath = result.we_wordv[0];
280 
281  boost::filesystem::path exeFilePath(_filePath);
282 
283  if (!exeFilePath.is_absolute() && exeFilePath.has_parent_path())
284  throw std::runtime_error(
285  "Relative paths are not supported: " + _filePath +
286  ". Use either absolute path or executable name which will be searched in PATH.");
287 
288  _filename = exeFilePath.filename().generic_string();
289 
290  // If no absolute path is given, search executable in PATH
291  if (!exeFilePath.is_absolute())
292  {
293  boost::filesystem::path exePath = boost::process::search_path(_filename);
294  _filePath = exePath.generic_string();
295  }
296 
297  _cmdStr = (_exePrefix.empty()) ? _filePath : (_exePrefix + _filename);
298  for (size_t i = 1; i < result.we_wordc; ++i)
299  {
300  _cmdStr += " ";
301  _cmdStr += result.we_wordv[i];
302  }
303 
304  wordfree(&result);
305  }
306  break;
307  case WRDE_NOSPACE:
308  // If the error was WRDE_NOSPACE,
309  // then perhaps part of the result was allocated.
310  throw std::runtime_error("memory error occurred while processing the user's executable path: " +
311  _exeStr);
312  break;
313 
314  case WRDE_BADCHAR:
315  throw std::runtime_error("Illegal occurrence of newline or one of |, &, ;, <, >, (, ), {, } in " +
316  _exeStr);
317  break;
318 
319  case WRDE_BADVAL:
320  throw std::runtime_error(
321  "An undefined shell variable was referenced, and the WRDE_UNDEF flag told us to "
322  "consider this an error in " +
323  _exeStr);
324  break;
325 
326  case WRDE_CMDSUB:
327  throw std::runtime_error(
328  "Command substitution occurred, and the WRDE_NOCMD flag told us to consider this an error in " +
329  _exeStr);
330  break;
331  case WRDE_SYNTAX:
332  throw std::runtime_error("Shell syntax error, such as unbalanced parentheses or unmatched quotes in " +
333  _exeStr);
334  break;
335 
336  default: // Some other error.
337  throw std::runtime_error("failed to process the user's executable path: " + _exeStr);
338  }
339  }
340 }; // namespace MiscCommon
341 #endif
_T * smart_append(_T *_pString, const typename _T::value_type _ItemToAdd)
appends character _ItemToAdd to the string _pString if there is no such suffix on the end of _pString...
Definition: MiscUtils.h:125
_T & replace(_T *_pString, const _T &_what, const _T &_with)
finds elements in a string match a specified string and replaces it.
Definition: MiscUtils.h:188
void parseExe(const std::string &_exeStr, const std::string &_exePrefix, std::string &_filePath, std::string &_filename, std::string &_cmdStr)
Definition: MiscUtils.h:255
_T & trim_left(_T *_pString, const typename _T::value_type &_chWhat)
trims leading characters from the string.
Definition: MiscUtils.h:159
A helper class. Helps to automatically track environment variables.
Definition: MiscUtils.h:51
Definition: MiscUtils.h:212
_T & to_lower(_T &_str)
convert string to lower case.
Definition: MiscUtils.h:249
_T & trim_right(_T *_pString, const typename _T::value_type &_chWhat)
trims trailing characters from the string.
Definition: MiscUtils.h:145
auto_setenv()
Definition: MiscUtils.h:54
Class which makes child to be non-copyable object.
Definition: MiscUtils.h:28
_T & to_upper(_T &_str)
convert string to upper case.
Definition: MiscUtils.h:235
char operator()(char c) const
Definition: MiscUtils.h:214
~auto_setenv()
Definition: MiscUtils.h:72
~NONCopyable()
Definition: MiscUtils.h:34
auto_setenv(const std::string &_VarName, const std::string &_NewValue)
Definition: MiscUtils.h:58
_T & trim(_T *_pString, const typename _T::value_type &_chWhat)
trims trailing and leading characters from the string.
Definition: MiscUtils.h:173
Definition: MiscUtils.h:43
#define _T(s)
Use TCHAR instead of char or wchar_t. It will be appropriately translated.
Definition: def.h:85
NONCopyable()
Definition: MiscUtils.h:31
int operator()(int c) const
Definition: MiscUtils.h:221
Definition: MiscUtils.h:219
void unset()
Definition: MiscUtils.h:93
void set(const std::string &_VarName, const std::string &_NewValue)
Definition: MiscUtils.h:78
Definition: MiscUtils.h:205
char operator()(char c) const
Definition: MiscUtils.h:207
Miscellaneous functions and helpers are located here.
Definition: BOOST_FILESYSTEM.h:21