Imported Upstream version 1.0beta3
[platform/upstream/syncevolution.git] / src / syncevo / util.h
1 /*
2  * Copyright (C) 2008-2009 Patrick Ohly <patrick.ohly@gmx.de>
3  * Copyright (C) 2009 Intel Corporation
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) version 3.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18  * 02110-1301  USA
19  */
20
21 #ifndef INCL_SYNCEVOLUTION_UTIL
22 # define INCL_SYNCEVOLUTION_UTIL
23
24 #include <syncevo/SyncML.h>
25
26 #include <boost/algorithm/string/case_conv.hpp>
27 #include <boost/algorithm/string/predicate.hpp>
28 #include <boost/function.hpp>
29
30 #include <stdarg.h>
31
32 #include <vector>
33 #include <sstream>
34 #include <string>
35 #include <utility>
36 #include <exception>
37 #include <list>
38
39 #include <syncevo/declarations.h>
40 SE_BEGIN_CXX
41 using namespace std;
42
43 class Logger;
44
45 /** case-insensitive less than for assoziative containers */
46 template <class T> class Nocase : public std::binary_function<T, T, bool> {
47 public:
48     bool operator()(const T &x, const T &y) const { return boost::ilexicographical_compare(x, y); }
49 };
50
51 /** case-insensitive equals */
52 template <class T> class Iequals : public std::binary_function<T, T, bool> {
53 public:
54     bool operator()(const T &x, const T &y) const { return boost::iequals(x, y); }
55 };
56
57 /** shorthand, primarily useful for BOOST_FOREACH macro */
58 typedef pair<string, string> StringPair;
59 typedef map<string, string> StringMap;
60
61 /**
62  * remove multiple slashes in a row and dots directly after a slash if not followed by filename,
63  * remove trailing /
64  */
65 string normalizePath(const string &path);
66
67 /**
68  * convert relative path to canonicalized absolute path
69  * @param path will be turned into absolute path if possible, otherwise left unchanged
70  * @return true if conversion is successful, false otherwise(errno will be set)
71  */
72 bool relToAbs(string &path);
73
74 /** ensure that m_path is writable, otherwise throw error */
75 void mkdir_p(const string &path);
76
77 inline bool rm_r_all(const string &path, bool isDir) { return true; }
78
79 /**
80  * remove a complete directory hierarchy; invoking on non-existant directory is okay
81  * @param path     relative or absolute path to be removed
82  * @param filter   an optional callback which determines whether an entry really is
83  *                 to be deleted (return true in that case); called with full path
84  *                 to entry and true if known to be a directory
85  */
86 void rm_r(const string &path, boost::function<bool (const string &,
87                                                     bool)> filter = rm_r_all);
88
89 /**
90  * copy complete directory hierarchy
91  *
92  * If the source is a directory, then the target
93  * also has to be a directory name. It will be
94  * created if necessary.
95  *
96  * Alternatively, both names may refer to files.
97  * In that case the directory which is going to
98  * contain the target file must exist.
99  *
100  * @param from     source directory or file
101  * @param to       target directory or file (must have same type as from)
102  */
103 void cp_r(const string &from, const string &to);
104
105 /** true if the path refers to a directory */
106 bool isDir(const string &path);
107
108 /**
109  * try to read a file into the given string, throw exception if fails
110  *
111  * @param filename     absolute or relative file name
112  * @retval content     filled with file content
113  * @return true if file could be read
114  */
115 bool ReadFile(const string &filename, string &content);
116
117 enum ExecuteFlags {
118     EXECUTE_NO_STDERR = 1<<0,       /**< suppress stderr of command */
119     EXECUTE_NO_STDOUT = 1<<1        /**< suppress stdout of command */
120 };
121
122 /**
123  * system() replacement
124  *
125  * If called without output redirection active (see LogRedirect),
126  * then it will simply call system(). If output redirection is
127  * active, the command is executed in a forked process without
128  * blocking the parent process and the parent reads the output,
129  * passing it through LogRedirect for processing.
130  *
131  * This is necessary to capture all output reliably: LogRedirect
132  * ensures that we don't deadlock, but to achieve that, it drops
133  * data when the child prints too much of it.
134  *
135  * @param cmd      command including parameters, without output redirection
136  * @param flags    see ExecuteFlags
137  * @return same as in system(): use WEXITSTATUS() et.al. to decode it
138  */
139 int Execute(const std::string &cmd, ExecuteFlags flags) throw();
140
141 /**
142  * Simple string hash function, derived from Dan Bernstein's algorithm.
143  */
144 unsigned long Hash(const char *str);
145 unsigned long Hash(const std::string &str);
146
147 /**
148  * SHA-256 implementation, returning hash as lowercase hex string (like sha256sum).
149  * Might not be available, in which case it raises an exception.
150  */
151 std::string SHA_256(const std::string &in);
152
153 /**
154  * This is a simplified implementation of a class representing and calculating
155  * UUIDs v4 inspired from RFC 4122. We do not use cryptographic pseudo-random
156  * numbers, instead we rely on rand/srand.
157  *
158  * We initialize the random generation with the system time given by time(), but
159  * only once.
160  *
161  * Instantiating this class will generate a new unique UUID, available afterwards
162  * in the base string class.
163  */
164 class UUID : public string {
165  public:
166     UUID();
167 };
168
169 /**
170  * A C++ wrapper around readir() which provides the names of all
171  * directory entries, excluding . and ..
172  *
173  */
174 class ReadDir {
175  public:
176     ReadDir(const string &path, bool throwError = true);
177
178     typedef vector<string>::const_iterator const_iterator;
179     typedef vector<string>::iterator iterator;
180     iterator begin() { return m_entries.begin(); }
181     iterator end() { return m_entries.end(); }
182     const_iterator begin() const { return m_entries.begin(); }
183     const_iterator end() const { return m_entries.end(); }
184
185     /**
186      * check whether directory contains entry, returns full path
187      * @param caseInsensitive    ignore case, pick first entry which matches randomly
188      */
189     string find(const string &entry, bool caseSensitive);
190
191  private:
192     string m_path;
193     vector<string> m_entries;
194 };
195
196 /**
197  * Using this macro ensures that tests, even if defined in
198  * object files which are not normally linked into the test
199  * binary, are included in the test suite under the group
200  * "SyncEvolution".
201  *
202  * Use it like this:
203  * @verbatim
204    #include "config.h"
205    #ifdef ENABLE_UNIT_TESTS
206    # include "test.h"
207    class Foo : public CppUnit::TestFixture {
208        CPPUNIT_TEST_SUITE(foo);
209        CPPUNIT_TEST(testBar);
210        CPPUNIT_TEST_SUITE_END();
211
212      public:
213        void testBar();
214    };
215    # SYNCEVOLUTION_TEST_SUITE_REGISTRATION(classname)
216    #endif
217    @endverbatim
218  */
219 #define SYNCEVOLUTION_TEST_SUITE_REGISTRATION( ATestFixtureType ) \
220     CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ATestFixtureType, "SyncEvolution" ); \
221     extern "C" { int funambolAutoRegisterRegistry ## ATestFixtureType = 12345; }
222
223 std::string StringPrintf(const char *format, ...)
224 #ifdef __GNUC__
225         __attribute__((format(printf, 1, 2)))
226 #endif
227 ;
228 std::string StringPrintfV(const char *format, va_list ap);
229
230 /**
231  * an exception which records the source file and line
232  * where it was thrown
233  *
234  * @TODO add function name
235  */
236 class Exception : public std::runtime_error
237 {
238  public:
239     Exception(const std::string &file,
240                            int line,
241                            const std::string &what) :
242     std::runtime_error(what),
243         m_file(file),
244         m_line(line)
245         {}
246     ~Exception() throw() {}
247     const std::string m_file;
248     const int m_line;
249
250     /**
251      * Convenience function, to be called inside a catch(..) block.
252      *
253      * Rethrows the exception to determine what it is, then logs it as
254      * an error. Turns certain known exceptions into the corresponding
255      * status code if status still was STATUS_OK when called.
256      * Returns updated status code.
257      *
258      * @param logger    the class which does the logging
259      */
260     static SyncMLStatus handle(SyncMLStatus *status = NULL, Logger *logger = NULL);
261     static SyncMLStatus handle(Logger *logger) { return handle(NULL, logger); }
262 };
263
264 /**
265  * StatusException by wrapping a SyncML status
266  */
267 class StatusException : public Exception
268 {
269 public:
270     StatusException(const std::string &file,
271                     int line,
272                     const std::string &what,
273                     SyncMLStatus status)
274         : Exception(file, line, what), m_status(status)
275     {}
276
277     SyncMLStatus syncMLStatus() const { return m_status; }
278 protected:
279     SyncMLStatus m_status;
280 };
281
282 /**
283  * replace ${} with environment variables, with
284  * XDG_DATA_HOME, XDG_CACHE_HOME and XDG_CONFIG_HOME having their normal
285  * defaults
286  */
287 std::string SubstEnvironment(const std::string &str);
288
289 inline string getHome() {
290     const char *homestr = getenv("HOME");
291     return homestr ? homestr : ".";
292 }
293
294 /**
295  * Parse a separator splitted set of strings src, the separator itself is
296  * escaped by a backslash. Spaces around the separator is also stripped.
297  * */
298 std::vector<std::string> unescapeJoinedString (const std::string &src, char separator);
299
300 /**
301  * Temporarily set env variable, restore old value on destruction.
302  * Useful for unit tests which depend on the environment.
303  */
304 class ScopedEnvChange
305 {
306  public:
307     ScopedEnvChange(const string &var, const string &value);
308     ~ScopedEnvChange();
309  private:
310     string m_var, m_oldval;
311     bool m_oldvalset;
312 };
313
314 std::string getCurrentTime();
315
316 /** throw a normal SyncEvolution Exception, including source information */
317 #define SE_THROW(_what) \
318     SE_THROW_EXCEPTION(Exception, _what)
319
320 /** throw a class which accepts file, line, what parameters */
321 #define SE_THROW_EXCEPTION(_class,  _what) \
322     throw _class(__FILE__, __LINE__, _what)
323
324 /** throw a class which accepts file, line, what parameters and status parameters*/
325 #define SE_THROW_EXCEPTION_STATUS(_class,  _what, _status) \
326     throw _class(__FILE__, __LINE__, _what, _status)
327
328 SE_END_CXX
329 #endif // INCL_SYNCEVOLUTION_UTIL