diff options
Diffstat (limited to '')
| -rw-r--r-- | project/dclib/dclib-basics.c | 934 | ||||
| -rw-r--r-- | project/dclib/dclib-basics.h | 394 | ||||
| -rw-r--r-- | project/dclib/dclib-cli.c | 5 | ||||
| -rw-r--r-- | project/dclib/dclib-color.c | 16 | ||||
| -rw-r--r-- | project/dclib/dclib-debug.c | 141 | ||||
| -rw-r--r-- | project/dclib/dclib-debug.h | 33 | ||||
| -rw-r--r-- | project/dclib/dclib-file.c | 725 | ||||
| -rw-r--r-- | project/dclib/dclib-file.h | 208 | ||||
| -rw-r--r-- | project/dclib/dclib-numeric.c | 139 | ||||
| -rw-r--r-- | project/dclib/dclib-system.h | 37 |
10 files changed, 2329 insertions, 303 deletions
diff --git a/project/dclib/dclib-basics.c b/project/dclib/dclib-basics.c index 7504951..bf0496c 100644 --- a/project/dclib/dclib-basics.c +++ b/project/dclib/dclib-basics.c @@ -34,11 +34,6 @@ #define _GNU_SOURCE 1 -#ifndef WIN_SZS_LIB - // needed for GetTermWidthFD() - #include <sys/ioctl.h> -#endif - #include <string.h> #include <unistd.h> #include <time.h> @@ -47,6 +42,7 @@ #include <errno.h> #include <sys/time.h> #include <fcntl.h> +#include <sys/ioctl.h> #include "dclib-basics.h" #include "dclib-debug.h" @@ -302,6 +298,21 @@ int GetProgramPath { char path[PATH_MAX], path2[PATH_MAX]; +#ifdef __APPLE__ + + //--- read apple path of executable + + extern int _NSGetExecutablePath( char* buf, uint32_t * bufsize ); + + uint32_t size = sizeof(path); + if (!_NSGetExecutablePath(path,&size)) + { + if ( realpath(path,path2) && *path2 ) + return StringCopyS(buf,buf_size,path2) - buf; + return StringCopyS(buf,buf_size,path) - buf; + } + +#else // !__APPLE__ //--- read files of /proc/... @@ -321,6 +332,8 @@ int GetProgramPath return StringCopyS(buf,buf_size,path) - buf; } +#endif // !__APPLE__ + //--- analyze argv0 @@ -377,9 +390,9 @@ int GetProgramPath void FreeString ( ccp str ) { - noTRACE("FreeString(%p) EmptyString=%p MinusString=%p\n", - str, EmptyString, MinusString ); - if ( str != EmptyString && str != EmptyQuote && str != MinusString ) + noTRACE("FreeString(%p) EmptyString=%p MinusString=%p, IsCircBuf=%d\n", + str, EmptyString, MinusString, IsCircBuf(str) ); + if ( str != EmptyString && str != EmptyQuote && str != MinusString && !IsCircBuf(str) ) FREE((char*)str); } @@ -506,19 +519,18 @@ char * StringCat3S ( char * buf, size_t buf_size, ccp src1, ccp src2, ccp src3 ) } /////////////////////////////////////////////////////////////////////////////// -// [[?]] -char * StringCat2A ( ccp src1, ccp src2 ) +char * StringCat2A ( ccp src1, ccp src2 ) { - mem_t mem = MemCat2A( MemByString(src1), MemByString(src2) ); + mem_t mem = MemCat2A( MemByString0(src1), MemByString0(src2) ); return (char*)mem.ptr; } //----------------------------------------------------------------------------- -char * StringCat3A ( ccp src1, ccp src2, ccp src3 ) +char * StringCat3A ( ccp src1, ccp src2, ccp src3 ) { - mem_t mem = MemCat3A( MemByString(src1), MemByString(src2), MemByString(src3) ); + mem_t mem = MemCat3A( MemByString0(src1), MemByString0(src2), MemByString0(src3) ); return (char*)mem.ptr; } @@ -1554,9 +1566,16 @@ static char *circ_ptr = circ_buf; /////////////////////////////////////////////////////////////////////////////// +bool IsCircBuf ( cvp ptr ) +{ + return ptr && (ccp)ptr >= circ_buf && (ccp)ptr < circ_buf + sizeof(circ_buf); +} + +/////////////////////////////////////////////////////////////////////////////// + char * GetCircBuf ( - // never returns NULL, but always ALIGN(4) + // Never returns NULL, but always ALIGN(4) u32 buf_size // wanted buffer size, caller must add 1 for NULL-term // if buf_size > CIRC_BUF_MAX_ALLOC: @@ -1591,7 +1610,7 @@ char * GetCircBuf char * CopyCircBuf ( - // never returns NULL, but always ALIGN(4) + // Never returns NULL, but always ALIGN(4) cvp data, // source to copy u32 data_size // see GetCircBuf() @@ -1606,8 +1625,8 @@ char * CopyCircBuf char * CopyCircBuf0 ( - // never returns NULL, but always ALIGN(4) - // an additional char is alloced and set to NULL + // Like CopyCircBuf(), but an additional char is alloced and set to NULL + // Never returns NULL, but always ALIGN(4). cvp data, // source to copy u32 data_size // see GetCircBuf() @@ -1623,6 +1642,8 @@ char * CopyCircBuf0 char * PrintCircBuf ( + // returns CopyCircBuf0() or EmptyString. + ccp format, // format string for vsnprintf() ... // arguments for 'format' ) @@ -1638,6 +1659,51 @@ char * PrintCircBuf /////////////////////////////////////////////////////////////////////////////// +char * AllocCircBuf +( + // Never returns NULL. Call FreeString(RESULT) to free possible alloced memory. + + cvp src, // NULL or source + int src_len, // len of 'src'; if -1: use strlen(source) + bool try_circ // use circ-buffer, if result is small enough +) +{ + if (!src) + return (char*)EmptyString; + + if ( src_len < 0 ) + src_len = strlen(src); + + return try_circ && src_len <= CIRC_BUF_MAX_ALLOC + ? CopyCircBuf(src,src_len) + : MEMDUP(src,src_len); +} + +/////////////////////////////////////////////////////////////////////////////// + +char * AllocCircBuf0 +( + // Never returns NULL. Call FreeString(RESULT) to free possible alloced memory. + // Like AllocCircBuf(), but an additional char is alloced and set to NULL + + cvp src, // NULL or source + int src_len, // len of 'src'; if -1: use strlen(source) + bool try_circ // use circ-buffer, if result is small enough +) +{ + if (!src) + return (char*)EmptyString; + + if ( src_len < 0 ) + src_len = strlen(src); + + return try_circ && src_len < CIRC_BUF_MAX_ALLOC + ? CopyCircBuf0(src,src_len) + : MEMDUP(src,src_len); // MEMDUP() always add 0-term +} + +/////////////////////////////////////////////////////////////////////////////// + void ReleaseCircBuf ( ccp end_buf, // pointer to end of previous alloced buffer @@ -2408,26 +2474,186 @@ mem_t MemCat3A ( const mem_t m1, const mem_t m2, const mem_t m3 ) // /////////////////////////////////////////////////////////////////////////////// -/////////////// struct mem_list_t /////////////// +/////////////// struct exmem_t /////////////// + +exmem_t EmptyExMem = {{EmptyString,0},0,false,false,false,false}; +exmem_t NullExMem = {{0,0},0,false,false,false,false}; + /////////////////////////////////////////////////////////////////////////////// -void InitializeMemList ( mem_list_t *ml ) +void FreeExMem ( const exmem_t *em ) { - DASSERT(ml); - memset(ml,0,sizeof(*ml)); + if (em) + { + if (em->is_alloced) + FreeString(em->data.ptr); + memset((exmem_t*)em,0,sizeof(*em)); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void FreeExMemCM ( const exmem_t *em, CopyMode_t copy_mode ) +{ + if ( em && copy_mode == CPM_MOVE ) + { + if (em->is_alloced) + FreeString(em->data.ptr); + memset((exmem_t*)em,0,sizeof(*em)); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +exmem_t AllocExMemS +( + cvp src, // NULL or source + int src_len, // len of 'src'; if -1: use strlen(source) + bool try_circ, // use circ-buffer, if result is small enough + cvp orig, // NULL or data to compare + int orig_len // len of 'orig'; if -1: use strlen(source) +) +{ + exmem_t em = {{0}}; + if (src) + { + if ( src_len < 0 ) + src_len = strlen(src); + if (!src_len) + em.data.ptr = EmptyString; + else + { + em.data.len = src_len; + if ( orig + && src_len == ( orig_len < 0 ? strlen(orig) : orig_len ) + && !memcmp(src,orig,src_len) + ) + { + em.data.ptr = orig; + em.is_original = true; + } + else if ( try_circ && src_len <= CIRC_BUF_MAX_ALLOC ) + { + em.data.ptr = CopyCircBuf(src,src_len); + em.is_circ_buf = true; + } + else + { + em.data.ptr = MEMDUP(src,src_len); + em.is_alloced = true; + } + } + } + + return em; } /////////////////////////////////////////////////////////////////////////////// +void AssignExMem ( exmem_t *dest, const exmem_t *source, CopyMode_t copy_mode ) +{ + if ( dest && dest != source ) + { + if (dest->is_alloced) + FreeString(dest->data.ptr); + const bool dest_key_alloced = dest->is_key_alloced; + if (source) + { + switch (copy_mode) + { + case CPM_COPY: + memset(dest,0,sizeof(*dest)); + dest->data.len = source->data.len; + dest->data.ptr = MEMDUP(source->data.ptr,source->data.len); + dest->is_alloced = true; + dest->attrib = source->attrib; + break; + + case CPM_MOVE: + *dest = *source; + memset((exmem_t*)source,0,sizeof(*source)); + break; + + case CPM_LINK: + *dest = *source; + dest->is_original = false; + dest->is_alloced = false; + break; + } + } + else + memset(dest,0,sizeof(*dest)); + dest->is_key_alloced = dest_key_alloced; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +exmem_t CopyExMemS ( ccp string, int slen, CopyMode_t copy_mode ) +{ + exmem_t em = {{0}}; + + if (string) + { + em.data.len = slen < 0 ? strlen(string) : slen; + + switch (copy_mode) + { + case CPM_COPY: + em.data.ptr = MEMDUP(string,em.data.len); + em.is_alloced = true; + break; + + case CPM_MOVE: + em.is_alloced = true; + // fall through + case CPM_LINK: + em.data.ptr = string; + break; + } + } + + return em; +} + +/////////////////////////////////////////////////////////////////////////////// + +ccp PrintExMem ( const exmem_t * em ) // print to circ-buf +{ + if (!em) + return MinusString; + + char ebuf[60]; + uint len; + PrintEscapedString(ebuf,sizeof(ebuf),em->data.ptr,em->data.len,CHMD__MODERN,'"',&len); + + return PrintCircBuf( + "[%c%c%c%c:%x] %u/%u %s", + em->is_key_alloced ? 'a' : '-', // flags: same as in DumpEML() + em->is_alloced ? 'A' : '-', + em->is_circ_buf ? 'C' : '-', + em->is_original ? 'O' : '-', + em->attrib, + len, em->data.len, ebuf ); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// struct mem_list_t /////////////// +/////////////////////////////////////////////////////////////////////////////// + void ResetMemList ( mem_list_t *ml ) { - DASSERT(ml); - FREE(ml->list); - FREE(ml->buf); - memset(ml,0,sizeof(*ml)); + if (ml) + { + FREE(ml->list); + FREE(ml->buf); + memset(ml,0,sizeof(*ml)); + } } /////////////////////////////////////////////////////////////////////////////// +// [[?]] void MoveMemList ( mem_list_t *dest, mem_list_t *src ) { @@ -2448,6 +2674,7 @@ void MoveMemList ( mem_list_t *dest, mem_list_t *src ) } /////////////////////////////////////////////////////////////////////////////// +// [[?]] void NeedBufMemList ( mem_list_t *ml, uint need_size, uint extra_size ) { @@ -2480,6 +2707,7 @@ void NeedBufMemList ( mem_list_t *ml, uint need_size, uint extra_size ) } /////////////////////////////////////////////////////////////////////////////// +// [[?]] void NeedElemMemList ( mem_list_t *ml, uint need_elem, uint need_size ) { @@ -2497,6 +2725,7 @@ void NeedElemMemList ( mem_list_t *ml, uint need_elem, uint need_size ) /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// +// [[?]] void InsertMemListN ( @@ -2643,6 +2872,7 @@ void InsertMemListN /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// +// [[?]] void CatMemListN ( @@ -2705,7 +2935,6 @@ void CatMemListN ? MALLOC(sizeof(*new_list)*need_elem) : dest->list; - //--- assign values char *bufptr = new_buf; @@ -2772,6 +3001,7 @@ void CatMemListN /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// +// [[?]] uint LeftMemList ( mem_list_t *ml, int count ) { @@ -2780,6 +3010,7 @@ uint LeftMemList ( mem_list_t *ml, int count ) } /////////////////////////////////////////////////////////////////////////////// +// [[?]] uint RightMemList ( mem_list_t *ml, int count ) { @@ -2795,6 +3026,7 @@ uint RightMemList ( mem_list_t *ml, int count ) } /////////////////////////////////////////////////////////////////////////////// +// [[?]] uint MidMemList ( mem_list_t *ml, int begin, int count ) { @@ -2820,6 +3052,7 @@ uint MidMemList ( mem_list_t *ml, int begin, int count ) } /////////////////////////////////////////////////////////////////////////////// +// [[?]] uint ExtractMemList ( mem_list_t *ml, int begin, int end ) { @@ -2830,6 +3063,7 @@ uint ExtractMemList ( mem_list_t *ml, int begin, int end ) } /////////////////////////////////////////////////////////////////////////////// +// [[?]] uint ExtractEndMemList ( mem_list_t *ml, int begin, int end ) { @@ -2840,6 +3074,7 @@ uint ExtractEndMemList ( mem_list_t *ml, int begin, int end ) } /////////////////////////////////////////////////////////////////////////////// +// [[?]] uint RemoveMemList ( mem_list_t *ml, int begin, int end ) { @@ -2850,6 +3085,7 @@ uint RemoveMemList ( mem_list_t *ml, int begin, int end ) } /////////////////////////////////////////////////////////////////////////////// +// [[?]] uint RemoveEndMemList ( mem_list_t *ml, int begin, int end ) { @@ -4797,10 +5033,11 @@ const KeywordTab_t KeyTab_OFF_AUTO_ON[] = //----------------------------------------------------------------------------- -int ScanKeywordOffAutoOn +int ScanKeywordOffAutoOnEx ( // returns one of OFFON_* + const KeywordTab_t *keytab, // Keyword table. If NULL, then use KeyTab_OFF_AUTO_ON[] ccp arg, // argument to scan int on_empty, // return this value on empty uint max_num, // >0: additionally accept+return number <= max_num @@ -4810,8 +5047,11 @@ int ScanKeywordOffAutoOn if ( !arg || !*arg ) return on_empty; + if (!keytab) + keytab = KeyTab_OFF_AUTO_ON; + int status; - const KeywordTab_t *key = ScanKeyword(&status,arg,KeyTab_OFF_AUTO_ON); + const KeywordTab_t *key = ScanKeyword(&status,arg,keytab); if (key) return key->id; @@ -4824,7 +5064,7 @@ int ScanKeywordOffAutoOn } if (object) - PrintKeywordError(KeyTab_OFF_AUTO_ON,arg,status,0,object); + PrintKeywordError(keytab,arg,status,0,object); return OFFON_ERROR; } @@ -5465,6 +5705,27 @@ void AppendStringField ( StringField_t * sf, ccp key, bool move_key ) /////////////////////////////////////////////////////////////////////////////// +void AppendUniqueStringField ( StringField_t * sf, ccp key, bool move_key ) +{ + DASSERT(sf); + if (!key) + return; + + ccp * src = sf->field; + ccp * end = sf->field + sf->used; + while ( src < end ) + if (!strcmp(*src++,key)) + { + if (move_key) + FreeString(key); + return; + } + + AppendStringField(sf,key,move_key); +} + +/////////////////////////////////////////////////////////////////////////////// + void SortStringField ( StringField_t * sf ) { DASSERT(sf); @@ -5719,11 +5980,8 @@ void RestoreStateStringField /////////////// ParamField_t /////////////// /////////////////////////////////////////////////////////////////////////////// -void InitializeParamField ( ParamField_t * pf ) -{ - DASSERT(pf); - memset(pf,0,sizeof(*pf)); -} +#undef PARAM_FIELD_GROW +#define PARAM_FIELD_GROW(s) (s)/4+100 /////////////////////////////////////////////////////////////////////////////// @@ -5812,7 +6070,7 @@ static ParamFieldItem_t * InsertParamFieldHelper ( ParamField_t * pf, int idx ) noPRINT("+SF: %u/%u/%u\n",idx,pf->used,pf->size); if ( pf->used == pf->size ) { - pf->size += 0x100; + pf->size += PARAM_FIELD_GROW(pf->size); pf->field = REALLOC(pf->field,pf->size*sizeof(*pf->field)); } DASSERT( idx <= pf->used ); @@ -5825,13 +6083,11 @@ static ParamFieldItem_t * InsertParamFieldHelper ( ParamField_t * pf, int idx ) /////////////////////////////////////////////////////////////////////////////// ParamFieldItem_t * FindInsertParamField - ( ParamField_t * pf, ccp key, bool move_key, bool *old_found ) + ( ParamField_t * pf, ccp key, bool move_key, uint num, bool *old_found ) { if (!key) return 0; - noTRACE("InsertParamField(%s,%x)\n",key,num); - bool found; int idx = FindParamFieldHelper(pf,&found,key); ParamFieldItem_t *item; @@ -5843,9 +6099,9 @@ ParamFieldItem_t * FindInsertParamField } else { - item = InsertParamFieldHelper(pf,idx); + item = InsertParamFieldHelper(pf,idx); item->key = move_key ? key : STRDUP(key); - item->num = 0; + item->num = num; item->data = 0; } @@ -5856,9 +6112,9 @@ ParamFieldItem_t * FindInsertParamField /////////////////////////////////////////////////////////////////////////////// -ParamFieldItem_t * CountParamField ( ParamField_t * pf, ccp key, bool move_key ) +ParamFieldItem_t * IncrementParamField ( ParamField_t * pf, ccp key, bool move_key ) { - ParamFieldItem_t *item = FindInsertParamField(pf,key,move_key,0); + ParamFieldItem_t *item = FindInsertParamField(pf,key,move_key,0,0); if (item) item->num++; return item; @@ -5896,35 +6152,6 @@ bool InsertParamField /////////////////////////////////////////////////////////////////////////////// -ParamFieldItem_t * InsertParamFieldEx - ( ParamField_t * pf, ccp key, bool move_key, uint num, bool *p_found ) -{ - if (!key) - return 0; - - noTRACE("InsertParamField(%s,%x)\n",key,num); - - bool found; - int idx = FindParamFieldHelper(pf,&found,key); - if (p_found) - *p_found = found; - - if (found) - { - if (move_key) - FreeString(key); - return pf->field + idx; - } - - ParamFieldItem_t * dest = InsertParamFieldHelper(pf,idx); - dest->key = move_key ? key : STRDUP(key); - dest->num = num; - dest->data = 0; - return dest; -} - -/////////////////////////////////////////////////////////////////////////////// - bool ReplaceParamField ( ParamField_t * pf, ccp key, bool move_key, uint num, cvp data ) { @@ -5987,7 +6214,7 @@ ParamFieldItem_t * AppendParamField noPRINT(">SF: %u/%u\n",pf->used,pf->size); if ( pf->used == pf->size ) { - pf->size += 0x100; + pf->size += PARAM_FIELD_GROW(pf->size); pf->field = REALLOC(pf->field,pf->size*sizeof(*pf->field)); } TRACE("AppendParamField(%s,%d) %d/%d\n",key,move_key,pf->used,pf->size); @@ -6044,6 +6271,569 @@ uint FindParamFieldHelper ( const ParamField_t * pf, bool * p_found, ccp key ) // /////////////////////////////////////////////////////////////////////////////// +/////////////// exmem_list_t /////////////// +/////////////////////////////////////////////////////////////////////////////// + +#undef EXMEM_LIST_GROW +#define EXMEM_LIST_GROW(s) (s)/2+50 + +//----------------------------------------------------------------------------- + +void ResetEML ( exmem_list_t * eml ) +{ + if (eml) + { + if ( eml->used > 0 ) + { + DASSERT(eml->list); + exmem_key_t *ptr = eml->list, *end; + for ( end = ptr + eml->used; ptr < end; ptr++ ) + { + if (ptr->data.is_key_alloced) + FreeString(ptr->key); + if (ptr->data.is_alloced) + FreeString(ptr->data.data.ptr); + } + } + FREE(eml->list); + + int (*func_cmp)( ccp s1, ccp s2 ) = eml->func_cmp; + InitializeEML(eml); + eml->func_cmp = func_cmp; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void MoveEML ( exmem_list_t * dest, exmem_list_t * src ) +{ + DASSERT(dest); + if ( src != dest ) + { + ResetEML(dest); + if (src) + { + *dest = *src; + InitializeEML(src); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +uint FindHelperEML ( const exmem_list_t * eml, ccp key, bool * p_found ) +{ + DASSERT(eml); + + int (*cmp)( ccp s1, ccp s2 ) = eml->func_cmp ? eml->func_cmp : strcmp; + + if ( eml->is_unsorted ) + { + uint i; + exmem_key_t *ptr = eml->list; + for ( i = 0; i < eml->used; i++, ptr++ ) + if (!cmp(key,ptr->key)) + { + if (p_found) + *p_found = true; + return i; + } + + if (p_found) + *p_found = false; + return eml->used; + } + + int beg = 0; + if (key) + { + int end = eml->used - 1; + while ( beg <= end ) + { + const uint idx = (beg+end)/2; + const int stat = cmp(key,eml->list[idx].key); + if ( stat < 0 ) + end = idx - 1 ; + else if ( stat > 0 ) + beg = idx + 1; + else + { + noTRACE("FindHelperEML(%s) FOUND=%d/%d/%d\n", + key, idx, eml->used, eml->size ); + if (p_found) + *p_found = true; + return idx; + } + } + } + + noTRACE("FindHelperEML(%s) failed=%d/%d/%d\n", + key, beg, eml->used, eml->size ); + + if (p_found) + *p_found = false; + return beg; +} + +/////////////////////////////////////////////////////////////////////////////// + +int FindIndexEML ( const exmem_list_t * eml, ccp key, int not_found_value ) +{ + bool found; + const int idx = FindHelperEML(eml,key,&found); + return found ? idx : not_found_value; +} + +/////////////////////////////////////////////////////////////////////////////// + +exmem_key_t * FindEML ( const exmem_list_t * eml, ccp key ) +{ + bool found; + const int idx = FindHelperEML(eml,key,&found); + return found ? eml->list + idx : 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +exmem_key_t * FindAttribEML ( const exmem_list_t * eml, u32 attrib ) +{ + DASSERT(eml); + noTRACE("FindAttribEML(%x)\n",attrib); + + exmem_key_t *ptr = eml->list, *end; + for ( end = ptr + eml->used; ptr < end; ptr++ ) + if ( ptr->data.attrib == attrib ) + return ptr; + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static exmem_key_t * InsertHelperEML + ( exmem_list_t * eml, int idx, + ccp key, CopyMode_t cm_key, + const exmem_t *data, CopyMode_t cm_data ) +{ + DASSERT(eml); + DASSERT( eml->used <= eml->size ); + noPRINT("+SF: %u/%u/%u\n",idx,eml->used,eml->size); + if ( eml->used == eml->size ) + { + eml->size += EXMEM_LIST_GROW(eml->size); + eml->list = REALLOC(eml->list,eml->size*sizeof(*eml->list)); + } + + DASSERT( idx <= eml->used ); + exmem_key_t * dest = eml->list + idx; + memmove(dest+1,dest,(eml->used-idx)*sizeof(*dest)); + eml->used++; + + dest->data = CopyExMem(data,cm_data); + dest->key = cm_key == CPM_COPY ? STRDUP(key) : key; + dest->data.is_key_alloced = cm_key != CPM_LINK; + + return dest; +} + +/////////////////////////////////////////////////////////////////////////////// + +exmem_key_t * FindInsertEML + ( exmem_list_t * eml, ccp key, CopyMode_t cm_key, bool *old_found ) +{ + if (!key) + return 0; + + bool found; + int idx = FindHelperEML(eml,key,&found); + exmem_key_t *item; + if (found) + { + if ( cm_key == CPM_MOVE ) + FreeString(key); + item = eml->list + idx; + } + else + item = InsertHelperEML(eml,idx,key,cm_key,0,0); + + if (old_found) + *old_found = found; + return item; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool InsertEML ( exmem_list_t * eml, ccp key, CopyMode_t cm_key, + const exmem_t *data, CopyMode_t cm_data ) +{ + DASSERT(eml); + + if (!key) + { + FreeExMemCM(data,cm_data); + return 0; + } + + bool found; + int idx = FindHelperEML(eml,key,&found); + if (found) + { + if ( cm_key == CPM_MOVE ) + FreeString(key); + FreeExMemCM(data,cm_data); + } + else + InsertHelperEML(eml,idx,key,cm_key,data,cm_data); + + return !found; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool ReplaceEML ( exmem_list_t * eml, ccp key, CopyMode_t cm_key, + const exmem_t *data, CopyMode_t cm_data ) +{ + DASSERT(eml); + + if (!key) + { + FreeExMemCM(data,cm_data); + return 0; + } + + bool found; + int idx = FindHelperEML(eml,key,&found); + if (found) + { + if ( cm_key == CPM_MOVE ) + FreeString(key); + + exmem_key_t * dest = eml->list + idx; + AssignExMem(&dest->data,data,cm_data); + } + else + InsertHelperEML(eml,idx,key,cm_key,data,cm_data); + + return !found; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool OverwriteEML ( exmem_list_t * eml, ccp key, CopyMode_t cm_key, + const exmem_t *data, CopyMode_t cm_data ) +{ + DASSERT(eml); + + if (!key) + { + FreeExMemCM(data,cm_data); + return 0; + } + + bool found; + int idx = FindHelperEML(eml,key,&found); + if (found) + { + if ( cm_key == CPM_MOVE ) + FreeString(key); + + exmem_key_t * dest = eml->list + idx; + AssignExMem(&dest->data,data,cm_data); + } + + return found; +} + +/////////////////////////////////////////////////////////////////////////////// + +exmem_key_t * AppendEML ( exmem_list_t * eml, ccp key, CopyMode_t cm_key, + const exmem_t *data, CopyMode_t cm_data ) +{ + DASSERT(eml); + + if (!key) + { + FreeExMemCM(data,cm_data); + return 0; + } + + if ( eml->used == eml->size ) + { + eml->size += EXMEM_LIST_GROW(eml->size); + eml->list = REALLOC(eml->list,eml->size*sizeof(*eml->list)); + } + TRACE("AppendEML(%s,%d) %d/%d\n",key,cm_key,eml->used,eml->size); + + exmem_key_t * dest = eml->list + eml->used++; + dest->data = CopyExMem(data,cm_data); + dest->key = cm_key == CPM_COPY ? STRDUP(key) : key; + dest->data.is_key_alloced = cm_key != CPM_LINK; + + eml->is_unsorted = true; + return dest; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool RemoveEML ( exmem_list_t * eml, ccp key ) +{ + bool found; + uint idx = FindHelperEML(eml,key,&found); + if (found) + { + DASSERT(eml->used); + eml->used--; + DASSERT( idx <= eml->used ); + exmem_key_t * dest = eml->list + idx; + if (dest->data.is_key_alloced) + FreeString(dest->key); + FreeExMem(&dest->data); + if (eml->used) + memmove(dest,dest+1,(eml->used-idx)*sizeof(*dest)); + else + eml->is_unsorted = false; + } + return found; +} + +/////////////////////////////////////////////////////////////////////////////// + +exmem_key_t * MatchEML ( const exmem_list_t * eml, ccp key ) +{ + DASSERT(eml); + if (key) + { + exmem_key_t *ptr = eml->list, *end; + for ( end = ptr + eml->used; ptr < end; ptr++ ) + if (MatchPattern(ptr->key,key,'/')) + return ptr; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +void DumpEML ( FILE *f, int indent, const exmem_list_t * eml, ccp info ) +{ + if ( f && eml && eml->used ) + { + indent = NormalizeIndent(indent); + fprintf(f,"%*s%s%s" "exmem list %p, N=%u/%u%s\n", + indent,"", info ? info : "", info ? " : " : "", + eml, eml->used, eml->size, eml->is_unsorted ? ", not sorted" : "" ); + + char buf[20]; + const int fw_idx = indent + snprintf(buf,sizeof(buf),"%d",eml->used-1) + 1; + + exmem_key_t *ptr, *end = eml->list + eml->used; + int fw_key = 0; + for ( ptr = eml->list; ptr < end; ptr++ ) + { + if (ptr->key) + { + const int klen = strlen(ptr->key); + if ( fw_key < klen ) + fw_key = klen; + } + } + if ( fw_key > 30 ) + fw_key = 30; + + uint idx = 0; + for ( ptr = eml->list; ptr < end; ptr++, idx++ ) + fprintf(f,"%*d [%c%c%c%c] %-*s = [%x] %s\n", + fw_idx, idx, + ptr->data.is_key_alloced? 'a' : '-', // flags: same as in PrintExMem() + ptr->data.is_alloced ? 'A' : '-', + ptr->data.is_circ_buf ? 'C' : '-', + ptr->data.is_original ? 'O' : '-', + fw_key, ptr->key ? ptr->key : "", + ptr->data.attrib, ptr->data.data.ptr ); + } +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +exmem_t ResolveSymbolsEML ( const exmem_list_t * eml, ccp source ) +{ + exmem_t em = {{0}}; + + if (source) + { + char name[100]; + + int try; + for ( try = 0; try < 50; try++ ) + { + ccp p1 = strstr(source,"$("); + if (!p1) + continue; + ccp p2 = strchr(p1,')'); + if (!p2) + break; + + const int plen = p2 - p1 - 2; + DASSERT(plen>=0); + + StringCopySM(name,sizeof(name),p1+2,plen); + const exmem_key_t *ref = FindEML(eml,name); + mem_t replace = ref ? ref->data.data : NullMem; + + char *temp = MEMDUP3(source, p1-source, + replace.ptr, replace.len, + p2+1, strlen(p2+1) ); + if (em.is_alloced) + FreeString(source); + source = temp; + em.is_alloced = true; + } + } + + em.data.ptr = source; + em.data.len = strlen(source); + em.is_original = !em.is_alloced; + return em; +} + +/////////////////////////////////////////////////////////////////////////////// + +uint ResolveAllSymbolsEML ( exmem_list_t * eml ) +{ + ASSERT(eml); + int try, count = 0; + char name[100]; + exmem_key_t *ptr, *end = eml->list + eml->used; + + for ( try = 0; try < 20; try++ ) + { + int try_again = 0; + + for ( ptr = eml->list; ptr < end; ptr++ ) + { + for( int try2 = 0; try2 < 10; try2++ ) + { + ccp str = ptr->data.data.ptr; + if (!str) + break; + + ccp p1 = strstr(str,"$("); + if (!p1) + break; + ccp p2 = strchr(p1,')'); + if (!p2) + break; + const int plen = p2 - p1 - 2; + ASSERT(plen>=0); + + StringCopySM(name,sizeof(name),p1+2,plen); + const exmem_key_t *ref = FindEML(eml,name); + mem_t replace = ref && ref != ptr ? ref->data.data : NullMem; + + char *temp = MEMDUP3( str, p1-str, + replace.ptr, replace.len, + p2+1, strlen(p2+1) ); + if (ptr->data.is_alloced) + FreeString(str); + ASSERT(temp); + ptr->data.data.ptr = temp; + ptr->data.data.len = strlen(temp); + ptr->data.is_alloced = true; + ptr->data.is_original = ptr->data.is_circ_buf = false; + try_again++; + count++; + } + } + + if (!try_again) + break; + } + return count; +} + +/////////////////////////////////////////////////////////////////////////////// + +// add symbols 'home', 'etc', 'install' = 'prog' and 'cwd' +void AddStandardSymbolsEML ( exmem_list_t * eml, bool overwrite ) +{ + DASSERT(eml); + + char buf[PATH_MAX]; + bool (*func)(exmem_list_t*,ccp,CopyMode_t,const exmem_t*,CopyMode_t) + = overwrite ? ReplaceEML : InsertEML; + PRINT0("overwrite=%d, func=%p, ins=%p, repl=%p\n",overwrite,func,InsertEML,ReplaceEML); + + exmem_t temp = ExMemByString("/etc"); + func(eml,"etc",CPM_LINK,&temp,CPM_LINK); + + ccp home = getenv("HOME"); + temp = ExMemByString0(home); + func(eml,"home",CPM_LINK,&temp,CPM_COPY); + + // https://wiki.archlinux.org/index.php/XDG_Base_Directory + ccp xdg = getenv("XDG_CONFIG_HOME"); + if ( xdg && *xdg ) + { + temp = ExMemByString0(xdg); + ccp colon = strchr(xdg,':'); + if (colon) + { + if ( colon == xdg ) + goto xdg_home; + temp.data.len = colon - xdg; + } + func(eml,"xdg_home",CPM_LINK,&temp,CPM_COPY); + } + else if (home) + { + xdg_home:; + xdg = PathCatPP(buf,sizeof(buf),home,".config"); + temp = ExMemByString0(xdg); + func(eml,"xdg_home",CPM_LINK,&temp,CPM_COPY); + } + + xdg = getenv("XDG_CONFIG_DIRS"); + if ( xdg && *xdg ) + { + temp = ExMemByString0(xdg); + ccp colon = strchr(xdg,':'); + if (colon) + { + if ( colon == xdg ) + goto xdg_etc; + temp.data.len = colon - xdg; + } + func(eml,"xdg_etc",CPM_LINK,&temp,CPM_COPY); + } + else + { + xdg_etc:; + temp = ExMemByString("/etc/xdg"); + func(eml,"xdg_etc",CPM_LINK,&temp,CPM_LINK); + } + + ccp install = ProgramDirectory(); + temp = ExMemByString0(install); + func(eml,"install",CPM_LINK,&temp,CPM_COPY); + func(eml,"prog",CPM_LINK,&temp,CPM_COPY); + + if (getcwd(buf,sizeof(buf))) + { + temp = ExMemByString0(buf); + func(eml,"cwd",CPM_LINK,&temp,CPM_COPY); + } + + #ifdef __CYGWIN__ + ccp prog_files = getenv("PROGRAMFILES"); + if ( !prog_files || !*prog_files ) + prog_files = "C:/Program Files"; + temp = GetNormalizeFilenameCygwin(prog_files,true); + func(eml,"programfiles",CPM_LINK,&temp,CPM_COPY); + FreeExMem(&temp); + #endif +} + +// +/////////////////////////////////////////////////////////////////////////////// /////////////// Memory Maps /////////////// /////////////////////////////////////////////////////////////////////////////// diff --git a/project/dclib/dclib-basics.h b/project/dclib/dclib-basics.h index c5395f6..5412d52 100644 --- a/project/dclib/dclib-basics.h +++ b/project/dclib/dclib-basics.h @@ -629,6 +629,40 @@ uint GetTextBOMLen ( const void * data, uint data_size ); // /////////////////////////////////////////////////////////////////////////////// +/////////////// CopyMode_t /////////////// +/////////////////////////////////////////////////////////////////////////////// +// [[CopyMode_t]] + +typedef enum CopyMode_t +{ + CPM_COPY, // make a copy of the data, alloced + CPM_MOVE, // move the alloced data + CPM_LINK, // link the data + +} CopyMode_t; + +/////////////////////////////////////////////////////////////////////////////// + +void * CopyData +( + const void *data, // data to copy/move/link + uint size, // size of 'data' + CopyMode_t mode, // copy mode + bool *res_alloced // not NULL: + // store true, if data must be freed + // otherwise store false +); + +/////////////////////////////////////////////////////////////////////////////// + +void FreeData +( + const void *data, // data to free + CopyMode_t mode // copy mode +); + +// +/////////////////////////////////////////////////////////////////////////////// /////////////// struct mem_t /////////////// /////////////////////////////////////////////////////////////////////////////// // [[mem_t]] @@ -640,8 +674,8 @@ typedef struct mem_t } mem_t; -extern mem_t EmptyMem; // mem_t(EmptyString,0) -extern mem_t NullMem; // mem_t(0,0) +extern mem_t EmptyMem; // mem_t(EmptyString,0) +extern mem_t NullMem; // mem_t(0,0) //----------------------------------------------------------------------------- @@ -651,6 +685,7 @@ static inline mem_t MemByChar ( char ch ) return mem; } +// NULL allowed static inline mem_t MemByString0 ( ccp str ) { if (!str) @@ -660,18 +695,21 @@ static inline mem_t MemByString0 ( ccp str ) return mem; } +// NULL forbidden static inline mem_t MemByString ( ccp str ) { mem_t mem = { str, strlen(str) }; return mem; } +// NULL forbidden if len<0 static inline mem_t MemByStringS ( ccp str, int len ) { mem_t mem = { str, len < 0 ? strlen(str) : len }; return mem; } +// NULL forbidden if end=0 static inline mem_t MemByStringE ( ccp str, ccp end ) { mem_t mem = { str, end ? end-str : strlen(str) }; @@ -792,6 +830,103 @@ static inline char * DupStrMem ( const mem_t src ) // /////////////////////////////////////////////////////////////////////////////// +/////////////// struct exmem_t /////////////// +/////////////////////////////////////////////////////////////////////////////// +// [[exmem_t]] + +typedef struct exmem_t +{ + mem_t data; // pointer and size of data + u32 attrib; // user defined attribute + bool is_original; // true: 'data' is a copy of source + bool is_circ_buf; // true: 'data' is part of circ-buf + bool is_alloced; // true: 'data' is alloced (not circ-buf) + bool is_key_alloced; // true: external key is alloced +} +exmem_t; + +extern exmem_t EmptyExMem; // mem_t(EmptyString,0),false,false +extern exmem_t NullExMem; // mem_t(0,0),false,false + +//----------------------------------------------------------------------------- +// constructors + +static inline exmem_t ExMemByChar ( char ch ) +{ + exmem_t em = { .data={ &ch, 1 }, .is_original=true }; + return em; +} + +static inline exmem_t ExMemByString0 ( ccp str ) +{ + if (!str) + return NullExMem; + + exmem_t em = { .data={ str, strlen(str) }, .is_original=true }; + return em; +} + +static inline exmem_t ExMemByString ( ccp str ) +{ + exmem_t em = { .data={ str, str ? strlen(str) : 0 }, .is_original=true }; + return em; +} + +static inline exmem_t ExMemByStringS ( ccp str, int len ) +{ + exmem_t em = { .data={ str, !str ? 0 : len < 0 ? strlen(str) : len }, .is_original=true }; + return em; +} + +static inline exmem_t ExMemByStringE ( ccp str, ccp end ) +{ + exmem_t em = { .data={ str, !str ? 0 : end ? end-str : strlen(str) }, .is_original=true }; + return em; +} + +static inline exmem_t ExMemByS ( ccp str, int len ) +{ + exmem_t em = { .data={ str, len }, .is_original=true }; + return em; +} + +static inline exmem_t ExMemByE ( ccp str, ccp end ) +{ + exmem_t em = { .data={ str, end-str }, .is_original=true }; + return em; +} + +//----------------------------------------------------------------------------- +// interface + +// 'em' maybe modified ignoring 'const' +void FreeExMem ( const exmem_t *em ); +void FreeExMemCM ( const exmem_t *em, CopyMode_t copy_mode ); // free if CPM_MOVE + +exmem_t AllocExMemS +( + cvp src, // NULL or source + int src_len, // len of 'src'; if -1: use strlen(source) + bool try_circ, // use circ-buffer, if result is small enough + cvp orig, // NULL or data to compare + int orig_len // len of 'orig'; if -1: use strlen(source) +); + +static inline exmem_t AllocExMemM ( mem_t src, bool try_circ, mem_t orig ) + { return AllocExMemS(src.ptr,src.len,try_circ,orig.ptr,orig.len); } + +void AssignExMem ( exmem_t *dest, const exmem_t *source, CopyMode_t copy_mode ); +static inline exmem_t CopyExMem ( const exmem_t *source, CopyMode_t copy_mode ) + { exmem_t em = {{0}}; AssignExMem(&em,source,copy_mode); return em; } + +exmem_t CopyExMemS ( ccp string, int slen, CopyMode_t copy_mode ); +static inline exmem_t CopyExMemM ( const mem_t source, CopyMode_t copy_mode ) + { return CopyExMemS(source.ptr,source.len,copy_mode); } + +ccp PrintExMem ( const exmem_t * em ); // print to circ-buf + +// +/////////////////////////////////////////////////////////////////////////////// /////////////// struct mem_list_t /////////////// /////////////////////////////////////////////////////////////////////////////// // [[mem_list_t]] @@ -825,7 +960,9 @@ mem_list_mode_t; //----------------------------------------------------------------------------- -void InitializeMemList ( mem_list_t *ml ); +static inline void InitializeMemList ( mem_list_t *ml ) + { DASSERT(ml); memset(ml,0,sizeof(*ml)); } + void ResetMemList ( mem_list_t *ml ); void MoveMemList ( mem_list_t *dest, mem_list_t *src ); @@ -1037,39 +1174,6 @@ uint PurgeCircBuf ( CircBuf_t *cb ); // /////////////////////////////////////////////////////////////////////////////// -/////////////// CopyMode_t /////////////// -/////////////////////////////////////////////////////////////////////////////// - -typedef enum CopyMode_t -{ - CPM_COPY, // make a copy of the data, alloced - CPM_MOVE, // move the alloced data - CPM_LINK, // link the data - -} CopyMode_t; - -/////////////////////////////////////////////////////////////////////////////// - -void * CopyData -( - const void *data, // data to copy/move/link - uint size, // size of 'data' - CopyMode_t mode, // copy mode - bool *res_alloced // not NULL: - // store true, if data must be freed - // otherwise store false -); - -/////////////////////////////////////////////////////////////////////////////// - -void FreeData -( - const void *data, // data to free - CopyMode_t mode // copy mode -); - -// -/////////////////////////////////////////////////////////////////////////////// /////////////// split strings /////////////// /////////////////////////////////////////////////////////////////////////////// @@ -1192,7 +1296,7 @@ ccp ProgramDirectory(void); void DefineLogDirectory ( ccp path0, bool force ); // get 'ProgInfo.logdir' without tailing '/' ("." as fall back) -ccp GetLogDirectory(); +ccp GetLogDirectory(void); #ifdef __CYGWIN__ ccp ProgramPathNoExt(void); @@ -1264,7 +1368,7 @@ ccp PathAllocPPE ( ccp path1, ccp path2, ccp ext ); static inline ccp PathCatPPE ( char *buf, size_t bufsize, ccp path1, ccp path2, ccp ext ) { return PathCatBufPPE(buf,bufsize,path1,path2,ext); } -// Same as PathCatPP*(), but use 'base' as prefix for relative pathes. +// Same as PathCatPP*(), but use 'base' as prefix for relative paths. // If 'base' is NULL (but not empty), use getcwd() instead. // PathCatBufBP() and PathCatBP() are special: path can be part of buf char *PathCatBufBP ( char *buf, size_t bufsize, ccp base, ccp path ); @@ -1389,9 +1493,12 @@ char * PrintID #define CIRC_BUF_MAX_ALLOC 0x0400 // request limit #define CIRC_BUF_SIZE 0x4000 // internal buffer size +// returns true if 'ptr' points into circ buffer => ignored by FreeString() +bool IsCircBuf ( cvp ptr ); + char * GetCircBuf ( - // never returns NULL, but always ALIGN(4) + // Never returns NULL, but always ALIGN(4) u32 buf_size // wanted buffer size, caller must add 1 for NULL-term // if buf_size > CIRC_BUF_MAX_ALLOC: @@ -1400,7 +1507,7 @@ char * GetCircBuf char * CopyCircBuf ( - // never returns NULL, but always ALIGN(4) + // Never returns NULL, but always ALIGN(4) cvp data, // source to copy u32 data_size // see GetCircBuf() @@ -1408,8 +1515,8 @@ char * CopyCircBuf char * CopyCircBuf0 ( - // never returns NULL, but always ALIGN(4) - // an additional char is alloced and set to NULL + // Like CopyCircBuf(), but an additional char is alloced and set to NULL + // Never returns NULL, but always ALIGN(4). cvp data, // source to copy u32 data_size // see GetCircBuf() @@ -1417,11 +1524,32 @@ char * CopyCircBuf0 char * PrintCircBuf ( + // returns CopyCircBuf0() or EmptyString. + ccp format, // format string for vsnprintf() ... // arguments for 'format' ) __attribute__ ((__format__(__printf__,1,2))); +char * AllocCircBuf +( + // Never returns NULL. Call FreeString(RESULT) to free possible alloced memory. + + cvp src, // NULL or source + int src_len, // len of 'src'; if -1: use strlen(source) + bool try_circ // use circ-buffer, if result is small enough +); + +char * AllocCircBuf0 +( + // Never returns NULL. Call FreeString(RESULT) to free possible alloced memory. + // Like AllocCircBuf(), but an additional char is alloced and set to NULL + + cvp src, // NULL or source + int src_len, // len of 'src'; if -1: use strlen(source) + bool try_circ // use circ-buffer, if result is small enough +); + void ReleaseCircBuf ( ccp end_buf, // pointer to end of previous alloced buffer @@ -2171,6 +2299,7 @@ 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__MODERN = CHMD_UTF8 | CHMD_ESC, CHMD__ALL = CHMD_UTF8 | CHMD_ESC, } __attribute__ ((packed)) CharMode_t; @@ -2233,13 +2362,25 @@ extern ccp TableDecode64default, TableEncode64default; /////////////////////////////////////////////////////////////////////////////// +uint GetEscapedSize +( + // returns the needed buffer size for PrintEscapedString() + + ccp source, // NULL or string to print + int src_len, // length of string. if -1, str is null terminated + CharMode_t char_mode, // modes, bit field (CHMD_*) + char quote // NULL or quotation char, that must be quoted +); + +//----------------------------------------------------------------------------- + char * PrintEscapedString ( // returns 'buf' char *buf, // valid destination buffer uint buf_size, // size of 'buf', >= 10 - ccp source, // NULL string to print + ccp source, // NULL or string to print int len, // length of string. if -1, str is null terminated CharMode_t char_mode, // modes, bit field (CHMD_*) char quote, // NULL or quotation char, that must be quoted @@ -2250,7 +2391,7 @@ char * PrintEscapedString uint ScanEscapedString ( - // returns the number of valid bytes in 'buf' (NULL term not counted) + // 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' @@ -2540,6 +2681,71 @@ ccp GetShiftJISStatistics(void); // /////////////////////////////////////////////////////////////////////////////// +/////////////// escape/quote strings, alloc space /////////////// +/////////////////////////////////////////////////////////////////////////////// + +char * EscapeString +( + // Returns a pointer. + // Use FreeString(result) to free possible alloced result. + // circ-buffer is ignored by FreeString(). + + 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 + char quote, // quoting character: " or ' or $ (for $'...') + bool try_circ, // use circ-buffer, if result is small enough + uint *dest_len // not NULL: Store length of result here +); + +//----------------------------------------------------------------------------- + +static inline char * EscapeStringM ( mem_t src, cvp if_null, CharMode_t cm ) + { return EscapeString(src.ptr,src.len,if_null,EmptyString,cm,0,false,0); } + +static char * EscapeStringS ( ccp src, cvp if_null, CharMode_t cm ) + { return EscapeString(src,-1,if_null,EmptyString,cm,0,false,0); } + +//----------------------------------------------------------------------------- + +static inline char * EscapeStringCircM ( mem_t src, cvp if_null, CharMode_t cm ) + { return EscapeString(src.ptr,src.len,if_null,EmptyString,cm,0,true,0); } + +static char * EscapeStringCircS ( ccp src, cvp if_null, CharMode_t cm ) + { return EscapeString(src,-1,if_null,EmptyString,cm,0,true,0); } + +//----------------------------------------------------------------------------- + +static inline char * QuoteStringM ( mem_t src, cvp if_null, CharMode_t cm ) + { return EscapeString(src.ptr,src.len,if_null,EmptyQuote,cm,true,false,0); } + +static char * QuoteStringS ( ccp src, cvp if_null, CharMode_t cm ) + { return EscapeString(src,-1,if_null,EmptyQuote,cm,'"',false,0); } + +static inline char * QuoteBashM ( mem_t src, cvp if_null, CharMode_t cm ) + { return EscapeString(src.ptr,src.len,if_null,EmptyQuote,cm,'$',false,0); } + +static char * QuoteBashS ( ccp src, cvp if_null, CharMode_t cm ) + { return EscapeString(src,-1,if_null,EmptyQuote,cm,'$',false,0); } + +//----------------------------------------------------------------------------- + +static inline char * QuoteStringCircM ( mem_t src, cvp if_null, CharMode_t cm ) + { return EscapeString(src.ptr,src.len,if_null,EmptyQuote,cm,'"',true,0); } + +static char * QuoteStringCircS ( ccp src, cvp if_null, CharMode_t cm ) + { return EscapeString(src,-1,if_null,EmptyQuote,cm,'"',true,0); } + +static inline char * QuoteBashCircM ( mem_t src, cvp if_null, CharMode_t cm ) + { return EscapeString(src.ptr,src.len,if_null,EmptyQuote,cm,'$',true,0); } + +static char * QuoteBashCircS ( ccp src, cvp if_null, CharMode_t cm ) + { return EscapeString(src,-1,if_null,EmptyQuote,cm,'$',true,0); } + +// +/////////////////////////////////////////////////////////////////////////////// /////////////// scan keywords /////////////// /////////////////////////////////////////////////////////////////////////////// @@ -2748,16 +2954,20 @@ OffOn_t; extern const KeywordTab_t KeyTab_OFF_AUTO_ON[]; -int ScanKeywordOffAutoOn +int ScanKeywordOffAutoOnEx ( // returns one of OFFON_* + const KeywordTab_t *keytab, // Keyword table. If NULL, then use KeyTab_OFF_AUTO_ON[] ccp arg, // argument to scan int on_empty, // return this value on empty uint max_num, // >0: additionally accept+return number <= max_num ccp object // NULL (silent) or object for error messages ); +static inline int ScanKeywordOffAutoOn( ccp arg, int on_empty, uint max_num, ccp object ) + { return ScanKeywordOffAutoOnEx(0,arg,on_empty,max_num,object); } + ccp GetKeywordOffAutoOn ( OffOn_t value ); // @@ -4393,9 +4603,12 @@ uint RemoveStringFieldByIndex ( StringField_t * sf, int index, int n ); // helper function ccp * InsertStringFieldHelper ( StringField_t * sf, int idx ); -// append at the end an do not sort +// append at the end and do not sort void AppendStringField ( StringField_t * sf, ccp key, bool move_key ); +// append at the end if nor already exists, do not sort +void AppendUniqueStringField ( StringField_t * sf, ccp key, bool move_key ); + // re-sort field using sf->func_cmp() void SortStringField ( StringField_t * sf ); @@ -4484,7 +4697,9 @@ typedef struct ParamField_t //----------------------------------------------------------------------------- -void InitializeParamField ( ParamField_t * pf ); +static inline void InitializeParamField ( ParamField_t * pf ) + { DASSERT(pf); memset(pf,0,sizeof(*pf)); } + void ResetParamField ( ParamField_t * pf ); void MoveParamField ( ParamField_t * dest, ParamField_t * src ); @@ -4492,18 +4707,16 @@ int FindParamFieldIndex ( const ParamField_t * pf, ccp key, int not_found_value ParamFieldItem_t * FindParamField ( const ParamField_t * pf, ccp key ); ParamFieldItem_t * FindParamFieldByNum ( const ParamField_t * pf, uint num ); ParamFieldItem_t * FindInsertParamField - ( ParamField_t * pf, ccp key, bool move_key, bool *old_found ); -ParamFieldItem_t * CountParamField ( ParamField_t * pf, ccp key, bool move_key ); + ( ParamField_t * pf, ccp key, bool move_key, uint num, bool *old_found ); +ParamFieldItem_t * IncrementParamField ( ParamField_t * pf, ccp key, bool move_key ); +// Insert: Insert only if not found, Replace: Insert or replace data // return: true if item inserted/deleted bool InsertParamField ( ParamField_t * pf, ccp key, bool move_key, uint num, cvp data ); bool ReplaceParamField( ParamField_t * pf, ccp key, bool move_key, uint num, cvp data ); bool RemoveParamField ( ParamField_t * pf, ccp key ); -ParamFieldItem_t * InsertParamFieldEx - ( ParamField_t * pf, ccp key, bool move_key, uint num, bool *found ); - -// append at the end an do not sort +// append at the end and do not sort ParamFieldItem_t * AppendParamField ( ParamField_t * pf, ccp key, bool move_key, uint num, cvp data ); @@ -4515,6 +4728,81 @@ ParamFieldItem_t * MatchParamField ( const ParamField_t * pf, ccp key ); // /////////////////////////////////////////////////////////////////////////////// +/////////////// struct exmem_list_t /////////////// +/////////////////////////////////////////////////////////////////////////////// +// [[exmem_key_t]] + +typedef struct exmem_key_t +{ + ccp key; // string as main key => data.is_key_alloced + exmem_t data; // data +} +exmem_key_t; + +//----------------------------------------------------------------------------- +// [[exmem_list_t]] + +typedef struct exmem_list_t +{ + exmem_key_t *list; // data list + uint used; // number of used titles in the title field + uint size; // number of allocated pointers in 'field' + bool is_unsorted; // true: list is not sorted (Append() was used) + int (*func_cmp)( ccp s1, ccp s2 ); // compare function, default is strcmp() +} +exmem_list_t; + +//----------------------------------------------------------------------------- + +static inline void InitializeEML ( exmem_list_t * eml ) + { DASSERT(eml); memset(eml,0,sizeof(*eml)); } + +void ResetEML ( exmem_list_t * eml ); +void MoveEML ( exmem_list_t * dest, exmem_list_t * src ); + +// return the index of the (next) item +uint FindHelperEML ( const exmem_list_t * eml, ccp key, bool *found ); + +int FindIndexEML ( const exmem_list_t * eml, ccp key, int not_found_value ); +exmem_key_t * FindEML ( const exmem_list_t * eml, ccp key ); +exmem_key_t * FindAttribEML ( const exmem_list_t * eml, u32 attrib ); +exmem_key_t * FindInsertEML ( exmem_list_t * eml, ccp key, CopyMode_t cm_key, bool *old_found ); + +// Insert if not found, ignore othwerwise. Return true if item inserted +bool InsertEML ( exmem_list_t * eml, ccp key, CopyMode_t cm_key, + const exmem_t *data, CopyMode_t cm_data ); + +// Insert or replace content. Return true if item inserted +bool ReplaceEML ( exmem_list_t * eml, ccp key, CopyMode_t cm_key, + const exmem_t *data, CopyMode_t cm_data ); + +// Replace content if found. Return true if item found +bool OverwriteEML ( exmem_list_t * eml, ccp key, CopyMode_t cm_key, + const exmem_t *data, CopyMode_t cm_data ); + +// Append at the end and do not sort +exmem_key_t * AppendEML ( exmem_list_t * eml, ccp key, CopyMode_t cm_key, + const exmem_t *data, CopyMode_t cm_data ); + +// Return true if item found and removed +bool RemoveEML ( exmem_list_t * eml, ccp key ); + + +// find first pattern that matches +exmem_key_t * MatchEML ( const exmem_list_t * eml, ccp key ); + +void DumpEML ( FILE *f, int indent, const exmem_list_t * eml, ccp info ); + +//----------------------------------------------------------------------------- + +exmem_t ResolveSymbolsEML ( const exmem_list_t * eml, ccp source ); +uint ResolveAllSymbolsEML ( exmem_list_t * eml ); + +// add symbols 'home', 'etc', 'install' = 'prog' and 'cwd' +void AddStandardSymbolsEML ( exmem_list_t * eml, bool overwrite ); + +// +/////////////////////////////////////////////////////////////////////////////// /////////////// Memory Map /////////////// /////////////////////////////////////////////////////////////////////////////// // [[MemMapItem_t]] diff --git a/project/dclib/dclib-cli.c b/project/dclib/dclib-cli.c index d2b16f3..b49ba99 100644 --- a/project/dclib/dclib-cli.c +++ b/project/dclib/dclib-cli.c @@ -315,13 +315,16 @@ enumError Command_COLORS if ( level < 0 ) { + ccp term = getenv("TERM"); + if (!term) + term = "?"; printf("%s--color=%d [%s], colorize=%d [%s]\n" "term=%s\n" "stdout: tty=%d, mode=%d [%s], have-color=%d, n-colors=%u%s\n", colout->status, opt_colorize, GetColorModeName(opt_colorize,"?"), colorize_stdout, GetColorModeName(colorize_stdout,"?"), - getenv("TERM"), isatty(fileno(stdout)), + term, isatty(fileno(stdout)), colout->col_mode, GetColorModeName(colout->col_mode,"?"), colout->colorize, colout->n_colors, colout->reset ); return ERR_OK; diff --git a/project/dclib/dclib-color.c b/project/dclib/dclib-color.c index 601a920..07e8625 100644 --- a/project/dclib/dclib-color.c +++ b/project/dclib/dclib-color.c @@ -3316,19 +3316,29 @@ const ColorSet_t * GetColorSetAuto ( bool force_on ) if ( auto_mode == COLMD_AUTO ) { + char *term = getenv("TERM"); + + #ifdef __CYGWIN__ + if (!term) + term = "cygwin"; + #else + if (!term) + term = "vt100"; + #endif + int error; - setupterm(getenv("TERM"),1,&error); + setupterm(term,1,&error); const int ncol = tigetnum("colors"); auto_mode = ncol >= 256 ? COLMD_256_COLORS : ncol >= 8 ? COLMD_8_COLORS : COLMD_OFF; - if ( auto_mode == COLMD_OFF && !strcmp(getenv("TERM"),"cygwin") ) + if ( auto_mode == COLMD_OFF && !strcmp(term,"cygwin") ) auto_mode = COLMD_8_COLORS; #ifdef TEST fprintf(stderr,">>> GetColorSetAuto(%d) => \"%s\" n=%d => %d [%s]\n", - force_on, getenv("TERM"), ncol, + force_on, term, ncol, auto_mode, GetColorModeName(auto_mode,0) ); #endif } diff --git a/project/dclib/dclib-debug.c b/project/dclib/dclib-debug.c index 9dfbd5e..7017608 100644 --- a/project/dclib/dclib-debug.c +++ b/project/dclib/dclib-debug.c @@ -1019,6 +1019,52 @@ void * dclib_memdup ( MPARAM const void * src, size_t copylen ) /////////////////////////////////////////////////////////////////////////////// +void * dclib_memdup2 ( MPARAM cvp src1, size_t len1, cvp src2, size_t len2 ) +{ + char *res = dclib_malloc( MCALL len1+len2+1); + char *dest = res; + if (len1) + { + memcpy(dest,src1,len1); + dest += len1; + } + if (len2) + { + memcpy(dest,src2,len2); + dest += len2; + } + *dest = 0; + return res; +} + +/////////////////////////////////////////////////////////////////////////////// + +void * dclib_memdup3 + ( MPARAM cvp src1, size_t len1, cvp src2, size_t len2, cvp src3, size_t len3 ) +{ + char *res = dclib_malloc( MCALL len1+len2+len3+1); + char *dest = res; + if (len1) + { + memcpy(dest,src1,len1); + dest += len1; + } + if (len2) + { + memcpy(dest,src2,len2); + dest += len2; + } + if (len3) + { + memcpy(dest,src3,len3); + dest += len3; + } + *dest = 0; + return res; +} + +/////////////////////////////////////////////////////////////////////////////// + void * dclib_allocdup ( MPARAM const void * src, size_t copylen ) { char * dest = dclib_malloc( MCALL copylen); @@ -1026,6 +1072,29 @@ void * dclib_allocdup ( MPARAM const void * src, size_t copylen ) return dest; } +/////////////////////////////////////////////////////////////////////////////// + +char * dclib_printdup ( MPARAM ccp format, ... ) +{ + char buf[2000]; + + va_list arg; + va_start(arg,format); + const int stat = vsnprintf(buf,sizeof(buf),format,arg) + 1; + va_end(arg); + + char * dest = dclib_malloc( MCALL stat ); + if ( stat <= sizeof(buf) ) + memcpy(dest,buf,stat); + else + { + va_start(arg,format); + vsnprintf(dest,stat,format,arg); + va_end(arg); + } + return dest; +} + // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// @@ -1511,6 +1580,54 @@ void * trace_memdup /////////////////////////////////////////////////////////////////////////////// +void * trace_memdup2 ( ccp func, ccp file, uint line, + cvp src1, size_t len1, cvp src2, size_t len2 ) +{ + char *res = trace_malloc(func,file,line,len1+len2+1); + char *dest = res; + + if (len1) + { + memcpy(dest,src1,len1); + dest += len1; + } + if (len2) + { + memcpy(dest,src2,len2); + dest += len2; + } + *dest = 0; + return res; +} + +/////////////////////////////////////////////////////////////////////////////// + +void * trace_memdup3 ( ccp func, ccp file, uint line, + cvp src1, size_t len1, cvp src2, size_t len2, cvp src3, size_t len3 ) +{ + char *res = trace_malloc(func,file,line,len1+len2+len3+1); + char *dest = res; + if (len1) + { + memcpy(dest,src1,len1); + dest += len1; + } + if (len2) + { + memcpy(dest,src2,len2); + dest += len2; + } + if (len3) + { + memcpy(dest,src3,len3); + dest += len3; + } + *dest = 0; + return res; +} + +/////////////////////////////////////////////////////////////////////////////// + void * trace_allocdup ( ccp func, ccp file, uint line, const void * src, size_t copylen ) { @@ -1519,6 +1636,30 @@ void * trace_allocdup return dest; } +/////////////////////////////////////////////////////////////////////////////// + +char * trace_printdup + ( ccp func, ccp file, uint line, ccp format, ... ) +{ + char buf[2000]; + + va_list arg; + va_start(arg,format); + const int stat = vsnprintf(buf,sizeof(buf),format,arg) + 1; + va_end(arg); + + char * dest = trace_malloc(func,file,line,stat); + if ( stat <= sizeof(buf) ) + memcpy(dest,buf,stat); + else + { + va_start(arg,format); + vsnprintf(dest,stat,format,arg); + va_end(arg); + } + return dest; +} + // /////////////////////////////////////////////////////////////////////////////// /////////////// mem check /////////////// diff --git a/project/dclib/dclib-debug.h b/project/dclib/dclib-debug.h index 2fc6e77..5851141 100644 --- a/project/dclib/dclib-debug.h +++ b/project/dclib/dclib-debug.h @@ -607,6 +607,9 @@ void * dclib_xmalloc ( size_t size ); void * dclib_xrealloc ( void * ptr, size_t size ); char * dclib_xstrdup ( ccp src ); +// HINT: the *memdup* functions always alloc 1 additonal byte and set it to NULL. + + #if TRACE_ALLOC_MODE > 1 void * dclib_calloc ( ccp,ccp,uint, size_t nmemb, size_t size ); void * dclib_malloc ( ccp,ccp,uint, size_t size ); @@ -614,8 +617,11 @@ char * dclib_xstrdup ( ccp src ); char * dclib_strdup ( ccp,ccp,uint, ccp src ); char * dclib_strdup2 ( ccp,ccp,uint, ccp src1, ccp src2 ); char * dclib_strdup3 ( ccp,ccp,uint, ccp src1, ccp src2, ccp src3 ); - void * dclib_memdup ( ccp,ccp,uint, const void * src, size_t copylen ); - void * dclib_allocdup( ccp,ccp,uint, const void * src, size_t copylen ); + void * dclib_memdup ( ccp,ccp,uint, cvp src, size_t copylen ); + void * dclib_memdup2 ( ccp,ccp,uint, cvp s1, size_t l1, cvp s2, size_t l2 ); + void * dclib_memdup3 ( ccp,ccp,uint, cvp s1, size_t l1, cvp s2, size_t l2, cvp s3, size_t l3 ); + void * dclib_allocdup( ccp,ccp,uint, cvp src, size_t copylen ); + char * dclib_printdup( ccp,ccp,uint, ccp format, ... ) __attribute__ ((__format__(__printf__,4,5))); #else void * dclib_calloc ( size_t nmemb, size_t size ); void * dclib_malloc ( size_t size ); @@ -623,8 +629,11 @@ char * dclib_xstrdup ( ccp src ); char * dclib_strdup ( ccp src ); char * dclib_strdup2 ( ccp src1, ccp src2 ); char * dclib_strdup3 ( ccp src1, ccp src2, ccp src3 ); - void * dclib_memdup ( const void * src, size_t copylen ); - void * dclib_allocdup( const void * src, size_t copylen ); + void * dclib_memdup ( cvp src, size_t copylen ); + void * dclib_memdup2 ( cvp s1, size_t l1, cvp s2, size_t l2 ); + void * dclib_memdup3 ( cvp s1, size_t l1, cvp s2, size_t l2, cvp s3, size_t l3 ); + void * dclib_allocdup( cvp src, size_t copylen ); + char * dclib_printdup( ccp format, ... ) __attribute__ ((__format__(__printf__,1,2))); #endif uint trace_test_alloc ( ccp,ccp,uint, const void * ptr, bool hexdump ); @@ -635,8 +644,11 @@ void * trace_realloc ( ccp,ccp,uint, void *ptr, size_t size ); char * trace_strdup ( ccp,ccp,uint, ccp src ); char * trace_strdup2 ( ccp,ccp,uint, ccp src1, ccp src2 ); char * trace_strdup3 ( ccp,ccp,uint, ccp src1, ccp src2, ccp src3 ); -void * trace_memdup ( ccp,ccp,uint, const void * src, size_t copylen ); -void * trace_allocdup ( ccp,ccp,uint, const void * src, size_t copylen ); +void * trace_memdup ( ccp,ccp,uint, cvp src, size_t copylen ); +void * trace_memdup2 ( ccp,ccp,uint, cvp s1, size_t l1, cvp s2, size_t l2 ); +void * trace_memdup3 ( ccp,ccp,uint, cvp s1, size_t l1, cvp s2, size_t l2, cvp s3, size_t l3 ); +void * trace_allocdup ( ccp,ccp,uint, cvp src, size_t copylen ); +char * trace_printdup ( ccp,ccp,uint, ccp format, ... ) __attribute__ ((__format__(__printf__,4,5))); #if TRACE_ALLOC_MODE > 2 void InitializeTraceAlloc(void); @@ -658,7 +670,10 @@ void * trace_allocdup ( ccp,ccp,uint, const void * src, size_t copylen ); #define STRDUP2(src1,src2) trace_strdup2(__FUNCTION__,__FILE__,__LINE__,src1,src2) #define STRDUP3(src1,src2,src3) trace_strdup3(__FUNCTION__,__FILE__,__LINE__,src1,src2,src3) #define MEMDUP(src,size) trace_memdup(__FUNCTION__,__FILE__,__LINE__,src,size) + #define MEMDUP2(s1,l1,s2,l2) trace_memdup2(__FUNCTION__,__FILE__,__LINE__,s1,l1,s2,l2) + #define MEMDUP3(s1,l1,s2,l2,s3,l3) trace_memdup3(__FUNCTION__,__FILE__,__LINE__,s1,l1,s2,l2,s3,l3) #define ALLOCDUP(src,size) trace_allocdup(__FUNCTION__,__FILE__,__LINE__,src,size) + #define PRINTDUP(...) trace_printdup(__FUNCTION__,__FILE__,__LINE__,__VA_ARGS__) #define INIT_TRACE_ALLOC InitializeTraceAlloc() #define CHECK_TRACE_ALLOC CheckTraceAlloc(__FUNCTION__,__FILE__,__LINE__) #define DUMP_TRACE_ALLOC(f) DumpTraceAlloc(__FUNCTION__,__FILE__,__LINE__,f) @@ -672,7 +687,10 @@ void * trace_allocdup ( ccp,ccp,uint, const void * src, size_t copylen ); #define STRDUP2(src1,src2) dclib_strdup2(__FUNCTION__,__FILE__,__LINE__,src1,src2) #define STRDUP3(src1,src2,src3) dclib_strdup3(__FUNCTION__,__FILE__,__LINE__,src1,src2,src3) #define MEMDUP(src,size) dclib_memdup(__FUNCTION__,__FILE__,__LINE__,src,size) + #define MEMDUP2(s1,l1,s2,l2) dclib_memdup2(__FUNCTION__,__FILE__,__LINE__,s1,l1,s2,l2) + #define MEMDUP3(s1,l1,s2,l2,s3,l3) dclib_memdup3(__FUNCTION__,__FILE__,__LINE__,s1,l1,s2,l2,s3,l3) #define ALLOCDUP(src,size) dclib_allocdup(__FUNCTION__,__FILE__,__LINE__,src,size) + #define PRINTDUP(...) dclib_printdup(__FUNCTION__,__FILE__,__LINE__,__VA_ARGS__) #define INIT_TRACE_ALLOC #define CHECK_TRACE_ALLOC #define DUMP_TRACE_ALLOC(f) @@ -686,7 +704,10 @@ void * trace_allocdup ( ccp,ccp,uint, const void * src, size_t copylen ); #define STRDUP2(src1,src2) dclib_strdup2(src1,src2) #define STRDUP3(src1,src2,src3) dclib_strdup3(src1,src2,src3) #define MEMDUP(src,size) dclib_memdup(src,size) + #define MEMDUP2(s1,l1,s2,l2) dclib_memdup2(s1,l1,s2,l2) + #define MEMDUP3(s1,l1,s2,l2,s3,l3) dclib_memdup3(s1,l1,s2,l2,s3,l3) #define ALLOCDUP(src,size) dclib_allocdup(src,size) + #define PRINTDUP(...) dclib_printdup(__VA_ARGS__) #define INIT_TRACE_ALLOC #define CHECK_TRACE_ALLOC #define DUMP_TRACE_ALLOC(f) diff --git a/project/dclib/dclib-file.c b/project/dclib/dclib-file.c index 333ec3a..1356d32 100644 --- a/project/dclib/dclib-file.c +++ b/project/dclib/dclib-file.c @@ -246,7 +246,7 @@ FileAttrib_t * SetFileAttrib ZeroFileAttrib(dest); if (S_ISREG(src_stat->st_mode)) { - #if HAVE_STATTIME_NSEC + #if HAVE_STATTIME_NSEC dest->atime = src_stat->st_atim; dest->mtime = src_stat->st_mtim; dest->ctime = src_stat->st_ctim; @@ -2690,6 +2690,47 @@ uint PrintLineBuffer /////////////// file helpers /////////////// /////////////////////////////////////////////////////////////////////////////// +const char inode_type_char[INTY__N+1] = "?-+SLFBCDR"; + +//----------------------------------------------------------------------------- + +inode_type_t GetInodeType ( int ret_status, mode_t md ) +{ + return ret_status ? INTY_NOTFOUND + : S_ISREG(md) ? INTY_REG + : S_ISDIR(md) ? INTY_DIR + : S_ISCHR(md) ? INTY_CHAR + : S_ISBLK(md) ? INTY_BLOCK + : S_ISFIFO(md) ? INTY_FIFO + : S_ISLNK(md) ? INTY_LINK + : S_ISSOCK(md) ? INTY_SOCK + : INTY_AVAIL; +} + +//----------------------------------------------------------------------------- + +inode_type_t GetInodeTypeByPath ( ccp path, mode_t *mode ) +{ + struct stat st; + const int ret_status = stat(path,&st); + if (mode) + *mode = ret_status ? 0 : st.st_mode; + return GetInodeType(ret_status,st.st_mode); +} + +//----------------------------------------------------------------------------- + +inode_type_t GetInodeTypeByFD ( int fd, mode_t *mode ) +{ + struct stat st; + const int ret_status = fstat(fd,&st); + if (mode) + *mode = ret_status ? 0 : st.st_mode; + return GetInodeType(ret_status,st.st_mode); +} + +/////////////////////////////////////////////////////////////////////////////// + int IsDirectory ( // analyse filename (last char == '/') and stat(fname) @@ -2990,7 +3031,7 @@ enumError RemoveSource ( ccp fname, // file to remove ccp dest_fname, // NULL or dest file name - // If real pathes are same: don't remove + // If real paths are same: don't remove bool print_log, // true: print a log message bool testmode // true: don't remove, log only ) @@ -3218,14 +3259,15 @@ char * NormalizeFileName uint buf_size, // size of buf ccp source, // NULL or source bool allow_slash, // true: allow '/' in source - bool is_utf8 // true: enter UTF-8 mode + bool is_utf8, // true: enter UTF-8 mode + trailing_slash slash_mode // manipulate trailing slash ) { DASSERT(buf); DASSERT(buf_size>1); char *dest = buf, *end = buf + buf_size - 1; - TRACE("NormalizeFileName(%s,%d)\n",source,allow_slash); + TRACE("NormalizeFileName(%s,%d,%d,%d)\n",source,allow_slash,is_utf8,slash_mode); if (source) { @@ -3271,19 +3313,22 @@ char * NormalizeFileName || ch == 0xd6 // Ö || ch == 0xdc // Ü ) - || strchr("_+-=%'\"$%&,.!()[]{}<>",ch) - || ch == '/' && allow_slash ) + || strchr("_+-=%'\"$%&#,.!()[]{}<>",ch) + ) { *dest++ = ch; skip_space = false; } #ifdef __CYGWIN__ - else if ( ch == '\\' && allow_slash ) + else if ( ( ch == '/' || ch == '\\' ) && allow_slash ) + #else + else if ( ch == '/' && allow_slash ) + #endif { - *dest++ = '/'; + if ( dest == buf || dest[-1] != '/' ) + *dest++ = '/'; skip_space = false; } - #endif else if (!skip_space) { *dest++ = ' '; @@ -3295,6 +3340,35 @@ char * NormalizeFileName if ( dest > buf && dest[-1] == ' ' ) dest--; + switch (slash_mode) + { + case TRSL_NONE: // do nothing special + break; + + case TRSL_AUTO: // add trailing slash if it is a directory, remove otherwise + *dest = 0; + if (IsDirectory(buf,false)) + goto add_slash; + // fall through + + case TRSL_REMOVE: // remove trailing slash always + if ( dest > buf && dest[-1] == '/' ) + dest--; + break; + + case TRSL_ADD_AUTO: // add trailing slash if it is a directory + *dest = 0; + if (!IsDirectory(buf,false)) + break; + // fall through + + case TRSL_ADD_ALWAYS: // add trailing slash always + add_slash: + if ( dest > buf && dest < end && dest[-1] != '/' ) + *dest++ = '/'; + break; + } + DASSERT( dest <= end ); *dest = 0; return dest; @@ -3303,19 +3377,16 @@ char * NormalizeFileName /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// -#ifdef __CYGWIN__ - - uint IsWindowsDriveSpec - ( +uint IsWindowsDriveSpec +( // returns the length of the found windows drive specification (0|2|3) - ccp src // valid string - ) - { - DASSERT(src); - - if ( ( *src >= 'a' && *src <= 'z' || *src >= 'A' && *src <= 'Z' ) - && src[1] == ':' ) + ccp src // NULL or valid string +) +{ + if ( src + && src[1] == ':' + && ( *src >= 'a' && *src <= 'z' || *src >= 'A' && *src <= 'Z' ) ) { if (!src[2]) return 2; @@ -3324,41 +3395,40 @@ char * NormalizeFileName return 3; } return 0; - } - -#endif // __CYGWIN__ +} /////////////////////////////////////////////////////////////////////////////// -#ifdef __CYGWIN__ - - uint NormalizeFilenameCygwin - ( +uint NormalizeFilenameCygwin +( // returns a pointer to the NULL terminator within 'buf' char * buf, // valid destination buffer uint buf_size, // size of buf ccp src // NULL or source - ) - { +) +{ static char prefix[] = "/cygdrive/"; if ( buf_size < sizeof(prefix) + 5 || !src ) { - *buf = 0; + if ( buf && buf_size ) + *buf = 0; return 0; } char * end = buf + buf_size - 1; char * dest = buf; - if ( ( *src >= 'a' && *src <= 'z' || *src >= 'A' && *src <= 'Z' ) + if ( ( *src >= 'a' && *src <= 'z' || *src >= 'A' && *src <= 'Z' ) && src[1] == ':' && ( src[2] == 0 || src[2] == '/' || src[2] == '\\' )) { memcpy(buf,prefix,sizeof(prefix)); dest = buf + sizeof(prefix)-1; *dest++ = tolower((int)*src); // cygwin needs the '(int)' + #ifdef __CYGWIN__ + // this can only be checked with real Cygwin. *dest = 0; if (IsDirectory(buf,false)) { @@ -3369,8 +3439,15 @@ char * NormalizeFileName } else dest = buf; + #else // + *dest++ = '/'; + src += 2; + if (*src) + src++; + #endif + } - ASSERT( dest < buf + buf_size ); + DASSERT( dest < buf + buf_size ); while ( dest < end && *src ) if ( *src == '\\' ) @@ -3384,29 +3461,367 @@ char * NormalizeFileName *dest = 0; ASSERT( dest < buf + buf_size ); return dest - buf; - } - -#endif // __CYGWIN__ +} /////////////////////////////////////////////////////////////////////////////// -#ifdef __CYGWIN__ +exmem_t GetNormalizeFilenameCygwin +( + // returns an object. Call FreeExMem(RESULT) to possible alloced memory. + + ccp source, // NULL or source + bool try_circ // use circ-buffer, if result is small enough +) +{ + char buf[PATH_MAX]; + const uint len = NormalizeFilenameCygwin(buf,sizeof(buf),source); + return AllocExMemS(buf,len,try_circ,source,-1); +} + +/////////////////////////////////////////////////////////////////////////////// - char * AllocNormalizedFilenameCygwin - ( +char * AllocNormalizedFilenameCygwin +( // returns an alloced buffer with the normalized filename - ccp source // NULL or string - ) - { + ccp source, // NULL or source + bool try_circ // use circ-buffer, if result is small enough +) +{ char buf[PATH_MAX]; const uint len = NormalizeFilenameCygwin(buf,sizeof(buf),source); - char * result = MEMDUP(buf,len); // MEMDUP allocs +1 byte and set it to NULL - DASSERT(buf[len]==0); - return result; - } + return AllocCircBuf(buf,len,try_circ); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// search file & config /////////////// +/////////////////////////////////////////////////////////////////////////////// + +void ResetSearchFile ( search_file_list_t *sfl ) +{ + if (sfl) + { + if (sfl->list) + { + uint i; + search_file_t *sf = sfl->list; + for ( i = 0; i < sfl->used; i++, sf++ ) + if (sf->alloced) + FreeString(sf->fname); + FREE(sfl->list); + } + + ResetEML(&sfl->symbols); + InitializeSearchFile(sfl); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +search_file_t * AppendSearchFile +( + search_file_list_t *sfl, // valid search list, new files will be appended + ccp fname, // path+fname to add + CopyMode_t copy_mode, // copy mode for 'fname' + ccp append_if_dir // append this if 'fname' is a directory +) +{ + search_file_t *res = 0; + if ( fname && *fname ) + { + #if 0 + ccp rpath = realpath(fname,0); + if (rpath) + { + if ( copy_mode == CPM_MOVE ) + FreeString(fname); + fname = rpath; + copy_mode = CPM_MOVE; + } + #endif + + uint i; + search_file_t *sf = sfl->list; + for ( i = 0; i < sfl->used; i++, sf++ ) + { + if (!strcmp(sf->fname,fname)) + { + res = sf; + goto end; + } + } + DASSERT( i == sfl->used ); + + + //-- check for directory + + const inode_type_t itype = GetInodeTypeByPath(fname,0); + if ( itype == INTY_DIR && append_if_dir ) + { + char buf[PATH_MAX]; + ccp fname2 = PathCatPP(buf,sizeof(buf),fname,append_if_dir); + res = AppendSearchFile(sfl,fname2,CPM_COPY,0); + } + else + { + if ( sfl->used == sfl->size ) + { + sfl->size += sfl->size/8 + 20; + sfl->list = REALLOC(sfl->list,sfl->size*sizeof(*sfl->list)); + } + + res = sfl->list + sfl->used++; + memset(res,0,sizeof(*res)); + res->itype = itype; + res->fname = CopyData(fname,strlen(fname)+1,copy_mode,&res->alloced); + fname = 0; + } + } + + end: + if ( fname && copy_mode == CPM_MOVE ) + FreeString(fname); + return res; +} + +/////////////////////////////////////////////////////////////////////////////// + +void DumpSearchFile ( FILE *f, int indent, + const search_file_list_t *sfl, bool show_symbols, ccp info ) +{ + if ( f && sfl && ( sfl->used || show_symbols && sfl->symbols.used )) + { + indent = NormalizeIndent(indent); + fprintf(f,"%*s%s%s" "SearchList %p, N=%u/%u\n", + indent,"", info ? info : "", info ? " : " : "", + sfl, sfl->used, sfl->size ); + + char buf[20]; + const int fw_idx = indent + + snprintf(buf,sizeof(buf),"%d",sfl->used) + + ( show_symbols ? 3 : 1 ); + + uint idx = 0; + search_file_t *ptr, *end = sfl->list + sfl->used; + for ( ptr = sfl->list; ptr < end; ptr++, idx++ ) + fprintf(f,"%*d [%c,%c:%02x] %s\n", + fw_idx, idx, + ptr->alloced ? 'A' : '-', + inode_type_char[ptr->itype], ptr->hint, ptr->fname ); + + if (show_symbols) + DumpEML(f,indent+2,&sfl->symbols,"Symbols"); + } +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +uint SearchConfig1 +( + search_file_list_t *sfl, + // valid search list, new file will be appended + ccp config_fname, // default filename (without path) of config file + + ccp option, // NULL or filename by option => CONF_HINT_OPT + ccp home_path, // NULL or home path for config file => CONF_HINT_HOME + ccp etc_path, // NULL or etc path for config file => CONF_HINT_ETC + ccp share_path, // NULL or share path for config file => CONF_HINT_MISC + + int stop_mode // >0: stop if found, >1: stop on option + + // hints (by source, values=prio): 8:option, 4:home, 2:etc, 1:prog-path +) +{ + DASSERT(sfl); + char buf[PATH_MAX]; + + uint count = 0; + search_file_t *sf; + if ( option && *option ) + { + sf = AppendSearchFile(sfl,option,CPM_COPY,config_fname); + if (sf) + { + sf->hint |= CONF_HINT_OPT; + if ( sf->itype == INTY_REG && ++count && stop_mode > 0 ) + return 1; + if ( stop_mode > 1 ) + return 0; + } + } + + if (home_path) + { + ccp home = getenv("HOME"); + if (home) + home_path = PathCatPP(buf,sizeof(buf),home,home_path); + sf = AppendSearchFile(sfl,home_path,CPM_COPY,config_fname); + if (sf) + { + sf->hint |= CONF_HINT_HOME; + if ( sf->itype == INTY_REG && ++count && stop_mode > 0 ) + return 1; + } + } + + if (etc_path) + { + sf = AppendSearchFile(sfl,etc_path,CPM_COPY,config_fname); + if (sf) + { + sf->hint |= CONF_HINT_ETC; + if ( sf->itype == INTY_REG && ++count && stop_mode > 0 ) + return 1; + } + } + + if (share_path) + { + sf = AppendSearchFile(sfl,share_path,CPM_COPY,config_fname); + if (sf) + { + sf->hint |= CONF_HINT_MISC; + if ( sf->itype == INTY_REG && ++count && stop_mode > 0 ) + return 1; + } + } + + ccp progpath = ProgramDirectory(); + if (progpath) + { + sf = AppendSearchFile(sfl,progpath,CPM_COPY,config_fname); + if (sf) + { + sf->hint |= CONF_HINT_INST; + if ( sf->itype == INTY_REG && ++count && stop_mode > 0 ) + return 1; + } + } + + return count; +} + +/////////////////////////////////////////////////////////////////////////////// + +static int add_search +( + // returns 0 if !stop_if_found, 2 if added+found, 1 if added, 0 else + + search_file_list_t *sfl, // valid data + ccp config_fname, // default filename (without path) of config file + ccp *list, // NULL or list of filenames + int n_list, // num of 'list' elements, -1:null terminated list + ccp prefix, // prefix for relative filenames + uint hint, // attributes + int stop_if_found // >0: stop if file found +) +{ + DASSERT(sfl); + if (!list) + return 0; + + if ( n_list < 0 ) + { + ccp *ptr; + for ( ptr = list; *ptr; ptr++ ) + ; + n_list = ptr - list; + } + if (!n_list) + return 0; + + int ret_val = 0; + char buf[PATH_MAX]; + for ( ; n_list > 0; n_list--, list++ ) + { + if (!*list) + continue; + + ccp path = **list == '/' || !prefix || !*prefix + ? *list + : PathCatPP(buf,sizeof(buf),prefix,*list); + exmem_t res = ResolveSymbolsEML(&sfl->symbols,path); + search_file_t *sf = AppendSearchFile( sfl, res.data.ptr, + res.is_alloced ? CPM_MOVE : CPM_COPY, config_fname ); + if (sf) + { + sf->hint |= hint; + if ( sf->itype == INTY_REG && stop_if_found > 0 ) + return 2; + ret_val = 1; + } + } + + return stop_if_found > 0 ? ret_val : 0; +} + +//----------------------------------------------------------------------------- + +bool SearchConfig +( + // for all paths: + // /... is an absolute path + // $(home)/... path relative to getenv("HOME") + // $(xdg_home)/... path relative to first path of getenv("XDG_CONFIG_HOME") + // $(xdg_etc)/... path relative to first path of getenv("XDG_CONFIG_DIRS") + // $(etc)/... path relative to /etc directory + // $(install)/... path relative to installation directory = ProgramDirectory() + // $(NAME)/... path relative to symbol in sfl->symbols + // xx relative paths otherwise + + search_file_list_t *sfl, + // valid search list, new paths will be appended + // sfl->symbols: home, etc and install are added (not replaced) + // It is used to resolve all $(NAME) references. + + ccp config_fname, // default filename (without path) of config file + + ccp *option, // NULL or filenames by option => CONF_HINT_OPT + int n_option, // num of 'option' elements, -1:null terminated list + ccp *xdg_home, // NULL or $(xdg_home) based paths => CONF_HINT_HOME + int n_xdg_home, // num of 'home' elements, -1:null terminated list + ccp *home, // NULL or $(home) based paths => CONF_HINT_HOME + int n_home, // num of 'home' elements, -1:null terminated list + ccp *etc, // NULL or $(etc) based paths => CONF_HINT_ETC + int n_etc, // num of 'etc' elements, -1:null terminated list + ccp *install, // NULL or $(install) based paths => CONF_HINT_INST + int n_install, // num of 'install' elements, -1:null terminated list + ccp *misc, // NULL or absolute paths => CONF_HINT_MISC + int n_misc, // num of 'misc' elements, -1:null terminated list + + int stop_mode // >0: stop if found, >1: stop on option +) +{ + // ==> see: https://wiki.archlinux.org/index.php/XDG_Base_Directory -#endif // __CYGWIN__ + DASSERT(sfl); + AddStandardSymbolsEML(&sfl->symbols,false); + + int stat = add_search(sfl,config_fname,option,n_option,0,CONF_HINT_OPT,stop_mode); + if ( stat > 1 ) + return true; + if ( stop_mode > 1 && stat ) + return false; + + if (add_search(sfl,config_fname,xdg_home,n_xdg_home,"$(xdg_home)",CONF_HINT_HOME,stop_mode)>1) + return true; + + if (add_search(sfl,config_fname,home,n_home,"$(home)",CONF_HINT_HOME,stop_mode)>1) + return true; + + if (add_search(sfl,config_fname,etc,n_etc,"$(xdg_etc)",CONF_HINT_ETC,stop_mode)>1) + return true; + + if (add_search(sfl,config_fname,etc,n_etc,"$(etc)",CONF_HINT_ETC,stop_mode)>1) + return true; + + if (add_search(sfl,config_fname,install,n_install,"$(install)",CONF_HINT_INST,stop_mode)>1) + return true; + + return add_search(sfl,config_fname,misc,n_misc,0,CONF_HINT_MISC,stop_mode)>1; +} // /////////////////////////////////////////////////////////////////////////////// @@ -4902,68 +5317,50 @@ void SaveCurrentStateByTable break; case SRT_FLOAT: - switch(srt->size) + if ( srt->size == sizeof(float) ) { - case sizeof(float): - { - const u8 *d = data + srt->offset; - for ( i = 0; i < n_elem; i++, d += elem_off ) - fprintf(f, "%s%.8g", i ? "," : "", *(float*)d ); - } - break; - - case sizeof(double): - { - const u8 *d = data + srt->offset; - for ( i = 0; i < n_elem; i++, d += elem_off ) - fprintf(f, "%s%.16g", i ? "," : "", *(double*)d ); - } - break; - - case sizeof(long double): - { - const u8 *d = data + srt->offset; - for ( i = 0; i < n_elem; i++, d += elem_off ) - fprintf(f, "%s%.20Lg", i ? "," : "", *(long double*)d ); - } - break; - - default: - fputs("0.0",f); + const u8 *d = data + srt->offset; + for ( i = 0; i < n_elem; i++, d += elem_off ) + fprintf(f, "%s%.8g", i ? "," : "", *(float*)d ); + } + else if ( srt->size == sizeof(double) ) + { + const u8 *d = data + srt->offset; + for ( i = 0; i < n_elem; i++, d += elem_off ) + fprintf(f, "%s%.16g", i ? "," : "", *(double*)d ); + } + else if ( srt->size == sizeof(long double) ) + { + const u8 *d = data + srt->offset; + for ( i = 0; i < n_elem; i++, d += elem_off ) + fprintf(f, "%s%.20Lg", i ? "," : "", *(long double*)d ); } + else + fputs("0.0",f); fputc('\n',f); break; case SRT_XFLOAT: - switch(srt->size) + if ( srt->size == sizeof(float) ) { - case sizeof(float): - { - const u8 *d = data + srt->offset; - for ( i = 0; i < n_elem; i++, d += elem_off ) - fprintf(f, "%s%a", i ? "," : "", *(float*)d ); - } - break; - - case sizeof(double): - { - const u8 *d = data + srt->offset; - for ( i = 0; i < n_elem; i++, d += elem_off ) - fprintf(f, "%s%a", i ? "," : "", *(double*)d ); - } - break; - - case sizeof(long double): - { - const u8 *d = data + srt->offset; - for ( i = 0; i < n_elem; i++, d += elem_off ) - fprintf(f, "%s%La", i ? "," : "", *(long double*)d ); - } - break; - - default: - fputs("0.0",f); + const u8 *d = data + srt->offset; + for ( i = 0; i < n_elem; i++, d += elem_off ) + fprintf(f, "%s%a", i ? "," : "", *(float*)d ); + } + else if ( srt->size == sizeof(double) ) + { + const u8 *d = data + srt->offset; + for ( i = 0; i < n_elem; i++, d += elem_off ) + fprintf(f, "%s%a", i ? "," : "", *(double*)d ); + } + else if ( srt->size == sizeof(long double) ) + { + const u8 *d = data + srt->offset; + for ( i = 0; i < n_elem; i++, d += elem_off ) + fprintf(f, "%s%La", i ? "," : "", *(long double*)d ); } + else + fputs("0.0",f); fputc('\n',f); break; @@ -5204,12 +5601,12 @@ void RestoreStateByTable uint i = 0; while (*src) { - switch(srt->size) - { - case sizeof(float): *(float*)val = strtof(src,&src); break; - case sizeof(double): *(double*)val = strtod(src,&src); break; - case sizeof(long double): *(long double*)val = strtold(src,&src); break; - } + if ( srt->size == sizeof(float) ) + *(float*)val = strtof(src,&src); + else if ( srt->size == sizeof(double) ) + *(double*)val = strtod(src,&src); + else if ( srt->size == sizeof(long double) ) + *(long double*)val = strtold(src,&src); if ( ++i == n_elem ) break; val += elem_off; @@ -5703,6 +6100,7 @@ ccp GetNamePSFF ( PrintScriptFF fform ) { case PSFF_UNKNOWN: return "TEXT"; case PSFF_ASSIGN: return "ASSIGN"; + case PSFF_CONFIG: return "CONFIG"; case PSFF_JSON: return "JSON"; case PSFF_BASH: return "BASH"; case PSFF_SH: return "SH"; @@ -5723,6 +6121,11 @@ void PrintScriptHeader ( PrintScript_t *ps ) ps->add_index = false; ps->sep[0] = ps->sep[1] = 0; + if ( !ps->var_name || !*ps->var_name ) + ps->var_name = "res"; + if ( !ps->var_prefix ) + ps->var_prefix = ""; + if ( ps->f ) { switch (ps->fform) @@ -5740,19 +6143,19 @@ void PrintScriptHeader ( PrintScript_t *ps ) case PSFF_PHP: if (ps->create_array) - fprintf(ps->f,"$%s = array();\n\n",ps->varname); + fprintf(ps->f,"$%s = array();\n\n",ps->var_name); ps->boc = "#"; break; case PSFF_MAKEDOC: if (ps->create_array) - fprintf(ps->f,"%s = @LIST\n\n",ps->varname); + fprintf(ps->f,"%s = @LIST\n\n",ps->var_name); ps->boc = "#!"; break; case PSFF_C: if (ps->create_array) - fprintf(ps->f,"%s = @LIST\n\n",ps->varname); + fprintf(ps->f,"%s = @LIST\n\n",ps->var_name); ps->boc = "//"; break; @@ -5781,7 +6184,7 @@ void PrintScriptFooter ( PrintScript_t *ps ) case PSFF_SH: if (ps->create_array) - fprintf(ps->f,"%s_N=%u\n\n",ps->varname,ps->index); + fprintf(ps->f,"%sN=%u\n\n",ps->var_prefix,ps->index); break; case PSFF_PHP: @@ -5817,9 +6220,9 @@ int PutScriptVars if ( ps->add_index ) snprintf( ps->prefix, sizeof(ps->prefix), - "%s_%u", ps->varname, ps->index ); + "%s%u", ps->var_prefix, ps->index ); else - StringCopyS( ps->prefix, sizeof(ps->prefix), ps->varname ); + StringCopyS( ps->prefix, sizeof(ps->prefix), ps->var_prefix ); switch (ps->fform) { @@ -5891,65 +6294,107 @@ int PutScriptVars varname = MemUpperS(varbuf,sizeof(varbuf),MemByS(varname,varlen)); varname = varbuf; } - - ccp param = ptr++; - while ( (uchar)*ptr >= ' ' ) + + ccp quote, param; + uint plen, free_param = 0; + if ( *++ptr == '"' ) + { ptr++; + param = ptr; + if (ps->auto_quote) + { + quote = EmptyString; + while ( *ptr && *ptr != '"' ) + { + if ( *ptr == '\\' && ptr[1] ) + ptr++; + ptr++; + } + param = EscapeString(param,ptr-param,EmptyString,EmptyString,CHMD__MODERN, + ps->fform == PSFF_BASH ? '$' : '"', true, &plen ); + free_param++; + } + else + { + quote = "\""; + while ( *ptr && !( ptr[0] == '"' && ptr[1] == '\n' )) + ptr++; + plen = ptr - param; + } + if ( *ptr == '"' ) + ptr++; + } + else + { + param = ptr; + quote = EmptyString; + while ( *ptr && *ptr != '\n' ) + ptr++; + plen = ptr - param; + } switch (ps->fform) { case PSFF_ASSIGN: - fprintf(f, "%.*s = %.*s\n", - varlen, varname, - (int)( ptr - param - 1 ), param+1 ); + fprintf(f, "%.*s = %s%.*s%s\n", + varlen, varname, quote, plen, param, quote ); + break; + + case PSFF_CONFIG: + if ( ps->eq_tabstop > 0 ) + { + int tabs = ps->eq_tabstop - varlen/8; + if ( tabs < 0 ) + tabs = 0; + fprintf(f, "%.*s%.*s= %.*s\n", + varlen, varname, tabs, Tabs20, plen, param ); + } + else + fprintf(f, "%.*s = %.*s\n", + varlen, varname, plen, param ); break; case PSFF_JSON: - fprintf(f, "%s\"%.*s\":%.*s", + fprintf(f, "%s\"%.*s\":%s%.*s%s", ps->count ? "," : "", - varlen, varname, - (int)( ptr - param - 1 ), param+1 ); + varlen, varname, quote, plen, param, quote ); break; case PSFF_BASH: if (ps->create_array) { - fprintf(f, "%s_%.*s%s=(%.*s)\n", + fprintf(f, "%s%.*s%s=(%s%.*s%s)\n", ps->prefix, - varlen, varname, - ps->index ? "+" : "", - (int)( ptr - param - 1 ), param+1 ); + varlen, varname, ps->index ? "+" : "", quote, plen, param, quote ); break; } // fall through case PSFF_SH: - fprintf(f, "%s_%.*s=%.*s\n", - ps->prefix, - varlen, varname, - (int)( ptr - param - 1 ), param+1 ); + fprintf(f, "%s%.*s=%s%.*s%s\n", + ps->prefix, varlen, varname, quote, plen, param, quote ); break; case PSFF_PHP: case PSFF_C: - fprintf(f, "$d->%.*s = %.*s;\n", - varlen, varname, - (int)( ptr - param - 1 ), param+1 ); + fprintf(f, "$d->%.*s = %s%.*s%s;\n", + varlen, varname, quote, plen, param, quote ); break; case PSFF_MAKEDOC: - fprintf(f, "d[\"%.*s\"] = %.*s\n", - varlen, varname, - (int)( ptr - param - 1 ), param+1 ); + fprintf(f, "d[\"%.*s\"] = %s%.*s%s\n", + varlen, varname, quote, plen, param, quote ); break; default: - fprintf(f, "%20.*s = %.*s\n", - varlen, varname, - (int)( ptr - param - 1 ), param+1 ); + fprintf(f, "%*.*s = %s%.*s%s\n", + ps->var_size > 0 ? ps->var_size : 20, + varlen, varname, quote, plen, param, quote ); break; } ps->count++; + if (free_param) + FreeString(param); //-- skip to next line next_line: @@ -5972,12 +6417,12 @@ int PutScriptVars case PSFF_PHP: fprintf(f, "$%s%s = $d;\n\n", - ps->prefix, ps->create_array ? "[]" : "" ); + ps->var_name, ps->create_array ? "[]" : "" ); break; case PSFF_MAKEDOC: fprintf(f, "%s %s= move(d);\n\n", - ps->prefix, ps->create_array ? "#" : "" ); + ps->var_name, ps->create_array ? "#" : "" ); break; default: diff --git a/project/dclib/dclib-file.h b/project/dclib/dclib-file.h index 1974475..e6f51f3 100644 --- a/project/dclib/dclib-file.h +++ b/project/dclib/dclib-file.h @@ -519,7 +519,7 @@ uint CloseAllExcept /////////////// CopyFile*(), TransferFile() /////////////// /////////////////////////////////////////////////////////////////////////////// -// compare pathes and by stat() +// compare paths and by stat() bool IsSameFile ( ccp path1, ccp path2 ); /////////////////////////////////////////////////////////////////////////////// @@ -845,6 +845,33 @@ uint PrintLineBuffer /////////////////////////////////////////////////////////////////////////////// /////////////// file helpers /////////////// /////////////////////////////////////////////////////////////////////////////// +// [[inode_type_t]] + +typedef enum inode_type_t +{ + INTY_UNKNOWN, // never tested + INTY_NOTFOUND, // file not found or error + INTY_AVAIL, // file is available + INTY_SOCK, // S_ISSOCK + INTY_LINK, // S_ISLNK + INTY_FIFO, // S_ISFIFO + INTY_BLOCK, // S_ISBLK + INTY_CHAR, // S_ISCHR + INTY_DIR, // S_ISDIR + INTY_REG, // S_ISREG + INTY__N +} +__attribute__ ((packed)) inode_type_t; + +extern const char inode_type_char[INTY__N+1]; + +//----------------------------------------------------------------------------- + +inode_type_t GetInodeType ( int ret_status, mode_t mode ); +inode_type_t GetInodeTypeByPath ( ccp path, mode_t *mode ); +inode_type_t GetInodeTypeByFD ( int fd, mode_t *mode ); + +/////////////////////////////////////////////////////////////////////////////// int IsDirectory ( @@ -935,7 +962,7 @@ enumError RemoveSource ( ccp fname, // file to remove ccp dest_fname, // NULL or dest file name - // If real pathes are same: don't remove + // If real paths are same: don't remove bool print_log, // true: print a log message bool testmode // true: don't remove, log only ); @@ -985,6 +1012,19 @@ uint NumberedFilename /////////////////////////////////////////////////////////////////////////////// /////////////// normalize filenames /////////////// /////////////////////////////////////////////////////////////////////////////// +// [[trailing_slash]] + +typedef enum trailing_slash +{ + TRSL_NONE, // do nothing special + TRSL_REMOVE, // remove trailing slash always + TRSL_ADD_ALWAYS, // add trailing slash always + TRSL_ADD_AUTO, // add trailing slash if it is a directory + TRSL_AUTO, // add trailing slash if it is a directory, remove otherwise +} +trailing_slash; + +/////////////////////////////////////////////////////////////////////////////// char * NormalizeFileName ( @@ -994,36 +1034,157 @@ char * NormalizeFileName uint buf_size, // size of buf ccp source, // NULL or source bool allow_slash, // true: allow '/' in source - bool is_utf8 // true: enter UTF-8 mode + bool is_utf8, // true: enter UTF-8 mode + trailing_slash slash_mode // manipulate trailing slash ); /////////////////////////////////////////////////////////////////////////////// -#ifdef __CYGWIN__ - uint IsWindowsDriveSpec - ( +uint IsWindowsDriveSpec +( // returns the length of the found windows drive specification (0|2|3) - ccp src // valid string - ); + ccp src // NULL or valid string +); - uint NormalizeFilenameCygwin - ( - // returns a pointer to the NULL terminator within 'buf' +uint NormalizeFilenameCygwin +( + // returns the used length (without 0-term) of buf. - char * buf, // valid destination buffer - uint buf_size, // size of buf - ccp src // NULL or source - ); + char * buf, // valid destination buffer + uint buf_size, // size of buf + ccp src // NULL or source +); - char * AllocNormalizedFilenameCygwin - ( +exmem_t GetNormalizeFilenameCygwin +( + // returns an object. Call FreeExMem(RESULT) to free possible alloced memory. + + ccp source, // NULL or source + bool try_circ // use circ-buffer, if result is small enough +); + +char * AllocNormalizedFilenameCygwin +( // returns an alloced buffer with the normalized filename + // Call FreeString(RESULT) to free possible alloced memory. - ccp source // NULL or string - ); + ccp source, // NULL or source + bool try_circ // use circ-buffer, if result is small enough +); + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// search file & config /////////////// +/////////////////////////////////////////////////////////////////////////////// +// [[search_file_t]]} -#endif // __CYGWIN__ +typedef struct search_file_t +{ + ccp fname; // filename + bool alloced; // is 'fname' alloced + inode_type_t itype; // one of INTY_* + u16 hint; // any hint +} +search_file_t; + +//----------------------------------------------------------------------------- +// [[search_file_list_t]]} + +typedef struct search_file_list_t +{ + search_file_t *list; // list of files + uint used; // number of used elements in 'list' + uint size; // number of alloced elements for 'list' + exmem_list_t symbols; // list to resolve $(SYMBOL) +} +search_file_list_t; + +//----------------------------------------------------------------------------- + +static inline void InitializeSearchFile ( search_file_list_t *sfl ) + { DASSERT(sfl); memset(sfl,0,sizeof(*sfl)); } + +void ResetSearchFile ( search_file_list_t *sfl ); + +search_file_t * AppendSearchFile +( + search_file_list_t *sfl, // valid search list, new files will be appended + ccp fname, // path+fname to add + CopyMode_t copy_mode, // copy mode for 'fname' + ccp append_if_dir // append this if 'fname' is a directory +); + +void DumpSearchFile ( FILE *f, int indent, + const search_file_list_t *sfl, bool show_symbols, ccp info ); + +/////////////////////////////////////////////////////////////////////////////// +// [[config_hint_t]] + +typedef enum config_hint_t +{ + CONF_HINT_MISC = 0x01, + CONF_HINT_INST = 0x02, + CONF_HINT_ETC = 0x04, + CONF_HINT_HOME = 0x08, + CONF_HINT_OPT = 0x10, +} +config_hint_t; + +//----------------------------------------------------------------------------- + +uint SearchConfig1 +( + search_file_list_t *sfl, + // valid search list, new file will be appended + ccp config_fname, // default filename (without path) of config file + + ccp option, // NULL or filename by option => CONF_HINT_OPT + ccp home_path, // NULL or home path for config file => CONF_HINT_HOME + ccp etc_path, // NULL or etc path for config file => CONF_HINT_ETC + ccp share_path, // NULL or share path for config file => CONF_HINT_MISC + + int stop_mode // >0: stop if found, >1: stop on option + + // hints (by source, values=prio): 8:option, 4:home, 2:etc, 1:prog-path +); + +//----------------------------------------------------------------------------- + +bool SearchConfig +( + // for all paths: + // /... is an absolute path + // $(home)/... path relative to getenv("HOME") + // $(xdg_home)/... path relative to first path of getenv("XDG_CONFIG_HOME") + // $(xdg_etc)/... path relative to first path of getenv("XDG_CONFIG_DIRS") + // $(etc)/... path relative to /etc directory + // $(install)/... path relative to installation directory = ProgramDirectory() + // $(NAME)/... path relative to symbol in sfl->symbols + // xx relative paths otherwise + + search_file_list_t *sfl, + // valid search list, new paths will be appended + // sfl->symbols: home, etc and install are added (not replaced) + // It is used to resolve all $(NAME) references. + + ccp config_fname, // default filename (without path) of config file + + ccp *option, // NULL or filenames by option => CONF_HINT_OPT + int n_option, // num of 'option' elements, -1:null terminated list + ccp *xdg_home, // NULL or $(xdg_home) based paths => CONF_HINT_HOME + int n_xdg_home, // num of 'home' elements, -1:null terminated list + ccp *home, // NULL or $(home) based paths => CONF_HINT_HOME + int n_home, // num of 'home' elements, -1:null terminated list + ccp *etc, // NULL or $(etc) based paths => CONF_HINT_ETC + int n_etc, // num of 'etc' elements, -1:null terminated list + ccp *install, // NULL or $(install) based paths => CONF_HINT_INST + int n_install, // num of 'install' elements, -1:null terminated list + ccp *misc, // NULL or absolute paths => CONF_HINT_MISC + int n_misc, // num of 'misc' elements, -1:null terminated list + + int stop_mode // >0: stop if found, >1: stop on option +); // /////////////////////////////////////////////////////////////////////////////// @@ -1341,6 +1502,7 @@ typedef enum PrintScriptFF { PSFF_UNKNOWN, // always 0 PSFF_ASSIGN, + PSFF_CONFIG, PSFF_JSON, PSFF_BASH, PSFF_SH, @@ -1359,9 +1521,13 @@ typedef struct PrintScript_t { FILE *f; // valid output file PrintScriptFF fform; // output: file format - ccp varname; // valid ponter to var name + ccp var_name; // NULL or variable name for result + ccp var_prefix; // NULL or prefix for member names + int var_size; // if > 0: print size of var name (some 'fform' only) + int eq_tabstop; // if > 0: indent '=' to set tabstop (some 'fform' only) LowerUpper_t force_case; // change case of var names if not LOUP_AUTO bool create_array; // true: create ar arrays + bool auto_quote; // true: detect quotes and use EscapeString() bool add_index; // true: add index to varname bool ena_empty; // true: enable empty lines bool ena_comments; // true: enable comments diff --git a/project/dclib/dclib-numeric.c b/project/dclib/dclib-numeric.c index 0f7a444..01fd734 100644 --- a/project/dclib/dclib-numeric.c +++ b/project/dclib/dclib-numeric.c @@ -968,19 +968,82 @@ ccp GetEncodingName ( EncodeMode_t em ) /////////////////////////////////////////////////////////////////////////////// +uint GetEscapedSize +( + // returns the needed buffer size for PrintEscapedString() + + ccp source, // NULL or string to print + int src_len, // length of string. if -1, str is null terminated + CharMode_t char_mode, // modes, bit field (CHMD_*) + char quote // NULL or quotation char, that must be quoted +) +{ + const CharMode_t utf8 = char_mode & CHMD_UTF8; + const CharMode_t allow_e = char_mode & CHMD_ESC; + + if ( !source || !*source ) + return 1; + ccp str = source; + ccp end = src_len < 0 ? 0 : str + src_len; + + uint size = 4; // +4 for escapes at end; +1 for NULL terminator + while ( !end || str < end ) + { + const u8 ch = (u8)*str++; + switch (ch) + { + case 0: + if (!end) + return size; + size += 4; + break; + + case '\\': + case '\a': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + case '\v': + size += 2; + break; + + case '\033': + size += allow_e ? 2 : 4; + break; + + default: + if ( ch == quote ) + size += 2; + else if ( ch < ' ' || !utf8 && (ch&0x7f) < ' ' || (ch&0x7f) == 0x7f ) + size += 4; + else + size++; + } + } + return size; +} + +/////////////////////////////////////////////////////////////////////////////// + char * PrintEscapedString ( // returns 'buf' char *buf, // valid destination buffer uint buf_size, // size of 'buf', >= 10 - ccp source, // NULL string to print + ccp source, // NULL or string to print int len, // length of string. if -1, str is null terminated CharMode_t char_mode, // modes, bit field (CHMD_*) char quote, // NULL or quotation char, that must be quoted uint *dest_len // not NULL: Store length of result here ) { + ///////////////////////////////////////////////////////// + ///// Update GetEscapedSize() on modifications!! ///// + ///////////////////////////////////////////////////////// + DASSERT(buf); DASSERT(buf_size>=10); @@ -1061,7 +1124,7 @@ char * PrintEscapedString uint ScanEscapedString ( - // returns the number of valid bytes in 'buf' (NULL term not counted) + // 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' @@ -2035,6 +2098,78 @@ mem_t EncodeByModeMem // /////////////////////////////////////////////////////////////////////////////// +/////////////// escape/quote strings, alloc space /////////////// +/////////////////////////////////////////////////////////////////////////////// + +char * EscapeString +( + // Returns a pointer. + // Use FreeString(result) to free possible alloced result. + // circ-buffer is ignored by FreeString(). + + 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 + char quote, // quoting character: " or ' or $ (for $'...') + bool try_circ, // use circ-buffer, if result is small enough + uint *dest_len // not NULL: Store length of result here +) +{ + if (!src) + return (char*)return_if_null; + if ( src_len < 0 ) + src_len = strlen(src); + if (!src_len) + return (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 = GetEscapedSize(src,src_len,char_mode,quote_char) + quote_mode; + char *buf = try_circ && size <= CIRC_BUF_MAX_ALLOC ? 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); + + if (dest_len) + *dest_len = len + quote_mode; + return buf; +}; + +// +/////////////////////////////////////////////////////////////////////////////// /////////////// time /////////////// /////////////////////////////////////////////////////////////////////////////// diff --git a/project/dclib/dclib-system.h b/project/dclib/dclib-system.h index 9a3dc5f..6829cb3 100644 --- a/project/dclib/dclib-system.h +++ b/project/dclib/dclib-system.h @@ -35,9 +35,12 @@ #ifndef DCLIB_SYSTEM_H #define DCLIB_SYSTEM_H 1 -#include <stdio.h> +#ifndef PRINT_SYSTEM_SETTINGS + #include <stdio.h> +#endif /////////////////////////////////////////////////////////////////////////////// +#ifndef PRINT_SYSTEM_SETTINGS typedef enum enumSystemID { @@ -46,17 +49,22 @@ typedef enum enumSystemID SYSID_X86_64 = 0x02000000, SYSID_CYGWIN32 = 0x03000000, SYSID_CYGWIN64 = 0x04000000, - SYSID_APPLE = 0x05000000, - SYSID_LINUX = 0x06000000, - SYSID_UNIX = 0x07000000, + SYSID_MAC_I386 = 0x05000000, + SYSID_MAC_X64 = 0x06000000, + SYSID_MAC_ARM = 0x07000000, + SYSID_LINUX = 0x08000000, + SYSID_UNIX = 0x09000000, } enumSystemID; +#endif + /////////////////////////////////////////////////////////////////////////////// #undef SYSTEM_LINUX #ifdef __CYGWIN__ + #define SYSTEM_LINUX 0 #define SYSTEM "cygwin" #ifdef __x86_64 #define SYSTEM2 "cygwin64" @@ -66,8 +74,18 @@ typedef enum enumSystemID #define SYSTEMID SYSID_CYGWIN32 #endif #elif __APPLE__ + #define SYSTEM_LINUX 0 #define SYSTEM "mac" - #define SYSTEMID SYSID_APPLE + #ifdef __aarch64__ + #define SYSTEM2 "mac/arm" + #define SYSTEMID SYSID_MAC_ARM + #elif __x86_64__ + #define SYSTEM2 "mac/x64" + #define SYSTEMID SYSID_MAC_X64 + #else + #define SYSTEM2 "mac/i386" + #define SYSTEMID SYSID_MAC_I386 + #endif #elif __linux__ #define SYSTEM_LINUX 1 #ifdef __i386__ @@ -81,6 +99,7 @@ typedef enum enumSystemID #define SYSTEMID SYSID_LINUX #endif #elif __unix__ + #define SYSTEM_LINUX 0 #define SYSTEM "unix" #define SYSTEMID SYSID_UNIX #else @@ -93,6 +112,7 @@ typedef enum enumSystemID #endif /////////////////////////////////////////////////////////////////////////////// +#ifndef PRINT_SYSTEM_SETTINGS static inline void dclibPrintSystem ( FILE * f ) { @@ -109,7 +129,14 @@ static inline void dclibPrintSystem ( FILE * f ) ); } +#endif /////////////////////////////////////////////////////////////////////////////// +#ifdef PRINT_SYSTEM_SETTINGS +result_SYSTEM=SYSTEM +result_SYSTEM2=SYSTEM2 +result_SYSTEM_LINUX=SYSTEM_LINUX +#endif + #endif // DCLIB_SYSTEM_H 1 |
