1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
|
/*
* utility.h
*
* Home page of code is: https://www.smartmontools.org
*
* Copyright (C) 2002-11 Bruce Allen
* Copyright (C) 2008-23 Christian Franke
* Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef UTILITY_H_
#define UTILITY_H_
#define UTILITY_H_CVSID "$Id: utility.h 5519 2023-07-24 15:57:54Z chrfranke $"
#include <float.h> // *DBL_MANT_DIG
#include <time.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <sys/types.h> // for regex.h (according to POSIX)
#ifdef WITH_CXX11_REGEX
#include <regex>
#else
#include <regex.h>
#endif
#ifndef __GNUC__
#define __attribute_format_printf(x, y) /**/
#elif defined(__MINGW32__) && __USE_MINGW_ANSI_STDIO
// Check format of __mingw_*printf() instead of MSVCRT.DLL:*printf()
#define __attribute_format_printf(x, y) __attribute__((format (gnu_printf, x, y)))
#else
#define __attribute_format_printf(x, y) __attribute__((format (printf, x, y)))
#endif
// Make version information string
// lines: 1: version only, 2: version+copyright, >=3: full information
std::string format_version_info(const char * prog_name, int lines = 2);
// return (v)sprintf() formatted std::string
std::string strprintf(const char * fmt, ...)
__attribute_format_printf(1, 2);
std::string vstrprintf(const char * fmt, va_list ap);
// Return true if STR starts with PREFIX
inline bool str_starts_with(const char * str, const char * prefix)
{ return !strncmp(str, prefix, strlen(prefix)); }
inline bool str_starts_with(const std::string & str, const char * prefix)
{ return !strncmp(str.c_str(), prefix, strlen(prefix)); }
// Convert time to broken-down local time, throw on error.
struct tm * time_to_tm_local(struct tm * tp, time_t t);
// Utility function prints date and time and timezone into a character
// buffer of length 64. All the fuss is needed to get the
// right timezone info (sigh).
#define DATEANDEPOCHLEN 64
void dateandtimezoneepoch(char (& buffer)[DATEANDEPOCHLEN], time_t tval);
// like printf() except that we can control it better. Note --
// although the prototype is given here in utility.h, the function
// itself is defined differently in smartctl and smartd. So the
// function definition(s) are in smartd.c and in smartctl.c.
void pout(const char *fmt, ...)
__attribute_format_printf(1, 2);
// replacement for perror() with redirected output.
void syserror(const char *message);
// Function for processing -t selective... option in smartctl
int split_selective_arg(char *s, uint64_t *start, uint64_t *stop, int *mode);
// Compile time check of byte ordering
// (inline const function allows compiler to remove dead code)
inline bool isbigendian()
{
#ifdef WORDS_BIGENDIAN
return true;
#else
return false;
#endif
}
void swap2(char *location);
void swap4(char *location);
void swap8(char *location);
// Typesafe variants using overloading
inline void swapx(unsigned short * p)
{ swap2((char*)p); }
inline void swapx(unsigned int * p)
{ swap4((char*)p); }
inline void swapx(uint64_t * p)
{ swap8((char*)p); }
// Runtime check of ./configure result, throws on error.
void check_config();
// This value follows the peripheral device type value as defined in
// SCSI Primary Commands, ANSI INCITS 301:1997. It is also used in
// the ATA standard for packet devices to define the device type.
const char *packetdevicetype(int type);
// returns true if any of the n bytes are nonzero, else zero.
bool nonempty(const void * data, int size);
// needed to fix glibc bug
void FixGlibcTimeZoneBug();
// Copy not null terminated char array to null terminated string.
// Replace non-ascii characters. Remove leading and trailing blanks.
const char * format_char_array(char * str, int strsize, const char * chr, int chrsize);
// Version for fixed size buffers.
template<size_t STRSIZE, size_t CHRSIZE>
inline const char * format_char_array(char (& str)[STRSIZE], const char (& chr)[CHRSIZE])
{ return format_char_array(str, (int)STRSIZE, chr, (int)CHRSIZE); }
// Format integer with thousands separator
const char * format_with_thousands_sep(char * str, int strsize, uint64_t val,
const char * thousands_sep = 0);
// Format capacity with SI prefixes
const char * format_capacity(char * str, int strsize, uint64_t val,
const char * decimal_point = 0);
// Wrapper class for a raw data buffer
class raw_buffer
{
public:
explicit raw_buffer(unsigned sz, unsigned char val = 0)
: m_data(new unsigned char[sz]),
m_size(sz)
{ memset(m_data, val, m_size); }
~raw_buffer()
{ delete [] m_data; }
unsigned size() const
{ return m_size; }
unsigned char * data()
{ return m_data; }
const unsigned char * data() const
{ return m_data; }
private:
unsigned char * m_data;
unsigned m_size;
raw_buffer(const raw_buffer &);
void operator=(const raw_buffer &);
};
/// Wrapper class for FILE *.
class stdio_file
{
public:
explicit stdio_file(FILE * f = 0, bool owner = false)
: m_file(f), m_owner(owner) { }
stdio_file(const char * name, const char * mode)
: m_file(fopen(name, mode)), m_owner(true) { }
~stdio_file()
{
if (m_file && m_owner)
fclose(m_file);
}
bool open(const char * name, const char * mode)
{
if (m_file && m_owner)
fclose(m_file);
m_file = fopen(name, mode);
m_owner = true;
return !!m_file;
}
void open(FILE * f, bool owner = false)
{
if (m_file && m_owner)
fclose(m_file);
m_file = f;
m_owner = owner;
}
bool close()
{
if (!m_file)
return true;
bool ok = !ferror(m_file);
if (fclose(m_file))
ok = false;
m_file = 0;
return ok;
}
operator FILE * ()
{ return m_file; }
bool operator!() const
{ return !m_file; }
private:
FILE * m_file;
bool m_owner;
stdio_file(const stdio_file &);
void operator=(const stdio_file &);
};
/// Wrapper class for POSIX regex(3) or std::regex
/// Supports copy & assignment and is compatible with STL containers.
class regular_expression
{
public:
// Construction & assignment
#ifdef WITH_CXX11_REGEX
regular_expression() = default;
#else
regular_expression();
~regular_expression();
regular_expression(const regular_expression & x);
regular_expression & operator=(const regular_expression & x);
#endif
/// Construct with pattern, throw on error.
explicit regular_expression(const char * pattern);
/// Set and compile new pattern, return false on error.
bool compile(const char * pattern);
// Get pattern from last compile().
const char * get_pattern() const
{ return m_pattern.c_str(); }
/// Get error message from last compile().
const char * get_errmsg() const
{ return m_errmsg.c_str(); }
// Return true if pattern is not set or bad.
bool empty() const
{ return (m_pattern.empty() || !m_errmsg.empty()); }
/// Return true if full string matches pattern
bool full_match(const char * str) const;
#ifdef WITH_CXX11_REGEX
struct match_range { int rm_so, rm_eo; };
#else
typedef regmatch_t match_range;
#endif
/// Return true if substring matches pattern, fill match_range array.
bool execute(const char * str, unsigned nmatch, match_range * pmatch) const;
private:
std::string m_pattern;
std::string m_errmsg;
#ifdef WITH_CXX11_REGEX
std::regex m_regex;
#else
regex_t m_regex_buf;
void free_buf();
void copy_buf(const regular_expression & x);
#endif
bool compile();
};
// 128-bit unsigned integer to string conversion.
// Provides full integer precision if compiler supports '__int128'.
// Otherwise precision depends on supported floating point data types.
#if defined(HAVE_LONG_DOUBLE_WIDER) && \
(!defined(__MINGW32__) || __USE_MINGW_ANSI_STDIO)
// MinGW 'long double' type does not work with MSVCRT/UCRT *printf()
#define HAVE_LONG_DOUBLE_WIDER_PRINTF 1
#else
#undef HAVE_LONG_DOUBLE_WIDER_PRINTF
#endif
// Return #bits precision provided by uint128_hilo_to_str().
inline int uint128_to_str_precision_bits()
{
#if defined(HAVE___INT128)
return 128;
#elif defined(HAVE_LONG_DOUBLE_WIDER_PRINTF)
return LDBL_MANT_DIG;
#else
return DBL_MANT_DIG;
#endif
}
// Convert 128-bit unsigned integer provided as two 64-bit halves to a string.
const char * uint128_hilo_to_str(char * str, int strsize, uint64_t value_hi, uint64_t value_lo);
// Version for fixed size buffers.
template <size_t SIZE>
inline const char * uint128_hilo_to_str(char (& str)[SIZE], uint64_t value_hi, uint64_t value_lo)
{ return uint128_hilo_to_str(str, (int)SIZE, value_hi, value_lo); }
/// Get microseconds since some unspecified starting point.
/// Used only for command duration measurements in debug outputs.
/// Returns -1 if unsupported.
long long get_timer_usec();
#ifdef _WIN32
// Get exe directory
//(implemented in os_win32.cpp)
std::string get_exe_dir();
#endif
#ifdef OLD_INTERFACE
// remaining controller types in old interface modules
#define CONTROLLER_UNKNOWN 0x00
#define CONTROLLER_ATA 0x01
#define CONTROLLER_SCSI 0x02
#endif
#endif
|