LCOV - code coverage report
Current view: top level - libprimis-headers - tools.h (source / functions) Hit Total Coverage
Test: Libprimis Test Coverage Lines: 188 190 98.9 %
Date: 2024-11-22 05:07:59 Functions: 85 106 80.2 %

          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        1622 : 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          19 : inline void formatstring(char (&d)[N], const char *fmt, ...)
     168             : {
     169             :     va_list v;
     170          19 :     va_start(v, fmt);
     171          19 :     vformatstring(d, fmt, v, static_cast<int>(N));
     172          19 :     va_end(v);
     173          19 : }
     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           3 : inline bool matchstring(std::string_view s, size_t len, std::string_view d)
     194             : {
     195           3 :     return len == d.size() && !std::memcmp(s.data(), d.data(), d.size());
     196             : }
     197             : 
     198         956 : inline char *newstring(size_t l)
     199             : {
     200         956 :     return new char[l+1];
     201             : }
     202         403 : inline char *newstring(const char *s, size_t l)
     203             : {
     204         403 :     return copystring(newstring(l), s, l+1);
     205             : }
     206         446 : inline char *newstring(const char *s)
     207             : {
     208         446 :     size_t l = strlen(s);
     209         446 :     char *d = newstring(l);
     210         446 :     std::memcpy(d, s, l+1);
     211         446 :     return d;
     212             : }
     213             : 
     214           1 : inline char *newconcatstring(const char *s, const char *t)
     215             : {
     216           1 :     size_t slen = strlen(s),
     217           1 :            tlen = strlen(t);
     218           1 :     char *r = newstring(slen + tlen);
     219           1 :     std::memcpy(r, s, slen);
     220           1 :     std::memcpy(&r[slen], t, tlen);
     221           1 :     r[slen+tlen] = '\0';
     222           1 :     return r;
     223             : }
     224             : 
     225             : template <class T>
     226             : struct databuf
     227             : {
     228             :     enum
     229             :     {
     230             :         OVERREAD  = 1<<0,
     231             :         OVERWROTE = 1<<1
     232             :     };
     233             : 
     234             :     T *buf;
     235             :     int len, maxlen;
     236             :     uchar flags;
     237             : 
     238           1 :     databuf() : buf(nullptr), len(0), maxlen(0), flags(0) {}
     239             : 
     240             :     template<class U>
     241          22 :     databuf(T *buf, U maxlen) : buf(buf), len(0), maxlen((int)maxlen), flags(0) {}
     242             : 
     243          19 :     void reset()
     244             :     {
     245          19 :         len = 0;
     246          19 :         flags = 0;
     247          19 :     }
     248             : 
     249           1 :     void reset(T *buf_, int maxlen_)
     250             :     {
     251           1 :         reset();
     252           1 :         buf = buf_;
     253           1 :         maxlen = maxlen_;
     254           1 :     }
     255             : 
     256             :     /**
     257             :      * @brief Adds an existing value in the underlying buffer to the databuf
     258             :      *
     259             :      * Increases the length of the databuf by one and incorporates the value at
     260             :      * the address after the end of the databuf's values.
     261             :      *
     262             :      * If the length is equal to or greater than the buffer's maximum length,
     263             :      * applies the OVERREAD flag and returns a null value.
     264             :      */
     265          33 :     const T &get()
     266             :     {
     267             :         static const T overreadval = 0;
     268          33 :         if(len<maxlen)
     269             :         {
     270          32 :             return buf[len++];
     271             :         }
     272           1 :         flags |= OVERREAD;
     273           1 :         return overreadval;
     274             :     }
     275             : 
     276             :     /**
     277             :      * @brief Returns a databuf<T> object containing the first n entries
     278             :      *
     279             :      * Returns a databuf object of type T which represents the first n elements
     280             :      * inside the databuf's array.
     281             :      *
     282             :      * If the size passed is larger than the databuf, the entire databuf object is
     283             :      * copied and returned.
     284             :      *
     285             :      * @param sz the size of the output array (aka get the first `sz` entries)
     286             :      *
     287             :      * @return the sub-buffer of `this` object
     288             :      */
     289           1 :     databuf subbuf(int sz)
     290             :     {
     291           1 :         sz = std::clamp(sz, 0, maxlen-len);
     292           1 :         len += sz;
     293           1 :         return databuf(&buf[len-sz], sz);
     294             :     }
     295             : 
     296             :     /**
     297             :      * @brief Adds N empty elements to the end of the array and returns a pointer
     298             :      *
     299             :      * Creates an array of size `sz` which is then pointed to and returned as
     300             :      * a naked pointer.
     301             :      *
     302             :      * @param sz the size of the buffer
     303             :      *
     304             :      * @return a pointer to the sub-array created
     305             :      */
     306           2 :     T *pad(int numvals)
     307             :     {
     308           2 :         T *vals = &buf[len];
     309           2 :         len += min(numvals, maxlen-len);
     310           2 :         return vals;
     311             :     }
     312             : 
     313             :     /**
     314             :      * @brief Adds an entry to the databuf if space is available
     315             :      *
     316             :      * If no space is available, applies the OVERWROTE flag to the flags field.
     317             :      *
     318             :      * @param val A const reference to the object to add
     319             :      */
     320          36 :     void put(const T &val)
     321             :     {
     322          36 :         if(len<maxlen)
     323             :         {
     324          35 :             buf[len++] = val;
     325             :         }
     326             :         else
     327             :         {
     328           1 :             flags |= OVERWROTE;
     329             :         }
     330          36 :     }
     331             : 
     332           4 :     void put(const T *vals, int numvals)
     333             :     {
     334           4 :         if(maxlen - len < numvals)
     335             :         {
     336           1 :             numvals = maxlen - len;
     337           1 :             flags |= OVERWROTE;
     338             :         }
     339           4 :         std::memcpy(&buf[len], (const void *)vals, numvals*sizeof(T));
     340           4 :         len += numvals;
     341           4 :     }
     342             : 
     343           2 :     int get(T *vals, int numvals)
     344             :     {
     345           2 :         if(maxlen - len < numvals)
     346             :         {
     347           0 :             numvals = maxlen - len;
     348           0 :             flags |= OVERREAD;
     349             :         }
     350           2 :         std::memcpy(vals, (void *)&buf[len], numvals*sizeof(T));
     351           2 :         len += numvals;
     352           2 :         return numvals;
     353             :     }
     354             : 
     355           1 :     void offset(int n)
     356             :     {
     357           1 :         n = min(n, maxlen);
     358           1 :         buf += n;
     359           1 :         maxlen -= n;
     360           1 :         len = max(len-n, 0);
     361           1 :     }
     362             : 
     363             :     /**
     364             :      * @brief Returns a pointer to the internal data array.
     365             :      *
     366             :      * This is a naked pointer to the internal data array and can therefore be used
     367             :      * to potentially break this container, if used carelessly.
     368             :      *
     369             :      * @return A pointer the data array
     370             :      */
     371           3 :     T *getbuf() const { return buf; }
     372             : 
     373             :     /**
     374             :      * @brief Returns whether any entries have been assigned to the array.
     375             :      *
     376             :      * @return true if the array has not been assigned to
     377             :      * @return false if the array has assigned values
     378             :      */
     379           2 :     bool empty() const { return len==0; }
     380             : 
     381             :     /**
     382             :      * @brief Returns the number of allocated entries in the databuf.
     383             :      *
     384             :      * Returns the number of entries which have been added to the databuf (not the
     385             :      * overall databuf size).
     386             :      *
     387             :      * @return the number of entries allocated in the databuf.
     388             :      */
     389           8 :     int length() const { return len; }
     390             : 
     391             :     /**
     392             :      * @brief Returns the number of values remaining before the databuf overflows.
     393             :      *
     394             :      * Returns the allocatable space remaining within the databuf object, in terms
     395             :      * of the number of entires which can be `put` into it before it becomes
     396             :      * OVERWROTE.
     397             :      *
     398             :      * @return the number of available entries in the databuf.
     399             :      */
     400          17 :     int remaining() const { return maxlen-len; }
     401             : 
     402             :     /**
     403             :      * @brief Returns whether the databuf has been accessed with too large of an index.
     404             :      *
     405             :      * Returns whether the OVERREAD flag has been set. If the databuf was attempted
     406             :      * to be accessed with an index larger than the number of allocated members,
     407             :      * this value will be set.
     408             :      *
     409             :      * @return true if the array has been overread
     410             :      * @return false if all read operations have been to valid entries
     411             :      */
     412           6 :     bool overread() const { return (flags&OVERREAD)!=0; }
     413             : 
     414             :     /**
     415             :      * @brief Returns whether the databuf has had invalid writes to it
     416             :      *
     417             :      * Returns whether the OVERWROTE flag has been set. If the databuf was attempted
     418             :      * to be wrote to while the databuf is already full, this flag will be set.
     419             :      *
     420             :      * @return true if the databuf has not been overwritten
     421             :      * @return false if the databuf has had only valid writes
     422             :      */
     423           2 :     bool overwrote() const { return (flags&OVERWROTE)!=0; }
     424             : 
     425           4 :     bool check(int n) { return remaining() >= n; }
     426             : 
     427           1 :     void forceoverread()
     428             :     {
     429           1 :         len = maxlen;
     430           1 :         flags |= OVERREAD;
     431           1 :     }
     432             : };
     433             : 
     434             : typedef databuf<char> charbuf;
     435             : typedef databuf<uchar> ucharbuf;
     436             : 
     437          11 : inline uint memhash(const void *ptr, int len)
     438             : {
     439          11 :     const uchar *data = (const uchar *)ptr;
     440          11 :     uint h = 5381;
     441         539 :     for(int i = 0; i < static_cast<int>(len); ++i)
     442             :     {
     443         528 :         h = ((h<<5)+h)^data[i];
     444             :     }
     445          11 :     return h;
     446             : }
     447             : 
     448             : template<class T>
     449           2 : inline T endianswap(T n) { union { T t; uint i; } conv; conv.t = n; conv.i = SDL_Swap32(conv.i); return conv.t; }
     450             : 
     451             : template<>
     452           3 : inline uint endianswap<uint>(uint n) { return SDL_Swap32(n); }
     453             : 
     454             : template<>
     455           4 : inline int endianswap<int>(int n) { return SDL_Swap32(n); }
     456             : 
     457             : /* workaround for some C platforms that have these two functions as macros - not used anywhere */
     458             : #ifdef getchar
     459             :     #undef getchar
     460             : #endif
     461             : #ifdef putchar
     462             :     #undef putchar
     463             : #endif
     464             : 
     465             : struct stream
     466             : {
     467             : #ifdef WIN32
     468             :     #if defined(__GNUC__) && !defined(__MINGW32__)
     469             :         typedef off64_t offset;
     470             :     #else
     471             :         typedef __int64 offset;
     472             :     #endif
     473             :     #else
     474             :         typedef off_t offset;
     475             : #endif
     476             :     //see file/gz/zipstream children for more interesting forms
     477          12 :     virtual ~stream() {}
     478             :     virtual void close() = 0;
     479             :     virtual bool end() = 0;
     480           4 :     virtual offset tell() { return -1; }
     481           1 :     virtual offset rawtell() { return tell(); }
     482           1 :     virtual bool seek(offset, int) { return false; }
     483             :     virtual offset size();
     484           1 :     virtual offset rawsize() { return size(); }
     485           4 :     virtual size_t read(void *, size_t) { return 0; }
     486           8 :     virtual size_t write(const void *, size_t) { return 0; }
     487           1 :     virtual bool flush() { return true; }
     488           1 :     virtual int getchar() { uchar c; return read(&c, 1) == 1 ? c : -1; }
     489           1 :     virtual bool putchar(int n) { uchar c = n; return write(&c, 1) == 1; }
     490             :     virtual bool getline(char *str, size_t len);
     491           2 :     virtual bool putstring(const char *str) { size_t len = strlen(str); return write(str, len) == len; }
     492           1 :     virtual bool putline(const char *str) { return putstring(str) && putchar('\n'); }
     493             :     virtual size_t printf(const char *fmt, ...) PRINTFARGS(2, 3);
     494           1 :     virtual uint getcrc() { return 0; }
     495             : 
     496             :     template<class T>
     497           1 :     size_t put(const T *v, size_t n) { return write(v, n*sizeof(T))/sizeof(T); }
     498             : 
     499             :     template<class T>
     500           2 :     bool put(T n) { return write(&n, sizeof(n)) == sizeof(n); }
     501             : 
     502             :     template<class T>
     503           1 :     size_t get(T *v, size_t n) { return read(v, n*sizeof(T))/sizeof(T); }
     504             : 
     505             :     template<class T>
     506           1 :     T get() { T n; return read(&n, sizeof(n)) == sizeof(n) ? n : 0; }
     507             : 
     508             :     template<class T>
     509           1 :     bool putbig(T n) { return put<T>(endianswap(n)); }
     510             : 
     511             :     SDL_RWops *rwops();
     512             : };
     513             : 
     514             : extern string homedir;
     515             : 
     516             : extern char *path(char *s);
     517             : extern std::string path(std::string s);
     518             : extern char *copypath(const char *s);
     519             : extern const char *sethomedir(const char *dir);
     520             : extern const char *findfile(const char *filename, const char *mode);
     521             : 
     522             : /**
     523             :  * @brief Initializes zip Cubescript commands.
     524             :  *
     525             :  * `addzip`
     526             :  *
     527             :  * `removezip`
     528             :  */
     529             : extern void initzipcmds();
     530             : 
     531             : extern stream *openrawfile(const char *filename, const char *mode);
     532             : extern stream *openzipfile(const char *filename, const char *mode);
     533             : extern stream *openfile(const char *filename, const char *mode);
     534             : extern stream *opengzfile(const char *filename, const char *mode, stream *file = nullptr, int level = Z_BEST_COMPRESSION);
     535             : 
     536             : template<class T>
     537          13 : inline void putint_(T &p, int n)
     538             : {
     539          13 :     if(n<128 && n>-127)
     540             :     {
     541          11 :         p.put(n);
     542             :     }
     543           2 :     else if(n<0x8000 && n>=-0x8000)
     544             :     {
     545           1 :         p.put(0x80);
     546           1 :         p.put(n);
     547           1 :         p.put(n>>8);
     548             :     }
     549             :     else
     550             :     {
     551           1 :         p.put(0x81);
     552           1 :         p.put(n);
     553           1 :         p.put(n>>8);
     554           1 :         p.put(n>>16);
     555           1 :         p.put(n>>24);
     556             :     }
     557          13 : }
     558             : 
     559             : template<class T>
     560           4 : inline void putuint_(T &p, int n)
     561             : {
     562           4 :     if(n < 0 || n >= (1<<21))
     563             :     {
     564           1 :         p.put(0x80 | (n & 0x7F));
     565           1 :         p.put(0x80 | ((n >> 7) & 0x7F));
     566           1 :         p.put(0x80 | ((n >> 14) & 0x7F));
     567           1 :         p.put(n >> 21);
     568             :     }
     569           3 :     else if(n < (1<<7))
     570             :     {
     571           1 :         p.put(n);
     572             :     }
     573           2 :     else if(n < (1<<14))
     574             :     {
     575           1 :         p.put(0x80 | (n & 0x7F));
     576           1 :         p.put(n >> 7);
     577             :     }
     578             :     else
     579             :     {
     580           1 :         p.put(0x80 | (n & 0x7F));
     581           1 :         p.put(0x80 | ((n >> 7) & 0x7F));
     582           1 :         p.put(n >> 14);
     583             :     }
     584           4 : }
     585             : 
     586             : extern void putint(std::vector<uchar> &p, int n);
     587             : 
     588             : template<typename T>
     589          11 : inline void vectorput(std::vector<uint8_t>& buf, const T& data)
     590             : {
     591          11 :     const uint8_t* data_ptr = reinterpret_cast<const uint8_t*>(&data);
     592          11 :     buf.insert(buf.end(), data_ptr, data_ptr + sizeof(T));
     593          11 : }
     594             : 
     595           1 : inline void vectorput(std::vector<uint8_t>& buf, const uint8_t* data, size_t size)
     596             : {
     597           1 :     buf.insert(buf.end(), data, data + size);
     598           1 : }
     599             : 
     600             : template<class T>
     601           2 : inline void sendstring_(const char *t, T &p)
     602             : {
     603          10 :     while(*t)
     604             :     {
     605           8 :         putint(p, *t++);
     606             :     }
     607           2 :     putint(p, 0);
     608           2 : }
     609             : 
     610             : template<class T>
     611           2 : inline void putfloat_(T &p, float f)
     612             : {
     613           2 :     p.put((uchar *)&f, sizeof(float));
     614           2 : }
     615             : 
     616             : extern void putint(ucharbuf &p, int n);
     617             : extern int getint(ucharbuf &p);
     618             : extern void putuint(ucharbuf &p, int n);
     619             : extern int getuint(ucharbuf &p);
     620             : extern void putfloat(ucharbuf &p, float f);
     621             : extern float getfloat(ucharbuf &p);
     622             : extern void sendstring(const char *t, ucharbuf &p);
     623             : extern void getstring(char *t, ucharbuf &p, size_t len);
     624             : 
     625             : template<size_t N>
     626           1 : inline void getstring(char (&t)[N], ucharbuf &p) { getstring(t, p, N); }
     627             : 
     628             : extern void filtertext(char *dst, const char *src, bool whitespace, bool forcespace, size_t len);
     629             : 
     630             : template<size_t N>
     631             : inline void filtertext(char (&dst)[N], const char *src, bool whitespace = true, bool forcespace = false) { filtertext(dst, src, whitespace, forcespace, N-1); }
     632             : 
     633             : #endif /* TOOLS_H_ */

Generated by: LCOV version 1.14