Loading...
Searching...
No Matches
utils.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2003-2025, John Wiegley. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * - Neither the name of New Artisans LLC nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
35
44#pragma once
45
46#include <boost/uuid/detail/sha1.hpp>
47#include <ledger.hh>
48
49#define TIMERS_ON 1
50
55
56namespace ledger {
57 using namespace boost;
58
59 typedef std::string string;
60 typedef std::list<string> strings_list;
61
62 typedef posix_time::ptime ptime;
63 typedef ptime::time_duration_type time_duration;
64 typedef gregorian::date date;
65 typedef gregorian::date_duration date_duration;
66 typedef posix_time::seconds seconds;
67
68 typedef boost::filesystem::path path;
69 typedef boost::filesystem::ifstream ifstream;
70 typedef boost::filesystem::ofstream ofstream;
71 typedef boost::filesystem::filesystem_error filesystem_error;
72}
73
75
80
81#ifdef assert
82#undef assert
83#endif
84
85#if !NO_ASSERTS
86
87namespace ledger {
88 void debug_assert(const string& reason, const string& func,
89 const string& file, std::size_t line);
90}
91
92#define assert(x) \
93 ((x) ? ((void)0) : debug_assert(#x, BOOST_CURRENT_FUNCTION, \
94 __FILE__, __LINE__))
95
96#else // !NO_ASSERTS
97
98#define assert(x) ((void)(x))
99
100#endif // !NO_ASSERTS
101
103
108
109#if VERIFY_ON
110
111namespace ledger {
112
113extern bool verify_enabled;
114
115#define VERIFY(x) if (ledger::verify_enabled) { assert(x); }
116#define DO_VERIFY() ledger::verify_enabled
117
118void initialize_memory_tracing();
119void shutdown_memory_tracing();
120
121std::size_t current_memory_size();
122std::size_t current_objects_size();
123
124void trace_ctor_func(void * ptr, const char * cls_name, const char * args,
125 std::size_t cls_size);
126void trace_dtor_func(void * ptr, const char * cls_name, std::size_t cls_size);
127
128#define TRACE_CTOR(cls, args) \
129 (DO_VERIFY() ? \
130 ledger::trace_ctor_func(this, #cls, args, sizeof(cls)) : ((void)0))
131#define TRACE_DTOR(cls) \
132 (DO_VERIFY() ? \
133 ledger::trace_dtor_func(this, #cls, sizeof(cls)) : ((void)0))
134
135void report_memory(std::ostream& out, bool report_all = false);
136
137} // namespace ledger
138
139#else // ! VERIFY_ON
140
141#define VERIFY(x)
142#define DO_VERIFY() false
143#define TRACE_CTOR(cls, args)
144#define TRACE_DTOR(cls)
145
146#endif // VERIFY_ON
147
148#define IF_VERIFY() if (DO_VERIFY())
149
151
161
162namespace ledger {
163
164extern string empty_string;
165
166strings_list split_arguments(const char * line);
167
168inline string to_string(long num) {
169 std::ostringstream buf;
170 buf << num;
171 return buf.str();
172}
173
174inline string to_string(std::size_t num) {
175 std::ostringstream buf;
176 buf << num;
177 return buf.str();
178}
179
180inline string lowered(const string& str) {
181 string tmp(str);
182 to_lower(tmp);
183 return tmp;
184}
185
186inline string operator+(const char * left, const string& right) {
187 return string(left) + right;
188}
189
190} // namespace ledger
191
193
198
199namespace ledger {
200
215
217extern std::ostream * _log_stream;
218extern std::ostringstream _log_buffer;
219
221
222#define LOGGER(cat) \
223 static const char * const _this_category = cat
224
225#if TRACING_ON
226
227extern uint16_t _trace_level;
228
229#define SHOW_TRACE(lvl) \
230 (ledger::_log_level >= ledger::LOG_TRACE && lvl <= ledger::_trace_level)
231#define TRACE(lvl, msg) \
232 (SHOW_TRACE(lvl) ? \
233 ((ledger::_log_buffer << msg), \
234 ledger::logger_func(ledger::LOG_TRACE)) : (void)0)
235
236#else // TRACING_ON
237
238#define SHOW_TRACE(lvl) false
239#define TRACE(lvl, msg)
240
241#endif // TRACING_ON
242
243#if DEBUG_ON
244
245extern optional<std::string> _log_category;
246#if HAVE_BOOST_REGEX_UNICODE
247 extern optional<boost::u32regex> _log_category_re;
248#else
249 extern optional<boost::regex> _log_category_re;
250#endif
251
252inline bool category_matches(const char * cat) {
253 if (_log_category) {
254 if (! _log_category_re) {
255 _log_category_re =
256#if HAVE_BOOST_REGEX_UNICODE
257 boost::make_u32regex(_log_category->c_str(),
258 boost::regex::perl | boost::regex::icase);
259#else
260 boost::regex(_log_category->c_str(),
261 boost::regex::perl | boost::regex::icase);
262#endif
263 }
264#if HAVE_BOOST_REGEX_UNICODE
265 return boost::u32regex_search(cat, *_log_category_re);
266#else
267 return boost::regex_search(cat, *_log_category_re);
268#endif
269 }
270 return false;
271}
272
273#define SHOW_DEBUG(cat) \
274 (ledger::_log_level >= ledger::LOG_DEBUG && ledger::category_matches(cat))
275#define SHOW_DEBUG_() SHOW_DEBUG(_this_category)
276
277#define DEBUG(cat, msg) \
278 (SHOW_DEBUG(cat) ? \
279 ((ledger::_log_buffer << msg), \
280 ledger::logger_func(ledger::LOG_DEBUG)) : (void)0)
281#define DEBUG_(msg) DEBUG(_this_category, msg)
282
283#else // DEBUG_ON
284
285#define SHOW_DEBUG(cat) false
286#define SHOW_DEBUG_() false
287#define DEBUG(cat, msg)
288#define DEBUG_(msg)
289
290#endif // DEBUG_ON
291
292#define LOG_MACRO(level, msg) \
293 (ledger::_log_level >= level ? \
294 ((ledger::_log_buffer << msg), ledger::logger_func(level)) : (void)0)
295
296#define SHOW_INFO() (ledger::_log_level >= ledger::LOG_INFO)
297#define SHOW_WARN() (ledger::_log_level >= ledger::LOG_WARN)
298#define SHOW_ERROR() (ledger::_log_level >= ledger::LOG_ERROR)
299#define SHOW_FATAL() (ledger::_log_level >= ledger::LOG_FATAL)
300#define SHOW_CRITICAL() (ledger::_log_level >= ledger::LOG_CRIT)
301
302#define INFO(msg) LOG_MACRO(ledger::LOG_INFO, msg)
303#define WARN(msg) LOG_MACRO(ledger::LOG_WARN, msg)
304#define ERROR(msg) LOG_MACRO(ledger::LOG_ERROR, msg)
305#define FATAL(msg) LOG_MACRO(ledger::LOG_FATAL, msg)
306#define CRITICAL(msg) LOG_MACRO(ledger::LOG_CRIT, msg)
307#define EXCEPTION(msg) LOG_MACRO(ledger::LOG_EXCEPT, msg)
308
309} // namespace ledger
310
311#define IF_TRACE(lvl) if (SHOW_TRACE(lvl))
312#define IF_DEBUG(cat) if (SHOW_DEBUG(cat))
313#define IF_DEBUG_() if (SHOW_DEBUG_())
314#define IF_INFO() if (SHOW_INFO())
315#define IF_WARN() if (SHOW_WARN())
316#define IF_ERROR() if (SHOW_ERROR())
317#define IF_FATAL() if (SHOW_FATAL())
318#define IF_CRITICAL() if (SHOW_CRITICAL())
319
321
327
328#if TIMERS_ON
329
330namespace ledger {
331
332void start_timer(const char * name, log_level_t lvl);
333void stop_timer(const char * name);
334void finish_timer(const char * name);
335
336#if TRACING_ON
337#define TRACE_START(name, lvl, msg) \
338 (SHOW_TRACE(lvl) ? \
339 ((ledger::_log_buffer << msg), \
340 ledger::start_timer(#name, ledger::LOG_TRACE)) : ((void)0))
341#define TRACE_STOP(name, lvl) \
342 (SHOW_TRACE(lvl) ? ledger::stop_timer(#name) : ((void)0))
343#define TRACE_FINISH(name, lvl) \
344 (SHOW_TRACE(lvl) ? ledger::finish_timer(#name) : ((void)0))
345#else
346#define TRACE_START(name, lvl, msg)
347#define TRACE_STOP(name, lvl)
348#define TRACE_FINISH(name, lvl)
349#endif
350
351#if DEBUG_ON
352#define DEBUG_START(name, cat, msg) \
353 (SHOW_DEBUG(cat) ? \
354 ((ledger::_log_buffer << msg), \
355 ledger::start_timer(#name, ledger::LOG_DEBUG)) : ((void)0))
356#define DEBUG_START_(name, msg) \
357 DEBUG_START_(name, _this_category, msg)
358#define DEBUG_STOP(name, cat) \
359 (SHOW_DEBUG(cat) ? ledger::stop_timer(#name) : ((void)0))
360#define DEBUG_STOP_(name) \
361 DEBUG_STOP_(name, _this_category)
362#define DEBUG_FINISH(name, cat) \
363 (SHOW_DEBUG(cat) ? ledger::finish_timer(#name) : ((void)0))
364#define DEBUG_FINISH_(name) \
365 DEBUG_FINISH_(name, _this_category)
366#else
367#define DEBUG_START(name, cat, msg)
368#define DEBUG_START_(name, msg)
369#define DEBUG_STOP(name)
370#define DEBUG_FINISH(name)
371#endif
372
373#define INFO_START(name, msg) \
374 (SHOW_INFO() ? \
375 ((ledger::_log_buffer << msg), \
376 ledger::start_timer(#name, ledger::LOG_INFO)) : ((void)0))
377#define INFO_STOP(name) \
378 (SHOW_INFO() ? stop_timer(#name) : ((void)0))
379#define INFO_FINISH(name) \
380 (SHOW_INFO() ? finish_timer(#name) : ((void)0))
381
382} // namespace ledger
383
384#else // !TIMERS_ON
385
386#define TRACE_START(lvl, msg, name)
387#define TRACE_STOP(name, lvl)
388#define TRACE_FINISH(name, lvl)
389
390#define DEBUG_START(name, msg)
391#define DEBUG_START_(name, cat, msg)
392#define DEBUG_STOP(name)
393#define DEBUG_FINISH(name)
394
395#define INFO_START(name, msg)
396#define INFO_STOP(name)
397#define INFO_FINISH(name)
398
399#endif // TIMERS_ON
400
402
403/*
404 * These files define the other internal facilities.
405 */
406
407#include "error.h"
408
414
416
417void sigint_handler(int sig);
418void sigpipe_handler(int sig);
419
420inline void check_for_signal() {
421 switch (caught_signal) {
422 case NONE_CAUGHT:
423 break;
424 case INTERRUPTED:
425 throw std::runtime_error(_("Interrupted by user (use Control-D to quit)"));
426 case PIPE_CLOSED:
427 throw std::runtime_error(_("Pipe terminated"));
428 }
429}
430
435
436#define foreach BOOST_FOREACH
437using std::unique_ptr;
438
439namespace ledger {
440
441template <typename T, typename U>
442inline T& downcast(U& object) {
443 return *polymorphic_downcast<T *>(&object);
444}
445
446path resolve_path(const path& pathname);
447
448inline const string& either_or(const string& first,
449 const string& second) {
450 return first.empty() ? second : first;
451}
452
453inline char * skip_ws(char * ptr) {
454 while (*ptr == ' ' || *ptr == '\t' || *ptr == '\n')
455 ptr++;
456 return ptr;
457}
458
459inline char * trim_ws(char * ptr) {
460 std::size_t len = std::strlen(ptr);
461 int i = int(len) - 1;
462 while (i >= 0 && (ptr[i] == ' ' || ptr[i] == '\t' || ptr[i] == '\n'))
463 ptr[i--] = '\0';
464 return skip_ws(ptr);
465}
466
467inline char * next_element(char * buf, bool variable = false) {
468 for (char * p = buf; *p; p++) {
469 if (! (*p == ' ' || *p == '\t'))
470 continue;
471
472 if (! variable) {
473 *p = '\0';
474 return skip_ws(p + 1);
475 }
476 else if (*p == '\t') {
477 *p = '\0';
478 return skip_ws(p + 1);
479 }
480 else if (*(p + 1) == ' ') {
481 *p = '\0';
482 return skip_ws(p + 2);
483 }
484 }
485 return NULL;
486}
487
488inline int peek_next_nonws(std::istream& in) {
489 int c = in.peek();
490 while (in.good() && ! in.eof() && std::isspace(c)) {
491 in.get();
492 c = in.peek();
493 }
494 return c;
495}
496
497#define READ_INTO(str, targ, size, var, cond) { \
498 char * _p = targ; \
499 var = str.peek(); \
500 while (str.good() && ! str.eof() && var != '\n' && \
501 (cond) && _p - targ < size) { \
502 var = str.get(); \
503 if (str.eof()) \
504 break; \
505 if (var == '\\') { \
506 var = str.get(); \
507 if (in.eof()) \
508 break; \
509 switch (var) { \
510 case 'b': var = '\b'; break; \
511 case 'f': var = '\f'; break; \
512 case 'n': var = '\n'; break; \
513 case 'r': var = '\r'; break; \
514 case 't': var = '\t'; break; \
515 case 'v': var = '\v'; break; \
516 default: break; \
517 } \
518 } \
519 *_p++ = var; \
520 var = str.peek(); \
521 } \
522 *_p = '\0'; \
523 }
524
525#define READ_INTO_(str, targ, size, var, idx, cond) { \
526 char * _p = targ; \
527 var = str.peek(); \
528 while (str.good() && ! str.eof() && var != '\n' && \
529 (cond) && _p - targ < size) { \
530 var = str.get(); \
531 if (str.eof()) \
532 break; \
533 idx++; \
534 if (var == '\\') { \
535 var = str.get(); \
536 if (in.eof()) \
537 break; \
538 switch (var) { \
539 case 'b': var = '\b'; break; \
540 case 'f': var = '\f'; break; \
541 case 'n': var = '\n'; break; \
542 case 'r': var = '\r'; break; \
543 case 't': var = '\t'; break; \
544 case 'v': var = '\v'; break; \
545 default: break; \
546 } \
547 idx++; \
548 } \
549 *_p++ = var; \
550 var = str.peek(); \
551 } \
552 *_p = '\0'; \
553 }
554
555inline string digest_to_hex(
556 const boost::uuids::detail::sha1::digest_type& message_digest,
557 size_t len = sizeof(boost::uuids::detail::sha1::digest_type) * 2
558) {
559 std::ostringstream buf;
560 buf.setf(std::ios_base::hex, std::ios_base::basefield);
561 buf.fill('0');
562
563 // sha1::digest_type is an array type and may change between Boost versions
564 const size_t count = std::min(
565 sizeof(message_digest) / sizeof(message_digest[0]),
566 (len - 1) / (sizeof(message_digest[0]) * 2) + 1
567 );
568 for(size_t i = 0; i < count; i++) {
569 buf.width(sizeof(message_digest[i]) * 2);
570 buf << (unsigned int)message_digest[i];
571 }
572 string hex = buf.str();
573 hex.resize(len, '0'); // in case a partial element is requested
574 return hex;
575}
576
577inline string sha1sum(
578 const string& str,
579 size_t len = sizeof(boost::uuids::detail::sha1::digest_type) * 2
580) {
581 static boost::uuids::detail::sha1 sha;
582 boost::uuids::detail::sha1::digest_type message_digest;
583
584 sha.reset();
585 sha.process_bytes(str.c_str(), str.length());
586 sha.get_digest(message_digest);
587 return digest_to_hex(message_digest, len);
588}
589
590extern const string version;
591
597
598} // namespace ledger
599
void sigint_handler(int sig)
void sigpipe_handler(int sig)
caught_signal_t
Definition utils.h:409
@ INTERRUPTED
Definition utils.h:411
@ PIPE_CLOSED
Definition utils.h:412
@ NONE_CAUGHT
Definition utils.h:410
caught_signal_t caught_signal
void check_for_signal()
Definition utils.h:420
boost::filesystem::ifstream ifstream
Definition utils.h:69
boost::filesystem::ofstream ofstream
Definition utils.h:70
string operator+(const char *left, const string &right)
Definition utils.h:186
string lowered(const string &str)
Definition utils.h:180
gregorian::date date
Definition utils.h:64
void logger_func(log_level_t level)
log_level_t _log_level
std::ostringstream _log_buffer
const string & either_or(const string &first, const string &second)
Definition utils.h:448
void start_timer(const char *name, log_level_t lvl)
ptime::time_duration_type time_duration
Definition utils.h:63
string empty_string
boost::filesystem::filesystem_error filesystem_error
Definition utils.h:71
gregorian::date_duration date_duration
Definition utils.h:65
string sha1sum(const string &str, size_t len=sizeof(boost::uuids::detail::sha1::digest_type) *2)
Definition utils.h:577
hash_type_t
Definition utils.h:592
@ HASH_SHA512_Half
Definition utils.h:595
@ NO_HASHES
Definition utils.h:593
@ HASH_SHA512
Definition utils.h:594
posix_time::ptime ptime
Definition utils.h:62
void finish_timer(const char *name)
char * next_element(char *buf, bool variable=false)
Definition utils.h:467
string to_string(long num)
Definition utils.h:168
log_level_t
Definition utils.h:201
@ LOG_ERROR
Definition utils.h:206
@ LOG_WARN
Definition utils.h:208
@ LOG_INFO
Definition utils.h:209
@ LOG_EXCEPT
Definition utils.h:210
@ LOG_CRIT
Definition utils.h:203
@ LOG_OFF
Definition utils.h:202
@ LOG_DEBUG
Definition utils.h:211
@ LOG_VERIFY
Definition utils.h:207
@ LOG_ASSERT
Definition utils.h:205
@ LOG_FATAL
Definition utils.h:204
@ LOG_TRACE
Definition utils.h:212
@ LOG_ALL
Definition utils.h:213
void stop_timer(const char *name)
std::ostream * _log_stream
boost::filesystem::path path
Definition utils.h:68
char * trim_ws(char *ptr)
Definition utils.h:459
int peek_next_nonws(std::istream &in)
Definition utils.h:488
void debug_assert(const string &reason, const string &func, const string &file, std::size_t line)
std::string string
Definition utils.h:59
std::list< string > strings_list
Definition utils.h:60
posix_time::seconds seconds
Definition utils.h:66
string digest_to_hex(const boost::uuids::detail::sha1::digest_type &message_digest, size_t len=sizeof(boost::uuids::detail::sha1::digest_type) *2)
Definition utils.h:555
path resolve_path(const path &pathname)
T & downcast(U &object)
Definition utils.h:442
const string version
strings_list split_arguments(const char *line)
char * skip_ws(char *ptr)
Definition utils.h:453