1
#define __MODULE__ "UTIL$"
2
#define __IDENT__ "V.01-00"
3
#define __REV__ "1.00.0"
7
** Abstract: General purpose and utility routines
9
** Author: Ruslan R. Laishev
11
** Creation date: 4-SEP-2017
13
** Modification history:
15
** 25-SEP-2017 RRL Added __util$log2buf(): format a message into the given buffer.
17
** 5-OCT-2017 RRL Added __util$syslog() : format and send a message to SYSLOG server;
18
** recoding __util$setlogfile -> util$deflog() to accept a SYSLOG IP address
21
** 6-OCT-2017 RRL Adopted __util$syslog() for M$ Windows.
23
** 12-OCT-2017 RRL Added conditional blocks on the __SYSLOG__;
24
** other changes to improve stability of code;
26
** 27-APR-2018 RRL Changed handling of the OPTS$K_INT to allow accept decimals and hexadecimals,
27
** replaced atoi() with strtoul().
29
** 28-MAY-2018 RRL Correct text of message.
31
** 6-AUG-2018 SYS Added a support for 64-bits long in the routines related option's processing.
33
** 10-NOV-2018 RRL Recoded logging related routines to use 'fd' instead of FILE;
35
** 12-NOV-2018 RRL Changed __util$rewindlog() to truncate file at begin after rewinding.
37
** 23-NOV-2018 RRL Fixed lseek()->29 on STDOUT_FILENO in the __util$rewindlogfile();
39
** 23-APR-2019 RRL Recoded __util$readconfig() to allow using similar keywords like:
43
** 4-JUN-2019 RRL Improved output buffer security in the $trace(), $log(), $logd(), $log2buf() routines.
45
** 25-JUN-2019 ARL Special changes for Adnroid;
46
** RRL Small changes in the __utility$trace();
48
** 8-JUL-2019 RRL Improved code quality in the routines processing of configuration options.
50
** 5-OCT-2019 RRL Adopted gettid() for APPLE/OSX
52
** 30-DEC-2019 RRL Improved error handling during processing _CONF option.
54
** 19-MAR-2020 RRL Addeв O_APPEND flag in call of open() in the __util$deflog().
56
** 7-MAY-2020 RRL Fixed incorrect value of 'mode' argument of open() under Windows.
61
#define _CRT_SECURE_NO_WARNINGS 1
62
#define WIN32_LEAN_AND_MEAN
68
#include <sys/timeb.h>
81
#include <sys/types.h>
87
#include <android/log.h>
92
//#include <execinfo.h>
93
#include <arpa/inet.h>
99
#define TIMSPECDEVIDER 1000000 /* Used to convert timespec's nanosec tro miliseconds */
101
#define gettid() GetCurrentThreadId()
102
//#define gettid() GetCurrentProcessId()
103
#define TIMSPECDEVIDER 1000 /* Used to convert timeval's microseconds to miliseconds */
104
#define PID_FMT "%6d"
106
#define gettid() (0xDEADBEEF)
110
#define __TRACE__ /* Enable $TRACE facility macro */
113
#include "utility_routines.h"
117
#pragma GCC diagnostic push
118
#pragma GCC diagnostic ignored "-Wparentheses"
123
#ifndef STDERR_FILENO
124
#define STDERR_FILENO 2
128
#define STDIN_FILENO 0
131
#ifndef STDOUT_FILENO
132
#define STDOUT_FILENO 1
138
int logoutput = STDOUT_FILENO; /* Default descriptor for default output device */
140
struct sockaddr_in slogsock; /* SYSLOG Host socket */
145
#define _GNU_SOURCE 1
148
#include <sys/syscall.h>
152
static inline pid_t gettid(void)
155
#if defined(__APPLE__) || defined(__OSX__)
168
* Description: a simplified analog of the C RTL syslog() routine is supposed to used to
169
* format and send a message directly to IP (has been defined by $deflog();
172
* __util$deflog(NULL, "172.28.4.112");
174
* char msg [] = "GAMEOVER, all your base are belong to us";
175
* __util$syslog(LOG_KERN, LOG_DEBUG, "NOXBIT", msg, sizeof(msg));
178
* fac: SYSLOG Facility code, see LOG_* constants
179
* pri: SYSLOG Severity code, see LOG_* constants
180
* tag: A tag string - a part of the MSG part :-)
181
* msg: message buffer to be send
182
* msglen: message length
190
unsigned __util$syslog
204
WSAMSG msg_desc = { 0 };
205
WSABUF bufv[] = {{buf, 0}, {msg, msglen}};
208
struct iovec bufv[] = {{buf, 0}, {msg, msglen}};
209
struct msghdr msg_desc = {0};
216
inet_aton("172.28.4.112", &slogsock.sin_addr);
217
slogsock.sin_port = htons(514);
218
slogsock.sin_family = AF_INET;
224
if ( status = WSAStartup(MAKEWORD(2,2), &wsa_data) )
226
perror("WSAstartup");
231
if ( 0 > (sd = socket(AF_INET, SOCK_DGRAM, 0)) )
238
/* Prepare the msghdr structure */
240
msg_desc.name = &slogsock;
241
msg_desc.namelen = sizeof(slogsock);
243
msg_desc.lpBuffers = (void *) &bufv;
244
msg_desc.dwBufferCount = sizeof(bufv)/sizeof(bufv[0]);
246
/* Form <priority + severity> part, add the tag field */
247
bufv[0].len = sprintf(buf, "<%d> %s: ", fac + sev, tag);
249
if ( 0 > WSASendMsg (sd, &msg_desc, 0, 0, 0, 0) )
257
msg_desc.msg_name = &slogsock;
258
msg_desc.msg_namelen = sizeof(slogsock);
260
msg_desc.msg_iov = (void *) &bufv;
261
msg_desc.msg_iovlen = sizeof(bufv)/sizeof(bufv[0]);
263
/* Form <priority + severity> part, add the tag field */
264
bufv[0].iov_len = sprintf(buf, "<%d> %16s: ", fac + sev, tag);
265
if ( 0 > sendmsg (sd, &msg_desc, 0) )
274
return STS$K_SUCCESS;
279
* Description: out to the current SYS$OUTPUT option's name and values.
283
* opts: options' table, address of array terminated by 'NUL' entry
290
int __util$showparams (
296
for (optp = opts; $ASCLEN(&optp->name); optp++)
298
switch ( optp->type )
301
$LOG(STS$K_INFO, "%.*s = %d (0x%04.4x)", $ASC(&optp->name),
302
*((unsigned short *) optp->ptr), *((unsigned short *) optp->ptr));
306
$LOG(STS$K_INFO, "%.*s = %s", $ASC(&optp->name), inet_ntoa( *((struct in_addr *) optp->ptr)) );
310
$LOG(STS$K_INFO, "%.*s = %s", $ASC(&optp->name), * ((int *)optp->ptr) ? "ON" : "OFF");
316
case (sizeof (unsigned long long)):
317
$LOG(STS$K_INFO, "%.*s = %llu (%#llx)", $ASC(&optp->name), *((unsigned long long *) optp->ptr),
318
*((unsigned long long *) optp->ptr));
321
case (sizeof (unsigned short)):
322
$LOG(STS$K_INFO, "%.*s = %d (%#x)", $ASC(&optp->name), *((unsigned short *) optp->ptr),
323
*((unsigned short *) optp->ptr));
327
$LOG(STS$K_INFO, "%.*s = %d (%#x)", $ASC(&optp->name), *((int *) optp->ptr), *((int *) optp->ptr));
333
$LOG(STS$K_INFO, "%.*s[0:%u] ='%.*s'", $ASC(&optp->name), ((ASC *)optp->ptr)->len, $ASC(optp->ptr));
337
$LOG(STS$K_INFO, "%.*s[0:%u] ='<password>'", $ASC(&optp->name), ((ASC *)optp->ptr)->len, $ASC(optp->ptr));
343
return STS$K_SUCCESS;
349
* Description: processing command line arguments to extract parameters according of options table;
350
* performs basic syntax checking, copy options values to local storage for using at run-time.
352
* fconf: A configuration file to be processed
353
* opts: options' table, address of array terminated by 'NUL' entry
356
* fills the 'runparams' vector by option
362
int __util$readconfig (
369
const char novalp [ 32 ] = {0};
370
char *argp, *valp = novalp, buf[256];
374
* Is the configuration file has been specified ?
376
if ( fconf && (*fconf) )
378
if ( !(finp = fopen(fconf, "r")) )
379
return $LOG(STS$K_ERROR, "Error open file '%s', errno = %d", fconf, errno);
383
* We expect to see opts in form: -<options_name>=<options_value>
385
for ( i = 1; fgets(buf, sizeof(buf), finp); i++ )
387
if ( !__util$uncomment(buf, (int) strlen(buf), '!') )
390
if ( !__util$trim(buf, (int) strlen(buf)) )
393
if ( (*(argp = buf) != '-') && (*(argp = buf) != '/') )
395
$LOG(STS$K_ERROR, "%s : %d : Option must be started with a '-' or '/', skip : '%s'", fconf, i, buf);
399
if ( valp = strchr(++argp, '=') )
401
argslen = (int) (valp - argp);
405
argslen = (int) strlen(argp);
411
* Compare a given from command line option name against options list,
412
* we expect that options list is terminated by zero-length entry.
414
* We allow an shortened keywords but it can be a reason of conflicts.
416
for (optp2 = NULL, optp = opts; $ASCLEN(&optp->name); optp++)
419
if ( !(_strnicmp (argp, $ASCPTR(&optp->name), $MIN(argslen, $ASCLEN(&optp->name)))) )
421
if ( !(strncasecmp (argp, $ASCPTR(&optp->name), $MIN(argslen, $ASCLEN(&optp->name)))) )
424
if ( argslen == $ASCLEN(&optp->name) ) /* Full matching */
430
if ( !optp2 ) /* If it's first hit - save option */
438
* Is the new hit is longest than old ?
440
if ( $ASCLEN(&optp2->name) < $ASCLEN(&optp->name) )
445
if ( !optp2 || !$ASCLEN(&optp2->name) )
447
$LOG(STS$K_WARN, "%s : %d : Skip unrecognized or unused option", fconf, i);
452
optp = optp2 ? optp2 : optp;
455
__util$trim (valp, (int) strlen(valp));
457
switch ( optp->type )
460
* ((unsigned short *) optp->ptr) = (unsigned short) atoi(valp);
465
if ( ! ((*(long *) optp->ptr) = inet_addr (valp)) )
467
if ( !inet_aton(valp, (struct in_addr *) optp->ptr) )
469
$LOG(STS$K_ERROR, "%s : %d : Error conversion '%s' to IP4 address", fconf, i, valp);
473
* ((int *)optp->ptr) = 1;
481
case (sizeof (unsigned long long)):
482
* ((unsigned long long *) optp->ptr) = strtoull(valp, &endptr, 0);
486
* ((int *) optp->ptr) = strtoul(valp, &endptr, 0);
494
((ASC *)optp->ptr)->len = (unsigned char) $MIN(strnlen(valp, optp->sz), ASC$K_SZ);
495
memcpy( ((ASC *)optp->ptr)->sts, valp, ((ASC *)optp->ptr)->len);
496
((ASC *)optp->ptr)->sts[((ASC *)optp->ptr)->len] = '\0';
500
$LOG(STS$K_ERROR, "%s : %d : Unrecognized option's '%.*s' internal type : 0x%X", fconf, i, $ASC(&optp->name), optp->type);
504
if ( finp && (finp != stdin) )
508
return STS$K_SUCCESS;
514
* Description: processing command line arguments to extract parameters according of options table;
515
* performs basic syntax checking, copy options values to local storage for using at run-time.
517
* argc: an argument count
518
* argv: an array of command line options
519
* opts: options' table, address of array terminated by 'NUL' entry
522
* fills the 'runparams' vector by option
528
int __util$getparams (
536
const char novalp [ 32 ] = {0};
537
char *argp, *valp = novalp;
542
* We expect to see opts in form:
543
* -<options_name>=<options_value>
545
* /<options_name>=<options_value>
547
for ( i = 1; i < argc; i++ )
549
/* Skip zero length strings */
550
if ( !strlen (argv[i]) )
553
/* Check option designator */
554
if ( (*(argp = argv[i]) != '-') && (*(argp = argv[i]) != '/') )
556
$LOG(STS$K_ERROR, "%d: Option must be started with '-' or '/', skip : '%s'", i, argv[i]);
560
if ( valp = strchr(++argp, '=') )
562
argslen = valp - argp;
566
argslen = strlen(argp);
571
* Compare a given from command line option name against options list,
572
* we expect that options list is terminated by zero-length entry.
574
* We allow an shortened keywords but it can be a reao of conflicts.
576
for (optp = opts; $ASCLEN(&optp->name); optp++)
578
if ( argslen != $ASCLEN(&optp->name) )
582
if ( !(_strnicmp (argp, $ASCPTR(&optp->name), $MIN(argslen, $ASCLEN(&optp->name)))) )
584
if ( !(strncasecmp (argp, $ASCPTR(&optp->name), $MIN(argslen, $ASCLEN(&optp->name)))) )
589
if ( !optp || !$ASCLEN(&optp->name) )
591
$LOG(STS$K_ERROR, "%d : Skip unrecognized option: '%s'", i, argp);
596
__util$trim (valp, (int) strlen(valp));
598
switch ( optp->type )
603
/* Store name of configuration file */
604
((ASC *)optp->ptr)->len = (unsigned char) strnlen(valp, sizeof(((ASC *)optp->ptr)->sts));
605
memcpy( ((ASC *)optp->ptr)->sts, valp, ((ASC *)optp->ptr)->len);
606
((ASC *)optp->ptr)->sts[((ASC *)optp->ptr)->len] = '\0';
609
if ( !(1 & __util$readconfig (valp, opts)) )
615
* ((unsigned short *) optp->ptr) = (unsigned short) atoi(valp);
620
if ( ! ((*(long *) optp->ptr) = inet_addr (valp)) )
622
if ( !inet_aton(valp, (struct in_addr *) optp->ptr) )
624
$LOG(STS$K_ERROR, "%d : Error conversion '%s' to IP4 address", i, valp);
628
* ((int *)optp->ptr) = 1;
636
case (sizeof (unsigned long long)):
637
* ((unsigned long long *) optp->ptr) = strtoull(valp, &endptr, 0);
641
* ((int *) optp->ptr) = strtoul(valp, &endptr, 0);
649
((ASC *)optp->ptr)->len = (unsigned char) $MIN(strnlen(valp, optp->sz), ASC$K_SZ);
650
memcpy( ((ASC *)optp->ptr)->sts, valp, ((ASC *)optp->ptr)->len);
651
((ASC *)optp->ptr)->sts[((ASC *)optp->ptr)->len] = '\0';
655
$LOG(STS$K_ERROR, "%d : Unrecognized option's '%.*s' internal type : 0x%X", i, $ASC(&optp->name), optp->type);
659
return STS$K_SUCCESS;
665
* Description: dump byte array to sys$output in hex, is supposed to be called indirectly by $DUMPHEX macro.
668
* __fi: A file name or module name string
669
* __li: Line number in the sourve file
670
* src: A pointer to source buffer do be dumped
671
* srclen: A Length of the source buffer
681
void __util$dumphex (
685
unsigned short srclen
688
const char lfmt [] = {"%02u-%02u-%04u %02u:%02u:%02u.%03u [%s\\%u] Dump of %u octets follows:"};
690
unsigned char *srcp = (unsigned char *) src, low, high;
691
unsigned olen = 0, i, j;
696
** Out to buffer "DD-MM-YYYY HH:MM:SS.msec [<function>\<line>]" prefix
701
localtime_s(&_tm, (time_t *)&now);
703
localtime_r((time_t *)&now, &_tm);
706
olen = snprintf (out, sizeof(out) - 1, lfmt,
707
_tm.tm_mday, _tm.tm_mon + 1, 1900 + _tm.tm_year,
708
_tm.tm_hour, _tm.tm_min, _tm.tm_sec, (unsigned) now.tv_nsec/TIMSPECDEVIDER,
711
/* Add <LF> at end of record*/
712
out[$MIN(olen++, sizeof(out))] = '\n';
713
write (logoutput, out, olen );
715
memset(out, ' ', sizeof(out));
718
** Format variable part of string line
720
for (i = 0; i < ((srclen / 16)); i++)
722
olen = sprintf(out, "\t+%04x: ", i * 16);
723
memset(out + olen, ' ', sizeof(out) - olen);
725
for (j = 0; j < 16; j++, srcp++)
728
low = (*srcp) & 0x0f;
730
out[olen + j * 3] = high + ((high < 10) ? '0' : 'a' - 10);
731
out[olen + j * 3 + 1] = low + ((low < 10) ? '0' : 'a' - 10);
733
out[olen + 16*3 + 2 + j] = isprint(*srcp) ? *srcp : '.';
736
/* Add <LF> at end of record*/
737
out[sizeof(out) - 1] = '\n';
739
/* Write to file and flush buffer depending on severity level */
740
write (logoutput, out, sizeof(out) );
745
olen = sprintf(out, "\t+%04x: ", i * 16);
746
memset(out + olen, ' ', sizeof(out) - olen);
748
for (j = 0; j < srclen % 16; j++, srcp++)
751
low = (*srcp) & 0x0f;
753
out[olen + j * 3] = high + ((high < 10) ? '0' : 'a' - 10);
754
out[olen + j * 3 + 1] = low + ((low < 10) ? '0' : 'a' - 10);
756
out[olen + 16*3 + 2 + j] = isprint(*srcp) ? *srcp : '.';
759
/* Add <LF> at end of record*/
760
out[sizeof(out) - 1] = '\n';
762
/* Write to file and flush buffer depending on severity level */
763
write (logoutput, out, sizeof(out) );
770
* Description: dump byte array to sys$output in hex, is supposed to be called indirectly by $DUMPHEX macro.
773
* src: A pointer to source buffer do be dumped
774
* srclen: A Length of the source buffer
786
unsigned short srclen,
791
unsigned char *srcp = (unsigned char *) src, low, high;
794
memset(out, ' ', outsz);
796
for (j = 0; j < 16; j++, srcp++)
799
low = (*srcp) & 0x0f;
801
out[j * 3] = high + ((high < 10) ? '0' : 'a' - 10);
802
out[j * 3 + 1] = low + ((low < 10) ? '0' : 'a' - 10);
804
out[16*3 + 2 + j] = isprint(*srcp) ? *srcp : '.';
807
out[16*3 + 2 + j] = '\0';
821
* Description: print to sys$output a programm trace information, supposed to be called from
825
* fmt: A format string
826
* __fi: A file name or module name string
827
* __li: Line number in the source file
828
* ... Format string arguments
848
const char lfmt [] = {"%02u-%02u-%04u %02u:%02u:%02u.%03u " PID_FMT " [%s\\%u] "},
849
mfmt [] = {"%02u-%02u-%04u %02u:%02u:%02u.%03u " PID_FMT " [%s\\%s\\%u] "};
861
** Out to buffer "DD-MM-YYYY HH:MM:SS.msec [<function>\<line>]" prefix
866
localtime_s(&_tm, (time_t *)&now);
868
localtime_r((time_t *)&now, &_tm);
872
? sprintf (out, mfmt, _tm.tm_mday, _tm.tm_mon + 1, 1900 + _tm.tm_year,
873
_tm.tm_hour, _tm.tm_min, _tm.tm_sec, (unsigned) now.tv_nsec/TIMSPECDEVIDER,
874
(unsigned) gettid(), __mod, __fi, __li)
875
: sprintf (out, lfmt, _tm.tm_mday, _tm.tm_mon + 1, 1900 + _tm.tm_year,
876
_tm.tm_hour, _tm.tm_min, _tm.tm_sec, (unsigned) now.tv_nsec/TIMSPECDEVIDER,
877
(unsigned) gettid(), __fi, __li);
880
** Format variable part of string line
882
va_start (arglist, __li);
883
olen += vsnprintf(out + olen, sizeof(out), fmt, arglist);
886
olen = $MIN(olen, sizeof(out) - 1);
888
/* Add <LF> at end of record*/
891
/* Write to file and flush buffer */
892
write (logoutput, out, olen );
896
/* ARL - for android logcat */
898
__android_log_print(ANDROID_LOG_VERBOSE, __mod, "%.*s", olen, out);
903
va_start (arglist, __li);
904
olen = vsnprintf(out, sizeof(out), fmt, arglist);
907
__util$syslog (LOG_USER, LOG_DEBUG, __mod, out, olen);
909
// syslog( LOG_PID | ((sev & 1) ? LOG_INFO : LOG_ERR), "%.*s", olen, out);
911
#endif /* __SYSLOG__ */
918
const char severity[STS$K_UNDEF + 1][16] = { "-W: ", "-S: ", "-E: ", "-I: ", "-F: ", "-?: "};
930
const char lfmt [] = "%02u-%02u-%04u %02u:%02u:%02u.%03u " PID_FMT " %%%s%3s";
932
unsigned olen, _sev = sev, opcom = sev & STS$K_SYSLOG;
939
if ( !($ISINRANGE(sev, STS$K_WARN, STS$K_ERROR)) )
943
** Out to buffer "DD-MM-YYYY HH:MM:SS.msec [<function>\<line>]<FAC>-E:" prefix
948
localtime_s(&_tm, (time_t *)&now);
950
localtime_r((time_t *)&now, &_tm);
953
olen = sprintf (out, lfmt,
954
_tm.tm_mday, _tm.tm_mon + 1, 1900 + _tm.tm_year,
955
_tm.tm_hour, _tm.tm_min, _tm.tm_sec, (unsigned) now.tv_nsec/TIMSPECDEVIDER,
956
(unsigned) gettid(), fac, severity[sev]);
958
va_start (arglist, fmt);
959
olen += vsnprintf(out + olen, sizeof(out) - olen, fmt, arglist);
962
olen = $MIN(olen, sizeof(out) - 1);
964
/* Add <LF> at end of record*/
967
/* Write to file and flush buffer depending on severity level */
968
write (logoutput, out, olen );
970
/* ARL - for android logcat */
972
__android_log_print(ANDROID_LOG_VERBOSE, fac, "%.*s", olen, out);
979
va_start (arglist, fmt);
980
olen = vsnprintf(out, sizeof(out), fmt, arglist);
983
syslog( LOG_PID | ((sev & 1) ? LOG_INFO : LOG_ERR), "%.*s", olen, out);
991
* @brief __util$log2buf - format a message into the given output buffer
999
unsigned __util$log2buf
1012
const char lfmt [] = "%02u-%02u-%04u %02u:%02u:%02u.%03u " PID_FMT " %%%s%3s";
1013
char *__outbuf = (char *) out;
1014
unsigned _sev = sev;
1016
struct timespec now;
1019
** Some sanity check
1021
if ( !($ISINRANGE(sev, STS$K_WARN, STS$K_ERROR)) )
1025
** Out to buffer "DD-MM-YYYY HH:MM:SS.msec [<function>\<line>]<FAC>-E:" prefix
1030
localtime_s(&_tm, (time_t *)&now);
1032
localtime_r((time_t *)&now, &_tm);
1035
*outlen = sprintf (__outbuf, lfmt,
1036
_tm.tm_mday, _tm.tm_mon + 1, 1900+_tm.tm_year,
1037
_tm.tm_hour, _tm.tm_min, _tm.tm_sec, (unsigned) now.tv_nsec/TIMSPECDEVIDER,
1038
(unsigned) gettid(), fac, severity[sev]);
1040
va_start (arglist, fmt);
1041
*outlen += vsnprintf(__outbuf + *outlen, outsz - *outlen, fmt, arglist);
1044
*outlen = $MIN(*outlen, outsz);
1046
/* Add NIL at end of record*/
1047
__outbuf[*outlen] = '\0';
1054
unsigned __util$logd
1067
const char lfmt [] = {"%02u-%02u-%04u %02u:%02u:%02u.%03u " PID_FMT " [%s\\%u] %%%s%3s"},
1068
mfmt [] = {"%02u-%02u-%04u %02u:%02u:%02u.%03u " PID_FMT " [%s\\%s\\%u] %%%s%3s"};
1070
unsigned olen, _sev = sev, opcom = sev & STS$K_SYSLOG;
1071
struct tm _tm = {0};
1072
struct timespec now = {0};
1074
sev &= ~STS$K_SYSLOG;
1077
** Some sanity check
1079
if ( !($ISINRANGE(sev, STS$K_WARN, STS$K_ERROR)) )
1083
** Out to buffer "DD-MM-YYYY HH:MM:SS.msec [<function>\<line>]-E-:" prefix
1088
localtime_s(&_tm, (time_t *)&now);
1090
localtime_r((time_t *)&now, &_tm);
1094
? sprintf (out, mfmt, _tm.tm_mday, _tm.tm_mon + 1, 1900 + _tm.tm_year,
1095
_tm.tm_hour, _tm.tm_min, _tm.tm_sec, (unsigned) now.tv_nsec/TIMSPECDEVIDER,
1096
(unsigned) gettid(), __mod, __fi, __li, fac, severity[sev])
1097
: sprintf (out, lfmt, _tm.tm_mday, _tm.tm_mon + 1, 1900 + _tm.tm_year,
1098
_tm.tm_hour, _tm.tm_min, _tm.tm_sec, (unsigned) now.tv_nsec/TIMSPECDEVIDER,
1099
(unsigned) gettid(), __fi, __li, fac, severity[sev]);
1101
va_start (arglist, __li);
1102
olen += vsnprintf(out + olen, sizeof(out) - olen, fmt, arglist);
1105
olen = $MIN(olen, sizeof(out) - 1);
1107
/* Add <LF> at end of record*/
1110
/* Write to file and flush buffer depending on severity level */
1111
write (logoutput, out, olen );
1113
/* ARL - for android logcat */
1115
__android_log_print(ANDROID_LOG_VERBOSE, fac, "%.*s", olen, out);
1121
va_start (arglist, __li);
1122
olen = vsnprintf(out, sizeof(out), fmt, arglist);
1125
__util$syslog (LOG_USER, LOG_DEBUG, fac, out, olen);
1127
// syslog( LOG_PID | ((sev & 1) ? LOG_INFO : LOG_ERR), "%.*s", olen, out);
1129
#endif /* __SYSLOG__ */
1135
* Description: Open a file to be used as default output file for $TRACE/$LOG/$DUMPHEX routines.
1136
* File will be open in shared for read and append mode!
1139
* logfile: a log file name string, ASCIZ
1140
* sloghost: a SYSLOG Host IP address, ASCIZ
1142
* Implicit output: global logoutput variable
1145
* condition status, see STS$ constants
1148
const char * logfile,
1149
const char * sloghost
1153
int mode = _S_IREAD | _S_IWRITE;
1155
const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
1160
/* Is there SYSLOG Host IP ? */
1163
inet_pton(AF_INET, sloghost, &slogsock.sin_addr);
1164
slogsock.sin_port = htons(514);
1165
slogsock.sin_family = AF_INET;
1169
return STS$K_SUCCESS;
1172
return STS$K_SUCCESS;
1174
if ( 0 > (fd = open(logfile, O_RDWR | O_CREAT | O_APPEND, mode)) )
1175
return $LOG(STS$K_ERROR, "Error opening log file '%s', errno = %d.", logfile, errno);
1177
lseek(fd, 0L, SEEK_END);
1181
return $LOG(STS$K_SUCCESS, "Log file '%s' has been opened.", logfile);
1187
* Description: compare a current file size with the 'limit' and rewind a current file pointer at begining of file.
1190
* condition status, see STS$ constants
1192
int __util$rewindlogfile (
1198
if ( (logoutput == STDOUT_FILENO) || !limit )
1199
return STS$K_SUCCESS;
1201
if ( 0 > (status = lseek (logoutput, 0, SEEK_CUR)) )
1202
return $LOG(STS$K_ERROR, "lseek() -> %d", errno);
1204
if ( status < limit )
1205
return STS$K_SUCCESS;
1207
if ( 0 > (status = lseek(logoutput, 0L, SEEK_SET)) )
1208
$LOG(STS$K_ERROR, "fseek() -> %d", errno);
1211
if ( 0 > (ftruncate(logoutput, status )) )
1212
$LOG(STS$K_ERROR, "ftruncate(%d, %d) -> %d", logoutput, status, errno);
1216
return STS$K_SUCCESS;
1222
http://util.deltatelecom.ru/ovms82src/debug/lis/strings.lis
1224
Source Listing 19-NOV-2004 08:39:18 Compaq C V6.5-001-48BCD Page 42
1225
4-MAR-2003 15:31:10 $1$DGA1016:[DEBUG_2.SRC]STRINGS.C;1
1228
/*++***********************************************************************/
1230
* FUNCTION : C_STR$pattern_match
1233
* This function is passed a pattern and a string to match against the
1234
* pattern. The pattern may contain wildcards (*,%), where '*' matches
1235
* 0 or more occurrences of anything, and '%' matches any one character.
1236
* In addition, a '\' in the pattern string will translate the next
1237
* character as literal. This is a recursive routine.
1241
* PROTOTYPE/PARAMETERS :
1245
* int : success or failure
1250
* establish a pointer to the first character in the magic string
1251
* and a pointer to the first character in the text string.
1253
* while there are still characters:
1254
* If the current character in the magic string is not a wild card
1255
* and they are different, then declare it a mismatch. If they
1256
* point to identical characters, then advance each pointer by one
1257
* and go aroung the loop again.
1259
* If the magic string pointer points at a WILD_PERCENT, then advance
1260
* both pointers, regardless of what's in the test string.
1262
* If the magic pointer points to WILD_STAR, then try matching the
1263
* rest of the magic string at each character position in the text
1264
* string by calling C_STR$pattern_match (i.e. this function)
1265
* recursively. If any of those succeed then declare this one a success.
1268
* (1) pattern$ is assumed to be preprocessed, i.e, * replaced by WILD_STAR,
1269
* '%' replaced by WILD_PERCENT, '\<character>' by '<character>', etc.
1271
* (2) str$, however, is LITERAL, ie, it does not have wildcards or
1272
* '\<character>', etc. *, %, and \ are given no special treatment.
1278
* 12-JUL-89 A. Seigel
1279
* (1) Created this function.
1281
* 11-SEP-89 A. Seigel
1282
* (1) Fixed bug with literals (\) in pattern$.
1285
Source Listing 19-NOV-2004 08:39:18 Compaq C V6.5-001-48BCD Page 43
1286
4-MAR-2003 15:31:10 $1$DGA1016:[DEBUG_2.SRC]STRINGS.C;1
1290
* 24-MAY-1990 J. Bell
1291
* (1) ANSI-ized declaration.
1294
* 27-NOV-2015 RRL Some reformating.
1296
/*--***********************************************************************/
1298
#define WILD_PERCENT '%'
1299
#define WILD_STAR '*'
1310
int __util$pattern_match (
1311
char * str$, /* A LITERAL string to match */
1312
char * pattern$ /* Pattern, with potential wildcards (*,%) to * match the string.*/
1315
int done = FALSE, matched_to_eos = FALSE;
1317
while( (*pattern$ != '\0') && (!done) && ( ((*str$=='\0') && ( (*pattern$==WILD_STAR)) ) || (*str$!='\0')) )
1323
matched_to_eos = FALSE;
1324
while ( (*str$ != '\0') && (! ( matched_to_eos = __util$pattern_match( str$++, pattern$))));
1326
if ( matched_to_eos )
1328
while (*str$ != '\0') str$++;
1329
while (*pattern$ != '\0') pattern$++;
1342
if (*str$ == *pattern$)
1351
while (*pattern$ == WILD_STAR) pattern$++;
1353
return ( (*str$ == '\0') && (*pattern$ == '\0') );
1357
/******************* end of C_STR$pattern_match *******************/
1361
void __util$traceback (void)
1367
nptrs = backtrace(buffer, sizeof(buffer));
1369
$LOG(STS$K_INFO, " --------------------- TRACEBACK BEGIN (%d) ------", nptrs);
1371
if ( !(strings = backtrace_symbols(buffer, nptrs)) )
1373
perror("backtrace_symbols");
1378
for (i = 0; i < nptrs; i++)
1379
$LOG(STS$K_INFO, "%d\t%s", i, strings[i]);
1381
$LOG(STS$K_INFO, " --------------------- TRACEBACK END ------");
1390
#pragma GCC diagnostic pop
1397
#ifdef __CRC32_TAB__
1399
extern unsigned int crc32c_tab[];
1403
#define __CRC32_TAB__ 1
1406
static const unsigned int __crc32c_tab__[] = {
1407
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
1408
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
1409
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
1410
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
1411
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
1412
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
1413
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
1414
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
1415
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
1416
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
1417
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
1418
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
1419
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
1420
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
1421
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
1422
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
1423
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
1424
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
1425
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
1426
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
1427
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
1428
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
1429
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
1430
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
1431
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
1432
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
1433
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
1434
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
1435
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
1436
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
1437
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
1438
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
1439
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
1440
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
1441
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
1442
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
1443
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
1444
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
1445
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
1446
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
1447
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
1448
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
1449
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
1451
#endif /* __CRC32_TAB__ */
1453
unsigned int __util$crc32c (unsigned int crc, const void *buf, size_t buflen)
1455
const unsigned char *p = (unsigned char *) buf;
1460
crc = __crc32c_tab__[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
1473
** The 'strstr' function locates the first occurrence in the string pointed
1474
** to by 's1' of the sequence of characters in the string pointed to by 's2'.
1478
** non-NULL the address of the located string
1479
** NULL indicates that the string was not found
1481
char * __util$strstr
1489
char *p1 = s1, *p2 = s2 + 1;
1490
size_t p1len = s1len, cmplen = s2len - 1;
1495
if ( !s1 || !s2 || !s1len || !s2len )
1498
if ( s1len < s2len )
1502
* Special check for single-byte substring
1505
return memchr(s1, *s2, s1len);
1508
** Find the first character of s2 in the remaining string. If it is
1509
** found, compare the rest of s2.
1511
while ( p1len && (p1 = memchr(p1, *s2, p1len)) )
1514
* Is the rest of the p1 is more then length of the s2 ?
1515
* No ?! Stop comparing , return the NULL pointer.
1517
if ( (s1len - (p1 - s1)) < cmplen )
1520
if ( !memcmp(p1 + 1, p2, cmplen) )
1524
p1len = s1len - (p1 - s1);
1529
** No match. Return the NULL pointer.
1531
return((char *) NULL);
1549
* The core formatting routine.
1550
* Do NOT use sprintf-style formatting codes in
1551
* message strings! Use the formatting directives
1556
* !U{L, W, B} = unsigned int, short, byte
1557
* !S{L, W, B} = signed int, short, byte
1558
* !X{L, W, B} = hexadecimal int, short, byte
1560
* !! = exclamation point
1563
#define snprintf(buf, len, format,...) _snprintf_s(buf, len, len, format, __VA_ARGS__)
1566
static int __util$vfao (char *fmt, char *buf, size_t bufsz, va_list ap)
1569
char tmpbuf[32], *outp = buf;
1571
for ( ;bufsz && *fmt; )
1594
/* !X{L, W, B}, U{L, W, B}, S{L, W, B}
1596
if (*fmt == 'U' || *fmt == 'X' || *fmt == 'S' )
1598
unsigned long val = 0;
1600
if (*(fmt+1) == 'B')
1602
val = va_arg(ap, unsigned char);
1603
len = snprintf(tmpbuf, sizeof(tmpbuf), ((*fmt == 'X') ? "0x%02X" : (*fmt == 'U') ? "%3u" : "%3d"),
1604
(unsigned char) val);
1606
else if (*(fmt + 1) == 'W')
1608
val = va_arg(ap, unsigned short);
1609
len = snprintf(tmpbuf, sizeof(tmpbuf), ((*fmt == 'X') ? "0x%04X" : ( *fmt == 'U') ? "%5u" : "%6d"),
1610
(unsigned short) val);
1612
else if (*(fmt + 1) == 'L')
1614
val = va_arg(ap, unsigned long);
1615
len = snprintf(tmpbuf, sizeof(tmpbuf), ((*fmt == 'X') ? "0x%08X": ( *fmt == 'U') ? "%11u" : "%11d"),
1616
(unsigned long) val);
1627
memcpy(outp, tmpbuf, len);
1643
if ( 0 > (len = snprintf(tmpbuf, sizeof(tmpbuf), "@%p", va_arg(ap, void *))) )
1649
memcpy(outp, tmpbuf, len);
1658
/* !AD, !AC, !AZ ... */
1661
unsigned int slen = 0;
1664
if (*(fmt+1) == 'D')
1666
slen = va_arg(ap, unsigned int);
1667
ptr = va_arg(ap, char *);
1670
else if (*(fmt+1) == 'Z')
1672
ptr = va_arg(ap, char *);
1673
slen = (unsigned int) strnlen(ptr, bufsz);
1675
else if (*(fmt+1) == 'C')
1677
ptr = va_arg(ap, char *);
1682
if (slen >= (unsigned int) bufsz)
1683
slen = (unsigned int)bufsz - 1;
1685
memcpy(outp, ptr, slen);
1694
// Unrecognized directive here, just loop back up to the top
1695
} /* while bufsz > 0 && *fmt != null char */
1698
return (outp - buf);
1703
int __util$fao (void *fmt, void *buf, size_t bufsz, ...)
1708
va_start(ap, bufsz);
1709
result = __util$vfao((char *) fmt, (char*) buf, bufsz, ap);
1717
struct _stm_buf /* One item of Stream buffer */
1719
ENTRY links; /* Left, right links, used by queue macros */
1720
int len; /* Actual length of data in the buffer */
1721
int ref; /* Count of reference */
1722
char buf[32]; /* Buffer itself */
1723
} _stm_buf_area[32]; /* We declare a static buffers area */
1725
QUEUE free_bufs = QUEUE_INITIALIZER,
1726
busy_bufs = QUEUE_INITIALIZER;
1729
int main (int argc, char *argv[])
1735
bcnt = __util$fao("!UL, !UW, !UB", buf, sizeof(buf), 1, 2, 3);
1737
for (bcnt = 0; bcnt < 32; bcnt++)
1738
$INSQTAIL(&free_bufs, &_stm_buf_area[bcnt], &count);
1750
#define $DEFMSGLIST \
1751
$DEFMSG(util, 0, S, NORMAL, "normal successful completion") \
1752
$DEFMSG(util, 1, W, WARNING, "unknown warning") \
1753
$DEFMSG(util, 2, E, ERROR, "unknown error") \
1754
$DEFMSG(util, 3, F, FATALERR, "unknown fatal error") \
1755
$DEFMSG(util, 13, E, NUMCNVERR, "numeric conversion error: !SL") \
1756
#DEFMSG(util,122, E, LIBRDERR, "error reading library file !SZ")
1758
#define $DEFMSG(fac, num, sev, nam, txt) #nam,
1759
static const char *__$msgmnemonics[] = {
1764
#define $DEFMSG(fac, num, sev,nam, txt) txt,
1765
static const char *__$msgtexts[] = {
1770
#define $DEFMSG(fac, num, sev, nam, txt) #define fac##txt num
1771
static const char *__$msgtexts[] = {
1775
#define $DEFMSG(fac, num, sev, nam, txt) fac##__##nam = STC_CODE_##typ(msg),
1783
//#define $MSGCOUNT (sizeof(__$##fac##msgmnemonics)/sizeof(__$##fac##msgmnemonics))
1795
#define IOBUFSZ 4096 /* A size of single buffer */
1796
#define IOBUFCNT 4096 /* A total number of buffers */
1798
struct _stm_buf /* One item of Stream buffer */
1800
ENTRY links; /* Left, right links, used by queue macros */
1801
int len; /* Actual length of data in the buffer */
1802
int ref; /* Count of reference */
1803
char buf[IOBUFSZ]; /* Buffer itself */
1804
} _stm_buf_area[IOBUFCNT]; /* We declare a static buffers area */
1806
QUEUE free_bufs = QUEUE_INITIALIZER,
1807
busy_bufs = QUEUE_INITIALIZER;
1810
DWORD WINAPI worker_f2b (void *arg)
1812
int status, count, i;
1813
struct _stm_buf * sbuf;
1815
$LOG(STS$K_INFO, "tid : %d running ...", GetCurrentThreadId());
1817
for (i = 0; i < 10000 * 500; i++)
1820
$LOG(STS$K_INFO, "tid:%d, iteration %d", GetCurrentThreadId(), i);
1822
if ( !(1 & (status = $REMQHEAD(&free_bufs, &sbuf, &count))) )
1824
$LOG(STS$K_ERROR, "$REMQHEAD() -> %d, count = %d", status, count);
1829
$LOG(STS$K_ERROR, "sbuf == NULL");
1832
if ( !(1 & (status = status = $INSQTAIL(&busy_bufs, sbuf, &count))) )
1833
$LOG(STS$K_ERROR, "$INSQTAIL() -> %d", status);
1839
DWORD WINAPI worker_b2f (void *arg)
1841
int status, count, i;
1842
struct _stm_buf * sbuf;
1844
$LOG(STS$K_INFO, "tid : %d running ...", GetCurrentThreadId());
1846
for (i = 0; i < 10000 * 500; i++)
1849
$LOG(STS$K_INFO, "tid:%d, iteration %d", GetCurrentThreadId(), i);
1851
if ( !(1 & (status = $REMQHEAD(&busy_bufs, &sbuf, &count))) )
1853
$LOG(STS$K_ERROR, "$REMQHEAD() -> %d, count = %d", status, count);
1859
$LOG(STS$K_ERROR, "sbuf == NULL");
1862
if ( !(1 & (status = status = $INSQTAIL(&free_bufs, sbuf, &count))) )
1863
$LOG(STS$K_ERROR, "$INSQTAIL() -> %d", status);
1871
int main (int argc, char *argv[])
1878
i = __util$fao("!UL, !UW, !UB", buf, sizeof(buf), 1, 2, 3);
1884
i = __util$pattern_match("ch33---0010904935.torrent", "*.torrent");
1886
i = __util$pattern_match("Hello World!!!", "*llo*");
1891
__util$getparams(argc, argv, opts);
1892
// __util$setlogfile("logfile2.log");
1895
//InitializeSRWLock(&free_bufs.lock);
1898
for (i = 0; i < IOBUFCNT; i++)
1899
$INSQTAIL(&free_bufs, &_stm_buf_area[i], &count);
1903
for (i = 0; i < 32; i++)
1905
if ( (scan_tid = CreateThread(NULL, 0, worker_f2b, NULL, 0, NULL)) == NULL )
1906
return $LOG(STS$K_ERROR, "Creation streaming thread was failed : %d", GetLastError());
1910
for (i = 0; i < 32; i++)
1912
if ( (scan_tid = CreateThread(NULL, 0, worker_b2f, NULL, 0, NULL)) == NULL )
1913
return $LOG(STS$K_ERROR, "Creation streaming thread was failed : %d", GetLastError());
1916
WaitForSingleObject(scan_tid, INFINITE);
1918
return STS$K_SUCCESS;