aboutsummaryrefslogtreecommitdiff
path: root/project/dclib
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--project/dclib/dclib-basics.c934
-rw-r--r--project/dclib/dclib-basics.h394
-rw-r--r--project/dclib/dclib-cli.c5
-rw-r--r--project/dclib/dclib-color.c16
-rw-r--r--project/dclib/dclib-debug.c141
-rw-r--r--project/dclib/dclib-debug.h33
-rw-r--r--project/dclib/dclib-file.c725
-rw-r--r--project/dclib/dclib-file.h208
-rw-r--r--project/dclib/dclib-numeric.c139
-rw-r--r--project/dclib/dclib-system.h37
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