From 06ff18cd020779c226f7c25d22016e06b898f303 Mon Sep 17 00:00:00 2001 From: Wiimm Date: Sat, 9 Jul 2022 11:48:24 +0200 Subject: SZS v2.28a.beta --- project/dclib/Makefile.inc | 2 +- project/dclib/dclib-basics.c | 753 ++++++++++++++++++++++++++++++++++++++++-- project/dclib/dclib-basics.h | 319 ++++++++++++++++-- project/dclib/dclib-debug.c | 225 ++++++++++--- project/dclib/dclib-debug.h | 68 +++- project/dclib/dclib-file.c | 473 ++++++++++++++++++++++++-- project/dclib/dclib-file.h | 68 +++- project/dclib/dclib-network.c | 8 + project/dclib/dclib-numeric.c | 373 +++++++++++++++++++-- project/dclib/dclib-numeric.h | 5 + project/dclib/dclib-parser.c | 150 +++++++++ project/dclib/dclib-parser.h | 89 +++++ project/dclib/dclib-regex.c | 1 + project/dclib/dclib-tables.c | 10 + project/dclib/dclib-types.h | 41 +++ project/dclib/dclib-utf8.h | 2 + project/dclib/dclib-vector.c | 4 +- project/dclib/lib-bmg.c | 134 +++++--- project/dclib/lib-bmg.h | 23 +- project/dclib/lib-mkw-def.c | 2 +- project/dclib/lib-mkw-def.h | 9 +- project/dclib/lib-mkw.h | 19 ++ 22 files changed, 2576 insertions(+), 202 deletions(-) create mode 100644 project/dclib/dclib-parser.c create mode 100644 project/dclib/dclib-parser.h (limited to 'project/dclib') 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=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 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 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 ) @@ -3324,6 +3632,100 @@ mem_t MemCat3A ( const mem_t m1, const mem_t m2, const mem_t m3 ) return res; } +/////////////////////////////////////////////////////////////////////////////// + +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 @@ -3605,6 +4007,155 @@ ccp PrintExMem ( const exmem_t * em ) // print to circ-buf len, em->data.len, ebuf ); } +// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +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); +} // /////////////////////////////////////////////////////////////////////////////// @@ -693,6 +711,20 @@ mem_t; 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); @@ -878,6 +910,21 @@ exmem_t; 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 @@ -940,6 +987,32 @@ static inline exmem_t ExMemDup ( cvp src, int size ) return em; } +//----------------------------------------------------------------------------- + +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 @@ -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 @@ -39,6 +39,21 @@ #include #include +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// 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 /////////////// @@ -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; @@ -3098,6 +3204,24 @@ bool IsSameFilename ( ccp fn1, ccp fn2 ) return !strcmp(fn1,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; +} + /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// @@ -3620,6 +3744,317 @@ ccp GetBlockDeviceHolder ( ccp name, ccp sep, int *ret_level ) return item->data; } +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// 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]] @@ -1007,6 +1020,43 @@ int SearchFiles void *param // third parameter of func() ); +/////////////////////////////////////////////////////////////////////////////// +// [[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]; @@ -1963,6 +1981,160 @@ mem_t DecodeJSONCirc return mem; } +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// [[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; +} + + /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// @@ -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 * + * * + *************************************************************************** + * * + * 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 * + * * + *************************************************************************** + * * + * 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 @@ -361,6 +361,47 @@ typedef float float32; // float as 32 bit binary data, endian is file dependent #define S64_MIN INT64_MIN #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 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 * * * 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 * * * @@ -63,6 +63,13 @@ MkwTrackCategory_t; 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 /////////////// -- cgit v1.3.1