Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief NDR 'standard' common utilities
0003  *   Enduro/eXecution system platform library
0004  *
0005  * @file nstdutil.c
0006  */
0007 /* -----------------------------------------------------------------------------
0008  * Enduro/X Middleware Platform for Distributed Transaction Processing
0009  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0010  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0011  * This software is released under one of the following licenses:
0012  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0013  * See LICENSE file for full text.
0014  * -----------------------------------------------------------------------------
0015  * AGPL license:
0016  *
0017  * This program is free software; you can redistribute it and/or modify it under
0018  * the terms of the GNU Affero General Public License, version 3 as published
0019  * by the Free Software Foundation;
0020  *
0021  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0022  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0023  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0024  * for more details.
0025  *
0026  * You should have received a copy of the GNU Affero General Public License along 
0027  * with this program; if not, write to the Free Software Foundation, Inc.,
0028  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0029  *
0030  * -----------------------------------------------------------------------------
0031  * A commercial use license is available from Mavimax, Ltd
0032  * contact@mavimax.com
0033  * -----------------------------------------------------------------------------
0034  */
0035 
0036 /*---------------------------Includes-----------------------------------*/
0037 #ifndef _GNU_SOURCE
0038 #define _GNU_SOURCE
0039 #endif
0040 #include <ndrstandard.h>
0041 #include <time.h>
0042 #include <sys/time.h>
0043 #include <stdlib.h>
0044 #include <string.h>
0045 #include <stdio.h>
0046 #include <sys/stat.h>
0047 #include <ctype.h>
0048 #include <pthread.h>
0049 #include <time.h>
0050 #include <fcntl.h>
0051 #include <sys_unix.h>
0052 #include <nstd_tls.h>
0053 #include <termios.h>
0054 #include <nstdutil.h>
0055 #include <ndebug.h>
0056 #include <userlog.h>
0057 #include <atmi_int.h>
0058 #include <errno.h>
0059 #include <excrypto.h>
0060 /*---------------------------Externs------------------------------------*/
0061 /*---------------------------Macros-------------------------------------*/
0062 #define _MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
0063 #define NDRX_TEMP_ATTEMPTS  1000 /**< Number of attempts for looking for tmp file */
0064 #define API_ENTRY {_Nunset_error();}
0065 /*---------------------------Enums--------------------------------------*/
0066 /*---------------------------Typedefs-----------------------------------*/
0067 /*---------------------------Globals------------------------------------*/
0068 /*---------------------------Statics------------------------------------*/
0069 /*---------------------------Prototypes---------------------------------*/
0070 
0071 /**
0072  * Compare 4 longs
0073  */
0074 expublic int ndrx_compare4(long a1, long a2, long a3, long a4, long b1, long b2, long b3, long b4)
0075 {
0076     
0077     long res1 =  a1 - b1;
0078     long res2 =  a2 - b2;
0079     long res3 =  a3 - b3;
0080     long res4 =  a4 - b4;
0081     
0082     if (res1!=0)
0083         return (int)res1;
0084     
0085     if (res2!=0)
0086         return (int)res2;
0087 
0088     if (res3!=0)
0089         return (int)res3;
0090     
0091     return (int)res4;
0092 }
0093 
0094 /**
0095  * Compre 3 segmeneted number
0096  * @param a1
0097  * @param a2
0098  * @param a3
0099  * @param b1
0100  * @param b2
0101  * @param b3
0102  * @return 
0103  */
0104 expublic int ndrx_compare3(long a1, long a2, long a3, long b1, long b2, long b3)
0105 {
0106     
0107     long res1 =  a1 - b1;
0108     long res2 =  a2 - b2;
0109     long res3 =  a3 - b3;
0110     
0111     
0112     if (res1!=0)
0113         return (int)res1;
0114     
0115     if (res2!=0)
0116         return (int)res2;
0117     
0118     return (int)res3;
0119     
0120 }
0121 
0122 /**
0123  * Return -1 in case if t1/tusec1 is less than t2/tusec2
0124  * return 0 in case if t1/tusec1 equals t2/tusec2
0125  * return 1 in case if t1/tusec1 greater t2/tusec2
0126  * @param t1 tstamp1
0127  * @param tusec1 tstamp1 (microsec)
0128  * @param t2 tstamp2
0129  * @param tusec2 tstamp2 (microsec)
0130  * @return see descr
0131  */
0132 expublic int ndrx_utc_cmp(long *t1, long *tusec1, long *t2, long *tusec2)
0133 {
0134     if ((*t1 < *t2) || (*t1 == *t2 && *tusec1 < *tusec2))
0135     {
0136         return -1;
0137     }
0138     else if (*t1 == *t2 && *tusec1 == *tusec2)
0139     {
0140         return 0;
0141     }
0142     else
0143     {
0144         return 1;
0145     }
0146 }
0147 
0148 /**
0149  * Return timestamp split in two fields
0150  * @param t
0151  * @param tusec
0152  */
0153 expublic void ndrx_utc_tstamp2(long *t, long *tusec)
0154 {
0155     struct timeval tv;
0156     
0157     gettimeofday(&tv, NULL);
0158     
0159     *t = tv.tv_sec;
0160     *tusec = tv.tv_usec;
0161 }
0162 
0163 /**
0164  * Return YYYY-MM-DD HH:MI:SS timestamp from two field epoch
0165  * @param ts
0166  * @return 
0167  */
0168 expublic char * ndrx_get_strtstamp2(int slot, long t, long tusec)
0169 {
0170     time_t tfmt;
0171     struct tm utc;
0172     NSTD_TLS_ENTRY;
0173     
0174     tfmt = t;
0175     gmtime_r(&tfmt, &utc);
0176     strftime(G_nstd_tls->util_buf1[slot], 
0177             sizeof(G_nstd_tls->util_buf1[slot]), "%Y-%m-%d %H:%M:%S", &utc);
0178     
0179     return G_nstd_tls->util_buf1[slot];
0180 }
0181 
0182 
0183 /**
0184  * Return timstamp UTC, milliseconds since epoch date.
0185  * This assumes that platform uses 64bit long long.
0186  * Or we can drop the milliseconds if the platform does not handle that.
0187  */
0188 expublic unsigned long long ndrx_utc_tstamp(void)
0189 {
0190     struct timeval tv;
0191     unsigned long long ret;
0192 
0193     gettimeofday(&tv, NULL);
0194 
0195     /* so basically we need 6 byte storage or more */
0196     if (sizeof(unsigned long long)>=8) 
0197     {
0198         ret =
0199             (unsigned long long)(tv.tv_sec) * 1000 +
0200             (unsigned long long)(tv.tv_usec) / 1000;
0201     }
0202     else
0203     {
0204         ret = (unsigned long long)(tv.tv_sec);
0205     }
0206     
0207     return ret;
0208 }
0209 
0210 /**
0211  * Return timestamp in microseconds
0212  * @return 
0213  */
0214 expublic unsigned long long ndrx_utc_tstamp_micro(void)
0215 {
0216     struct timeval tv;
0217     unsigned long long ret;
0218 
0219     gettimeofday(&tv, NULL);
0220     
0221     if (sizeof(unsigned long long)>=8) 
0222     {
0223         ret =
0224             (unsigned long long)(tv.tv_sec) * 1000000 +
0225             (unsigned long long)(tv.tv_usec);
0226     }
0227     else
0228     {
0229         ret = (unsigned long long)(tv.tv_sec);
0230     }
0231     
0232     return ret;
0233 }
0234 
0235 /**
0236  * Return YYYY-MM-DD HH:MI:SS timestamp from micro seconds based timestamp.
0237  * @param ts
0238  * @return 
0239  */
0240 expublic char * ndrx_get_strtstamp_from_sec(int slot, long ts)
0241 {
0242     time_t t;
0243     struct tm utc;
0244     
0245     NSTD_TLS_ENTRY;
0246     
0247     t = ts;
0248     gmtime_r(&t, &utc);
0249     strftime(G_nstd_tls->util_buf2[slot], 
0250             sizeof(G_nstd_tls->util_buf2[slot]), "%Y-%m-%d %H:%M:%S", &utc);
0251     
0252     return G_nstd_tls->util_buf2[slot];
0253 }
0254 
0255 /**
0256  * Get tick count in one second for current platform
0257  * @return 
0258  */
0259 expublic unsigned long long ndrx_get_micro_resolution_for_sec(void)
0260 {
0261     unsigned long long ret;    
0262     
0263     if (sizeof(unsigned long long)>=8) 
0264     {
0265         ret = 1000000;
0266     }
0267     else
0268     {
0269         ret = 1;
0270     }
0271     
0272     return ret;
0273 }
0274 
0275 /**
0276  * Return date/time local 
0277  * @param p_date - ptr to store long date, format YYYYMMDD
0278  * @param p_time - ptr to store long time, format HHMISS
0279  * @param p_usec - ptr to store microseconds
0280  */
0281 expublic void ndrx_get_dt_local(long *p_date, long *p_time, long *p_usec)
0282 {
0283     struct tm       stm;
0284     struct timeval  timeval;
0285     struct timezone timezone_val;
0286 
0287     gettimeofday (&timeval, &timezone_val);
0288     
0289     localtime_r(&timeval.tv_sec, &stm);
0290     
0291     *p_time = 10000L*stm.tm_hour+100*stm.tm_min+1*stm.tm_sec;
0292     *p_date = 10000L*(1900 + stm.tm_year)+100*(1+stm.tm_mon)+1*(stm.tm_mday);
0293     *p_usec = timeval.tv_usec;
0294 
0295     return;
0296 }
0297 
0298 /**
0299  * Calculate delta milliseconds for two time specs.
0300  * @param stop period stop
0301  * @param start period start
0302  * @return different in milliseconds between stop and start.
0303  */
0304 expublic long ndrx_timespec_get_delta(struct timespec *stop, struct timespec *start)
0305 {
0306     long ret;
0307     
0308     /* calculate delta */
0309     ret = (stop->tv_sec - start->tv_sec)*1000 /* Convert to milliseconds */ +
0310                (stop->tv_nsec - start->tv_nsec)/1000000; /* Convert to milliseconds */
0311 
0312     return ret;
0313 }
0314 
0315 /**
0316  * Provide ceil division x by y for positive numbers
0317  * @param x number to divide
0318  * @param y divider
0319  * @return ceiling of division
0320  */
0321 expublic long ndrx_ceil(long x, long y)
0322 {
0323     return (x + y - 1) / y;
0324 }
0325 
0326 /**
0327  * Replace string with other string, return malloced new copy
0328  * @param orig original string
0329  * @param rep string to replace
0330  * @param with replace with
0331  * @return NULL (if orgin is NULL) or newly allocated string
0332  */
0333 expublic char *ndrx_str_replace(char *orig, char *rep, char *with) {
0334     char *result; /* the return string */
0335     char *ins;    /* the next insert point */
0336     char *tmp;    /* varies */
0337     int len_rep;  /* length of rep */
0338     int len_with; /* length of with */
0339     int len_front; /* distance between rep and end of last rep */
0340     int count;    /* number of replacements */
0341 
0342     if (!orig)
0343         return NULL;
0344     if (!rep)
0345         rep = "";
0346     len_rep = strlen(rep);
0347     if (!with)
0348         with = "";
0349     len_with = strlen(with);
0350 
0351     ins = orig;
0352     for (count = 0; (tmp = strstr(ins, rep)); ++count)
0353     {
0354         ins = tmp + len_rep;
0355     }
0356 
0357     /* first time through the loop, all the variable are set correctly 
0358      * from here on,
0359      *    tmp points to the end of the result string
0360      *    ins points to the next occurrence of rep in orig
0361      *    orig points to the remainder of orig after "end of rep"
0362      */
0363     tmp = result = NDRX_FPMALLOC(strlen(orig) + (len_with - len_rep) * count + 1, 0);
0364 
0365     if (!result)
0366         return NULL;
0367 
0368     while (count--)
0369     {
0370         ins = strstr(orig, rep);
0371         len_front = ins - orig;
0372         NDRX_STRNCPY(tmp, orig, len_front);
0373         tmp =  tmp + len_front;
0374         tmp = strcpy(tmp, with) + len_with;
0375         orig += len_front + len_rep; /* move to next "end of rep" */
0376     }
0377     strcpy(tmp, orig);
0378     return result;
0379 }
0380 
0381 /**
0382  * Substitute environment 
0383  * TODO: Implement $[<func>:data] substitution. Currently available functions:
0384  * $[dec:<encrypted base64 string>] or just will copy to new function
0385  * Bug #452
0386  * @param str
0387  * @param buf_len buffer len for overrun checks
0388  * @return 
0389  */
0390 expublic char * ndrx_str_env_subs_len(char * str, int buf_size)
0391 {
0392     char *p, *p2, *p3;
0393     char *next = str;
0394     char envnm[1024];
0395     char *env;
0396     char *out;
0397     char *empty="";
0398     char *malloced;
0399     char *pval;
0400     char *tempbuf = NULL;
0401     char *close;
0402     
0403 #define FUNCTION_SEPERATOR  '='
0404     
0405     while (NULL!=(p=strstr(next, "${")))
0406     {
0407         p2=strstr(next, "\\${");
0408         p3=strstr(next, "\\\\${");
0409         
0410         /* this is escaped stuff, we shall ignore that */
0411         if (p == p3+2)
0412         {
0413             /* This is normally escaped \, thus ignore & continue 
0414              * Does not affects our value
0415              */
0416         }
0417         else if (p == (p2+1))
0418         {
0419             /* This is our placeholder escaped, thus skip 
0420              * But we need to kill the escape
0421              */
0422             memmove(p2, p, strlen(p)+1);
0423             next=p+3; 
0424             continue;
0425         }
0426         
0427         /* Bug #317 */
0428         close =strchr(p, '}');
0429         if (NULL!=close)
0430         {
0431             long bufsz;
0432             int cpylen = close-p-2;
0433             int envlen;
0434             /* do substitution */
0435             NDRX_STRNCPY(envnm, p+2, cpylen);
0436             envnm[cpylen] = EXEOS;
0437             
0438             if (NULL==(pval=strchr(envnm, FUNCTION_SEPERATOR)))
0439             {
0440                 env = getenv(envnm);
0441                 
0442                 if (NULL!=env)
0443                     out = env;
0444                 else
0445                     out = empty;
0446             }
0447             else
0448             {
0449                 *pval=EXEOS;
0450                 pval++;
0451                 
0452                 if (0==(bufsz=strlen(pval)))
0453                 {
0454                     userlog("Invalid encrypted data (zero len, maybe invalid sep? not =?) "
0455                             "for: [%s] - fill empty", envnm);
0456                     out = empty;
0457                 }
0458                 else
0459                 {
0460                     int err;
0461                     tempbuf = NDRX_MALLOC(bufsz);
0462                     
0463                     if (NULL==tempbuf)
0464                     {
0465                         err = errno;
0466                         userlog("Failed to allocate %ld bytes for decryption buffer: %s", 
0467                                 bufsz, strerror(errno));
0468                         NDRX_LOG_EARLY(log_error, "Failed to allocate %ld bytes "
0469                                 "for decryption buffer: %s", 
0470                                 bufsz, strerror(errno));
0471                         goto out;
0472                     }
0473                     
0474                     /* So function is:  
0475                      * - 'envnm'
0476                      * and the value is 'p'
0477                      * So syntax:
0478                      * ${dec=<encrypted string>}
0479                      */    
0480                     if (0==strcmp(envnm, "dec"))
0481                     {
0482                         /* About to decrypt the value... of p 
0483                          * space of the data will be shorter or the same size or smaller
0484                          * encrypted block.
0485                          */
0486                         if (EXSUCCEED!=ndrx_crypto_dec_string(pval, tempbuf, &bufsz))
0487                         {
0488                             userlog("Failed to decrypt [%s] string: %s",
0489                                     pval, Nstrerror(Nerror));
0490                             NDRX_LOG_EARLY(log_error, "Failed to decrypt [%s] string: %s",
0491                                     pval, Nstrerror(Nerror));
0492                             out = empty;
0493                         }
0494                         out = tempbuf;
0495                     }
0496                     else
0497                     {
0498                         userlog("Unsupported substitution function: [%s] - skipping", 
0499                                 pval);
0500                         NDRX_LOG_EARLY(log_error, "Failed to decrypt [%s] string: %s",
0501                                 pval, Nstrerror(Nerror));
0502                         out = empty;
0503                     }
0504                     
0505                 } /* if data > 0 */
0506             } /* if is function instead of env variable */
0507 
0508             envlen = strlen(out);
0509             
0510             /* fix up the buffer!!! */
0511             if (cpylen+3==envlen)
0512             {
0513                 memcpy(p, out, envlen);
0514             }
0515             else if (cpylen+3 < envlen)
0516             {
0517                 int missing;
0518                 
0519                 /* if buf_len == 0, skip the checks. */           
0520                 if (buf_size > 0 && 
0521                         strlen(str) - (cpylen+3) + envlen > buf_size-1 /*incl EOS*/)
0522                 {
0523                     if (NULL!=tempbuf)
0524                     {
0525                         NDRX_FREE(tempbuf);
0526                     }
0527                     /* cannot continue it is buffer overrun! */
0528                     
0529                     return str;
0530                 }
0531                 
0532                 missing = envlen - (cpylen+2);
0533                 
0534                 /* we have to stretch that stuff and then copy in, including eos */
0535                 memmove(close+missing, close+1, strlen(close+1)+1);
0536                 memcpy(p, out, envlen);
0537             }
0538             else if (cpylen+3 > envlen)
0539             {
0540                 /*int overleft = cpylen+2 - envlen; */
0541                 /* copy there, and reduce total len */
0542                 memcpy(p, out, envlen);
0543                 /* copy left overs after } at the end of the env, including eos */
0544                 memmove(p+envlen, close+1, strlen(close+1)+1);
0545             }
0546             
0547             /* free-up if temp buffer allocated. */
0548             
0549             next = p+envlen;
0550         }
0551         else
0552         {
0553             /* just step forward... */
0554             next+=2;
0555         }
0556         
0557         if (NULL!=tempbuf)
0558         {
0559             /* fix #268 */
0560             NDRX_FREE(tempbuf);
0561             tempbuf=NULL;
0562         }
0563     }
0564     
0565 out:
0566 
0567     if (NULL!=tempbuf)
0568     {
0569         /* fix #268 */
0570         NDRX_FREE(tempbuf);
0571         tempbuf=NULL;
0572     }
0573 
0574     /* replace '\\' -> '\'  */
0575     if (strstr(str, "\\"))
0576     {
0577         malloced = ndrx_str_replace(str, "\\\\", "\\");
0578         strcpy(str, malloced);
0579         NDRX_FPFREE(malloced);
0580     }
0581     
0582     return str;
0583 }
0584 
0585 /* TODO: we need a callback for value getter. Also how we determine 
0586  * temp buffer size? Alloc temp space in the size of the buf_size? 
0587  * Also we need to have configurable open/close symbols.
0588  * We will have two data pointers
0589  * This works with NDRX logger.
0590  * Note that value cannot contain '}' for the functions and env variables
0591  */
0592 expublic int ndrx_str_subs_context(char * str, int buf_size, char opensymb, char closesymb,
0593         void *data1, void *data2, void *data3, void *data4,
0594         int (*pf_get_data) (void *data1, void *data2, void *data3, void *data4,
0595             char *symbol, char *outbuf, long outbufsz))
0596 {
0597     char *p, *p2, *p3;
0598     char *next = str;
0599     char symbol[1024];
0600     char *malloced;
0601     char *tempbuf = NULL;
0602     char open1[]={'$',opensymb,EXEOS};
0603     char open2[]={'\\', '$', opensymb, EXEOS};
0604     char open3[]={'\\', '\\', '$', opensymb, EXEOS};
0605     char *outbuf = NULL;
0606     int ret = EXSUCCEED;
0607     char *close;
0608     
0609     NDRX_MALLOC_OUT(outbuf, buf_size, char);
0610     
0611     while (NULL!=(p=strstr(next, open1)))
0612     {
0613         p2=strstr(next, open2);
0614         p3=strstr(next, open3);
0615         
0616         /* this is escaped stuff, we shall ignore that */
0617         if (p == p3+2)
0618         {
0619             /* This is normally escaped \, thus ignore & continue 
0620              * Does not affects our value
0621              */
0622         }
0623         else if (p == (p2+1))
0624         {
0625             /* This is our placeholder escaped, thus skip 
0626              * But we need to kill the escape
0627              */
0628             memmove(p2, p, strlen(p)+1);
0629             next=p+3; 
0630             continue;
0631         }
0632         
0633         /* Bug #317*/
0634         close =strchr(p, closesymb);
0635         if (NULL!=close)
0636         {
0637             long bufsz;
0638             int cpylen = close-p-2;
0639             int envlen;
0640             /* do substitution */
0641             NDRX_STRNCPY(symbol, p+2, cpylen);
0642             symbol[cpylen] = EXEOS;
0643             
0644             if (EXSUCCEED!=(ret=pf_get_data(data1, data2, data3, data4,
0645                     symbol, outbuf, buf_size)))
0646             {
0647                 NDRX_LOG(log_error, "Failed to substitute [%s] error: %d", symbol, ret);
0648                 goto out;
0649             }
0650             
0651             envlen = strlen(outbuf);
0652             
0653             /* fix up the buffer!!! */
0654             if (cpylen+3==envlen)
0655             {
0656                 memcpy(p, outbuf, envlen);
0657             }
0658             else if (cpylen+3 < envlen)
0659             {
0660                 int totlen;
0661                 int missing;
0662                 /* if buf_len == 0, skip the checks. */
0663                 if (buf_size > 0 && 
0664                         (totlen=(strlen(str) - (cpylen+3) + envlen)) > buf_size-1 /*incl EOS*/)
0665                 {
0666                     if (NULL!=tempbuf)
0667                     {
0668                         NDRX_FREE(tempbuf);
0669                     }
0670                     /* cannot continue it is buffer overrun! Maybe fail here? */
0671                     NDRX_LOG(log_error, "buffer overrun in string "
0672                             "formatting totlen=%d, bufsz-1=%d", totlen, buf_size-1);
0673                     EXFAIL_OUT(ret);
0674                 }
0675                 missing = envlen - (cpylen+2);
0676                 
0677                 /* we have to stretch that stuff and then copy in, including eos */
0678                 memmove(close+missing, close+1, strlen(close+1)+1);
0679                 memcpy(p, outbuf, envlen);
0680                 
0681             }
0682             else if (cpylen+3 > envlen)
0683             {
0684                 /*int overleft = cpylen+2 - envlen; */
0685                 /* copy there, and reduce total len */
0686                 memcpy(p, outbuf, envlen);
0687                 /* copy left overs after } at the end of the env, including eos */
0688                 memmove(p+envlen, close+1, strlen(close+1)+1);
0689                 
0690             }
0691             
0692             /* free-up if temp buffer allocated. */
0693             
0694             next = p+envlen;
0695         }
0696         else
0697         {
0698             /* just step forward... */
0699             next+=2;
0700         }
0701         
0702         if (NULL!=tempbuf)
0703         {
0704             /* fix #268 */
0705             tempbuf=NULL;
0706             NDRX_FREE(tempbuf);
0707         }
0708     }
0709     
0710 out:
0711     /* replace '\\' -> '\'  */
0712     if (strstr(str, "\\"))
0713     {
0714         malloced = ndrx_str_replace(str, "\\\\", "\\");
0715         strcpy(str, malloced);
0716         NDRX_FPFREE(malloced);
0717     }
0718 
0719     if (NULL!=outbuf)
0720     {
0721         NDRX_FREE(outbuf);
0722     }
0723 
0724     return ret;
0725 }
0726 
0727 
0728 /**
0729  * Unknown buffer len.
0730  * @param str
0731  * @return 
0732  */
0733 expublic char * ndrx_str_env_subs(char * str)
0734 {
0735     return ndrx_str_env_subs_len(str, 0);
0736 }
0737 
0738 /**
0739  * Decode numbers from config file ending with K, M, G
0740  * NOTE! This does change the str value!!!!
0741  * @param str
0742  * @return number parsed/built
0743  */
0744 expublic double ndrx_num_dec_parsecfg(char * str)
0745 {
0746     double ret = 0;
0747     double multipler = 1;
0748     int len = strlen(str);
0749     int mapplied = EXFALSE;
0750     
0751     if (len>1)
0752     {
0753         switch (str[len-1])
0754         {
0755             case 'k':
0756             case 'K':
0757                 multipler = 1000.0f;
0758                 mapplied = EXTRUE;
0759                 break;
0760             case 'm':
0761             case 'M':
0762                 multipler = 1000000.0f;
0763                 mapplied = EXTRUE;
0764                 break;
0765             case 'g':
0766             case 'G':
0767                 multipler = 1000000000.0f;
0768                 mapplied = EXTRUE;
0769                 break;
0770         }
0771         /* Avoid precision issues... */
0772         if (mapplied)
0773         {
0774             str[len-1] = EXEOS;
0775         }
0776     }
0777     
0778     ret = atof(str);
0779     
0780     ret*=multipler;
0781     
0782     return ret;
0783 }
0784 
0785 /**
0786  * Parse milli-seconds based record
0787  * @param str NOTE string is modified (last postfix removed for parsing)
0788  * @return parsed number of milliseconds
0789  */
0790 expublic double ndrx_num_time_parsecfg(char * str)
0791 {
0792     double ret = 0;
0793     double multipler = 1;
0794     int len = strlen(str);
0795     int mapplied = EXFALSE;
0796     
0797     if (len>1)
0798     {
0799         switch (str[len-1])
0800         {
0801             case 's':
0802                 /* second */
0803                 multipler = 1000.0f;
0804                 mapplied = EXTRUE;
0805                 break;
0806             case 'm':
0807                 /* minute */
0808                 multipler = 60.0f * 1000.0f;
0809                 mapplied = EXTRUE;
0810                 break;
0811             case 'h':
0812                 /* hour */
0813                 multipler = 60.0f * 60.0f * 1000.0f;
0814                 mapplied = EXTRUE;
0815                 break;
0816         }
0817         /* Avoid precision issues... */
0818         if (mapplied)
0819         {
0820             str[len-1] = EXEOS;
0821         }
0822     }
0823     
0824     ret = atof(str);
0825     
0826     ret*=multipler;
0827     
0828     return ret;
0829 }
0830 
0831 /**
0832  * Print the string up to max version
0833  * This assumes that buffer is atleast 2x symbols
0834  * @param str string to process
0835  * @param slot slot to use for temp strings
0836  * @param buf_sz max len to trim of 
0837  * @return ptr to printable string
0838  */
0839 expublic char *ndrx_decode_str(char *str, char *buf, int buf_sz)
0840 {
0841     int len = strlen(str);
0842     
0843     if (len < buf_sz)
0844     {
0845         return str;
0846     }
0847     
0848     NDRX_STRCPY_SAFE_DST(buf, str, buf_sz);
0849     
0850     buf[buf_sz-2]='+';
0851     
0852     return buf;
0853 }
0854 
0855 /**
0856  * Decode number
0857  * @param t
0858  * @param slot
0859  * @return 
0860  */
0861 expublic char *ndrx_decode_num(long tt, int slot, int level, int levels)
0862 {
0863     char tmp[128];
0864     long next_t=0;
0865     long t = tt;
0866 #define DEC_K  ((long)1000)
0867 #define DEC_M  ((long)1000*1000)
0868 #define DEC_B  ((long)1000*1000*1000)
0869 #define DEC_T  ((long long)1000*1000*1000*1000)
0870 
0871     NSTD_TLS_ENTRY;
0872     
0873     level++;
0874 
0875     if ((double)t/DEC_K < 1.0) /* Less that thousand */
0876     {
0877         snprintf(tmp, sizeof(tmp), "%ld", t);
0878     }
0879     else if ((double)t/DEC_M < 1.0) /* less than milliion */
0880     {
0881         snprintf(tmp, sizeof(tmp), "%ldK", t/DEC_K);
0882         
0883         if (level<levels)
0884             next_t = t%DEC_K;
0885     }
0886     else if ((double)t/DEC_B < 1.0) /* less that billion */
0887     {
0888         snprintf(tmp, sizeof(tmp), "%ldM", t/DEC_M);
0889         
0890         if (level<levels)
0891             next_t = t%DEC_M;
0892     }
0893     else if ((double)t/DEC_T < 1.0) /* less than trillion */
0894     {
0895         snprintf(tmp, sizeof(tmp), "%ldB", t/DEC_B);
0896         
0897         if (level<levels)
0898             next_t = t%DEC_B;
0899     }
0900     
0901     if (level==1)
0902     {
0903         NDRX_STRCPY_SAFE(G_nstd_tls->util_text[slot], tmp);
0904     }
0905     else
0906     {
0907         strcat(G_nstd_tls->util_text[slot], tmp);
0908     }
0909     
0910     if (next_t)
0911         ndrx_decode_num(next_t, slot, level, levels);
0912     
0913     return G_nstd_tls->util_text[slot];
0914 }
0915 
0916 /**
0917  * Strip specified char from string
0918  * @param haystack - string to strip
0919  * @param needle - chars to strip
0920  * @return 
0921  */
0922 expublic char *ndrx_str_strip(char *haystack, char *needle)
0923 {
0924     char *dest;
0925     char *src;
0926     int len = strlen(needle);
0927     int i;
0928     int have_found;
0929     dest = src = haystack;
0930 
0931     for (; EXEOS!=*src; src++)
0932     {
0933         have_found = EXFALSE;
0934         for (i=0; i<len; i++)
0935         {
0936             if (*src == needle[i])
0937             {
0938                 have_found = EXTRUE;
0939                 continue;
0940             }
0941         }
0942         /* Copy only if have found... */
0943         if (!have_found)
0944         {
0945             *dest = *src;
0946             dest++;
0947         }
0948     }
0949     
0950     *dest = EXEOS;
0951     
0952     return haystack;
0953 }
0954 
0955 /**
0956  * Strip off given chars from string ending
0957  * @param s string to process
0958  * @param needle chars to search and strip off from end
0959  * @return same s string
0960  */
0961 expublic char* ndrx_str_rstrip(char* s, char *needle)
0962 { 
0963     char* p = s + strlen(s);
0964     while (p > s)
0965     {
0966         p--;
0967         
0968         if (strchr(needle, *p))
0969         {
0970             *p = '\0';
0971         }
0972         else
0973         {
0974             /* we are done */
0975             break;
0976         }
0977     }
0978     return s;
0979 }
0980 
0981 /**
0982  * Return pointer to data where first non-matched char starts (strip from left)
0983  * @param s string to process
0984  * @param needle char to strip off
0985  * @return ptr to start non matched char
0986  */
0987 expublic char* ndrx_str_lstrip_ptr(char* s, char *needle)
0988 {
0989     int len = strlen(s);
0990     int i;
0991     char *p =s;
0992     
0993     for (i=0; i<len; i++)
0994     {
0995         if (strchr(needle, *p))
0996         {
0997             p++;
0998         }
0999         else
1000         {
1001             break;
1002         }
1003     }
1004     
1005     return p;
1006 }
1007 
1008 /**
1009  * Check is string a integer
1010  * @param str string to test
1011  * @return TRUE/FALSE
1012  */
1013 expublic int ndrx_isint(char *str)
1014 {
1015    if (*str == '-')
1016    {
1017       ++str;
1018    }
1019 
1020    if (!*str)
1021    {
1022       return EXFALSE;
1023    }
1024 
1025    while (*str)
1026    {
1027       if (!isdigit(*str))
1028       {
1029          return EXFALSE;
1030       }
1031       else
1032       {
1033          ++str;
1034       }
1035    }
1036    
1037    return EXTRUE;
1038 }
1039 
1040 /**
1041  * check is string empty or whitespace
1042  * @param s string to check
1043  * @return EXTRUE / EXFALSE
1044  */
1045 expublic int ndrx_isempty(const char *s)
1046 {
1047 
1048     while ( isspace( (unsigned char)*s) )
1049     {
1050         s++;
1051     }
1052 
1053     return *s == EXEOS ? EXTRUE : EXFALSE;
1054 }
1055 
1056 /**
1057  * Count the number of specified chars in string
1058  * @param str
1059  * @param chkchar chart to count
1060  * @return 
1061  */
1062 expublic int ndrx_nr_chars(char *str, char chkchar)
1063 {
1064     char *p = str;
1065     int count = 0;
1066     
1067     do
1068     {
1069         if (*p == chkchar)
1070         {
1071             count++;
1072         }
1073     } while (*(p++));
1074 
1075     return count;
1076 }
1077 
1078 /**
1079  * Returns the string mapped to long value
1080  * @param map - mapping table
1081  * @param val - value to map
1082  * @param endval - List end/default value
1083  * @return ptr to maping str
1084  */
1085 expublic char *ndrx_dolongstrgmap(longstrmap_t *map, long val, long endval)
1086 {
1087     do 
1088     {
1089         if (map->from == val)
1090         {
1091             return map->to;
1092         }
1093         map++;
1094     } while (endval!=map->from);
1095     
1096     return map->to;
1097 }
1098 
1099 
1100 /**
1101  * Returns the string mapped to long value
1102  * @param map - mapping table
1103  * @param val - value to map
1104  * @param endval - List end/default value
1105  * @return ptr to maping str
1106  */
1107 expublic char *ndrx_docharstrgmap(longstrmap_t *map, char val, char endval)
1108 {
1109     do 
1110     {
1111         if (map->from == val)
1112         {
1113             return map->to;
1114         }
1115         map++;
1116     } while (endval!=map->from);
1117     
1118     return map->to;
1119 }
1120 
1121 
1122 /**
1123  * Get thread id (not the very portable way...)
1124  * @return 
1125  */
1126 expublic uint64_t ndrx_gettid(void) 
1127 {
1128     pthread_t ptid = pthread_self();
1129     uint64_t threadId = 0;
1130     memcpy(&threadId, &ptid, _MIN(sizeof(threadId), sizeof(ptid)));
1131     return threadId;
1132 }
1133 
1134 /**
1135  * Tests for file existance
1136  * @param filename path + filename
1137  * @return TRUE if exists / FALSE not exists
1138  */
1139 expublic int ndrx_file_exists(char *filename)
1140 {
1141     struct stat st;
1142     int result = stat(filename, &st);
1143     return result == 0;
1144 }
1145 
1146 /**
1147  * Touch the file (create empty one)
1148  * @param filename path + file name
1149  * @return EXSUCCEED/EXFAIL
1150  */
1151 expublic int ndrx_file_touch(char *filename)
1152 {
1153     FILE *f = fopen(filename, "a");
1154     
1155     if (NULL==f)
1156     {
1157         return EXFAIL;
1158     }
1159     
1160     fclose(f);
1161     
1162     return EXSUCCEED;
1163 }
1164 
1165 /**
1166  * Test if given path is regular file
1167  * @param path
1168  * @return 
1169  */
1170 expublic int ndrx_file_regular(char *path)
1171 {
1172     struct stat path_stat;
1173     stat(path, &path_stat);
1174     return S_ISREG(path_stat.st_mode);
1175 }
1176 
1177 /**
1178  * read from stdin with stripping of trailing \r or \n
1179  * @return NULL or allocated stdin string read
1180  */
1181 expublic char * ndrx_fgets_stdin_strip(char *buf, int bufsz)
1182 {
1183     int len;
1184 
1185     if (NULL==fgets(buf, bufsz, stdin))
1186     {
1187         userlog("%s: fgets fail: %s", __func__, strerror(errno));
1188         return NULL;
1189     }
1190     
1191     len = strlen(buf);
1192     
1193     if (len>0)
1194     {
1195         len--;
1196         
1197         /* strip off newline */
1198         if (buf[len]=='\n')
1199         {
1200             buf[len] = 0;
1201             len--;
1202         }
1203         
1204         /* strip off \r */
1205         if (len>= 0 && buf[len]=='\r')
1206         {
1207             buf[len] = 0;
1208         }
1209     }
1210         
1211     return buf;
1212 }
1213 
1214 
1215 /**
1216  * Enduro/X Cross platform getline version (system version, more close to GNU)
1217  * @param lineptr must be pre-allocated (for Macos will use fgets on this buffer)
1218  * @param n buffer size (ptr to)
1219  * @param stream file to read from
1220  * @return number bytes read for Macos will return just 1 or -1
1221  */
1222 expublic ssize_t ndrx_getline(char **lineptr, size_t *n, FILE *stream)
1223 {
1224 #ifdef HAVE_GETLINE
1225     
1226     return getline(lineptr, n, stream);
1227     
1228 #else
1229     if (NULL==fgets(*lineptr, *n, stream))
1230     {
1231         return EXFAIL;
1232     }
1233     else
1234     {
1235         return EXTRUE;
1236     }
1237 #endif
1238 }
1239 
1240 /**
1241  * Calculate crc32 of given file
1242  * @param file
1243  * @return CRC32 or FAIL (-1)
1244  */
1245 expublic int ndrx_get_cksum(char *file)
1246 {
1247     unsigned char checksum = 0;
1248     int ret = EXSUCCEED;
1249     
1250     FILE *fp = fopen(file,"rb");
1251     
1252     if (NULL!=fp)
1253     {
1254         
1255         while (!feof(fp) && !ferror(fp)) {
1256            checksum ^= fgetc(fp);
1257         }
1258 
1259         fclose(fp);
1260     }
1261     else
1262     {
1263         ret = EXFAIL;
1264     }
1265     
1266     if (EXSUCCEED==ret)
1267     {
1268         return checksum;
1269     }
1270     else
1271     {
1272         return EXFAIL;
1273     }
1274 }
1275 
1276 /**
1277  * Get the path from executable
1278  * @param out_path  Out buffer (full binary name where lives...)
1279  * @param bufsz Out buffer size
1280  * @param in_binary Binary to search for
1281  * @return NULL (if not found) or ptr to out_path if found
1282  */
1283 expublic char * ndrx_get_executable_path(char * out_path, size_t bufsz, char * in_binary)
1284 {
1285     char * systemPath = NULL;
1286     char * candidateDir = NULL;
1287     int found = EXFALSE;
1288     char *ret;
1289     
1290     systemPath = getenv ("PATH");
1291     if (systemPath != NULL)
1292     {
1293         systemPath = strdup (systemPath);
1294         for (candidateDir = strtok (systemPath, ":"); 
1295                 candidateDir != NULL; 
1296                 candidateDir = strtok (NULL, ":"))
1297         {
1298             snprintf(out_path, bufsz, "%s/%s", candidateDir, in_binary);
1299             
1300             if (access(out_path, F_OK) == 0)
1301             {
1302                 found = EXTRUE;
1303                 goto out;
1304             }
1305         }
1306     }
1307 
1308 out:
1309     
1310     if (systemPath)
1311     {
1312         free(systemPath);
1313     }
1314 
1315     if (found) 
1316     {
1317         ret = out_path;
1318     }
1319     else
1320     {
1321         out_path[0] = EXEOS;
1322         ret = NULL;
1323     }
1324     
1325     return ret;
1326 }
1327 
1328 /**
1329  * Allocate & duplicate the ptr to which org points
1330  * @param org memroy to copy
1331  * @param len length to copy
1332  * @return NULL or allocated memory
1333  */
1334 expublic char * ndrx_memdup(char *org, size_t len)
1335 {
1336     char *ret;
1337     
1338     if (NULL!=(ret = NDRX_MALLOC(len)))
1339     {
1340         memcpy(ret, org, len);
1341         return ret;
1342     }
1343     
1344     return NULL;
1345 }
1346 
1347 /**
1348  * Locale independent atof
1349  * Basically this assumes that home decimal separator is '.'. I.e. \r str must
1350  * contain only '.'.
1351  * @param str string to convert to float, decimal separator is '.'.
1352  * @return converted decimal value
1353  */
1354 expublic double ndrx_atof(char *str)
1355 {
1356     char test[5];
1357     char buf[128];
1358     char *p;
1359     int len, i;
1360     
1361     /* extract the decimal separator... */
1362     snprintf(test, sizeof(test), "%.1f", 0.0f);
1363     
1364     if (NDRX_LOCALE_STOCK_DECSEP!=test[1])
1365     {
1366         NDRX_STRCPY_SAFE(buf, str);
1367         len = strlen(buf);
1368         
1369         for (i=0; i<len; i++)
1370         {
1371             if (NDRX_LOCALE_STOCK_DECSEP==buf[i])
1372             {
1373                 buf[i] = test[1];
1374             }
1375         }
1376         
1377         p = buf;
1378     }
1379     else
1380     {
1381         p = str;
1382     }
1383     
1384     return atof(p);
1385 }
1386 
1387 /**
1388  * Extract tokens from string
1389  * @param str
1390  * @param fmt   Format string for scanf
1391  * @param tokens
1392  * @param tokens_elmsz
1393  * @param len
1394  * @param start_tok 0 based index of token to start to extract
1395  * @param stop_tok 0 based indrex of token to stop to extracts
1396  * @return 0 - no tokens extracted
1397  */
1398 expublic int ndrx_tokens_extract(char *str1, char *fmt, void *tokens, 
1399         int tokens_elmsz, int len, int start_tok, int stop_tok)
1400 {
1401     int ret = 0;
1402     char *str = NDRX_STRDUP(str1);
1403     char *ptr;
1404     char *token;
1405     char *str_first = str;
1406     int toks=0;
1407     int is_hex;
1408     char *int_fmt = "%d";
1409     
1410     if (0==strcmp(fmt, "%x"))
1411     {
1412         is_hex=EXTRUE;
1413     }
1414     else
1415     {   
1416         is_hex=EXFALSE;
1417     }
1418     
1419     if (NULL==str)
1420     {
1421         int err = errno;
1422         NDRX_LOG(log_error, "Failed to duplicate [%s]: %s", str1, strerror(err));
1423         userlog("Failed to duplicate [%s]: %s", str1, strerror(err));
1424         goto out;
1425     }
1426     
1427     while ((token = strtok_r(str_first, "\t ", &ptr)))
1428     {
1429         if (NULL!=str_first)
1430         {
1431             str_first = NULL; /* now loop over the string */
1432         }
1433         
1434         if (toks>=start_tok)
1435         {
1436             if (ret<len)
1437             {
1438                 /* special for potential hex columns */
1439                 if (is_hex)
1440                 {
1441                     if (0==strncmp(token, "0x", 2) || 
1442                         0==strncmp(token, "0X", 2))
1443                     {    
1444                         token+=2;
1445                         sscanf(token, fmt, tokens);
1446                     }
1447                     else
1448                     {
1449                         /* data is in int fmt... */
1450                         sscanf(token, int_fmt, tokens);
1451                     }
1452                 }
1453                 else
1454                 {
1455                     /* other types */
1456                     sscanf(token, fmt, tokens);
1457                 }
1458                 
1459                 tokens+=tokens_elmsz;
1460             }
1461             else
1462             {
1463                 break;
1464             }
1465             ret++;
1466         }
1467         
1468         if (toks>=stop_tok)
1469         {
1470             break;
1471         }
1472         toks++;
1473     }
1474     
1475 out:
1476 
1477     if (NULL!=str)
1478     {
1479         NDRX_FREE(str);
1480     }
1481     return ret;
1482 }
1483 
1484 /**
1485  * Remove trailing newlines
1486  * @param str
1487  * @return 
1488  */
1489 expublic void ndrx_chomp(char *str)
1490 {
1491     int len = strlen(str);
1492 
1493     while (len>1 && (str[len-1]=='\n' || str[len-1]=='\r'))
1494     {
1495         str[len-1] = EXEOS;
1496         len--;
1497     }
1498 }
1499 
1500 /**
1501  * 32bit rotate left
1502  * @param x variable to rotate bits left
1503  * @param n number of bits to rotate
1504  * @return return value
1505  */
1506 expublic uint32_t ndrx_rotl32b (uint32_t x, uint32_t n)
1507 {
1508   if (!n) return x;
1509   return (x<<n) | (x>>(32-n));
1510 }
1511 
1512 
1513 /**
1514  * Return string len, but do it until the max position
1515  * @param str string to test
1516  * @param max max len to test to
1517  * @return string len
1518  */
1519 expublic size_t ndrx_strnlen(char *str, size_t max)
1520 {
1521     char *p;
1522     
1523     for(p = str; max && *p; ++p)
1524     {
1525         max--;
1526     }
1527     
1528     return(p - str);
1529 }
1530 
1531 /**
1532  * Initialize the grow list
1533  * @param list ptr to list (can be un-initialized memory)
1534  * @param step number of elements by which to reallocate ahead
1535  * @param size element size
1536  */
1537 expublic void ndrx_growlist_init(ndrx_growlist_t *list, int step, size_t size)
1538 {
1539     list->maxindexused = EXFAIL;
1540     list->itemsalloc = 0;
1541     list->step = step;
1542     list->size = size;
1543     list->mem = NULL;
1544 }
1545 
1546 /**
1547  * Add element to the list. Allocate/reallocate linear array as needed.
1548  * @param list list struct pointer
1549  * @param item ptr to item
1550  * @param index zero based item index in the memory
1551  * @return EXSUCCEED (all OK), EXFAIL (failed to allocate)
1552  */
1553 expublic int ndrx_growlist_add(ndrx_growlist_t *list, void *item, int index)
1554 {
1555     return ndrx_growlist_add_many(list, item, index, 1);
1556 }
1557 
1558 /**
1559  * Add many items with single shot
1560  * @param list list where to add
1561  * @param item ptr to first item
1562  * @param index where to load
1563  * @param count number of items in ptr (consecutive one by one)
1564  * @return EXSUCCEED/EXFAIL
1565  */
1566 expublic int ndrx_growlist_add_many(ndrx_growlist_t *list, void *item, int index, int count)
1567 {
1568     int ret = EXSUCCEED;
1569     int next_blocks;
1570     size_t new_size;
1571     char *p;
1572     
1573     if (NULL==list->mem)
1574     {
1575         new_size = list->step * list->size;
1576         if (NULL==(list->mem = NDRX_FPMALLOC(list->step * list->size, 0)))
1577         {
1578             userlog("Failed to alloc %d bytes: %s", new_size,
1579                         strerror(errno));
1580             
1581             EXFAIL_OUT(ret);
1582         }
1583         
1584         list->itemsalloc+=list->step;
1585     }
1586     
1587     while (index+count > list->itemsalloc)
1588     {
1589         list->itemsalloc+=list->step;
1590         
1591         next_blocks = list->itemsalloc / list->step;
1592         
1593         new_size = next_blocks * list->step * list->size;
1594         /*
1595         NDRX_LOG(log_debug, "realloc: new_size: %d (index: %d items: %d)", 
1596                 new_size, index, list->items);
1597         */
1598         if (NULL==(list->mem = NDRX_FPREALLOC(list->mem, new_size)))
1599         {
1600             userlog("Failed to realloc %d bytes (%d blocks): %s", new_size,
1601                         next_blocks, strerror(errno));
1602             
1603             EXFAIL_OUT(ret);
1604         }
1605     }
1606     
1607     /* finally we are ready for data */
1608     p = list->mem;
1609     p+=(index * list->size);
1610     
1611     /*
1612     NDRX_LOG(log_debug, "Ptr: %p, write ptr %p, from %p (size: %d, index: %d)",
1613             list->mem, p, item, (int)list->size, index);
1614     
1615     NDRX_DUMP(log_debug, "data for writting", item, list->size);
1616     */
1617     memcpy( p, item, list->size*count);
1618     
1619     
1620     if ((index+count-1) > list->maxindexused)
1621     {
1622         list->maxindexused = index+count-1;
1623     }
1624     
1625 out:
1626 
1627     return ret;
1628     
1629 }
1630 
1631 /**
1632  * Append entry (at the end of the array)
1633  * @param list list to be appended
1634  * @param item item to be added to the end of the array
1635  * @return EXSUCCEED/EXFAIL (out of the mem)
1636  */
1637 expublic int ndrx_growlist_append(ndrx_growlist_t *list, void *item)
1638 {
1639     return ndrx_growlist_add(list, item, list->maxindexused+1);
1640 }
1641 
1642 /**
1643  * Added multiple items to the buffer
1644  * @param list list item
1645  * @param item item to add (ptr to first)
1646  * @param count to add
1647  * @return EXSUCCEED/EXFAIL
1648  */
1649 expublic int ndrx_growlist_append_many(ndrx_growlist_t *list, void *item, int count)
1650 {
1651     return ndrx_growlist_add_many(list, item, list->maxindexused+1, count);
1652 }
1653 
1654 /**
1655  * Free up the grow list. User is completely responsible for any data to be freed
1656  * from the mem block
1657  * @param list ptr to list
1658  */
1659 expublic void ndrx_growlist_free(ndrx_growlist_t *list)
1660 {
1661     if (NULL!=list->mem)
1662     {
1663         NDRX_FPFREE(list->mem);
1664         /* reset list to initial state */
1665         list->mem=NULL;
1666         list->maxindexused=EXFAIL;
1667         list->itemsalloc = 0;
1668     }
1669 }
1670 
1671 /**
1672  * Return chunks of split string
1673  * @param s1 last string ptr to on which strsep was executed
1674  * @param s2 chars by which to split
1675  * @return NULL if not found, or ptr to first split string
1676  */
1677 expublic char *ndrx_strsep(char **s1, char *s2)
1678 {
1679     char *p1 = *s1;
1680 
1681     if (p1 != NULL) 
1682     {
1683         *s1 = strpbrk(p1, s2);
1684         if (*s1 != NULL)
1685         {
1686             *(*s1) = '\0';
1687             
1688             /* move to next position */
1689             (*s1)++;
1690         }
1691     }
1692     
1693     return p1;
1694 }
1695 
1696 /**
1697  * Parse arguments and load into target 
1698  * @param[in] args argument descriptor
1699  * @param[out] obj object to process
1700  * @param[in] fldnm field name
1701  * @param[in] value string value to load (will be converted accordingly)
1702  * @param[out] errbuf error buffer where to put the error msg if parser fails
1703  * @param [out] errbufsz error buffer size
1704  * @return EXSUCCEED/EXFAIL
1705  */
1706 expublic int ndrx_args_loader_set(ndrx_args_loader_t *args, void *obj, 
1707         char *fldnm, char *value,
1708         char *errbuf, size_t errbufsz)
1709 {
1710     int ret = EXSUCCEED;
1711     int *p_bool; 
1712     int *p_int; 
1713     int tmp_int;
1714     
1715     while (EXFAIL!=args->offset)
1716     {
1717         if (0==strcmp(fldnm, args->cname))
1718         {
1719             switch (args->fld_type)
1720             {
1721                 case NDRX_ARGS_BOOL:
1722 
1723                     p_bool = (int *)((char *)obj + args->offset);
1724 
1725                     if (0==strcmp(value, "y") || 0==strcmp(value, "Y"))
1726                     {
1727                         *p_bool = EXTRUE;
1728                     }
1729                     else if (0==strcmp(value, "n") || 0==strcmp(value, "N"))
1730                     {
1731                         *p_bool = EXFALSE;
1732                     }
1733                     else
1734                     {
1735                         snprintf(errbuf, errbufsz, "Unsupported value for [%s] "
1736                                 "bool field must be [yYnN], got: [%s]", 
1737                                 args->cname, value);
1738 
1739                         NDRX_LOG(log_error, "%s", errbuf);
1740                         EXFAIL_OUT(ret);
1741                     }
1742 
1743                     NDRX_LOG(log_warn, "[%s] set to [%d]", args->cname, *p_bool);
1744 
1745                     break;
1746                 case NDRX_ARGS_INT:
1747 
1748                     /* TODO: Parse and set... */
1749                     p_int = (int *)((char *)obj + args->offset);
1750                     tmp_int = atoi(value);
1751 
1752                     if (tmp_int < (int)args->min_value)
1753                     {
1754                         snprintf(errbuf, errbufsz, "Unsupported value for [%s] "
1755                                 "int field, min [%d], got: [%d]", 
1756                                 args->cname, (int)args->min_value, tmp_int);
1757                         NDRX_LOG(log_error, "%s", errbuf);
1758                         EXFAIL_OUT(ret);
1759                     }
1760                     else if (tmp_int > (int)args->max_value)
1761                     {
1762                         snprintf(errbuf, errbufsz, "Unsupported value for [%s] "
1763                                 "int field, max [%d], got: [%d]", 
1764                                 args->cname, (int)args->max_value, tmp_int);
1765                         NDRX_LOG(log_error, "%s", errbuf);
1766                         EXFAIL_OUT(ret);
1767                     }
1768                     *p_int = tmp_int;
1769 
1770                     NDRX_LOG(log_warn, "[%s] set to [%d]", args->cname, *p_int);
1771 
1772                     break;
1773                 case NDRX_ARGS_CB:
1774                     
1775                     if (EXSUCCEED!=args->cb_set(args, value, 0, obj, errbuf, errbufsz))
1776                     {
1777                         EXFAIL_OUT(ret);
1778                     }
1779                     
1780                     break;
1781                 default:
1782                     snprintf(errbuf, errbufsz, "Type not supported: %d", 
1783                             args->fld_type);
1784                     EXFAIL_OUT(ret);
1785                     break;
1786             }
1787             
1788             break;
1789         } /* fldnm == args->cname */
1790         args++;
1791     }
1792     
1793     if (EXFAIL==args->offset)
1794     {
1795         snprintf(errbuf, errbufsz, "Setting not found [%s]", fldnm);
1796         NDRX_LOG(log_error, "%s", errbuf);
1797         EXFAIL_OUT(ret);
1798     }
1799     
1800 out:
1801     return ret;
1802 }
1803 
1804 /**
1805  * Get argument value
1806  * @param[in] args argument descriptor
1807  * @param[out] obj object to process
1808  * @param[in] fldnm field name to get
1809  * @param[out] value string value to load (will be converted accordingly)
1810  * @param[out] valuesz buffer size of value
1811  * @param[out] errbuf error buffer where to put the error msg if parser fails
1812  * @param [out] errbufsz error buffer size
1813  * @return EXSUCCEED/EXFAIL
1814  */
1815 expublic int ndrx_args_loader_get(ndrx_args_loader_t *args, void *obj, char *fldnm,
1816         char *value, int valuesz,
1817         char *errbuf, size_t errbufsz)
1818 {
1819     int ret = EXSUCCEED;
1820     int *p_bool; 
1821     int *p_int; 
1822     
1823     while (EXFAIL!=args->offset)
1824     {
1825         if (0==strcmp(fldnm, args->cname))
1826         {
1827             switch (args->fld_type)
1828             {
1829                 case NDRX_ARGS_BOOL:
1830 
1831                     p_bool = (int *)((char *)obj + args->offset);
1832 
1833                     snprintf(value, valuesz, "%s", (*p_bool)?"Y":"N");
1834 
1835                     break;
1836                 case NDRX_ARGS_INT:
1837 
1838                     p_int = (int *)((char *)obj + args->offset);
1839 
1840                     snprintf(value, valuesz, "%d", *p_int);
1841 
1842                     break;
1843                 case NDRX_ARGS_CB:
1844                     
1845                     if (EXSUCCEED!=args->cb_get(args, value, valuesz, obj, errbuf, errbufsz))
1846                     {
1847                         EXFAIL_OUT(ret);
1848                     }
1849                     
1850                     break;
1851                 default:
1852                     snprintf(errbuf, errbufsz, "Type not supported: %d", 
1853                             args->fld_type);
1854                     NDRX_LOG(log_error, "%s", errbuf);
1855                     EXFAIL_OUT(ret);
1856                     break;
1857             }
1858             
1859             /* we are done */
1860             break;
1861         }
1862         args++;
1863     }
1864     
1865     if (EXFAIL==args->offset)
1866     {
1867         snprintf(errbuf, errbufsz, "Setting not found [%s]", fldnm);
1868         NDRX_LOG(log_error, "%s", errbuf);
1869         EXFAIL_OUT(ret);
1870     }
1871     
1872 out:
1873     return ret;
1874 }
1875 
1876 /**
1877  * Return confirmation or rejection.
1878  * Or error in case if arg not valid value
1879  * @param arg YyNn
1880  * @return TRUE (yY), FALSE (nN), FAIL (invalid value)
1881  */
1882 expublic int ndrx_args_confirm(char *arg)
1883 {
1884     int ret = EXFAIL;
1885     
1886     if (strlen(arg) !=1 )
1887     {
1888         ret = EXFAIL;
1889     }
1890     else if (NULL!=strstr(NDRX_ARGS_YES, arg))
1891     {
1892         ret=EXTRUE;
1893     }
1894     else if (NULL!=strstr(NDRX_ARGS_NO, arg))
1895     {
1896         ret=EXFALSE;
1897     }
1898     
1899     return ret;
1900 }
1901 
1902 /**
1903  * Decode numbers like:
1904  * Kk -> *1024
1905  * Mm -> *1024*1024
1906  * Gg -> *1024*1024*1024
1907  * Tt -> *1024*1024*1024*1024
1908  * @param bytesenc
1909  * @param outnrbytes
1910  * @return EXSUCCEED/EXFAIL (invalid suffix)
1911  */
1912 expublic int ndrx_storage_decode(char *bytesenc, long *outnrbytes)
1913 {
1914     int ret = EXSUCCEED;
1915     int len = strlen(bytesenc);
1916     char tmp[256];
1917     char suffix;
1918     long vout;
1919     
1920     if (len < 2)
1921     {
1922         EXFAIL_OUT(ret);
1923     }
1924     
1925     NDRX_STRCPY_SAFE(tmp, bytesenc);
1926     
1927     suffix = bytesenc[len-1];
1928     tmp[len-1] = EXEOS;
1929     
1930     vout = atol(tmp);
1931     
1932     if (suffix>='0' && suffix <= '9')
1933     {
1934         /* no suffix provided, all ok, just jump out... */
1935         goto out;
1936     }
1937             
1938     switch (suffix)
1939     {
1940         case 'T':
1941         case 't':
1942             vout *=NDRX_STOR_KBYTE;
1943         case 'G':
1944         case 'g':
1945             vout *=NDRX_STOR_KBYTE;
1946         case 'M':
1947         case 'm':
1948             vout *=NDRX_STOR_KBYTE;
1949         case 'K':
1950         case 'k':
1951             vout *=NDRX_STOR_KBYTE;
1952             break;
1953         default:
1954             NDRX_LOG(log_error, "Invalid suffix for [%s] %c", bytesenc, suffix);
1955             EXFAIL_OUT(ret);
1956             break;
1957     }
1958     
1959 out:
1960     if (EXSUCCEED==ret)
1961     {
1962         *outnrbytes = vout;
1963     }
1964 
1965     return ret;
1966 }
1967 
1968 /**
1969  * Encode the output number for human readable size
1970  * @param bytes number of bytes
1971  * @param outbuf where to store
1972  * @param outbufsz text buffer size
1973  */
1974 expublic void ndrx_storage_encode(long bytes, char *outbuf, int outbufsz)
1975 {
1976     int ret = EXSUCCEED;
1977     int loops=0;
1978     double left_over = bytes;
1979     char suffix=EXEOS;
1980     
1981     while (1)
1982     {
1983         
1984         if ( left_over < (double)NDRX_STOR_KBYTE)
1985         {
1986             break;
1987         }
1988         
1989         left_over= left_over / (double)NDRX_STOR_KBYTE;
1990         
1991         loops++;
1992     }
1993     
1994     switch (loops)
1995     {
1996         case 4:
1997             suffix = 'T';
1998             break;
1999         case 3:
2000             suffix = 'G';
2001             break;
2002         case 2:
2003             suffix = 'M';
2004             break;
2005         case 1:
2006             suffix = 'K';
2007             break;
2008         case 0:
2009             suffix = 'B';
2010             break;
2011         default:
2012             suffix = '?';
2013             break;
2014     }
2015     
2016     snprintf(outbuf, outbufsz, "%.3lf%c", left_over, suffix);
2017     
2018 }
2019 
2020 /**
2021  * Replace one character to another
2022  * @param str string to change
2023  * @param from_char find & replace this char
2024  * @param to_char replace with this change
2025  * @return input string
2026  */
2027 expublic char *ndrx_strchr_repl (char *str, char from_char, char to_char) 
2028 {
2029     
2030     char *p = str;
2031     
2032     while ((p = strchr (p, from_char)) != NULL)
2033     {
2034         *p = to_char;
2035         p++;
2036     }
2037     
2038     return str;
2039 }
2040 
2041 /**
2042  * Find entry in hash 
2043  * @param hash hash object
2044  * @param key key to find
2045  * @return result or NULL not found
2046  */
2047 expublic ndrx_intmap_t *ndrx_intmap_find (ndrx_intmap_t ** hash, int key)
2048 {
2049     ndrx_intmap_t *ret = NULL;
2050     EXHASH_FIND_INT( (*hash), &key, ret);
2051     return ret;
2052 }
2053 
2054 /**
2055  * Add key to hash
2056  * @param hash hash object
2057  * @param key key to add
2058  * @param value value to add
2059  * @return object created/add or NULL on OOM
2060  */
2061 expublic ndrx_intmap_t * ndrx_intmap_add (ndrx_intmap_t ** hash, int key, int value)
2062 {
2063     ndrx_intmap_t * el;
2064     el = NDRX_CALLOC(1, sizeof(ndrx_intmap_t));
2065     
2066     if (NULL==el)
2067     {
2068         userlog("intmap: Failed to alloc %d bytes: %s", sizeof(ndrx_intmap_t), 
2069                 strerror(errno));
2070     }
2071     else
2072     {
2073         el->key = key;
2074         el->value = value;
2075         EXHASH_ADD_INT((*hash), key, el);   
2076     }
2077     
2078     return el;
2079 }
2080 
2081 /**
2082  * Delete all from hash
2083  * @param hash has object
2084  */
2085 expublic void ndrx_intmap_remove (ndrx_intmap_t ** hash)
2086 {
2087     ndrx_intmap_t *e=NULL, *et=NULL;
2088     
2089     EXHASH_ITER(hh, (*hash), e, et)
2090     {
2091         EXHASH_DEL((*hash), e);
2092         NDRX_FREE(e);
2093     }
2094     
2095 }
2096 
2097 #define TEMP_MAKS_LEN 6
2098 /**
2099  * Generate temporary file name. Cross platform. Seem Solaris 10 does not have
2100  *  this, also AIX has some extra lib deps. Thu having own version.
2101  * Last 6 chars before suffix are replaced with random values
2102  * @param filetempl this is string show last 6 characters will be randomly filled
2103  *  to get unique file name
2104  * @param suffixlen chars from the end that shall not be filled (left uninit)
2105  * @param flags NDRX_STDF_TEST test flag, do not set random names -> return
2106  *  file exists.
2107  * @return file pointer or NULL in case of error. EEXIST - all attempts exceeded
2108  *  EINVAL - filetempl strlen is shorter than 6 + suffix len.
2109  */
2110 expublic FILE* ndrx_mkstemps(char *filetempl, int suffixlen, long flags)
2111 {
2112     FILE *ret = NULL;
2113     int i, j, len, fd, err;
2114     char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
2115     int chk_size = sizeof(letters) -1; /* strip off EOS */
2116     
2117     /*
2118     fd = open(tmpname, O_EXCL | O_CREAT, 0600);
2119     */
2120     
2121     len = strlen(filetempl);
2122     
2123     if (len < TEMP_MAKS_LEN + suffixlen)
2124     {
2125         errno = EINVAL;
2126         goto out;
2127     }
2128     
2129     for (i=0; i<NDRX_TEMP_ATTEMPTS; i++)
2130     {
2131         if (!(flags & NDRX_STDF_TEST))
2132         {
2133             for (j=len-suffixlen-TEMP_MAKS_LEN; j<len-suffixlen; j++)
2134             {
2135                 filetempl[j] = letters[ndrx_rand() % chk_size];
2136             }
2137         }
2138         
2139         fd = open(filetempl, O_EXCL | O_CREAT | O_WRONLY, 0600);
2140 
2141         if (EXFAIL==fd)
2142         {
2143             if (EEXIST!=errno)
2144             {
2145                 err = errno;
2146                 
2147                 NDRX_LOG(log_error, "Failed to create temp name [%s]: %s", 
2148                         filetempl, strerror(err));
2149                 
2150                 errno = err; /* log write may reset... */
2151                 goto out;
2152             } /* else try next */
2153         }
2154         else
2155         {
2156             /* OK file is open, if open ok, the fclose() will close the FD too */
2157             ret = fdopen(fd, "w");
2158             if (NULL==ret)
2159             {
2160                 err = errno;
2161                 
2162                 NDRX_LOG(log_error, "Failed to fdopen: %s", strerror(err));
2163                 close(fd);
2164                 errno = err; /* log write may reset... */
2165                 goto out;
2166             }
2167             break;
2168         }
2169     }
2170     
2171     if (NULL==ret)
2172     {
2173         NDRX_LOG(log_error, "%d attempts exceeded, no free file found: [%s] (last templ)", 
2174                 NDRX_TEMP_ATTEMPTS, filetempl);
2175         errno = EEXIST;
2176     }
2177     
2178 out:
2179     return ret;
2180 }
2181 
2182 /**
2183  * Check is given string buffer numeric
2184  * @param str buffer to test
2185  * @return EXTRUE/EXFALSE
2186  */
2187 expublic int ndrx_is_numberic(char *str)
2188 {
2189     while(*str != EXEOS)
2190     {
2191         if(*str < '0' || *str > '9')
2192         {
2193             return EXFALSE;
2194         }
2195         
2196         str++;
2197     }
2198     
2199     return EXTRUE;
2200 }
2201 
2202 /**
2203  * Read password from CLI, disable terminal while read
2204  * @param buf buffer where to load input
2205  * @param bufsz buffer size
2206  */
2207 expublic void ndrx_read_silent(char *buf, size_t bufsz)
2208 {
2209     static struct termios old_terminal;
2210     static struct termios new_terminal;
2211 
2212     /* get terminal attrib*/
2213     tcgetattr(STDIN_FILENO, &old_terminal);
2214 
2215     /* remove echo */
2216     new_terminal = old_terminal;
2217     new_terminal.c_lflag &= ~(ECHO);
2218 
2219     /* apply settings */
2220     tcsetattr(STDIN_FILENO, TCSANOW, &new_terminal);
2221 
2222     ndrx_fgets_stdin_strip(buf, bufsz);
2223 
2224     /* restore original terminal settings */
2225     tcsetattr(STDIN_FILENO, TCSANOW, &old_terminal);    
2226 }
2227 
2228 /**
2229  * Read and check password
2230  * @param msg message for password request
2231  * @param buf buffer where to load the password (may be updated even on fail - no match)
2232  * @param bufsz buffer size of password
2233  * @return EXSUCCEED - read twice, machined, EXFAIL - did not match or malloc fail
2234  */
2235 expublic int ndrx_get_password(char *msg, char *buf, size_t bufsz)
2236 {
2237     char *tmp_buf = NDRX_MALLOC(bufsz);
2238     int ret = EXSUCCEED;
2239     
2240     if (NULL==tmp_buf)
2241     {
2242         fprintf(stderr, "System error.\n");
2243         NDRX_LOG(log_error, "Failed to malloc: %s", strerror(errno));
2244         EXFAIL_OUT(ret);
2245     }
2246     
2247     fprintf(stderr, "Enter %s: ", msg);
2248     ndrx_read_silent(tmp_buf, bufsz);
2249     fprintf(stderr, "\n");
2250     
2251     fprintf(stderr, "Retype %s: ", msg);
2252     ndrx_read_silent(buf, bufsz);
2253     fprintf(stderr, "\n");
2254     
2255     if (0!=strcmp(buf, tmp_buf))
2256     {
2257         fprintf(stderr, "Sorry, input do not match\n");
2258         EXFAIL_OUT(ret);
2259     }
2260     
2261 out:
2262             
2263     if (NULL!=tmp_buf)
2264     {
2265         NDRX_FREE(tmp_buf);
2266     }
2267 
2268     return ret;
2269 }
2270 
2271 /**
2272  * Calculate the due time past and future
2273  * @param due time to process
2274  * @param ms milliseconds to substract or add
2275  */
2276 expublic void ndrx_timespec_plus(struct timespec *due, long ms)
2277 {
2278     due->tv_sec += (ms / 1000);
2279     due->tv_nsec += ((ms % 1000) * 1000000);
2280     
2281     if (due->tv_nsec >= 1000000000)
2282     {
2283         due->tv_nsec -= 1000000000;
2284         due->tv_sec++;
2285     }
2286     else if (due->tv_nsec < 0)
2287     {
2288         due->tv_nsec += 1000000000;
2289         due->tv_sec--;
2290     }
2291 }
2292 
2293 /**
2294  * Copy to destination with dest size set.
2295  * Use this where macros does not work (.y/.l)
2296  * @param dest dest buffer
2297  * @param src source buffer
2298  * @param dst_size dest len
2299  */
2300 expublic void ndrx_strcpy_safe_dst(char *dest, const char *src, size_t dst_size)
2301 {
2302     NDRX_STRCPY_SAFE_DST(dest, src, dst_size);
2303 }
2304 
2305 /**
2306  * Copy number of chars, ensure that string is terminated with EOS
2307  * Ensure that dest buffer does not go over. Ensure for EOS
2308  * @param dest dest buffer
2309  * @param src source buffer
2310  * @param n number chars to copy
2311  * @param dst_size dest buffer size
2312  */
2313 expublic void ndrx_strncpy_eos(char *dest, const char *src, size_t n, size_t dst_size)
2314 {
2315     NDRX_STRNCPY_EOS(dest, src, n, dst_size);
2316 }
2317 
2318 /**
2319  * Safe strcat with dest buffer checking
2320  * @param dest dst buffer
2321  * @param dst_size dest size
2322  * @param src source buffer to copy from
2323  */
2324 expublic void ndrx_strcat_s(char *dest, size_t dst_size, const char *src)
2325 {
2326     NDRX_STRCAT_S(dest, dst_size, src);
2327     
2328 }
2329 
2330 /**
2331  * Check that identifier is valid c style identifier
2332  * @param str string to check
2333  * @param max_len max allowed len
2334  * @return EXSUCCEED/EXFAIL
2335  */
2336 expublic int ndrx_str_valid_cid(char *str, int max_len)
2337 { 
2338     int i;
2339     int len = strlen(str);
2340     
2341     if (len < 1 || len > max_len)
2342     {
2343         return EXFALSE;
2344     }
2345     
2346     if (!((str[0] >= 'a' && str[0] <= 'z') 
2347           || (str[0] >= 'A' && str[1] <= 'Z') 
2348           || str[0] == '_')) 
2349     {
2350         return EXFALSE;
2351     }
2352   
2353     for (i = 1; i < len; i++)
2354     { 
2355         if (!((str[i] >= 'a' && str[i] <= 'z') 
2356               || (str[i] >= 'A' && str[i] <= 'Z') 
2357               || (str[i] >= '0' && str[i] <= '9') 
2358               || str[i] == '_')) 
2359         return EXFALSE;
2360     } 
2361   
2362     return EXTRUE;
2363 }
2364 
2365 /**
2366  * May contain [a-zA-Z0-9_]+
2367  * @param str string to check
2368  * @param max_len max allowed len
2369  * @return EXSUCCEED/EXFAIL
2370  */
2371 expublic int ndrx_str_valid_alphanumeric_(char *str, int max_len)
2372 { 
2373     int i;
2374     int len = strlen(str);
2375     
2376     if (len < 1 || len > max_len)
2377     {
2378         return EXFALSE;
2379     }
2380 
2381     for (i = 0; i < len; i++)
2382     { 
2383         if (!((str[i] >= 'a' && str[i] <= 'z') 
2384               || (str[i] >= 'A' && str[i] <= 'Z') 
2385               || (str[i] >= '0' && str[i] <= '9') 
2386               || str[i] == '_')) 
2387         return EXFALSE;
2388     } 
2389   
2390     return EXTRUE;
2391 }
2392 
2393 
2394 /**
2395  * Check that str ends with needle
2396  * @param str string
2397  * @param needle what to search for str trailing
2398  * @return EXTRUE, EXFALSE
2399  */
2400 expublic int ndrx_str_ends_with(char *str, char *needle)
2401 {
2402     int len_str = strlen(str);
2403     int len_needle = strlen(needle);
2404     
2405     return  (len_str >= len_needle) && (0 == strcmp(str + (len_str-len_needle), needle));
2406 }
2407 
2408 /**
2409  * Return file age in seconds
2410  * @param fname file name to check
2411  * @return (-1 on failure) or number of seconds of file age
2412  */
2413 expublic long ndrx_file_age(char *fname)
2414 {
2415     struct stat buf;
2416     struct timespec tm;
2417     struct timespec tm2;
2418     long diff=EXFAIL;
2419     
2420         /* get the age of the file */
2421     if (EXSUCCEED!=stat(fname, &buf))
2422     {
2423         NDRX_LOG(log_error, "Failed to stat [%s]: %s", fname, strerror(errno));
2424         goto out;
2425     }
2426     
2427     clock_gettime(CLOCK_REALTIME, &tm);
2428 
2429 #ifdef EX_OS_DARWIN
2430     diff = ndrx_timespec_get_delta(&tm, &buf.st_ctimespec) / 1000;
2431 #elif EX_OS_AIX
2432     tm2.tv_sec = buf.st_ctime;
2433     tm2.tv_nsec = buf.st_ctime_n;
2434     diff = ndrx_timespec_get_delta(&tm, &tm2) / 1000;
2435 #else
2436     diff = ndrx_timespec_get_delta(&tm, &buf.st_ctim) / 1000;
2437 #endif
2438     
2439 out:
2440     return diff;
2441 }
2442 
2443 /**
2444  * Load the file in malloc'd buffer
2445  * @param fname
2446  * @param list non init list 
2447  * @return EXSUCCEED/EXFAIL
2448  */
2449 expublic char *ndrx_file_read(char *fname, size_t *bytes_loaded)
2450 {
2451     FILE *f = NULL;
2452     char *buf=NULL;
2453     size_t cur_len =0;
2454     size_t nrread=0;
2455     size_t allocd=0;
2456 #define LOAD_STEP   1024
2457     
2458     if (NULL==(f=NDRX_FOPEN(fname, "rb")))
2459     {
2460         _Nset_error_fmt(NENOENT, "Failed to open [%s] file: %s", 
2461                 fname, strerror(errno));
2462         goto out;
2463     }
2464     
2465     do
2466     {
2467         cur_len+=nrread;
2468         if (allocd - cur_len < LOAD_STEP)
2469         {
2470             allocd+=LOAD_STEP;
2471             buf = NDRX_REALLOC(buf, allocd);
2472             
2473             if (NULL==buf)
2474             {
2475                 _Nset_error_fmt(NENOENT, "Failed to malloc %d bytes", (int)allocd);
2476                 goto out;
2477             }
2478         }
2479     } while ((nrread = fread(&buf[cur_len], 1, LOAD_STEP, f)) >= 1);
2480         
2481     
2482     if (ferror(f)) 
2483     {
2484         _Nset_error_fmt(NESYSTEM, "Failed to read [%s] file: %s", fname, strerror(errno));
2485         
2486         NDRX_FREE(buf);
2487         buf=NULL;
2488         goto out;
2489     }
2490     
2491     *bytes_loaded=cur_len;
2492     
2493 out:
2494             
2495     if (NULL!=f)
2496     {
2497         NDRX_FCLOSE(f);
2498     }
2499 
2500     return buf;
2501 }
2502 
2503 /**
2504  * If confirmation is required for command, then check it.
2505  * @param message
2506  * @param argc
2507  * @param argv
2508  * @return TRUE/FALSE
2509  */
2510 expublic int ndrx_chk_confirm(char *message, short is_confirmed)
2511 {
2512     int ret=EXFALSE;
2513     char buffer[128];
2514     int ans_ok = EXFALSE;
2515     
2516     if (!is_confirmed)
2517     {
2518         if (isatty(0))
2519         {
2520             do
2521             {
2522                 /* Ask Are you sure */
2523                 fprintf(stderr, "%s [Y/N]: ", message);
2524                 while (NULL==fgets(buffer, sizeof(buffer), stdin))
2525                 {
2526                     /* do nothing */
2527                 }
2528 
2529                 if (toupper(buffer[0])=='Y' && '\n'==buffer[1] && EXEOS==buffer[2])
2530                 {
2531                     ret=EXTRUE;
2532                     ans_ok=EXTRUE;
2533                 }
2534                 else if (toupper(buffer[0])=='N' && '\n'==buffer[1] && EXEOS==buffer[2])
2535                 {
2536                     ret=EXFALSE;
2537                     ans_ok=EXTRUE;
2538                 }
2539 
2540             } while (!ans_ok);
2541         }
2542         else
2543         {
2544             NDRX_LOG(log_warn, "Not tty, assuming no for: %s", message);
2545         }
2546     }
2547     else
2548     {
2549         ret=EXTRUE;
2550     }
2551     
2552     return ret;
2553 }
2554 
2555     
2556 /**
2557  * C format escape in dest buffer, ensure that in case of full buffer, trailing
2558  * percent is stripped.
2559  * @param dst where to unload
2560  * @param dstsz dest size
2561  * @param src source to escape
2562  * @return dest string
2563  */
2564 expublic char *ndrx_str_fmtesc(char *dst, size_t dstsz, char *src)
2565 {
2566     int i, j=0, len = strlen(src);
2567     /* include eos... */
2568     for (i=0; i<=len; i++)
2569     {
2570         if (src[i]!='%' && j<dstsz-1)
2571         {
2572             dst[j]=src[i];
2573             j++;
2574         }
2575         else if (src[i]=='%' && j<dstsz-2)
2576         {
2577             dst[j]='%';
2578             j++;
2579             dst[j]='%';
2580             j++;
2581         }
2582         else
2583         {
2584             /* dest buffer exceeded */
2585             dst[j]=EXEOS;
2586             break;
2587         }
2588     }
2589     
2590     return dst;
2591 }
2592 
2593 /**
2594  * Thread safe pseudo random function, per standard library TLS context
2595  * @return random value
2596  */
2597 expublic int ndrx_rand(void)
2598 {
2599     NSTD_TLS_ENTRY;
2600     
2601     if (!G_nstd_tls->rand_init)
2602     {
2603         ndrx_rand_seedset(&G_nstd_tls->rand_seed);
2604         G_nstd_tls->rand_init=EXTRUE;
2605     }
2606     
2607     return rand_r(&G_nstd_tls->rand_seed);
2608 }
2609 
2610 /**
2611  * Get the real-time reading (best guess of real time)
2612  */
2613 expublic int ndrx_realtime_get(struct timespec *tp)
2614 {
2615     int ret = EXSUCCEED;
2616 #if 0
2617     clockid_t clk_id=CLOCK_REALTIME;
2618 
2619 #ifdef EX_OS_LINUX
2620     clk_id=CLOCK_BOOTTIME;
2621 #endif
2622 
2623     if (EXSUCCEED!=clock_gettime(clk_id, tp))
2624 #endif
2625     if (EXSUCCEED!=clock_gettime(CLOCK_MONOTONIC, tp))
2626     {
2627         ret = EXFAIL;
2628     }
2629 
2630     return ret;
2631 }
2632 
2633 /**
2634  * Non modifying basename() version
2635  * @param path path to get basename from (filename)
2636  * @return extract filename
2637  */
2638 expublic char * ndrx_basename(char *path)
2639 {
2640     char *p = strrchr(path, '/');
2641     
2642     if (NULL!=p)
2643     {
2644         return p+1;
2645     }
2646     else
2647     {
2648         return path;
2649     }
2650 }
2651 
2652 
2653 /**
2654  * Copy string to volatile char array.
2655  * @param dest destination volatile array
2656  * @param src source buffer
2657  * @param dest_size destination buffer size
2658  */
2659 expublic void ndrx_volatile_strcpy(volatile char *dest, const volatile char *src, size_t dest_size)
2660 {
2661     size_t i;
2662 
2663     for (i = 0; i < dest_size - 1 && src[i] != '\0'; ++i)
2664     {
2665         dest[i] = src[i];
2666     }
2667     dest[i] = '\0';
2668 }
2669 
2670 /**
2671  * Copy volatile memory
2672  * @param dest destination buffer
2673  * @param src source buffer
2674  * @param n number of bytes to copy
2675  */
2676 expublic void ndrx_volatile_memcy(volatile char *dest, const volatile char *src, size_t n)
2677 {
2678     size_t i;
2679 
2680     for (i=0; i<n; i++)
2681     {
2682         dest[i] = src[i];
2683     }
2684 }
2685 
2686 
2687 /**
2688  * Advisory lock, entire file (write exclusive)
2689  * @param fd file descriptor to lock
2690  * @param do_wait shall process wait for the lock or return NEBUSY
2691  * @return EXSUCCEED/EXFAIL(nerror set)
2692  */
2693 expublic int ndrx_file_lock(int fd, int do_wait)
2694 {
2695     int ret=EXSUCCEED;
2696     struct flock fl;
2697     int cmd=F_SETLK;
2698     API_ENTRY;
2699 
2700     if (do_wait)
2701     {
2702         cmd=F_SETLKW;
2703     }
2704 
2705     fl.l_type = F_WRLCK;
2706     fl.l_whence = SEEK_SET;
2707     fl.l_start = 0;
2708     fl.l_len = 0; /* Lock the entire file */
2709 
2710     if (fcntl(fd, cmd, &fl) == -1)
2711     {
2712         int err=errno;
2713 
2714         NDRX_LOG(log_error, "Error acquiring write lock (cmd=%d): %s",
2715             cmd, strerror(err));
2716 
2717         if (EACCES==err || EAGAIN==err)
2718         {
2719             _Nset_error_fmt(NEBUSY, "failed to lock fd=%d, cmd=%d: %s", fd, cmd, strerror(err));
2720         }
2721         else
2722         {
2723             _Nset_error_fmt(NEUNIX, "failed to lock fd=%d, cmd=%d: %s", fd, cmd, strerror(err));
2724         }
2725         
2726         EXFAIL_OUT(ret);
2727     }
2728 
2729     NDRX_LOG(log_info, "fd %d locked for writing", fd);
2730 
2731 out:
2732     return ret;
2733 }
2734 
2735 /**
2736  * Unlock the previously locked file (with full contents lock)
2737  * @param fd file descriptor
2738  * @return EXSUCCEED/EXFAIL (nerror set)
2739  */
2740 expublic int ndrx_file_unlock(int fd)
2741 {
2742     int ret = EXSUCCEED;
2743     struct flock fl;
2744     API_ENTRY;
2745 
2746     fl.l_type = F_UNLCK;
2747     fl.l_whence = SEEK_SET;
2748     fl.l_start = 0;
2749     fl.l_len = 0; /* Lock the entire file */
2750 
2751     if (EXFAIL==fcntl(fd, F_SETLK, &fl))
2752     {
2753         int err=errno;
2754         NDRX_LOG(log_error, "Error unlocking fd %d: %s",
2755             fd, strerror(err));
2756         _Nset_error_fmt(NEUNIX, "failed to unlock fd %d: %s", fd, strerror(err));
2757         EXFAIL_OUT(ret);
2758     }
2759 out:
2760     return ret;
2761 }
2762 
2763 /* vim: set ts=4 sw=4 et smartindent: */
2764