]> sourceware.org Git - systemtap.git/blame - util.h
PR23860: reduce stack pressure from format strings
[systemtap.git] / util.h
CommitLineData
42e38653
DB
1#ifndef UTIL_H
2#define UTIL_H
3
58a834b1 4#include "config.h"
fce2d171 5#include <cstdlib>
60d98537 6#include <cstring>
5e3b8687 7#include <cerrno>
1b78aef5
DS
8#include <string>
9#include <vector>
72dbc915
FCE
10#include <iostream>
11#include <sstream>
12#include <stdexcept>
3f99432c 13#include <cctype>
e4e3d6b7 14#include <set>
e1e8b44e 15#include <iomanip>
05fb3e0c 16#include <map>
004f2b9c 17#include <algorithm>
593f09eb 18#include <limits>
004f2b9c 19
a69b4b55 20extern "C" {
52c2652f 21#if ENABLE_NLS
58a834b1
LB
22#include <libintl.h>
23#include <locale.h>
52c2652f 24#endif
a69b4b55 25#include <signal.h>
f13fc0db 26#include <stdint.h>
aeb9cc10 27#include <spawn.h>
e1e8b44e 28#include <assert.h>
3f95ed01 29#include <poll.h>
f13fc0db 30}
1b78aef5 31
0f263207
JS
32// Sanity check C++11 support. We're only requiring GCC 4.4's level of
33// functionality, so trust either __cplusplus or the GNUC macros.
34#if !(__cplusplus >= 201103L || \
35 (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)))
36#error "C++11 support is required!"
37#endif
38
d6d4dc4b
JS
39// NB: GCC didn't add C++11 final/override until 4.7, but until then it also
40// only had __cplusplus=1 regardless of -std (GCC PR1773). So checking new
41// __cplusplus is probably good enough here; otherwise we should autoconf it.
42#if __cplusplus >= 201103L
43#define cxx_final final
44#define cxx_override override
45#else
46#define cxx_final
47#define cxx_override
48#endif
49
3892d516 50#include "privilege.h"
47d349b1 51#include "stringtable.h"
f2013cc9 52
58a834b1
LB
53#if ENABLE_NLS
54#define _(string) gettext(string)
55#define _N(string, string_plural, count) \
56 ngettext((string), (string_plural), (count))
57#else
58#define _(string) (string)
59#define _N(string, string_plural, count) \
60 ( (count) == 1 ? (string) : (string_plural) )
61#endif
62#define _F(format, ...) autosprintf(_(format), __VA_ARGS__)
63#define _NF(format, format_plural, count, ...) \
64 autosprintf(_N((format), (format_plural), (count)), __VA_ARGS__)
9e1a2390
JL
65#define _STRINGIFY_MORE(s) #s
66#define _STRINGIFY(s) _STRINGIFY_MORE(s)
a22da505 67#define ERR_SRC (std::string(__FILE__) + ":" + _STRINGIFY(__LINE__))
9e1a2390
JL
68#define SEMANTIC_ERROR(...) semantic_error(ERR_SRC, __VA_ARGS__)
69#define PARSE_ERROR(...) parse_error(ERR_SRC, __VA_ARGS__)
58a834b1 70
72dbc915 71const char *get_home_directory(void);
b12c8986 72size_t get_file_size(const std::string &path);
a5751672 73size_t get_file_size(int fd);
b12c8986 74bool file_exists (const std::string &path);
f3fdcc93 75bool dir_exists(const std::string &path);
e16dc041
JS
76bool copy_file(const std::string& src, const std::string& dest,
77 bool verbose=false);
3b6f3bbb 78int create_dir(const char *dir, int mode = 0777);
98f552c2 79int remove_file_or_dir(const char *dir);
3892d516 80extern "C" gid_t get_gid (const char *group_name);
438b5a40 81int appendenv (const char *env_name, const std::string source);
0da3e7a0 82bool in_group_id (gid_t target_gid);
85007c04 83std::string getmemusage ();
1b78aef5 84void tokenize(const std::string& str, std::vector<std::string>& tokens,
9c269440 85 const std::string& delimiters = " ");
49dbe419 86void tokenize_full(const std::string& str, std::vector<std::string>& tokens,
9c269440 87 const std::string& delimiters = " ");
91699a70 88void tokenize_cxx(const std::string& str, std::vector<std::string>& tokens);
004f2b9c 89std::vector<std::pair<const char*,int> > split_lines(const char *buf, size_t n);
0a567f6d 90std::string find_executable(const std::string& name);
63b4fd14 91std::string find_executable(const std::string& name,
05fb3e0c 92 const std::string& sysroot,
0a567f6d 93 const std::map<std::string,std::string>& sysenv,
63b4fd14 94 const std::string& env_path = "PATH");
dbe9d133
JL
95bool is_fully_resolved(const std::string& name,
96 const std::string& sysroot,
97 const std::map<std::string,std::string>& sysenv,
98 const std::string& env_path = "PATH");
8c711d30 99const std::string cmdstr_quoted(const std::string& cmd);
38bf68a8 100const std::string detox_path(const std::string& str);
5eea6ed1 101const std::string cmdstr_join(const std::vector<std::string>& cmds);
8fdd1f2e
DS
102const std::string join(const std::vector<std::string>& cmds,
103 const std::string& delim);
01cc94dc 104int stap_waitpid(int verbose, pid_t pid);
20f90026 105pid_t stap_spawn(int verbose, const std::vector<std::string>& args);
aeb9cc10 106pid_t stap_spawn(int verbose, const std::vector<std::string>& args,
e4e3d6b7 107 posix_spawn_file_actions_t* fa, const std::vector<std::string>& envVec = std::vector<std::string> ());
645383d5 108pid_t stap_spawn_piped(int verbose, const std::vector<std::string>& args,
e96f2257 109 int* child_in=NULL, int* child_out=NULL, int* child_err=NULL);
b13c6a37
JS
110int stap_system(int verbose, const std::string& description,
111 const std::vector<std::string>& args,
ff520ff4 112 bool null_out=false, bool null_err=false);
b13c6a37
JS
113inline int stap_system(int verbose, const std::vector<std::string>& args,
114 bool null_out=false, bool null_err=false)
115{ return stap_system(verbose, args.front(), args, null_out, null_err); }
20f90026 116int stap_system_read(int verbose, const std::vector<std::string>& args, std::ostream& out);
9a9be966 117std::pair<bool,int> stap_fork_read(int verbose, std::ostream& out);
4cc40e82 118int kill_stap_spawn(int sig);
c0d1b5a0 119void assert_regexp_match (const std::string& name, const std::string& value, const std::string& re);
8aabf152 120int regexp_match (const std::string& value, const std::string& re, std::vector<std::string>& matches);
37001baa 121bool contains_glob_chars (const std::string &str);
5750ecc6
FCE
122std::string escape_glob_chars (const std::string& str);
123std::string unescape_glob_chars (const std::string& str);
a81fb5d4 124std::string csh_to_ksh (const std::string& csh);
e207d98f 125bool identifier_string_needs_escape (const std::string& str);
dd8cb30b 126std::string escaped_identifier_string (const std::string& str);
f44430b4
SM
127std::string escaped_character (unsigned c);
128std::string escaped_literal_string (const std::string& str);
aeb9cc10 129std::string kernel_release_from_build_tree (const std::string &kernel_build_tree, int verbose = 0);
daa75206 130std::string normalize_machine(const std::string& machine);
081b45d1 131int elf_class_from_normalized_machine(const std::string& machine);
2695da79 132std::string autosprintf(const char* format, ...) __attribute__ ((format (printf, 1, 2)));
e4e3d6b7 133const std::set<std::string>& localization_variables();
28946fe7 134std::string get_self_path();
a03a3744 135bool is_valid_pid (pid_t pid, std::string& err_msg);
72dbc915
FCE
136
137// stringification generics
138
139
aca66a36
JS
140template <typename IN>
141inline std::string lex_cast(IN const & in)
72dbc915 142{
aca66a36
JS
143 std::ostringstream ss;
144 if (!(ss << in))
58a834b1 145 throw std::runtime_error(_("bad lexical cast"));
aca66a36 146 return ss.str();
72dbc915
FCE
147}
148
0de802f8
JS
149#if __cplusplus < 201103L
150// Older C++0x only had the "long long" implementations, so we cast up.
151#define INT_TO_STRING(IN) \
152 LEX_CAST_TO_STRING(signed IN, long long) \
153 LEX_CAST_TO_STRING(unsigned IN, unsigned long long)
154#else
155// Otherwise, keep the values native.
156#define INT_TO_STRING(IN) \
157 LEX_CAST_TO_STRING(signed IN, signed IN) \
158 LEX_CAST_TO_STRING(unsigned IN, unsigned IN)
159#endif
160
161#define LEX_CAST_TO_STRING(IN, CAST) \
162 template <> \
163 inline std::string lex_cast(IN const & in) \
164 { \
165 return std::to_string(static_cast<CAST>(in)); \
166 }
167
168INT_TO_STRING(char)
169INT_TO_STRING(short)
170INT_TO_STRING(int)
171INT_TO_STRING(long)
172INT_TO_STRING(long long)
173
174#undef INT_TO_STRING
175#undef LEX_CAST_TO_STRING
176
72dbc915 177
aca66a36
JS
178template <typename OUT>
179inline OUT lex_cast(std::string const & in)
72dbc915 180{
aca66a36 181 std::istringstream ss(in);
72dbc915 182 OUT out;
aca66a36 183 if (!(ss >> out && ss.eof()))
58a834b1 184 throw std::runtime_error(_("bad lexical cast"));
72dbc915
FCE
185 return out;
186}
187
188
f13fc0db
JS
189// We want [u]int8_t to be treated numerically, not just extracting a char.
190template <>
191inline int8_t lex_cast(std::string const & in)
192{
193 int16_t out = lex_cast<int16_t>(in);
194 if (out < -128 || out > 127)
58a834b1 195 throw std::runtime_error(_("bad lexical cast"));
f13fc0db
JS
196 return out;
197}
198template <>
199inline uint8_t lex_cast(std::string const & in)
200{
201 uint16_t out = lex_cast<uint16_t>(in);
202 if (out > 0xff && out < 0xff80) // don't error if it looks sign-extended
58a834b1 203 throw std::runtime_error(_("bad lexical cast"));
f13fc0db
JS
204 return out;
205}
206
207
aca66a36
JS
208template <typename IN>
209inline std::string
72dbc915
FCE
210lex_cast_hex(IN const & in)
211{
aca66a36 212 std::ostringstream ss;
49e1b0a1 213 if (!(ss << std::showbase << std::hex << in << std::dec))
58a834b1 214 throw std::runtime_error(_("bad lexical cast"));
aca66a36 215 return ss.str();
72dbc915
FCE
216}
217
e1e8b44e
CM
218//Convert binary data to hex data.
219template <typename IN>
220inline std::string
221hex_dump(IN const & in, size_t len)
222{
223 std::ostringstream ss;
224 unsigned i;
225 if (!(ss << std::hex << std::setfill('0')))
226 throw std::runtime_error(_("bad lexical cast"));
227
228 for(i = 0; i < len; i++)
229 {
230 int temp = in[i];
231 ss << std::setw(2) << temp;
232 }
233 std::string hex = ss.str();
234 assert(hex.length() == 2 * len);
235 return hex;
236}
72dbc915
FCE
237
238// Return as quoted string, so that when compiled as a C literal, it
239// would print to the user out nicely.
dff50e09 240template <typename IN>
72dbc915
FCE
241inline std::string
242lex_cast_qstring(IN const & in)
243{
244 std::stringstream ss;
72dbc915 245 if (!(ss << in))
58a834b1 246 throw std::runtime_error(_("bad lexical cast"));
aca66a36
JS
247 return lex_cast_qstring(ss.str());
248}
249
250
251template <>
252inline std::string
253lex_cast_qstring(std::string const & in)
254{
255 std::string out;
256 out += '"';
257 for (const char *p = in.c_str(); *p; ++p)
72dbc915 258 {
aca66a36 259 unsigned char c = *p;
3f99432c
FCE
260 if (! isprint(c))
261 {
aca66a36 262 out += '\\';
3f99432c 263 // quick & dirty octal converter
aca66a36
JS
264 out += "01234567" [(c >> 6) & 0x07];
265 out += "01234567" [(c >> 3) & 0x07];
266 out += "01234567" [(c >> 0) & 0x07];
dff50e09 267 }
3f99432c
FCE
268 else if (c == '"' || c == '\\')
269 {
aca66a36
JS
270 out += '\\';
271 out += c;
3f99432c
FCE
272 }
273 else
aca66a36 274 out += c;
72dbc915 275 }
aca66a36
JS
276 out += '"';
277 return out;
72dbc915 278}
73267b89 279
c9efa5c9
JS
280
281// Delete all values from a map-like container and clear it
282// (The template is permissive -- be good!)
283template <typename T>
284void delete_map(T& t)
285{
286 for (typename T::iterator i = t.begin(); i != t.end(); ++i)
287 delete i->second;
288 t.clear();
289}
290
291
4cb10751
CM
292// Automatically save a variable, and restore it at the
293// end of the function.
294template <class V>
295class save_and_restore
296{
297 V* ptr;
298 V previous_value;
299
300 public:
301 // Optionally pass a second argument to the constructor to initialize the
302 // variable to some value, after saving its old value.
303 save_and_restore(V* ptr_in, V value_in): ptr(ptr_in), previous_value(*ptr_in) { *ptr_in = value_in; }
304 save_and_restore(V*ptr_in): ptr(ptr_in), previous_value(*ptr_in){}
305
306 // Retrieve the old value and restore it in the destructor
307 ~save_and_restore() { *ptr = previous_value; }
308};
309
004f2b9c
JL
310template <typename T>
311inline bool vector_has(std::vector<T>& v, T item)
312{
313 return std::find(v.begin(), v.end(), item) != v.end();
314}
4cb10751 315
60d98537
JS
316// Returns whether a string starts with the given prefix
317inline bool
318startswith(const std::string & s, const char * prefix)
319{
320 return (s.compare(0, std::strlen(prefix), prefix) == 0);
321}
322
5bca76a8
JS
323inline bool
324startswith(const std::string & s, const std::string & prefix)
325{
326 return (s.compare(0, prefix.length(), prefix) == 0);
327}
328
60d98537
JS
329// Returns whether a string ends with the given suffix
330inline bool
331endswith(const std::string & s, const char * suffix)
332{
333 size_t s_len = s.size(), suffix_len = std::strlen(suffix);
334 if (suffix_len > s_len)
335 return false;
336 return (s.compare(s_len - suffix_len, suffix_len, suffix) == 0);
337}
338
339
a69b4b55
JS
340// Mask our usual signals for the life of this object.
341struct stap_sigmasker {
342 sigset_t old;
343 stap_sigmasker()
344 {
345 sigset_t mask;
346 sigemptyset (&mask);
347 sigaddset (&mask, SIGHUP);
348 sigaddset (&mask, SIGPIPE);
349 sigaddset (&mask, SIGINT);
350 sigaddset (&mask, SIGTERM);
351 sigprocmask (SIG_BLOCK, &mask, &old);
352 }
6d27dcff
JS
353 stap_sigmasker(const sigset_t *mask)
354 {
355 sigprocmask (SIG_BLOCK, mask, &old);
356 }
a69b4b55
JS
357 ~stap_sigmasker()
358 {
359 sigprocmask (SIG_SETMASK, &old, NULL);
360 }
361};
362
fce2d171
JS
363// Convert a possibly-relative path to a full path
364inline std::string
365resolve_path(const std::string& path)
366{
367 std::string result(path);
368 char* resolved_path = realpath(path.c_str(), NULL);
369 if (resolved_path)
370 {
371 result = resolved_path;
372 std::free(resolved_path);
373 }
374 return result;
375}
376
cde0f3ce
JL
377// Used in levenshtein
378template<typename T>
379class Array2D
380{
381 private:
382 T * data;
383 public:
384 const unsigned width;
385 const unsigned height;
386 T& operator() (unsigned x, unsigned y) { return data[y*width + x]; }
387 Array2D(const unsigned w, const unsigned h) : width(w), height(h) { data = new T[w*h]; }
388 ~Array2D() { delete [] data; }
389};
390
391// String sorter using the Levenshtein algorithm
392unsigned levenshtein(const std::string& a, const std::string& b);
fce2d171 393
593f09eb
JL
394// Returns comma-separated list of set elements closest to the target string.
395// Print a maximum amount of 'max' elements, with a maximum levenshtein score
396// of 'threshold'.
397std::string levenshtein_suggest(const std::string& target,
398 const std::set<std::string>& elems,
399 unsigned max = std::numeric_limits<unsigned>::max(),
400 unsigned threshold = std::numeric_limits<unsigned>::max());
401
a3e980f9 402std::string levenshtein_suggest(const std::string& target,
47d349b1 403 const std::set<interned_string>& elems,
a3e980f9
FCE
404 unsigned max = std::numeric_limits<unsigned>::max(),
405 unsigned threshold = std::numeric_limits<unsigned>::max());
406
3f95ed01
JS
407#ifndef HAVE_PPOLL
408// This is a poor-man's ppoll; see the implementation for more details...
409int ppoll(struct pollfd *fds, nfds_t nfds,
410 const struct timespec *timeout_ts,
411 const sigset_t *sigmask);
412#endif
413
414
01fb72a0
DS
415int read_from_file (const std::string &fname, int &data);
416template <class T>
417int write_to_file (const std::string &fname, const T &data);
418int flush_to_stream (const std::string &fname, std::ostream &o);
419
1f4b9e55
DS
420void ltrim(std::string &s);
421void rtrim(std::string &s);
422void trim(std::string &s);
423
109c21b7 424bool get_distro_info(std::vector<std::string> &info);
42e38653 425#endif // UTIL_H
a69b4b55 426
73267b89 427/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.25727 seconds and 5 git commands to generate.