aboutsummaryrefslogtreecommitdiff
path: root/project/dclib
diff options
context:
space:
mode:
authorWiimm <wiimm@wiimm.de>2022-07-09 11:48:24 +0200
committerWiimm <wiimm@wiimm.de>2022-07-09 11:48:24 +0200
commit06ff18cd020779c226f7c25d22016e06b898f303 (patch)
treeb5c12ca4c6b9b0c86e63d2b6a965b8bd74dd0d86 /project/dclib
parentf30e94a61fdc9fb13fd1fbd8b75502fedf5a2f71 (diff)
SZS v2.28a.beta
Diffstat (limited to 'project/dclib')
-rw-r--r--project/dclib/Makefile.inc2
-rw-r--r--project/dclib/dclib-basics.c753
-rw-r--r--project/dclib/dclib-basics.h319
-rw-r--r--project/dclib/dclib-debug.c225
-rw-r--r--project/dclib/dclib-debug.h68
-rw-r--r--project/dclib/dclib-file.c473
-rw-r--r--project/dclib/dclib-file.h68
-rw-r--r--project/dclib/dclib-network.c8
-rw-r--r--project/dclib/dclib-numeric.c373
-rw-r--r--project/dclib/dclib-numeric.h5
-rw-r--r--project/dclib/dclib-parser.c150
-rw-r--r--project/dclib/dclib-parser.h89
-rw-r--r--project/dclib/dclib-regex.c1
-rw-r--r--project/dclib/dclib-tables.c10
-rw-r--r--project/dclib/dclib-types.h41
-rw-r--r--project/dclib/dclib-utf8.h2
-rw-r--r--project/dclib/dclib-vector.c4
-rw-r--r--project/dclib/lib-bmg.c134
-rw-r--r--project/dclib/lib-bmg.h23
-rw-r--r--project/dclib/lib-mkw-def.c2
-rw-r--r--project/dclib/lib-mkw-def.h9
-rw-r--r--project/dclib/lib-mkw.h19
22 files changed, 2576 insertions, 202 deletions
diff --git a/project/dclib/Makefile.inc b/project/dclib/Makefile.inc
index 45fc2a5..b505f2e 100644
--- a/project/dclib/Makefile.inc
+++ b/project/dclib/Makefile.inc
@@ -18,7 +18,7 @@
# standard object files
DCLIB_O := dclib-basics.o dclib-cli.o dclib-color.o dclib-numeric.o \
- dclib-file.o dclib-option.o dclib-regex.o \
+ dclib-parser.o dclib-file.o dclib-option.o dclib-regex.o \
dclib-utf8.o dclib-shift-jis.o \
dclib-vector.o dclib-tables.o dclib-ui.o \
dclib-xdump.o dclib-debug.o
diff --git a/project/dclib/dclib-basics.c b/project/dclib/dclib-basics.c
index 964b5d2..03e3215 100644
--- a/project/dclib/dclib-basics.c
+++ b/project/dclib/dclib-basics.c
@@ -418,11 +418,13 @@ char * StringCopyE ( char * buf, ccp buf_end, ccp src )
DASSERT(buf);
DASSERT(buf<buf_end);
- buf_end--;
if (src)
+ {
+ buf_end--;
while( buf < buf_end && *src )
*buf++ = *src++;
+ }
*buf = 0;
return buf;
@@ -432,12 +434,22 @@ char * StringCopyE ( char * buf, ccp buf_end, ccp src )
char * StringCopyS ( char * buf, size_t buf_size, ccp src )
{
- return StringCopyE(buf,buf+buf_size,src);
+ DASSERT(buf);
+ if ( buf_size <= 0 )
+ return buf;
+
+ DASSERT(buf_size>=0);
+
+ if (src)
+ while( --buf_size > 0 && *src )
+ *buf++ = *src++;
+ *buf = 0;
+ return buf;
}
///////////////////////////////////////////////////////////////////////////////
-char * StringCopyEM ( char * buf, ccp buf_end, ccp src, size_t max_copy )
+char * StringCopyEM ( char * buf, ccp buf_end, ccp src, ssize_t max_copy )
{
// RESULT: end of copied string pointing to NULL
// 'src' may be a NULL pointer.
@@ -458,7 +470,7 @@ char * StringCopyEM ( char * buf, ccp buf_end, ccp src, size_t max_copy )
//-----------------------------------------------------------------------------
-char * StringCopySM ( char * buf, size_t buf_size, ccp src, size_t max_copy )
+char * StringCopySM ( char * buf, size_t buf_size, ccp src, ssize_t max_copy )
{
return StringCopyEM(buf,buf+buf_size,src,max_copy);
}
@@ -495,6 +507,47 @@ char * StringCat2S ( char * buf, size_t buf_size, ccp src1, ccp src2 )
///////////////////////////////////////////////////////////////////////////////
+char * StringCatSep2E ( char * buf, ccp buf_end, ccp sep, ccp src1, ccp src2 )
+{
+ // RESULT: end of copied string pointing to NULL
+ // 'src*' may be a NULL pointer.
+
+ DASSERT(buf);
+ DASSERT(buf<buf_end);
+
+ if ( !sep || !*sep )
+ return StringCat2E(buf,buf_end,src1,src2);
+
+ char *buf0 = buf;
+ buf_end--;
+
+ if (src1)
+ while( buf < buf_end && *src1 )
+ *buf++ = *src1++;
+
+ if (src2)
+ {
+ if ( buf > buf0 )
+ while ( buf < buf_end && *sep )
+ *buf++ = *sep++;
+
+ while( buf < buf_end && *src2 )
+ *buf++ = *src2++;
+ }
+
+ *buf = 0;
+ return buf;
+}
+
+//-----------------------------------------------------------------------------
+
+char * StringCatSep2S ( char * buf, size_t buf_size, ccp sep, ccp src1, ccp src2 )
+{
+ return StringCatSep2E(buf,buf+buf_size,sep,src1,src2);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
char * StringCat3E ( char * buf, ccp buf_end, ccp src1, ccp src2, ccp src3 )
{
// RESULT: end of copied string pointing to NULL
@@ -529,6 +582,62 @@ char * StringCat3S ( char * buf, size_t buf_size, ccp src1, ccp src2, ccp src3 )
///////////////////////////////////////////////////////////////////////////////
+char * StringCatSep3E
+ ( char * buf, ccp buf_end, ccp sep, ccp src1, ccp src2, ccp src3 )
+{
+ // RESULT: end of copied string pointing to NULL
+ // 'src*' may be a NULL pointer.
+
+ DASSERT(buf);
+ DASSERT(buf<buf_end);
+
+ if ( !sep || !*sep )
+ return StringCat3E(buf,buf_end,src1,src2,src3);
+
+ buf_end--;
+ char *buf0 = buf;
+
+ if (src1)
+ while( buf < buf_end && *src1 )
+ *buf++ = *src1++;
+
+ if (src2)
+ {
+ if ( buf > buf0 )
+ {
+ ccp ptr = sep;
+ while ( buf < buf_end && *ptr )
+ *buf++ = *ptr++;
+ }
+
+ while( buf < buf_end && *src2 )
+ *buf++ = *src2++;
+ }
+
+ if (src3)
+ {
+ if ( buf > buf0 )
+ while ( buf < buf_end && *sep )
+ *buf++ = *sep++;
+
+ while( buf < buf_end && *src3 )
+ *buf++ = *src3++;
+ }
+
+ *buf = 0;
+ return buf;
+}
+
+//-----------------------------------------------------------------------------
+
+char * StringCatSep3S
+ ( char * buf, size_t buf_size, ccp sep, ccp src1, ccp src2, ccp src3 )
+{
+ return StringCatSep3E(buf,buf+buf_size,sep,src1,src2,src3);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
char * StringCat2A ( ccp src1, ccp src2 )
{
mem_t mem = MemCat2A( MemByString0(src1), MemByString0(src2) );
@@ -545,6 +654,27 @@ char * StringCat3A ( ccp src1, ccp src2, ccp src3 )
///////////////////////////////////////////////////////////////////////////////
+char * StringCatSep2A ( ccp sep, ccp src1, ccp src2 )
+{
+ mem_t mem = MemCatSep2A( MemByString0(sep),
+ MemByString0(src1),
+ MemByString0(src2) );
+ return (char*)mem.ptr;
+}
+
+//-----------------------------------------------------------------------------
+
+char * StringCatSep3A ( ccp sep, ccp src1, ccp src2, ccp src3 )
+{
+ mem_t mem = MemCatSep3A( MemByString0(sep),
+ MemByString0(src1),
+ MemByString0(src2),
+ MemByString0(src3) );
+ return (char*)mem.ptr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
ccp StringCenterE
(
char * buf, // result buffer; if NULL, circ-buf is used
@@ -583,7 +713,7 @@ ccp StringCenterE
while ( *src && dest < buf_end )
*dest++ = *src++;
-
+
while ( n2-- > 0 && dest < buf_end )
*dest++ = ' ';
@@ -1853,6 +1983,7 @@ char * PrintID
///////////////////////////////////////////////////////////////////////////////
/////////////// circ buf ///////////////
///////////////////////////////////////////////////////////////////////////////
+// [[CircBuf]]
static __thread char circ_buf[CIRC_BUF_SIZE];
static __thread char *circ_ptr = 0;
@@ -2924,7 +3055,7 @@ static char ** insert_arg_manager
if ( am->force_case == LOUP_LOWER || am->force_case == LOUP_UPPER )
{
- ccp end = arg + strlen(arg) + 1;
+ char * end = arg + strlen(arg) + 1;
if (am->force_case == LOUP_LOWER)
StringLowerE(arg,end,arg);
else
@@ -2940,6 +3071,7 @@ static char ** insert_arg_manager
uint InsertArgManager
( ArgManager_t *am, int pos, ccp arg1, ccp arg2, bool move_arg )
{
+ DASSERT(am);
PRINT("InsertArgManager(,%d,%s,%s,%d)\n",pos,arg1,arg2,move_arg);
pos = CheckIndex1(am->argc,pos);
@@ -2961,6 +3093,34 @@ uint InsertArgManager
return pos+n;
}
+//-----------------------------------------------------------------------------
+
+uint InsertListArgManager
+ ( ArgManager_t *am, int pos, int argc, char ** argv, bool move_arg )
+{
+ DASSERT(am);
+
+ pos = CheckIndex1(am->argc,pos);
+ if ( argc > 0 )
+ {
+ PrepareEditArgManager(am,argc);
+ DASSERT( pos>=0 && pos <= am->argc );
+ char **dest = am->argv + pos;
+ if ( pos < am->argc )
+ memmove( dest+argc, dest, (u8*)(am->argv+am->argc) - (u8*)dest );
+ pos += argc;
+ am->argc += argc;
+ am->argv[am->argc] = 0;
+
+ if ( move_arg && am->force_case == LOUP_AUTO )
+ memcpy( dest, argv, argc*sizeof(*dest) );
+ else
+ while ( argc-- > 0 )
+ dest = insert_arg_manager(am,dest,*argv++,move_arg);
+ }
+ return pos;
+}
+
///////////////////////////////////////////////////////////////////////////////
uint ReplaceArgManager
@@ -3063,7 +3223,7 @@ uint ScanQuotedArgManager ( ArgManager_t *am, ccp src, bool is_utf8 )
for(;;)
{
- while ( *src == ' ' || *src == '\t' )
+ while (isspace(*src))
src++;
if (!*src)
break;
@@ -3079,15 +3239,14 @@ uint ScanQuotedArgManager ( ArgManager_t *am, ccp src, bool is_utf8 )
}
else
{
- while ( dest < bufend && *src && *src != ' ' && *src != '\t'
- && *src != '\'' && *src != '\"' )
+ while ( dest < bufend && !isspace(*src) && *src != '\'' && *src != '\"' )
{
if ( *src == '\\' && src[1] )
src++;
*dest++ = *src++;
}
}
- if ( !*src || *src == ' ' || *src == '\t' )
+ if (isspace(*src))
break;
}
ccp arg = MEMDUP(buf,dest-buf);
@@ -3099,6 +3258,155 @@ uint ScanQuotedArgManager ( ArgManager_t *am, ccp src, bool is_utf8 )
///////////////////////////////////////////////////////////////////////////////
+enumError ScanFileArgManager
+(
+ ArgManager_t *am, // valid arg-manager
+ int pos, // insert position, relative to end if <0
+ ccp fname, // filename to open
+ int silent, // 0: print all error messages
+ // 1: suppress file size warning
+ // 2: suppress all error messages
+ int *n_added
+)
+{
+ if (n_added)
+ *n_added = 0;
+ pos = CheckIndex1(am->argc,pos);
+
+ u8 *data;
+ size_t size;
+ enumError err = LoadFileAlloc(fname,0,0,&data,&size,0,silent,0,0);
+
+ if (!err)
+ {
+ if (memchr(data,0,size))
+ {
+ if ( silent < 2 )
+ ERROR0(ERR_WARNING,"Binary file ignored: %s\n",fname);
+ err = ERR_WARNING;
+ }
+ else
+ {
+ ArgManager_t temp = { .force_case = am->force_case };
+ ScanQuotedArgManager(&temp,(ccp)data,true);
+ uint newpos = InsertListArgManager(am,pos,temp.argc,temp.argv,true);
+ if (n_added)
+ *n_added = newpos - pos;
+ FREE(temp.argv);
+ }
+ }
+
+ FREE(data);
+ return err;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+enumError ExpandAtArgManager
+(
+ ArgManager_t *am, // valid arg-manager
+ arg_expand_mode_t expand_mode, // objects to be replaced
+ int recursion, // maximum recursion depth
+ int silent // 0: print all error messages
+ // 1: suppress file size warning
+ // 2: suppress all error messages
+)
+{
+ if (!am)
+ return ERR_MISSING_PARAM;
+
+ expand_mode &= AMXM_ALL;
+ if (!expand_mode)
+ return ERR_OK;
+
+ enumError max_err = ERR_OK;
+
+ for ( int try = 0;; try++ )
+ {
+ bool dirty = false;
+
+ int pos = 0;
+ while ( pos < am->argc )
+ {
+ ccp arg = am->argv[pos];
+ if (arg)
+ {
+ int n_rm = 0;
+ ccp fname = 0;
+ int len = strlen(arg);
+
+ if ( len >= 1 && *arg == '@' )
+ {
+ if ( len > 1 && expand_mode & AMXM_P1 )
+ {
+ n_rm = 1;
+ fname = arg+1;
+ }
+ else if ( len == 1 && expand_mode & AMXM_P2 && pos+1 < am->argc )
+ {
+ n_rm = 2;
+ fname = am->argv[pos+1];
+ }
+ }
+ else if ( len >= 2 && !memcmp(arg,"-@",2) )
+ {
+ if ( len > 2 && expand_mode & AMXM_S1 )
+ {
+ n_rm = 1;
+ fname = arg+2;
+ }
+ else if ( len == 2 && expand_mode & AMXM_S2 && pos+1 < am->argc )
+ {
+ n_rm = 2;
+ fname = am->argv[pos+1];
+ }
+ }
+ else if ( len >= 3 && !memcmp(arg,"--@",3) )
+ {
+ if ( len > 3 && arg[3] == '=' && expand_mode & AMXM_L1 )
+ {
+ n_rm = 1;
+ fname = arg+4;
+ }
+ else if ( len == 3 && expand_mode & AMXM_L2 && pos+1 < am->argc )
+ {
+ n_rm = 2;
+ fname = am->argv[pos+1];
+ }
+ }
+
+ if (n_rm)
+ {
+ PRINT1("rm @%u %d, file=%s\n",pos,n_rm,fname);
+ int n_added;
+ enumError err = ScanFileArgManager(am,pos,fname,silent,&n_added);
+ if ( max_err < err )
+ max_err = err;
+ if (n_added)
+ {
+ pos += n_added;
+ dirty = true;
+ }
+
+ // remove after insert to keep fname valid!
+ PRINT1("rm @%u %d\n",pos,n_rm);
+ RemoveArgManager(am,pos,n_rm);
+ }
+ else
+ pos++;
+
+ } // if (arg)
+ } // while
+
+ if ( !dirty || try >= recursion )
+ break;
+ }
+
+ return max_err;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
bool CheckFilterArgManager ( const ArgManager_t *filter, ccp name )
{
if ( !name || !*name )
@@ -3325,6 +3633,100 @@ mem_t MemCat3A ( const mem_t m1, const mem_t m2, const mem_t m3 )
}
///////////////////////////////////////////////////////////////////////////////
+
+mem_t MemCatSep2A ( const mem_t sep, const mem_t m1, const mem_t m2 )
+{
+ const uint slen = sep.len >= 0 ? sep.len : strlen(sep.ptr);
+ if (!slen)
+ return MemCat2A(m1,m2);
+
+ const uint len1 = m1.len >= 0 ? m1.len : strlen(m1.ptr);
+ const uint len2 = m2.len >= 0 ? m2.len : strlen(m2.ptr);
+
+ char *dest;
+ mem_t res;
+ res.len = len1 + len2;
+ if ( len1 && len2 )
+ res.len += slen;
+
+ res.ptr = dest = MALLOC(res.len+1);
+ dest[res.len] = 0;
+
+ if (len1)
+ {
+ memcpy(dest,m1.ptr,len1);
+ dest += len1;
+ }
+
+ if (len2)
+ {
+ if (len1)
+ {
+ memcpy(dest,sep.ptr,slen);
+ dest += slen;
+ }
+
+ memcpy(dest,m2.ptr,len2);
+ }
+
+ return res;
+}
+
+//-----------------------------------------------------------------------------
+
+mem_t MemCatSep3A ( const mem_t sep, const mem_t m1, const mem_t m2, const mem_t m3 )
+{
+ const uint slen = sep.len >= 0 ? sep.len : strlen(sep.ptr);
+ if (!slen)
+ return MemCat3A(m1,m2,m3);
+
+ const uint len1 = m1.len >= 0 ? m1.len : strlen(m1.ptr);
+ const uint len2 = m2.len >= 0 ? m2.len : strlen(m2.ptr);
+ const uint len3 = m3.len >= 0 ? m3.len : strlen(m3.ptr);
+
+ char *dest;
+ mem_t res;
+ res.len = len1 + len2 + len3
+ + ( (len1>0) + (len2>0) + (len3>0) - 1 ) * slen;
+
+ res.ptr = dest = MALLOC(res.len+1);
+
+ if (len1)
+ {
+ memcpy(dest,m1.ptr,len1);
+ dest += len1;
+ }
+
+ if (len2)
+ {
+ if ( dest > res.ptr )
+ {
+ memcpy(dest,sep.ptr,slen);
+ dest += slen;
+ }
+
+ memcpy(dest,m2.ptr,len2);
+ dest += len2;
+ }
+
+ if (len3)
+ {
+ if ( dest > res.ptr )
+ {
+ memcpy(dest,sep.ptr,slen);
+ dest += slen;
+ }
+
+ memcpy(dest,m3.ptr,len3);
+ dest += len3;
+ }
+
+ *dest = 0;
+ ASSERT( dest == res.ptr + res.len );
+ return res;
+}
+
+///////////////////////////////////////////////////////////////////////////////
// UTF8 support
mem_t MidMem8 ( const mem_t src, int begin, int count )
@@ -3607,6 +4009,155 @@ ccp PrintExMem ( const exmem_t * em ) // print to circ-buf
//
///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+uint GetMemSrcN ( const mem_src_t *src )
+{
+ if (!src)
+ return 0;
+
+ if ( src->n_src >= 0 )
+ return src->n_src;
+
+ const mem_t *ptr = src->src;
+ while ( ptr->ptr )
+ ptr++;
+ const uint n_src = ptr - src->src;
+
+ if ( src->allow_write )
+ *(uint*)&src->n_src = n_src;
+ return n_src;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+uint GetMemSrcLen ( mem_t sep, const mem_src_t *src )
+{
+ if ( !src || src->n_src <= 0 )
+ return 0;
+
+ int n_valid_src = 0, sum_len = 0;
+ int n_src = GetMemSrcN(src);
+ for ( const mem_t *ptr = src->src; n_src > 0; ptr++, n_src-- )
+ {
+ int slen = ptr->len;
+ if ( slen < 0 )
+ {
+ slen = ptr->ptr ? strlen(ptr->ptr) : 0;
+ if (src->allow_write)
+ *(int*)&ptr->len = slen;
+ }
+ if ( slen > 0 )
+ {
+ n_valid_src++;
+ sum_len += slen;
+ }
+ }
+
+ if ( n_valid_src > 1 )
+ sum_len += (n_valid_src-1)*sep.len;
+ return sum_len;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+exmem_t GetExmemDestBuf ( const exmem_dest_t * dest, uint len )
+{
+ exmem_t res = { .data.len = len };
+ len++; // for additional 0-term
+
+ if (!dest)
+ goto malloc;
+ else if ( dest->buf && len <= dest->buf_size )
+ {
+ res.data.ptr = dest->buf;
+ }
+ else if ( dest->try_circ && len <= CIRC_BUF_MAX_ALLOC )
+ {
+ res.is_circ_buf = true;
+ res.data.ptr = GetCircBuf(len);
+ }
+ else
+ {
+ malloc:;
+ res.is_alloced = true;
+ res.data.ptr = MALLOC(len);
+ }
+
+ return res;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+exmem_t ExMemCat
+(
+ exmem_dest_t *dest, // kind of destination, if NULL then MALLOC()
+ mem_t sep, // insert separators between sources with len>0
+ const mem_src_t *src // sources. NULL allowed
+)
+{
+ const uint total_size = GetMemSrcLen(sep,src);
+ exmem_t res = GetExmemDestBuf(dest,total_size);
+ char *bufdest = (char*)res.data.ptr;
+
+ int n_src = GetMemSrcN(src);
+ for ( const mem_t *ptr = src->src; n_src > 0; ptr++, n_src-- )
+ {
+ int slen = ptr->len;
+ if ( slen < 0 )
+ slen = ptr->ptr ? strlen(ptr->ptr) : 0;
+ if ( slen > 0 )
+ {
+ if ( sep.len && bufdest > res.data.ptr )
+ {
+ memcpy(bufdest,sep.ptr,sep.len);
+ bufdest += sep.len;
+ }
+
+ memcpy(bufdest,ptr->ptr,slen);
+ bufdest += slen;
+ ASSERT( bufdest <= res.data.ptr + res.data.len );
+ }
+ }
+ ASSERT( bufdest == res.data.ptr + res.data.len );
+ *bufdest = 0;
+ return res;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+exmem_t ExMemCat2
+(
+ exmem_dest_t *dest, // kind of destination, if NULL then MALLOC()
+ mem_t sep, // insert separators between sources with len>0
+ mem_t src1, // first source
+ mem_t src2 // second source
+)
+{
+ mem_t list[] = { src1, src2 };
+ mem_src_t src = { .src = list, .n_src = 2, true };
+ return ExMemCat(dest,sep,&src);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+exmem_t ExMemCat3
+(
+ exmem_dest_t *dest, // kind of destination, if NULL then MALLOC()
+ mem_t sep, // insert separators between sources with len>0
+ mem_t src1, // first source
+ mem_t src2, // second source
+ mem_t src3 // third source
+)
+{
+ mem_t list[] = { src1, src2, src3 };
+ mem_src_t src = { .src = list, .n_src = 3, true };
+ return ExMemCat(dest,sep,&src);
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
/////////////// struct mem_list_t ///////////////
///////////////////////////////////////////////////////////////////////////////
@@ -4160,7 +4711,6 @@ void * MemDupMemPool ( MemPool_t *mp, cvp source, uint size )
///////////////////////////////////////////////////////////////////////////////
/////////////// CircBuf_t ///////////////
///////////////////////////////////////////////////////////////////////////////
-// [[CircBuf_t]]
void InitializeCircBuf ( CircBuf_t *cb, uint size )
{
@@ -4337,6 +4887,8 @@ void * CopyData
)
{
DASSERT( data || !size );
+ DASSERT( mode == CPM_COPY || mode == CPM_MOVE || mode == CPM_LINK );
+
if ( !data || !size )
{
if (res_alloced)
@@ -4347,21 +4899,33 @@ void * CopyData
if (res_alloced)
*res_alloced = mode != CPM_LINK;
- return mode == CPM_MOVE || mode == CPM_LINK
- ? (void*)data
- : MEMDUP(data,size);
+ return mode == CPM_COPY ? MEMDUP(data,size) : (void*)data;
}
///////////////////////////////////////////////////////////////////////////////
-void FreeData
+char * CopyString
(
- const void *data, // data to free
- CopyMode_t mode // copy mode
+ ccp string, // string to copy/move/link
+ CopyMode_t mode, // copy mode
+ bool *res_alloced // not NULL:
+ // store true, if data must be freed
+ // otherwise store false
)
{
- if ( mode != CPM_LINK && data != EmptyString )
- FREE((void*)data);
+ DASSERT( mode == CPM_COPY || mode == CPM_MOVE || mode == CPM_LINK );
+
+ if ( !string || !*string )
+ {
+ if (res_alloced)
+ *res_alloced = false;
+ return string ? (char*)EmptyString : 0;
+ }
+
+ if (res_alloced)
+ *res_alloced = mode != CPM_LINK;
+
+ return mode == CPM_COPY ? STRDUP(string) : (char*)string;
}
//
@@ -5024,6 +5588,35 @@ uint SplitByTextMemList
/////////////// MatchPattern() ///////////////
///////////////////////////////////////////////////////////////////////////////
+bool HaveWildcards ( mem_t str )
+{
+ if (!str.ptr)
+ return false;
+ if ( str.len < 0 )
+ str.len = strlen(str.ptr);
+
+ for ( ccp w = PATTERN_WILDCARDS; *w; w++ )
+ if (memchr(str.ptr,*w,str.len))
+ return true;
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+char * FindFirstWildcard ( mem_t str )
+{
+ if (!str.len)
+ return 0;
+
+ ccp end = str.ptr + str.len;
+ for ( ccp ptr = str.ptr; ptr < end; ptr++ )
+ if (strchr(PATTERN_WILDCARDS,*ptr))
+ return (char*)ptr;
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
static ccp AnalyseBrackets
(
ccp pattern,
@@ -5154,7 +5747,7 @@ static bool MatchPatternHelper
return true;
return false;
- case ' ':
+ case '\t':
if ( *text < 1 || * text > ' ' )
return false;
text++;
@@ -5388,8 +5981,8 @@ 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)
+ // -2: no prefix found (no rule found)
+ // -1: empty line (no rule found)
// 0: rule found, but don't match
// 1: rule found and match
ccp src, // source line, scanned until CONTROL
@@ -5816,6 +6409,73 @@ uint CollectAmbiguousKeywords
///////////////////////////////////////////////////////////////////////////////
+ccp GetKeywordError
+(
+ const KeywordTab_t * key_tab, // NULL or pointer to command table
+ ccp key_arg, // analyzed command
+ int key_stat, // status of ScanKeyword()
+ ccp object // NULL or object for error messages
+ // default= 'command'
+)
+{
+ DASSERT(key_arg);
+
+ if ( !object || !*object )
+ object = "command";
+
+ if ( key_stat <= 0 )
+ return PrintCircBuf("Unknown %s: %s",object,key_arg);
+
+ char buf[1000], *dest = buf;
+ if (key_tab)
+ {
+ int n = 0;
+ char *buf_end = buf + sizeof(buf) - 2;
+ const int arg_len = strlen(key_arg);
+ const KeywordTab_t *ct;
+ int last_id = -1;
+
+ for ( ct = key_tab; ct->name1 && dest < buf_end; ct++ )
+ {
+ if ( ct->id != last_id )
+ {
+ ccp ok = 0;
+ if (!strncasecmp(key_arg,ct->name1,arg_len))
+ ok = ct->name1;
+ else if ( ct->name2 && !strncasecmp(key_arg,ct->name2,arg_len))
+ ok = ct->name2;
+ if (ok)
+ {
+ if (!n++)
+ {
+ *dest++ = ' ';
+ *dest++ = '[';
+ }
+ else if ( n > 5 )
+ {
+ dest = StringCopyE(dest,buf_end,",...");
+ break;
+ }
+ else
+ *dest++ = ',';
+ dest = StringCopyE(dest,buf_end,ok);
+ last_id = ct->id;
+ }
+ }
+ }
+ if ( dest > buf+1 )
+ *dest++ = ']';
+ else
+ dest = buf;
+ }
+ *dest = 0;
+
+ return PrintCircBuf("%c%s abbreviation is ambiguous: %s%s",
+ toupper((int)*object), object+1, key_arg, buf );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
enumError PrintKeywordError
(
const KeywordTab_t * key_tab, // NULL or pointer to command table
@@ -5839,7 +6499,7 @@ enumError PrintKeywordError
if (key_tab)
{
int n = 0;
- ccp buf_end = buf + sizeof(buf) - 2;
+ char *buf_end = buf + sizeof(buf) - 2;
const int arg_len = strlen(key_arg);
const KeywordTab_t *ct;
int last_id = -1;
@@ -6680,7 +7340,7 @@ void AppendUniqueStringField ( StringField_t * sf, ccp key, bool move_key )
return;
ccp * src = sf->field;
- ccp * end = sf->field + sf->used;
+ ccp * end = src + sf->used;
while ( src < end )
if (!strcmp(*src++,key))
{
@@ -7237,6 +7897,51 @@ uint FindParamFieldHelper ( const ParamField_t * pf, bool * p_found, ccp key )
return beg;
}
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+ccp GetParamFieldStr ( ParamField_t *pf, uint mark, ccp key, ccp def )
+{
+ DASSERT(pf);
+ DASSERT(key);
+
+ ParamFieldItem_t *it = FindParamField(pf,key);
+ if ( it && it->data )
+ {
+ it->num |= mark;
+ return (ccp)it->data;
+ }
+ return def;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+int GetParamFieldInt ( ParamField_t *pf, uint mark, ccp key, int def )
+{
+ DASSERT(pf);
+ DASSERT(key);
+
+ ParamFieldItem_t *it = FindParamField(pf,key);
+ if ( it && it->data )
+ {
+ it->num |= mark;
+ char *end;
+ const int num = str2l((ccp)it->data,&end,10);
+ if (!*end)
+ return num;
+ }
+ return def;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+int GetParamFieldIntMM
+ ( ParamField_t *pf, uint mark, ccp key, int def, int min, int max )
+{
+ const int num = GetParamFieldInt(pf,mark,key,def);
+ return num >= min && num <= max ? num : def;
+}
+
//
///////////////////////////////////////////////////////////////////////////////
/////////////// exmem_list_t ///////////////
diff --git a/project/dclib/dclib-basics.h b/project/dclib/dclib-basics.h
index 47827c7..01e53a7 100644
--- a/project/dclib/dclib-basics.h
+++ b/project/dclib/dclib-basics.h
@@ -74,6 +74,9 @@
#define GET_INT_SIGN(type) ({ typeof(type) a=-1; a>0 ? 1 : -1; })
#define GET_INT_TYPE(type) ((int)sizeof(type)*GET_INT_SIGN(type))
+// free a string if str is !NULL | !EmptyString | !MinusString | !IsCircBuf()
+void FreeString ( ccp str );
+
//
///////////////////////////////////////////////////////////////////////////////
/////////////// HAVE_* ///////////////
@@ -671,11 +674,26 @@ void * CopyData
///////////////////////////////////////////////////////////////////////////////
-void FreeData
+char * CopyString
+(
+ ccp string, // string to copy/move/link
+ CopyMode_t mode, // copy mode
+ bool *res_alloced // not NULL:
+ // store true, if data must be freed
+ // otherwise store false
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+static inline void FreeData
(
const void *data, // data to free
CopyMode_t mode // copy mode
-);
+)
+{
+ if ( mode != CPM_LINK )
+ FreeString(data);
+}
//
///////////////////////////////////////////////////////////////////////////////
@@ -694,6 +712,20 @@ extern mem_t EmptyMem; // mem_t(EmptyString,0)
extern mem_t NullMem; // mem_t(0,0)
//-----------------------------------------------------------------------------
+// [[mem_src_t]]
+
+typedef struct mem_src_t
+{
+ const mem_t *src; // list of sources
+ int n_src; // number of sources; if <0: first NULL ptr terminates list
+ bool allow_write; // TRUE: allow to write n_src & src->len if <0
+}
+mem_src_t;
+
+uint GetMemSrcN ( const mem_src_t *src ); // NULL allowed
+uint GetMemSrcLen ( mem_t sep, const mem_src_t *src ); // NULL allowed
+
+//-----------------------------------------------------------------------------
static inline mem_t MemByChar ( char ch )
{
@@ -822,15 +854,15 @@ static mem_t RightMem8 ( const mem_t src, int count )
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 );
+mem_t MemCatSep2A ( const mem_t sep, const mem_t m1, const mem_t m2 );
+mem_t MemCatSep3A ( const mem_t sep, 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 !NULL | !EmptyString | !MinusString | !IsCircBuf()
-void FreeString ( ccp str );
-
static inline void FreeMem ( mem_t *mem )
{
DASSERT(mem);
@@ -879,6 +911,21 @@ extern exmem_t EmptyExMem; // mem_t(EmptyString,0),false,false
extern exmem_t NullExMem; // mem_t(0,0),false,false
//-----------------------------------------------------------------------------
+// [[exmem_dest_t]]
+
+typedef struct exmem_dest_t
+{
+ char *buf; // Dest buffer. If NULL then alloc buffer.
+ uint buf_size; // Size of 'buf'. If too small then alloc buffer.
+ bool try_circ; // TRUE: Use circ-buffer, if result is small enough.
+}
+exmem_dest_t;
+
+// Get a buffer by settings. The returned buffer is always large enough
+// to store len+1 bytes. If dest==NULL: Force MALLOC()
+exmem_t GetExmemDestBuf ( const exmem_dest_t * dest, uint len );
+
+//-----------------------------------------------------------------------------
// constructors
static inline exmem_t ExMemByChar ( char ch )
@@ -941,6 +988,32 @@ static inline exmem_t ExMemDup ( cvp src, int size )
}
//-----------------------------------------------------------------------------
+
+exmem_t ExMemCat
+(
+ exmem_dest_t *dest, // kind of destination, if NULL then MALLOC()
+ mem_t sep, // insert separators between sources with len>0
+ const mem_src_t *src // sources. NULL allowed
+);
+
+exmem_t ExMemCat2
+(
+ exmem_dest_t *dest, // kind of destination, if NULL then MALLOC()
+ mem_t sep, // insert separators between sources with len>0
+ mem_t src1, // first source
+ mem_t src2 // second source
+);
+
+exmem_t ExMemCat3
+(
+ exmem_dest_t *dest, // kind of destination, if NULL then MALLOC()
+ mem_t sep, // insert separators between sources with len>0
+ mem_t src1, // first source
+ mem_t src2, // second source
+ mem_t src3 // third source
+);
+
+//-----------------------------------------------------------------------------
// interface
// 'em' can be modified ignoring 'const'
@@ -1340,7 +1413,7 @@ static inline uint GetGoodAllocSizeA ( uint need, uint align )
//
///////////////////////////////////////////////////////////////////////////////
-/////////////// some basic string functions ///////////////
+/////////////// basic string functions ///////////////
///////////////////////////////////////////////////////////////////////////////
extern const char EmptyQuote[]; // »""« Ignored by FreeString()
@@ -1399,24 +1472,33 @@ int GetProgramPath
//-----
-// StringCopy(), StringCopyE(), StringCat*()
+// StringCopyS(), StringCopyE(), StringCat*()
// RESULT: end of copied string pointing to a NULL character.
// 'src*' may be a NULL pointer.
+// if max_copy<0: ignore it!
-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 * StringCopyS ( char *buf, size_t bufsize, ccp src );
+char * StringCopySM ( char *buf, size_t bufsize, ccp src, ssize_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 );
+char * StringCopyE ( char *buf, ccp buf_end, ccp src );
+char * StringCopyEM ( char *buf, ccp buf_end, ccp src, ssize_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 );
+// like above, but cat with separators
+char * StringCatSep2S ( char *buf, size_t bufsize, ccp sep, ccp src1, ccp src2 );
+char * StringCatSep3S ( char *buf, size_t bufsize, ccp sep, ccp src1, ccp src2, ccp src3 );
+char * StringCatSep2E ( char *buf, ccp buf_end, ccp sep, ccp src1, ccp src2 );
+char * StringCatSep3E ( char *buf, ccp buf_end, ccp sep, ccp src1, ccp src2, ccp src3 );
+char * StringCatSep2A ( ccp sep, ccp src1, ccp src2 );
+char * StringCatSep3A ( ccp sep, ccp src1, ccp src2, ccp src3 );
+
// center string
ccp StringCenterE ( char * buf, ccp buf_end, ccp src, int width );
static inline ccp StringCenterS ( char *buf, size_t bufsize, ccp src, int width )
@@ -1485,7 +1567,7 @@ char * PathCombineFast ( char *dest_buf, uint buf_size, ccp path, ccp base_path
// 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 * 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
@@ -1586,6 +1668,7 @@ char * PrintID
///////////////////////////////////////////////////////////////////////////////
/////////////// circ buf ///////////////
///////////////////////////////////////////////////////////////////////////////
+// [[CircBuf]]
#define CIRC_BUF_MAX_ALLOC 0x0400 // request limit
#define CIRC_BUF_SIZE 0x4000 // internal buffer size
@@ -1957,7 +2040,10 @@ mem_t MoveFromFastBufMem ( FastBuf_t *fb );
/////////////// MatchPattern() ///////////////
///////////////////////////////////////////////////////////////////////////////
-#define PATTERN_WILDCARDS "*# ?[{"
+#define PATTERN_WILDCARDS "*#\t?[{"
+
+bool HaveWildcards ( mem_t str );
+char * FindFirstWildcard ( mem_t str );
bool MatchPatternFull
(
@@ -1977,8 +2063,8 @@ 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)
+ // -2: no prefix found (no rule found)
+ // -1: empty line (no rule found)
// 0: rule found, but don't match
// 1: rule found and match
ccp src, // source line, scanned untilCONTROL
@@ -2088,14 +2174,15 @@ void CloneArgManager ( ArgManager_t *am, int argc, char ** argv );
void AddSpaceArgManager ( ArgManager_t *am, int needed_space );
void CopyArgManager ( ArgManager_t *dest, const ArgManager_t *src );
-void MoveArgManager ( ArgManager_t *dest, ArgManager_t *src );
+void MoveArgManager ( ArgManager_t *dest, ArgManager_t *src );
void PrepareEditArgManager ( ArgManager_t *am, int needed_space );
// return the pos behind last insert arguments
-uint AppendArgManager ( ArgManager_t *am, ccp arg1, ccp arg2, bool move_arg );
-uint InsertArgManager ( ArgManager_t *am, int pos, ccp arg1, ccp arg2, bool move_arg );
-uint ReplaceArgManager( ArgManager_t *am, int pos, ccp arg1, ccp arg2, bool move_arg );
+uint AppendArgManager ( ArgManager_t *am, ccp arg1, ccp arg2, bool move_arg );
+uint ReplaceArgManager ( ArgManager_t *am, int pos, ccp arg1, ccp arg2, bool move_arg );
+uint InsertArgManager ( ArgManager_t *am, int pos, ccp arg1, ccp arg2, bool move_arg );
+uint InsertListArgManager( ArgManager_t *am, int pos, int argc, char ** argv, bool move_arg );
// return the pos at removed argument
uint RemoveArgManager ( ArgManager_t *am, int pos, int count );
@@ -2108,6 +2195,50 @@ bool CheckFilterArgManager ( const ArgManager_t *filter, ccp name );
void DumpArgManager ( FILE *f, int indent, const ArgManager_t *am, ccp title );
+enumError ScanFileArgManager
+(
+ ArgManager_t *am, // valid arg-manager
+ int pos, // insert position, relative to end if <0
+ ccp fname, // filename to open
+ int silent, // 0: print all error messages
+ // 1: suppress file size warning
+ // 2: suppress all error messages
+ int *n_added
+);
+
+//-----------------------------------------------------------------------------
+
+typedef enum arg_expand_mode_t
+{
+ // AMXM = ArgManager eXpand Mode
+ // P = parameters, S = short options, L = long options
+ // 1 = single arg, 2 = double arg
+
+ AMXM_P1 = 0x01, // expand "@file"
+ AMXM_P2 = 0x02, // expand "@ file"
+ AMXM_S1 = 0x04, // expand "-@file"
+ AMXM_S2 = 0x08, // expand "-@ file"
+ AMXM_L1 = 0x10, // expand "--@=file" watch out '='
+ AMXM_L2 = 0x20, // expand "--@ file"
+
+ AMXM_PARAM = AMXM_P1 | AMXM_P2,
+ AMXM_SHORT = AMXM_S1 | AMXM_S2,
+ AMXM_LONG = AMXM_L1 | AMXM_L2,
+
+ AMXM_ALL = AMXM_PARAM | AMXM_SHORT | AMXM_LONG,
+}
+arg_expand_mode_t;
+
+enumError ExpandAtArgManager
+(
+ ArgManager_t *am, // valid arg-manager
+ arg_expand_mode_t expand_mode, // objects to be replaced
+ int recursion, // maximum recursion depth
+ int silent // 0: print all error messages
+ // 1: suppress file size warning
+ // 2: suppress all error messages
+);
+
//
///////////////////////////////////////////////////////////////////////////////
/////////////// sizeof_info_t ///////////////
@@ -2617,9 +2748,12 @@ 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_PIPE = 0x04, // escape pipes '|' to '\!'
+ CHMD_IF_REQUIRED = 0x08, // check for special chars and encode only if required
+ CHMD__ALL = 0x0f,
CHMD__MODERN = CHMD_UTF8 | CHMD_ESC,
- CHMD__ALL = CHMD_UTF8 | CHMD_ESC,
+ CHMD__PIPE8 = CHMD__MODERN | CHMD_PIPE | CHMD_IF_REQUIRED,
}
__attribute__ ((packed)) CharMode_t;
@@ -2631,11 +2765,14 @@ 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_PIPE, // analyse and use ENCODE_OFF|ENCODE_STRING, escape '|' too
+ ENCODE_PIPE8, // analyse and use ENCODE_OFF|ENCODE_UTF8, escape '|' too
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_HEX, // Use hex-string without quotes
ENCODE__N // number of encoding modes
}
@@ -2681,9 +2818,11 @@ extern ccp TableDecode64default, TableEncode64default;
///////////////////////////////////////////////////////////////////////////////
-uint GetEscapedSize
+uint GetEscapeLen
(
- // returns the needed buffer size for PrintEscapedString()
+ // returns the extra size needed for escapes.
+ // Add 'src_len' to get the escaped string size.
+ // Add 'additionally 4 to get a good buffer size.
ccp source, // NULL or string to print
int src_len, // length of string. if -1, str is null terminated
@@ -2717,10 +2856,27 @@ uint ScanEscapedString
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
+ int quote, // -1:auto, 0:none, >0: quotation char
uint *scanned_len // not NULL: Store number of scanned 'source' bytes here
);
+//-----------------------------------------------------------------------------
+// escan string from tabels with pipe separator (UTF8 only)
+
+static inline uint ScanEscapedStringPipe
+(
+ // returns the number of valid bytes in 'buf' (NULL term added but not counted)
+
+ char *buf, // valid destination buffer, maybe source
+ uint buf_size, // size of 'buf'
+ ccp source, // string to scan
+ uint *scanned_len // not NULL: Store number of scanned 'source' bytes here
+)
+{
+ return ScanEscapedString(buf,buf_size,source,-1,true,
+ source && *source == '"' ? '"' : '|', scanned_len );
+}
+
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
@@ -2845,7 +3001,7 @@ static inline uint DecodeJSON
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
- int quote, // 0:none, -1:auto, >0: quotation char
+ int quote, // -1:auto, 0:none, >0: quotation char
uint *scanned_len // not NULL: Store number of scanned 'str' bytes here
)
{
@@ -2862,7 +3018,7 @@ mem_t DecodeJSONCirc
ccp source, // NULL or string to decode
int source_len, // length of 'source'. If -1, str is NULL terminated
- int quote // 0:none, -1:auto, >0: quotation char
+ int quote // -1:auto, 0:none, >0: quotation char
);
///////////////////////////////////////////////////////////////////////////////
@@ -2908,6 +3064,60 @@ mem_t QuoteJSONCirc
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
+uint DecodeHex
+(
+ // 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
+ int quote, // -1:auto, 0:none, >0: quotation char
+ uint *scanned_len // not NULL: Store number of scanned 'str' bytes here
+);
+
+//-----------------------------------------------------------------------------
+
+mem_t DecodeHexCirc
+(
+ // 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
+ int quote // -1:auto, 0:none, >0: quotation char
+);
+
+///////////////////////////////////////////////////////////////////////////////
+
+uint EncodeHex
+(
+ // 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)
+ ccp digits // digits to use, eg. LoDigits[] (=fallback) or HiDigits[]
+);
+
+//-----------------------------------------------------------------------------
+
+mem_t EncodeHexCirc
+(
+ // 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)
+ ccp digits // digits to use, eg. LoDigits[] (=fallback) or HiDigits[]
+);
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
uint DecodeByMode
(
// returns the number of valid bytes in 'buf'. Result is NULL-terminated.
@@ -3003,6 +3213,22 @@ ccp GetShiftJISStatistics(void);
/////////////// escape/quote strings, alloc space ///////////////
///////////////////////////////////////////////////////////////////////////////
+exmem_t EscapeStringEx
+(
+ // Returns an exmem_t struct. If not quoted (CHMD_IF_REQUIRED) it returns 'src'
+ // Use FreeExMem(&result) to free possible alloced result.
+
+ cvp src, // NULL or source
+ int src_len, // size of 'src'. If -1: Use strlen(src)
+ cvp return_if_null, // return this, if 'src==NULL'
+ cvp return_if_empty, // return this, if src is empty (have no chars)
+ CharMode_t char_mode, // how to escape (CHMD_*)
+ char quote, // quoting character: " or ' or $ (for $'...')
+ bool try_circ // use circ-buffer, if result is small enough
+);
+
+//-----------------------------------------------------------------------------
+
char * EscapeString
(
// Returns a pointer.
@@ -3063,6 +3289,23 @@ static inline char * QuoteBashCircM ( mem_t src, cvp if_null, CharMode_t cm )
static char * QuoteBashCircS ( ccp src, cvp if_null, CharMode_t cm )
{ return EscapeString(src,-1,if_null,EmptyQuote,cm,'$',true,0); }
+
+//-----------------------------------------------------------------------------
+// Escape strings for tables with pipe separator (UTF8 only).
+// Use FreeExMem(result) to free possible alloced result.
+
+static inline exmem_t EscapeStringPipeM ( mem_t src )
+ { return EscapeStringEx(src.ptr,src.len,EmptyString,EmptyString,CHMD__PIPE8,'"',false); }
+
+static exmem_t EscapeStringPipeS ( ccp src )
+ { return EscapeStringEx(src,-1,EmptyString,EmptyString,CHMD__PIPE8,'"',false); }
+
+static inline exmem_t EscapeStringPipeCircM ( mem_t src )
+ { return EscapeStringEx(src.ptr,src.len,EmptyString,EmptyString,CHMD__PIPE8,'"',true); }
+
+static exmem_t EscapeStringPipeCircS ( ccp src )
+ { return EscapeStringEx(src,-1,EmptyString,EmptyString,CHMD__PIPE8,'"',false); }
+
//
///////////////////////////////////////////////////////////////////////////////
/////////////// struct Escape_t ///////////////
@@ -3230,6 +3473,17 @@ s64 ScanKeywordListMask
//-----------------------------------------------------------------------------
+ccp GetKeywordError
+(
+ // return circ-buf
+
+ const KeywordTab_t * key_tab, // NULL or pointer to command table
+ ccp key_arg, // analyzed command
+ int key_stat, // status of ScanKeyword()
+ ccp object // NULL or object for error messages
+ // default= 'command'
+);
+
enumError PrintKeywordError
(
const KeywordTab_t * key_tab, // NULL or pointer to command table
@@ -5928,6 +6182,13 @@ uint FindParamFieldHelper ( const ParamField_t * pf, bool * found, ccp key );
// find first pattern that matches
ParamFieldItem_t * MatchParamField ( const ParamField_t * pf, ccp key );
+//-----------------------------------------------------------------------------
+// get values and set marker by 'num |= mark'
+
+ccp GetParamFieldStr ( ParamField_t *pf, uint mark, ccp key, ccp def );
+int GetParamFieldInt ( ParamField_t *pf, uint mark, ccp key, int def );
+int GetParamFieldIntMM ( ParamField_t *pf, uint mark, ccp key, int def, int min, int max );
+
//
///////////////////////////////////////////////////////////////////////////////
/////////////// struct exmem_list_t ///////////////
diff --git a/project/dclib/dclib-debug.c b/project/dclib/dclib-debug.c
index 6e23f6e..ed3a2d1 100644
--- a/project/dclib/dclib-debug.c
+++ b/project/dclib/dclib-debug.c
@@ -378,7 +378,11 @@ void ListErrorCodes
/////////////// error handling ///////////////
///////////////////////////////////////////////////////////////////////////////
-ProgInfo_t ProgInfo = {0};
+#ifdef EXTENDED_ERRORS
+ ProgInfo_t ProgInfo = { .error_level = ERRLEV_EXTENDED };
+#else
+ ProgInfo_t ProgInfo = { .error_level = ERRLEV_MINIMAL };
+#endif
///////////////////////////////////////////////////////////////////////////////
@@ -409,6 +413,15 @@ enumError PrintErrorFile ( ccp func, ccp file, uint line, struct File_t *F,
enumError PrintErrorArg ( ccp func, ccp file, unsigned int line,
int syserr, enumError err_code, ccp format, va_list arg )
{
+ if ( err_code > ERR_OK )
+ {
+ ProgInfo.error_count++;
+
+ ProgInfo.last_error = err_code;
+ if ( ProgInfo.max_error < err_code )
+ ProgInfo.max_error = err_code;
+ }
+
fflush(stdout);
if (!stdwrn)
{
@@ -457,23 +470,22 @@ enumError PrintErrorArg ( ccp func, ccp file, unsigned int line,
fflush(TRACE_FILE);
#endif
- #if defined(EXTENDED_ERRORS)
- if ( err_code > ERR_WARNING )
- #else
- if ( err_code >= ERR_NOT_IMPLEMENTED )
- #endif
+ ccp coln, col1, col0;
+ if (IsFileColorized(stdwrn))
+ {
+ coln = GetTextMode(1,TTM_COL_INFO);
+ col1 = GetTextMode(1, err_code > ERR_WARNING ? TTM_COL_WARN : TTM_COL_HINT );
+ col0 = TermTextModeReset;
+ }
+ else
+ coln = col1 = col0 = EmptyString;
+
+
+ if ( err_code >= ERR_NOT_IMPLEMENTED
+ || ProgInfo.error_level >= ERRLEV_HEADING && err_code > ERR_WARNING )
{
- ccp coln = EmptyString;
- ccp col1 = EmptyString;
- ccp col0 = EmptyString;
- if (IsFileColorized(stdwrn))
- {
- coln = GetTextMode(1,TTM_COL_INFO);
- col1 = GetTextMode(1, err_code > ERR_WARNING ? TTM_COL_WARN : TTM_COL_HINT );
- col0 = TermTextModeReset;
- }
- if ( stdwrn == stderr )
+ if ( err_code >= ERR_NOT_IMPLEMENTED || ProgInfo.error_level >= ERRLEV_EXTENDED )
{
if ( err_code > ERR_WARNING )
fprintf(stdwrn,"%s%s%s:%s ERROR #%d [%s] in %s() @ %s#%d%s\n",
@@ -494,22 +506,23 @@ enumError PrintErrorArg ( ccp func, ccp file, unsigned int line,
prefix, coln, ProgInfo.progname, col1, col0 );
}
- #if defined(EXTENDED_ERRORS) && EXTENDED_ERRORS > 1
- #ifdef SVN_NEXT
- fprintf(stdwrn,"%s -> %s/%s?annotate=%d#l%d\n",
- prefix, URI_VIEWVC, file, SVN_NEXT, line );
- #elif defined(REVISION_NEXT)
- fprintf(stdwrn,"%s -> %s/%s?annotate=%d#l%d\n",
- prefix, URI_VIEWVC, file, REVISION_NEXT, line );
- #endif
- #endif
+ if ( ProgInfo.error_level >= ERRLEV_ANNOTATE )
+ {
+ #ifdef SVN_NEXT
+ fprintf(stdwrn,"%s -> %s/%s?annotate=%d#l%d\n",
+ prefix, URI_VIEWVC, file, SVN_NEXT, line );
+ #elif defined(REVISION_NEXT)
+ fprintf(stdwrn,"%s -> %s/%s?annotate=%d#l%d\n",
+ prefix, URI_VIEWVC, file, REVISION_NEXT, line );
+ #endif
+ }
fputs(prefix,stdwrn);
PutLines(stdwrn,plen,fw,0,prefix,msg,0);
}
else
{
- fprintf(stdwrn,"%s%s:",prefix,ProgInfo.progname);
+ fprintf(stdwrn,"%s%s%s:%s",prefix,coln,ProgInfo.progname,col0);
PutLines(stdwrn,plen,fw,strlen(ProgInfo.progname)+1,prefix,msg,0);
}
@@ -521,18 +534,8 @@ enumError PrintErrorArg ( ccp func, ccp file, unsigned int line,
}
fflush(stdwrn);
- if ( err_code > ERR_OK )
- {
- ProgInfo.error_count++;
-
- ProgInfo.last_error = err_code;
- if ( ProgInfo.max_error < err_code )
- ProgInfo.max_error = err_code;
-
- if ( err_code > ERR_NOT_IMPLEMENTED )
- exit(err_code);
- }
-
+ if ( err_code > ERR_NOT_IMPLEMENTED )
+ exit(err_code);
return err_code;
}
@@ -625,8 +628,152 @@ uint HexDump ( FILE * f, int indent, u64 addr, int addr_fw, int row_len,
return stat < 0 ? 0 : stat;
}
+///////////////////////////////////////////////////////////////////////////////
+
+uint HexDump16BE2 ( FILE * f, int indent, u64 addr,
+ const void * data, size_t count )
+{
+ // return the number of printed lines
+ return HexDumpBE2(f,indent,addr,4,16,data,count);
+}
+
+//-----------------------------------------------------------------------------
+
+uint HexDump20BE2 ( FILE * f, int indent, u64 addr,
+ const void * data, size_t count )
+{
+ // return the number of printed lines
+ return HexDumpBE2(f,indent,addr,4,20,data,count);
+}
+
+//-----------------------------------------------------------------------------
+
+uint HexDumpBE2 ( FILE * f, int indent, u64 addr, int addr_fw, int row_len,
+ const void * p_data, size_t count )
+{
+ // return the number of printed lines
+ if ( !f || !p_data || !count )
+ return 0;
+
+ XDump_t xd;
+ InitializeXDumpEx(&xd,f,indent,addr,addr_fw,row_len);
+ xd.format = XDUMPF_INT_2;
+ xd.endian = DC_BIG_ENDIAN;
+
+ const int stat = XDump(&xd,p_data,count,true);
+ return stat < 0 ? 0 : stat;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+uint HexDump16LE2 ( FILE * f, int indent, u64 addr,
+ const void * data, size_t count )
+{
+ // return the number of printed lines
+ return HexDumpLE2(f,indent,addr,4,16,data,count);
+}
+
+//-----------------------------------------------------------------------------
+
+uint HexDump20LE2 ( FILE * f, int indent, u64 addr,
+ const void * data, size_t count )
+{
+ // return the number of printed lines
+ return HexDumpLE2(f,indent,addr,4,20,data,count);
+}
+
+//-----------------------------------------------------------------------------
+
+uint HexDumpLE2 ( FILE * f, int indent, u64 addr, int addr_fw, int row_len,
+ const void * p_data, size_t count )
+{
+ // return the number of printed lines
+ if ( !f || !p_data || !count )
+ return 0;
+
+ XDump_t xd;
+ InitializeXDumpEx(&xd,f,indent,addr,addr_fw,row_len);
+ xd.format = XDUMPF_INT_2;
+ xd.endian = DC_LITTLE_ENDIAN;
+
+ const int stat = XDump(&xd,p_data,count,true);
+ return stat < 0 ? 0 : stat;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+uint HexDump16BE4 ( FILE * f, int indent, u64 addr,
+ const void * data, size_t count )
+{
+ // return the number of printed lines
+ return HexDumpBE4(f,indent,addr,4,16,data,count);
+}
+
+//-----------------------------------------------------------------------------
+
+uint HexDump20BE4 ( FILE * f, int indent, u64 addr,
+ const void * data, size_t count )
+{
+ // return the number of printed lines
+ return HexDumpBE4(f,indent,addr,4,20,data,count);
+}
+
//-----------------------------------------------------------------------------
+uint HexDumpBE4 ( FILE * f, int indent, u64 addr, int addr_fw, int row_len,
+ const void * p_data, size_t count )
+{
+ // return the number of printed lines
+ if ( !f || !p_data || !count )
+ return 0;
+
+ XDump_t xd;
+ InitializeXDumpEx(&xd,f,indent,addr,addr_fw,row_len);
+ xd.format = XDUMPF_INT_4;
+ xd.endian = DC_BIG_ENDIAN;
+
+ const int stat = XDump(&xd,p_data,count,true);
+ return stat < 0 ? 0 : stat;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+uint HexDump16LE4 ( FILE * f, int indent, u64 addr,
+ const void * data, size_t count )
+{
+ // return the number of printed lines
+ return HexDumpLE4(f,indent,addr,4,16,data,count);
+}
+
+//-----------------------------------------------------------------------------
+
+uint HexDump20LE4 ( FILE * f, int indent, u64 addr,
+ const void * data, size_t count )
+{
+ // return the number of printed lines
+ return HexDumpLE4(f,indent,addr,4,20,data,count);
+}
+
+//-----------------------------------------------------------------------------
+
+uint HexDumpLE4 ( FILE * f, int indent, u64 addr, int addr_fw, int row_len,
+ const void * p_data, size_t count )
+{
+ // return the number of printed lines
+ if ( !f || !p_data || !count )
+ return 0;
+
+ XDump_t xd;
+ InitializeXDumpEx(&xd,f,indent,addr,addr_fw,row_len);
+ xd.format = XDUMPF_INT_4;
+ xd.endian = DC_LITTLE_ENDIAN;
+
+ const int stat = XDump(&xd,p_data,count,true);
+ return stat < 0 ? 0 : stat;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
uint HexDump016 ( FILE * f, int indent, u64 addr,
const void * data, size_t count )
{
@@ -650,7 +797,7 @@ uint HexDump0 ( FILE * f, int indent, u64 addr, int addr_fw, int row_len,
return stat < 0 ? 0 : stat;
}
-//-----------------------------------------------------------------------------
+///////////////////////////////////////////////////////////////////////////////
void HexDiff16 ( FILE * f, int indent, u64 addr,
const void * data1, size_t count1,
diff --git a/project/dclib/dclib-debug.h b/project/dclib/dclib-debug.h
index b8aefc8..1147646 100644
--- a/project/dclib/dclib-debug.h
+++ b/project/dclib/dclib-debug.h
@@ -41,6 +41,21 @@
//
///////////////////////////////////////////////////////////////////////////////
+/////////////// error_level_t ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[error_level_t]]
+
+typedef enum error_level_t
+{
+ ERRLEV_MINIMAL, // simple error line only
+ ERRLEV_HEADING, // headline with: tool: ERROR # [ERR_NAME]
+ ERRLEV_EXTENDED, // extended headline with function and source
+ ERRLEV_ANNOTATE, // like ERRLEV_EXTENDED; but append 'URL?annotate='
+}
+error_level_t;
+
+//
+///////////////////////////////////////////////////////////////////////////////
/////////////// program info ///////////////
///////////////////////////////////////////////////////////////////////////////
// [[ProgInfo_t]]
@@ -58,7 +73,8 @@ typedef struct ProgInfo_t
ccp toolversion; // version of the tool, set by SetupProgname()
ccp tooltitle; // title of the tool, set by SetupProgname()
- bool multi_processing; // TRUE: program uses multiple thread
+ error_level_t error_level; // one of ERRLEV_*
+ bool multi_processing; // TRUE: program uses multiple threads
enumError last_error; // last error, set by PrintErrorArg()
enumError max_error; // max error, set by PrintErrorArg()
@@ -149,25 +165,50 @@ extern bool hexdump_align;
// HexDump*() return the number of printed lines
uint HexDump ( FILE * f, int indent, u64 addr, int addr_fw, int row_len,
- const void * data, size_t count );
-
+ const void * data, size_t count );
uint HexDump16 ( FILE * f, int indent, u64 addr,
- const void * data, size_t count );
+ const void * data, size_t count );
uint HexDump20 ( FILE * f, int indent, u64 addr,
- const void * data, size_t count );
+ const void * data, size_t count );
+
+uint HexDumpBE2 ( FILE * f, int indent, u64 addr, int addr_fw, int row_len,
+ const void * data, size_t count );
+uint HexDump16BE2 ( FILE * f, int indent, u64 addr,
+ const void * data, size_t count );
+uint HexDump20BE2 ( FILE * f, int indent, u64 addr,
+ const void * data, size_t count );
+
+uint HexDumpLE2 ( FILE * f, int indent, u64 addr, int addr_fw, int row_len,
+ const void * data, size_t count );
+uint HexDump16LE2 ( FILE * f, int indent, u64 addr,
+ const void * data, size_t count );
+uint HexDump20LE2 ( FILE * f, int indent, u64 addr,
+ const void * data, size_t count );
+
+uint HexDumpBE4 ( FILE * f, int indent, u64 addr, int addr_fw, int row_len,
+ const void * data, size_t count );
+uint HexDump16BE4 ( FILE * f, int indent, u64 addr,
+ const void * data, size_t count );
+uint HexDump20BE4 ( FILE * f, int indent, u64 addr,
+ const void * data, size_t count );
+
+uint HexDumpLE4 ( FILE * f, int indent, u64 addr, int addr_fw, int row_len,
+ const void * data, size_t count );
+uint HexDump16LE4 ( FILE * f, int indent, u64 addr,
+ const void * data, size_t count );
+uint HexDump20LE4 ( FILE * f, int indent, u64 addr,
+ const void * data, size_t count );
// HexDump0*() will supress null-only lines.
uint HexDump0 ( FILE * f, int indent, u64 addr, int addr_fw, int row_len,
const void * data, size_t count );
-
uint HexDump016 ( FILE * f, int indent, u64 addr,
const void * data, size_t count );
void HexDiff ( FILE * f, int indent, u64 addr, int addr_fw, int row_len,
const void * p_data1, size_t count1,
const void * p_data2, size_t count2 );
-
void HexDiff16 ( FILE * f, int indent, u64 addr,
const void * data1, size_t count1,
const void * data2, size_t count2 );
@@ -414,41 +455,42 @@ void WAIT_ARG_FUNC ( ccp format, va_list arg );
///////////////////////////////////////////////////////////////////////////////
+#undef HAVE_PRINT
#undef PRINT
#undef PRINT_IF
#undef PRINT_SIZEOF
#undef BINGO
+#undef HAVE_PRINT0
#undef PRINT0
#undef PRINT_IF0
#undef PRINT_SIZEOF0
#undef BINGO0
+#undef HAVE_PRINT1
#undef PRINT1
#undef PRINT_IF1
#undef PRINT_SIZEOF1
#undef BINGO1
+#undef HAVE_PRINTD
#undef PRINTD
#undef PRINT_IFD
#undef PRINT_SIZEOFD
#undef BINGOD
-#undef HAVE_PRINTD
#undef xBINGO
-#undef HAVE_PRINT
#undef PRINT_TIME
-#undef HAVE_PRINT0 // always false
-#define HAVE_PRINT0 0
-
// always disabled
+#define HAVE_PRINT0 0
#define PRINT0 TRACE
#define PRINT_IF0 TRACE_IF
#define PRINT_SIZEOF0 TRACE_SIZEOF
#define BINGO0 TRACELINE
// always enabled
+#define HAVE_PRINT1 1
#define PRINT1(...) PRINT_FUNC(__VA_ARGS__)
#define PRINT_IF1(cond,...) if (cond) PRINT_FUNC(__VA_ARGS__)
#define PRINT_SIZEOF1(t) PRINT_FUNC("%7zd ==%6zx/hex == sizeof(%s)\n",sizeof(t),sizeof(t),#t)
@@ -456,7 +498,7 @@ void WAIT_ARG_FUNC ( ccp format, va_list arg );
#if defined(DEBUG) && defined(TEST)
- #define HAVE_PRINT 1
+ #define HAVE_PRINT 1
#define PRINT PRINT1
#define PRINT_IF PRINT_IF1
#define PRINT_SIZEOF PRINT_SIZEOF1
diff --git a/project/dclib/dclib-file.c b/project/dclib/dclib-file.c
index aae70a3..d1f93da 100644
--- a/project/dclib/dclib-file.c
+++ b/project/dclib/dclib-file.c
@@ -260,12 +260,31 @@ exmem_t SearchToolByPATH ( ccp tool )
char fname[PATH_MAX];
if (strchr(tool,'/'))
{
+//PRINT1("SEARCH ABS: %s\n",tool);
struct stat st;
if ( !stat(tool,&st) && st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH) )
+ {
+//PRINT1("FOUND ABS: %s\n",tool);
AssignExMemS(&dest,tool,-1,CPM_COPY);
+ }
}
else
{
+ #ifdef __CYGWINxxx__
+ if ( ProgInfo.progpath && *ProgInfo.progpath )
+ {
+ PathCatPP(fname,sizeof(fname),ProgInfo.progpath,tool);
+//PRINT1("SEARCH+: %s\n",fname);
+ struct stat st;
+ if ( !stat(fname,&st) && st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH) )
+ {
+//PRINT1("FOUND+: %s\n",fname);
+ AssignExMemS(&dest,fname,-1,CPM_COPY);
+ return dest;
+ }
+ }
+ #endif
+
ccp path = getenv("PATH");
for(;;)
{
@@ -279,9 +298,11 @@ exmem_t SearchToolByPATH ( ccp tool )
break;
const int flen = snprintf(fname,sizeof(fname),"%.*s/%s",len,start,tool);
+//PRINT1("SEARCH: %s\n",fname);
struct stat st;
if ( !stat(fname,&st) && st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH) )
{
+//PRINT1("FOUND: %s\n",fname);
AssignExMemS(&dest,fname,flen,CPM_COPY);
break;
}
@@ -311,6 +332,7 @@ exmem_t SearchToolByList ( ccp * list, int max )
ccp arg = *list++;
if (arg)
{
+//PRINT1("SEARCH: %s\n",arg);
if ( *arg == '>' )
{
ccp env = getenv(arg+1);
@@ -324,7 +346,10 @@ exmem_t SearchToolByList ( ccp * list, int max )
{
dest = SearchToolByPATH(arg);
if (dest.data.len)
+ {
+ //AssignExMemS(&dest,arg,-1,CPM_LINK);
break;
+ }
}
}
}
@@ -344,17 +369,33 @@ static FILE *pager_file = 0;
FILE * OpenPipeToPager()
{
static bool done = false;
-
if (!done)
{
done = true;
+ // first: set less option -R to enable colors
+ ccp less = getenv("LESS");
+ if ( less && *less )
+ {
+ char buf[200];
+ snprintf(buf,sizeof(buf),"%s -R",less);
+ setenv("LESS",buf,1);
+ }
+ else
+ setenv("LESS","-R",1);
+
static ccp search_tab[] =
{
">DC_PAGER",
">DC_PAGER1",
">DC_PAGER2",
">PAGER",
+ #ifdef __CYGWINxxx__
+ "/usr/bin/less",
+ "/cygdrive/c/Program Files/Wiimm/SZS/less",
+ "/usr/bin/more",
+ "/cygdrive/c/Program Files/Wiimm/SZS/more",
+ #endif
"less",
"more",
0
@@ -362,7 +403,18 @@ FILE * OpenPipeToPager()
exmem_t pager = SearchToolByList(search_tab,-1);
if (pager.data.ptr)
+ {
+ #ifdef __CYGWINxxx__
+PRINT1("popen(%s)\n",pager.data.ptr);
+ char buf[500];
+ StringCat3S(buf,sizeof(buf),"'",pager.data.ptr,"'");
+PRINT1("popen(%s)\n",buf);
+ pager_file = popen(buf,"we");
+PRINT_IF1(!pager_file,"popen(%s) FAILED\n",buf);
+ #else
pager_file = popen(pager.data.ptr,"we");
+ #endif
+ }
FreeExMem(&pager);
}
@@ -375,6 +427,10 @@ void ClosePagerFile()
{
if (pager_file)
{
+ if ( stdout == pager_file ) stdout = 0;
+ if ( stderr == pager_file ) stderr = 0;
+ if ( stdwrn == pager_file ) stdwrn = 0;
+ if ( stdlog == pager_file ) stdlog = 0;
pclose(pager_file);
pager_file = 0;
}
@@ -389,6 +445,16 @@ bool StdoutToPager()
{
fflush(stdout);
stdout = f;
+
+ if ( stderr && isatty(fileno(stderr)) )
+ stderr = f;
+
+ if ( stdwrn && isatty(fileno(stdwrn)) )
+ stdwrn = f;
+
+ if ( stdlog && isatty(fileno(stdlog)) )
+ stdlog = f;
+
return true;
}
return false;
@@ -399,10 +465,7 @@ bool StdoutToPager()
void CloseStdoutToPager()
{
if ( pager_file && pager_file == stdout )
- {
ClosePagerFile();
- stdout = 0;
- }
}
//
@@ -1808,7 +1871,7 @@ enumError LoadFile
bool fatt_max // true: store *max* values to 'fatt'
)
{
- ASSERT(data);
+ DASSERT(data);
if (!size)
return ERR_OK;
@@ -2222,58 +2285,101 @@ enumError CopyFileTemp
enumError TransferFile
(
- ccp src, // source path
+ LogFile_t *log, // not NULL: log activities
ccp dest, // destination path
+ ccp src, // source path
TransferMode_t tfer_mode, // transfer mode
mode_t open_mode // mode for CopyFile*() -> open()
)
{
- if ( !dest || !src || !*dest || !*src )
+ if ( !dest || !*dest || !src || !*src )
return ERR_MISSING_PARAM;
if (IsSameFile(src,dest))
return ERR_NOTHING_TO_DO;
+ const bool testmode = ( tfer_mode & TFMD_F_TEST ) != 0;
+
if ( tfer_mode & TFMD_J_MOVE1 )
{
LOGPRINT("TransferFile(MOVE1) %s -> %s\n",src,dest);
struct stat st;
- if ( !stat(src,&st) && st.st_nlink == 1 && !rename(src,dest) )
+ if ( !stat(src,&st) && st.st_nlink == 1
+ && ( testmode || !rename(src,dest) ))
+ {
+ if (log)
+ PrintLogFile(log, "%s:\n\t< %s\n\t> %s\n",
+ testmode ? "Would MOVE" : "MOVED", src, dest );
return ERR_OK;
+ }
}
else if ( tfer_mode & TFMD_J_MOVE )
{
LOGPRINT("TransferFile(MOVE) %s -> %s\n",src,dest);
- if (!rename(src,dest))
+ if ( testmode || !rename(src,dest) )
+ {
+ if (log)
+ PrintLogFile(log, "%s:\n\t< %s\n\t> %s\n",
+ testmode ? "Would MOVE" : "MOVED", src, dest );
return ERR_OK;
+ }
}
if ( tfer_mode & TFMD_J_LINK )
{
LOGPRINT("TransferFile(RM_DEST) %s\n",dest);
- if ( tfer_mode & TFMD_J_RM_DEST )
+ if ( tfer_mode & TFMD_J_RM_DEST && !testmode )
unlink(dest);
LOGPRINT("TransferFile(LINK) %s -> %s\n",src,dest);
- if (!link(src,dest))
+ if ( testmode || !link(src,dest) )
+ {
+ if (log)
+ PrintLogFile(log, "%s:\n\t< %s\n\t> %s\n",
+ testmode ? "Would LINK" : "LINKED", src, dest );
return ERR_OK;
+ }
}
if ( tfer_mode & TFMD_J_COPY )
{
LOGPRINT("TransferFile(COPY) %s -> %s\n",src,dest);
- enumError err = tfer_mode & TFMD_J_RM_DEST
- ? CopyFileTemp(src,dest,open_mode)
- : CopyFile(src,dest,open_mode);
- if ( err == ERR_OK )
+ if (testmode)
{
- if ( tfer_mode & TFMD_J_RM_SRC )
+ if (log)
{
- PRINT("TransferFile(RM_SRC) %s",src);
- unlink(src);
+ if ( tfer_mode & TFMD_J_RM_DEST )
+ PrintLogFile(log, "Would REMOVE DEST: %s\n",dest);
+ PrintLogFile(log, "Would COPY:\n\t< %s\n\t> %s\n",src,dest);
+ if ( tfer_mode & TFMD_J_RM_SRC )
+ PrintLogFile(log, "Would REMOVE SRC: %s\n",src);
}
return ERR_OK;
}
+ else
+ {
+ enumError err = tfer_mode & TFMD_J_RM_DEST
+ ? CopyFileTemp(src,dest,open_mode)
+ : CopyFile(src,dest,open_mode);
+ if ( err == ERR_OK )
+ {
+ if (log)
+ {
+ if ( tfer_mode & TFMD_J_RM_DEST )
+ PrintLogFile(log, "REMOVE DEST: %s\n",dest);
+ PrintLogFile(log, "COPY:\n\t< %s\n\t> %s\n",src,dest);
+ }
+
+ if ( tfer_mode & TFMD_J_RM_SRC )
+ {
+ PRINT("TransferFile(RM_SRC) %s",src);
+ unlink(src);
+ if (log)
+ PrintLogFile(log, "REMOVE SRC: %s\n",src);
+ }
+ return ERR_OK;
+ }
+ }
}
return ERR_ERROR;
@@ -3099,6 +3205,24 @@ bool IsSameFilename ( ccp fn1, ccp fn2 )
}
///////////////////////////////////////////////////////////////////////////////
+
+// convert type get by readdir() to of struct stat.st_mode
+uint ConvertDType2STMode ( uint d_type )
+{
+ switch (d_type)
+ {
+ case DT_BLK: return S_IFBLK;
+ case DT_CHR: return S_IFCHR;
+ case DT_DIR: return S_IFDIR;
+ case DT_FIFO: return S_IFIFO;
+ case DT_LNK: return S_IFLNK;
+ case DT_REG: return S_IFREG;
+ case DT_SOCK: return S_IFSOCK;
+ }
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool enable_config_search_log = false;
@@ -3622,6 +3746,317 @@ ccp GetBlockDeviceHolder ( ccp name, ccp sep, int *ret_level )
//
///////////////////////////////////////////////////////////////////////////////
+/////////////// SearchPaths() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[search_paths_t]]
+
+typedef struct search_paths_t
+{
+ mem_t source; // path to analyse, any string outside
+ bool allow_hidden; // true: allow hidden dirs and files
+
+ char *path_buf; // pointer to complete path, work buffer
+ char *path_star; // begin of '**' for search_paths_dir()
+ char *path_ptr; // current end of path
+ char *path_end; // end of 'path_buf' -1
+
+ SearchPathsFunc func; // function to call, never NULL
+ void *param; // last param for func()
+
+ search_paths_stat_t status; // search status
+}
+search_paths_t;
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void search_paths_hit ( search_paths_t *sp, mem_t path, uint d_type )
+{
+ DASSERT(sp);
+ enumError err = sp->func(path,d_type,sp->param);
+ if ( err < 0 )
+ {
+ err = -err;
+ sp->status.abort = true;
+ }
+
+ if ( err != ERR_JOB_IGNORED )
+ {
+ sp->status.hit_count++;
+ if ( sp->status.max_err < err )
+ sp->status.max_err = err;
+ }
+
+ sp->status.func_count++;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void search_paths_dir ( search_paths_t *sp, ParamField_t *collect, int min, int max )
+{
+ DASSERT(sp);
+ DASSERT(collect);
+ PRINT0("%s%s** %d - %d%s\n",colerr->debug,sp->path_buf,min,max,colerr->reset);
+
+ search_paths_t local = *sp;
+ char *path_ptr = local.path_ptr;
+
+ DIR *fdir = opendir( *local.path_buf ? local.path_buf: "." );
+ local.status.dir_count++;
+ if (fdir)
+ {
+ for(;;)
+ {
+ struct dirent *dent = readdir(fdir);
+ if (!dent)
+ break;
+
+ if ( dent->d_name[0] == '.'
+ && ( !local.allow_hidden
+ || !dent->d_name[1]
+ || dent->d_name[1] == '.' && !dent->d_name[2] ))
+ {
+ continue;
+ }
+
+ local.path_ptr = StringCopyE(path_ptr,sp->path_end,dent->d_name);
+
+ uint st_mode = ConvertDType2STMode(dent->d_type);
+ if (!st_mode)
+ {
+ struct stat st;
+ if (stat(local.path_buf,&st))
+ continue;
+ st_mode = st.st_mode;
+ }
+ if (!S_ISDIR(st_mode))
+ continue;
+
+ DASSERT(local.path_star);
+ DASSERT( local.path_star >= local.path_buf );
+ DASSERT( local.path_star <= local.path_ptr );
+
+ PRINT0("FOUND: [t=%d,m:%x,add=%d,r=%d] %s\n",
+ dent->d_type, st_mode, min<=0, max>0, local.path_star );
+ if ( min <= 0 )
+ InsertParamField(collect,local.path_star,false,st_mode,0);
+ if ( max > 0 )
+ {
+ *local.path_ptr++ = '/';
+ *local.path_ptr = 0;
+ search_paths_dir(&local,collect,min-1,max-1);
+ }
+ }
+ closedir(fdir);
+ }
+
+ sp->status = local.status;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void search_paths_helper ( search_paths_t *sp )
+{
+ ccp wc = FindFirstWildcard(sp->source);
+ if (!wc)
+ {
+ char *end = StringCopyEM(sp->path_ptr,sp->path_end,sp->source.ptr,sp->source.len);
+ struct stat st;
+ if (!stat(sp->path_buf,&st))
+ {
+ mem_t path = { .ptr = sp->path_buf, .len = end - sp->path_buf };
+ search_paths_hit(sp,path,st.st_mode);
+ }
+ return;
+ }
+
+ search_paths_t local = *sp;
+
+ ccp pat = memrchr(local.source.ptr,'/',wc-local.source.ptr);
+ pat = pat ? pat+1 : local.source.ptr;
+
+ ccp source_end = local.source.ptr + local.source.len;
+ ccp next = memchr(wc,'/',source_end-wc);
+ if (!next)
+ next = source_end;
+
+ mem_t pattern;
+ pattern.len = next - pat;
+ pattern.ptr = MEMDUP(pat,pattern.len);
+ const bool allow_hidden = local.allow_hidden || pattern.ptr[0] == '.';
+
+ char *path_ptr = StringCopyEM(local.path_ptr,local.path_end,local.source.ptr,pat-local.source.ptr);
+ local.path_ptr = path_ptr;
+
+ local.source.ptr = next;
+ local.source.len = source_end - next;
+ const bool want_dir = local.source.len && local.source.ptr[0] == '/';
+
+ PRINT0("SPLIT: %s %s%s%s %.*s [want_dir=%d]\n",
+ local.path_buf,
+ colerr->highlight, pattern.ptr, colerr->reset,
+ local.source.len, local.source.ptr, want_dir );
+
+ ParamField_t collect;
+ InitializeParamField(&collect);
+ collect.func_cmp = strcasecmp;
+
+
+ //--- check for **...
+
+ if ( pattern.ptr[0] == '*' && pattern.ptr[1] == '*' )
+ {
+ u32 n1 = 0, n2 = 100;
+ char *ptr = (char*)pattern.ptr+2;
+ if (*ptr)
+ {
+ if (isdigit(*ptr))
+ n1 = str2ul(ptr,&ptr,10);
+ if (*ptr)
+ {
+ if ( *ptr != '-' )
+ goto terminate;
+ if ( *++ptr )
+ {
+ n2 = str2ul(ptr,&ptr,10);
+ if (*ptr)
+ goto terminate;
+ }
+ }
+ else
+ n2 = n1;
+ if ( n2 > 100 )
+ n2 = 100;
+ if ( n1 > n2 )
+ goto terminate;
+ }
+
+ local.path_star = path_ptr;
+ search_paths_dir(&local,&collect,n1,n2);
+ PRINT0("%sDIR: %d records for **%s\n",colerr->highlight,collect.used,colerr->reset);
+
+ ParamFieldItem_t *end = collect.field + collect.used;
+ for ( ParamFieldItem_t *ptr = collect.field; !local.status.abort && ptr < end; ptr++ )
+ {
+ local.path_ptr = StringCopyE(path_ptr,sp->path_end,ptr->key);
+ PRINT0("%sDIR: %s%s\n",colerr->highlight,local.path_buf,colerr->reset);
+ search_paths_helper(&local);
+ if (local.status.abort)
+ break;
+ }
+ goto terminate;
+ }
+
+
+ //--- scan directory
+
+ DIR *fdir = opendir( *local.path_buf ? local.path_buf: "." );
+ local.status.dir_count++;
+ if (fdir)
+ {
+ for(;;)
+ {
+ struct dirent *dent = readdir(fdir);
+ if (!dent)
+ break;
+
+ if ( dent->d_name[0] == '.'
+ && ( !allow_hidden
+ || !dent->d_name[1]
+ || dent->d_name[1] == '.' && !dent->d_name[2] ))
+ {
+ continue;
+ }
+
+ uint st_mode = ConvertDType2STMode(dent->d_type);
+ if ( st_mode && want_dir && !S_ISDIR(st_mode) && !S_ISLNK(st_mode) )
+ continue;
+
+ if ( MatchPatternFull(pattern.ptr,dent->d_name) )
+ {
+ if (!st_mode)
+ {
+ local.path_ptr = StringCopyE(path_ptr,sp->path_end,dent->d_name);
+ struct stat st;
+ if (stat(local.path_buf,&st))
+ continue;
+ if ( want_dir && !S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode) )
+ continue;
+ st_mode = st.st_mode;
+ }
+ PRINT0("BINGO: [%d,%x] %s\n",dent->d_type,st_mode,dent->d_name);
+ InsertParamField(&collect,dent->d_name,false,st_mode,0);
+ }
+ }
+ closedir(fdir);
+ }
+
+ if (!local.status.abort)
+ {
+ ParamFieldItem_t *end = collect.field + collect.used;
+ for ( ParamFieldItem_t *ptr = collect.field; !local.status.abort && ptr < end; ptr++ )
+ {
+ local.path_ptr = StringCopyE(path_ptr,sp->path_end,ptr->key);
+ if (local.source.len)
+ {
+ search_paths_helper(&local);
+ if (local.status.abort)
+ break;
+ }
+ else
+ {
+ mem_t path = { .ptr = local.path_buf, .len = local.path_ptr - local.path_buf };
+ search_paths_hit(&local,path,ptr->num);
+ }
+ }
+ }
+
+ terminate:;
+ ResetParamField(&collect);
+ FreeString(pattern.ptr);
+ sp->status = local.status;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+search_paths_stat_t SearchPaths
+(
+ ccp path1, // not NULL: part #1 of base path
+ ccp path2, // not NULL: part #2 of base path
+ bool allow_hidden, // allow hiddent directories and files
+ SearchPathsFunc func, // callback function, never NULL
+ void *param // last param for func()
+)
+{
+ if (!func)
+ {
+ search_paths_stat_t stat = { .max_err = ERR_MISSING_PARAM };
+ return stat;
+ }
+
+ char srcbuf[PATH_MAX+2];
+ ccp source = PathCatPP(srcbuf,sizeof(srcbuf),path1,path2);
+
+ char pathbuf[PATH_MAX];
+ search_paths_t sp =
+ {
+ .source.ptr = source,
+ .source.len = strlen(source),
+ .allow_hidden = allow_hidden,
+ .path_buf = pathbuf,
+ .path_ptr = pathbuf,
+ .path_end = pathbuf + sizeof(pathbuf) - 2,
+ .func = func,
+ .param = param,
+ };
+
+ search_paths_helper(&sp);
+ PRINT0("abort=%d, max_err = %d, %u dirs scanned, %u func calls, %u hits\n",
+ sp.abort, sp.max_err, sp.dir_count, sp.func_count, sp.hit_count );
+ return sp.status;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
/////////////// normalize filenames ///////////////
///////////////////////////////////////////////////////////////////////////////
@@ -3833,7 +4268,7 @@ uint NormalizeFilenameCygwin
*dest++ = *src++;
*dest = 0;
- ASSERT( dest < buf + buf_size );
+ DASSERT( dest < buf + buf_size );
return dest - buf;
}
diff --git a/project/dclib/dclib-file.h b/project/dclib/dclib-file.h
index f9dd2fc..92a3283 100644
--- a/project/dclib/dclib-file.h
+++ b/project/dclib/dclib-file.h
@@ -632,13 +632,22 @@ typedef enum TransferMode_t
{
//--- jobs
- TFMD_J_MOVE = 0x01, // move file
- TFMD_J_MOVE1 = 0x02, // move file, but only if not linked (ignore TFMD_J_MOVE)
- TFMD_J_RM_DEST = 0x04, // remove dest before TFMD_J_LINK and TFMD_J_COPY
- TFMD_J_LINK = 0x08, // link file
- TFMD_J_COPY = 0x10, // copy file
- TFMD_J_RM_SRC = 0x20, // remove source after TFMD_J_COPY
-// TFMD_J_TOUCH = 0x40, // touch destination => not supported yet
+ TFMD_J_MOVE = 0x001, // move file
+ TFMD_J_MOVE1 = 0x002, // move file, but only if not linked (ignore TFMD_J_MOVE)
+ TFMD_J_RM_DEST = 0x004, // remove dest before TFMD_J_LINK and TFMD_J_COPY
+ TFMD_J_LINK = 0x008, // link file
+ TFMD_J_COPY = 0x010, // copy file
+ TFMD_J_RM_SRC = 0x020, // remove source after TFMD_J_COPY
+// TFMD_J_TOUCH = 0x040, // touch destination => not supported yet
+
+ //--- flags
+
+ TFMD_F_TEST = 0x100, // testmode, don't touch files
+
+ //--- masks
+
+ TFMD_M_JOBS = 0x03f, // mask for jobs
+ TFMD_M_FLAGS = 0x100, // mask for flags
//--- modes
@@ -648,7 +657,7 @@ typedef enum TransferMode_t
TFMD_COPY = TFMD_J_RM_DEST | TFMD_J_COPY,
TFMD_CAT = TFMD_J_COPY,
}
-__attribute__ ((packed)) TransferMode_t;
+TransferMode_t;
//-----------------------------------------------------------------------------
@@ -662,8 +671,9 @@ __attribute__ ((packed)) TransferMode_t;
enumError TransferFile
(
- ccp src, // source path
+ LogFile_t *log, // not NULL: log activities
ccp dest, // destination path
+ ccp src, // source path
TransferMode_t tfer_mode, // transfer mode
mode_t open_mode // mode for CopyFile*() -> open()
);
@@ -947,6 +957,9 @@ int ExistDirectory
bool IsSameFilename ( ccp fn1, ccp fn2 );
+// convert type get by readdir() to of struct stat.st_mode
+uint ConvertDType2STMode ( uint d_type );
+
///////////////////////////////////////////////////////////////////////////////
// [[FindConfigFile_t]]
@@ -1008,6 +1021,43 @@ int SearchFiles
);
///////////////////////////////////////////////////////////////////////////////
+// [[search_paths_stat_t]]
+
+typedef struct search_paths_stat_t
+{
+ bool abort; // true: abort search
+ enumError max_err; // max found error
+
+ uint dir_count; // number of scanned directories
+ uint func_count; // number of func() calls
+ uint hit_count; // number of hits (!ERR_JOB_IGNORED)
+}
+search_paths_stat_t;
+
+//-----------------------------------------------------------------------------
+
+// error codes < 0 mean: abort.
+// return ERR_JOB_IGNORED if path finally not match
+
+typedef enumError (*SearchPathsFunc)
+(
+ mem_t path, // full path of existing file, never NULL
+ uint st_mode, // copy of struct stat.st_mode, see "man 2 stat"
+ void *param // user defined parameter
+);
+
+//-----------------------------------------------------------------------------
+
+search_paths_stat_t SearchPaths
+(
+ ccp path1, // not NULL: part #1 of base path
+ ccp path2, // not NULL: part #2 of base path
+ bool allow_hidden, // allow hiddent directories and files
+ SearchPathsFunc func, // callback function, never NULL
+ void *param // last param for func()
+);
+
+///////////////////////////////////////////////////////////////////////////////
enumError CreatePath
(
diff --git a/project/dclib/dclib-network.c b/project/dclib/dclib-network.c
index 76390e3..9c350b9 100644
--- a/project/dclib/dclib-network.c
+++ b/project/dclib/dclib-network.c
@@ -3520,7 +3520,11 @@ int PrintBinary1TCPStream
return -1;
char buf[10000], *end_buf = buf + sizeof(buf) - 4;
+ #if 0 // dcc12: throws error: buf may be used uninitialized
char *dest = StringCopyE(buf,end_buf,cmd);
+ #else
+ char *dest = StringCopyS(buf,sizeof(buf)-4,cmd);
+ #endif
if ( dest + 6 + bin_size >= end_buf )
return -1;
@@ -3579,7 +3583,11 @@ int PrintBinary2TCPStream
return -1;
char buf[10000], *end_buf = buf + sizeof(buf) - 4;
+ #if 0 // dcc12: throws error: buf may be used uninitialized
char *dest = StringCopyE(buf,end_buf,cmd);
+ #else
+ char *dest = StringCopyS(buf,sizeof(buf)-4,cmd);
+ #endif
if ( dest + 9 + bin1_size + bin2_size >= end_buf )
return -1;
diff --git a/project/dclib/dclib-numeric.c b/project/dclib/dclib-numeric.c
index 0b21975..c339a29 100644
--- a/project/dclib/dclib-numeric.c
+++ b/project/dclib/dclib-numeric.c
@@ -1197,9 +1197,11 @@ ccp GetEncodingName ( EncodeMode_t em )
///////////////////////////////////////////////////////////////////////////////
-uint GetEscapedSize
+uint GetEscapeLen
(
- // returns the needed buffer size for PrintEscapedString()
+ // returns the extra size needed for escapes.
+ // Add 'src_len' to get the escaped string size.
+ // Add 'additionally 4 to get a good buffer size.
ccp source, // NULL or string to print
int src_len, // length of string. if -1, str is null terminated
@@ -1208,14 +1210,15 @@ uint GetEscapedSize
)
{
const CharMode_t utf8 = char_mode & CHMD_UTF8;
- const CharMode_t allow_e = char_mode & CHMD_ESC;
+ const int esc_size = char_mode & CHMD_ESC ? 1 : 3;
+ const int pipe_size = char_mode & CHMD_PIPE ? 1 : 0;
if ( !source || !*source )
- return 1;
+ return 0;
ccp str = source;
ccp end = src_len < 0 ? 0 : str + src_len;
- uint size = 4; // +4 for escapes at end; +1 for NULL terminator
+ uint size = 0;
while ( !end || str < end )
{
const u8 ch = (u8)*str++;
@@ -1224,7 +1227,7 @@ uint GetEscapedSize
case 0:
if (!end)
return size;
- size += 4;
+ size += 3;
break;
case '\\':
@@ -1235,20 +1238,22 @@ uint GetEscapedSize
case '\r':
case '\t':
case '\v':
- size += 2;
+ size++;
break;
case '\033':
- size += allow_e ? 2 : 4;
+ size += esc_size;
+ break;
+
+ case '|':
+ size += pipe_size;
break;
default:
if ( ch == quote )
- size += 2;
- else if ( ch < ' ' || !utf8 && (ch&0x7f) < ' ' || (ch&0x7f) == 0x7f )
- size += 4;
- else
size++;
+ else if ( ch < ' ' || !utf8 && (ch&0x7f) < ' ' || (ch&0x7f) == 0x7f )
+ size += 3;
}
}
return size;
@@ -1269,15 +1274,16 @@ char * PrintEscapedString
uint *dest_len // not NULL: Store length of result here
)
{
- /////////////////////////////////////////////////////////
- ///// Update GetEscapedSize() on modifications!! /////
- /////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////
+ ///// Update GetEscapeLen() on modifications!! /////
+ ///////////////////////////////////////////////////////
DASSERT(buf);
DASSERT(buf_size>=10);
const CharMode_t utf8 = char_mode & CHMD_UTF8;
const CharMode_t allow_e = char_mode & CHMD_ESC;
+ const CharMode_t esc_pipe = char_mode & CHMD_PIPE;
char *dest = buf;
char *dest_end = dest + buf_size - 4;
@@ -1325,6 +1331,16 @@ char * PrintEscapedString
}
break;
+ case '|':
+ if (esc_pipe)
+ {
+ *dest++ = '\\';
+ *dest++ = '!';
+ }
+ else
+ *dest++ = '|';
+ break;
+
default:
if ( ch == quote )
{
@@ -1360,7 +1376,7 @@ uint ScanEscapedString
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
+ int quote, // -1:auto, 0:none, >0: quotation char
uint *scanned_len // not NULL: Store number of scanned 'source' bytes here
)
{
@@ -1380,6 +1396,8 @@ uint ScanEscapedString
quote = *src++;
have_quote = true;
}
+ else if ( have_quote && *src == quote )
+ src++;
while ( dest < dest_end && src < src_end )
{
@@ -1947,7 +1965,7 @@ mem_t DecodeJSONCirc
ccp source, // NULL or string to decode
int source_len, // length of 'source'. If -1, str is NULL terminated
- int quote // 0:none, -1:auto, >0: quotation char
+ int quote // -1:auto, 0:none, >0: quotation char
)
{
char buf[CIRC_BUF_MAX_ALLOC+10];
@@ -1965,6 +1983,160 @@ mem_t DecodeJSONCirc
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
+// [[hex]]
+
+uint EncodeHex
+(
+ // 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)
+ ccp digits // digits to use, eg. LoDigits[] (=fallback) or HiDigits[]
+)
+{
+ DASSERT(buf);
+ DASSERT(buf_size>2);
+
+ if (!digits)
+ digits = LoDigits;
+
+ char *dest = buf;
+ char *dest_end = dest + buf_size - 1;
+
+ if (!source)
+ source = "";
+ ccp str = source;
+ ccp end = str + ( source_len < 0 ? strlen(str) : source_len );
+
+ while ( dest < dest_end && str < end )
+ {
+ const u8 ch = (u8)*str++;
+ *dest++ = digits[ch>>4];
+ *dest++ = digits[ch&15];
+ }
+ *dest = 0;
+ return dest - buf;
+}
+
+//-----------------------------------------------------------------------------
+// [[hex]]
+
+mem_t EncodeHexCirc
+(
+ // 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)
+ ccp digits // digits to use, eg. LoDigits[] (=fallback) or HiDigits[]
+)
+{
+ char buf[CIRC_BUF_MAX_ALLOC+10];
+ mem_t mem;
+ mem.len = EncodeHex(buf,sizeof(buf),source,source_len,digits);
+ if ( mem.len < CIRC_BUF_MAX_ALLOC )
+ mem.ptr = CopyCircBuf(buf,mem.len+1);
+ else
+ {
+ mem.ptr = 0;
+ mem.len = 0;
+ }
+ return mem;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// [[hex]]
+
+uint DecodeHex
+(
+ // 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
+ int quote, // -1:auto, 0:none, >0: quotation char
+ uint *scanned_len // not NULL: Store number of scanned 'str' bytes here
+)
+{
+ DASSERT(buf);
+ DASSERT(buf_size>3);
+ DASSERT(source);
+
+ char *dest = buf;
+ char *dest_end = dest + buf_size - 1;
+
+ ccp src = source;
+ ccp src_end = src + ( source_len < 0 ? strlen(src) : source_len );
+
+ bool have_quote = quote > 0;
+ if ( quote == -1 && src < src_end && ( *src == '"' || *src == '\'' ))
+ {
+ quote = *src++;
+ have_quote = true;
+ }
+
+ while ( dest < dest_end && src < src_end )
+ {
+ u8 hi = TableNumbers[(u8)*src];
+ if ( hi >= 16 )
+ break;
+ hi <<= 4;
+
+ u8 lo = ++src < src_end ? TableNumbers[(u8)*src] : 0;
+ if ( lo >= 16 )
+ {
+ *dest++ = hi;
+ break;
+ }
+ *dest++ = hi | lo;
+ src++;
+ }
+
+ if (scanned_len)
+ {
+ if ( have_quote && src < src_end && *src == quote )
+ src++;
+ *scanned_len = src - source;
+ }
+
+ *dest = 0;
+ return dest - buf;
+}
+
+//-----------------------------------------------------------------------------
+// [[hex]]
+
+mem_t DecodeHexCirc
+(
+ // 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
+ int quote // -1:auto, 0:none, >0: quotation char
+)
+{
+ char buf[CIRC_BUF_MAX_ALLOC+10];
+ mem_t mem;
+ mem.len = DecodeHex(buf,sizeof(buf),source,source_len,quote,0);
+ if ( mem.len < CIRC_BUF_MAX_ALLOC )
+ mem.ptr = CopyCircBuf(buf,mem.len+1);
+ else
+ {
+ mem.ptr = 0;
+ mem.len = 0;
+ }
+ return mem;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
uint DecodeByMode
(
@@ -1996,10 +2168,12 @@ uint DecodeByMode
switch (emode)
{
case ENCODE_STRING:
+ case ENCODE_PIPE:
len = ScanEscapedString(buf,buf_size,source,slen,false,-1,scanned_len);
break;
case ENCODE_UTF8:
+ case ENCODE_PIPE8:
len = ScanEscapedString(buf,buf_size,source,slen,true,-1,scanned_len);
break;
@@ -2020,6 +2194,10 @@ uint DecodeByMode
len = DecodeJSON(buf,buf_size,source,slen,-1,scanned_len);
break;
+ case ENCODE_HEX:
+ len = DecodeHex(buf,buf_size,source,slen,-1,scanned_len);
+ break;
+
default:
if ( slen < 0 )
len = StringCopyS(buf,buf_size,source) - buf;
@@ -2066,6 +2244,8 @@ mem_t DecodeByModeMem
{
case ENCODE_STRING:
case ENCODE_UTF8:
+ case ENCODE_PIPE:
+ case ENCODE_PIPE8:
need = slen + 5;
break;
@@ -2076,6 +2256,10 @@ mem_t DecodeByModeMem
need = ( 3*slen ) / 4 + 12;
break;
+ case ENCODE_HEX:
+ need = (slen+3)/2;
+ break;
+
//case ENCODE_JSON: // [[json]]
default:
need = slen + 3; // at least 3 bytes
@@ -2215,7 +2399,15 @@ uint EncodeByMode
break;
case ENCODE_UTF8:
- PrintEscapedString(buf,buf_size,source,slen,CHMD__ALL,0,&len);
+ PrintEscapedString(buf,buf_size,source,slen,CHMD__MODERN,0,&len);
+ break;
+
+ case ENCODE_PIPE:
+ PrintEscapedString(buf,buf_size,source,slen,CHMD_IF_REQUIRED|CHMD_PIPE,0,&len);
+ break;
+
+ case ENCODE_PIPE8:
+ PrintEscapedString(buf,buf_size,source,slen,CHMD__MODERN|CHMD_IF_REQUIRED|CHMD_PIPE,0,&len);
break;
case ENCODE_BASE64:
@@ -2242,6 +2434,10 @@ uint EncodeByMode
len = EncodeJSON(buf,buf_size,source,slen);
break;
+ case ENCODE_HEX:
+ len = EncodeHex(buf,buf_size,source,slen,0);
+ break;
+
default:
if ( slen < 0 )
len = StringCopyS(buf,buf_size,source) - buf;
@@ -2284,6 +2480,8 @@ mem_t EncodeByModeMem
{
case ENCODE_STRING:
case ENCODE_UTF8:
+ case ENCODE_PIPE:
+ case ENCODE_PIPE8:
need = slen * 4 + 5;
break;
@@ -2294,6 +2492,10 @@ mem_t EncodeByModeMem
need = ( 4*slen ) / 3 + 10;
break;
+ case ENCODE_HEX:
+ need = 2*slen + 1;
+ break;
+
case ENCODE_JSON: // [[json]]
{
need = slen + 1;
@@ -2330,6 +2532,79 @@ mem_t EncodeByModeMem
/////////////// escape/quote strings, alloc space ///////////////
///////////////////////////////////////////////////////////////////////////////
+exmem_t EscapeStringEx
+(
+ // Returns an exmem_t struct. If not quoted (CHMD_IF_REQUIRED) it returns 'src'
+ // Use FreeExMem(&result) to free possible alloced result.
+
+ cvp src, // NULL or source
+ int src_len, // size of 'src'. If -1: Use strlen(src)
+ cvp return_if_null, // return this, if 'src==NULL'
+ cvp return_if_empty, // return this, if src is empty (have no chars)
+ CharMode_t char_mode, // how to escape (CHMD_*)
+ char quote, // quoting character: " or ' or $ (for $'...')
+ bool try_circ // use circ-buffer, if result is small enough
+)
+{
+ if (!src)
+ return ExMemByString((char*)return_if_null);
+
+ if ( src_len < 0 )
+ src_len = strlen(src);
+ if (!src_len)
+ return ExMemByString((char*)return_if_empty);
+
+ char quote_char;
+ uint quote_mode;
+ if ( quote == '$' )
+ {
+ quote_mode = 3;
+ quote_char = '\'';
+ }
+ else if (quote)
+ {
+ quote_mode = 2;
+ quote_char = quote;
+ }
+ else
+ {
+ quote_mode = 0;
+ quote_char = '"';
+ }
+
+ uint size = GetEscapeLen(src,src_len,char_mode,quote_char);
+ if ( !size && char_mode & CHMD_IF_REQUIRED )
+ return ExMemByS(src,src_len);
+
+ size += quote_mode + src_len + 4;
+ const bool use_circ = try_circ && size <= CIRC_BUF_MAX_ALLOC;
+ char *buf = use_circ ? GetCircBuf(size) : MALLOC(size);
+
+ uint len;
+ if ( quote_mode == 3 )
+ {
+ PrintEscapedString(buf+2,size-3,src,src_len,char_mode,quote_char,&len);
+ buf[0] = '$';
+ buf[1] = buf[len+2] = quote_char;
+ buf[len+3] = 0;
+
+ }
+ else if ( quote_mode == 2 )
+ {
+ PrintEscapedString(buf+1,size-2,src,src_len,char_mode,quote_char,&len);
+ buf[0] = buf[len+1] = quote_char;
+ buf[len+2] = 0;
+ }
+ else
+ PrintEscapedString(buf,size,src,src_len,char_mode,quote_char,&len);
+
+ exmem_t res = { .data={ buf, len+quote_mode },
+ .is_circ_buf = use_circ, .is_alloced = !use_circ };
+ return res;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
char * EscapeString
(
// Returns a pointer.
@@ -2353,6 +2628,14 @@ char * EscapeString
if (!src_len)
return (char*)return_if_empty;
+ #if 1
+ exmem_t res = EscapeStringEx(src,src_len,return_if_null,return_if_empty,char_mode,quote,try_circ);
+ if (dest_len)
+ *dest_len = res.data.len;
+ return res.is_circ_buf || res.is_alloced
+ ? (char*)res.data.ptr
+ : MEMDUP(res.data.ptr,res.data.len);
+ #else // [[2do]] [[obsolete]]
char quote_char;
uint quote_mode;
if ( quote == '$' )
@@ -2371,7 +2654,18 @@ char * EscapeString
quote_char = '"';
}
- uint size = GetEscapedSize(src,src_len,char_mode,quote_char) + quote_mode;
+ uint size = GetEscapeLen(src,src_len,char_mode,quote_char);
+ if ( !size && char_mode & CHMD_IF_REQUIRED )
+ {
+ char *buf = try_circ && size <= CIRC_BUF_MAX_ALLOC ? GetCircBuf(src_len+1) : MALLOC(src_len+1);
+ memcpy(buf,src,src_len);
+ buf[src_len] = 0;
+ if (dest_len)
+ *dest_len = src_len;
+ return buf;
+ }
+
+ size += quote_mode + src_len + 4;
char *buf = try_circ && size <= CIRC_BUF_MAX_ALLOC ? GetCircBuf(size) : MALLOC(size);
uint len;
@@ -2395,6 +2689,7 @@ char * EscapeString
if (dest_len)
*dest_len = len + quote_mode;
return buf;
+ #endif
};
//
@@ -6630,6 +6925,7 @@ char * ScanEscape
case 'r': code = '\r'; break;
case 't': code = '\t'; break;
case 'v': code = '\v'; break;
+ case '!': code = '|'; break;
case 'x':
src = ScanNumber(&code,src,src_end,16,2);
@@ -8223,7 +8519,8 @@ char * ScanSizeRange
{
have_d1 = *source == ':' && opt & RAOPT_COLON
|| *source == '#' && opt & RAOPT_HASH
- || *source == ',' && opt & RAOPT_COMMA;
+ || *source == ',' && opt & RAOPT_COMMA
+ || *source == '-' && (opt & (RAOPT_COMMA|RAOPT_NEG)) == RAOPT_COMMA;
}
char *end = have_d1 ? (char*)source
@@ -8242,7 +8539,7 @@ char * ScanSizeRange
|| *end == '-' && opt & RAOPT_MINUS;
const bool have_size = *end == '#' && opt & RAOPT_HASH
|| *end == ',' && opt & RAOPT_COMMA;
-
+ PRINT0("have_d1=%d, have_range=%d, have_size=%d, %.0g:%.0g |%s|\n",have_d1,have_range,have_size,d1,d2,end);
if ( have_range || have_size )
{
if ( d1 < 0 && max_value > 0 && opt & RAOPT_NEG )
@@ -9489,6 +9786,40 @@ float double2float ( double d )
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
+u64 MulDivU64 ( u64 factor1, u64 factor2, u64 divisor )
+{
+ #if HAVE_INT128
+
+ return (u128)factor1 * (u128)factor2 / divisor;
+
+ #else
+
+ if ( !factor1 || !factor2 )
+ return 0;
+
+ const double product = (double)factor1 * (double)factor2;
+ return product < 0xfffffffffffffff0
+ ? factor1 * factor2 / divisor
+ : (u64) trunc( product / divisor );
+
+ #endif
+}
+
+//-----------------------------------------------------------------------------
+
+s64 MulDivS64 ( s64 factor1, s64 factor2, s64 divisor )
+{
+ bool neg = false;
+ if ( factor1 < 0 ) { factor1 = -factor1; neg = !neg; }
+ if ( factor2 < 0 ) { factor2 = -factor2; neg = !neg; }
+ if ( divisor < 0 ) { divisor = -divisor; neg = !neg; }
+ s64 r = MulDivU64(factor1,factor2,divisor);
+ return neg ? -r : r;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
ccp PrintNiceID4 ( uint id )
{
if (!id)
diff --git a/project/dclib/dclib-numeric.h b/project/dclib/dclib-numeric.h
index 5ab36ef..8cca5a9 100644
--- a/project/dclib/dclib-numeric.h
+++ b/project/dclib/dclib-numeric.h
@@ -819,6 +819,11 @@ static inline s64 double2int64 ( double d ) { return (s64) trunc (d+0.5); }
///////////////////////////////////////////////////////////////////////////////
+u64 MulDivU64 ( u64 factor1, u64 factor2, u64 divisor );
+s64 MulDivS64 ( s64 factor1, s64 factor2, s64 divisor );
+
+///////////////////////////////////////////////////////////////////////////////
+
// all values are multiple of 26*26*100 = 67600 = 0x00010810
#define GOOD_MAX_NICE4_5 67600 // 1 * 67600
#define GOOD_MAX_NICE4_6 946400 // 14 * 67600
diff --git a/project/dclib/dclib-parser.c b/project/dclib/dclib-parser.c
new file mode 100644
index 0000000..2391cbc
--- /dev/null
+++ b/project/dclib/dclib-parser.c
@@ -0,0 +1,150 @@
+
+/***************************************************************************
+ * *
+ * _____ ____ *
+ * | __ \ / __ \ _ _ _____ *
+ * | | \ \ / / \_\ | | | | _ \ *
+ * | | \ \| | | | | | |_| | *
+ * | | | || | | | | | ___/ *
+ * | | / /| | __ | | | | _ \ *
+ * | |__/ / \ \__/ / | |___| | |_| | *
+ * |_____/ \____/ |_____|_|_____/ *
+ * *
+ * Wiimms source code library *
+ * *
+ ***************************************************************************
+ * *
+ * Copyright (c) 2012-2022 by Dirk Clemens <wiimm@wiimm.de> *
+ * *
+ ***************************************************************************
+ * *
+ * This library 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 library 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 *
+ * *
+ ***************************************************************************/
+
+#define _GNU_SOURCE 1
+
+#include "dclib-basics.h"
+#include "dclib-parser.h"
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// ScanText_t ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+void SetupScanText ( ScanText_t *st, cvp data, uint data_size )
+{
+ DASSERT(st);
+ memset(st,0,sizeof(*st));
+ st->data = data;
+ st->data_size = data_size;
+ st->ignore_comments = true;
+
+ RewindScanText(st);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void ResetScanText ( ScanText_t *st )
+{
+ if (st)
+ {
+ if (st->fname_alloced)
+ FreeString(st->fname);
+ memset(st,0,sizeof(*st));
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SetFilenameScanText( ScanText_t *st, ccp fname, CopyMode_t cm )
+{
+ DASSERT(st);
+ if (st->fname_alloced)
+ FreeString(st->fname);
+ st->fname = CopyString(fname,cm,&st->fname_alloced);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void RewindScanText ( ScanText_t *st )
+{
+ DASSERT(st);
+
+ st->ptr = st->data;
+ st->eot = st->data + st->data_size;
+ st->line = st->data;
+ st->eol = st->data;
+
+ st->is_eot = !st->ptr || st->ptr >= st->eot;
+ st->is_section = false;
+ st->is_term = st->is_eot;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool NextLineScanText ( ScanText_t *st )
+{
+ DASSERT(st);
+ st->is_section = false;
+
+ ccp ptr = st->ptr;
+ ccp eot = st->eot;
+ if ( !ptr || ptr >= eot )
+ {
+ st->line = st->eol = ptr;
+ st->is_eot = st->is_term = true;
+ return false;
+ }
+
+ while ( ptr < eot )
+ {
+ // skip leading spaced and controls
+ while ( ptr < eot && (uchar)*ptr <= ' ' )
+ ptr++;
+
+ ccp line = ptr;
+ while ( ptr < eot && *ptr && *ptr != '\r' && *ptr != '\n' )
+ ptr++;
+ ccp eol = ptr;
+ while ( eol > line && eol[-1] == ' ' || eol[-1] == '\t' )
+ eol--;
+
+ if ( line == eol || *line == '#' && st->ignore_comments )
+ continue;
+ if ( st->detect_sections > 0
+ && *line == '['
+ && eol[-1] == ']'
+ && !memchr(line+1,'[',eol-line-2)
+ && !memchr(line+1,']',eol-line-2)
+ )
+ {
+ st->is_section = true;
+ }
+
+ st->line = line;
+ st->eol = eol;
+ break;
+ }
+
+ st->ptr = ptr;
+ st->is_eot = ptr >= eot;
+ st->is_term = st->is_eot || st->is_section;
+ return !st->is_term;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// END ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
diff --git a/project/dclib/dclib-parser.h b/project/dclib/dclib-parser.h
new file mode 100644
index 0000000..b7fa301
--- /dev/null
+++ b/project/dclib/dclib-parser.h
@@ -0,0 +1,89 @@
+
+/***************************************************************************
+ * *
+ * _____ ____ *
+ * | __ \ / __ \ _ _ _____ *
+ * | | \ \ / / \_\ | | | | _ \ *
+ * | | \ \| | | | | | |_| | *
+ * | | | || | | | | | ___/ *
+ * | | / /| | __ | | | | _ \ *
+ * | |__/ / \ \__/ / | |___| | |_| | *
+ * |_____/ \____/ |_____|_|_____/ *
+ * *
+ * Wiimms source code library *
+ * *
+ ***************************************************************************
+ * *
+ * Copyright (c) 2012-2022 by Dirk Clemens <wiimm@wiimm.de> *
+ * *
+ ***************************************************************************
+ * *
+ * This library 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 library 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_PARSER_H
+#define DCLIB_PARSER_H 1
+
+#include "dclib-types.h"
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// ScanText_t ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// [[ScanText_t]]
+
+typedef struct ScanText_t
+{
+ //-- base data
+
+ ccp data; // begin of text
+ uint data_size; // total size of text
+
+ ccp fname; // NULL or filename for messages
+ bool fname_alloced; // true: call FreeString(fname)
+
+ //-- options
+
+ bool ignore_comments; // true: ignore lines with leading '#'
+ int detect_sections; // >0: detect lines of format '[...]'
+
+ //-- current statee
+
+ ccp ptr; // current text position
+ ccp eot; // end of text
+ ccp line; // current line
+ ccp eol; // end of current line
+
+ bool is_eot; // end of text reached
+ bool is_section; // new section reached
+ bool is_term; // := is_eot || is_section
+}
+ScanText_t;
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SetupScanText ( ScanText_t *st, cvp data, uint data_size );
+void ResetScanText ( ScanText_t *st );
+void SetFilenameScanText( ScanText_t *st, ccp fname, CopyMode_t cm );
+
+void RewindScanText ( ScanText_t *st );
+bool NextLineScanText ( ScanText_t *st );
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// E N D ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+#endif // DCLIB_PARSER_H
+
diff --git a/project/dclib/dclib-regex.c b/project/dclib/dclib-regex.c
index f879566..3ee51bf 100644
--- a/project/dclib/dclib-regex.c
+++ b/project/dclib/dclib-regex.c
@@ -340,6 +340,7 @@ int ReplaceRegex
return -ERR_INVALID_DATA;
ClearFastBuf(res);
+ res->buf[0] = 0;
if ( !re || !re->valid )
return -ERR_INVALID_DATA;
diff --git a/project/dclib/dclib-tables.c b/project/dclib/dclib-tables.c
index 629e805..310e9a2 100644
--- a/project/dclib/dclib-tables.c
+++ b/project/dclib/dclib-tables.c
@@ -442,6 +442,9 @@ const sizeof_info_t sizeof_info_linux[] =
SIZEOF_INFO_ENTRY(int)
SIZEOF_INFO_ENTRY(long)
SIZEOF_INFO_ENTRY(long long)
+ #ifdef __SIZEOF_INT128__
+ SIZEOF_INFO_ENTRY(__int128_t)
+ #endif
SIZEOF_INFO_ENTRY(float)
SIZEOF_INFO_ENTRY(double)
SIZEOF_INFO_ENTRY(long double)
@@ -471,6 +474,10 @@ const sizeof_info_t sizeof_info_dclib[] =
SIZEOF_INFO_ENTRY(u16)
SIZEOF_INFO_ENTRY(u32)
SIZEOF_INFO_ENTRY(u64)
+ #if HAVE_INT128
+ SIZEOF_INFO_ENTRY(u128)
+ #endif
+ SIZEOF_INFO_ENTRY(intx_t)
SIZEOF_INFO_ENTRY(mem_t)
SIZEOF_INFO_ENTRY(exmem_t)
@@ -497,6 +504,7 @@ const sizeof_info_t sizeof_info_dclib[] =
SIZEOF_INFO_ENTRY(Escape_t)
SIZEOF_INFO_TITLE("dcLib buffers")
+ SIZEOF_INFO_ENTRY(exmem_dest_t)
SIZEOF_INFO_ENTRY(sha1_hash_t)
SIZEOF_INFO_ENTRY(sha1_hex_t)
SIZEOF_INFO_ENTRY(sha1_id_t)
@@ -509,6 +517,7 @@ const sizeof_info_t sizeof_info_dclib[] =
SIZEOF_INFO_ENTRY(GrowBuffer_t)
SIZEOF_INFO_TITLE("dcLib lists")
+ SIZEOF_INFO_ENTRY(mem_src_t)
SIZEOF_INFO_ENTRY(mem_list_t)
SIZEOF_INFO_ENTRY(exmem_key_t)
SIZEOF_INFO_ENTRY(exmem_list_t)
@@ -546,6 +555,7 @@ const sizeof_info_t sizeof_info_dclib[] =
#endif
SIZEOF_INFO_ENTRY(search_file_t)
SIZEOF_INFO_ENTRY(search_file_list_t)
+ SIZEOF_INFO_ENTRY(search_paths_stat_t)
SIZEOF_INFO_ENTRY(CatchOutput_t)
SIZEOF_INFO_ENTRY(SectionInfo_t)
SIZEOF_INFO_ENTRY(stat_file_count_t)
diff --git a/project/dclib/dclib-types.h b/project/dclib/dclib-types.h
index 7818bc0..1cea28e 100644
--- a/project/dclib/dclib-types.h
+++ b/project/dclib/dclib-types.h
@@ -362,6 +362,47 @@ typedef float float32; // float as 32 bit binary data, endian is file dependent
#define S64_MAX INT64_MAX
///////////////////////////////////////////////////////////////////////////////
+// int128 support
+
+#undef HAVE_INT128
+#ifdef __SIZEOF_INT128__
+
+ #define HAVE_INT128 1
+
+ typedef __int128_t s128;
+ typedef __uint128_t u128;
+
+#else
+
+ #define HAVE_INT128 0
+
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// [[intx_t]]
+
+typedef union intx_t
+{
+ s8 s8[16];
+ u8 u8[16];
+
+ s16 s16[8];
+ u16 u16[8];
+
+ s32 s32[4];
+ u32 u32[4];
+
+ s64 s64[2];
+ u64 u64[2];
+
+ #if HAVE_INT128
+ s128 s128[1];
+ u128 u128[1];
+ #endif
+}
+intx_t;
+
+///////////////////////////////////////////////////////////////////////////////
#ifndef DCLIB_BASIC_TYPES
#define DCLIB_BASIC_TYPES 1
diff --git a/project/dclib/dclib-utf8.h b/project/dclib/dclib-utf8.h
index c4d9380..5236a4e 100644
--- a/project/dclib/dclib-utf8.h
+++ b/project/dclib/dclib-utf8.h
@@ -41,6 +41,7 @@
///////////////////////////////////////////////////////////////////////////////
///// this software is taken from dcLib2 and now publiced under GPL2. /////
///////////////////////////////////////////////////////////////////////////////
+// [[dcUnicodeConsts]]
typedef enum dcUnicodeConsts
{
@@ -54,6 +55,7 @@ typedef enum dcUnicodeConsts
} dcUnicodeConsts;
///////////////////////////////////////////////////////////////////////////////
+// [[dcUTF8Mode]]
typedef enum dcUTF8Mode
{
diff --git a/project/dclib/dclib-vector.c b/project/dclib/dclib-vector.c
index af18888..378fa82 100644
--- a/project/dclib/dclib-vector.c
+++ b/project/dclib/dclib-vector.c
@@ -1059,9 +1059,9 @@ u64 N_MatrixD_inverse = 0; // total number of inverse transformations
void InitializeMatrixD ( MatrixD_t * mat )
{
DASSERT(mat);
- const uint seqnum = mat->valid ? mat->sequence_number : 0;
+// const uint seqnum = mat->valid ? mat->sequence_number : 0;
memset(mat,0,sizeof(*mat));
- mat->sequence_number = seqnum;
+// mat->sequence_number = seqnum;
mat->scale.x = mat->scale.y = mat->scale.z = 1.0;
mat->scale_origin.x = mat->scale_origin.y = mat->scale_origin.z = 0.0;
diff --git a/project/dclib/lib-bmg.c b/project/dclib/lib-bmg.c
index 0540243..9b7f5fd 100644
--- a/project/dclib/lib-bmg.c
+++ b/project/dclib/lib-bmg.c
@@ -3664,10 +3664,38 @@ enumError SaveRawBMG
SetFileAttrib(&F.fatt,&bmg->fatt,0);
if ( fwrite(bmg->raw_data,1,bmg->raw_data_size,F.f) != bmg->raw_data_size )
- FILEERROR1(&F,ERR_WRITE_FAILED,"Write failed: %s\n",fname);
+ err = FILEERROR1(&F,ERR_WRITE_FAILED,"Write failed: %s\n",fname);
return ResetFile(&F,set_time);
}
+///////////////////////////////////////////////////////////////////////////////
+
+enumError SaveRawFileBMG
+(
+ bmg_t * bmg, // pointer to valid bmg
+ FILE * f, // valid output file
+ ccp fname // NULL or filename for error messages
+)
+{
+ DASSERT(bmg);
+
+
+ //--- create raw data
+
+ enumError err = CreateRawBMG(bmg);
+ if (err)
+ return err;
+ DASSERT(bmg->raw_data);
+ DASSERT(bmg->raw_data_size);
+
+
+ //--- write to file
+
+ if ( fwrite(bmg->raw_data,1,bmg->raw_data_size,f) != bmg->raw_data_size )
+ err = ERROR1(ERR_WRITE_FAILED,"Write failed: %s\n",fname?fname:"?");
+ return err;
+}
+
//
///////////////////////////////////////////////////////////////////////////////
/////////////// SaveTextBMG() ///////////////
@@ -3741,15 +3769,16 @@ char * PrintAttribBMG
///////////////////////////////////////////////////////////////////////////////
static void print_message
- ( File_t *F, bmg_t *bmg, const bmg_item_t *bi, ccp mid_name )
+ ( FILE *f, bmg_t *bmg, const bmg_item_t *bi, ccp mid_name )
{
+ DASSERT(f);
DASSERT(bmg);
DASSERT(bi);
if ( bmg->active_cond != bi->cond )
{
bmg->active_cond = bi->cond;
- fprintf(F->f,"@? %x\n",bmg->active_cond);
+ fprintf(f,"@? %x\n",bmg->active_cond);
}
ccp slot;
@@ -3779,14 +3808,14 @@ static void print_message
if ( bmg->attrib_used == 4 )
{
// classic, compatible with all versions
- fprintf(F->f,"%s\t~%s 0x%08x\r\n",mid_name,slot,be32(bi->attrib));
+ fprintf(f,"%s\t~%s 0x%08x\r\n",mid_name,slot,be32(bi->attrib));
}
else
{
// use new attrib vector
PrintAttribBMG( attrib, sizeof(attrib),
bi->attrib, bi->attrib_used, bmg->attrib, true );
- fprintf(F->f,"%s\t~%s %s\r\n",mid_name,slot,attrib);
+ fprintf(f,"%s\t~%s %s\r\n",mid_name,slot,attrib);
}
}
@@ -3806,10 +3835,10 @@ static void print_message
snprintf(attrib,sizeof(attrib),"%s\t",mid_name);
if ( bi->text == bmg_null_entry )
- fprintf(F->f,"%s/\r\n",attrib);
+ fprintf(f,"%s/\r\n",attrib);
else if ( bi->text )
{
- fputs(attrib,F->f);
+ fputs(attrib,f);
const int use_colors = opt_bmg_colors != 1
? opt_bmg_colors
: bmg->use_color_names > 0;
@@ -3870,7 +3899,7 @@ static void print_message
if ( good_break && good_break < end - 8 )
ptr = good_break;
- fprintf(F->f,"%s %.*s\r\n", sep, (int)(ptr-start), start );
+ fprintf(f,"%s %.*s\r\n", sep, (int)(ptr-start), start );
sep = "\t+";
} while ( ptr < end );
@@ -3885,17 +3914,47 @@ enumError SaveTextBMG
ccp fname, // filename of destination
FileMode_t fmode, // create-file mode
bool set_time, // true: set time stamps
- bool force_numeric, // true: force numric MIDs
+ bool force_numeric, // true: force numeric MIDs
uint brief_count // >0: suppress syntax info
// >1: suppress all comments
// >2: suppress '#BMG' magic
)
{
- // use DOS/Windows line format -> unix can handle it ;)
-
DASSERT(bmg);
DASSERT(fname);
PRINT("SaveTextBMG(%s,%d)\n",fname,set_time);
+
+ //--- open file
+
+ File_t F;
+ enumError err = CreateFile(&F,true,fname,fmode);
+ if ( err > ERR_WARNING || !F.f )
+ return err;
+ SetFileAttrib(&F.fatt,&bmg->fatt,0);
+
+ err = SaveTextFileBMG(bmg,F.f,fname,force_numeric,brief_count);
+
+ ResetFile(&F,set_time);
+ return err;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+
+enumError SaveTextFileBMG
+(
+ bmg_t * bmg, // pointer to valid bmg
+ FILE * f, // valid output file
+ ccp fname, // NULL or filename for error messages
+ bool force_numeric, // true: force numeric MIDs
+ uint brief_count // >0: suppress syntax info
+ // >1: suppress all comments
+ // >2: suppress '#BMG' magic
+)
+{
+ // use DOS/Windows line format -> unix can handle it ;)
+
+ DASSERT(bmg);
bmg->active_cond = 0;
enum { BRIEF_ALL, BRIEF_NO_SYNTAX, BRIEF_NO_COMMENT, BRIEF_NO_MAGIC };
@@ -3970,19 +4029,11 @@ enumError SaveTextBMG
};
- //--- open file
-
- File_t F;
- enumError err = CreateFile(&F,true,fname,fmode);
- if ( err > ERR_WARNING || !F.f )
- return err;
- SetFileAttrib(&F.fatt,&bmg->fatt,0);
-
const bool print_full = brief_count == BRIEF_ALL && !opt_bmg_export;
if (print_full)
- fwrite(text_head,1,sizeof(text_head)-1,F.f);
+ fwrite(text_head,1,sizeof(text_head)-1,f);
else if ( brief_count < BRIEF_NO_MAGIC )
- fprintf(F.f,"%s\r\n\r\n",BMG_TEXT_MAGIC);
+ fprintf(f,"%s\r\n\r\n",BMG_TEXT_MAGIC);
HavePredifinedSlots(bmg);
bmg->legacy = bmg->legacy != 0;
@@ -4006,7 +4057,7 @@ enumError SaveTextBMG
PrintAttribBMG(abuf,sizeof(abuf),bmg->attrib,bmg->attrib_used,0,true);
if (print_full)
{
- fprintf(F.f,text_param,
+ fprintf(f,text_param,
param_announce,
endian->is_le, bmg->legacy,
encoding, bmg->have_mid, bmg->inf_size, abuf,
@@ -4014,7 +4065,7 @@ enumError SaveTextBMG
param_announce = "";
}
else if ( brief_count < BRIEF_NO_MAGIC )
- fprintf(F.f,"@ENDIAN = %u\r\n"
+ fprintf(f,"@ENDIAN = %u\r\n"
"@LEGACY = %u\r\n"
"@ENCODING = %u\r\n"
"@BMG-MID = %u\r\n"
@@ -4035,12 +4086,12 @@ enumError SaveTextBMG
)
{
if (print_full)
- fprintf(F.f,unknown_param,
+ fprintf(f,unknown_param,
param_announce,
bmg->unknown_inf_0c,
bmg->unknown_mid_0a, bmg->unknown_mid_0c );
else if ( brief_count < BRIEF_NO_MAGIC )
- fprintf(F.f,"@UNKNOWN-INF32-0C = %#x\r\n"
+ fprintf(f,"@UNKNOWN-INF32-0C = %#x\r\n"
"@UNKNOWN-MID16-0A = %#x\r\n"
"@UNKNOWN-MID32-0C = %#x\r\n"
"\r\n",
@@ -4087,14 +4138,14 @@ enumError SaveTextBMG
if (!last_cup)
{
intro = intro_other;
- fprintf(F.f,"\r\n#--- standard track names\r\n\r\n");
+ fprintf(f,"\r\n#--- standard track names\r\n\r\n");
}
else
- fputs("\r\n",F.f);
+ fputs("\r\n",f);
last_cup = cup;
}
snprintf(mid_name,sizeof(mid_name), " T%c%c", cup, idx % 4 + '1' );
- print_message(&F,bmg,bi1,mid_name);
+ print_message(f,bmg,bi1,mid_name);
already_printed[ bi1->mid - MID__VIP_BEG ] = true;
already_printed[ bi2->mid - MID__VIP_BEG ] = true;
@@ -4137,14 +4188,14 @@ enumError SaveTextBMG
if (!last_cup)
{
intro = intro_other;
- fprintf(F.f,"\r\n#--- battle track names\r\n\r\n");
+ fprintf(f,"\r\n#--- battle track names\r\n\r\n");
}
else
- fputs("\r\n",F.f);
+ fputs("\r\n",f);
last_cup = cup;
}
snprintf(mid_name,sizeof(mid_name), " U%c%c", cup, idx % 5 + '1' );
- print_message(&F,bmg,bi1,mid_name);
+ print_message(f,bmg,bi1,mid_name);
already_printed[ bi1->mid - MID__VIP_BEG ] = true;
already_printed[ bi2->mid - MID__VIP_BEG ] = true;
@@ -4175,14 +4226,14 @@ enumError SaveTextBMG
if ( brief_count < BRIEF_NO_COMMENT )
{
intro = intro_other;
- fprintf(F.f,"\r\n#--- online chat\r\n\r\n");
+ fprintf(f,"\r\n#--- online chat\r\n\r\n");
}
for ( ; bi1 < bi1end; bi1++ )
{
DASSERT( bi1->mid >= MID_CHAT_BEG && bi1->mid <= MID_CHAT_END );
snprintf(mid_name,sizeof(mid_name)," M%02u",bi1->mid-MID_CHAT_BEG+1);
- print_message(&F,bmg,bi1,mid_name);
+ print_message(f,bmg,bi1,mid_name);
already_printed[bi1->mid-MID__VIP_BEG] = true;
}
}
@@ -4282,22 +4333,22 @@ enumError SaveTextBMG
while ( sep->mid && mid >= sep->mid )
sep++;
if ( sep > sep_tab+1 && sep[-2].mid == mid && sep[-2].info )
- fprintf(F.f,"\r\n#--- [%x] %s\r\n", mid, sep[-2].info );
+ fprintf(f,"\r\n#--- [%x] %s\r\n", mid, sep[-2].info );
else if ( sep[-1].info )
- fprintf(F.f,"\r\n#--- [%x:%x] %s\r\n",
+ fprintf(f,"\r\n#--- [%x:%x] %s\r\n",
sep[-1].mid, sep->mid-1, sep[-1].info );
else
- fputs("\r\n",F.f);
+ fputs("\r\n",f);
intro = 0;
}
if ( brief_count < BRIEF_NO_COMMENT && intro )
{
- fputs(intro,F.f);
+ fputs(intro,f);
intro = 0;
}
snprintf(mid_name,sizeof(mid_name),"%6x",bi->mid);
- print_message(&F,bmg,bi,mid_name);
+ print_message(f,bmg,bi,mid_name);
}
}
@@ -4309,7 +4360,7 @@ enumError SaveTextBMG
XDump_t xd;
InitializeXDump(&xd);
SetupXDump(&xd,XDUMPC_DUMP);
- xd.f = F.f;
+ xd.f = f;
xd.indent = 1;
xd.prefix = "@X";
xd.eol = "\r\n";
@@ -4326,7 +4377,7 @@ enumError SaveTextBMG
raw->total_size, raw->total_size );
char name[20];
- fprintf(F.f,"\r\n#\f\r\n#--------------------------------------"
+ fprintf(f,"\r\n#\f\r\n#--------------------------------------"
"----------------------------------------\r\n\r\n"
"@SECTION \"%s\"\r\n\r\n",
PrintEscapedString( name, sizeof(name),
@@ -4343,8 +4394,7 @@ enumError SaveTextBMG
//--- terminate
if ( brief_count < 2 )
- fputs("\r\n",F.f);
- ResetFile(&F,set_time);
+ fputs("\r\n",f);
return ERR_OK;
}
diff --git a/project/dclib/lib-bmg.h b/project/dclib/lib-bmg.h
index 98d3d9e..636f681 100644
--- a/project/dclib/lib-bmg.h
+++ b/project/dclib/lib-bmg.h
@@ -88,6 +88,9 @@ enum
MID_BCUP_BEG = 0x2489,
MID_BCUP_END = MID_BCUP_BEG + BMG_N_BCUP,
+ BMG_RCUP_TRACKS = 4,
+ BMG_BCUP_TRACKS = 5,
+
MID_ENGINE_BEG = 0x0589,
MID_ENGINE_END = MID_ENGINE_BEG + 4,
@@ -898,13 +901,31 @@ enumError SaveRawBMG
bool set_time // true: set time stamps
);
+enumError SaveRawFileBMG
+(
+ bmg_t * bmg, // pointer to valid bmg
+ FILE * f, // valid output file
+ ccp fname // NULL or filename for error messages
+);
+
enumError SaveTextBMG
(
bmg_t * bmg, // pointer to valid bmg
ccp fname, // filename of destination
FileMode_t fmode, // create-file mode
bool set_time, // true: set time stamps
- bool force_numeric, // true: force numric MIDs
+ bool force_numeric, // true: force numeric MIDs
+ uint brief_count // >0: suppress syntax info
+ // >1: suppress all comments
+ // >2: suppress '#BMG' magic
+);
+
+enumError SaveTextFileBMG
+(
+ bmg_t * bmg, // pointer to valid bmg
+ FILE * f, // valid output file
+ ccp fname, // NULL or filename for error messages
+ bool force_numeric, // true: force numeric MIDs
uint brief_count // >0: suppress syntax info
// >1: suppress all comments
// >2: suppress '#BMG' magic
diff --git a/project/dclib/lib-mkw-def.c b/project/dclib/lib-mkw-def.c
index dbd0e5d..911262e 100644
--- a/project/dclib/lib-mkw-def.c
+++ b/project/dclib/lib-mkw-def.c
@@ -9,7 +9,7 @@
* | |__/ / \ \__/ / | |___| | |_| | *
* |_____/ \____/ |_____|_|_____/ *
* *
- * A php library by Dirk Clemens *
+ * A library by Dirk Clemens *
* *
* Copyright (c) 2014-2022 by Dirk Clemens <develop@cle-mens.de> *
* *
diff --git a/project/dclib/lib-mkw-def.h b/project/dclib/lib-mkw-def.h
index 82c73c4..1f44c4e 100644
--- a/project/dclib/lib-mkw-def.h
+++ b/project/dclib/lib-mkw-def.h
@@ -9,7 +9,7 @@
* | |__/ / \ \__/ / | |___| | |_| | *
* |_____/ \____/ |_____|_|_____/ *
* *
- * A php library by Dirk Clemens *
+ * A library by Dirk Clemens *
* *
* Copyright (c) 2014-2022 by Dirk Clemens <develop@cle-mens.de> *
* *
@@ -65,6 +65,13 @@ MkwTrackCategory_t * GetMkwTrackCategory ( int id );
//
///////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////// misc //////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+#define MKW_MAX_TRACK_SLOT 4095
+
+//
+///////////////////////////////////////////////////////////////////////////////
////////////////////////////////// sizeof /////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
diff --git a/project/dclib/lib-mkw.h b/project/dclib/lib-mkw.h
index f0df9b5..8a19dbb 100644
--- a/project/dclib/lib-mkw.h
+++ b/project/dclib/lib-mkw.h
@@ -89,6 +89,17 @@ enum mkw_consts_t // some constants
MKW_ORIGINAL_BEG = MKW_TRACK_BEG,
MKW_ORIGINAL_END = MKW_ARENA_END,
+ //--- LE-CODE random tracks
+
+ MKW_N_LE_RANDOM = 0x04,
+ MKW_LE_RANDOM_BEG = 0x3e,
+ MKW_LE_RANDOM_END = MKW_LE_RANDOM_BEG + MKW_N_LE_RANDOM,
+
+ //--- LE-CODE extended slots
+
+ MKW_LE_SLOT_BEG = 0x44,
+ MKW_LE_SLOT_END = 0x1000,
+ MKW_N_LE_SLOT = MKW_LE_SLOT_END - MKW_LE_SLOT_BEG,
//--- music ids
@@ -111,6 +122,14 @@ static inline bool IsMkwOriginal ( uint tid )
static inline bool IsMkwCustom ( uint tid )
{ return tid >= MKW_ARENA_END; }
+static inline bool IsLecodeRandom ( uint tid )
+ { return tid >= MKW_LE_RANDOM_BEG && tid < MKW_LE_RANDOM_END; }
+
+static inline bool IsValidLecodeSlot ( uint tid )
+ { return tid < MKW_ARENA_END
+ || tid >= MKW_LE_SLOT_BEG && tid < MKW_LE_SLOT_END
+ || tid >= MKW_LE_RANDOM_BEG && tid < MKW_LE_RANDOM_END; }
+
//
///////////////////////////////////////////////////////////////////////////////
/////////////// 24p support ///////////////