2328824e0b778a68f0922a565b5253ac30742576
[sip-router] / ut.h
1 /*
2  *$Id$
3  *
4  * - various general purpose functions
5  *
6  * Copyright (C) 2001-2003 FhG Fokus
7  *
8  * This file is part of ser, a free SIP server.
9  *
10  * ser is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version
14  *
15  * For a license to use the ser software under conditions
16  * other than those described here, or to purchase support for this
17  * software, please contact iptel.org by e-mail at the following addresses:
18  *    info@iptel.org
19  *
20  * ser is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License 
26  * along with this program; if not, write to the Free Software 
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28  *
29  * History
30  * ------
31  * 2003-01-18 un_escape function introduced for convenience of code needing
32  *            the complex&slow feature of unescaping
33  * 2003-01-28 scratchpad removed (jiri)
34  * 2003-01-29 pathmax added (jiri)
35  * 2003-02-13 strlower added (janakj)
36  * 2003-02-28 scratchpad compatibility abandoned (jiri)
37  * 2003-03-30 str2int and str2float added (janakj)
38  * 2003-04-26 ZSW (jiri)
39  * 2004-03-08 updated int2str (64 bits, INT2STR_MAX_LEN used) (andrei)
40  * 2005-11-29 reverse_hex2int/int2reverse_hex switched to unsigned int (andrei)
41  * 2005-12-09 added msgid_var (andrei)
42  * 2007-05-14 added get_sys_ver() (andrei)
43  * 2007-06-05 added MAX_UVAR_VALUE(), MAX_int(a,b) MIN_int(a,b) (andrei)
44  * 2008-05-21 added ushort2sbuf(), ushort2str() (andrei)
45  */
46
47
48 #ifndef ut_h
49 #define ut_h
50
51 #include "comp_defs.h"
52
53 #include <sys/types.h>
54 #include <sys/select.h>
55 #include <sys/time.h>
56 #include <limits.h>
57 #include <time.h>
58 #include <unistd.h>
59 #include <ctype.h>
60 #include <string.h>
61 #include <strings.h>
62
63 #include "compiler_opt.h"
64 #include "config.h"
65 #include "dprint.h"
66 #include "str.h"
67 #include "mem/mem.h"
68 #include "mem/shm_mem.h"
69
70
71
72 /* zero-string wrapper */
73 #define ZSW(_c) ((_c)?(_c):"")
74
75 /* returns string beginning and length without insignificant chars */
76 #define trim_len( _len, _begin, _mystr ) \
77         do{     static char _c; \
78                 (_len)=(_mystr).len; \
79                 while ((_len) && ((_c=(_mystr).s[(_len)-1])==0 || _c=='\r' || \
80                                         _c=='\n' || _c==' ' || _c=='\t' )) \
81                         (_len)--; \
82                 (_begin)=(_mystr).s; \
83                 while ((_len) && ((_c=*(_begin))==' ' || _c=='\t')) { \
84                         (_len)--;\
85                         (_begin)++; \
86                 } \
87         }while(0)
88
89 #define trim_r( _mystr ) \
90         do{     static char _c; \
91                 while( ((_mystr).len) && ( ((_c=(_mystr).s[(_mystr).len-1]))==0 ||\
92                                                                         _c=='\r' || _c=='\n' ) \
93                                 ) \
94                         (_mystr).len--; \
95         }while(0)
96
97
98 #define  translate_pointer( _new_buf , _org_buf , _p) \
99         ( (_p)?(_new_buf + (_p-_org_buf)):(0) )
100
101 #define via_len(_via) \
102         ((_via)->bsize-((_via)->name.s-\
103                 ((_via)->hdr.s+(_via)->hdr.len)))
104
105
106
107 /* rounds to sizeof(type), but type must have a 2^k size (e.g. short, int,
108  * long, void*) */
109 #define ROUND2TYPE(s, type) \
110         (((s)+(sizeof(type)-1))&(~(sizeof(type)-1)))
111
112
113 /* rounds to sizeof(char*) - the first 4 byte multiple on 32 bit archs
114  * and the first 8 byte multiple on 64 bit archs */
115 #define ROUND_POINTER(s) ROUND2TYPE(s, char*)
116
117 /* rounds to sizeof(long) - the first 4 byte multiple on 32 bit archs
118  * and the first 8 byte multiple on 64 bit archs  (equiv. to ROUND_POINTER)*/
119 #define ROUND_LONG(s)  ROUND2TYPE(s, long)
120
121 /* rounds to sizeof(int) - the first t byte multiple on 32 and 64  bit archs */
122 #define ROUND_INT(s) ROUND2TYPE(s, int)
123
124 /* rounds to sizeof(short) - the first 2 byte multiple */
125 #define ROUND_SHORT(s) ROUND2TYPE(s, short)
126
127
128 /* params: v - either a variable name, structure member or a type
129  * returns an unsigned long containing the maximum possible value that will
130  * fit in v, if v is unsigned or converted to an unsigned version
131  * example: MAX_UVAR_VALUE(unsigned short); MAX_UVAR_VALUE(i);
132  *  MAX_UVAR_VALUE(((struct foo*)0)->bar) */
133 #define MAX_UVAR_VALUE(v) \
134         (((unsigned long)(-1))>>((sizeof(unsigned long)-sizeof(v))*8UL))
135
136
137 #define MIN_int(a, b) (((a)<(b))?(a):(b))
138 #define MAX_int(a, b) (((a)>(b))?(a):(b))
139
140 #define MIN_unsigned(a, b) (unsigned)(((unsigned)(a)<(unsigned)(b))?(a):(b))
141 #define MAX_unsigned(a, b) (unsigned)(((unsigned)(a)>(unsigned)(b))?(a):(b))
142
143 #if 0
144 #define MIN_int(a, b) ((b)+(((a)-(b))& -((a)<(b))))
145 #define MAX_int(a, b) ((a)-(((a)-(b))& -((b)>(a))))
146
147 /* depend on signed right shift result which depends on the compiler */
148 #define MIN_int(a, b) ((b)+(((a)-(b))&(((a)-(b))>>(sizeof(int)*8-1))))
149 #define MAX_int(a, b) ((a)-(((a)-(b))&(((a)-(b))>>(sizeof(int)*8-1))))
150 #endif
151
152
153 #define append_str(_dest,_src,_len)                             \
154         do{                                                                                     \
155                 memcpy( (_dest) , (_src) , (_len) );    \
156                 (_dest) += (_len) ;                                             \
157         }while(0);                                                                      \
158
159         
160 /*! append _c char to _dest string */
161 #define append_chr(_dest,_c) \
162         *((_dest)++) = _c;
163
164
165 /* links a value to a msgid */
166 struct msgid_var{
167         union{
168                 char char_val;
169                 int int_val;
170                 long long_val;
171         }u;
172         unsigned int msgid;
173 };
174
175 /* return the value or 0 if the msg_id doesn't match */
176 #define get_msgid_val(var, id, type)\
177         ((type)((type)((var).msgid!=(id))-1)&((var).u.type##_val))
178
179 #define set_msgid_val(var, id, type, value)\
180         do{\
181                 (var).msgid=(id); \
182                 (var).u.type##_val=(value); \
183         }while(0)
184
185 /* char to hex conversion table */
186 static char fourbits2char[16] = { '0', '1', '2', '3', '4', '5',
187         '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
188
189
190 /* converts a str to an u. short, returns the u. short and sets *err on
191  * error and if err!=null
192   */
193 static inline unsigned short str2s(const char* s, unsigned int len,
194                                                                         int *err)
195 {
196         unsigned short ret;
197         int i;
198         unsigned char *limit;
199         unsigned char *init;
200         unsigned char* str;
201
202         /*init*/
203         str=(unsigned char*)s;
204         ret=i=0;
205         limit=str+len;
206         init=str;
207
208         for(;str<limit ;str++){
209                 if ( (*str <= '9' ) && (*str >= '0') ){
210                                 ret=ret*10+*str-'0';
211                                 i++;
212                                 if (i>5) goto error_digits;
213                 }else{
214                                 /* error unknown char */
215                                 goto error_char;
216                 }
217         }
218         if (err) *err=0;
219         return ret;
220
221 error_digits:
222         /*DBG("str2s: ERROR: too many letters in [%.*s]\n", (int)len, init); */
223         if (err) *err=1;
224         return 0;
225 error_char:
226         /*DBG("str2s: ERROR: unexpected char %c in %.*s\n", *str, (int)len, init);
227          * */
228         if (err) *err=1;
229         return 0;
230 }
231
232
233
234 static inline int btostr( char *p,  unsigned char val)
235 {
236         unsigned int a,b,i =0;
237
238         if ( (a=val/100)!=0 )
239                 *(p+(i++)) = a+'0';         /*first digit*/
240         if ( (b=val%100/10)!=0 || a)
241                 *(p+(i++)) = b+'0';        /*second digit*/
242         *(p+(i++)) = '0'+val%10;              /*third digit*/
243
244         return i;
245 }
246
247
248 #define INT2STR_MAX_LEN  (19+1+1) /* 2^64~= 16*10^18 => 19+1 digits + \0 */
249
250 /* 
251  * returns a pointer to a static buffer containing l in asciiz (with base "base") & sets len 
252  * left padded with 0 to "size"
253  */
254 static inline char* int2str_base_0pad(unsigned int l, int* len, int base, 
255                                                                                         int size)
256 {
257         static char r[INT2STR_MAX_LEN];
258         int i, j;
259
260         if (base < 2) {
261                 BUG("base underflow\n");
262                 return NULL;
263         }
264         if (base > 36) {
265                 BUG("base overflow\n");
266                 return NULL;
267         }
268         i=INT2STR_MAX_LEN-2;
269         j=i-size;
270         r[INT2STR_MAX_LEN-1]=0; /* null terminate */
271         do{
272                 r[i]=l%base;
273                 if (r[i]<10)
274                         r[i]+='0';
275                 else
276                         r[i]+='a'-10;
277                 i--;
278                 l/=base;
279         }while((l || i>j) && (i>=0));
280         if (l && (i<0)){
281                 BUG("result buffer overflow\n");
282         }
283         if (len) *len=(INT2STR_MAX_LEN-2)-i;
284         return &r[i+1];
285 }
286
287 /* returns a pointer to a static buffer containing l in asciiz (with base "base") & sets len */
288 static inline char* int2str_base(unsigned int l, int* len, int base)
289 {
290         return int2str_base_0pad(l, len, base, 0);
291 }
292
293
294
295 /* print int to asciiz in a string buffer
296  * - be sure result buffer is at least INT2STR_MAX_LEN in size */
297 static inline char* int2strbuf(unsigned int l, char *r, int r_size, int* len)
298 {
299         int i;
300
301         if(unlikely(r_size<INT2STR_MAX_LEN)) {
302                 if (len)
303                         *len = 0;
304                 return 0; /* => if someone misuses it => crash (feature no. 1) */
305         }
306         i=INT2STR_MAX_LEN-2;
307         r[INT2STR_MAX_LEN-1]=0; /* null terminate */
308         do{
309                 r[i]=l%10+'0';
310                 i--;
311                 l/=10;
312         }while(l && (i>=0));
313         if (l && (i<0)){
314                 LOG(L_CRIT, "BUG: int2str: overflow\n");
315         }
316         if (len) *len=(INT2STR_MAX_LEN-2)-i;
317         return &r[i+1];
318 }
319
320 extern char ut_buf_int2str[INT2STR_MAX_LEN];
321 /* returns a pointer to a static buffer containing l in asciiz & sets len */
322 static inline char* int2str(unsigned long l, int* len)
323 {
324         return int2strbuf(l, ut_buf_int2str, INT2STR_MAX_LEN, len);
325 }
326
327 /* Signed INTeger-TO-STRing: convers a long to a string
328  * returns a pointer to a static buffer containing l in asciiz & sets len */
329 static inline char* sint2str(long l, int* len)
330 {
331         int sign;
332         char *p;
333
334         sign = 0;
335         if(l<0) {
336                 sign = 1;
337                 l = -l;
338         }
339         p = int2str((unsigned long)l, len);
340         if(sign && *len<(INT2STR_MAX_LEN-1)) {
341                 *(--p) = '-';
342                 if (len) (*len)++;
343         }
344         return p;
345 }
346
347
348
349
350 #define USHORT2SBUF_MAX_LEN  5 /* 65535*/
351 /* converts an unsigned short (16 bits) to asciiz
352  * returns bytes written or 0 on error
353  * the passed len must be at least USHORT2SBUF_MAX chars or error
354  * would be returned.
355  * (optimized for port conversion (4 or 5 digits most of the time)*/
356 static inline int ushort2sbuf(unsigned short u, char* buf, int len)
357 {
358         int offs;
359         unsigned char a, b, c, d;
360         
361         if (unlikely(len<USHORT2SBUF_MAX_LEN))
362                 return 0;
363         offs=0;
364         a=u/10000; u%=10000;
365         buf[offs]=a+'0'; offs+=(a!=0);
366         b=u/1000;  u%=1000;
367         buf[offs]=b+'0'; offs+=((offs|b)!=0);
368         c=u/100;   u%=100;
369         buf[offs]=c+'0'; offs+=((offs|c)!=0);
370         d=u/10;    u%=10;
371         buf[offs]=d+'0'; offs+=((offs|d)!=0);
372         buf[offs]=(unsigned char)u+'0';
373         return offs+1;
374 }
375
376
377
378 #define USHORT2STR_MAX_LEN  (USHORT2SBUF_MAX_LEN+1) /* 65535\0*/
379 /* converts an unsigned short (16 bits) to asciiz
380  * (optimized for port conversiob (4 or 5 digits most of the time)*/
381 static inline char* ushort2str(unsigned short u)
382 {
383         static char buf[USHORT2STR_MAX_LEN];
384         int len;
385
386         len=ushort2sbuf(u, buf, sizeof(buf)-1);
387         buf[len]=0;
388         return buf;
389 }
390
391
392
393 /* faster memchr version */
394 static inline char* q_memchr(char* p, int c, unsigned int size)
395 {
396         char* end;
397
398         end=p+size;
399         for(;p<end;p++){
400                 if (*p==(unsigned char)c) return p;
401         }
402         return 0;
403 }
404         
405
406 /* returns -1 on error, 1! on success (consistent with int2reverse_hex) */
407 inline static int reverse_hex2int( char *c, int len, unsigned int* res)
408 {
409         char *pc;
410         char mychar;
411
412         *res=0;
413         for (pc=c+len-1; len>0; pc--, len--) {
414                 *res <<= 4 ;
415                 mychar=*pc;
416                 if ( mychar >='0' && mychar <='9') *res+=mychar -'0';
417                 else if (mychar >='a' && mychar <='f') *res+=mychar -'a'+10;
418                 else if (mychar  >='A' && mychar <='F') *res+=mychar -'A'+10;
419                 else return -1;
420         }
421         return 1;
422 }
423
424 inline static int int2reverse_hex( char **c, int *size, unsigned int nr )
425 {
426         unsigned short digit;
427
428         if (*size && nr==0) {
429                 **c = '0';
430                 (*c)++;
431                 (*size)--;
432                 return 1;
433         }
434
435         while (*size && nr ) {
436                 digit = nr & 0xf ;
437                 **c= digit >= 10 ? digit + 'a' - 10 : digit + '0';
438                 nr >>= 4;
439                 (*c)++;
440                 (*size)--;
441         }
442         return nr ? -1 /* number not processed; too little space */ : 1;
443 }
444
445 /* double output length assumed ; does NOT zero-terminate */
446 inline static int string2hex( 
447         /* input */ unsigned char *str, int len,
448         /* output */ char *hex )
449 {
450         int orig_len;
451
452         if (len==0) {
453                 *hex='0';
454                 return 1;
455         }
456
457         orig_len=len;
458         while ( len ) {
459
460                 *hex=fourbits2char[(*str) >> 4];
461                 hex++;
462                 *hex=fourbits2char[(*str) & 0xf];
463                 hex++;
464                 len--;
465                 str++;
466
467         }
468         return orig_len-len;
469 }
470
471 /* portable sleep in microseconds (no interrupt handling now) */
472
473 inline static void sleep_us( unsigned int nusecs )
474 {
475         struct timeval tval;
476         tval.tv_sec =nusecs/1000000;
477         tval.tv_usec=nusecs%1000000;
478         select(0, NULL, NULL, NULL, &tval );
479 }
480
481
482 /* portable determination of max_path */
483 inline static int pathmax()
484 {
485 #ifdef PATH_MAX
486         static int pathmax=PATH_MAX;
487 #else
488         static int pathmax=0;
489 #endif
490         if (pathmax==0) { /* init */
491                 pathmax=pathconf("/", _PC_PATH_MAX);
492                 pathmax=(pathmax<=0)?PATH_MAX_GUESS:pathmax+1;
493         }
494         return pathmax;
495 }
496
497 inline static int hex2int(char hex_digit)
498 {
499         if (hex_digit>='0' && hex_digit<='9')
500                 return hex_digit-'0';
501         if (hex_digit>='a' && hex_digit<='f')
502                 return hex_digit-'a'+10;
503         if (hex_digit>='A' && hex_digit<='F')
504                 return hex_digit-'A'+10;
505         /* no valid hex digit ... */
506         LOG(L_ERR, "ERROR: hex2int: '%c' is no hex char\n", hex_digit );
507         return -1;
508 }
509
510 /* Un-escape URI user  -- it takes a pointer to original user
511    str, as well as the new, unescaped one, which MUST have
512    an allocated buffer linked to the 'str' structure ;
513    (the buffer can be allocated with the same length as
514    the original string -- the output string is always
515    shorter (if escaped characters occur) or same-long
516    as the original one).
517
518    only printable characters are permitted
519
520         <0 is returned on an unescaping error, length of the
521         unescaped string otherwise
522 */
523 inline static int un_escape(str *user, str *new_user ) 
524 {
525         int i, j, value;
526         int hi, lo;
527
528         if( new_user==0 || new_user->s==0) {
529                 LOG(L_CRIT, "BUG: un_escape: called with invalid param\n");
530                 return -1;
531         }
532
533         new_user->len = 0;
534         j = 0;
535
536         for (i = 0; i < user->len; i++) {
537                 if (user->s[i] == '%') {
538                         if (i + 2 >= user->len) {
539                                 LOG(L_ERR, "ERROR: un_escape: escape sequence too short in"
540                                         " '%.*s' @ %d\n",
541                                         user->len, user->s, i );
542                                 goto error;
543                         }
544                         hi=hex2int(user->s[i + 1]);
545                         if (hi<0) {
546                                 LOG(L_ERR, "ERROR: un_escape: non-hex high digit in an escape sequence in"
547                                         " '%.*s' @ %d\n",
548                                         user->len, user->s, i+1 );
549                                 goto error;
550                         }
551                         lo=hex2int(user->s[i + 2]);
552                         if (lo<0) {
553                                 LOG(L_ERR, "ERROR: non-hex low digit in an escape sequence in "
554                                         "'%.*s' @ %d\n",
555                                         user->len, user->s, i+2 );
556                                 goto error;
557                         }
558                         value=(hi<<4)+lo;
559                         if (value < 32 || value > 126) {
560                                 LOG(L_ERR, "ERROR: non-ASCII escaped character in '%.*s' @ %d\n",
561                                         user->len, user->s, i );
562                                 goto error;
563                         }
564                         new_user->s[j] = value;
565                         i+=2; /* consume the two hex digits, for cycle will move to the next char */
566                 } else {
567                         new_user->s[j] = user->s[i];
568                 }
569         j++; /* good -- we translated another character */
570         }
571         new_user->len = j;
572         return j;
573
574 error:
575         new_user->len = j;
576         return -1;
577
578
579
580 /*
581  * Convert a string to lower case
582  */
583 static inline void strlower(str* _s)
584 {
585         int i;
586
587         for(i = 0; i < _s->len; i++) {
588                 _s->s[i] = tolower(_s->s[i]);
589         }
590 }
591
592
593 /*
594  * Convert a str into integer
595  */
596 static inline int str2int(str* _s, unsigned int* _r)
597 {
598         int i;
599         
600         *_r = 0;
601         for(i = 0; i < _s->len; i++) {
602                 if ((_s->s[i] >= '0') && (_s->s[i] <= '9')) {
603                         *_r *= 10;
604                         *_r += _s->s[i] - '0';
605                 } else {
606                         return -1;
607                 }
608         }
609         
610         return 0;
611 }
612
613 /*
614  * Convert an str to signed integer
615  */
616 static inline int str2sint(str* _s, int* _r)
617 {
618         int i;
619         int sign;
620
621         if (_s->len == 0) return -1;
622
623         *_r = 0;
624         sign = 1;
625         i = 0;
626         if (_s->s[0] == '+') {
627                 i++;
628         } else if (_s->s[0] == '-') {
629                 sign = -1;
630                 i++;
631         }
632         for(; i < _s->len; i++) {
633                 if ((_s->s[i] >= '0') && (_s->s[i] <= '9')) {
634                         *_r *= 10;
635                         *_r += _s->s[i] - '0';
636                 } else {
637                         return -1;
638                 }
639         }
640         *_r *= sign;
641
642         return 0;
643 }
644
645
646
647 #ifdef SHM_MEM
648 /**
649  * \brief Make a copy of a str structure using shm_malloc
650  * \param dst destination
651  * \param src source
652  * \return 0 on success, -1 on failure
653  */
654 static inline int shm_str_dup(str* dst, const str* src)
655 {
656         dst->s = shm_malloc(src->len);
657         if (!dst->s) {
658                 SHM_MEM_ERROR;
659                 return -1;
660         }
661
662         memcpy(dst->s, src->s, src->len);
663         dst->len = src->len;
664         return 0;
665 }
666 #endif /* SHM_MEM */
667
668
669
670 /**
671  * \brief Make a copy of a str structure using pkg_malloc
672  * \param dst destination
673  * \param src source
674  * \return 0 on success, -1 on failure
675  */
676 static inline int pkg_str_dup(str* dst, const str* src)
677 {
678         dst->s = pkg_malloc(src->len);
679         if (dst->s==NULL)
680         {
681                 PKG_MEM_ERROR;
682                 return -1;
683         }
684
685         memcpy(dst->s, src->s, src->len);
686         dst->len = src->len;
687         return 0;
688 }
689
690 /**
691  * \brief Compare two str's case sensitive
692  * \param str1 first str
693  * \param str2 second str
694  * \return 0 if both are equal, positive if str1 is greater, negative if str2 is greater, -2 on errors
695  */
696 static inline int str_strcmp(const str *str1, const str *str2)
697 {
698         if(str1==NULL || str2==NULL || str1->s ==NULL || str2->s==NULL || str1->len<0 || str2->len<0)
699         {
700                 LM_ERR("bad parameters\n");
701                 return -2;
702         }
703
704         if (str1->len < str2->len)
705                 return -1;
706         else if (str1->len > str2->len)
707                 return 1;
708         else
709                 return strncmp(str1->s, str2->s, str1->len);
710 }
711
712 /**
713  * \brief Compare two str's case insensitive
714  * \param str1 first str
715  * \param str2 second str
716  * \return 0 if both are equal, positive if str1 is greater, negative if str2 is greater, -2 on errors
717  */
718 static inline int str_strcasecmp(const str *str1, const str *str2)
719 {
720         if(str1==NULL || str2==NULL || str1->s ==NULL || str2->s==NULL || str1->len<0 || str2->len<0)
721         {
722                 LM_ERR("bad parameters\n");
723                 return -2;
724         }
725         if (str1->len < str2->len)
726                 return -1;
727         else if (str1->len > str2->len)
728                 return 1;
729         else
730                 return strncasecmp(str1->s, str2->s, str1->len);
731 }
732
733 /* converts a username into uid:gid,
734  * returns -1 on error & 0 on success */
735 int user2uid(int* uid, int* gid, char* user);
736
737 /* converts a group name into a gid
738  * returns -1 on error, 0 on success */
739 int group2gid(int* gid, char* group);
740
741 /*
742  * Replacement of timegm (does not exists on all platforms
743  * Taken from 
744  * http://lists.samba.org/archive/samba-technical/2002-November/025737.html
745  */
746 time_t _timegm(struct tm* t);
747
748 /* Convert time_t value that is relative to local timezone to UTC */
749 time_t local2utc(time_t in);
750
751 /* Convert time_t value in UTC to to value relative to local time zone */
752 time_t utc2local(time_t in);
753
754 /*
755  * Return str as zero terminated string allocated
756  * using pkg_malloc
757  */
758 char* as_asciiz(str* s);
759
760
761 /* return system version (major.minor.minor2) as
762  *  (major<<16)|(minor)<<8|(minor2)
763  * (if some of them are missing, they are set to 0)
764  * if the parameters are not null they are set to the coresp. part */
765 unsigned int get_sys_version(int* major, int* minor, int* minor2);
766
767 /** Converts relative pathnames to absolute pathnames. This function returns
768  * the full pathname of a file in parameter. If the file pathname does not
769  * start with / then it will be converted into an absolute pathname. The
770  * function gets the absolute directory pathname from \c base and appends \c
771  * file to it. The first parameter can be NULL, in this case the function will
772  * use the location of the main SER configuration file as reference.
773  * @param base filename to be used as reference when \c file is relative. It
774  *             must be absolute. The location of the SER configuration file
775  *             will be used as reference if you set the value of this
776  *             parameter to NULL.
777  * @param file A pathname to be converted to absolute.
778  * @return A string containing absolute pathname, the string must be freed
779  * with free. NULL on error.
780  */
781 char* get_abs_pathname(str* base, str* file);
782
783 #endif