aboutsummaryrefslogtreecommitdiff
path: root/project/dclib/dclib-file.c
diff options
context:
space:
mode:
Diffstat (limited to 'project/dclib/dclib-file.c')
-rw-r--r--project/dclib/dclib-file.c798
1 files changed, 736 insertions, 62 deletions
diff --git a/project/dclib/dclib-file.c b/project/dclib/dclib-file.c
index f58ace1..aae70a3 100644
--- a/project/dclib/dclib-file.c
+++ b/project/dclib/dclib-file.c
@@ -14,16 +14,16 @@
* *
***************************************************************************
* *
- * Copyright (c) 2012-2021 by Dirk Clemens <wiimm@wiimm.de> *
+ * Copyright (c) 2012-2022 by Dirk Clemens <wiimm@wiimm.de> *
* *
***************************************************************************
* *
- * This program is free software; you can redistribute it and/or modify *
+ * This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
- * This program is distributed in the hope that it will be useful, *
+ * This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
@@ -96,6 +96,317 @@ bool EnableSingleCharInput()
//
///////////////////////////////////////////////////////////////////////////////
+/////////////// log helpers ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+LogFile_t GlobalLogFile = {0};
+
+///////////////////////////////////////////////////////////////////////////////
+
+FILE * TryOpenFile ( FILE *f, ccp fname, ccp mode )
+{
+ if ( f == TRY_OPEN_FILE )
+ f = fopen(fname,mode);
+ else if (f)
+ {
+ rewind(f);
+ fflush(f);
+ }
+ return f;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+int GetLogTimestamp ( char *buf, uint buf_size, TimestampMode_t ts_mode )
+{
+ DASSERT(buf);
+ DASSERT(buf_size>2);
+
+ uint len;
+ if ( ts_mode >= TSM_USEC )
+ {
+ const u64 usec = GetTimeUSec(false);
+ const uint sec = usec/1000000 % SEC_PER_DAY;
+ len = snprintf(buf,buf_size,
+ "%02u:%02u:%02u.%06llu ",
+ sec / 3600,
+ sec / 60 % 60,
+ sec % 60,
+ usec % 1000000 );
+ }
+ else if ( ts_mode >= TSM_MSEC )
+ {
+ const u64 msec = GetTimeMSec(false);
+ const uint sec = msec/USEC_PER_MSEC % SEC_PER_DAY;
+ len = snprintf(buf,buf_size,
+ "%02u:%02u:%02u.%03llu ",
+ sec / 3600,
+ sec / 60 % 60,
+ sec % 60,
+ msec % 1000 );
+ }
+ else if ( ts_mode >= TSM_SEC )
+ {
+ const uint sec = GetTimeSec(false) % SEC_PER_DAY;
+ len = snprintf(buf,buf_size,
+ "%02u:%02u:%02u ",
+ sec / 3600,
+ sec / 60 % 60,
+ sec % 60 );
+ }
+ else
+ {
+ *buf = 0;
+ len = 0;
+ }
+
+ if ( len >= buf_size )
+ {
+ len = buf_size - 1;
+ buf[len] = 0;
+ }
+ return len;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+int PrintLogTimestamp ( LogFile_t *lf )
+{
+ DASSERT(lf);
+ DASSERT(lf->log);
+
+ int stat = 0;
+ if ( lf && lf->log )
+ {
+ char buf[50];
+ stat = GetLogTimestamp(buf,sizeof(buf),lf->ts_mode);
+ if ( stat > 0 )
+ fwrite(buf,stat,1,lf->log);
+ }
+ return stat;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+int PutLogFile ( LogFile_t *lf, ccp text, int text_len )
+{
+ if (!lf)
+ lf = &GlobalLogFile;
+
+ if ( !lf->log || !text )
+ return 0;
+
+ //--- collect data first to have a single print
+
+ char buf[2000];
+ char *dest = buf + GetLogTimestamp( buf, sizeof(buf), lf->ts_mode );
+ dest = StringCopyEMem( dest, buf+sizeof(buf), lf->tag );
+ dest = StringCopyEM( dest, buf+sizeof(buf), text,
+ text_len < 0 ? strlen(text) : text_len );
+
+ const int len = dest - buf;
+ fwrite(buf,len,1,lf->log);
+ if (lf->flush)
+ fflush(lf->log);
+ if ( lf->log == stdout )
+ stdout_seq_count++;
+ return len;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+int PrintArgLogFile ( LogFile_t *lf, ccp format, va_list arg )
+{
+ int stat = 0;
+ if (format)
+ {
+ char buf[2000];
+ int len = vsnprintf(buf,sizeof(buf),format,arg);
+ if ( len >= 0 )
+ {
+ if ( len >= sizeof(buf)-1 )
+ {
+ len = sizeof(buf)-1;
+ buf[sizeof(buf)-1] = 0;
+ }
+ stat = PutLogFile(lf,buf,len);
+ }
+ }
+ return stat;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+int PrintLogFile ( LogFile_t *lf, ccp format, ... )
+{
+ va_list arg;
+ va_start(arg,format);
+ const int stat = PrintArgLogFile(lf,format,arg);
+ va_end(arg);
+ return stat;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// search tool ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+exmem_t SearchToolByPATH ( ccp tool )
+{
+ exmem_t dest = {};
+ if ( tool && *tool )
+ {
+ char fname[PATH_MAX];
+ if (strchr(tool,'/'))
+ {
+ struct stat st;
+ if ( !stat(tool,&st) && st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH) )
+ AssignExMemS(&dest,tool,-1,CPM_COPY);
+ }
+ else
+ {
+ ccp path = getenv("PATH");
+ for(;;)
+ {
+ while ( *path == ':' )
+ path++;
+ ccp start = path;
+ while ( *path && *path != ':' )
+ path++;
+ const int len = path - start;
+ if (!len)
+ break;
+
+ const int flen = snprintf(fname,sizeof(fname),"%.*s/%s",len,start,tool);
+ struct stat st;
+ if ( !stat(fname,&st) && st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH) )
+ {
+ AssignExMemS(&dest,fname,flen,CPM_COPY);
+ break;
+ }
+ }
+ }
+ }
+ return dest;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+exmem_t SearchToolByList ( ccp * list, int max )
+{
+ exmem_t dest = {};
+
+ if (list)
+ {
+ if ( max < 0 )
+ {
+ max = 0;
+ for ( ccp *ptr = list; *ptr; ptr++ )
+ max++;
+ }
+
+ while ( max-- > 0 )
+ {
+ ccp arg = *list++;
+ if (arg)
+ {
+ if ( *arg == '>' )
+ {
+ ccp env = getenv(arg+1);
+ if ( env && *env )
+ {
+ AssignExMemS(&dest,env,-1,CPM_LINK);
+ break;
+ }
+ }
+ else
+ {
+ dest = SearchToolByPATH(arg);
+ if (dest.data.len)
+ break;
+ }
+ }
+ }
+ }
+ return dest;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// pipe to pager ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static FILE *pager_file = 0;
+
+///////////////////////////////////////////////////////////////////////////////
+
+FILE * OpenPipeToPager()
+{
+ static bool done = false;
+
+ if (!done)
+ {
+ done = true;
+
+ static ccp search_tab[] =
+ {
+ ">DC_PAGER",
+ ">DC_PAGER1",
+ ">DC_PAGER2",
+ ">PAGER",
+ "less",
+ "more",
+ 0
+ };
+
+ exmem_t pager = SearchToolByList(search_tab,-1);
+ if (pager.data.ptr)
+ pager_file = popen(pager.data.ptr,"we");
+ FreeExMem(&pager);
+ }
+
+ return pager_file;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void ClosePagerFile()
+{
+ if (pager_file)
+ {
+ pclose(pager_file);
+ pager_file = 0;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool StdoutToPager()
+{
+ FILE *f = OpenPipeToPager();
+ if (f)
+ {
+ fflush(stdout);
+ stdout = f;
+ return true;
+ }
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CloseStdoutToPager()
+{
+ if ( pager_file && pager_file == stdout )
+ {
+ ClosePagerFile();
+ stdout = 0;
+ }
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
/////////////// enum FileMode_t ///////////////
///////////////////////////////////////////////////////////////////////////////
@@ -3246,6 +3557,69 @@ uint NumberedFilename
return index;
}
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static char * GetBlockDeviceHolderHelper
+ ( char *buf, char *endbuf, ccp name, ccp sep, int *level )
+{
+ DASSERT(buf);
+ DASSERT(endbuf);
+ DASSERT(level);
+
+ char path[200];
+ snprintf(path,sizeof(path),"/sys/class/block/%s/holders",name);
+ if (IsDirectory(path,0))
+ {
+ DIR *fdir = opendir(path);
+ if (fdir)
+ {
+ for(;;)
+ {
+ struct dirent *dent = readdir(fdir);
+ if (!dent)
+ break;
+ if ( dent->d_name[0] != '.' )
+ {
+ buf = GetBlockDeviceHolderHelper(buf,endbuf,dent->d_name,sep,level);
+ (*level)++;
+ break;
+ }
+ }
+ closedir(fdir);
+ }
+ }
+
+ return StringCat2E(buf,endbuf,sep,name);
+}
+
+//-----------------------------------------------------------------------------
+
+ccp GetBlockDeviceHolder ( ccp name, ccp sep, int *ret_level )
+{
+ static ParamField_t db = { .free_data = true };
+
+ bool old_found;
+ ParamFieldItem_t *item = FindInsertParamField(&db,name,false,0,&old_found);
+ DASSERT(item)
+ if (!old_found)
+ {
+ int level = 0;
+ char buf[1000];
+ ccp end = GetBlockDeviceHolderHelper(buf,buf+sizeof(buf)-strlen(sep)-1,name,sep,&level);
+ ccp beg = buf + strlen(sep);
+ if ( beg < end )
+ {
+ item->num = level;
+ item->data = MEMDUP(beg,end-beg+1);
+ }
+ }
+
+ if (ret_level)
+ *ret_level = item->num;
+ return item->data;
+}
+
//
///////////////////////////////////////////////////////////////////////////////
/////////////// normalize filenames ///////////////
@@ -3305,13 +3679,13 @@ char * NormalizeFileName
if ( isalnum(ch)
|| ( is_utf8
? ch >= 0x80
- : ch == 0xe4 // ä
- || ch == 0xf6 // ö
- || ch == 0xfc // ü
- || ch == 0xdf // ß
- || ch == 0xc4 // Ä
- || ch == 0xd6 // Ö
- || ch == 0xdc // Ü
+ : ch == 0xe4 // ä
+ || ch == 0xf6 // ö
+ || ch == 0xfc // ü
+ || ch == 0xdf // ß
+ || ch == 0xc4 // Ä
+ || ch == 0xd6 // Ö
+ || ch == 0xdc // Ü
)
|| strchr("_+-=%'\"$%&#,.!()[]{}<>",ch)
)
@@ -3439,7 +3813,7 @@ uint NormalizeFilenameCygwin
}
else
dest = buf;
- #else //
+ #else //
*dest++ = '/';
src += 2;
if (*src)
@@ -3623,7 +3997,7 @@ 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 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
@@ -3659,7 +4033,7 @@ static int add_search
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;
@@ -3755,6 +4129,7 @@ void ClearFDList ( FDList_t *fdl )
fdl->now_usec = GetTimeUSec(false);
fdl->timeout_usec = M1(fdl->timeout_usec);
+ fdl->timeout_nsec = M1(fdl->timeout_nsec);
}
///////////////////////////////////////////////////////////////////////////////
@@ -3815,10 +4190,11 @@ uint AddFDList
FDList_t *fdl, // valid socket list
int sock, // socket to add
- uint events // bit field: POLLIN|POLLOUT|POLLERR
+ uint events // bit field: POLLIN|POLLPRI|POLLOUT|POLLRDHUP|...
)
{
- if ( sock == -1 || !(events&(POLLIN|POLLOUT|POLLERR)) )
+ events &= ~(POLLERR|POLLHUP|POLLNVAL); // only result!
+ if ( sock == -1 || !events )
return ~0;
fdl->n_sock++;
@@ -3840,7 +4216,7 @@ uint AddFDList
FD_SET(sock,&fdl->readfds);
if ( events & POLLOUT )
FD_SET(sock,&fdl->writefds);
- if ( events & POLLERR )
+ if ( events & POLLPRI )
FD_SET(sock,&fdl->exceptfds);
return ~0;
}
@@ -3849,7 +4225,7 @@ uint AddFDList
uint GetEventFDList
(
- // returns bit field: POLLIN|POLLOUT|POLLERR
+ // returns bit field: POLLIN|POLLOUT|POLLERR|...
FDList_t *fdl, // valid socket list
int sock, // socket to look for
@@ -3879,13 +4255,53 @@ uint GetEventFDList
if (FD_ISSET(sock,&fdl->writefds))
revents |= POLLOUT;
if (FD_ISSET(sock,&fdl->exceptfds))
- revents |= POLLERR;
+ revents |= POLLPRI;
return revents;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
+static s_usec_t prepare_wait_fdl ( FDList_t *fdl )
+{
+ DASSERT(fdl);
+ const s_usec_t now_usec = GetTimeUSec(false);
+
+ if (fdl->timeout_nsec)
+ {
+ const u_usec_t wait_until
+ = ( (s_usec_t)fdl->timeout_nsec - (s_usec_t)GetTimerNSec() )
+ / NSEC_PER_USEC + now_usec + 1;
+ if ( !fdl->timeout_usec || fdl->timeout_usec > wait_until )
+ fdl->timeout_usec = wait_until;
+ }
+
+ if ( fdl->min_wait_usec && fdl->timeout_usec )
+ {
+ const u_usec_t wait_until = now_usec + fdl->min_wait_usec;
+ if ( fdl->timeout_usec < wait_until )
+ fdl->timeout_usec = wait_until;
+ }
+
+ return now_usec;
+}
+
+//-----------------------------------------------------------------------------
+
+static void finish_wait_fdl ( FDList_t *fdl, u_usec_t start_usec )
+{
+ DASSERT(fdl);
+ UpdateCurrentTime();
+ fdl->now_usec = current_time.usec;
+ fdl->last_wait_usec = fdl->now_usec - start_usec;
+ fdl->wait_usec += fdl->last_wait_usec;
+ fdl->wait_count++;
+
+ UpdateCpuUsageIncrement();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
int WaitFDList
(
FDList_t *fdl // valid socket list
@@ -3893,49 +4309,75 @@ int WaitFDList
{
DASSERT(fdl);
- int stat;
- u64 now_usec = GetTimeUSec(false);
+ const s_usec_t now_usec = prepare_wait_fdl(fdl);
+ int stat;
if (fdl->use_poll)
{
int timeout;
- if ( fdl->timeout_usec > now_usec )
+ if ( !fdl->timeout_usec )
+ timeout = -1;
+ else if ( fdl->timeout_usec > now_usec )
{
- u64 delta = ( fdl->timeout_usec - now_usec ) / 1000;
- timeout = delta > 0x7fffffffull ? -1 : delta;
+ u_msec_t delta = ( fdl->timeout_usec - now_usec ) / USEC_PER_MSEC;
+ timeout = delta < 0x7fffffff ? delta : 0x7fffffff;
+ if (!timeout)
+ timeout = 1;
}
else
timeout = 0;
+ if (fdl->debug_file)
+ {
+ fprintf(fdl->debug_file,"POLL: timeout=%d\n",timeout);
+ fflush(fdl->debug_file);
+ }
stat = poll( fdl->poll_list, fdl->poll_used, timeout );
}
else
{
struct timeval tv, *ptv = &tv;
- if ( fdl->timeout_usec > now_usec )
+ if ( !fdl->timeout_usec )
+ ptv = NULL;
+ else if ( fdl->timeout_usec > now_usec )
{
- const u64 delta = fdl->timeout_usec - now_usec;
- if ( delta > 1000000ull * 0x7fffffffull )
- ptv = NULL;
+ const u_usec_t delta = fdl->timeout_usec - now_usec;
+ if ( delta > USEC_PER_YEAR )
+ {
+ tv.tv_sec = SEC_PER_YEAR;
+ tv.tv_usec = 0;
+ }
+ else if ( delta > USEC_PER_MSEC )
+ {
+ tv.tv_sec = delta / USEC_PER_SEC;
+ tv.tv_usec = delta % USEC_PER_SEC;
+ }
else
{
- tv.tv_sec = delta / 1000000;
- tv.tv_usec = delta % 1000000;
+ tv.tv_sec = 0;
+ tv.tv_usec = USEC_PER_MSEC;
}
}
else
tv.tv_sec = tv.tv_usec = 0;
-//DEL fprintf(stderr,"#SELECT %lld: ptv=%d: %lu.%06lu\n",
-//DEL fdl->timeout_usec-now_usec, ptv!=0, tv.tv_sec, tv.tv_usec );
+ if (fdl->debug_file)
+ {
+ if (ptv)
+ fprintf(fdl->debug_file,"# SELECT: usec=%lld, Δnow=%lld, timeout=%llu.%06llu\n",
+ fdl->timeout_usec, fdl->timeout_usec - now_usec,
+ (u64)ptv->tv_sec, (u64)ptv->tv_usec );
+ else
+ fprintf(fdl->debug_file,"# SELECT: usec=%lld, Δnow=%lld, timeout=NULL\n",
+ fdl->timeout_usec, fdl->timeout_usec - now_usec );
+ fflush(fdl->debug_file);
+ }
+
stat = select( fdl->max_fd+1, &fdl->readfds, &fdl->writefds,
&fdl->exceptfds, ptv );
}
- fdl->now_usec = GetTimeUSec(false);
- fdl->cur_usec = fdl->now_usec - now_usec;
- fdl->wait_usec += fdl->cur_usec;
- fdl->wait_count++;
+ finish_wait_fdl(fdl,now_usec);
return stat;
}
@@ -3943,7 +4385,7 @@ int WaitFDList
int PWaitFDList
(
- FDList_t *fdl, // valid socket list
+ FDList_t *fdl, // valid socket list
const sigset_t *sigmask // NULL or signal mask
)
{
@@ -3963,18 +4405,24 @@ int PWaitFDList
}
#endif
+ const u_usec_t now_usec = prepare_wait_fdl(fdl);
+
struct timespec ts, *pts = &ts;
- u64 now_usec = GetTimeUSec(false);
if ( fdl->timeout_usec > now_usec )
{
const u64 delta = fdl->timeout_usec - now_usec;
if ( delta > 1000000ull * 0x7fffffffull )
pts = NULL;
- else
+ else if ( delta > USEC_PER_MSEC )
{
ts.tv_sec = delta / 1000000;
ts.tv_nsec = delta % 1000000 * 1000;
}
+ else
+ {
+ ts.tv_sec = 0;
+ ts.tv_nsec = NSEC_PER_MSEC;
+ }
}
else
ts.tv_sec = ts.tv_nsec = 0;
@@ -3989,10 +4437,7 @@ int PWaitFDList
&fdl->exceptfds, pts, sigmask );
#endif
- fdl->now_usec = GetTimeUSec(false);
- fdl->cur_usec = fdl->now_usec - now_usec;
- fdl->wait_usec += fdl->cur_usec;
- fdl->wait_count++;
+ finish_wait_fdl(fdl,now_usec);
return stat;
}
@@ -5391,6 +5836,8 @@ void RestoreStateByTable
uint aelem_count = 0;
uint aelem_offset = 0;
+ bool mode_add = false;
+
for ( ; srt->type != SRT__TERM; srt++ )
{
if ( srt->type == SRT_DEF_ARRAY )
@@ -5407,6 +5854,16 @@ void RestoreStateByTable
continue;
}
+ if ( srt->type >= SRT_MODE__BEGIN && srt->type <= SRT_MODE__END )
+ {
+ switch (srt->type)
+ {
+ case SRT_MODE_ASSIGN: mode_add = false; break;
+ case SRT_MODE_ADD: mode_add = true; break;
+ }
+ continue;
+ }
+
if ( srt->type == SRT__IS_LIST || !srt->name )
continue;
@@ -5456,13 +5913,22 @@ void RestoreStateByTable
if ( !i && srt->type == SRT_COUNT && num <= UINT_MAX )
last_count = num;
- switch(srt->size)
- {
- case 1: *(u8*) val = num; break;
- case 2: *(u16*)val = num; break;
- case 4: *(u32*)val = num; break;
- case 8: *(u64*)val = num; break;
- }
+ if (mode_add)
+ switch(srt->size)
+ {
+ case 1: *(u8*) val += num; break;
+ case 2: *(u16*)val += num; break;
+ case 4: *(u32*)val += num; break;
+ case 8: *(u64*)val += num; break;
+ }
+ else
+ switch(srt->size)
+ {
+ case 1: *(u8*) val = num; break;
+ case 2: *(u16*)val = num; break;
+ case 4: *(u32*)val = num; break;
+ case 8: *(u64*)val = num; break;
+ }
if ( ++i == n_elem )
break;
val += elem_off;
@@ -5485,13 +5951,22 @@ void RestoreStateByTable
while (*src)
{
s64 num = str2ll(src,&src,10);
- switch(srt->size)
- {
- case 1: *(s8*) val = num; break;
- case 2: *(s16*)val = num; break;
- case 4: *(s32*)val = num; break;
- case 8: *(s64*)val = num; break;
- }
+ if (mode_add)
+ switch(srt->size)
+ {
+ case 1: *(s8*) val += num; break;
+ case 2: *(s16*)val += num; break;
+ case 4: *(s32*)val += num; break;
+ case 8: *(s64*)val += num; break;
+ }
+ else
+ switch(srt->size)
+ {
+ case 1: *(s8*) val = num; break;
+ case 2: *(s16*)val = num; break;
+ case 4: *(s32*)val = num; break;
+ case 8: *(s64*)val = num; break;
+ }
if ( ++i == n_elem )
break;
val += elem_off;
@@ -5514,12 +5989,25 @@ void RestoreStateByTable
uint i = 0;
while (*src)
{
- 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 (mode_add)
+ {
+ 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);
+ }
+ else
+ {
+ 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;
@@ -6378,6 +6866,192 @@ int PrintScriptVars
//
///////////////////////////////////////////////////////////////////////////////
+/////////////// CpuStatus_t ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+CpuStatus_t GetCpuStatus ( CpuStatus_t * prev_cpuinfo )
+{
+ //--- retrieve static data
+
+ static int n_cpu = -1;
+ static int clock_ticks = 100;
+
+ char buf[1000];
+
+ if ( n_cpu < 0 )
+ {
+ n_cpu = 0;
+ FILE *f = fopen("/proc/cpuinfo","r");
+ if (f)
+ {
+ while (fgets(buf,sizeof(buf),f))
+ if ( !memcmp(buf,"processor",9) && buf[9] <= ' ' )
+ n_cpu++;
+ fclose(f);
+ }
+
+ clock_ticks = sysconf(_SC_CLK_TCK);
+ if ( clock_ticks <= 0 )
+ clock_ticks = 100;
+ }
+
+
+ //--- retrieve cpu data
+
+ CpuStatus_t current =
+ {
+ .valid = true,
+ .nsec = GetTimerNSec(),
+ .n_cpu = n_cpu,
+ .clock_ticks = clock_ticks
+ };
+
+
+ // man 5 proc | oo +/proc/loadavg
+ FILE *f_load = fopen("/proc/loadavg","r");
+ if (f_load)
+ {
+ if (fgets(buf,sizeof(buf),f_load))
+ {
+ char *ptr = buf;
+ current.loadavg_1m = strtod(ptr,&ptr);
+ current.loadavg_5m = strtod(ptr,&ptr);
+ current.loadavg_15m = strtod(ptr,&ptr);
+
+ current.running_proc = strtol(ptr,&ptr,10);
+ current.total_proc = strtol(ptr+1,&ptr,10);
+ }
+ fclose(f_load);
+ }
+
+
+ // man 5 proc | oo +/proc/stat
+ FILE * f_stat = fopen("/proc/stat","r");
+ if (f_stat)
+ {
+ while (fgets(buf,sizeof(buf),f_stat))
+ if ( !memcmp(buf,"cpu ",4) )
+ {
+ char *ptr = buf;
+ current.user = strtol(ptr+4,&ptr,10) * 10000 / clock_ticks;
+ current.nice = strtol(ptr,&ptr,10) * 10000 / clock_ticks;
+ current.system = strtol(ptr,&ptr,10) * 10000 / clock_ticks;
+ current.idle = strtol(ptr,&ptr,10) * 10000 / clock_ticks;
+ break;
+ }
+ fclose(f_stat);
+ }
+
+ if (!prev_cpuinfo)
+ return current;
+
+
+ //--- get delta for result
+
+ if (!prev_cpuinfo->valid)
+ *prev_cpuinfo = current;
+
+ CpuStatus_t res = current;
+ res.nsec -= prev_cpuinfo->nsec;
+ res.user -= prev_cpuinfo->user;
+ res.nice -= prev_cpuinfo->nice;
+ res.system -= prev_cpuinfo->system;
+ res.idle -= prev_cpuinfo->idle;
+
+ *prev_cpuinfo = current;
+ return res;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+ccp PrintCpuStatus ( const CpuStatus_t * cpuinfo )
+{
+ if ( !cpuinfo || !cpuinfo->valid )
+ return "INVALID";
+
+ return PrintCircBuf(
+ "ticks=%d, cpus=%d, times=%lld+%lld+%lld+%lld=%lld, avg=%4.2f,%4.2f,%4.2f %u/%u, nsec=%llu",
+ cpuinfo->clock_ticks,
+ cpuinfo->n_cpu,
+ cpuinfo->user, cpuinfo->nice, cpuinfo->system, cpuinfo->idle,
+ cpuinfo->user + cpuinfo->nice + cpuinfo->system + cpuinfo->idle,
+ cpuinfo->loadavg[0], cpuinfo->loadavg[1], cpuinfo->loadavg[2],
+ cpuinfo->running_proc, cpuinfo->total_proc,
+ cpuinfo->nsec );
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// MemoryStatus_t ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+MemoryStatus_t GetMemoryStatus(void)
+{
+ MemoryStatus_t mem = {0};
+
+ FILE *f = fopen("/proc/meminfo","r");
+ if (f)
+ {
+ char buf[200];
+ int count = 5; // abort, if all 5 params scanned
+
+ while ( count > 0 && fgets(buf,sizeof(buf),f) )
+ {
+ ccp colon = strchr(buf,':');
+ if (colon)
+ {
+ u64 num = strtoul(colon+1,0,10) * 1024;
+ switch (colon-buf)
+ {
+ case 6:
+ if (!memcmp(buf,"Cached",6)) { count--; mem.cached = num; break; }
+ break;
+
+ case 7:
+ if (!memcmp(buf,"MemFree",7)) { count--; mem.free = num; break; }
+ if (!memcmp(buf,"Buffers",7)) { count--; mem.buffers = num; break; }
+ break;
+
+ case 8:
+ if (!memcmp(buf,"MemTotal",8)) { count--; mem.total = num; break; }
+ break;
+
+ case 12:
+ if (!memcmp(buf,"MemAvailable",12)) { count--; mem.avail = num; break; }
+ break;
+ }
+ }
+ }
+ fclose(f);
+ mem.used = mem.total - mem.free - mem.buffers - mem.cached;
+ }
+ return mem;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+ccp PrintMemoryStatus ( const MemoryStatus_t * ms )
+{
+ MemoryStatus_t temp;
+ if (!ms)
+ {
+ temp = GetMemoryStatus();
+ ms = &temp;
+ }
+
+ const sizeform_mode_t mode = DC_SFORM_NARROW;
+ return PrintCircBuf(
+ "tot=%s, free=%s, avail=%s, used=%s, buf=%s, cache=%s\n",
+ PrintNumberU7(0,0,ms->total,mode),
+ PrintNumberU7(0,0,ms->free,mode),
+ PrintNumberU7(0,0,ms->avail,mode),
+ PrintNumberU7(0,0,ms->used,mode),
+ PrintNumberU7(0,0,ms->buffers,mode),
+ PrintNumberU7(0,0,ms->cached,mode) );
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
/////////////// END ///////////////
///////////////////////////////////////////////////////////////////////////////