aboutsummaryrefslogtreecommitdiff
path: root/project/dclib/dclib-basics.h
diff options
context:
space:
mode:
authorroot <root@dc13.lemmi>2020-07-21 10:00:46 +0200
committerroot <root@dc13.lemmi>2020-07-21 10:00:46 +0200
commit1192c4575ea7afdf38e3fa0df4587a08620af11e (patch)
tree6910a62487c282d0840d2e668aa7eb40b7c8a3fd /project/dclib/dclib-basics.h
parent76de8a89f7c1d1b4522eb66e8f89d248e8c1781f (diff)
SZS v2.18a
Diffstat (limited to '')
-rw-r--r--project/dclib/dclib-basics.h5252
1 files changed, 5252 insertions, 0 deletions
diff --git a/project/dclib/dclib-basics.h b/project/dclib/dclib-basics.h
new file mode 100644
index 0000000..7c6e7a2
--- /dev/null
+++ b/project/dclib/dclib-basics.h
@@ -0,0 +1,5252 @@
+
+/***************************************************************************
+ * *
+ * _____ ____ *
+ * | __ \ / __ \ _ _ _____ *
+ * | | \ \ / / \_\ | | | | _ \ *
+ * | | \ \| | | | | | |_| | *
+ * | | | || | | | | | ___/ *
+ * | | / /| | __ | | | | _ \ *
+ * | |__/ / \ \__/ / | |___| | |_| | *
+ * |_____/ \____/ |_____|_|_____/ *
+ * *
+ * Wiimms source code library *
+ * *
+ ***************************************************************************
+ * *
+ * Copyright (c) 2012-2020 by Dirk Clemens <wiimm@wiimm.de> *
+ * *
+ ***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * See file gpl-2.0.txt or http://www.gnu.org/licenses/gpl-2.0.txt *
+ * *
+ ***************************************************************************/
+
+#ifndef DCLIB_BASICS_H
+#define DCLIB_BASICS_H 1
+
+#define _GNU_SOURCE 1
+
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+
+#ifndef WIN_DCLIB
+ #include <stdint.h>
+#endif
+
+#include "dclib-types.h"
+#include "dclib-debug.h"
+#include "dclib-color.h"
+#include "dclib-numeric.h"
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// helpers ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+#define SIZEOFMEMBER(type,a) sizeof(((type*)0)->a)
+
+#define SIZEOFRANGE(type,a,b) \
+ ( offsetof(type,b) + sizeof(((type*)0)->b) - offsetof(type,a) )
+
+#define PTR_DISTANCE(a,b) ( (u8*)(a) - (u8*)(b) )
+#define PTR_DISTANCE_INT(a,b) ( (int)( (u8*)(a) - (u8*)(b) ))
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// bits ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+extern const uchar TableBitCount[0x100];
+extern const char TableLowest0Bit[0x100];
+extern const char TableLowest1Bit[0x100];
+extern const char TableHighest0Bit[0x100];
+extern const char TableHighest1Bit[0x100];
+
+uint Count1Bits ( cvp addr, uint size );
+static inline uint Count0Bits ( cvp addr, uint size )
+ { return CHAR_BIT * size - Count1Bits(addr,size); }
+
+#define Count1BitsObj(obj) Count1Bits(&(obj),sizeof(obj))
+#define Count0BitsObj(obj) Count1Bits(&(obj),sizeof(obj))
+
+static inline uint Count1Bits8 ( u8 data )
+{
+ return TableBitCount[data];
+}
+
+static inline uint Count1Bits16 ( u16 data )
+{
+ const u8 * d = (u8*)&data;
+ return TableBitCount[d[0]]
+ + TableBitCount[d[1]];
+}
+
+static inline uint Count1Bits32 ( u32 data )
+{
+ // __builtin_popcount(unsigned int) is slower than table based summary
+
+ const u8 * d = (u8*)&data;
+ return TableBitCount[d[0]]
+ + TableBitCount[d[1]]
+ + TableBitCount[d[2]]
+ + TableBitCount[d[3]];
+}
+
+static inline uint Count1Bits64 ( u64 data )
+{
+ #if __GNUC__ > 3
+ return __builtin_popcountll(data);
+ #else
+ const u8 * d = (u8*)&data;
+ return TableBitCount[d[0]]
+ + TableBitCount[d[1]]
+ + TableBitCount[d[2]]
+ + TableBitCount[d[3]]
+ + TableBitCount[d[4]]
+ + TableBitCount[d[5]]
+ + TableBitCount[d[6]]
+ + TableBitCount[d[7]];
+ #endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+int FindLowest0BitBE ( cvp addr, uint size );
+int FindLowest1BitBE ( cvp addr, uint size );
+int FindHighest0BitBE ( cvp addr, uint size );
+int FindHighest1BitBE ( cvp addr, uint size );
+
+int FindLowest0BitLE ( cvp addr, uint size );
+int FindLowest1BitLE ( cvp addr, uint size );
+int FindHighest0BitLE ( cvp addr, uint size );
+int FindHighest1BitLE ( cvp addr, uint size );
+
+#if __BYTE_ORDER == 1234
+ #define FindLowest0Bit FindLowest0BitLE
+ #define FindLowest1Bit FindLowest1BitLE
+ #define FindHighest0Bit FindHighest0BitLE
+ #define FindHighest1Bit FindHighest1BitLE
+#else
+ #define FindLowest0Bit FindLowest0BitBE
+ #define FindLowest1Bit FindLowest1BitBE
+ #define FindHighest0Bit FindHighest0BitBE
+ #define FindHighest1Bit FindHighest1BitBE
+#endif
+
+u32 GetAlign32 ( u32 data );
+u64 GetAlign64 ( u64 data );
+
+///////////////////////////////////////////////////////////////////////////////
+
+static inline void SetBit ( void *addr, uint bit_num )
+ { ((u8*)addr)[ bit_num >> 3 ] |= 1 << ( bit_num & 7 ); }
+
+static inline void ClearBit ( void *addr, uint bit_num )
+ { ((u8*)addr)[ bit_num >> 3 ] &= ~(1 << ( bit_num & 7 )); }
+
+static inline void InvertBit ( void *addr, uint bit_num )
+ { ((u8*)addr)[ bit_num >> 3 ] ^= 1 << ( bit_num & 7 ); }
+
+static inline bool TestBit ( const void *addr, uint bit_num )
+ { return ( ((u8*)addr)[ bit_num >> 3 ] & 1 << ( bit_num & 7 ) ) != 0; }
+
+// change a single bit and return the previous state
+bool TestSetBit ( void *addr, uint bit_num );
+bool TestClearBit ( void *addr, uint bit_num );
+bool TestInvertBit ( void *addr, uint bit_num );
+
+// change bits inclusive 'beg' to exclusive 'end' if beg_bitnum<end_bitnum
+void SetBits ( void *addr, uint beg_bitnum, uint end_bitnum );
+void ClearBits ( void *addr, uint beg_bitnum, uint end_bitnum );
+void InvertBits ( void *addr, uint beg_bitnum, uint end_bitnum );
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+int PrintBitfieldEx
+(
+ // returns the number of printed characters, or -1 if buffer is to small
+
+ char *buf, // buffer
+ uint buf_size, // size of 'buf'
+ cvp bit_field, // address of bit field
+ uint min_idx, // minimal index (inclusive) to check
+ uint max_idx, // maximal index (inclusive) to check
+ bool use_ranges, // true: create ranges 'a:b'
+ int mult, // each printed index is first multiplyed by 'mult'
+ int add // ... and then added to 'add'.
+);
+
+static inline int PrintBitfield
+(
+ // returns the number of printed characters, or -1 if buffer is to small
+
+ char *buf, // buffer
+ uint buf_size, // size of 'buf'
+ cvp bit_field, // address of bit field
+ uint bit_field_size, // size of 'bit_field' in bytes
+ bool use_ranges // true: create ranges 'a:b'
+)
+{
+ return PrintBitfieldEx ( buf, buf_size, bit_field,
+ 0, 8*bit_field_size-1, use_ranges, 1, 0 );
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// low level endian conversions ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+//----------------------------------------------------
+// swapping bytes = inverse byte order
+// void dswap16 ( void * data_ptr );
+// void dswap24 ( void * data_ptr );
+// void dswap32 ( void * data_ptr );
+// void dswap48 ( void * data_ptr );
+// void dswap64 ( void * data_ptr );
+//----------------------------------------------------
+
+static inline void dswap16 ( void * data_ptr )
+{
+ u8 *d = data_ptr;
+ u8 temp = d[0];
+ d[0] = d[1];
+ d[1] = temp;
+}
+
+static inline void dswap24 ( void * data_ptr )
+{
+ u8 *d = data_ptr;
+ const u8 temp = d[0];
+ d[0] = d[2];
+ d[2] = temp;
+}
+
+static inline void dswap32 ( void * data_ptr )
+{
+ u8 temp, *d = data_ptr;
+ temp = d[0]; d[0] = d[3]; d[3] = temp;
+ temp = d[1]; d[1] = d[2]; d[2] = temp;
+}
+
+static inline void dswap48 ( void * data_ptr )
+{
+ u8 temp, *d = data_ptr;
+ temp = d[0]; d[0] = d[5]; d[5] = temp;
+ temp = d[1]; d[1] = d[4]; d[4] = temp;
+ temp = d[2]; d[2] = d[3]; d[3] = temp;
+}
+
+static inline void dswap64 ( void * data_ptr )
+{
+ u8 temp, *d = data_ptr;
+ temp = d[0]; d[0] = d[7]; d[7] = temp;
+ temp = d[1]; d[1] = d[6]; d[6] = temp;
+ temp = d[2]; d[2] = d[5]; d[5] = temp;
+ temp = d[3]; d[3] = d[4]; d[4] = temp;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+//----------------------------------------------------
+// read data and swap bytes (inverse byte order)
+// u16 swap16 ( const void * data_ptr );
+// u32 swap24 ( const void * data_ptr );
+// u32 swap32 ( const void * data_ptr );
+// u64 swap48 ( const void * data_ptr );
+// u64 swap64 ( const void * data_ptr );
+// float swapf4 ( const void * data_ptr );
+// double swapf8 ( const void * data_ptr );
+//----------------------------------------------------
+
+static inline u16 swap16 ( const void * data_ptr )
+{
+ u8 r[2];
+ const u8 *d = data_ptr;
+ r[1] = *d++;
+ r[0] = *d;
+ return *(u16*)r;
+}
+
+static inline u32 swap24 ( const void * data_ptr )
+{
+ u8 r[4];
+ const u8 *d = data_ptr;
+ r[3] = 0;
+ r[2] = *d++;
+ r[1] = *d++;
+ r[0] = *d;
+ return *(u32*)r;
+}
+
+static inline u32 swap32 ( const void * data_ptr )
+{
+ u8 r[4];
+ const u8 *d = data_ptr;
+ r[3] = *d++;
+ r[2] = *d++;
+ r[1] = *d++;
+ r[0] = *d;
+ return *(u32*)r;
+}
+
+static inline u64 swap48 ( const void * data_ptr )
+{
+ u8 r[8];
+ const u8 *d = data_ptr;
+ r[7] = 0;
+ r[6] = 0;
+ r[5] = *d++;
+ r[4] = *d++;
+ r[3] = *d++;
+ r[2] = *d++;
+ r[1] = *d++;
+ r[0] = *d;
+ return *(u64*)r;
+}
+
+static inline u64 swap64 ( const void * data_ptr )
+{
+ u8 r[8];
+ const u8 *d = data_ptr;
+ r[7] = *d++;
+ r[6] = *d++;
+ r[5] = *d++;
+ r[4] = *d++;
+ r[3] = *d++;
+ r[2] = *d++;
+ r[1] = *d++;
+ r[0] = *d;
+ return *(u64*)r;
+}
+
+static inline float swapf4 ( const void * data_ptr )
+{
+ // assume: local system supports IEEE 754
+ union { float f; u32 i; } u;
+ u.i = swap32(data_ptr);
+ return u.f;
+}
+
+static inline double swapf8 ( const void * data_ptr )
+{
+ // assume: local system supports IEEE 754
+ union { double f; u64 i; } u;
+ u.i = swap64(data_ptr);
+ return u.f;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+//----------------------------------------------------
+// convert big endian data to a number in host format
+// u16 be16 ( const void * be_data_ptr );
+// u32 be24 ( const void * be_data_ptr );
+// u32 be32 ( const void * be_data_ptr );
+// u64 be40 ( const void * be_data_ptr );
+// u64 be48 ( const void * be_data_ptr );
+// u64 be56 ( const void * be_data_ptr );
+// u64 be64 ( const void * be_data_ptr );
+// float bef4 ( const void * be_data_ptr );
+// double bef8 ( const void * be_data_ptr );
+//----------------------------------------------------
+
+static inline u16 be16 ( const void * be_data_ptr )
+{
+ const u8 * d = be_data_ptr;
+ return d[0] << 8 | d[1];
+}
+
+static inline u32 be24 ( const void * be_data_ptr )
+{
+ const u8 * d = be_data_ptr;
+ return ( d[0] << 8 | d[1] ) << 8 | d[2];
+}
+
+static inline u32 be32 ( const void * be_data_ptr )
+{
+ const u8 * d = be_data_ptr;
+ return (( d[0] << 8 | d[1] ) << 8 | d[2] ) << 8 | d[3];
+}
+
+static inline u64 be40 ( const void * be_data_ptr )
+{
+ const u8 * d = be_data_ptr;
+ return (u64)be32(d) << 8 | ((u8*)d)[4];
+}
+
+static inline u64 be48 ( const void * be_data_ptr )
+{
+ const u8 * d = be_data_ptr;
+ return (u64)be32(d) << 16 | be16(d+4);
+}
+
+static inline u64 be56 ( const void * be_data_ptr )
+{
+ const u8 * d = be_data_ptr;
+ return (u64)be32(d) << 24 | be24(d+4);
+}
+
+static inline u64 be64 ( const void * be_data_ptr )
+{
+ const u8 * d = be_data_ptr;
+ return (u64)be32(d) << 32 | be32(d+4);
+}
+
+static inline float bef4 ( const void * be_data_ptr )
+{
+ // assume: local system supports IEEE 754
+ union { float f; u32 i; } u;
+ u.i = be32(be_data_ptr);
+ return u.f;
+}
+
+static inline double bef8 ( const void * be_data_ptr )
+{
+ // assume: local system supports IEEE 754
+ union { double f; u64 i; } u;
+ u.i = be64(be_data_ptr);
+ return u.f;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+//-------------------------------------------------------
+// convert little endian data to a number in host format
+// u16 le16 ( const void * le_data_ptr );
+// u32 le24 ( const void * le_data_ptr );
+// u32 le32 ( const void * le_data_ptr );
+// u64 le40 ( const void * le_data_ptr );
+// u64 le48 ( const void * le_data_ptr );
+// u64 le56 ( const void * le_data_ptr );
+// u64 le64 ( const void * le_data_ptr );
+// float lef4 ( const void * le_data_ptr );
+// double lef8 ( const void * le_data_ptr );
+//-------------------------------------------------------
+
+static inline u16 le16 ( const void * le_data_ptr )
+{
+ const u8 * d = le_data_ptr;
+ return d[1] << 8 | d[0];
+}
+
+static inline u32 le24 ( const void * le_data_ptr )
+{
+ const u8 * d = le_data_ptr;
+ return ( d[2] << 8 | d[1] ) << 8 | d[0];
+}
+
+static inline u32 le32 ( const void * le_data_ptr )
+{
+ const u8 * d = le_data_ptr;
+ return (( d[3] << 8 | d[2] ) << 8 | d[1] ) << 8 | d[0];
+}
+
+static inline u64 le40 ( const void * le_data_ptr )
+{
+ const u8 * d = le_data_ptr;
+ return (u64)le32(d+1) << 8 | ((u8*)d)[0];
+}
+
+static inline u64 le48 ( const void * le_data_ptr )
+{
+ const u8 * d = le_data_ptr;
+ return (u64)le16(d+4) << 32 | le32(d);
+}
+
+static inline u64 le56 ( const void * le_data_ptr )
+{
+ const u8 * d = le_data_ptr;
+ return (u64)le24(d+4) << 32 | le32(d);
+}
+
+static inline u64 le64 ( const void * le_data_ptr )
+{
+ const u8 * d = le_data_ptr;
+ return (u64)le32(d+4) << 32 | le32(d);
+}
+
+static inline float lef4 ( const void * le_data_ptr )
+{
+ // assume: local system supports IEEE 754
+
+ union { float f; u32 i; } u;
+ u.i = le32(le_data_ptr);
+ return u.f;
+}
+
+static inline double lef8 ( const void * le_data_ptr )
+{
+ // assume: local system supports IEEE 754
+
+ union { double f; u64 i; } u;
+ u.i = le64(le_data_ptr);
+ return u.f;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+//-------------------------------------------
+// convert u64 from/to network byte order
+// be64_t hton64 ( u64 data );
+// u64 ntoh64 ( be64_t data );
+//-------------------------------------------
+
+static inline be64_t hton64 ( u64 data )
+{
+ be64_t result;
+ ((u32*)&result)[0] = htonl( (u32)(data >> 32) );
+ ((u32*)&result)[1] = htonl( (u32)data );
+ return result;
+}
+
+static inline u64 ntoh64 ( be64_t data )
+{
+ return (u64)ntohl(((u32*)&data)[0]) << 32 | ntohl(((u32*)&data)[1]);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+// convert a number in host format into big endian data
+void write_be16 ( void * be_data_ptr, u16 data );
+void write_be24 ( void * be_data_ptr, u32 data );
+void write_be32 ( void * be_data_ptr, u32 data );
+void write_be40 ( void * be_data_ptr, u64 data );
+void write_be48 ( void * be_data_ptr, u64 data );
+void write_be56 ( void * be_data_ptr, u64 data );
+void write_be64 ( void * be_data_ptr, u64 data );
+void write_bef4 ( void * be_data_ptr, float data );
+void write_bef8 ( void * be_data_ptr, double data );
+
+// convert a number in host format into little endian data
+void write_le16 ( void * le_data_ptr, u16 data );
+void write_le24 ( void * le_data_ptr, u32 data );
+void write_le32 ( void * le_data_ptr, u32 data );
+void write_le40 ( void * le_data_ptr, u64 data );
+void write_le48 ( void * le_data_ptr, u64 data );
+void write_le56 ( void * le_data_ptr, u64 data );
+void write_le64 ( void * le_data_ptr, u64 data );
+void write_lef4 ( void * le_data_ptr, float data );
+void write_lef8 ( void * le_data_ptr, double data );
+
+// convert lists
+void be16n ( u16 * dest, const u16 * src, int n );
+void be32n ( u32 * dest, const u32 * src, int n );
+void bef4n ( float32 * dest, const float32 * src, int n );
+void le16n ( u16 * dest, const u16 * src, int n );
+void lef4n ( float32 * dest, const float32 * src, int n );
+
+void write_be16n ( u16 * dest, const u16 * src, int n );
+void write_be32n ( u32 * dest, const u32 * src, int n );
+void write_bef4n ( float32 * dest, const float32 * src, int n );
+void write_le16n ( u16 * dest, const u16 * src, int n );
+void write_lef4n ( float32 * dest, const float32 * src, int n );
+
+//-----------------------------------------------------------------------------
+// [[endian_func_t]]
+
+typedef struct endian_func_t
+{
+ //--- info section
+
+ u8 bom[2]; // btye order mark: BE=0xfe,0xff, LE=0xff,0xfe
+ bool is_be; // true: is big endian
+ bool is_le; // true: is little endian
+ dcEndian_t endian; // DC_BIG_ENDIAN or DC_LITTLE_ENDIAN
+
+ //--- read functions
+
+ u16 (*rd16) ( const void * data_ptr );
+ u32 (*rd24) ( const void * data_ptr );
+ u32 (*rd32) ( const void * data_ptr );
+ u64 (*rd40) ( const void * data_ptr );
+ u64 (*rd48) ( const void * data_ptr );
+ u64 (*rd56) ( const void * data_ptr );
+ u64 (*rd64) ( const void * data_ptr );
+ float (*rdf4) ( const void * data_ptr );
+ double (*rdf8) ( const void * data_ptr );
+
+ //--- write functions
+
+ void (*wr16) ( void * data_ptr, u16 data );
+ void (*wr24) ( void * data_ptr, u32 data );
+ void (*wr32) ( void * data_ptr, u32 data );
+ void (*wr40) ( void * data_ptr, u64 data );
+ void (*wr48) ( void * data_ptr, u64 data );
+ void (*wr56) ( void * data_ptr, u64 data );
+ void (*wr64) ( void * data_ptr, u64 data );
+ void (*wrf4) ( void * data_ptr, float data );
+ void (*wrf8) ( void * data_ptr, double data );
+
+} endian_func_t;
+
+extern const endian_func_t be_func;
+extern const endian_func_t le_func;
+
+const endian_func_t * GetEndianFunc ( const void * byte_order_mark );
+uint GetTextBOMLen ( const void * data, uint data_size );
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// struct mem_t ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[mem_t]]
+
+typedef struct mem_t
+{
+ ccp ptr; // NULL or a pointer to the data
+ int len; // length in bytes of the data
+}
+mem_t;
+
+extern mem_t EmptyMem; // mem_t(EmptyString,0)
+extern mem_t NullMem; // mem_t(0,0)
+
+//-----------------------------------------------------------------------------
+
+static inline mem_t MemByChar ( char ch )
+{
+ mem_t mem = { &ch, 1 };
+ return mem;
+}
+
+static inline mem_t MemByString0 ( ccp str )
+{
+ if (!str)
+ return NullMem;
+
+ mem_t mem = { str, strlen(str) };
+ return mem;
+}
+
+static inline mem_t MemByString ( ccp str )
+{
+ mem_t mem = { str, strlen(str) };
+ return mem;
+}
+
+static inline mem_t MemByStringS ( ccp str, int len )
+{
+ mem_t mem = { str, len < 0 ? strlen(str) : len };
+ return mem;
+}
+
+static inline mem_t MemByStringE ( ccp str, ccp end )
+{
+ mem_t mem = { str, end ? end-str : strlen(str) };
+ return mem;
+}
+
+static inline mem_t MemByS ( ccp str, int len )
+{
+ mem_t mem = { str, len };
+ return mem;
+}
+
+static inline mem_t MemByE ( ccp str, ccp end )
+{
+ mem_t mem = { str, end-str };
+ return mem;
+}
+
+//-----------------------------------------------------------------------------
+
+// Index helpers
+// For the 'End' variants, index 0 is end_of_source
+
+int CheckIndex1 ( int max, int index );
+int CheckIndex1End ( int max, int index );
+int CheckIndex2 ( int max, int * p_begin, int * p_end );
+int CheckIndex2End ( int max, int * p_begin, int * p_end );
+
+//-----------------------------------------------------------------------------
+
+// All functions are robust.
+// A negative index is relative to the end of source.
+// For RightMem() and ExtractEndMem(), index 0 means: end of source.
+// count<0 means: copy left from 'begin' (only MidMem()) or skip bytes.
+
+mem_t MidMem ( const mem_t src, int begin, int count );
+
+static inline mem_t LeftMem ( const mem_t src, int count )
+{
+ mem_t res;
+ res.ptr = src.ptr;
+ res.len = CheckIndex1(src.len,count);
+ return res;
+}
+
+static inline mem_t RightMem ( const mem_t src, int count )
+{
+ mem_t res;
+ res.len = src.len - CheckIndex1End(src.len,-count);
+ res.ptr = src.ptr + src.len - res.len;
+ return res;
+}
+
+static inline mem_t ExtractMem ( const mem_t src, int begin, int end )
+{
+ mem_t res;
+ res.len = CheckIndex2(src.len,&begin,&end);
+ res.ptr = src.ptr + begin;
+ return res;
+}
+
+static inline mem_t ExtractEndMem ( const mem_t src, int begin, int end )
+{
+ mem_t res;
+ res.len = CheckIndex2End(src.len,&begin,&end);
+ res.ptr = src.ptr + begin;
+ return res;
+}
+
+mem_t BeforeMem ( const mem_t src, ccp ref );
+mem_t BehindMem ( const mem_t src, ccp ref );
+
+//-----------------------------------------------------------------------------
+
+// Alloc dest buffer and terminate with 0.
+// If m*.len < 0, then use strlen().
+
+mem_t MemCat2A ( const mem_t m1, const mem_t m2 );
+mem_t MemCat3A ( const mem_t m1, const mem_t m2, const mem_t m3 );
+
+//-----------------------------------------------------------------------------
+
+int CmpMem ( const mem_t s1, const mem_t s2 );
+int StrCmpMem ( const mem_t mem, ccp str );
+bool LeftStrCmpMemEQ ( const mem_t mem, ccp str );
+
+// free a string if str is not NULL|EmptyString|MinusString
+void FreeString ( ccp str );
+
+static inline void FreeMem ( mem_t *mem )
+{
+ DASSERT(mem);
+ FreeString(mem->ptr);
+ mem->ptr = 0;
+ mem->len = 0;
+}
+
+static inline void AssignDupMem ( mem_t *dest, mem_t src )
+{
+ DASSERT(dest);
+ FreeString(dest->ptr);
+ dest->ptr = MEMDUP(src.ptr,src.len);
+ dest->len = src.len;
+}
+
+static inline mem_t DupMem ( const mem_t src )
+{
+ mem_t res = { MEMDUP(src.ptr,src.len), src.len };
+ return res;
+}
+
+static inline char * DupStrMem ( const mem_t src )
+{
+ return MEMDUP(src.ptr,src.len);
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// struct mem_list_t ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[mem_list_t]]
+
+typedef struct mem_list_t
+{
+ mem_t *list; // List of mem_t objects.
+ // Elements are always terminated with NULL.
+ // Content is stored in 'buf' or points to EmptyString.
+
+ uint used; // Number of active 'list' elements
+ uint size; // Number of alloced 'list' elements
+
+ char *buf; // Alloced temp buffer
+ uint buf_used; // Usage of 'buf'
+ uint buf_size; // Size of 'buf'
+}
+mem_list_t;
+
+//-----------------------------------------------------------------------------
+
+void InitializeMemList ( mem_list_t *ml );
+void ResetMemList ( mem_list_t *ml );
+void MoveMemList ( mem_list_t *dest, mem_list_t *src );
+
+void GrowBufMemList ( mem_list_t *ml, uint need_size );
+void PrepareMemList ( mem_list_t *ml, uint n_elem, uint buf_size );
+
+//-----------------------------------------------------------------------------
+
+void InsertMemListN
+(
+ mem_list_t *ml, // valid destination mem_list
+ int pos, // insert position => CheckIndex1()
+ const mem_t *src, // source list
+ uint src_len, // number of elements in source list
+ uint src_ignore // 0: insert all
+ // 1: ignore NULL
+ // 2: ignore NULL and empty
+ // 3: replace NULL by EmptyString
+);
+
+//-----------------------------------------------------------------------------
+
+static inline void InsertMemList2
+(
+ mem_list_t *ml, // valid destination mem_list
+ int pos, // insert position => CheckIndex1()
+ const mem_list_t *src, // source mem_list
+ uint src_ignore // 0: insert all
+ // 1: ignore NULL
+ // 2: ignore NULL and empty
+ // 3: replace NULL by EmptyString
+)
+{
+ DASSERT(src);
+ InsertMemListN(ml,pos,src->list,src->used,src_ignore);
+}
+
+//-----------------------------------------------------------------------------
+
+static inline void AppendMemListN
+(
+ mem_list_t *ml, // valid destination mem_list
+ const mem_t *src, // source list
+ uint src_len, // number of elements in source list
+ uint src_ignore // 0: insert all
+ // 1: ignore NULL
+ // 2: ignore NULL and empty
+ // 3: replace NULL by EmptyString
+)
+{
+ DASSERT(ml);
+ InsertMemListN(ml,ml->used,src,src_len,src_ignore);
+}
+
+//-----------------------------------------------------------------------------
+
+static inline void AppendMemList2
+(
+ mem_list_t *ml, // valid destination mem_list
+ const mem_list_t *src, // source mem_list
+ uint src_ignore // 0: insert all
+ // 1: ignore NULL
+ // 2: ignore NULL and empty
+ // 3: replace NULL by EmptyString
+)
+{
+ DASSERT(ml);
+ DASSERT(src);
+ InsertMemListN(ml,ml->used,src->list,src->used,src_ignore);
+}
+
+//-----------------------------------------------------------------------------
+
+static inline void AssignMemListN
+(
+ mem_list_t *ml, // valid destination mem_list
+ const mem_t *src, // source list
+ uint src_len, // number of elements in source list
+ uint src_ignore // 0: insert all
+ // 1: ignore NULL
+ // 2: ignore NULL and empty
+ // 3: replace NULL by EmptyString
+)
+{
+ DASSERT(ml);
+ ml->used = 0;
+ InsertMemListN(ml,0,src,src_len,src_ignore);
+}
+
+//-----------------------------------------------------------------------------
+
+static inline void AssignMemList2
+(
+ mem_list_t *ml, // valid destination mem_list
+ const mem_list_t *src, // source mem_list
+ uint src_ignore // 0: insert all
+ // 1: ignore NULL
+ // 2: ignore NULL and empty
+ // 3: replace NULL by EmptyString
+)
+{
+ DASSERT(ml);
+ DASSERT(src);
+ ml->used = 0;
+ InsertMemListN(ml,0,src->list,src->used,src_ignore);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CatMemListN
+(
+ mem_list_t *dest, // valid destination mem_list
+ const mem_list_t **src_list, // list with mem lists, element may be NULL
+ uint n_src_list, // number of elements in 'src'
+ uint src_ignore // 0: insert all
+ // 1: ignore NULL
+ // 2: ignore NULL and empty
+ // 3: replace NULL by EmptyString
+);
+
+//-----------------------------------------------------------------------------
+
+static inline void CatMemList2
+(
+ mem_list_t *dest, // valid destination mem_list
+ const mem_list_t *src1, // source mem_list
+ const mem_list_t *src2, // source mem_list
+ uint src_ignore // 0: insert all
+ // 1: ignore NULL
+ // 2: ignore NULL and empty
+ // 3: replace NULL by EmptyString
+)
+{
+ const mem_list_t *ml[2] = { src1, src2 };
+ CatMemListN(dest,ml,2,src_ignore);
+}
+
+//-----------------------------------------------------------------------------
+
+static inline void CatMemList3
+(
+ mem_list_t *dest, // valid destination mem_list
+ const mem_list_t *src1, // source mem_list
+ const mem_list_t *src2, // source mem_list
+ const mem_list_t *src3, // source mem_list
+ uint src_ignore // 0: insert all
+ // 1: ignore NULL
+ // 2: ignore NULL and empty
+ // 3: replace NULL by EmptyString
+)
+{
+ const mem_list_t *ml[3] = { src1, src2, src3 };
+ CatMemListN(dest,ml,3,src_ignore);
+}
+
+//-----------------------------------------------------------------------------
+
+// All functions are robust and modify the current list.
+// A negative index is relative to the end of source.
+// For RightMemList() and *EndMemList(), index 0 means: end of source.
+// count<0 means: copy left from 'begin' (only MidMemList()) or skip bytes.
+// All functions return the number of elements aufer operation.
+
+uint LeftMemList ( mem_list_t *ml, int count );
+uint RightMemList ( mem_list_t *ml, int count );
+uint MidMemList ( mem_list_t *ml, int begin, int count );
+uint ExtractMemList ( mem_list_t *ml, int begin, int end );
+uint ExtractEndMemList ( mem_list_t *ml, int begin, int end );
+uint RemoveMemList ( mem_list_t *ml, int begin, int end );
+uint RemoveEndMemList ( mem_list_t *ml, int begin, int end );
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// MemPool_t ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[MemPoolChunk_t]]
+
+typedef struct MemPoolChunk_t
+{
+ struct MemPoolChunk_t *next;
+ char data[];
+}
+MemPoolChunk_t;
+
+//-----------------------------------------------------------------------------
+// [[MemPool_t]]
+
+typedef struct MemPool_t
+{
+ MemPoolChunk_t *chunk; // pointer to first (=current) chunk
+ uint space; // space left in current chunk
+ uint chunk_size; // wanted chunk size
+}
+MemPool_t;
+
+//-----------------------------------------------------------------------------
+
+static inline void InitializeMemPool ( MemPool_t *mp, uint chunk_size )
+ { DASSERT(mp); memset(mp,0,sizeof(*mp)); mp->chunk_size = chunk_size; }
+
+void ResetMemPool ( MemPool_t *mp );
+void * MallocMemPool ( MemPool_t *mp, uint size );
+void * CallocMemPool ( MemPool_t *mp, uint size );
+void * MallocMemPoolA ( MemPool_t *mp, uint size, uint align );
+void * CallocMemPoolA ( MemPool_t *mp, uint size, uint align );
+void * MemDupMemPool ( MemPool_t *mp, cvp source, uint size );
+
+static inline void * StrDupMemPool ( MemPool_t *mp, ccp source )
+ { DASSERT(mp); return source ? MemDupMemPool(mp,source,strlen(source)) : 0; }
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// CircBuf_t ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[CircBuf_t]]
+
+typedef struct CircBuf_t
+{
+ char *buf; // NULL or alloced buffer
+ uint pos; // position of first valid byte
+ uint used; // used bytes in buffer
+ uint size; // size of 'buf'
+}
+CircBuf_t;
+
+///////////////////////////////////////////////////////////////////////////////
+
+void InitializeCircBuf ( CircBuf_t *cb, uint size );
+void ResetCircBuf ( CircBuf_t *cb );
+uint WriteCircBuf ( CircBuf_t *cb, cvp data, uint size );
+uint PeakCircBuf ( CircBuf_t *cb, char *buf, uint buf_size );
+uint ReadCircBuf ( CircBuf_t *cb, char *buf, uint buf_size );
+uint DropCircBuf ( CircBuf_t *cb, uint size );
+void ClearCircBuf ( CircBuf_t *cb );
+uint PurgeCircBuf ( CircBuf_t *cb );
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// CopyMode_t ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+typedef enum CopyMode_t
+{
+ CPM_COPY, // make a copy of the data, alloced
+ CPM_MOVE, // move the alloced data
+ CPM_LINK, // link the data
+
+} CopyMode_t;
+
+///////////////////////////////////////////////////////////////////////////////
+
+void * CopyData
+(
+ const void *data, // data to copy/move/link
+ uint size, // size of 'data'
+ CopyMode_t mode, // copy mode
+ bool *res_alloced // not NULL:
+ // store true, if data must be freed
+ // otherwise store false
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+void FreeData
+(
+ const void *data, // data to free
+ CopyMode_t mode // copy mode
+);
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// split strings ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+uint SplitByCharMem
+(
+ // 'mem_list' will be padded with {EmptyString,0}
+
+ mem_t *mem_list, // array of mem_t
+ uint n_mem, // number of elements of 'mem_list'
+ mem_t source, // source string
+ char sep // separator character
+);
+
+//-----------------------------------------------------------------------------
+
+uint SplitByTextMem
+(
+ // 'mem_list' will be padded with {EmptyString,0}
+
+ mem_t *mem_list, // array of mem_t
+ uint n_mem, // number of elements of 'mem_list'
+ mem_t source, // source string
+ mem_t sep // separator text
+);
+
+//-----------------------------------------------------------------------------
+
+uint SplitByCharMemList
+(
+ mem_list_t *ml, // valid destination mem_list
+ bool init_ml, // true: initialize 'ml' first
+ mem_t source, // source string
+ char sep, // separator character
+ int max_fields // >0: max number of result fields
+);
+
+//-----------------------------------------------------------------------------
+
+uint SplitByTextMemList
+(
+ mem_list_t *ml, // valid destination mem_list
+ bool init_ml, // true: initialize 'ml' first
+ mem_t source, // source string
+ mem_t sep, // separator text
+ int max_fields // >0: max number of result fields
+);
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// alloc info ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+extern bool alloc_info_calced;
+extern uint alloc_info_overhead;
+extern uint alloc_info_block_size;
+extern uint alloc_info_add1;
+extern uint alloc_info_add2;
+extern uint alloc_info_mask;
+
+///////////////////////////////////////////////////////////////////////////////
+
+uint SetupAllocInfo(void);
+
+static inline uint GetGoodAllocSize ( uint need )
+{
+ return ( need + alloc_info_add1 & alloc_info_mask )
+ + alloc_info_add2;
+}
+
+static inline uint GetGoodAllocSize2 ( uint n_elem, uint itemsize )
+{
+ return (( n_elem*itemsize + alloc_info_add1 & alloc_info_mask )
+ + alloc_info_add2 ) / itemsize;
+}
+
+static inline uint GetGoodAllocSizeA ( uint need, uint align )
+{
+ need = ( need + align - 1) / align * align;
+ return (( need + alloc_info_add1 & alloc_info_mask )
+ + alloc_info_add2 ) / align * align;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// some basic string functions ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+extern const char EmptyQuote[]; // »""« Ignored by FreeString()
+extern const char EmptyString[4]; // »« + 4*NULL, Ignored by FreeString()
+extern const char MinusString[4]; // »-« + 3*NULL, Ignored by FreeString()
+
+extern const char LoDigits[0x41]; // 0-9 a-z A-Z .+ NULL
+extern const char HiDigits[0x41]; // 0-9 A-Z a-z .+ NULL
+
+extern const char Tabs20[21]; // 20 * TAB + NULL
+extern const char LF20[21]; // 20 * LF + NULL
+extern const char Space200[201]; // 200 * ' ' + NULL
+extern const char Minus300[301]; // 300 * '-' + NULL
+extern const char Underline200[201]; // 200 * '_' + NULL
+extern const char Hash200[201]; // 200 * '#' + NULL
+extern const char Slash200[201]; // 200 * '/' + NULL
+
+// UTF-8 => 3 bytes per char
+extern const char ThinLine300_3[901]; // 300 * '─' (U+2500) + NULL
+
+//-----------------------------------------------------------------------------
+
+void SetupMultiProcessing(void);
+void PrintSettingsDCLIB ( FILE *f, int indent );
+void SetupProgname ( int argc, char ** argv,
+ ccp tool_name, ccp tool_vers, ccp tool_title );
+
+// return NULL or 'progpath', calc GetProgramPath() once if needed
+ccp ProgramPath(void);
+
+// return NULL or 'progdir', calc ProgramPath() once if needed
+ccp ProgramDirectory(void);
+
+#ifdef __CYGWIN__
+ ccp ProgramPathNoExt(void);
+#else
+ static inline ccp ProgramPathNoExt(void) { return ProgramPath(); }
+#endif
+
+int GetProgramPath
+(
+ // returns strlen(buf) on success, -1 on failure
+
+ char *buf, // buffer for the result; empty string on failure.
+ uint buf_size, // size of buffer
+ bool check_proc, // true: read files of /proc/... to find path
+ ccp argv0 // not NULL: analyse this argument (argv[0])
+);
+
+//-----
+
+// StringCopy(), StringCopyE(), StringCat*()
+// RESULT: end of copied string pointing to a NULL character.
+// 'src*' may be a NULL pointer.
+
+char * StringCopyS ( char * buf, size_t bufsize, ccp src );
+char * StringCopySM ( char * buf, size_t bufsize, ccp src, size_t max_copy );
+char * StringCat2S ( char * buf, size_t bufsize, ccp src1, ccp src2 );
+char * StringCat3S ( char * buf, size_t bufsize, ccp src1, ccp src2, ccp src3 );
+
+char * StringCopyE ( char * buf, ccp buf_end, ccp src );
+char * StringCopyEM ( char * buf, ccp buf_end, ccp src, size_t max_copy );
+char * StringCat2E ( char * buf, ccp buf_end, ccp src1, ccp src2 );
+char * StringCat3E ( char * buf, ccp buf_end, ccp src1, ccp src2, ccp src3 );
+
+// alloc space and return
+char * StringCat2A ( ccp src1, ccp src2 );
+char * StringCat3A ( ccp src1, ccp src2, ccp src3 );
+
+static inline char * StringCopySMem ( char * buf, size_t bufsize, mem_t mem )
+ { return StringCopySM(buf,bufsize,mem.ptr,mem.len); }
+static inline char * StringCopyEMem ( char * buf, ccp buf_end, mem_t mem )
+ { return StringCopyEM(buf,buf_end,mem.ptr,mem.len); }
+
+char * StringLowerS ( char * buf, size_t bufsize, ccp src );
+char * StringLowerE ( char * buf, ccp buf_end, ccp src );
+char * StringUpperS ( char * buf, size_t bufsize, ccp src );
+char * StringUpperE ( char * buf, ccp buf_end, ccp src );
+
+// special handling for unsigned decimals
+int StrNumCmp ( ccp a, ccp b );
+
+// count the number of equal bytes and return a value of 0 to SIZE
+uint CountEqual ( cvp m1, cvp m2, uint size );
+
+// Concatenate path + path, return pointer to buf
+// Return pointer to buf or path1|path2|buf or alloced string
+char *PathCatBufPP ( char *buf, size_t bufsize, ccp path1, ccp path2 );
+char *PathCatBufPPE ( char *buf, size_t bufsize, ccp path1, ccp path2, ccp ext );
+ccp PathCatPP ( char *buf, size_t bufsize, ccp path1, ccp path2 );
+//ccp PathCatPPE ( char *buf, size_t bufsize, ccp path1, ccp path2, ccp ext );
+ccp PathAllocPP ( ccp path1, ccp path2 );
+ccp PathAllocPPE ( ccp path1, ccp path2, ccp ext );
+
+// inline wrapper
+static inline ccp PathCatPPE ( char *buf, size_t bufsize, ccp path1, ccp path2, ccp ext )
+ { return PathCatBufPPE(buf,bufsize,path1,path2,ext); }
+
+// Same as PathCatPP*(), but use 'base' as prefix for relative pathes.
+// If 'base' is NULL (but not empty), use getcwd() instead.
+// PathCatBufBP() and PathCatBP() are special: path can be part of buf
+char *PathCatBufBP ( char *buf, size_t bufsize, ccp base, ccp path );
+char *PathCatBufBPP ( char *buf, size_t bufsize, ccp base, ccp path1, ccp path2 );
+char *PathCatBufBPPE ( char *buf, size_t bufsize, ccp base, ccp path1, ccp path2, ccp ext );
+ccp PathCatBP ( char *buf, size_t bufsize, ccp base, ccp path );
+ccp PathCatBPP ( char *buf, size_t bufsize, ccp base, ccp path1, ccp path2 );
+ccp PathCatBPPE ( char *buf, size_t bufsize, ccp base, ccp path1, ccp path2, ccp ext );
+ccp PathAllocBP ( ccp base, ccp path );
+ccp PathAllocBPP ( ccp base, ccp path1, ccp path2 );
+ccp PathAllocBPPE ( ccp base, ccp path1, ccp path2, ccp ext );
+
+char * PathCombine ( char *temp_buf, uint buf_size, ccp path, ccp base_path );
+char * PathCombineFast ( char *dest_buf, uint buf_size, ccp path, ccp base_path );
+
+// Remove last extension and add a new one.
+// If ext==NULL or emtpy: remove only
+// 'ext' may start with '.'. If not, a additional '.' is included
+// If 'path' is NULL or path==buf: Inplace job using 'buf' as source.
+char * NewFileExtE ( char * buf, ccp buf_end, ccp path, ccp ext );
+char * NewFileExtS ( char * buf, size_t bufsize, ccp path, ccp ext );
+
+// eliminate leading './' before comparing
+int StrPathCmp ( ccp path1, ccp path2 );
+
+int PathCmp
+(
+ ccp path1, // NULL or first path
+ ccp path2, // NULL or second path
+ uint mode // bit field:
+ // 1: skip (multiple) leading './'
+ // 2: compare case insensitive
+ // 4: sort with respect for unsigned decimal numbers
+);
+
+int ReplaceToBuf
+(
+ // returns -1 on error (buf to small) or the length of the resulting string.
+ // In the later case, a 0 byte is appended, but not counting for the length.
+
+ char *buf, // pointer to buf
+ uint buf_size, // size of 'buf'
+
+ ccp src1, // NULL or source, maybe part of 'buf'
+ int src1_len, // length of 'src1', if -1: determine by strlen()
+ int pos, // robust replace position, <0: relative to end
+ int rm_len, // robust num of chars to remove, <0: rm before 'pos'
+
+ ccp src2, // NULL or source to insert, must not be part of 'buf'
+ int src2_len // lengh of 'src2', if -1: determine by strlen()
+);
+
+int NormalizeIndent ( int indent );
+
+//-----------------------------------------------------
+
+// skips all character 1..SPACE; 'src' can be NULL
+char * SkipControls ( ccp src );
+
+// skips all character 0..SPACE; if end==NULL: Use SkipControls(); 'src' can be NULL
+char * SkipControlsE ( ccp src, ccp end );
+
+// same as above, but skip also 'ch1'; 'src' can be NULL
+char * SkipControls1 ( ccp src, char ch1 );
+char * SkipControlsE1 ( ccp src, ccp end, char ch1 );
+
+// same as above, but skip also 'ch1' and 'ch2'; 'src' can be NULL
+char * SkipControls2 ( ccp src, char ch1, char ch2 );
+char * SkipControlsE2 ( ccp src, ccp end, char ch1, char ch2 );
+
+//-----------------------------------------------------
+
+// return the number of chars until first EOL ( \0 | \r | \n );
+// pointer are NULL save
+uint LineLen ( ccp ptr );
+uint LineLenE ( ccp ptr, ccp end );
+
+//-----------------------------------------------------
+
+uint TrimBlanks
+(
+ char *str, // pointer to string, modified
+ ccp end // NULL or end of string
+);
+
+char * ScanName
+(
+ // return a pointer to the first unused character
+ char *buf, // destination buffer, terminated with NULL
+ uint buf_size, // size of 'buf', must be >0
+ ccp str, // source string
+ ccp end, // NULL or end of 'str'
+ bool allow_signs // true: allow '-' and '+'
+);
+
+//-----------------------------------------------------
+// Format of version number: AABBCCDD = A.BB | A.BB.CC
+// If D != 0x00 && D != 0xff => append: 'beta' D
+//-----------------------------------------------------
+
+char * PrintVersion
+(
+ char * buf, // result buffer
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u32 version // version number to print
+);
+
+char * PrintID
+(
+ const void * id, // ID to convert in printable format
+ size_t id_len, // len of 'id'
+ void * buf // Pointer to buffer, size >= id_len + 1
+ // If NULL, a local circulary static buffer is used
+);
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// circ buf ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+#define CIRC_BUF_MAX_ALLOC 0x0400 // request limit
+#define CIRC_BUF_SIZE 0x4000 // internal buffer size
+
+char * GetCircBuf
+(
+ // never returns NULL, but always ALIGN(4)
+
+ u32 buf_size // wanted buffer size, caller must add 1 for NULL-term
+ // if buf_size > CIRC_BUF_MAX_ALLOC:
+ // ==> ERROR0(ERR_OUT_OF_MEMORY)
+);
+
+char * CopyCircBuf
+(
+ // never returns NULL, but always ALIGN(4)
+
+ cvp data, // source to copy
+ u32 data_size // see GetCircBuf()
+);
+
+char * CopyCircBuf0
+(
+ // never returns NULL, but always ALIGN(4)
+ // an additional char is alloced and set to NULL
+
+ cvp data, // source to copy
+ u32 data_size // see GetCircBuf()
+);
+
+char * PrintCircBuf
+(
+ ccp format, // format string for vsnprintf()
+ ... // arguments for 'format'
+)
+__attribute__ ((__format__(__printf__,1,2)));
+
+void ReleaseCircBuf
+(
+ ccp end_buf, // pointer to end of previous alloced buffer
+ uint release_size // number of bytes to give back from end
+);
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// struct IntMode_t ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[IntMode_t]]
+
+typedef enum IntMode_t
+{
+ IMD_UNSET = 0, // default, always 0
+
+ //--- big endian modes
+
+ IMD_BE0, // default big endian
+ IMD_BE1,
+ IMD_BE2,
+ IMD_BE3,
+ IMD_BE4,
+ IMD_BE5,
+ IMD_BE6,
+ IMD_BE7,
+ IMD_BE8,
+
+ //--- little endian modes
+
+ IMD_LE0, // default little endian
+ IMD_LE1,
+ IMD_LE2,
+ IMD_LE3,
+ IMD_LE4,
+ IMD_LE5,
+ IMD_LE6,
+ IMD_LE7,
+ IMD_LE8,
+
+ //--- local endian modes
+
+ #ifdef LITTLE_ENDIAN
+
+ IMD_0 = IMD_LE0,
+ IMD_1 = IMD_LE1,
+ IMD_2 = IMD_LE2,
+ IMD_3 = IMD_LE3,
+ IMD_4 = IMD_LE4,
+ IMD_5 = IMD_LE5,
+ IMD_6 = IMD_LE6,
+ IMD_7 = IMD_LE7,
+ IMD_8 = IMD_LE8,
+
+ #else
+
+ IMD_0 = IMD_BE0,
+ IMD_1 = IMD_BE1,
+ IMD_2 = IMD_BE2,
+ IMD_3 = IMD_BE3,
+ IMD_4 = IMD_BE4,
+ IMD_5 = IMD_BE5,
+ IMD_6 = IMD_BE6,
+ IMD_7 = IMD_BE7,
+ IMD_8 = IMD_BE8,
+
+ #endif
+}
+__attribute__ ((packed)) IntMode_t;
+
+//-----------------------------------------------------------------------------
+
+ccp GetIntModeName ( IntMode_t mode );
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// struct FastBuf_t ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[FastBuf_t]]
+
+typedef struct FastBuf_t
+{
+ char *buf; // pointer to buffer
+ char *ptr; // pointer to first unused char (always space for 0-term)
+ char *end; // pointer to end of buffer := buf+size-1
+
+ uint fast_buf_size; // size of 'fast_buf+space'
+ char fast_buf[4]; // first use buffer with minimal space
+ char space[]; // additional space
+}
+FastBuf_t;
+
+///////////////////////////////////////////////////////////////////////////////
+
+//------------------------------------------------------------------
+//
+// 4 examples for initialization:
+//
+// FastBuf_t fb1;
+// InitializeFastBufAlloc(&fb1,1000);
+// printf("fb1: %s: %s\n", GetFastBufStatus(&fb1), fb1.buf );
+//
+// FastBuf_t fb2;
+// InitializeFastBuf(&fb2,sizeof(fb2));
+// printf("fb2: %s: %s\n", GetFastBufStatus(&fb2), fb2.buf );
+//
+// struct { FastBuf_t b; char space[2000]; } fb3;
+// InitializeFastBuf(&fb3,sizeof(fb3));
+// printf("fb3: %s: %s\n", GetFastBufStatus(&fb.b), fb3.b.buf );
+//
+// char fb4x[2000];
+// FastBuf_t *fb4 = InitializeFastBuf(fb4x,sizeof(fb4x));
+// printf("fb4: %s: %s\n", GetFastBufStatus(fb4), fb4->buf );
+//
+//------------------------------------------------------------------
+
+FastBuf_t * InitializeFastBuf ( cvp mem, uint size );
+FastBuf_t * InitializeFastBufAlloc ( FastBuf_t *fb, uint size );
+
+void ResetFastBuf ( FastBuf_t *fb );
+static inline void ClearFastBuf ( FastBuf_t *fb )
+ { DASSERT(fb); fb->ptr = fb->buf; }
+
+ccp GetFastBufStatus ( const FastBuf_t *fb );
+int ReserveSpaceFastBuf ( FastBuf_t *fb, uint size );
+char * GetSpaceFastBuf ( FastBuf_t *fb, uint size );
+
+uint InsertFastBuf ( FastBuf_t *fb, int index, cvp source, int size );
+char * AppendFastBuf ( FastBuf_t *fb, cvp source, int size );
+char * WriteFastBuf ( FastBuf_t *fb, uint offset, cvp source, int size );
+uint AssignFastBuf ( FastBuf_t *fb, cvp source, int size );
+uint DropFastBuf ( FastBuf_t *fb, int index, int size );
+
+void CopyFastBuf ( FastBuf_t *dest, const FastBuf_t *src );
+void MoveFastBuf ( FastBuf_t *dest, FastBuf_t *src );
+
+static inline void AppendMemFastBuf ( FastBuf_t *fb, const mem_t mem )
+ { AppendFastBuf(fb,mem.ptr,mem.len); }
+
+static inline void AppendCharFastBuf ( FastBuf_t *fb, char ch )
+{
+ DASSERT(fb);
+ GetSpaceFastBuf(fb,1)[0] = ch;
+}
+
+void AppendUTF8CharFastBuf ( FastBuf_t *fb, u32 code );
+void AppendBE16FastBuf ( FastBuf_t *fb, u16 num );
+void AppendBE32FastBuf ( FastBuf_t *fb, u32 num );
+void AppendInt64FastBuf ( FastBuf_t *fb, u64 val, IntMode_t mode );
+
+static inline void AppendU16FastBuf ( FastBuf_t *fb, u16 num )
+ { AppendFastBuf(fb,&num,sizeof(num)); }
+static inline void AppendU32FastBuf ( FastBuf_t *fb, u32 num )
+ { AppendFastBuf(fb,&num,sizeof(num)); }
+static inline void AppendU64FastBuf ( FastBuf_t *fb, u64 num )
+ { AppendFastBuf(fb,&num,sizeof(num)); }
+
+static inline int GetFastBufLen ( const FastBuf_t *fb )
+ { DASSERT(fb); return fb->ptr - fb->buf; }
+
+//-----------------------------------------------------------------------------
+// The resulting strings of GetFastBufString() and GetFastBufMem0() are always
+// terminated by an additional NULL byte.
+// The resulting strings of GetFastBufMem() is not terminated by a NULL byte.
+//-----------------------------------------------------------------------------
+
+static inline char * GetFastBufString ( const FastBuf_t *fb )
+{
+ DASSERT(fb);
+ *fb->ptr = 0;
+ return fb->buf;
+}
+
+static inline mem_t GetFastBufMem0 ( const FastBuf_t *fb )
+{
+ DASSERT(fb);
+ *fb->ptr = 0;
+ mem_t mem = { fb->buf, fb->ptr - fb->buf };
+ return mem;
+}
+
+static inline mem_t GetFastBufMem ( const FastBuf_t *fb )
+{
+ DASSERT(fb);
+ mem_t mem = { fb->buf, fb->ptr - fb->buf };
+ return mem;
+}
+
+//-----------------------------------------------------------------------------
+// The allocated result is always terminated by an additional NULL byte.
+// FastBuf_t itself is reset, similar to ResetFastBuf()
+
+char * MoveFromFastBufString ( FastBuf_t *fb );
+mem_t MoveFromFastBufMem ( FastBuf_t *fb );
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// MatchPattern() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+#define PATTERN_WILDCARDS "*# ?[{"
+
+bool MatchPatternFull
+(
+ ccp pattern, // pattern text
+ ccp text // raw text
+);
+
+bool MatchPattern
+(
+ ccp pattern, // pattern text
+ ccp text, // raw text
+ char path_sep // path separator character, standard is '/'
+);
+
+char * MatchRuleLine
+(
+ // returns a pointer to the first non scanned char
+
+ int *status, // not NULL: return match status here
+ // -2: no prefix found (no ruile found)
+ // -1: empty line (no ruile found)
+ // 0: rule found, but don't match
+ // 1: rule found and match
+ ccp src, // source line, scanned untilCONTROL
+ char rule_prefix, // NULL or a rule-beginning-char'
+ ccp path, // path to verify
+ char path_sep // path separator character, standard is '/'
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+static inline int GetHexDigit ( char ch )
+{
+ return ch >= '0' && ch <= '9' ? ch-'0'
+ : ch >= 'a' && ch <= 'f' ? ch-'a'+10
+ : ch >= 'A' && ch <= 'F' ? ch-'A'+10
+ : -1;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// SplitArg_t ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[SplitArg_t]]
+
+typedef struct SplitArg_t
+{
+ uint argc; // number of arguments in 'argv'
+ char **argv; // array with 'argc' arguments + a NULL term, alloced
+ uint argv_size; // number of alloced pointers for 'argv' without NULL term
+
+ char *temp; // NULL or temporary buffer
+ uint temp_size; // size of 'temp'
+}
+SplitArg_t;
+
+static inline void InitializeSplitArg ( SplitArg_t *sa )
+ { DASSERT(sa); memset(sa,0,sizeof(*sa)); }
+
+void ResetSplitArg ( SplitArg_t *sa );
+
+int ScanSplitArg
+(
+ // returns arg->argc;
+
+ SplitArg_t *arg, // pointer to object
+ bool init_arg, // true: call InitializeSplitArg()
+ ccp src, // NULL or source string
+ ccp src_end, // end of 'src'; if NULL: calculated by strlen(src)
+ char *work_buf // pointer to a buffer for strings, may be 'src'
+ // size must be: length of 'src' + 1
+ // if NULL, a temporary buffer is alloced.
+);
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// ContainerData_t, Container_t ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+//-----------------------------------------------------------------------------
+// OVERVIEW
+//-----------------------------------------------------------------------------
+// Container_t * CreateContainer ( Container_t, protect, data,size, CopyMode_t )
+// Container_t * InheritContainer ( Container_t cur, protect, Container_t parent, data,size )
+// bool AssignContainer ( Container_t, protect, data,size, CopyMode_t )
+// void ResetContainer ( Container_t )
+// void DeleteContainer ( Container_t )
+// void UnlinkContainerData ( Container_t )
+// ContainerData_t * LinkContainerData ( Container_t )
+// ContainerData_t * MoveContainerData ( Container_t )
+// Container_t * CatchContainerData ( Container_t, int protect, ContainerData_t )
+// Container_t * UseContainerData ( Container_t, int protect, Container_t )
+//------------
+// ContainerData_t DisjoinContainerData ( Container_t )
+// void JoinContainerData ( Container_t, ContainerData_t )
+// void FreeContainerData ( ContainerData_t )
+//------------
+// static inline bool ModificationAllowed ( const Container_t )
+// void ModifyAllContainer ( Container_t )
+// void ModifyContainer ( Container_t, data, size, CopyMode_t )
+// int SetProtectContainer ( Container_t, int new_protect )
+// static inline int AddProtectContainer ( Container_t, int add_protect )
+// static inline bool IsValidContainer ( const Container_t * c )
+// static inline bool InContainerP ( const Container_t, cvp ptr )
+// static inline bool InContainerS ( const Container_t, cvp ptr, uint size )
+// static inline bool InContainerE ( const Container_t, cvp ptr, cvp end )
+// uint DumpInfoContainer ( f,colset,indent,prefix, Container_t, hexdump_len )
+// uint DumpInfoContainerData ( f,col,indent,prefix, CData_t, hex_len, hex_indent )
+//-----------------------------------------------------------------------------
+
+///////////////////////////////////////////////////////////////////////////////
+// [[ContainerData_t]]
+
+typedef struct ContainerData_t
+{
+ u8 *data; // data
+ uint size; // size of 'data'
+ int ref_count; // reference counter
+ int protect_count; // >0: don't modify data
+ bool data_alloced; // true: free data
+
+} ContainerData_t;
+
+//-----------------------------------------------------------------------------
+// [[Container_t]]
+
+typedef struct Container_t
+{
+ ContainerData_t *cdata; // NULL or pointer to ContainerData
+ int protect_level; // >0: don't modify data
+
+} Container_t;
+
+///////////////////////////////////////////////////////////////////////////////
+
+Container_t * CreateContainer
+(
+ // returns 'c' or the alloced container
+ // 'c' is always initialized
+
+ Container_t *c, // valid container, alloc one if NULL
+ int protect, // initial value for protection
+ const void *data, // data to copy/move/link
+ uint size, // size of 'data'
+ CopyMode_t mode // copy mode on creation
+);
+
+//-----------------------------------------------------------------------------
+
+Container_t * InheritContainer
+(
+ // returns 'c' or the alloced container
+
+ Container_t *c, // valid container, alloc one if NULL
+ int protect, // initial value for protection
+ const Container_t *parent, // NULL or valid parent container
+ const void *data, // data to copy/move/link
+ uint size // size of 'data'
+);
+
+//-----------------------------------------------------------------------------
+
+bool AssignContainer
+(
+ // return TRUE on new ContainerData_t
+
+ Container_t *c, // valid container; if NULL: only FREE(data)
+ int protect, // new protection level
+ const void *data, // data to copy/move/link
+ uint size, // size of 'data'
+ CopyMode_t mode // copy mode on creation
+);
+
+//-----------------------------------------------------------------------------
+
+void ResetContainer
+(
+ Container_t *c // container to reset => no data
+);
+
+//-----------------------------------------------------------------------------
+
+void DeleteContainer
+(
+ Container_t *c // container to reset and to free => no data
+);
+
+//-----------------------------------------------------------------------------
+
+void UnlinkContainerData
+(
+ Container_t *c // container to reset => no data
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+ContainerData_t * LinkContainerData
+(
+ // increment 'ref_count' and return NULL or current ContainerData
+ // => use CatchContainerData() to complete operation
+
+ const Container_t *c // NULL or valid container
+);
+
+//-----------------------------------------------------------------------------
+
+ContainerData_t * MoveContainerData
+(
+ // return NULL or unlinked current ContainerData
+ // => use CatchContainerData() to complete operation
+ Container_t *c // NULL or valid container
+);
+
+//-----------------------------------------------------------------------------
+
+Container_t * CatchContainerData
+(
+ // returns 'c' or the alloced container
+ // 'c' is always initialized
+
+ Container_t *c, // valid container, alloc one if NULL
+ int protect, // initial value for protection
+ ContainerData_t *cdata // if not NULL: catch this
+);
+
+//-----------------------------------------------------------------------------
+
+static inline Container_t * UseContainerData
+(
+ // returns 'c' or the alloced container
+
+ Container_t *c, // valid container, alloc one if NULL
+ int protect, // initial value for protection
+ const Container_t *src // if not NULL: catch this
+)
+{
+ return CatchContainerData(c,protect,LinkContainerData(src));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+ContainerData_t * DisjoinContainerData
+(
+ // Disjoin data container date without freeing it. Call either
+ // JoinContainerData() or FreeContainerData() to finish operation.
+ // Reference counters are not modified.
+ // Return the data container or NULL
+
+ Container_t *c // NULL or valid container
+);
+
+//-----------------------------------------------------------------------------
+
+void JoinContainerData
+(
+ // Join a data container, that was diojoined by DisjoinContainerData()
+ // Reference counters are not modified.
+
+ Container_t *c, // if NULL: FreeContainerData()
+ ContainerData_t *cdata // NULL or container-data to join
+);
+
+//-----------------------------------------------------------------------------
+
+void FreeContainerData
+(
+ // Decrement the reference counter of an already disjoined data container
+ // and free it if unused.
+
+ ContainerData_t *cdata // NULL or container-data to free
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+static inline bool ModificationAllowed ( const Container_t *c )
+ { return c && c->cdata
+ && ( c->cdata->ref_count <= 1
+ || c->cdata->protect_count <= ( c->protect_level > 0 ) );
+ }
+
+//-----------------------------------------------------------------------------
+
+bool ModifyAllContainer
+(
+ // prepare modification of container-data, create a copy if necessary
+ // return true, if a new container-data is used
+
+ Container_t *c // NULL or valid container
+);
+
+//-----------------------------------------------------------------------------
+
+bool ModifyContainer
+(
+ // prepare modification of container-data, create an extract if necessary
+ // return true, if a new container-data is used
+
+ Container_t *c, // NULL or valid container
+ const void *data, // data to copy/move/link
+ uint size, // size of 'data'
+ CopyMode_t mode // copy mode on creation
+);
+
+//-----------------------------------------------------------------------------
+
+int SetProtectContainer
+(
+ // returns 'c' new protection level
+ Container_t *c, // valid container, alloc one if NULL
+ int new_protect // new protection value
+);
+
+//-----------------------------------------------------------------------------
+
+static inline int AddProtectContainer
+(
+ // returns 'c' new protection level
+ Container_t *c, // valid container, alloc one if NULL
+ int add_protect // new protection value
+)
+{
+ DASSERT(c);
+ return SetProtectContainer(c,c->protect_level+add_protect);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static inline bool IsValidContainer ( const Container_t * c )
+ { return c && c->cdata && c->cdata->data; }
+
+//-----------------------------------------------------------------------------
+
+static inline bool InContainerP ( const Container_t * c, cvp ptr )
+ { return c && c->cdata && ptr
+ && (u8*)ptr >= c->cdata->data
+ && (u8*)ptr <= c->cdata->data + c->cdata->size; }
+
+//-----------------------------------------------------------------------------
+
+static inline bool InContainerS ( const Container_t * c, cvp ptr, uint size )
+ { return c && c->cdata && ptr
+ && (u8*)ptr >= c->cdata->data
+ && (u8*)ptr + size <= c->cdata->data + c->cdata->size; }
+
+//-----------------------------------------------------------------------------
+
+static inline bool InContainerE ( const Container_t * c, cvp ptr, cvp end )
+ { return c && c->cdata
+ && ptr && (u8*)ptr >= c->cdata->data
+ && end && (u8*)end <= c->cdata->data + c->cdata->size; }
+
+///////////////////////////////////////////////////////////////////////////////
+
+struct ColorSet_t;
+uint DumpInfoContainer
+(
+ // return the number of printed lines
+
+ FILE *f, // valid output file
+ const ColorSet_t *colset, // NULL or color set
+ int indent, // indent the output
+ ccp prefix, // not NULL: use it as prefix behind indention
+ const Container_t *c, // dump infos for this container, NULL allowed
+ uint hexdump_len // max number of bytes used for a hexdump
+);
+
+//-----------------------------------------------------------------------------
+
+uint DumpInfoContainerData
+(
+ // return the number of printed lines
+
+ FILE *f, // valid output file
+ const ColorSet_t *colset, // NULL or color set
+ int indent, // indent of output
+ ccp prefix, // not NULL: use it as prefix behind indention
+ const
+ ContainerData_t *cdata, // dump infos for this container-data, NULL allowed
+ uint hexdump_len, // max number of bytes used for a hexdump
+ int hexdump_indent // indent of hexdump
+);
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// print lines with autobreak ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+void PutLines
+(
+ FILE * f, // valid output stream
+ int indent, // indent of output
+ int fw, // field width of output
+ int first_line, // length without prefix of already printed first line
+ ccp prefix, // NULL or prefix for each line
+ ccp text, // text to print
+ ccp eol // End Of Line test. If NULL -> LF
+);
+
+void PrintArgLines
+(
+ FILE * f, // valid output stream
+ int indent, // indent of output
+ int fw, // field width of output
+ int first_line, // length without prefix of already printed first line
+ ccp prefix, // NULL or prefix for each line
+ ccp format, // format string for vsnprintf()
+ va_list arg // parameters for 'format'
+);
+
+void PrintLines
+(
+ FILE * f, // valid output stream
+ int indent, // indent of output
+ int fw, // field width of output
+ int first_line, // length without prefix of already printed first line
+ ccp prefix, // NULL or prefix for each line
+ ccp format, // format string for vsnprintf()
+ ... // arguments for 'vsnprintf(format,...)'
+)
+__attribute__ ((__format__(__printf__,6,7)));
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+//
+// Rules for P*ColoredLines():
+//
+// |+ : Define a TAB pos (not is defined at start)
+// |- : Remove a TAB pos
+// |[pos,...] : Comma separated list: Clear all tabs and define new TABs
+// POS : Define TAB add POS
+// POS*DELTA : Define TAB add POS and then at every DELTA
+// \t : Jump to TAB stop
+//
+// | or |> : Define an indention for continuation lines.
+// Use the single char only, if a letter, digit, underline, SPACE,
+// CTRL or '{' follows. All ather chars are reserved for extensions.
+// \r : Force a new continuation line.
+// \n : Terminate current line.
+// \r\n : Same as '\n'.
+//
+// {name} : Change active color to NAME
+// {name|text} : Use color NAME only for TEXT, then restore active color.
+// {} : Reset and deactivate all colors.
+//
+// || : Print Single '|'
+// {{ : Print Single '{'
+//
+///////////////////////////////////////////////////////////////////////////////
+
+uint PutColoredLines
+(
+ // returns the number of written lines
+
+ FILE * f, // valid output stream
+ const ColorSet_t *colset, // NULL or color set
+ int indent, // indent of output
+ int fw, // field width; indent+prefix+eol don't count
+ ccp prefix, // NULL or prefix for each line
+ ccp eol, // End Of Line test. If NULL -> LF
+ ccp text // text to print
+);
+
+uint PrintArgColoredLines
+(
+ // returns the number of written lines
+
+ FILE * f, // valid output stream
+ const ColorSet_t *colset, // NULL or color set
+ int indent, // indent of output
+ int fw, // field width; indent+prefix+eol don't count
+ ccp prefix, // NULL or prefix for each line
+ ccp eol, // End Of Line test. If NULL -> LF
+ ccp format, // format string for vsnprintf()
+ va_list arg // parameters for 'format'
+);
+
+uint PrintColoredLines
+(
+ // returns the number of written lines
+
+ FILE * f, // valid output stream
+ const ColorSet_t *colset, // NULL or color set
+ int indent, // indent of output
+ int fw, // field width; indent+prefix+eol don't count
+ ccp prefix, // NULL or prefix for each line
+ ccp eol, // End Of Line test. If NULL -> LF
+ ccp format, // format string for vsnprintf()
+ ... // arguments for 'vsnprintf(format,...)'
+)
+__attribute__ ((__format__(__printf__,7,8)));
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// encoding/decoding ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+extern const u32 TableCRC32[0x100];
+u32 CalcCRC32 ( u32 crc, cvp buf, uint size );
+
+///////////////////////////////////////////////////////////////////////////////
+
+extern const u16 TableCP1252_80[0x20];
+
+///////////////////////////////////////////////////////////////////////////////
+// [[CharMode_t]]
+
+typedef enum CharMode_t // select encodig/decoding method
+{
+ CHMD_UTF8 = 0x01, // UTF8 support enabled (compatible with legacy bool)
+ CHMD_ESC = 0x02, // escape ESC by \e
+
+ CHMD__ALL = CHMD_UTF8 | CHMD_ESC,
+}
+__attribute__ ((packed)) CharMode_t;
+
+///////////////////////////////////////////////////////////////////////////////
+// [[EncodeMode_t]]
+
+typedef enum EncodeMode_t // select encodig/decoding method
+{
+ ENCODE_OFF, // no encoding (always 0)
+ ENCODE_STRING, // ScanEscapedString(ANSI), byte mode
+ ENCODE_UTF8, // ScanEscapedString(UTF8), force UTF8 on decoding
+ ENCODE_BASE64, // Base64
+ ENCODE_BASE64URL, // Base64.URL (=) / decoder detects Standard + URL + STAR
+ ENCODE_BASE64STAR, // Base64.URL (*) / decoder detects Standard + URL + STAR
+ ENCODE_BASE64XML, // Base64 with XML name tokens / decoder detects Standard + XML (name+id)
+ ENCODE_JSON, // JSON string encoding
+
+ ENCODE__N // number of encoding modes
+}
+EncodeMode_t;
+
+///////////////////////////////////////////////////////////////////////////////
+// [[DecodeType_t]]
+
+enum DecodeType_t // for decoding tables
+{
+ DECODE_NULL = -1,
+ DECODE_CONTROL = -2,
+ DECODE_LINE = -3,
+ DECODE_SPACE = -4,
+ DECODE_SEPARATE = -5,
+ DECODE_FILLER = -6,
+ DECODE_OTHER = -7
+};
+
+extern const char TableNumbers[256];
+
+extern char TableDecode64[256]; // Standard coding
+extern char TableDecode64url[256]; // Standard + URL + STAR coding
+extern char TableDecode64xml[256]; // Standard + XML (name tokens + identifiers)
+
+extern const char TableEncode64[64+1]; // last char is filler
+extern const char TableEncode64url[64+1]; // URL coding, used by Nintendo
+extern const char TableEncode64star[64+1]; // Like URL, with '*' instead of '=' as filler
+extern const char TableEncode64xml[64+1]; // XML name tokens
+
+// for tests: encode the 48 bytes to get the full BASE64 alphabet
+extern const u8 TableAlphabet64[48];
+
+// Default tables for DecodeBase64() and EncodeBase64(), if no table is defined.
+// They are initialized with TableDecode64[] and TableEncode64[].
+extern ccp TableDecode64default, TableEncode64default;
+
+///////////////////////////////////////////////////////////////////////////////
+
+char * PrintEscapedString
+(
+ // returns 'buf'
+
+ char *buf, // valid destination buffer
+ uint buf_size, // size of 'buf', >= 10
+ ccp source, // NULL string to print
+ int len, // length of string. if -1, str is null terminated
+ CharMode_t char_mode, // modes, bit field (CHMD_*)
+ char quote, // NULL or quotation char, that must be quoted
+ uint *dest_len // not NULL: Store length of result here
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+uint ScanEscapedString
+(
+ // returns the number of valid bytes in 'buf' (NULL term not counted)
+
+ char *buf, // valid destination buffer, maybe source
+ uint buf_size, // size of 'buf'
+ ccp source, // string to scan
+ int len, // length of string. if -1, str is null terminated
+ bool utf8, // true: source and output is UTF-8
+ int quote, // 0:none, -1:auto, >0: quotation char
+ uint *scanned_len // not NULL: Store number of scanned 'source' bytes here
+);
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+u64 DecodeU64
+(
+ ccp source, // string to decode
+ int len, // length of string. if -1, str is null terminated
+ uint base, // number of possible digits (2..36):
+ uint *scanned_len // not NULL: Store number of scanned 'str' bytes here
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+ccp EncodeU64
+(
+ char * buf, // result buffer (size depends on base)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u64 num, // number to encode
+ uint base // number of possible digits (2..64):
+);
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+uint DecodeBase64
+(
+ // returns the number of valid bytes in 'buf'
+
+ char *buf, // valid destination buffer
+ uint buf_size, // size of 'buf', >= 3
+ ccp source, // NULL or string to decode
+ int len, // length of string. if -1, str is null terminated
+ const char decode64[256], // decoding table; if NULL: use TableDecode64default
+ bool allow_white_spaces, // true: skip white spaces
+ uint *scanned_len // not NULL: Store number of scanned 'str' bytes here
+);
+
+//-----------------------------------------------------------------------------
+
+mem_t DecodeBase64Circ
+(
+ // Returns a buffer alloced by GetCircBuf()
+ // with valid pointer and null terminated.
+ // If result is too large (>CIRC_BUF_MAX_ALLOC) then (0,0) is returned.
+
+ ccp source, // NULL or string to decode
+ int len, // length of string. if -1, str is null terminated
+ const char decode64[256] // decoding table; if NULL: use TableDecode64default
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+uint EncodeBase64
+(
+ // returns the number of scanned bytes of 'source'
+
+ char *buf, // valid destination buffer
+ uint buf_size, // size of 'buf', >= 4
+ const void *source, // NULL or data to encode
+ int source_len, // length of 'source'; if <0: use strlen(source)
+ const char encode64[64+1], // encoding table; if NULL: use TableEncode64default
+ bool use_filler, // use filler for aligned output
+ ccp next_line, // not NULL: use this string as new line sep
+ uint next_line_trigger // >0: use 'next_line' every # input bytes
+);
+
+//-----------------------------------------------------------------------------
+
+mem_t EncodeBase64Circ
+(
+ // Returns a buffer alloced by GetCircBuf()
+ // with valid pointer and null terminated.
+ // If result is too large (>CIRC_BUF_MAX_ALLOC) then (0,0) is returned.
+
+ const void *source, // NULL or data to encode
+ int source_len, // length of 'source'; if <0: use strlen(source)
+ const char encode64[64+1] // encoding table; if NULL: use TableEncode64default
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+static inline uint EncodeBase64Len ( uint src_len )
+ { return 4 * (src_len+2) / 3; }
+
+static inline uint EncodeBase64FillLen ( uint src_len )
+ { return (src_len+2) / 3 * 4; }
+
+static inline uint DecodeBase64Len ( uint src_len )
+ { return 3 * src_len / 4; }
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static inline uint DecodeJSON
+(
+ // returns the number of valid bytes in 'buf'
+
+ char *buf, // valid destination buffer
+ uint buf_size, // size of 'buf', >= 3
+ ccp source, // NULL or string to decode
+ int source_len, // length of 'source'. If -1, str is NULL terminated
+ uint *scanned_len // not NULL: Store number of scanned 'str' bytes here
+)
+{
+ return ScanEscapedString(buf,buf_size,source,source_len,true,0,scanned_len);
+}
+
+//-----------------------------------------------------------------------------
+
+mem_t DecodeJSONCirc
+(
+ // Returns a buffer alloced by GetCircBuf()
+ // with valid pointer and null terminated.
+ // If result is too large (>CIRC_BUF_MAX_ALLOC) then (0,0) is returned.
+
+ ccp source, // NULL or string to decode
+ int source_len // length of 'source'. If -1, str is NULL terminated
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+uint EncodeJSON
+(
+ // returns the number of valid bytes in 'buf'. Result is NULL-terminated.
+
+ char *buf, // valid destination buffer
+ uint buf_size, // size of 'buf', >2 and 2 bytes longer than needed
+ const void *source, // NULL or data to encode
+ int source_len // length of 'source'; if <0: use strlen(source)
+);
+
+//-----------------------------------------------------------------------------
+
+mem_t EncodeJSONCirc
+(
+ // Returns a buffer alloced by GetCircBuf()
+ // with valid pointer and null terminated.
+ // If result is too large (>CIRC_BUF_MAX_ALLOC) then (0,0) is returned.
+
+ const void *source, // NULL or data to encode
+ int source_len // length of 'source'; if <0: use strlen(source)
+);
+
+//-----------------------------------------------------------------------------
+
+mem_t QuoteJSONCirc
+(
+ // Returns a buffer alloced by GetCircBuf()
+ // with valid pointer and null terminated.
+ // If result is too large (>CIRC_BUF_MAX_ALLOC) then (0,0) is returned.
+
+ const void *source, // NULL or data to encode
+ int source_len, // length of 'source'; if <0: use strlen(source)
+ int null_if // return 'null' without quotes ...
+ // <=0: never
+ // >=1: if source == NULL
+ // >=2: if source_len == 0
+);
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+uint DecodeByMode
+(
+ // returns the number of valid bytes in 'buf'. Result is NULL-terminated.
+
+ char *buf, // valid destination buffer
+ uint buf_size, // size of 'buf', >= 3
+ ccp source, // string to decode
+ int slen, // length of string. if -1, str is null terminated
+ EncodeMode_t emode // encoding mode
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+uint EncodeByMode
+(
+ // returns the number of valid bytes in 'buf'. Result is NULL-terminated.
+
+ char *buf, // valid destination buffer
+ uint buf_size, // size of 'buf', >= 4
+ ccp source, // string to encode
+ int slen, // length of string. if -1, str is null terminated
+ EncodeMode_t emode // encoding mode
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+mem_t DecodeByModeMem
+(
+ // Returns the decoded 'source'. Result is NULL-terminated.
+ // It points either to 'buf' or is alloced (on buf==NULL or to less space)
+ // If alloced (mem.ptr!=buf) => call FreeMem(&mem)
+
+ char *buf, // NULL or destination buffer
+ uint buf_size, // size of 'buf'
+ ccp source, // string to decode
+ int slen, // length of string. if -1, str is null terminated
+ EncodeMode_t emode // encoding mode
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+mem_t EncodeByModeMem
+(
+ // Returns the encoded 'source'. Result is NULL-terminated.
+ // It points either to 'buf' or is alloced (on buf==NULL or to less space)
+ // If alloced (mem.ptr!=buf) => call FreeMem(&mem)
+
+ char *buf, // NULL or destination buffer
+ uint buf_size, // size of 'buf'
+ ccp source, // string to encode
+ int slen, // length of string. if -1, str is null terminated
+ EncodeMode_t emode // encoding mode
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+#define SJIS_TAB_MAPPING_BEG 0xeea0 // first code used for table mapping
+#define SJIS_TAB_MAPPING_END 0xeecf // last code used for table mapping
+#define SJIS_INVALID_CODE 0xffff // invalid code
+#define SJIS_CACHE_SIZE 0xffff // number of elements in cache
+
+static inline bool IsValidShiftJIS ( uint code )
+ { return code < SJIS_TAB_MAPPING_BEG
+ || code > SJIS_TAB_MAPPING_END && code < SJIS_INVALID_CODE; }
+
+int ScanShiftJISChar ( cucp * str );
+int ScanShiftJISCharE ( cucp * str, cvp end );
+
+void SetupGetShiftJISCache(void);
+int GetShiftJISChar ( u32 code );
+
+ccp GetShiftJISStatistics(void);
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// scan keywords ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+#define KEYWORD_NAME_MAX 100
+
+typedef s64 (*KeywordCallbackFunc)
+(
+ void *param, // NULL or user defined parameter
+ ccp name, // normalized name of option
+ const KeywordTab_t *key_tab, // valid pointer to command table
+ const KeywordTab_t *key, // valid pointer to found command
+ char prefix, // 0 | '-' | '+' | '='
+ s64 result // current value of result
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+const KeywordTab_t *GetKewordById
+(
+ const KeywordTab_t *key_tab, // NULL or pointer to command table
+ s64 id // id to search
+);
+
+//-----------------------------------------------------------------------------
+
+const KeywordTab_t *GetKewordByIdAndOpt
+(
+ const KeywordTab_t *key_tab, // NULL or pointer to command table
+ s64 id, // id to search
+ s64 opt // opt to search
+);
+
+//-----------------------------------------------------------------------------
+
+static inline ccp GetKewordNameById
+(
+ const KeywordTab_t *key_tab, // NULL or pointer to command table
+ s64 id, // id to search
+ ccp res_not_found // return this if not found
+)
+{
+ const KeywordTab_t *key = GetKewordById(key_tab,id);
+ return key ? key->name1 : res_not_found;
+}
+
+//-----------------------------------------------------------------------------
+
+static inline ccp GetKewordNameByIdAndOpt
+(
+ const KeywordTab_t *key_tab, // NULL or pointer to command table
+ s64 id, // id to search
+ s64 opt, // opt to search
+ ccp res_not_found // return this if not found
+)
+{
+ const KeywordTab_t *key = GetKewordByIdAndOpt(key_tab,id,opt);
+ return key ? key->name1 : res_not_found;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+const KeywordTab_t * ScanKeyword
+(
+ int *res_abbrev, // NULL or pointer to result 'abbrev_count'
+ ccp arg, // argument to scan
+ const KeywordTab_t *key_tab // valid pointer to command table
+);
+
+//-----------------------------------------------------------------------------
+
+s64 ScanKeywordListEx
+(
+ ccp arg, // argument to scan
+ const KeywordTab_t * key_tab, // valid pointer to command table
+ KeywordCallbackFunc func, // NULL or calculation function
+ bool allow_prefix, // allow '-' | '+' | '=' as prefix
+ u32 max_number, // allow numbers < 'max_number' (0=disabled)
+ s64 result, // start value for result
+
+ uint err_mode, // bit field:
+ // 1: continue on error
+ ccp err_msg, // not NULL: print a warning message:
+ // "<ERR_MSG>: Unknown keyword: <KEY>"
+ enumError err_code, // use 'err_code' for the 'err_msg'
+ uint *err_count // not NULL: store errors here
+);
+
+static inline s64 ScanKeywordList
+(
+ ccp arg, // argument to scan
+ const KeywordTab_t * key_tab, // valid pointer to command table
+ KeywordCallbackFunc func, // NULL or calculation function
+ bool allow_prefix, // allow '-' | '+' | '=' as prefix
+ u32 max_number, // allow numbers < 'max_number' (0=disabled)
+ s64 result, // start value for result
+
+ ccp err_msg, // not NULL: print a warning message:
+ // "<ERR_MSG>: Unknown keyword: <KEY>"
+ enumError err_code // use 'err_code' for the 'err_msg'
+)
+{
+ return ScanKeywordListEx( arg, key_tab, func, allow_prefix,
+ max_number, result, 0, err_msg, err_code, 0 );
+}
+
+//-----------------------------------------------------------------------------
+
+enumError ScanKeywordListFunc
+(
+ ccp arg, // argument to scan
+ const KeywordTab_t *key_tab, // valid pointer to command table
+ KeywordCallbackFunc func, // calculation function
+ void *param, // used define parameter for 'func'
+ bool allow_prefix // allow '-' | '+' | '=' as prefix
+);
+
+//-----------------------------------------------------------------------------
+
+s64 ScanKeywordListMask
+(
+ ccp arg, // argument to scan
+ const KeywordTab_t * key_tab // valid pointer to command table
+);
+
+//-----------------------------------------------------------------------------
+
+enumError PrintKeywordError
+(
+ const KeywordTab_t * key_tab, // NULL or pointer to command table
+ ccp key_arg, // analyzed command
+ int key_stat, // status of ScanKeyword()
+ ccp prefix, // NULL or prefix for messages
+ ccp object // NULL or object for error messages
+ // default= 'command'
+);
+
+uint CollectAmbiguousKeywords
+(
+ char *buf, // destination buffer, 200 bytes are good
+ uint buf_size, // size of buffer
+ const KeywordTab_t * key_tab, // NULL or pointer to command table
+ ccp key_arg // analyzed command
+);
+
+//-----------------------------------------------------------------------------
+
+char * PrintKeywordList
+(
+ // returns a pointer to the result buffer
+
+ char *buf, // result buffer
+ // If NULL, a local circulary static buffer
+ // with max CIRC_BUF_MAX_ALLOC bytes is used
+ uint buf_size, // size of 'buf', at least 10 bytes if buf is set
+ uint *ret_length, // not NULL: store result length here
+
+ const KeywordTab_t *tab, // related keyword table
+ u64 mode, // mode to print
+ u64 default_mode, // NULL or default mode
+ u64 hide_mode // bit field to hide parameters
+);
+
+//-----------------------------------------------------------------------------
+
+int ScanKeywordOffOn
+(
+ // returns 0 for '0|OFF'; 1 for '1|ON; -1 for empty; -2 on error
+
+ ccp arg, // argument to scan
+ uint max_num, // >0: additionally accept+return number <= max_num
+ ccp object // NULL (silent) or object for error messages
+);
+
+//-----------------------------------------------------------------------------
+
+enumError Command_ARGTEST ( int argc, char ** argv );
+enumError Command_TESTCOLORS ( int argc, char ** argv );
+
+enumError Command_COLORS
+(
+ int level, // only used, if mode==NULL
+ // < 0: status message (ignore mode)
+ // >= 1: include names
+ // >= 2: include alt names
+ // >= 3: include color names incl bold
+ // >= 4: include background color names
+ uint mode, // output mode => see PrintColorSetHelper()
+ uint format // output format => see PrintColorSetEx()
+);
+
+
+///////////////////////////////////////////////////////////////////////////////
+/////////////// OFF/AUTO/ON/FORCE ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[OffOn_t]]
+
+typedef enum OffOn_t
+{
+ OFFON_ERROR = -99,
+ OFFON_OFF = -1,
+ OFFON_AUTO = 0,
+ OFFON_ON = 1,
+ OFFON_FORCE = 2,
+}
+OffOn_t;
+
+extern const KeywordTab_t KeyTab_OFF_AUTO_ON[];
+
+int ScanKeywordOffAutoOn
+(
+ // returns one of OFFON_*
+
+ ccp arg, // argument to scan
+ int on_empty, // return this value on empty
+ uint max_num, // >0: additionally accept+return number <= max_num
+ ccp object // NULL (silent) or object for error messages
+);
+
+ccp GetKeywordOffAutoOn ( OffOn_t value );
+
+// //
+///////////////////////////////////////////////////////////////////////////////
+/////////////// scan command lists ///////////////
+///////////////////////////////////////////////////////////////////////////////
+//
+// Scan a semicolon separated command list with binary support of format:
+// COMMAND := NAME [BINLIST] CONTROL* ['='] CONTROL* [PARAM] CONTROL* ';'
+// BLANK := TAB(9) or SPACE(32)
+// CONTROL := NUL..SPACE (0..32)
+// NAME := 1..99 alphanumeric chars incl. minus and underline
+// BINLIST := BINARY [BINLIST]
+// BINARY := BLANK* '\1' be16:SIZE DATA
+// PARAM := all except ';'
+//
+// CONTROLS are possible before and behind the '=' and at the end of param.
+// Only BLANK* are allowed between command NAME and BINARY block.
+// BINARY data starts with \1 and is stored as '->bin' and '->bin_len' and
+// inludes SIZE and DATA. The BINARY.SIZE includes itself and is a 16-bit
+// big-endian number. In '->bin[]', member 'be16:SIZE' is excluded,
+// but '->bin[].ptr - 2' points to be16:SIZE.
+//
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[CommandList_t]] docu -> see above
+
+struct TCPStream_t;
+#define COMMAND_LIST_N_BIN 5
+
+typedef struct CommandList_t
+{
+ //--- input params
+
+ ccp command; // command text
+ uint command_len; // total length of 'command'
+ char command_sep; // not NULL: alternative command separator
+ u8 change_case; // >0: convert command to lower(1) or upper(2) case
+ bool term_param; // 1: write a NULL at end-of-param => modify 'command'
+ // 2: write a ';' at end-of-param => modify 'command'
+ // in this case, ';' is counted to 'record_len'
+ bool is_terminated; // true: last command is terminated
+ // even without ';'
+
+ //--- user parameters, pass-through
+
+ struct TCPStream_t
+ *user_ts; // NULL or a stream for replies
+ void *user_ptr; // any pointer
+ int user_int; // any number or id
+
+ ccp log_fname; // not NULL: open log file
+ uint log_level; // 0:off, 1:stat+err, 2:+cmd, 3:+bin+param, 4:+func
+
+ //--- analysed data, only valid at callback
+
+ char cmd[100]; // scanned command name
+ uint cmd_len; // length of scanned command name
+
+ uint n_bin; // number of binary blocks
+ mem_t bin[COMMAND_LIST_N_BIN];
+ // binary data detected, if bin[].ptr not null
+
+ ccp param; // pointer to text parameter, not NULL terminated
+ uint param_len; // length of text parameter
+ const u8 *record; // complete record from NAME to END_RECORD_CHAR
+ uint record_len; // length of trimmed record
+ uint input_len; // length of complete record at input time
+
+ //--- statistics
+
+ uint read_cmd_len; // number of used bytes of 'command'
+ uint fail_count; // number of failed commands
+ uint cmd_count; // number of commands
+}
+CommandList_t;
+
+// return -1 to abort scanning
+typedef int (*CommandListFunc) ( CommandList_t *cli );
+
+//-----------------------------------------------------------------------------
+
+static inline void InitializeCommandList ( CommandList_t *cli )
+ { DASSERT(cli); memset(cli,0,sizeof(*cli)); }
+
+static inline void ClearCommandList ( CommandList_t *cli )
+ { DASSERT(cli); }
+
+static inline void ResetCommandList ( CommandList_t *cli )
+ { DASSERT(cli); memset(cli,0,sizeof(*cli)); }
+
+// a test function for ScanCommandList()
+int ExecCommandOfList ( CommandList_t *cli );
+
+int ScanCommandList
+(
+ // scan a semicolon separated command list. See above for format
+ // returns -1 on 'cli->fail_count'; otherwise 'cli->cmd_count'
+
+ CommandList_t *cli, // valid command list
+ CommandListFunc func // NULL or function for each command
+);
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// numeric functions ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+extern int urandom_available; // <0:not, =0:not tested, >0:ok
+extern bool use_urandom_for_myrandom;
+
+uint ReadFromUrandom ( void *dest, uint size );
+
+///////////////////////////////////////////////////////////////////////////////
+
+u32 MyRandom ( u32 max );
+u64 MySeed ( u64 base );
+u64 MySeedByTime(void);
+
+void MyRandomFill ( void * buf, size_t size );
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CreateUUID ( uuid_buf_t dest );
+uint CreateTextUUID ( char *buf, uint bufsize );
+uint PrintUUID ( char *buf, uint bufsize, uuid_buf_t uuid );
+char * ScanUUID ( uuid_buf_t uuid, ccp source );
+
+///////////////////////////////////////////////////////////////////////////////
+
+uint gcd ( uint n1, uint n2 ); // greatest common divisor, german: ggt
+u32 gcd32 ( u32 n1, u32 n2 );
+u64 gcd64 ( u64 n1, u64 n2 );
+
+uint lcm ( uint n1, uint n2 ); // lowest common multiple, german: kgv
+u32 lcm32 ( u32 n1, u32 n2 );
+u64 lcm64 ( u64 n1, u64 n2 );
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// scan number ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+enum DigitTable_t
+{
+ NUMBER_NULL = -1, // NULL
+ NUMBER_CONTROL = -2, // < 0x20, but not SPACE or LINE
+ NUMBER_LINE = -3, // LF, CR
+ NUMBER_SPACE = -4, // SPACE, TAB, VT
+ NUMBER_TIE = -5, // ':' '-' '.'
+ NUMBER_SEPARATE = -6, // ',' ';'
+ NUMBER_OTHER = -7 // all other
+};
+
+extern const char DigitTable[256];
+
+//-----------------------------------------------------------------------------
+
+u64 ScanDigits
+(
+ // same as ScanNumber(), but other interface
+ // returns the scanned number
+
+ ccp *source, // pointer to source string, modified
+ ccp end_source, // NULL or end of 'source'
+ uint intbase, // integer base, 2..36
+ int maxchar, // max number of digits to read
+ uint *count // not NULL: store number of scanned digits here
+);
+
+//-----------------------------------------------------------------------------
+
+char * ScanNumber
+(
+ // same as ScanDigits(), but other interface
+ // returns a pointer to the first not used character
+
+ uint *dest_num, // store result here, never NULL
+ ccp src, // pointer to source string, modified
+ ccp src_end, // NULL or end of 'src'
+ uint intbase, // integer base, 2..36
+ int maxchar // max number of digits to read
+);
+
+//-----------------------------------------------------------------------------
+
+char * ScanEscape
+(
+ // returns a pointer to the first not used character
+
+ uint *dest_code, // store result here, never NULL
+ ccp src, // pointer to source string (behind escape char)
+ ccp src_end // NULL or end of 'src'
+);
+
+//-----------------------------------------------------------------------------
+
+uint ScanHexString
+(
+ // return the number of written bytes
+
+ void *buf, // write scanned data here
+ uint buf_size, // size of buf
+ ccp *source, // pointer to source string, modified
+ ccp end_source, // NULL or end of 'source'
+ bool allow_tie // allow chars ' .:-' and TAB,VT as byte separator
+);
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+char * ScanS32
+(
+ // return 'source' on error
+
+ s32 *res_num, // not NULL: store result (only on success)
+ ccp source, // NULL or source text
+ uint default_base // base for numbers without '0x' prefix
+ // 0: C like with octal support
+ // 10: standard value for decimal numbers
+ // 16: standard value for hex numbers
+);
+
+static inline char * ScanU32 ( u32 *res_num, ccp source, uint default_base )
+ { return ScanS32((s32*)res_num,source,default_base); }
+
+//-----------------------------------------------------------------------------
+
+char * ScanS64
+(
+ // return 'source' on error
+
+ s64 *res_num, // not NULL: store result (only on success)
+ ccp source, // NULL or source text
+ uint default_base // base for numbers without '0x' prefix
+ // 0: C like with octal support
+ // 10: standard value for decimal numbers
+ // 16: standard value for hex numbers
+);
+
+static inline char * ScanU64 ( u64 *res_num, ccp source, uint default_base )
+ { return ScanS64((s64*)res_num,source,default_base); }
+
+//-----------------------------------------------------------------------------
+
+#if __WORDSIZE >= 64
+
+ static inline char * ScanINT ( int *res_num, ccp source, uint default_base )
+ { return ScanS32((s32*)res_num,source,default_base); }
+ static inline char * ScanUINT ( uint *res_num, ccp source, uint default_base )
+ { return ScanS32((s32*)res_num,source,default_base); }
+
+#else
+
+ static inline char * ScanINT ( int *res_num, ccp source, uint default_base )
+ { return ScanS64((s64*)res_num,source,default_base); }
+ static inline char * ScanUINT ( uint *res_num, ccp source, uint default_base )
+ { return ScanS64((s64*)res_num,source,default_base); }
+
+#endif
+
+//-----------------------------------------------------------------------------
+// strto*() replacements: Use Scan*() with better base support, NULL allowed as source
+
+long int str2l ( const char *nptr, char **endptr, int base );
+long long int str2ll ( const char *nptr, char **endptr, int base );
+unsigned long int str2ul ( const char *nptr, char **endptr, int base );
+unsigned long long int str2ull ( const char *nptr, char **endptr, int base );
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// print numbers and size ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[sizeform_mode_t]]
+
+typedef enum sizeform_mode_t
+{
+ DC_SFORM_ALIGN = 0x01, // aligned output
+ DC_SFORM_NARROW = 0x02, // suppress space between number and unit
+ DC_SFORM_UNIT1 = 0x04, // limit unit to 1 character (space for bytes)
+ DC_SFORM_INC = 0x08, // increment to next factor if no fraction is lost
+ DC_SFORM_PLUS = 0x10, // on signed output: print PLUS sign for values >0
+ DC_SFORM_DASH = 0x20, // on NULL: print only a dash (minus sign)
+
+ DC_SFORM__MASK = 0x3f, // mask of above
+ DC_SFORM__AUTO = 0x40, // hint for some functions to decide by themself
+
+ DC_SFORM_TINY = DC_SFORM_NARROW | DC_SFORM_UNIT1,
+}
+sizeform_mode_t;
+
+///////////////////////////////////////////////////////////////////////////////
+
+float RoundF2bytes ( float f );
+float RoundF3bytes ( float f );
+double RoundD6bytes ( double d );
+double RoundD7bytes ( double d );
+
+///////////////////////////////////////////////////////////////////////////////
+
+char * PrintNumberU4 ( char *buf, size_t buf_size, u64 num, sizeform_mode_t mode );
+char * PrintNumberU5 ( char *buf, size_t buf_size, u64 num, sizeform_mode_t mode );
+char * PrintNumberU6 ( char *buf, size_t buf_size, u64 num, sizeform_mode_t mode );
+char * PrintNumberU7 ( char *buf, size_t buf_size, u64 num, sizeform_mode_t mode );
+
+char * PrintNumberS5 ( char *buf, size_t buf_size, s64 num, sizeform_mode_t mode );
+char * PrintNumberS6 ( char *buf, size_t buf_size, s64 num, sizeform_mode_t mode );
+char * PrintNumberS7 ( char *buf, size_t buf_size, s64 num, sizeform_mode_t mode );
+
+char * PrintNumberD5 ( char *buf, size_t buf_size, double num, sizeform_mode_t mode );
+char * PrintNumberD6 ( char *buf, size_t buf_size, double num, sizeform_mode_t mode );
+char * PrintNumberD7 ( char *buf, size_t buf_size, double num, sizeform_mode_t mode );
+
+// Parameters:
+// char *buf, // result buffer
+// // NULL: use a local circulary static buffer
+// size_t buf_size, // size of 'buf', ignored if buf==NULL
+// * num, // number to print
+// sizeform_mode_t mode // any of DC_SFORM_ALIGN, DC_SFORM_DASH[not *D*()]
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[size_mode_t]]
+
+typedef enum size_mode_t
+{
+ //----- modes => used as index for dc_size_tab_1000[] & dc_size_tab_1024[]
+
+ DC_SIZE_DEFAULT = 0, // special default value, fall back to AUTO
+ DC_SIZE_AUTO, // select unit automatically
+
+ DC_SIZE_BYTES, // force output in bytes
+ DC_SIZE_K, // force output in KB or KiB (kilo,kibi)
+ DC_SIZE_M, // force output in MB or MiB (mega,mebi)
+ DC_SIZE_G, // force output in GB or GiB (giga,gibi)
+ DC_SIZE_T, // force output in TB or TiB (tera,tebi)
+ DC_SIZE_P, // force output in PB or PiB (peta,pebi)
+ DC_SIZE_E, // force output in EB or EiB (exa, exbi)
+ // zetta/zebi & yotta/yobi not supported because >2^64
+
+ DC_SIZE_N_MODES, // number of modes
+
+ //----- flags
+
+ DC_SIZE_F_1000 = 0x010, // force output in SI units (kB=1000, MB=1000000,...)
+ DC_SIZE_F_1024 = 0x020, // force output in IEC units (KiB=1024, MiB=1024*1024,...)
+ DC_SIZE_F_AUTO_UNIT = 0x040, // suppress output of unit for non AUTO mode
+ DC_SIZE_F_NO_UNIT = 0x080, // suppress allways output of unit
+
+ //----- masks
+
+ DC_SIZE_M_MODE = 0x00f, // mask for modes
+ DC_SIZE_M_BASE = 0x030, // mask for base
+ DC_SIZE_M_ALL = 0x0ff, // all relevant bits
+}
+size_mode_t;
+
+//-----------------------------------------------------------------------------
+
+extern ccp dc_size_tab_1000[DC_SIZE_N_MODES+1];
+extern ccp dc_size_tab_1024[DC_SIZE_N_MODES+1];
+
+//-----------------------------------------------------------------------------
+
+ccp GetSizeUnit // get a unit for column headers
+(
+ size_mode_t mode, // print mode
+ ccp if_invalid // output for invalid modes
+);
+
+//-----------------------------------------------------------------------------
+
+int GetSizeFW // get a good value field width
+(
+ size_mode_t mode, // print mode
+ int min_fw // minimum fw => return max(calc_fw,min_fw);
+ // this value is also returned for invalid modes
+);
+
+//-----------------------------------------------------------------------------
+
+char * PrintSize
+(
+ char *buf, // result buffer
+ // NULL: use a local circulary static buffer
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u64 size, // size to print
+ sizeform_mode_t sform_mode, // output format, bit field
+ size_mode_t mode // print mode
+);
+
+//-----------------------------------------------------------------------------
+
+char * PrintSize1000
+(
+ char *buf, // result buffer
+ // NULL: use a local circulary static buffer
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u64 size, // size to print
+ sizeform_mode_t sform_mode // output format, bit field
+);
+
+//-----------------------------------------------------------------------------
+
+char * PrintSize1024
+(
+ char *buf, // result buffer
+ // NULL: use a local circulary static buffer
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u64 size, // size to print
+ sizeform_mode_t sform_mode // output format, bit field
+);
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// scan size ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+extern u64 (*ScanSizeFactorHook)
+(
+ char ch_factor, // char to analyze
+ int force_base // if 1000|1024: force multiple of this
+);
+
+u64 ScanSizeFactor
+(
+ char ch_factor, // char to analyze
+ int force_base // if 1000|1024: force multiple of this
+);
+
+char * ScanSizeTerm
+(
+ double *num, // not NULL: store result
+ ccp source, // source text
+ u64 default_factor, // use this factor if number hasn't one
+ int force_base // if 1000|1024: force multiple of this
+);
+
+char * ScanSize
+(
+ double *num, // not NULL: store result
+ ccp source, // source text
+ u64 default_factor, // use this factor if number hasn't one
+ u64 default_factor_add, // use this factor for summands
+ int force_base // if 1000|1024: force multiple of this
+);
+
+char * ScanSizeU32
+(
+ u32 *num, // not NULL: store result
+ ccp source, // source text
+ u64 default_factor, // use this factor if number hasn't one
+ u64 default_factor_add, // use this factor for summands
+ int force_base // if 1000|1024: force multiple of this
+);
+
+char * ScanSizeU64
+(
+ u64 *num, // not NULL: store result
+ ccp source, // source text
+ u64 default_factor, // use this factor if number hasn't one
+ u64 default_factor_add, // use this factor for summands
+ int force_base // if 1000|1024: force multiple of this
+);
+
+//-----------------------------------------------------------------------------
+// strto*() like wrappers
+
+u32 GetSizeU32 ( ccp src, char **end, int force_base );
+u64 GetSizeU64 ( ccp src, char **end, int force_base );
+double GetSizeD ( ccp src, char **end, int force_base );
+
+//-----------------------------------------------------------------------------
+
+char * ScanSizeRange
+(
+ int *stat, // if not NULL: store result
+ // 0:none, 1:single, 2:range
+ double *num1, // not NULL: store 'from' result
+ double *num2, // not NULL: store 'to' result
+
+ ccp source, // source text
+ u64 default_factor, // use this factor if number hasn't one
+ u64 default_factor_add, // use this factor for summands
+ int force_base, // if 1000|1024: force multiple of this
+ double max_value // >0: max value for open ranges
+);
+
+char * ScanSizeRangeU32
+(
+ int *stat, // if not NULL: store result
+ // 0:none, 1:single, 2:range
+ u32 *num1, // not NULL: store 'from' result
+ u32 *num2, // not NULL: store 'to' result
+
+ ccp source, // source text
+ u64 default_factor, // use this factor if number hasn't one
+ u64 default_factor_add, // use this factor for summands
+ int force_base, // if 1000|1024: force multiple of this
+ u32 max_value // >0: max value for open ranges
+);
+
+char * ScanSizeRangeU64
+(
+ int *stat, // if not NULL: store result
+ // 0:none, 1:single, 2:range
+ u64 *num1, // not NULL: store 'from' result
+ u64 *num2, // not NULL: store 'to' result
+
+ ccp source, // source text
+ u64 default_factor, // use this factor if number hasn't one
+ u64 default_factor_add, // use this factor for summands
+ int force_base, // if 1000|1024: force multiple of this
+ u64 max_value // >0: max value for open ranges
+);
+
+//-----------------------------------------------------------------------------
+
+char * ScanSizeRangeList
+(
+ uint *n_range, // not NULL: store number of scanned ranges
+ double *num, // array with '2*max_range' elements
+ // unused elements are filled with 0.0
+ uint max_range, // max number of allowed ranges
+
+ ccp source, // source text
+ u64 default_factor, // use this factor if number hasn't one
+ u64 default_factor_add, // use this factor for summands
+ int force_base, // if 1000|1024: force multiple of this
+ double max_value // >0: max value for open ranges
+);
+
+char * ScanSizeRangeListU32
+(
+ uint *n_range, // not NULL: store number of scanned ranges
+ u32 *num, // array with '2*max_range' elements
+ // unused elements are filled with 0
+ uint max_range, // max number of allowed ranges
+
+ ccp source, // source text
+ u32 default_factor, // use this factor if number hasn't one
+ u32 default_factor_add, // use this factor for summands
+ int force_base, // if 1000|1024: force multiple of this
+ u32 max_value // >0: max value for open ranges
+);
+
+char * ScanSizeRangeListU64
+(
+ uint *n_range, // not NULL: store number of scanned ranges
+ u64 *num, // array with '2*max_range' elements
+ // unused elements are filled with 0
+ uint max_range, // max number of allowed ranges
+
+ ccp source, // source text
+ u64 default_factor, // use this factor if number hasn't one
+ u64 default_factor_add, // use this factor for summands
+ int force_base, // if 1000|1024: force multiple of this
+ u64 max_value // >0: max value for open ranges
+);
+
+//-----------------------------------------------------------------------------
+
+enumError ScanSizeOpt
+(
+ double *num, // not NULL: store result
+ ccp source, // source text
+ u64 default_factor, // use this factor if number hasn't one
+ u64 default_factor_add, // use this factor for summands
+ int force_base, // if 1000|1024: force multiple of this
+
+ ccp opt_name, // NULL or name of option for error messages
+ u64 min, // >0: minimum allowed value
+ u64 max, // >0: maximum allowed value
+ bool print_err // true: print error messages
+);
+
+enumError ScanSizeOptU64
+(
+ u64 *num, // not NULL: store result
+ ccp source, // source text
+ u64 default_factor, // use this factor if number hasn't one
+ int force_base, // if 1000|1024: force multiple of this
+
+ ccp opt_name, // NULL or name of option for error messages
+ u64 min, // >0: minimum allowed value
+ u64 max, // >0: maximum allowed value
+ u32 multiple, // >0: result must be multiple
+ u32 pow2, // >0: result must power of '1<<pow2'
+ bool print_err // true: print error messages
+);
+
+enumError ScanSizeOptU32
+(
+ u32 *num, // not NULL: store result
+ ccp source, // source text
+ u64 default_factor, // use this factor if number hasn't one
+ int force_base, // if 1000|1024: force multiple of this
+
+ ccp opt_name, // NULL or name of option for error messages
+ u64 min, // >0: minimum allowed value
+ u64 max, // >0: maximum allowed value
+ u32 multiple, // >0: result must be multiple
+ u32 pow2, // >0: result must power of '1<<pow2'
+ bool print_err // true: print error messages
+);
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// Scan Duration ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[ScanDuration_t]]
+
+typedef enum ScanDuration_t
+{
+ SDUMD_SKIP_BLANKS = 0x01, // skip leading blanks
+ SDUMD_ALLOW_COLON = 0x02, // allow 'H:M' and 'H:M:S'
+ SDUMD_ALLOW_DIV = 0x04, // allow fraction 'n/d' as number
+
+ SDUMD_ALLOW_LIST = 0x10, // allow lists like '9h12m'
+ SDUMD_ALLOW_SPACE_SEP = 0x20, // lists: allow spaces as list separator
+ SDUMD_ALLOW_PLUS_SEP = 0x40, // lists: allow '+' as list separator
+ SDUMD_ALLOW_MINUS_SEP = 0x80, // lists: allow '-' as list separator
+
+ SDUMD_M_ALL = 0xf7,
+}
+ScanDuration_t;
+
+//-----------------------------------------------------------------------------
+
+char * ScanDuration
+(
+ double *num, // not NULL: store result
+ ccp source, // source text
+ double default_factor, // default factor if no SI unit found
+ ScanDuration_t mode
+);
+
+double GetDurationFactor ( char ch );
+
+char * ScanSIFactor
+(
+ // returns end of scanned string
+
+ double *num, // not NULL: store result
+ ccp source, // source text
+ double default_factor // return this if no factor found
+);
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// time & timer ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+//--- conversion factors
+
+#define SEC_PER_MIN 60
+#define SEC_PER_HOUR 3600
+#define SEC_PER_DAY 86400
+#define SEC_PER_WEEK 604800
+
+#define MSEC_PER_SEC 1000ull
+#define MSEC_PER_MIN (60*MSEC_PER_SEC)
+#define MSEC_PER_HOUR (3600*MSEC_PER_SEC)
+#define MSEC_PER_DAY (SEC_PER_DAY*MSEC_PER_SEC)
+#define MSEC_PER_WEEK (SEC_PER_WEEK*MSEC_PER_SEC)
+
+#define USEC_PER_MSEC 1000ull
+#define USEC_PER_SEC 1000000ull
+#define USEC_PER_MIN (60*USEC_PER_SEC)
+#define USEC_PER_HOUR (3600*USEC_PER_SEC)
+#define USEC_PER_DAY (SEC_PER_DAY*USEC_PER_SEC)
+#define USEC_PER_WEEK (SEC_PER_WEEK*USEC_PER_SEC)
+
+//--- time types
+
+typedef uint u_sec_t; // unsigned type to store time as seconds
+typedef int s_sec_t; // signed type to store time as seconds
+typedef u64 u_msec_t; // unsigned type to store time as milliseconds
+typedef s64 s_msec_t; // signed type to store time as milliseconds
+typedef u64 u_usec_t; // unsigned type to store time as microseconds
+typedef s64 s_usec_t; // signed type to store time as microseconds
+
+// [[DayTime_t]]
+typedef struct DayTime_t
+{
+ time_t time; // seconds since epoch, like time()
+ int day; // days since epoch
+ int hour; // hour of day
+ int min; // minute of hour
+ int sec; // second of minute
+ int usec; // microsecond of second
+}
+DayTime_t;
+
+//--- only valid after call to SetupTimezone()
+
+extern s64 timezone_adjust_sec;
+extern s64 timezone_adjust_usec;
+extern int timezone_adjust_isdst;
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SetupTimezone ( bool force );
+
+struct timeval GetTimeOfDay ( bool localtime );
+DayTime_t GetDayTime ( bool localtime );
+u_sec_t GetTimeSec ( bool localtime );
+u_msec_t GetTimeMSec ( bool localtime );
+u_usec_t GetTimeUSec ( bool localtime );
+
+u_msec_t GetTimerMSec(void);
+u_usec_t GetTimerUSec(void);
+
+static inline u64 double2msec ( double d ) { return d>0.0 ? (u64)trunc( 1e3*d+0.5 ) : 0; }
+static inline u64 double2usec ( double d ) { return d>0.0 ? (u64)trunc( 1e6*d+0.5 ) : 0; }
+
+static inline double msec2double ( u64 num ) { return num * 1e-3; }
+static inline double usec2double ( u64 num ) { return num * 1e-6; }
+
+//--- another epoch: Monday, 2001-01-01
+
+#define EPOCH_2001_SEC 0x3a4fc880
+#define EPOCH_2001_MSEC (EPOCH_2001_SEC*MSEC_PER_SEC)
+#define EPOCH_2001_USEC (EPOCH_2001_SEC*USEC_PER_SEC)
+
+///////////////////////////////////////////////////////////////////////////////
+
+ccp PrintTimeByFormat
+(
+ // returns temporary buffer by GetCircBuf();
+
+ ccp format, // format string for strftime()
+ time_t time // seconds since epoch -> time()
+);
+
+ccp PrintTimeByFormatUTC
+(
+ // returns temporary buffer by GetCircBuf();
+
+ ccp format, // format string for strftime()
+ time_t time // seconds since epoch -> time()
+);
+
+//-----------------------------------------------------------------------------
+
+ccp PrintUsecByFormat
+(
+ // returns temporary buffer by GetCircBuf();
+
+ ccp format, // format string for strftime()
+ time_t time, // seconds since epoch -> time()
+ uint usec // micro second of second
+);
+
+ccp PrintUsecByFormatUTC
+(
+ // returns temporary buffer by GetCircBuf();
+
+ ccp format, // format string for strftime()
+ time_t time, // seconds since epoch -> time()
+ uint usec // micro second of second
+);
+
+//-----------------------------------------------------------------------------
+
+
+ccp PrintTimevalByFormat
+(
+ // returns temporary buffer by GetCircBuf();
+
+ ccp format, // format string for strftime()
+ const struct timeval *tv // time to print, if NULL use gettimeofday()
+);
+
+
+ccp PrintTimevalByFormatUTC
+(
+ // returns temporary buffer by GetCircBuf();
+
+ ccp format, // format string for strftime()
+ const struct timeval *tv // time to print, if NULL use gettimeofday()
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+ccp PrintTimeSec
+(
+ char * buf, // result buffer (>19 bytes are good)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u_sec_t sec // seconds (=time) to print
+);
+
+//-----------------------------------------------------------------------------
+
+ccp PrintTimeMSec
+(
+ char * buf, // result buffer (>23 bytes are good)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u_msec_t msec, // milliseconds to print
+ uint fraction // number of digits (0-3) to print as fraction
+);
+
+//-----------------------------------------------------------------------------
+
+ccp PrintTimeUSec
+(
+ char * buf, // result buffer (>26 bytes are good)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u_usec_t usec, // microseconds to print
+ uint fraction // number of digits (0-6) to print as fraction
+);
+
+//-----------------------------------------------------------------------------
+
+ccp PrintTimerMSec
+(
+ char * buf, // result buffer (>12 bytes are good)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u32 msec, // milliseconds to print
+ uint fraction // number of digits (0-3) to print as fraction
+);
+
+ccp PrintTimerUSec
+(
+ char * buf, // result buffer (>16 bytes are good)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ s_usec_t usec, // microseconds to print
+ uint fraction // number of digits (0-3) to print as fraction
+);
+
+//-----------------------------------------------------------------------------
+
+ccp PrintTimer3 // helper function
+(
+ char * buf, // result buffer (>3 bytes)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u64 sec, // seconds to print
+ int usec, // 0...999999: usec fraction, otherwise suppress ms/us output
+ bool aligned // true: print aligned 3 character output
+);
+
+static inline ccp PrintTimerSec3
+(
+ char * buf, // result buffer (>3 bytes)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u_sec_t sec, // seconds to print
+ bool aligned // true: print aligned 3 character output
+)
+{
+ return PrintTimer3(buf,buf_size,sec,-1,aligned);
+}
+
+static inline ccp PrintTimerMSec3
+(
+ char * buf, // result buffer (>3 bytes)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u_msec_t msec, // microseconds to print
+ bool aligned // true: print aligned 3 character output
+)
+{
+ return PrintTimer3(buf,buf_size,msec/1000,msec%1000*1000,aligned);
+}
+
+static inline ccp PrintTimerUSec3
+(
+ char * buf, // result buffer (>3 bytes)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u_usec_t usec, // microseconds to print
+ bool aligned // true: print aligned 3 character output
+)
+{
+ return PrintTimer3(buf,buf_size,usec/1000000,usec%1000000,aligned);
+}
+
+//-----------------------------------------------------------------------------
+
+ccp PrintTimer4 // helper function
+(
+ char * buf, // result buffer (>4 bytes)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u64 sec, // seconds to print
+ int usec, // 0...999999: usec fraction, otherwise suppress ms/us output
+ bool aligned // true: print aligned 4 character output
+);
+
+static inline ccp PrintTimerSec4
+(
+ char * buf, // result buffer (>4 bytes)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u_sec_t sec, // seconds to print
+ bool aligned // true: print aligned 4 character output
+)
+{
+ return PrintTimer4(buf,buf_size,sec,-1,aligned);
+}
+
+static inline ccp PrintTimerMSec4
+(
+ char * buf, // result buffer (>4 bytes)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u_msec_t msec, // microseconds to print
+ bool aligned // true: print aligned 4 character output
+)
+{
+ return PrintTimer4(buf,buf_size,msec/1000,msec%1000*1000,aligned);
+}
+
+static inline ccp PrintTimerUSec4
+(
+ char * buf, // result buffer (>4 bytes)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u_usec_t usec, // microseconds to print
+ bool aligned // true: print aligned 4 character output
+)
+{
+ return PrintTimer4(buf,buf_size,usec/1000000,usec%1000000,aligned);
+}
+
+//-----------------------------------------------------------------------------
+
+ccp PrintTimer6 // helper function
+(
+ char * buf, // result buffer (>6 bytes)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u64 sec, // seconds to print
+ int usec, // 0...999999: usec fraction,
+ // otherwise suppress ms/us output
+ bool aligned // true: print aligned 6 character output
+);
+
+static inline ccp PrintTimerSec6
+(
+ char * buf, // result buffer (>6 bytes)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u_sec_t sec, // seconds to print
+ bool aligned // true: print aligned 6 character output
+)
+{
+ return PrintTimer6(buf,buf_size,sec,-1,aligned);
+}
+
+static inline ccp PrintTimerMSec6
+(
+ char * buf, // result buffer (>6 bytes)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u_msec_t msec, // microseconds to print
+ bool aligned // true: print aligned 6 character output
+)
+{
+ return PrintTimer6(buf,buf_size,msec/1000,msec%1000*1000,aligned);
+}
+
+static inline ccp PrintTimerUSec6
+(
+ char * buf, // result buffer (>6 bytes)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u_usec_t usec, // microseconds to print
+ bool aligned // true: print aligned 6 character output
+)
+{
+ return PrintTimer6(buf,buf_size,usec/1000000,usec%1000000,aligned);
+}
+
+//-----------------------------------------------------------------------------
+
+ccp PrintTimerUSec4s
+(
+ char * buf, // result buffer (>4 bytes)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ s_usec_t usec, // microseconds to print
+ sizeform_mode_t mode // support of DC_SFORM_ALIGN, DC_SFORM_PLUS
+);
+
+static inline ccp PrintTimerMSec4s
+(
+ char * buf, // result buffer (>4 bytes)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ s_msec_t msec, // milliseconds to print
+ sizeform_mode_t mode // support of DC_SFORM_ALIGN, DC_SFORM_PLUS
+)
+{
+ return PrintTimerUSec4s(buf,buf_size,1000*msec,mode);
+}
+
+static inline ccp PrintTimerSec4s
+(
+ char * buf, // result buffer (>4 bytes)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ int sec, // seconds to print
+ sizeform_mode_t mode // support of DC_SFORM_ALIGN, DC_SFORM_PLUS
+)
+{
+ return PrintTimerUSec4s(buf,buf_size,1000000ll*sec,mode);
+}
+
+//-----------------------------------------------------------------------------
+
+ccp PrintTimerUSec7s
+(
+ char * buf, // result buffer (>7 bytes)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ s_usec_t usec, // microseconds to print
+ sizeform_mode_t mode // support of DC_SFORM_ALIGN, DC_SFORM_PLUS
+);
+
+static inline ccp PrintTimerMSec7s
+(
+ char * buf, // result buffer (>7 bytes)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ s_msec_t msec, // milliseconds to print
+ sizeform_mode_t mode // support of DC_SFORM_ALIGN, DC_SFORM_PLUS
+)
+{
+ return PrintTimerUSec7s(buf,buf_size,1000*msec,mode);
+}
+
+static inline ccp PrintTimerSec7s
+(
+ char * buf, // result buffer (>7 bytes)
+ // If NULL, a local circulary static buffer is used
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ int sec, // seconds to print
+ sizeform_mode_t mode // support of DC_SFORM_ALIGN, DC_SFORM_PLUS
+)
+{
+ return PrintTimerUSec7s(buf,buf_size,1000000ll*sec,mode);
+}
+
+//-----------------------------------------------------------------------------
+
+typedef struct xtime_t
+{
+ time_t time;
+ suseconds_t usec;
+ u64 total_usec;
+ u64 rel_usec;
+
+} xtime_t;
+
+u64 GetXTime ( xtime_t * xtime );
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// scan date & time ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+// ScanInterval*() is old ==> try ScanDuration()
+
+char * ScanInterval
+(
+ time_t *res_time, // not NULL: store seconds
+ u32 *res_usec, // not NULL: store micro seconds of second
+ ccp source // source text
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+char * ScanInterval64
+(
+ u64 *res_usec, // not NULL: store total micro seconds
+ ccp source // source text
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+char * ScanDateTime
+(
+ time_t *res_time, // not NULL: store seconds
+ u32 *res_usec, // not NULL: store micro seconds of second
+ ccp source, // source text
+ bool allow_delta // true: allow +|- interval
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+char * ScanDateTime64
+(
+ u64 *res_usec, // not NULL: store total micro seconds
+ ccp source, // source text
+ bool allow_delta // true: allow +|- interval
+);
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// Since 2001 ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+// Values for day and week are exact.
+// Values for month, quarter and year are based on 365.2425 days/year.
+
+//-----------------------------------------------------------------------
+// name full/13 short/11 alt/10 tiny/8
+//-----------------------------------------------------------------------
+// hour YYYY-MM-DD HH YY-MM-DD HH DD. HH:xx MM-DD HH
+// day YYYY-MM-DD << << YY-MM-DD
+// week YYYYwWW << << <<
+// month YYYY-MM << << <<
+// quarter YYYYqQ << << <<
+// year YYYY << << <<
+//-----------------------------------------------------------------------
+
+enum
+{
+ S2001_FW_FULL = 13, ///< Standard-Text mit vollem Jahr (maximal 13 Zeichen).
+ S2001_FW_SHORT = 11, ///< Verkürzte Stundenangabe (maximal 11 Zeichen).
+ S2001_FW_ALT = 10, ///< Alternative Stundenangabe mit »:xx« (maximal 10 Zeichen).
+ S2001_FW_TINY = 8, ///< Verkürzte Stunden- und Wochenangabe (maximal 8 Zeichen).
+
+ S2001_DUR_HOUR = 3600, ///< Dauer einer Stunde in Sekunden.
+ S2001_DUR_DAY = 86400, ///< Dauer eines Tages in Sekunden.
+ S2001_DUR_WEEK = 604800, ///< Dauer einer Woche in Sekunden.
+ S2001_DUR_MONTH = 2629746, ///< Dauer eines Monats in Sekunden (365.2425/12 Tage).
+ S2001_DUR_QUARTER = 7889238, ///< Dauer eines Quartals in Sekunden (365.2425/4 Tage).
+ S2001_DUR_YEAR = 31556952, ///< Dauer eines Jahres in Sekunden (365.2425 Tage).
+};
+
+///////////////////////////////////////////////////////////////////////////
+// hour support
+
+static inline int time2hour ( s64 time )
+ { return time / 3600 - 271752; }
+
+static inline double time2hourF ( s64 time )
+ { return time / 3600.0 - 271752; }
+
+static inline s64 hour2time ( int hour )
+ { return ( hour + 271752 ) * 3600; }
+
+static inline int hour2duration ( int hour )
+ { return S2001_DUR_HOUR; }
+
+ccp hour2text
+(
+ int hour, // hour to print
+ int fw, // wanted field width assuming separators are 1 char
+ ccp sep_date, // NULL or separator within date
+ // if NULL: use '-'
+ ccp sep_dt // NULL or separator of between date and time
+ // if NULL: use ' '
+);
+
+///////////////////////////////////////////////////////////////////////////
+// day support
+
+static inline int time2day ( s64 time )
+ { return time / 86400 - 11323; }
+
+static inline double time2dayF ( s64 time )
+ { return time / 86400.0 - 11323; }
+
+static inline s64 day2time ( int day )
+ { return ( day + 11323 ) * 86400; }
+
+static inline int day2duration ( int day )
+ { return S2001_DUR_DAY; }
+
+ccp day2text
+(
+ int day, // day to print
+ int fw, // wanted field width assuming separators are 1 char
+ ccp sep_date, // NULL or separator within date
+ // if NULL: use '-'
+ ccp sep_dt // ignored
+);
+
+///////////////////////////////////////////////////////////////////////////
+// week support
+
+static inline int time2week ( s64 time )
+ { return ( time - 978307200 ) / 604800; }
+
+static inline double time2weekF ( s64 time )
+ { return ( time - 978307200 ) / 604800.0; }
+
+static inline s64 week2time ( int week )
+ { return week * 604800 + 978307200; }
+
+static inline int week2duration ( int week )
+ { return S2001_DUR_WEEK; }
+
+ccp week2text
+(
+ int week, // week to print
+ int fw, // wanted field width assuming separators are 1 char
+ ccp sep_date, // NULL or separator within date
+ // if NULL: use 'w'
+ ccp sep_dt // ignored
+);
+
+///////////////////////////////////////////////////////////////////////////
+// month support
+
+int time2month ( time_t tim );
+time_t month2time ( int month );
+
+static inline int month2duration ( int month )
+ { return month2time(month+1) - month2time(month); }
+
+ccp month2text
+(
+ int month, // month to print
+ int fw, // wanted field width assuming separators are 1 char
+ ccp sep_date, // NULL or separator within date
+ // if NULL: use '-'
+ ccp sep_dt // ignored
+);
+
+///////////////////////////////////////////////////////////////////////////
+// quarter support
+
+int time2quarter ( time_t tim );
+time_t quarter2time ( int quarter );
+
+static inline int quarter2duration ( int quarter )
+ { return quarter2time(quarter+1) - quarter2time(quarter); }
+
+ccp quarter2text
+(
+ int quarter, // quarter to print
+ int fw, // wanted field width assuming separators are 1 char
+ ccp sep_date, // NULL or separator within date
+ // if NULL: use 'q'
+ ccp sep_dt // ignored
+);
+
+///////////////////////////////////////////////////////////////////////////
+// year support
+
+int time2year ( time_t tim );
+time_t year2time ( int year );
+
+static inline int year2duration ( int year )
+ { return year2time(year+1) - year2time(year); }
+
+static inline ccp year2text
+(
+ int year, // year to print
+ int fw, // wanted field width assuming separators are 1 char
+ ccp sep_date, // ignored
+ ccp sep_dt // ignored
+)
+{
+ return PrintCircBuf("%04d",year);
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// sockaddr support ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[sockaddr_t]] [[sockaddr_in_t]] [[sockaddr_un_t]] [[sockaddr_info_t]]
+
+typedef struct sockaddr sockaddr_t;
+typedef struct sockaddr_in sockaddr_in_t;
+typedef struct sockaddr_un sockaddr_un_t;
+
+typedef struct sockaddr_info_t
+{
+ sockaddr_t *sa; // pointer to sockaddr or sockaddr_*
+ uint size; // size of '*sa'
+}
+sockaddr_info_t;
+
+//-----------------------------------------------------------------------------
+
+// [[doxygen]]
+static inline sockaddr_info_t CreateSockaddrInfo ( cvp sa, uint size )
+{
+ sockaddr_info_t i =
+ {
+ .sa = (sockaddr_t*)sa,
+ .size = size
+ };
+ return i;
+}
+
+//-----------------------------------------------------------------------------
+
+// [[doxygen]]
+static inline void SetupSockaddrInfo ( sockaddr_info_t *sai, cvp sa, uint size )
+{
+ DASSERT(sai);
+ sai->sa = (sockaddr_t*)sa;
+ sai->size = size ? size : sizeof(sockaddr_in_t);
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// PrintIP4*() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+#define FW_IPV4_A 12 // 255.16777215
+#define FW_IPV4_B 13 // 255.255.65535
+#define FW_IPV4_C 15 // 255.255.255.255
+
+#define FW_IPV4_PORT 5 // 65535
+
+#define FW_IPV4_A_PORT (FW_IPV4_A+1+FW_IPV4_PORT)
+#define FW_IPV4_B_PORT (FW_IPV4_B+1+FW_IPV4_PORT)
+#define FW_IPV4_C_PORT (FW_IPV4_C+1+FW_IPV4_PORT)
+
+//-----------------------------------------------------------------------------
+
+char * PrintIP4A
+(
+ // print in A-notation
+
+ char *buf, // result buffer
+ // NULL: use a local circulary static buffer
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u32 ip4, // IP4 to print
+ s32 port // 0..0xffff: add ':port'
+);
+
+char * PrintIP4B
+(
+ // print in A-notation
+
+ char *buf, // result buffer
+ // NULL: use a local circulary static buffer
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u32 ip4, // IP4 to print
+ s32 port // 0..0xffff: add ':port'
+);
+
+//-----------------------------------------------------------------------------
+// print in C-notation (usual notation)
+
+char * PrintIP4
+(
+ char *buf, // result buffer
+ // NULL: use a local circulary static buffer
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u32 ip4, // IP4 to print
+ s32 port // 0..0xffff: add ':port'
+);
+
+char * PrintLeftIP4
+(
+ char *buf, // result buffer
+ // NULL: use a local circulary static buffer
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u32 ip4, // IP4 to print
+ s32 port // 0..0xffff: add ':port'
+);
+
+char * PrintRightIP4
+(
+ char *buf, // result buffer
+ // NULL: use a local circulary static buffer
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u32 ip4, // IP4 to print
+ s32 port, // 0..0xffff: add ':port'
+ uint port_mode // 0: 'ip:port', 1: 'ip :port', 2: 'ip : port'
+);
+
+char * PrintAlignedIP4
+(
+ char *buf, // result buffer
+ // NULL: use a local circulary static buffer
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+ u32 ip4, // IP4 to print
+ s32 port // 0..0xffff: add ':port'
+);
+
+//-----------------------------------------------------------------------------
+struct sockaddr_in;
+
+static inline char * PrintIP4sa
+(
+ char *buf, // result buffer
+ // NULL: use a local circulary static buffer
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+
+ const struct sockaddr_in *sa // socket address
+)
+{
+ DASSERT(sa);
+ return PrintIP4(buf,buf_size,
+ ntohl(sa->sin_addr.s_addr), ntohs(sa->sin_port) );
+}
+
+static inline char * PrintRightIP4sa
+(
+ char *buf, // result buffer
+ // NULL: use a local circulary static buffer
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+
+ struct sockaddr_in *sa // socket address
+)
+{
+ DASSERT(sa);
+ return PrintRightIP4(buf,buf_size,
+ ntohl(sa->sin_addr.s_addr), ntohs(sa->sin_port), 0 );
+}
+
+static inline char * PrintAlignedIP4sa
+(
+ char *buf, // result buffer
+ // NULL: use a local circulary static buffer
+ size_t buf_size, // size of 'buf', ignored if buf==NULL
+
+ struct sockaddr_in *sa // socket address
+)
+{
+ DASSERT(sa);
+ return PrintAlignedIP4(buf,buf_size,
+ ntohl(sa->sin_addr.s_addr), ntohs(sa->sin_port) );
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// dynamic data support ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[DynData_t]]
+
+typedef struct DynData_t
+{
+ u8 *data; // pointer to data, alloced
+ uint len; // length of used data
+ uint size; // size of allocated data
+}
+DynData_t;
+
+//-----------------------------------------------------------------------------
+
+void ResetDD ( DynData_t *dd );
+void InsertDD ( DynData_t *dd, const void *data, uint data_size );
+
+///////////////////////////////////////////////////////////////////////////////
+// [[DynDataList_t]]
+
+typedef struct DynDataList_t
+{
+ DynData_t *list; // pointer to the data list
+ uint used; // number of used data elements
+ uint size; // number of allocated pointer in 'list'
+}
+DynDataList_t;
+
+//-----------------------------------------------------------------------------
+
+void ResetDDL ( DynDataList_t *ddl );
+
+DynData_t *InsertDDL
+(
+ DynDataList_t *ddl, // valid dynamic data list
+ uint index, // element index to change
+ const void *data, // NULL or data to assign
+ uint data_size // size of data
+);
+
+DynData_t *GetDDL
+(
+ DynDataList_t *ddl, // valid dynamic data list
+ uint index, // element index to get
+ uint create // >0: create an empty element if not exist
+ // >index: create at least # elements
+);
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// struct StringField_t ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[StringField_t]]
+
+typedef struct StringField_t
+{
+ ccp * field; // pointer to the string field
+ uint used; // number of used titles in the title field
+ uint size; // number of allocated pointer in 'field'
+ int (*func_cmp)( ccp s1, ccp s2 ); // compare function, default is strcmp()
+
+} StringField_t;
+
+//-----------------------------------------------------------------------------
+
+static inline void InitializeStringField ( StringField_t * sf )
+ { DASSERT(sf); memset(sf,0,sizeof(*sf)); }
+
+void ResetStringField ( StringField_t * sf );
+void MoveStringField ( StringField_t * dest, StringField_t * src );
+
+int FindStringFieldIndex ( const StringField_t * sf, ccp key, int not_found_value );
+ccp FindStringField ( const StringField_t * sf, ccp key );
+
+// return: true if item inserted/deleted
+bool InsertStringField ( StringField_t * sf, ccp key, bool move_key );
+bool RemoveStringField ( StringField_t * sf, ccp key );
+uint RemoveStringFieldByIndex ( StringField_t * sf, int index, int n );
+
+// helper function
+ccp * InsertStringFieldHelper ( StringField_t * sf, int idx );
+
+// append at the end an do not sort
+void AppendStringField ( StringField_t * sf, ccp key, bool move_key );
+
+// re-sort field using sf->func_cmp()
+void SortStringField ( StringField_t * sf );
+
+// return the index of the (next) item
+uint FindStringFieldHelper ( const StringField_t * sf, bool * found, ccp key );
+
+// find first pattern that matches
+ccp MatchStringField ( const StringField_t * sf, ccp key );
+
+//-----------------------------------------------------------------------------
+// file support
+
+enumError LoadStringField
+(
+ StringField_t * sf, // string field
+ bool init_sf, // true: initialize 'sf' first
+ bool sort, // true: sort 'sf'
+ ccp filename, // filename of source file
+ bool silent // true: don't print open/read errors
+);
+
+enumError SaveStringField
+(
+ StringField_t * sf, // valid string field
+ ccp filename, // filename of dest file
+ bool rm_if_empty // true: rm dest file if 'sf' is empty
+);
+
+enumError WriteStringField
+(
+ FILE * f, // open destination file
+ ccp filename, // NULL or filename (needed on write error)
+ StringField_t * sf, // valid string field
+ ccp prefix, // not NULL: insert prefix before each line
+ ccp eol // end of line text (if NULL: use LF)
+);
+
+//-----------------------------------------------------------------------------
+// save-state support
+
+void SaveCurrentStateStringField
+(
+ FILE *f, // output file
+ ccp name_prefix, // NULL or prefix of name, up to 40 chars
+ uint tab_pos, // tab pos of '='
+ const StringField_t *sf, // valid string field
+ EncodeMode_t emode // encoding mode
+);
+
+struct RestoreState_t;
+void RestoreStateStringField
+(
+ struct RestoreState_t *rs, // info data, may be modified
+ ccp name_prefix, // NULL or prefix of name, up to 40 chars
+ StringField_t *sf, // string field
+ bool init_sf, // true: initialize 'sf', otherwise reset
+ EncodeMode_t emode // encoding mode
+);
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// struct ParamField_t ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[ParamFieldItem_t]]
+
+typedef struct ParamFieldItem_t
+{
+ ccp key; // string as main key
+ uint num; // user defined numeric parameter
+ void *data; // user defined pointer
+
+} ParamFieldItem_t;
+
+//-----------------------------------------------------------------------------
+// [[ParamField_t]]
+
+typedef struct ParamField_t
+{
+ ParamFieldItem_t * field; // pointer to the string field
+ uint used; // number of used titles in the title field
+ uint size; // number of allocated pointer in 'field'
+ bool free_data; // true: unused data will be free'd
+ // initialized with 'false'
+ int (*func_cmp)( ccp s1, ccp s2 ); // compare function, default is strcmp()
+} ParamField_t;
+
+//-----------------------------------------------------------------------------
+
+void InitializeParamField ( ParamField_t * pf );
+void ResetParamField ( ParamField_t * pf );
+void MoveParamField ( ParamField_t * dest, ParamField_t * src );
+
+int FindParamFieldIndex ( const ParamField_t * pf, ccp key, int not_found_value );
+ParamFieldItem_t * FindParamField ( const ParamField_t * pf, ccp key );
+ParamFieldItem_t * FindParamFieldByNum ( const ParamField_t * pf, uint num );
+ParamFieldItem_t * FindInsertParamField
+ ( ParamField_t * pf, ccp key, bool move_key, bool *old_found );
+ParamFieldItem_t * CountParamField ( ParamField_t * pf, ccp key, bool move_key );
+
+// return: true if item inserted/deleted
+bool InsertParamField ( ParamField_t * pf, ccp key, bool move_key, uint num, cvp data );
+bool ReplaceParamField( ParamField_t * pf, ccp key, bool move_key, uint num, cvp data );
+bool RemoveParamField ( ParamField_t * pf, ccp key );
+
+ParamFieldItem_t * InsertParamFieldEx
+ ( ParamField_t * pf, ccp key, bool move_key, uint num, bool *found );
+
+// append at the end an do not sort
+ParamFieldItem_t * AppendParamField
+ ( ParamField_t * pf, ccp key, bool move_key, uint num, cvp data );
+
+// return the index of the (next) item
+uint FindParamFieldHelper ( const ParamField_t * pf, bool * found, ccp key );
+
+// find first pattern that matches
+ParamFieldItem_t * MatchParamField ( const ParamField_t * pf, ccp key );
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// Memory Map ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[MemMapItem_t]]
+
+typedef struct MemMapItem_t
+{
+ u64 off; // offset
+ u64 size; // size
+ u8 overlap; // system info: item overlaps other items
+ u8 index; // user defined index
+ char info[62]; // user defined info text
+
+} MemMapItem_t;
+
+//-----------------------------------------------------------------------------
+// [[MemMap_t]]
+
+typedef struct MemMap_t
+{
+ MemMapItem_t ** field; // pointer to the item field
+ uint used; // number of used titles in the item field
+ uint size; // number of allocated pointer in 'field'
+ u64 begin; // first address
+
+} MemMap_t;
+
+//-----------------------------------------------------------------------------
+// Memory maps allow duplicate entries.
+// The off+size pair is used as key.
+// The entries are sorted by off and size (small values first).
+//-----------------------------------------------------------------------------
+
+void InitializeMemMap ( MemMap_t * mm );
+void ResetMemMap ( MemMap_t * mm );
+
+void CopyMemMap
+(
+ MemMap_t * mm1, // merged mem map, not NULL, cleared
+ const MemMap_t * mm2, // NULL or second mem map
+ bool use_tie // TRUE: use InsertMemMapTie()
+);
+
+void MergeMemMap
+(
+ MemMap_t * mm1, // merged mem map, not NULL, not cleared
+ const MemMap_t * mm2, // NULL or second mem map
+ bool use_tie // TRUE: use InsertMemMapTie()
+);
+
+MemMapItem_t * FindMemMap
+(
+ // returns NULL or the pointer to the one! matched key (={off,size})
+
+ MemMap_t * mm,
+ off_t off,
+ off_t size
+);
+
+uint InsertMemMapIndex
+(
+ // returns the index of the new item
+
+ MemMap_t * mm, // mem map pointer
+ off_t off, // offset of area
+ off_t size // size of area
+);
+
+MemMapItem_t * InsertMemMap
+(
+ // returns a pointer to a new item (never NULL)
+
+ MemMap_t * mm, // mem map pointer
+ off_t off, // offset of area
+ off_t size // size of area
+);
+
+MemMapItem_t * InsertMemMapTie
+(
+ // returns a pointer to a new or existing item (never NULL)
+
+ MemMap_t * mm, // mem map pointer
+ off_t off, // offset of area
+ off_t size // size of area
+);
+
+void InsertMemMapWrapper
+(
+ void * param, // user defined parameter
+ u64 offset, // offset of object
+ u64 size, // size of object
+ ccp info // info about object
+);
+
+// Remove all entires with key. Return number of delete entries
+//uint RemoveMemMap ( MemMap_t * mm, off_t off, off_t size );
+
+// Return the index of the found or next item
+uint FindMemMapHelper ( MemMap_t * mm, off_t off, off_t size );
+
+// Calculate overlaps. Return number of items with overlap.
+uint CalcOverlapMemMap ( MemMap_t * mm );
+
+u64 FindFreeSpaceMemMap
+(
+ // return address or NULL on not-found
+
+ const MemMap_t * mm,
+ u64 addr_beg, // first possible address
+ u64 addr_end, // last possible address
+ u64 size, // minimal size
+ u64 align, // aligning
+ u64 *space // not NULL: store available space here
+);
+
+// Print out memory map
+void PrintMemMap ( MemMap_t * mm, FILE * f, int indent, ccp info_head );
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// Memory Map: Scan addresses ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[ScanAddr_t]]
+
+typedef struct ScanAddr_t
+{
+ uint stat; // 0:invalid, 1:single address, 2:range
+ uint addr; // address
+ uint size; // size inf bytes
+
+} ScanAddr_t;
+
+//-----------------------------------------------------------------------------
+
+char * ScanAddress
+(
+ // returns first not scanned char of 'arg'
+
+ ScanAddr_t * result, // result, initialized by ScanAddress()
+ ccp arg, // format: ADDR | ADDR:END | ADDR#SIZE
+ uint default_base // base for numbers without '0x' prefix
+ // 0: C like with octal support
+ // 10: standard value for decimal numbers
+ // 16: standard value for hex numbers
+);
+
+//-----------------------------------------------------------------------------
+
+uint InsertAddressMemMap
+(
+ // returns the number of added addresses
+
+ MemMap_t * mm, // mem map pointer
+ bool use_tie, // TRUE: use InsertMemMapTie()
+ ccp arg, // comma separated list of addresses
+ // formats: ADDR | ADDR:END | ADDR#SIZE
+ uint default_base // base for numbers without '0x' prefix
+ // 0: C like with octal support
+ // 10: standard value for decimal numbers
+ // 16: standard value for hex numbers
+);
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// DataBuf_t ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+struct DataBuf_t;
+
+typedef enumError (*DataBufFill_t)
+(
+ // function to fill the buffer
+
+ struct DataBuf_t* db, // valid pointer to related DataBuf_t to fill
+ uint need, // number of bytes needed => wait for more data
+ int mode // user mode, null on auto fill
+);
+
+//-----------------------------------------------------------------------------
+// [[DataBuf_t]]
+
+typedef struct DataBuf_t
+{
+ uint size; // size of buffer
+ uint used; // number of used bytes
+ u64 offset; // current file offset, related to 'data'
+
+ u8 *buf; // pointer to buffer, cyclic usage
+ u8 *buf_end; // pointer to buffer end := buf + size
+
+ u8 *data; // pointer to data
+ u8 *data_end; // pointer to end of data
+
+ //--- user data
+
+ DataBufFill_t fill_func; // function to fill buffer
+ void *user_data; // NULL or pointer to user data for 'fill_func'
+}
+DataBuf_t;
+
+///////////////////////////////////////////////////////////////////////////////
+// management
+
+void InitializeDataBuf
+ ( DataBuf_t *db, uint buf_size, DataBufFill_t func, void *user_data );
+void ResetDataBuf ( DataBuf_t *db );
+void ResizeDataBuf ( DataBuf_t *db, uint new_buf_size );
+void ClearDataBuf ( DataBuf_t *db, uint new_buf_size_if_not_null );
+void EmptyDataBuf ( DataBuf_t *db );
+void PackDataBuf ( DataBuf_t *db );
+
+///////////////////////////////////////////////////////////////////////////////
+// debugging
+
+bool IsValidDataBuf ( DataBuf_t *db );
+bool DumpDataBuf ( FILE *f, uint indent, DataBuf_t *db, bool if_invalid );
+
+// fill the buffer with a test pattern:
+// '-' for unused bytes
+// ">0123456789<" in a longer or shorter form for used bytes
+void FillPatternDataBuf ( DataBuf_t *db );
+
+///////////////////////////////////////////////////////////////////////////////
+// insert and remove data
+
+static inline enumError FillDataBuf( DataBuf_t *db, uint need, int mode )
+{
+ return db && db->fill_func ? db->fill_func(db,need,mode) : ERR_WARNING;
+}
+
+uint InsertDataBuf
+(
+ // Insert at top of buffer.
+ // Return the number of inserted bytes
+
+ DataBuf_t *db, // valid pointer to data buffer
+ const void *data, // data to insert
+ uint data_size, // size of 'data'
+ bool all_or_none // true: insert complete data or nothing
+);
+
+uint AppendDataBuf
+(
+ // Append data at end of buffer
+ // Return the number of inserted bytes
+
+ DataBuf_t *db, // valid pointer to data buffer
+ const void *data, // data to insert
+ uint data_size, // size of 'data'
+ bool all_or_none // true: insert complete data or nothing
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+void * GetPtrDataBuf
+(
+ // Return a pointer to the data and make sure,
+ // that the data is not wrapped. Return NULL if failed.
+
+ DataBuf_t *db, // valid pointer to data buffer
+ uint data_size, // number of needed bytes
+ uint align, // >1: Data alignment is also needed.
+ // Only 2,4,8,16,... are allowed, but not verified.
+ // Begin of buffer is always well aligned.
+ bool drop // true: On success, drop data from buffer
+ // In real, the data is available and only
+ // the pointers and counters are updated.
+);
+
+uint CopyDataBuf
+(
+ // Copy data from buffer, but don't remove it
+ // Return the number of copied bytes
+
+ DataBuf_t *db, // valid pointer to data buffer
+ void *dest, // destination buffer wit at least 'max_size' space
+ uint min_read, // return with 0 read bytes if less bytes available
+ // if 'min_read' > 'size', NULL is returned
+ uint max_read // try to read upto 'max_read' bytes
+);
+
+uint GetDataBuf
+(
+ // Copy data from buffer and remove it
+ // Return the number of copied bytes
+
+ DataBuf_t *db, // valid pointer to data buffer
+ void *dest, // destination buffer wit at least 'max_size' space
+ uint min_read, // return with 0 read bytes if less bytes available
+ uint max_read // try to read upto 'max_read' bytes
+);
+
+uint SkipDataBuf
+(
+ // Skip 'skip_size' from input stream. Read more data if needed.
+ // Return the number of really skiped bytes
+ // If <skip_size is returned, no more data is available.
+
+ DataBuf_t *db, // valid pointer to data buffer
+ uint skip_size // number of bytes to drop
+);
+
+uint DropDataBuf
+(
+ // Remove upto 'drop_size' bytes from buffer.
+ // Return the number of dropped bytes.
+
+ DataBuf_t *db, // valid pointer to data buffer
+ uint drop_size // number of bytes to drop
+);
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// ResizeElement_t, ResizeHelper_t ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+typedef struct ResizeElement_t
+{
+ uint n_elem;
+ uint factor;
+}
+ResizeElement_t;
+
+//-----------------------------------------------------------------------------
+
+typedef struct ResizeHelper_t
+{
+ //--- basic data
+
+ uint src_size; // size of source
+ uint dest_size; // size of dest
+
+
+ //--- calculated data
+
+ uint sum_factor; // sum of all factors
+ uint half_factor; // half of 'sum_factor2'
+
+ uint idx_inc; // increment of 'src_idx'
+ uint frac_inc; // increment of 'src_frac'
+ uint frac_next; // if 'frac>=frac_next': increment 'src_idx'
+
+
+ //--- iteration data
+
+ uint dest_idx; // dest index: (0..dest_size(
+ uint src_idx; // src index: (0..src_size(
+ uint src_frac; // (0..frac_next(
+
+ ResizeElement_t // list terminates with n_elem=0
+ elem[4]; // ==> max 3 elements are used
+
+}
+ResizeHelper_t;
+
+//-----------------------------------------------------------------------------
+
+void InitializeResize
+(
+ ResizeHelper_t *r, // data structure
+ uint s_size, // size of source
+ uint d_size // size of dest
+);
+
+bool FirstResize ( ResizeHelper_t *r );
+bool NextResize ( ResizeHelper_t *r );
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// restore configuration ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[RestoreStateLog_t]]
+
+typedef enum RestoreStateLog_t
+{
+ RSL_WARNINGS = 0x01, // general warnings
+ RSL_MISSED_NAMES = 0x02, // hints about missed names
+ RSL_UNUSED_NAMES = 0x04, // hints about unused names
+
+ RSL_ALL = 0x07 // all flags
+}
+RestoreStateLog_t;
+
+//-----------------------------------------------------------------------------
+// [[RestoreState_t]]
+
+typedef struct RestoreState_t
+{
+ ccp sect; // section name
+ ccp path; // section sub path
+ int index; // index or -1
+ ParamField_t param; // name=value parameters
+ cvp user_param; // pointer provided as parameter by user
+ cvp user_info; // pointer to deliver insfos between stages
+
+ RestoreStateLog_t log_mode; // log mode
+ FILE *log_file; // log file
+
+}
+RestoreState_t;
+
+//-----------------------------------------------------------------------------
+
+typedef void (*RestoreStateFunc)
+(
+ RestoreState_t *rs, // info data, can be modified (cleaned after call)
+ cvp user_table // pointer provided by RestoreStateTab_t[]
+);
+
+//-----------------------------------------------------------------------------
+
+typedef struct RestoreStateTab_t
+{
+ ccp name; // name of section
+ RestoreStateFunc func; // function to call
+ cvp user_table; // any user provided pointer
+}
+RestoreStateTab_t;
+
+///////////////////////////////////////////////////////////////////////////////
+
+enumError RestoreState
+(
+ const RestoreStateTab_t
+ *table, // section table, terminated by name==0
+ void *data, // file data, modified, terminated by NULL or LF
+ uint size, // size of file data
+ RestoreStateLog_t log_mode, // print warnings (bit field)
+ FILE *log_file, // error file; if NULL use stderr
+ cvp user_param // pointer provided by user
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+// print into cyclic buffer
+ccp PrintRestoreStateSection ( const RestoreState_t *rs );
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+ParamFieldItem_t * GetParamField
+(
+ const RestoreState_t *rs, // valid restore-state structure
+ ccp name // name of member
+);
+
+//-----------------------------------------------------------------------------
+
+int GetParamFieldINT
+(
+ const RestoreState_t *rs, // valid restore-state structure
+ ccp name, // name of member
+ int not_found // return this value if not found
+);
+
+//-----------------------------------------------------------------------------
+
+uint GetParamFieldUINT
+(
+ const RestoreState_t *rs, // valid restore-state structure
+ ccp name, // name of member
+ uint not_found // return this value if not found
+);
+
+//-----------------------------------------------------------------------------
+
+u64 GetParamFieldS64
+(
+ const RestoreState_t *rs, // valid restore-state structure
+ ccp name, // name of member
+ s64 not_found // return this value if not found
+);
+
+//-----------------------------------------------------------------------------
+
+u64 GetParamFieldU64
+(
+ const RestoreState_t *rs, // valid restore-state structure
+ ccp name, // name of member
+ u64 not_found // return this value if not found
+);
+
+//-----------------------------------------------------------------------------
+
+float GetParamFieldFLOAT
+(
+ const RestoreState_t *rs, // valid restore-state structure
+ ccp name, // name of member
+ float not_found // return this value if not found
+);
+
+//-----------------------------------------------------------------------------
+
+double GetParamFieldDBL
+(
+ const RestoreState_t *rs, // valid restore-state structure
+ ccp name, // name of member
+ double not_found // return this value if not found
+);
+
+//-----------------------------------------------------------------------------
+
+long double GetParamFieldLDBL
+(
+ const RestoreState_t *rs, // valid restore-state structure
+ ccp name, // name of member
+ long double not_found // return this value if not found
+);
+
+//-----------------------------------------------------------------------------
+
+int GetParamFieldBUF
+(
+ // returns >=0: length of read data; -1:nothing done (not_found==NULL)
+
+ char *buf, // buffer to store result
+ uint buf_size, // size of buffer
+
+ const RestoreState_t *rs, // valid restore-state structure
+ ccp name, // name of member
+ EncodeMode_t decode, // decoding mode, fall back to OFF
+ // supported: STRING, UTF8, BASE64, BASE64X
+ ccp not_found // not NULL: store this value if not found
+);
+
+//-----------------------------------------------------------------------------
+
+mem_t GetParamFieldMEM
+(
+ // Returns the decoded 'source'. Result is NULL-terminated.
+ // It points either to 'buf' or is alloced (on buf==NULL or to less space)
+ // If alloced (mem.ptr!=buf) => call FreeMem(&mem)
+
+ char *buf, // buffer to store result
+ uint buf_size, // size of buffer
+
+ const RestoreState_t *rs, // valid restore-state structure
+ ccp name, // name of member
+ EncodeMode_t decode, // decoding mode, fall back to OFF
+ // supported: STRING, UTF8, BASE64, BASE64X
+ mem_t not_found // not NULL: return this value
+);
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// save + restore config by table ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[SaveRestoreType_t]]
+
+typedef enum SaveRestoreType_t
+{
+ SRT__TERM, // list terminator
+
+ SRT_BOOL, // type bool
+ SRT_UINT, // unsigned int of any size (%llu)
+ SRT_HEX, // unsigned int of any size as hex (%#llx)
+ SRT_INT, // signed int of any size (%lld)
+ SRT_FLOAT, // float (%.8g) or double (%.16g) or long double (%.20g)
+ SRT_XFLOAT, // float or double or long double as hex-float (%a/%La)
+
+ SRT_STRING_SIZE, // string with max size, var is char[]
+ SRT_STRING_ALLOC, // alloced string, var is ccp or char*
+ SRT_MEM, // alloced string, var is mem_t
+
+ SRT__IS_LIST, //----- from here: print lists; also used as separator
+
+ SRT_STRING_FIELD, // var is StringField_t
+ SRT_PARAM_FIELD, // var is ParamField_t
+}
+SaveRestoreType_t;
+
+///////////////////////////////////////////////////////////////////////////////
+// [[SaveRestoreTab_t]]
+
+typedef struct SaveRestoreTab_t
+{
+ uint offset; // offset of variable
+ uint size; // sizeof( var or string )
+ ccp name; // name in configuration file
+ u16 n_elem; // >0: is array with N elements
+ u8 type; // SaveRestoreType_t
+ u8 emode; // EncodeMode_t
+}
+__attribute__ ((packed)) SaveRestoreTab_t;
+
+//-----------------------------------------------------------------------------
+
+// At the very beginning of the table, define 'SRT_NAME' by 2 lines:
+// #undef SRT_NAME
+// #define SRT_NAME name_of_the_struct
+
+#define DEF_SRT_VAR(v,ne,n,t,e) {offsetof(SRT_NAME,v),sizeof(((SRT_NAME*)0)->v),n,ne,t,e}
+
+#define DEF_SRT_BOOL(v,n) DEF_SRT_VAR(v,1,n,SRT_BOOL,0)
+#define DEF_SRT_UINT(v,n) DEF_SRT_VAR(v,1,n,SRT_UINT,0)
+#define DEF_SRT_HEX(v,n) DEF_SRT_VAR(v,1,n,SRT_HEX,0)
+#define DEF_SRT_INT(v,n) DEF_SRT_VAR(v,1,n,SRT_INT,0)
+#define DEF_SRT_FLOAT(v,n) DEF_SRT_VAR(v,1,n,SRT_FLOAT,0)
+#define DEF_SRT_XFLOAT(v,n) DEF_SRT_VAR(v,1,n,SRT_XFLOAT,0)
+
+#define DEF_SRT_STR_SIZE(v,n,e) DEF_SRT_VAR(v,1,n,SRT_STRING_SIZE,e)
+#define DEF_SRT_STR_ALLOC(v,n,e) DEF_SRT_VAR(v,1,n,SRT_STRING_ALLOC,e)
+#define DEF_SRT_MEM(v,n,e) DEF_SRT_VAR(v,1,n,SRT_MEM,e)
+#define DEF_SRT_STRING_FIELD(v,n,e) DEF_SRT_VAR(v,1,n,SRT_STRING_FIELD,e)
+#define DEF_SRT_PARAM_FIELD(v,n,e) DEF_SRT_VAR(v,1,n,SRT_PARAM_FIELD,e)
+
+#define DEF_SRT_BOOL_N(v,ne,n) DEF_SRT_VAR(v,ne,n,SRT_BOOL,0)
+#define DEF_SRT_UINT_N(v,ne,n) DEF_SRT_VAR(v,ne,n,SRT_UINT,0)
+#define DEF_SRT_HEX_N(v,ne,n) DEF_SRT_VAR(v,ne,n,SRT_HEX,0)
+#define DEF_SRT_INT_N(v,ne,n) DEF_SRT_VAR(v,ne,n,SRT_INT,0)
+#define DEF_SRT_FLOAT_N(v,ne,n) DEF_SRT_VAR(v,ne,n,SRT_FLOAT,0)
+#define DEF_SRT_XFLOAT_N(v,ne,n) DEF_SRT_VAR(v,ne,n,SRT_XFLOAT,0)
+
+#define DEF_SRT_ARRAY(v,n,t,e) \
+ {offsetof(SRT_NAME,v), sizeof(((SRT_NAME*)0)->v[0]), n, \
+ sizeof(((SRT_NAME*)0)->v)/sizeof(*((SRT_NAME*)0)->v), t, e }
+
+#define DEF_SRT_BOOL_A(v,n) DEF_SRT_ARRAY(v,n,SRT_BOOL,0)
+#define DEF_SRT_UINT_A(v,n) DEF_SRT_ARRAY(v,n,SRT_UINT,0)
+#define DEF_SRT_HEX_A(v,n) DEF_SRT_ARRAY(v,n,SRT_HEX,0)
+#define DEF_SRT_INT_A(v,n) DEF_SRT_ARRAY(v,n,SRT_INT,0)
+#define DEF_SRT_FLOAT_A(v,n) DEF_SRT_ARRAY(v,n,SRT_FLOAT,0)
+#define DEF_SRT_XFLOAT_A(v,n) DEF_SRT_ARRAY(v,n,SRT_XFLOAT,0)
+
+#define DEF_SRT_SEPARATOR() {0,0,0,0,SRT__IS_LIST,0}
+#define DEF_SRT_COMMENT(c) {0,0,c,0,SRT__IS_LIST,0}
+#define DEF_SRT_TERM() {0,0,0,0,SRT__TERM,0}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void DumpStateTable
+(
+ FILE *f, // valid output file
+ int indent,
+ const SaveRestoreTab_t
+ *srt // list of variables
+);
+
+void SaveCurrentStateByTable
+(
+ FILE *f, // valid output file
+ cvp data0, // valid pointer to source struct
+ const SaveRestoreTab_t
+ *srt, // list of variables
+ ccp prefix, // NULL or prefix for names
+ uint fw_name // field width of name, 0=AUTO
+ // tabs are used for multiple of 8 and for AUTO
+);
+
+void RestoreStateByTable
+(
+ RestoreState_t *rs, // info data, can be modified (cleaned after call)
+ void *data0, // valid pointer to destination struct
+ const SaveRestoreTab_t
+ *srt, // list of variables
+ ccp prefix // NULL or prefix for names
+);
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// GrowBuffer_t ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[GrowBuffer_t]]
+
+typedef struct GrowBuffer_t
+{
+ // allways: gb->ptr[gb->used] == 0
+
+ u8 *buf; // NULL or data buffer
+ uint size; // size of 'buf'
+ uint grow_size; // >0: auto grow buffer by multiple of this
+ uint max_size; // >0: max size for auto grow
+
+ u8 *ptr; // pointer to first valid byte
+ uint used; // number of valid bytes behind 'ptr'
+ uint max_used; // max 'used' value
+
+ uint disabled; // disable rading from TCP socket
+}
+GrowBuffer_t;
+
+///////////////////////////////////////////////////////////////////////////////
+
+void LogGrowBuffer
+(
+ FILE *f, // output file
+ int indent, // indention
+ const GrowBuffer_t *gb, // valid grow-buffer
+ ccp format, // format string for vfprintf()
+ ... // arguments for 'vfprintf(format,...)'
+)
+__attribute__ ((__format__(__printf__,4,5)));
+
+//-----------------------------------------------------------------------------
+
+void InitializeGrowBuffer ( GrowBuffer_t *gb, uint max_buf_size );
+void ResetGrowBuffer ( GrowBuffer_t *gb );
+uint ClearGrowBuffer ( GrowBuffer_t *gb ); // returns available space
+uint PurgeGrowBuffer ( GrowBuffer_t *gb ); // returns available space
+
+//-----------------------------------------------------------------------------
+
+uint GetSpaceGrowBuffer
+(
+ // returns the maximum possible space
+ const GrowBuffer_t *gb // valid grow-buffer object
+);
+
+//-----------------------------------------------------------------------------
+
+uint PrepareGrowBuffer
+(
+ // returns the number of available space, smaller than or equal 'size'
+
+ GrowBuffer_t *gb, // valid grow-buffer object
+ uint size, // needed size
+ bool force // always alloc enough space and return 'size'
+);
+
+uint InsertGrowBuffer
+(
+ // returns the number of inserted bytes
+
+ GrowBuffer_t *gb, // valid grow-buffer object
+ const void *data, // data to insert
+ uint size // size of 'data'
+);
+
+static inline uint InsertCharGrowBuffer
+(
+ // returns the number of inserted bytes (0 on fail, 1 else)
+
+ GrowBuffer_t *gb, // valid grow-buffer object
+ char ch // any character including NULL
+)
+{
+ return InsertGrowBuffer(gb,&ch,1);
+}
+
+static inline uint InsertMemGrowBuffer
+(
+ // returns the number of inserted bytes
+
+ GrowBuffer_t *gb, // valid grow-buffer object
+ mem_t mem // any data
+)
+{
+ return InsertGrowBuffer(gb,mem.ptr,mem.len);
+}
+
+uint InsertCapNGrowBuffer
+(
+ // insert 'cap_1' or 'cap_n' depending of 'n' and the existence of 'cap_*'
+ // returns the number of inserted bytes
+
+ GrowBuffer_t *gb, // valid grow-buffer object
+ int n, // repeat number; if <1: insert nothing
+ mem_t cap_1, // default for N=1
+ mem_t cap_n // default for N>1
+);
+
+uint WriteCapN
+(
+ // print 'cap_1' or 'cap_n' depending of 'n' and the existence of 'cap_*'
+ // returns the number of printed bytes
+
+ FILE *f, // valid FILE
+ int n, // repeat number; if <1: insert nothing
+ mem_t cap_1, // default for N=1
+ mem_t cap_n // default for N>1
+);
+
+uint InsertCatchedGrowBuffer
+(
+ // returns the number of inserted bytes
+
+ GrowBuffer_t *gb, // valid grow-buffer object
+ SavedStdFiles_t *ssf // saved output and catched data
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+uint PrintArgGrowBuffer
+(
+ // returns the number of inserted bytes
+
+ GrowBuffer_t *gb, // valid grow-buffer object
+ ccp format, // format string for vfprintf()
+ va_list arg // arguments for 'vsnprintf(format,...)'
+);
+
+uint PrintGrowBuffer
+(
+ // returns the number of inserted bytes
+
+ GrowBuffer_t *gb, // valid grow-buffer object
+ ccp format, // format string for vfprintf()
+ ... // arguments for 'vsnprintf(format,...)'
+)
+__attribute__ ((__format__(__printf__,2,3)));
+
+//-----------------------------------------------------------------------------
+
+uint ConvertToCrLfGrowBuffer
+(
+ // returns the number of inserted CR bytes
+
+ GrowBuffer_t *gb, // valid grow-buffer object
+ uint begin // index to begin with conversion
+);
+
+//-----------------------------------------------------------------------------
+
+uint DropGrowBuffer
+(
+ // returns the number of dropped bytes
+
+ GrowBuffer_t *gb, // valid grow-buffer object
+ uint size // number of bytes to drop
+);
+
+//-----------------------------------------------------------------------------
+#ifndef __APPLE__
+
+FILE * OpenFileGrowBuffer
+(
+ // returns a FILE opened by fmemopen() => call CloseFileGrowBuffer()
+
+ GrowBuffer_t *gb, // valid grow-buffer object
+ uint size // needed size
+);
+
+int CloseFileGrowBuffer
+(
+ // returns the number of wirtten bytes, or -1 on error
+ GrowBuffer_t *gb, // valid grow-buffer object
+ FILE *f // FILE returned by OpenFileGrowBuffer()
+);
+
+#endif // !__APPLE__
+//-----------------------------------------------------------------------------
+
+void SaveCurrentStateGrowBuffer
+(
+ FILE *f, // output file
+ ccp name_prefix, // NULL or prefix of name
+ uint tab_pos, // tab pos of '='
+ const GrowBuffer_t *gb // valid grow-buffer
+);
+
+void RestoreStateGrowBuffer
+(
+ GrowBuffer_t *gb, // valid grow-buffer
+ ccp name_prefix, // NULL or prefix of name
+ RestoreState_t *rs // info data, can be modified (cleaned after call)
+);
+
+//-----------------------------------------------------------------------------
+
+int WriteDirectGrowBuffer
+(
+ // write() data direct without blocking and without calling any notifier.
+ // If output buf is not empty or send failed, append the data to 'gb'.
+ // Returns the number of bytes added to the grow buffer or -1 on error.
+ // The data is send+stored completely (returns 'size') or not at all
+ // (returns '0'). -1 is returned if the socket is invalid.
+
+ GrowBuffer_t *gb, // grow buffer to cache data
+ int fd, // destination file
+ bool flush_output, // true: try to flush 'gb' before
+ cvp data, // data to send
+ uint size, // size of 'data', If NULL && flush: flush only
+ uint *send_count // not NULL: add num of sent bytes
+);
+
+//-----------------------------------------------------------------------------
+
+int SendDirectGrowBuffer
+(
+ // send() data direct without blocking and without calling any notifier.
+ // If output buf is not empty or send failed, append the data to 'gb'.
+ // Returns the number of bytes added to the grow buffer or -1 on error.
+ // The data is send+stored completely (returns 'size') or not at all
+ // (returns '0'). -1 is returned if the socket is invalid.
+
+ GrowBuffer_t *gb, // grow buffer to cache data
+ int sock, // destination socket
+ bool flush_output, // true: try to flush 'gb' before
+ cvp data, // data to send
+ uint size, // size of 'data', If NULL && flush: flush only
+ uint *send_count // not NULL: add num of sent bytes
+);
+
+//-----------------------------------------------------------------------------
+
+static inline int FlushGrowBuffer
+(
+ // Try to flush the bufer using SendDirectGrowBuffer() withour new data.
+
+ GrowBuffer_t *gb, // grow buffer to cache data
+ int sock, // destination socket
+ uint *send_count // not NULL: add num of sent bytes
+)
+{
+ return SendDirectGrowBuffer(gb,sock,true,0,0,send_count);
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// misc ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+#define CONVERT_TO_STRING1(a) #a
+#define CONVERT_TO_STRING(a) CONVERT_TO_STRING1(a)
+
+extern int opt_new; // default 0
+
+float double2float ( double d ); // reduce precision
+
+uint CreateUniqueId ( int range );
+
+void Sha1Hex2Bin ( sha1_hash_t bin, ccp src, ccp end );
+void Sha1Bin2Hex ( sha1_hex_t hex, cvp bin );
+ccp GetSha1Hex ( cvp bin );
+
+///////////////////////////////////////////////////////////////////////////////
+
+static uint snprintfS ( char *buf, size_t size, ccp format, ... )
+ __attribute__ ((__format__(__printf__,3,4)));
+
+static inline uint snprintfS ( char *buf, size_t size, ccp format, ... )
+{
+ va_list arg;
+ va_start(arg,format);
+ const int res = vsnprintf(buf,size,format,arg);
+ va_end(arg);
+
+ return res < 0 ? 0 : res < size ? res : size - 1;
+}
+
+static char * snprintfE ( char *buf, char *end, ccp format, ... )
+ __attribute__ ((__format__(__printf__,3,4)));
+
+static inline char * snprintfE ( char *buf, char *end, ccp format, ... )
+{
+ const int size = end - buf;
+ DASSERT( size > 0 );
+
+ va_list arg;
+ va_start(arg,format);
+ const int res = vsnprintf(buf,size,format,arg);
+ va_end(arg);
+
+ return buf + ( res < 0 ? 0 : res < size ? res : size - 1 );
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// E N D ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+#endif // DCLIB_BASICS_H