LCOV - code coverage report
Current view: top level - libprimis-headers - tools.h (source / functions) Coverage Total Hit
Test: Libprimis Test Coverage Lines: 98.9 % 187 185
Test Date: 2025-04-17 05:09:30 Functions: 79.8 % 104 83

            Line data    Source code
       1              : /**
       2              :  * @file tools.h
       3              :  * @brief Legacy tooling inherited from the Cube engine.
       4              :  *
       5              :  * This file contains a collection of deprecated, standalone tooling that replicates
       6              :  * some standard library functionality. It is highly recommended that the std library
       7              :  * equivalents of these utilities are used in their place.
       8              :  */
       9              : 
      10              : #ifndef TOOLS_H_
      11              : #define TOOLS_H_
      12              : 
      13              : typedef unsigned char uchar;
      14              : typedef unsigned short ushort;
      15              : typedef unsigned int uint;
      16              : typedef unsigned long ulong;
      17              : typedef signed long long int llong;
      18              : typedef unsigned long long int ullong;
      19              : 
      20              : #if defined(__GNUC__) || defined(_MSC_VER)
      21              :     #define RESTRICT __restrict
      22              : #else
      23              :     #define RESTRICT
      24              : #endif
      25              : 
      26              : #ifdef max
      27              :     #undef max
      28              : #endif
      29              : #ifdef min
      30              :     #undef min
      31              : #endif
      32              : template<class T>
      33           87 : inline T max(T a, T b)
      34              : {
      35           87 :     return a > b ? a : b;
      36              : }
      37              : template<class T>
      38            3 : inline T max(T a, T b, T c)
      39              : {
      40            3 :     return max(max(a, b), c);
      41              : }
      42              : template<class T>
      43         1256 : inline T min(T a, T b)
      44              : {
      45         1256 :     return a < b ? a : b;
      46              : }
      47              : template<class T>
      48            3 : inline T min(T a, T b, T c)
      49              : {
      50            3 :     return min(min(a, b), c);
      51              : }
      52              : 
      53              : #ifdef __GNUC__
      54              :     #define BITSCAN(mask) (__builtin_ffs(mask)-1)
      55              : #else
      56              :     #ifdef WIN32
      57              :         #pragma intrinsic(_BitScanForward)
      58              :         inline int BITSCAN(uint mask)
      59              :         {
      60              :             ulong i;
      61              :             return _BitScanForward(&i, mask) ? i : -1;
      62              :         }
      63              :     #else
      64              :         inline int BITSCAN(uint mask)
      65              :         {
      66              :             if(!mask) return -1;
      67              :             int i = 1;
      68              :             if(!(mask&0xFFFF)) { i += 16; mask >>= 16; }
      69              :             if(!(mask&0xFF)) { i += 8; mask >>= 8; }
      70              :             if(!(mask&0xF)) { i += 4; mask >>= 4; }
      71              :             if(!(mask&3)) { i += 2; mask >>= 2; }
      72              :             return i - (mask&1);
      73              :         }
      74              :     #endif
      75              : #endif
      76              : 
      77            1 : inline int randomint(int x)
      78              : {
      79            1 :     return rand()%(x);
      80              : }
      81            1 : inline float randomfloat(int x)
      82              : {
      83            1 :     return (float((rand()*float(x))/float(RAND_MAX)));
      84              : }
      85              : //1103515245+12345 are magic constants for LCG psuedorandom generator
      86            3 : inline float detrnd(uint s, int x)
      87              : {
      88            3 :     return static_cast<int>(((s*1103515245+12345)>>16)%x);
      89              : }
      90              : 
      91              : constexpr double SQRT2 = 1.4142135623731;
      92              : constexpr double SQRT3 = 1.73205080756888;
      93              : 
      94              : #ifdef WIN32
      95              :     #ifndef M_PI
      96              :         constexpr double M_PI = 3.14159265358979323846;
      97              :     #endif
      98              :     #ifndef M_LN2
      99              :         constexpr double M_LN2 = 0.693147180559945309417;
     100              :     #endif
     101              : 
     102              :     #ifndef __GNUC__
     103              :         #pragma warning (3: 4189)       // local variable is initialized but not referenced
     104              :         #pragma warning (disable: 4244) // conversion from 'int' to 'float', possible loss of data
     105              :         #pragma warning (disable: 4267) // conversion from 'size_t' to 'int', possible loss of data
     106              :         #pragma warning (disable: 4355) // 'this' : used in base member initializer list
     107              :         #pragma warning (disable: 4996) // 'strncpy' was declared deprecated
     108              :     #endif
     109              : 
     110              :     #define strcasecmp _stricmp
     111              :     #define strncasecmp _strnicmp
     112              :     #define PATHDIV '\\'
     113              : 
     114              : #else
     115              :     #define __cdecl
     116              :     #define _vsnprintf vsnprintf
     117              :     #define PATHDIV '/'
     118              : #endif
     119              : 
     120              : #define RAD static_cast<float>(180.0f / M_PI) //M_PI is a double
     121              : 
     122              : 
     123              : #ifdef __GNUC__
     124              :     #define PRINTFARGS(fmt, args) __attribute__((format(printf, fmt, args)))
     125              : #else
     126              :     #define PRINTFARGS(fmt, args)
     127              : #endif
     128              : 
     129              : // easy safe strings
     130              : const int maxstrlen = 260;
     131              : 
     132              : typedef char string[maxstrlen];
     133              : 
     134         1618 : inline void vformatstring(char *d, const char *fmt, va_list v, int len) { _vsnprintf(d, len, fmt, v); d[len-1] = 0; }
     135              : 
     136              : template<size_t N>
     137            6 : inline void vformatstring(char (&d)[N], const char *fmt, va_list v) { vformatstring(d, fmt, v, N); }
     138              : 
     139         1159 : inline char *copystring(char *d, const char *s, size_t len)
     140              : {
     141         1159 :     size_t slen = min(strlen(s), len-1);
     142         1159 :     std::memcpy(d, s, slen);
     143         1159 :     d[slen] = 0;
     144         1159 :     return d;
     145              : }
     146              : template<size_t N>
     147           16 : inline char *copystring(char (&d)[N], const char *s) { return copystring(d, s, N); }
     148              : 
     149           16 : inline char *concatstring(char *d, const char *s, size_t len) { size_t used = strlen(d); return used < len ? copystring(d+used, s, len-used) : d; }
     150              : 
     151              : template<size_t N>
     152           15 : inline char *concatstring(char (&d)[N], const char *s) { return concatstring(d, s, N); }
     153              : 
     154              : inline void nformatstring(char *d, int len, const char *fmt, ...) PRINTFARGS(3, 4);
     155          200 : inline void nformatstring(char *d, int len, const char *fmt, ...)
     156              : {
     157              :     va_list v;
     158          200 :     va_start(v, fmt);
     159          200 :     vformatstring(d, fmt, v, len);
     160          200 :     va_end(v);
     161          200 : }
     162              : 
     163              : template<size_t N>
     164              : inline void formatstring(char (&d)[N], const char *fmt, ...) PRINTFARGS(2, 3);
     165              : 
     166              : template<size_t N>
     167           15 : inline void formatstring(char (&d)[N], const char *fmt, ...)
     168              : {
     169              :     va_list v;
     170           15 :     va_start(v, fmt);
     171           15 :     vformatstring(d, fmt, v, static_cast<int>(N));
     172           15 :     va_end(v);
     173           15 : }
     174              : 
     175              : template<size_t N>
     176              : inline void concformatstring(char (&d)[N], const char *fmt, ...) PRINTFARGS(2, 3);
     177              : 
     178              : template<size_t N>
     179            1 : inline void concformatstring(char (&d)[N], const char *fmt, ...)
     180              : {
     181              :     va_list v;
     182            1 :     va_start(v, fmt);
     183            1 :     int len = strlen(d);
     184            1 :     vformatstring(d + len, fmt, v, static_cast<int>(N) - len);
     185            1 :     va_end(v);
     186            1 : }
     187              : 
     188              : extern char *tempformatstring(const char *fmt, ...) PRINTFARGS(1, 2);
     189              : 
     190              : #define DEF_FORMAT_STRING(d,...) string d; formatstring(d, __VA_ARGS__)
     191              : #define DEFV_FORMAT_STRING(d,last,fmt) string d; { va_list ap; va_start(ap, last); vformatstring(d, fmt, ap); va_end(ap); }
     192              : 
     193          959 : inline char *newstring(size_t l)
     194              : {
     195          959 :     return new char[l+1];
     196              : }
     197              : 
     198          403 : inline char *newstring(const char *s, size_t l)
     199              : {
     200          403 :     return copystring(newstring(l), s, l+1);
     201              : }
     202              : 
     203          449 : inline char *newstring(const char *s)
     204              : {
     205          449 :     size_t l = strlen(s);
     206          449 :     char *d = newstring(l);
     207          449 :     std::memcpy(d, s, l+1);
     208          449 :     return d;
     209              : }
     210              : 
     211            1 : inline char *newconcatstring(const char *s, const char *t)
     212              : {
     213            1 :     size_t slen = strlen(s),
     214            1 :            tlen = strlen(t);
     215            1 :     char *r = newstring(slen + tlen);
     216            1 :     std::memcpy(r, s, slen);
     217            1 :     std::memcpy(&r[slen], t, tlen);
     218            1 :     r[slen+tlen] = '\0';
     219            1 :     return r;
     220              : }
     221              : 
     222              : template <class T>
     223              : struct databuf
     224              : {
     225              :     enum
     226              :     {
     227              :         OVERREAD  = 1<<0,
     228              :         OVERWROTE = 1<<1
     229              :     };
     230              : 
     231              :     T *buf;
     232              :     int len, maxlen;
     233              :     uchar flags;
     234              : 
     235            1 :     databuf() : buf(nullptr), len(0), maxlen(0), flags(0) {}
     236              : 
     237              :     template<class U>
     238           22 :     databuf(T *buf, U maxlen) : buf(buf), len(0), maxlen(static_cast<int>(maxlen)), flags(0) {}
     239              : 
     240           19 :     void reset()
     241              :     {
     242           19 :         len = 0;
     243           19 :         flags = 0;
     244           19 :     }
     245              : 
     246            1 :     void reset(T *buf_, int maxlen_)
     247              :     {
     248            1 :         reset();
     249            1 :         buf = buf_;
     250            1 :         maxlen = maxlen_;
     251            1 :     }
     252              : 
     253              :     /**
     254              :      * @brief Adds an existing value in the underlying buffer to the databuf
     255              :      *
     256              :      * Increases the length of the databuf by one and incorporates the value at
     257              :      * the address after the end of the databuf's values.
     258              :      *
     259              :      * If the length is equal to or greater than the buffer's maximum length,
     260              :      * applies the OVERREAD flag and returns a null value.
     261              :      */
     262           33 :     const T &get()
     263              :     {
     264              :         static const T overreadval = 0;
     265           33 :         if(len<maxlen)
     266              :         {
     267           32 :             return buf[len++];
     268              :         }
     269            1 :         flags |= OVERREAD;
     270            1 :         return overreadval;
     271              :     }
     272              : 
     273              :     /**
     274              :      * @brief Returns a databuf<T> object containing the first n entries
     275              :      *
     276              :      * Returns a databuf object of type T which represents the first n elements
     277              :      * inside the databuf's array.
     278              :      *
     279              :      * If the size passed is larger than the databuf, the entire databuf object is
     280              :      * copied and returned.
     281              :      *
     282              :      * @param sz the size of the output array (aka get the first `sz` entries)
     283              :      *
     284              :      * @return the sub-buffer of `this` object
     285              :      */
     286            1 :     databuf subbuf(int sz)
     287              :     {
     288            1 :         sz = std::clamp(sz, 0, maxlen-len);
     289            1 :         len += sz;
     290            1 :         return databuf(&buf[len-sz], sz);
     291              :     }
     292              : 
     293              :     /**
     294              :      * @brief Adds N empty elements to the end of the array and returns a pointer
     295              :      *
     296              :      * Creates an array of size `sz` which is then pointed to and returned as
     297              :      * a naked pointer.
     298              :      *
     299              :      * @param sz the size of the buffer
     300              :      *
     301              :      * @return a pointer to the sub-array created
     302              :      */
     303            2 :     T *pad(int numvals)
     304              :     {
     305            2 :         T *vals = &buf[len];
     306            2 :         len += min(numvals, maxlen-len);
     307            2 :         return vals;
     308              :     }
     309              : 
     310              :     /**
     311              :      * @brief Adds an entry to the databuf if space is available
     312              :      *
     313              :      * If no space is available, applies the OVERWROTE flag to the flags field.
     314              :      *
     315              :      * @param val A const reference to the object to add
     316              :      */
     317           36 :     void put(const T &val)
     318              :     {
     319           36 :         if(len<maxlen)
     320              :         {
     321           35 :             buf[len++] = val;
     322              :         }
     323              :         else
     324              :         {
     325            1 :             flags |= OVERWROTE;
     326              :         }
     327           36 :     }
     328              : 
     329            4 :     void put(const T *vals, int numvals)
     330              :     {
     331            4 :         if(maxlen - len < numvals)
     332              :         {
     333            1 :             numvals = maxlen - len;
     334            1 :             flags |= OVERWROTE;
     335              :         }
     336            4 :         std::memcpy(&buf[len], static_cast<const void *>(vals), numvals*sizeof(T));
     337            4 :         len += numvals;
     338            4 :     }
     339              : 
     340            2 :     int get(T *vals, int numvals)
     341              :     {
     342            2 :         if(maxlen - len < numvals)
     343              :         {
     344            0 :             numvals = maxlen - len;
     345            0 :             flags |= OVERREAD;
     346              :         }
     347            2 :         std::memcpy(vals, static_cast<void *>(&buf[len]), numvals*sizeof(T));
     348            2 :         len += numvals;
     349            2 :         return numvals;
     350              :     }
     351              : 
     352            1 :     void offset(int n)
     353              :     {
     354            1 :         n = min(n, maxlen);
     355            1 :         buf += n;
     356            1 :         maxlen -= n;
     357            1 :         len = max(len-n, 0);
     358            1 :     }
     359              : 
     360              :     /**
     361              :      * @brief Returns a pointer to the internal data array.
     362              :      *
     363              :      * This is a naked pointer to the internal data array and can therefore be used
     364              :      * to potentially break this container, if used carelessly.
     365              :      *
     366              :      * @return A pointer the data array
     367              :      */
     368            3 :     T *getbuf() const { return buf; }
     369              : 
     370              :     /**
     371              :      * @brief Returns whether any entries have been assigned to the array.
     372              :      *
     373              :      * @return true if the array has not been assigned to
     374              :      * @return false if the array has assigned values
     375              :      */
     376            2 :     bool empty() const { return len==0; }
     377              : 
     378              :     /**
     379              :      * @brief Returns the number of allocated entries in the databuf.
     380              :      *
     381              :      * Returns the number of entries which have been added to the databuf (not the
     382              :      * overall databuf size).
     383              :      *
     384              :      * @return the number of entries allocated in the databuf.
     385              :      */
     386            8 :     int length() const { return len; }
     387              : 
     388              :     /**
     389              :      * @brief Returns the number of values remaining before the databuf overflows.
     390              :      *
     391              :      * Returns the allocatable space remaining within the databuf object, in terms
     392              :      * of the number of entires which can be `put` into it before it becomes
     393              :      * OVERWROTE.
     394              :      *
     395              :      * @return the number of available entries in the databuf.
     396              :      */
     397           17 :     int remaining() const { return maxlen-len; }
     398              : 
     399              :     /**
     400              :      * @brief Returns whether the databuf has been accessed with too large of an index.
     401              :      *
     402              :      * Returns whether the OVERREAD flag has been set. If the databuf was attempted
     403              :      * to be accessed with an index larger than the number of allocated members,
     404              :      * this value will be set.
     405              :      *
     406              :      * @return true if the array has been overread
     407              :      * @return false if all read operations have been to valid entries
     408              :      */
     409            6 :     bool overread() const { return (flags&OVERREAD)!=0; }
     410              : 
     411              :     /**
     412              :      * @brief Returns whether the databuf has had invalid writes to it
     413              :      *
     414              :      * Returns whether the OVERWROTE flag has been set. If the databuf was attempted
     415              :      * to be wrote to while the databuf is already full, this flag will be set.
     416              :      *
     417              :      * @return true if the databuf has not been overwritten
     418              :      * @return false if the databuf has had only valid writes
     419              :      */
     420            2 :     bool overwrote() const { return (flags&OVERWROTE)!=0; }
     421              : 
     422            4 :     bool check(int n) { return remaining() >= n; }
     423              : 
     424            1 :     void forceoverread()
     425              :     {
     426            1 :         len = maxlen;
     427            1 :         flags |= OVERREAD;
     428            1 :     }
     429              : };
     430              : 
     431              : typedef databuf<char> charbuf;
     432              : typedef databuf<uchar> ucharbuf;
     433              : 
     434           11 : inline uint memhash(const void *ptr, int len)
     435              : {
     436           11 :     const uchar *data = static_cast<const uchar *>(ptr);
     437           11 :     uint h = 5381;
     438          539 :     for(int i = 0; i < static_cast<int>(len); ++i)
     439              :     {
     440          528 :         h = ((h<<5)+h)^data[i];
     441              :     }
     442           11 :     return h;
     443              : }
     444              : 
     445              : template<class T>
     446              : inline T endianswap(T n) { union { T t; uint i; } conv; conv.t = n; conv.i = SDL_Swap32(conv.i); return conv.t; }
     447              : 
     448              : template<>
     449            5 : inline uint endianswap<uint>(uint n) { return SDL_Swap32(n); }
     450              : 
     451              : template<>
     452            4 : inline int endianswap<int>(int n) { return SDL_Swap32(n); }
     453              : 
     454              : /* workaround for some C platforms that have these two functions as macros - not used anywhere */
     455              : #ifdef getchar
     456              :     #undef getchar
     457              : #endif
     458              : #ifdef putchar
     459              :     #undef putchar
     460              : #endif
     461              : 
     462              : struct stream
     463              : {
     464              : #ifdef WIN32
     465              :     #if defined(__GNUC__) && !defined(__MINGW32__)
     466              :         typedef off64_t offset;
     467              :     #else
     468              :         typedef __int64 offset;
     469              :     #endif
     470              :     #else
     471              :         typedef off_t offset;
     472              : #endif
     473              :     //see file/gz/zipstream children for more interesting forms
     474           12 :     virtual ~stream() {}
     475              :     virtual void close() = 0;
     476              :     virtual bool end() = 0;
     477            4 :     virtual offset tell() const { return -1; }
     478            1 :     virtual offset rawtell() const { return tell(); }
     479            1 :     virtual bool seek(offset, int) { return false; }
     480              :     virtual offset size();
     481            1 :     virtual offset rawsize() { return size(); }
     482            4 :     virtual size_t read(void *, size_t) { return 0; }
     483            8 :     virtual size_t write(const void *, size_t) { return 0; }
     484            1 :     virtual bool flush() { return true; }
     485            2 :     virtual int getchar() { uchar c; return read(&c, 1) == 1 ? c : -1; }
     486            2 :     virtual bool putchar(int n) { uchar c = n; return write(&c, 1) == 1; }
     487              :     virtual bool getline(char *str, size_t len);
     488            2 :     virtual bool putstring(const char *str) { size_t len = strlen(str); return write(str, len) == len; }
     489            1 :     virtual bool putline(const char *str) { return putstring(str) && putchar('\n'); }
     490              :     virtual size_t printf(const char *fmt, ...) PRINTFARGS(2, 3);
     491            1 :     virtual uint getcrc() { return 0; }
     492              : 
     493              :     template<class T>
     494            1 :     size_t put(const T *v, size_t n) { return write(v, n*sizeof(T))/sizeof(T); }
     495              : 
     496              :     template<class T>
     497            2 :     bool put(T n) { return write(&n, sizeof(n)) == sizeof(n); }
     498              : 
     499              :     template<class T>
     500            1 :     size_t get(T *v, size_t n) { return read(v, n*sizeof(T))/sizeof(T); }
     501              : 
     502              :     template<class T>
     503            2 :     T get() { T n; return read(&n, sizeof(n)) == sizeof(n) ? n : 0; }
     504              : 
     505              :     template<class T>
     506            1 :     bool putbig(T n) { return put<T>(endianswap(n)); }
     507              : 
     508              :     SDL_RWops *rwops();
     509              : };
     510              : 
     511              : extern std::string homedir;
     512              : 
     513              : extern char *path(char *s);
     514              : extern std::string path(std::string s);
     515              : extern char *copypath(const char *s);
     516              : extern const char *sethomedir(const char *dir);
     517              : extern const char *findfile(const char *filename, const char *mode);
     518              : 
     519              : /**
     520              :  * @brief Initializes zip Cubescript commands.
     521              :  *
     522              :  * `addzip`
     523              :  *
     524              :  * `removezip`
     525              :  */
     526              : extern void initzipcmds();
     527              : 
     528              : extern stream *openrawfile(const char *filename, const char *mode);
     529              : extern stream *openzipfile(const char *filename, const char *mode);
     530              : extern stream *openfile(const char *filename, const char *mode);
     531              : extern stream *opengzfile(const char *filename, const char *mode, stream *file = nullptr, int level = Z_BEST_COMPRESSION);
     532              : 
     533              : template<class T>
     534           13 : inline void putint_(T &p, int n)
     535              : {
     536           13 :     if(n<128 && n>-127)
     537              :     {
     538           11 :         p.put(n);
     539              :     }
     540            2 :     else if(n<0x8000 && n>=-0x8000)
     541              :     {
     542            1 :         p.put(0x80);
     543            1 :         p.put(n);
     544            1 :         p.put(n>>8);
     545              :     }
     546              :     else
     547              :     {
     548            1 :         p.put(0x81);
     549            1 :         p.put(n);
     550            1 :         p.put(n>>8);
     551            1 :         p.put(n>>16);
     552            1 :         p.put(n>>24);
     553              :     }
     554           13 : }
     555              : 
     556              : template<class T>
     557            4 : inline void putuint_(T &p, int n)
     558              : {
     559            4 :     if(n < 0 || n >= (1<<21))
     560              :     {
     561            1 :         p.put(0x80 | (n & 0x7F));
     562            1 :         p.put(0x80 | ((n >> 7) & 0x7F));
     563            1 :         p.put(0x80 | ((n >> 14) & 0x7F));
     564            1 :         p.put(n >> 21);
     565              :     }
     566            3 :     else if(n < (1<<7))
     567              :     {
     568            1 :         p.put(n);
     569              :     }
     570            2 :     else if(n < (1<<14))
     571              :     {
     572            1 :         p.put(0x80 | (n & 0x7F));
     573            1 :         p.put(n >> 7);
     574              :     }
     575              :     else
     576              :     {
     577            1 :         p.put(0x80 | (n & 0x7F));
     578            1 :         p.put(0x80 | ((n >> 7) & 0x7F));
     579            1 :         p.put(n >> 14);
     580              :     }
     581            4 : }
     582              : 
     583              : extern void putint(std::vector<uchar> &p, int n);
     584              : 
     585              : template<typename T>
     586           11 : inline void vectorput(std::vector<uint8_t>& buf, const T& data)
     587              : {
     588           11 :     const uint8_t* data_ptr = reinterpret_cast<const uint8_t*>(&data);
     589           11 :     buf.insert(buf.end(), data_ptr, data_ptr + sizeof(T));
     590           11 : }
     591              : 
     592            1 : inline void vectorput(std::vector<uint8_t>& buf, const uint8_t* data, size_t size)
     593              : {
     594            1 :     buf.insert(buf.end(), data, data + size);
     595            1 : }
     596              : 
     597              : template<class T>
     598            2 : inline void sendstring_(const char *t, T &p)
     599              : {
     600           10 :     while(*t)
     601              :     {
     602            8 :         putint(p, *t++);
     603              :     }
     604            2 :     putint(p, 0);
     605            2 : }
     606              : 
     607              : template<class T>
     608            2 : inline void putfloat_(T &p, float f)
     609              : {
     610            2 :     p.put(reinterpret_cast<uchar *>(&f), sizeof(float));
     611            2 : }
     612              : 
     613              : extern void putint(ucharbuf &p, int n);
     614              : extern int getint(ucharbuf &p);
     615              : extern void putuint(ucharbuf &p, int n);
     616              : extern int getuint(ucharbuf &p);
     617              : extern void putfloat(ucharbuf &p, float f);
     618              : extern float getfloat(ucharbuf &p);
     619              : extern void sendstring(const char *t, ucharbuf &p);
     620              : extern void getstring(char *t, ucharbuf &p, size_t len);
     621              : 
     622              : template<size_t N>
     623            1 : inline void getstring(char (&t)[N], ucharbuf &p) { getstring(t, p, N); }
     624              : 
     625              : extern void filtertext(char *dst, const char *src, bool whitespace, bool forcespace, size_t len);
     626              : 
     627              : template<size_t N>
     628              : inline void filtertext(char (&dst)[N], const char *src, bool whitespace = true, bool forcespace = false) { filtertext(dst, src, whitespace, forcespace, N-1); }
     629              : 
     630              : #endif /* TOOLS_H_ */
        

Generated by: LCOV version 2.0-1