1 /* Copyright (C) 2000-2015 Lavtech.com corp. All rights reserved.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2 of the License, or
6    (at your option) any later version.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16 */
17 
18 #include "udm_config.h"
19 
20 #include <stdio.h>
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <time.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #ifdef HAVE_SYS_SOCKET_H
30 #include <sys/socket.h>
31 #endif
32 #include <errno.h>
33 
34 #ifdef HAVE_IO_H
35 #include <io.h>  /* for Win */
36 #endif
37 
38 #ifdef HAVE_DIRECT_H
39 #include <direct.h> /* for Win */
40 #endif
41 
42 #ifdef HAVE_SYS_TIME_H
43 #include <sys/time.h>
44 #endif
45 
46 #ifdef HAVE_SYS_TIMES_H
47 #include <sys/times.h>
48 #endif
49 
50 #ifdef HAVE_UNISTD_H
51 #include <unistd.h>
52 #endif
53 #include <signal.h>
54 
55 #include "udm_signals.h"
56 #include "udm_utils.h"
57 
58 
59 char udm_null_char= 0;
60 
61 static char udm_hex_digits[]= "0123456789ABCDEF";
62 
63 
64 size_t
UdmHexEncode(char * dst,const char * src,size_t len)65 UdmHexEncode(char *dst, const char *src, size_t len)
66 {
67   size_t i;
68   for (i=0; i < len; i++)
69   {
70     unsigned int ch= (unsigned int) (unsigned char) src[i];
71     *dst++= udm_hex_digits[(ch >> 4) & 0x0F];
72     *dst++= udm_hex_digits[ch & 0x0F];
73   }
74   *dst= '\0';
75   return len * 2;
76 }
77 
78 
79 static inline int
udm_isdigit(int ch)80 udm_isdigit(int ch)
81 {
82   return ch >= '0' && ch <= '9';
83 }
84 
85 
86 static inline int
udm_isupper(int ch)87 udm_isupper(int ch)
88 {
89   return ch >= 'A' && ch <= 'Z';
90 }
91 
92 
93 static inline int
udm_islower(int ch)94 udm_islower(int ch)
95 {
96   return ch >= 'a' && ch <= 'z';
97 }
98 
99 
100 static inline int
udm_isxdigit(int ch)101 udm_isxdigit(int ch)
102 {
103   return udm_isdigit(ch) || udm_isupper(ch) || udm_islower(ch);
104 }
105 
106 
107 static char
ch2x(int ch)108 ch2x(int ch)
109 {
110   if (udm_isdigit(ch))
111     return ch - '0';
112   else if (udm_isupper(ch))
113     return ch - 'A' + 10;
114   else if (udm_islower(ch))
115     return ch - 'a' + 10;
116   else
117     return -1;
118 }
119 
120 
121 
122 
123 
124 /*
125   Decode a HEX-encoded string.
126 
127   When a non-hex digit character is met,
128   we break and return the length of the well-formed hex prefix.
129   DecodeHexStr() needs this, as Oracle pads RAW values with spaces.
130 */
131 size_t
UdmHexDecode(char * dst,const char * src,size_t len)132 UdmHexDecode(char *dst, const char *src, size_t len)
133 {
134   char *dst0= dst;
135   for ( ; len > 1; len-= 2)
136   {
137     int hi, lo;
138     if ((hi= ch2x(*src++)) < 0 || (lo= ch2x(*src++)) < 0)
139       break; /* Bad character */
140     *dst++= hi << 4 | lo;
141   }
142   return dst - dst0;
143 }
144 
145 
146 double
udm_strntod(const char * s,size_t len)147 udm_strntod(const char *s, size_t len)
148 {
149   char tmp[64];
150   len= len >= sizeof(tmp) ? sizeof(tmp) - 1 : len;
151   memcpy(tmp, s, len);
152   tmp[len]= 0;
153   return atof(tmp);
154 }
155 
156 
157 int
udm_strntoi(const char * s,size_t len)158 udm_strntoi(const char *s, size_t len)
159 {
160   char tmp[64];
161   len= len >= sizeof(tmp) ? sizeof(tmp) - 1 : len;
162   memcpy(tmp, s, len);
163   tmp[len]= 0;
164   return atoi(tmp);
165 }
166 
167 
168 udm_bool_t
udm_strntobool(const char * str,size_t length)169 udm_strntobool(const char *str, size_t length)
170 {
171   return ((length == 3 && UDM_TEST(!strncasecmp(str, "yes", 3))) ||
172           (length > 0 && str[0] >= '1' && str[0] <='9') ||
173           udm_strntoi(str, length) == 1);
174 }
175 
176 
177 size_t
UdmUnescapeCGIQuery(char * d,const char * s)178 UdmUnescapeCGIQuery(char *d, const char *s)
179 {
180   char *dd;
181 
182   for (dd= d; *s; s++)
183   {
184     if(*s == '%' && ch2x(s[1]) >= 0 && ch2x(s[2]) >= 0)
185     {
186       *d++= ch2x(s[1]) * 16 + ch2x(s[2]);
187       s+= 2;
188     }
189     else if(*s=='+')
190     {
191       *d++=' ';
192     }
193     else
194     {
195       *d++=*s;
196     }
197   }
198   *d=0;
199   return d - dd;
200 }
201 
202 
203 /*
204   Similar to UdmURLDecode, but for not null-terminated strings.
205 */
206 size_t
UdmURLDecode(char * d,const char * s,size_t length)207 UdmURLDecode(char *d, const char *s, size_t length)
208 {
209   char *d0= d;
210   const char *srcend;
211   for (srcend= s + length; s < srcend; s++)
212   {
213     if (*s == '%' && s + 2 < srcend && ch2x(s[1]) >= 0 && ch2x(s[2]) >= 0)
214     {
215       *d++= ch2x(s[1]) * 16 + ch2x(s[2]);
216       s+= 2;
217     }
218     else
219     {
220       *d++= *s == '+' ? ' ' : *s;
221     }
222   }
223   *d= 0;
224   return d - d0;
225 }
226 
227 
228 UDM_API(size_t)
UdmURLEncode(char * d,const char * s,size_t length)229 UdmURLEncode(char *d, const char *s, size_t length)
230 {
231   char *dd= d;
232   const char *send= s + length;
233 
234   for ( ; s < send; s++, d++)
235   {
236     if ((*s & 0x80) || strchr("%&<>+[](){}/?#'\"\\;,",*s))
237     {
238       sprintf(d,"%%%X",(int) (unsigned char)*s);
239       d+=2;
240     }
241     else if (*s==' ')
242     {
243       *d='+';
244     }
245     else
246     {
247       *d=*s;
248     }
249   }
250   *d= 0;
251   return d - dd;
252 }
253 
254 
255 char *
UdmEscapeURI(char * d,const char * s)256 UdmEscapeURI(char *d,const char *s)
257 {
258   char *dd;
259   if ((d==NULL)||(s==NULL))return(0);
260   dd=d;
261   while (*s)
262   {
263     if (strchr(" ",*s))
264     {
265       sprintf(d,"%%%X",(int)*s);
266       d+=2;
267     }
268     else
269     {
270       *d=*s;
271     }
272     s++;
273     d++;
274   }
275   *d= 0;
276   return(dd);
277 }
278 
279 
280 /*
281   Remove parent level like /parent/../index.html from path recursively
282 */
UdmRemove2Dot(char * path)283 char * UdmRemove2Dot(char *path)
284 {
285   char *ptr;
286   char *tail;
287 
288   if (!(ptr=strstr(path,"../"))) return path;
289   if (ptr==path) return path; /* How could it be? */
290   tail=ptr+2;
291   ptr--;
292   *ptr=0;
293   if (!(ptr=strrchr(path,'/'))) *path=0; else *ptr=0;
294   path=strcat(path,tail);
295   return UdmRemove2Dot(path);
296 }
297 
298 
299 
UdmInit()300 UDM_API(udm_rc_t) UdmInit()
301 {
302   UdmInitTZ();
303   return 0;
304 }
305 
306 
307 #ifdef WIN32
UdmBuild(char * path,int omode)308 int UdmBuild(char *path, int omode)
309 {
310   struct stat sb;
311   int last, retval, ret_code;
312   char *p;
313 
314   p = path;
315   retval = 0;
316   if (p[0] == UDMSLASH)    /* Skip leading slashes. */
317     ++p;
318   for (last = 0; !last ; ++p) {
319     if (p[0] == '\0')
320       last = 1;
321     else
322     if (p[0] != UDMSLASH)
323       continue;
324     *p = '\0';
325     if (p[1] == '\0')
326       last = 1;
327 
328     if (path[strlen(path)-1]==':'){
329       char buf[5*1024];
330 
331       sprintf(buf,"%s",path);
332       strcat(buf, "\\");
333       ret_code=stat(buf, &sb);
334     }else{
335       ret_code=stat(path, &sb);
336     }
337 
338     if (ret_code) {
339       if (errno != ENOENT || mkdir(path) < 0 ){
340         /* warn("%s", path); */
341         retval = 1;
342         break;
343       }
344     }
345     else if ((sb.st_mode & S_IFMT) != S_IFDIR) {
346       if (last)
347         errno = EEXIST;
348       else
349         errno = ENOTDIR;
350       /* warn("%s", path); */
351       retval = 1;
352       break;
353     }
354     if (!last)
355       *p = UDMSLASH;
356   }
357   return (retval);
358 }
359 
360 #else
361 
UdmBuild(char * path,int omode)362 int UdmBuild(char *path, int omode)
363 {
364   struct stat sb;
365   mode_t numask, oumask;
366   int first, last, retval;
367   char *p;
368 
369   p = path;
370   oumask = 0;
371   retval = 0;
372   if (p[0] == UDMSLASH)    /* Skip leading slashes. */
373     ++p;
374   for (first = 1, last = 0; !last ; ++p) {
375     if (p[0] == '\0')
376       last = 1;
377     else if (p[0] != UDMSLASH)
378       continue;
379     *p = '\0';
380     if (p[1] == '\0')
381       last = 1;
382     if (first) {
383       /*
384        * POSIX 1003.2:
385        * For each dir operand that does not name an existing
386        * directory, effects equivalent to those cased by the
387        * following command shall occcur:
388        *
389        * mkdir -p -m $(umask -S),u+wx $(dirname dir) &&
390        *    mkdir [-m mode] dir
391        *
392        * We change the user's umask and then restore it,
393        * instead of doing chmod's.
394        */
395       oumask = umask(0);
396       numask = oumask & ~(S_IWUSR | S_IXUSR);
397       (void)umask(numask);
398       first = 0;
399     }
400     if (last)
401       (void)umask(oumask);
402     if (stat(path, &sb)) {
403       if (errno != ENOENT ||
404           mkdir(path, last ? omode :
405           S_IRWXU | S_IRWXG | S_IRWXO) < 0
406          ){
407         /* warn("%s", path); */
408         retval = 1;
409         break;
410       }
411     }
412     else if ((sb.st_mode & S_IFMT) != S_IFDIR) {
413       if (last)
414         errno = EEXIST;
415       else
416         errno = ENOTDIR;
417       /* warn("%s", path); */
418       retval = 1;
419       break;
420     }
421     if (!last)
422       *p = UDMSLASH;
423   }
424   if (!first && !last)
425     (void)umask(oumask);
426   return (retval);
427 }
428 
429 #endif
430 
431 
432 char *
UdmBuildParamStr(char * dst,size_t len,const char * src,char ** argv,size_t argc)433 UdmBuildParamStr(char * dst,size_t len,const char * src,
434                  char ** argv,size_t argc)
435 {
436   const char * s;
437   char * d;
438   size_t argn;
439   size_t curlen;
440 
441   *dst='\0';
442   s=src;
443   d=dst;
444   curlen=0;
445 
446   while (*s)
447   {
448     if (*s=='$')
449     {
450       argn=atoi(s+1);
451       if ((argn<=argc)&&(argn>0))
452       {
453         size_t arglen;
454         arglen=strlen(argv[argn-1]);
455         if (arglen+curlen+1<len)
456         {
457           strcpy(d,argv[argn-1]);
458           d+=strlen(d);
459           curlen+=arglen;
460         }else{
461           break;
462         }
463       }
464       s++;
465       while (*s>='0'&&*s<='9')
466         s++;
467     }else
468 #ifdef WIN32
469 #else
470     if (*s=='\\')
471     {
472       s++;
473       if (*s)
474       {
475         if (curlen+2<len)
476         {
477           *d=*s;
478           s++;
479           d++;
480           *d='\0';
481           curlen++;
482         }
483         else
484         {
485           break;
486         }
487       }
488     }
489     else
490 #endif
491     {
492       if (curlen+2<len)
493       {
494         *d=*s;
495         s++;
496         d++;
497         *d='\0';
498         curlen++;
499       }
500       else
501       {
502         break;
503       }
504     }
505   }
506   return dst;
507 }
508 
509 /*********** Environment variable routines *******/
510 
511 int
UdmSetEnv(const char * name,const char * value)512 UdmSetEnv(const char * name,const char * value)
513 {
514 #ifdef HAVE_SETENV
515   return(setenv(name,value,1));
516 #else
517 #ifdef HAVE_PUTENV
518   int res;
519   char * s;
520   s= (char*) UdmMalloc(strlen(name)+strlen(value)+3);
521   sprintf(s, "%s=%s", name, value);
522   res= putenv(s);
523   UDM_FREE(s);
524   return res;
525 #else
526   return 0;
527 #endif
528 #endif
529 
530 }
531 
532 
533 void
UdmUnsetEnv(const char * name)534 UdmUnsetEnv(const char * name)
535 {
536 #ifdef HAVE_UNSETENV
537   unsetenv(name);
538 #else
539   UdmSetEnv(name,"");
540 #endif
541 }
542 
543 
544 /******************* String routines ******************/
545 
546 char*
UdmStrRemoveChars(char * str,const char * sep)547 UdmStrRemoveChars(char * str, const char * sep)
548 {
549   char *s, *e;
550   int has_sep= 0;
551 
552   e= s= str;
553   while (*s)
554   {
555     if (strchr(sep,*s))
556     {
557       if (!has_sep)
558       {
559         e= s;
560         has_sep= 1;
561       }
562     }
563     else
564     {
565       if (has_sep)
566       {
567         memmove(e,s,strlen(s)+1);
568         s= e;
569         has_sep= 0;
570       }
571     }
572     s++;
573   }
574   /* End spaces */
575   if (has_sep)
576     *e= '\0';
577 
578   return str;
579 }
580 
581 
582 char*
UdmStrRemoveDoubleChars(char * str,const char * sep)583 UdmStrRemoveDoubleChars(char * str, const char * sep)
584 {
585   char * s, *e;
586   int has_sep=0;
587 
588   /* Initial spaces */
589   for(s=str;(*s)&&(strchr(sep,*s));s++);
590   if (s!=str)memmove(str,s,strlen(s)+1);
591   e=s=str;
592 
593   /* Middle spaces */
594   while (*s)
595   {
596     if (strchr(sep,*s))
597     {
598       if (!has_sep)
599       {
600         e=s;
601         has_sep=1;
602       }
603     }
604     else
605     {
606       if (has_sep)
607       {
608         *e=' ';
609         memmove(e+1,s,strlen(s)+1);
610         s=e+1;
611         has_sep=0;
612       }
613     }
614     s++;
615   }
616 
617   /* End spaces */
618   if (has_sep)*e='\0';
619 
620   return str;
621 }
622 
623 
624 size_t
UdmStrRemoveDoubleSpaces(char * ustr)625 UdmStrRemoveDoubleSpaces(char *ustr)
626 {
627   char *u, *e, addspace=0;
628 
629   for(u= e= ustr; *u ;)
630   {
631     switch(*u)
632     {
633       case ' ':
634       case '\t':
635       case '\r':
636       case '\n':
637       /*case 0xA0:*/ /* TODO34: Usually nbsp, but not in UTF-8 */
638         addspace=1;
639         u++;
640         break;
641 
642       default:
643         if (addspace)
644         {
645           if (e > ustr)
646           {
647             *e=' ';
648             e++;
649           }
650           addspace= 0;
651         }
652         *e= *u;
653         e++;
654         u++;
655         break;
656     }
657   }
658   *e= 0;
659   return e - ustr;
660 }
661 
662 
663 
664 
665 
666 size_t
UdmUniRemoveDoubleSpaces(int * ustr)667 UdmUniRemoveDoubleSpaces(int *ustr)
668 {
669   int *u, *e, addspace=0;
670 
671   for(u= e= ustr; *u ;)
672   {
673     switch(*u)
674     {
675       case ' ':
676       case '\t':
677       case '\r':
678       case '\n':
679       case 0xA0: /* nbsp */
680         addspace=1;
681         u++;
682         break;
683 
684       default:
685         if (addspace)
686         {
687           if (e > ustr)
688           {
689             *e=' ';
690             e++;
691           }
692           addspace= 0;
693         }
694         *e= *u;
695         e++;
696         u++;
697         break;
698     }
699   }
700   *e= 0;
701   return e - ustr;
702 }
703 
704 
705 void
UdmUniPrint(int * ustr)706 UdmUniPrint(int *ustr)
707 {
708   int * lt;
709   for(lt=ustr;*lt;lt++)
710   {
711     fprintf(stderr,"%04X ",*lt);
712   }
713   fprintf(stderr,"\n");
714 }
715 
716 
717 /**************** recv and send ***********/
718 
719 ssize_t
UdmRecvall(int s,void * buf,size_t len)720 UdmRecvall(int s, void *buf, size_t len)
721 {
722 #ifdef MSG_WAITALL
723   if (len == 0)
724     return 0;
725   return recv(s, buf, len, MSG_WAITALL);
726 #else
727   ssize_t received= 0, r= 0;
728   char *b= buf;
729   time_t start= time(NULL);
730   if (len == 0)
731      return received;
732   while ( ((size_t)received < len) && ((r = recv(s, b+received, len-received,0)) >= 0))
733   {
734     received+= r;
735     if (have_sigint || have_sigterm
736 #ifndef WIN32
737         || have_sigpipe
738 #endif
739         ) break;
740     if (time(NULL) - start > 300)
741       break;
742   }
743   return (r < 0) ? r : received;
744 #endif
745 }
746 
747 
748 /* To bust performance you may increase this value, but be sure, that kernel can handle it */
749 #define UDM_BLKLEN 8196
750 
751 ssize_t
UdmSend(int s,const void * msg,size_t len,int flags)752 UdmSend(int s, const void *msg, size_t len, int flags)
753 {
754   ssize_t o = 0;
755   size_t olen, slen;
756   const char *p= (const char*) msg;
757 
758   while (len)
759   {
760     slen = (len < UDM_BLKLEN) ? len : UDM_BLKLEN;
761     olen = send(s, p, slen, flags);
762     if (olen == (size_t)-1) return olen;
763     len -= olen;
764     p += olen;
765     o += olen;
766   }
767   return o;
768 }
769 
770 
771 /********** File lock routines *************** */
772 
773 #ifndef WIN32
774 static struct flock*
file_lock(struct flock * ret,int type,int whence)775 file_lock(struct flock *ret, int type, int whence)
776 {
777   ret->l_type= type ;
778   ret->l_start= 0 ;
779   ret->l_whence= whence ;
780   ret->l_len= 0 ;
781   ret->l_pid= getpid() ;
782   return ret;
783 }
784 #endif
785 
786 
787 void
UdmWriteLock(int fd)788 UdmWriteLock(int fd)
789 {  /* an exclusive lock on an entire file */
790 #ifndef WIN32
791   static struct flock ret ;
792   fcntl(fd, F_SETLKW, file_lock(&ret, F_WRLCK, SEEK_SET));
793 #else
794 /* Windows routine */
795   DWORD filelen_high;
796   DWORD filelen_low;
797   OVERLAPPED overlap_str;
798   int lock_res;
799 
800   overlap_str.Offset= 0;
801   overlap_str.OffsetHigh= 0;
802   overlap_str.hEvent= 0;
803 
804   filelen_low= GetFileSize((HANDLE)fd, &filelen_high);
805   lock_res= LockFileEx((HANDLE)fd, LOCKFILE_EXCLUSIVE_LOCK, 0, filelen_low, filelen_high, &overlap_str);
806   UDM_ASSERT(lock_res);
807 #endif
808 }
809 
810 
811 void
UdmUnLock(int fd)812 UdmUnLock(int fd) /* ulock an entire file */
813 {
814 #ifndef WIN32
815   static struct flock ret ;
816   fcntl(fd, F_SETLKW, file_lock(&ret, F_UNLCK, SEEK_SET));
817 #else
818   /* Windows routine */
819   DWORD filelen_high;
820   DWORD filelen_low;
821   int lock_res;
822 
823   filelen_low= GetFileSize((HANDLE)fd, &filelen_high);
824   lock_res= UnlockFile((HANDLE)fd, 0, 0, filelen_low, filelen_high);
825   UDM_ASSERT(lock_res);
826 #endif
827 
828 }
829 
830 void
UdmReadLock(int fd)831 UdmReadLock(int fd)
832 {   /* a shared lock on an entire file */
833 #ifndef WIN32
834   static struct flock ret ;
835   fcntl(fd, F_SETLKW, file_lock(&ret, F_RDLCK, SEEK_SET));
836 #else
837   /* Windows routine */
838   DWORD filelen_high;
839   DWORD filelen_low;
840   OVERLAPPED overlap_str;
841   int lock_res;
842 
843   overlap_str.Offset= 0;
844   overlap_str.OffsetHigh= 0;
845   overlap_str.hEvent= 0;
846 
847   filelen_low= GetFileSize((HANDLE)fd, &filelen_high);
848   lock_res= LockFileEx((HANDLE)fd, 0, 0, filelen_low, filelen_high, &overlap_str);
849   UDM_ASSERT(lock_res);
850 #endif
851 }
852 
853 
854 void
UdmReadLockFILE(FILE * f)855 UdmReadLockFILE(FILE *f)
856 {   /* a shared lock on an entire file */
857 #ifndef WIN32
858   static struct flock ret ;
859   fcntl(fileno(f), F_SETLKW, file_lock(&ret, F_RDLCK, SEEK_SET));
860 #else
861   /* Windows routine */
862   int file_desc = fileno(f);
863   UdmReadLock(file_desc);
864 #endif
865 }
866 
867 
868 UDM_API(void)
UdmWriteLockFILE(FILE * f)869 UdmWriteLockFILE(FILE *f)
870 {  /* an exclusive lock on an entire file */
871 #ifndef WIN32
872   static struct flock ret ;
873   fcntl(fileno(f), F_SETLKW, file_lock(&ret, F_WRLCK, SEEK_SET));
874 #else
875   /* Windows routine */
876   int file_desc = fileno(f);
877   UdmWriteLock(file_desc);
878 #endif
879 }
880 
881 
882 UDM_API(void)
UdmUnLockFILE(FILE * f)883 UdmUnLockFILE(FILE *f)
884 { /* ulock an entire file */
885 #ifndef WIN32
886   static struct flock ret ;
887   fcntl(fileno(f), F_SETLKW, file_lock(&ret, F_UNLCK, SEEK_SET));
888 #else
889   /* Windows routine */
890   int file_desc = fileno(f);
891   UdmUnLock(file_desc);
892 #endif
893 }
894 
895 
896 
897 
898 /******************** ZINT4 routines ********************/
899 
900 /*
901    Note that buf must be at least X * 5 + 5 bytes.
902    Where X is the number of integers in array.
903 */
904 void
udm_zint4_init(UDM_ZINT4_STATE * state,char * buf)905 udm_zint4_init(UDM_ZINT4_STATE *state, char *buf)
906 {
907   state->bits_left= 8;
908   state->prev= 0;
909   state->end= state->buf= (unsigned char *)buf;
910 }
911 
912 
913 static inline void
udm_zint4_write_bits(UDM_ZINT4_STATE * state,unsigned char byte,unsigned char nbits)914 udm_zint4_write_bits(UDM_ZINT4_STATE *state,
915                      unsigned char byte, unsigned char nbits)
916 {
917   if (state->bits_left == 8)
918     *state->end= 0;
919   if (state->bits_left >= nbits)
920   {
921     *state->end+= byte << (state->bits_left - nbits);
922     if (nbits == state->bits_left)
923     {
924       state->end++;
925       state->bits_left= 8;
926     }
927     else
928       state->bits_left-= nbits;
929     return;
930   }
931   *state->end+= byte >> (nbits - state->bits_left);
932   state->end++;
933   state->bits_left+= 8 - nbits;
934   *state->end= byte << state->bits_left;
935 }
936 
937 
938 /*
939   Encoding components:
940   Bits Bit mask                                         Range
941   ==== ================================================ ==========
942   5           0 xxxx                                    0x0000000F
943   10         10 xxxx xxxx                               0x000000FF
944   15        110 xxxx xxxx xxxx                          0x00000FFF
945   20       1110 xxxx xxxx xxxx xxxx                     0x0000FFFF
946   25      11110 xxxx xxxx xxxx xxxx xxxx                0x000FFFFF
947   30     111110 xxxx xxxx xxxx xxxx xxxx xxxx           0x00FFFFFF
948   35    1111110 xxxx xxxx xxxx xxxx xxxx xxxx xxxx      0x0FFFFFFF
949   40   11111110 xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx 0xFFFFFFFF
950 */
951 
952 void
udm_zint4(UDM_ZINT4_STATE * state,int next)953 udm_zint4(UDM_ZINT4_STATE *state, int next)
954 {
955   unsigned int n= (unsigned int)(next - state->prev);
956   state->prev= next;
957   if (n < 0x10) /* compressed to 5 bits, 1 block */
958   {
959     udm_zint4_write_bits(state, n, 5);
960   }
961   else if (n < 0x110) /* compressed to 10 bits, 2 blocks */
962   {
963     n-= 0x10;
964     udm_zint4_write_bits(state, 2, 2);
965     udm_zint4_write_bits(state, n, 8);
966   }
967   else if (n < 0x1110) /* compressed to 15 bits, 3 blocks */
968   {
969     n-= 0x110;
970     udm_zint4_write_bits(state, 6, 3);
971     udm_zint4_write_bits(state, n >> 8, 4);
972     udm_zint4_write_bits(state, n & 0xff, 8);
973   }
974   else if (n < 0x11110) /* compressed to 20 bits, 4 blocks */
975   {
976     n-= 0x1110;
977     udm_zint4_write_bits(state, 0xe, 4);
978     udm_zint4_write_bits(state, n >> 8, 8);
979     udm_zint4_write_bits(state, n & 0xff, 8);
980   }
981   else if (n < 0x111110) /* compressed to 25 bits, 5 blocks */
982   {
983     n-= 0x11110;
984     udm_zint4_write_bits(state, 0x1e, 5);
985     udm_zint4_write_bits(state, n >> 16, 4);
986     udm_zint4_write_bits(state, (n >> 8) & 0xff, 8);
987     udm_zint4_write_bits(state, n & 0xff, 8);
988   }
989   else if (n < 0x1111110) /* compressed to 30 bits, 6 blocks */
990   {
991     n-= 0x111110;
992     udm_zint4_write_bits(state, 0x3e, 6);
993     udm_zint4_write_bits(state, n >> 16, 8);
994     udm_zint4_write_bits(state, (n >> 8) & 0xff, 8);
995     udm_zint4_write_bits(state, n & 0xff, 8);
996   }
997   else if (n < 0x11111110) /* compressed to 35 bits */
998   {
999     n-= 0x1111110;
1000     udm_zint4_write_bits(state, 0x7e, 7);
1001     udm_zint4_write_bits(state, n >> 24, 4);
1002     udm_zint4_write_bits(state, (n >> 16) & 0xff, 8);
1003     udm_zint4_write_bits(state, (n >> 8) & 0xff, 8);
1004     udm_zint4_write_bits(state, n & 0xff, 8);
1005   }
1006   else /* compressed to 40 bits */
1007   {
1008     n-= 0x11111110;
1009     udm_zint4_write_bits(state, 0xfe, 8);
1010     udm_zint4_write_bits(state, n >> 24, 8);
1011     udm_zint4_write_bits(state, (n >> 16) & 0xff, 8);
1012     udm_zint4_write_bits(state, (n >> 8) & 0xff, 8);
1013     udm_zint4_write_bits(state, n & 0xff, 8);
1014  }
1015 }
1016 
1017 
1018 void
udm_zint4_finalize(UDM_ZINT4_STATE * state)1019 udm_zint4_finalize(UDM_ZINT4_STATE *state)
1020 {
1021   if (state->bits_left < 8)
1022     udm_zint4_write_bits(state, 0xff, 8);
1023   *state->end++= 0xff;
1024   *state->end++= 0xff;
1025   *state->end++= 0xff;
1026   *state->end++= 0xff;
1027   *state->end++= 0xff;
1028 }
1029 
1030 
1031 int
udm_dezint4(const char * buf,int4 * array,int buf_len)1032 udm_dezint4(const char *buf, int4 *array, int buf_len)
1033 {
1034   unsigned char next_byte= *buf;
1035   unsigned char bit_idx= 8;
1036   char nblocks= 1;
1037   int4 prev= 0, *array_end;
1038   if ((unsigned char)buf[buf_len - 1] != 0xff ||
1039       (unsigned char)buf[buf_len - 2] != 0xff ||
1040       (unsigned char)buf[buf_len - 3] != 0xff ||
1041       (unsigned char)buf[buf_len - 4] != 0xff ||
1042       (unsigned char)buf[buf_len - 5] != 0xff)
1043     return(0);
1044   for (array_end= array;; array_end++)
1045   {
1046     uint4 next= 0;
1047     /* Extract number of blocks */
1048     while (next_byte & (1 << --bit_idx))
1049     {
1050       if (++nblocks == 9)
1051         return(array_end - array);
1052       if (! bit_idx)
1053       {
1054         bit_idx= 8;
1055         next_byte= *++buf;
1056       }
1057     }
1058     if (! bit_idx)
1059     {
1060       bit_idx= 8;
1061       next_byte= *++buf;
1062     }
1063 
1064     for (;; nblocks--)
1065     {
1066       switch (bit_idx) {
1067         case 1:
1068           next+= (next_byte & 1) << 3;
1069           bit_idx= 5;
1070           next_byte= *++buf;
1071           next+= (next_byte >> 5) & 0xf;
1072           break;
1073         case 2:
1074           next+= (next_byte & 3) << 2;
1075           bit_idx= 6;
1076           next_byte= *++buf;
1077           next+= (next_byte >> 6) & 7;
1078           break;
1079         case 3:
1080           next+= (next_byte & 7) << 1;
1081           bit_idx= 7;
1082           next_byte= *++buf;
1083           next+= (next_byte >> 7) & 3;
1084           break;
1085         case 4:
1086           next+= next_byte & 0xf;
1087           bit_idx= 8;
1088           next_byte= *++buf;
1089           break;
1090         case 5:
1091           bit_idx= 1;
1092           next+= (next_byte >> 1) & 0xf;
1093           break;
1094         case 6:
1095           bit_idx= 2;
1096           next+= (next_byte >> 2) & 0xf;
1097           break;
1098         case 7:
1099           bit_idx= 3;
1100           next+= (next_byte >> 3) & 0xf;
1101           break;
1102         case 8:
1103           bit_idx= 4;
1104           next+= (next_byte >> 4) & 0xf;
1105           break;
1106       }
1107       if (nblocks > 1)
1108         next= (next + 1) << 4;
1109       else
1110         break;
1111     }
1112     prev+= next;
1113     *array_end= prev;
1114   }
1115   return(array_end - array);
1116 }
1117 
1118 
1119 /****************** Sort and Search routines ***************/
1120 
1121 #ifdef HAVE_DEBUG
UdmSort(void * base,size_t nmemb,size_t size,int (* compar)(const void *,const void *))1122 void UdmSort(void *base, size_t nmemb, size_t size,
1123              int(*compar)(const void *, const void *))
1124 {
1125   UDM_ASSERT(nmemb > 0);
1126   qsort(base, nmemb, size, compar);
1127 }
1128 
UdmBSearch(const void * key,const void * base,size_t nmemb,size_t size,int (* compar)(const void *,const void *))1129 void *UdmBSearch(const void *key, const void *base, size_t nmemb,
1130                  size_t size, int (*compar)(const void *, const void *))
1131 {
1132   UDM_ASSERT(nmemb > 0);
1133   return bsearch(key, base, nmemb, size, compar);
1134 }
1135 #endif
1136 
1137 
1138 /*************** Directory routines **************/
1139 
1140 #ifdef WIN32
1141 #include <winreg.h>
1142 #endif
1143 
1144 
1145 #if defined(WIN32)
1146 static size_t
UdmGetDirWinReg(char * d,size_t dlen,udm_dirtype_t type)1147 UdmGetDirWinReg(char *d, size_t dlen, udm_dirtype_t type)
1148 {
1149   HKEY hKey;
1150   LONG res= RegOpenKeyEx(HKEY_LOCAL_MACHINE, UDM_REG_DIRS_KEY, 0,
1151                          KEY_READ | KEY_WOW64_32KEY, &hKey);
1152   size_t ret= 0;
1153   if (res == ERROR_SUCCESS)
1154   {
1155     char buf[MAX_PATH]= "";
1156     DWORD dwType;
1157     DWORD cbData= MAX_PATH;
1158     if (ERROR_SUCCESS == RegQueryValueEx(hKey, UDM_REG_INSTALLDIR_VALUE,
1159                                          NULL, &dwType, (LPBYTE)buf, &cbData))
1160       ret= udm_snprintf(d, dlen, "%s%s", buf,
1161                         type == UDM_DIRTYPE_SHARE ? "\\share" :
1162                         type == UDM_DIRTYPE_VAR ? "\\var" :
1163                         type == UDM_DIRTYPE_CONF ? "\\etc" : "");
1164     RegCloseKey(hKey);
1165   }
1166   /*return ret ?  ret : GetCurrentDirectory(dlen, d);*/
1167   return ret;
1168 }
1169 #endif
1170 
1171 
1172 static size_t
UdmGetDirEnvOrCompiled(char * d,size_t dlen,udm_dirtype_t type)1173 UdmGetDirEnvOrCompiled(char *d, size_t dlen, udm_dirtype_t type)
1174 {
1175   char *env;
1176   UDM_ASSERT(dlen > 0);
1177   switch (type)
1178   {
1179     case UDM_DIRTYPE_CONF:
1180       if (!(env= getenv("UDM_CONF_DIR")))
1181         env= getenv("UDM_ETC_DIR");
1182       return udm_snprintf(d, dlen, "%s", env ? env : UDM_CONF_DIR);
1183 
1184     case UDM_DIRTYPE_SHARE:
1185       env= getenv("UDM_SHARE_DIR");
1186       return udm_snprintf(d, dlen, "%s", env ? env : UDM_SHARE_DIR);
1187 
1188     case UDM_DIRTYPE_VAR:
1189       env= getenv("UDM_VAR_DIR");
1190       return udm_snprintf(d, dlen, "%s", env ? env : UDM_VAR_DIR);
1191 
1192     case UDM_DIRTYPE_TMP:
1193       if (!(env= getenv("UDM_TMP_DIR")))
1194         env= getenv("TMPDIR");
1195       return udm_snprintf(d, dlen, "%s", env ? env : UDM_TMP_DIR);
1196     default:
1197       *d= '\0';
1198   }
1199   *d= '\0';
1200   return 0;
1201 }
1202 
1203 
1204 size_t
UdmGetDir(char * d,size_t dlen,udm_dirtype_t type)1205 UdmGetDir(char *d, size_t dlen, udm_dirtype_t type)
1206 {
1207 #if defined(WIN32)
1208   size_t res;
1209   if ((res= UdmGetDirWinReg(d, dlen, type)))
1210     return res;
1211 #endif
1212   return UdmGetDirEnvOrCompiled(d, dlen, type);
1213 }
1214 
1215 
1216 size_t
UdmGetFileName(char * d,size_t dlen,udm_dirtype_t type,const char * fname)1217 UdmGetFileName(char *d, size_t dlen, udm_dirtype_t type, const char *fname)
1218 {
1219   size_t len= UdmGetDir(d, dlen, type);
1220   if (len < dlen)
1221     len+= udm_snprintf(d + len, dlen - len, "%s%s", UDMSLASHSTR, fname);
1222   return len;
1223 }
1224 
1225 
1226 static int log_10_int[]=
1227 {
1228          1,
1229         10,
1230        100,
1231       1000,
1232      10000,
1233     100000,
1234    1000000,
1235   10000000,
1236  100000000,
1237 1000000000,
1238 };
1239 
1240 
UdmNormalizeDecimal(char * dst,size_t dlen,const char * src)1241 int UdmNormalizeDecimal(char *dst, size_t dlen, const char *src)
1242 {
1243   int ipart, fpart;
1244   char *endptr;
1245   long long int nr;
1246 
1247   ipart= strtol(src, &endptr, 10);
1248   if (*endptr ==  '.')
1249   {
1250     size_t flen;
1251     char *endptr2;
1252     endptr++;
1253     fpart= strtol(endptr, &endptr2, 10);
1254     if ((flen= endptr2 - endptr) <= 9)
1255       fpart*= log_10_int[9 - flen];
1256   }
1257   else
1258     fpart= 0;
1259   nr= (((long long int) ipart) * 1000000000) + fpart;
1260   udm_snprintf(dst, dlen, "%018lld", nr);
1261   return 0;
1262 }
1263 
1264 /*********** UDM_STR routines **************/
UdmStrInit(UDM_STR * str)1265 void UdmStrInit(UDM_STR *str)
1266 {
1267   str->str= NULL;
1268   str->length= 0;
1269 }
1270 
1271 
UdmStrFree(UDM_STR * str)1272 void UdmStrFree(UDM_STR *str)
1273 {
1274   UdmFree(str->str);
1275 }
1276 
1277 
UdmStrMemdup(UDM_STR * str,const char * src,size_t length)1278 udm_rc_t UdmStrMemdup(UDM_STR *str, const char *src, size_t length)
1279 {
1280   if (!(str->str= UdmMalloc(length)))
1281   {
1282     str->length= 0;
1283     return UDM_ERROR;
1284   }
1285   str->length= length;
1286   memcpy(str->str, src, length);
1287   return UDM_OK;
1288 }
1289 
1290 
UdmStrNDup(UDM_STR * to,const char * str,size_t length)1291 udm_rc_t UdmStrNDup(UDM_STR *to, const char *str, size_t length)
1292 {
1293   if (!(to->str= UdmMalloc(length + 1)))
1294   {
1295     to->length= 0;
1296     return UDM_ERROR;
1297   }
1298   to->length= length;
1299   memcpy(to->str, str, length);
1300   to->str[length]= '\0';
1301   return UDM_OK;
1302 }
1303 
1304 
1305 /*********** Const string routines *********/
UdmConstStrInit(UDM_CONST_STR * str)1306 void UdmConstStrInit(UDM_CONST_STR *str)
1307 {
1308   str->str= NULL;
1309   str->length= 0;
1310 }
1311 
1312 
UdmConstStrSet(UDM_CONST_STR * str,const char * s,size_t length)1313 void UdmConstStrSet(UDM_CONST_STR *str, const char *s, size_t length)
1314 {
1315   str->str= s;
1316   str->length= length;
1317 }
1318 
1319 
UdmConstStrSetStr(UDM_CONST_STR * str,const char * s)1320 void UdmConstStrSetStr(UDM_CONST_STR *str, const char *s)
1321 {
1322   str->str= s;
1323   str->length= strlen(s);
1324 }
1325 
1326 
UdmConstStrNCaseCmp(const UDM_CONST_STR * str,const char * s,size_t length)1327 int UdmConstStrNCaseCmp(const UDM_CONST_STR *str, const char *s, size_t length)
1328 {
1329   if (str->length != length)
1330     return 1;
1331   return strncasecmp(str->str, s, length);
1332 }
1333 
1334 
UdmConstStrDup(const UDM_CONST_STR * str)1335 char *UdmConstStrDup(const UDM_CONST_STR *str)
1336 {
1337   return udm_strndup(str->str, str->length);
1338 }
1339 
1340 
UdmConstStrTrim(UDM_CONST_STR * str,const char * sep)1341 void UdmConstStrTrim(UDM_CONST_STR *str, const char *sep)
1342 {
1343   for ( ; str->length > 0 && strchr(sep, str->str[0]) ; str->str++, str->length--);
1344   for ( ; str->length > 0 && strchr(sep, str->str[str->length - 1]); str->length--);
1345 }
1346 
1347 /**************** Const token routines *********************/
1348 char *
UdmConstTokenStrDup(const UDM_CONST_TOKEN * str)1349 UdmConstTokenStrDup(const UDM_CONST_TOKEN *str)
1350 {
1351   return udm_strndup(str->str, str->end - str->str);
1352 }
1353 
1354 
UdmConstTokenSet(UDM_CONST_TOKEN * dst,const char * str,size_t length)1355 void UdmConstTokenSet(UDM_CONST_TOKEN *dst, const char *str, size_t length)
1356 {
1357   dst->str= str;
1358   dst->end= str + length;
1359 }
1360 
1361 
1362 /**************** Quoted printable *************************/
1363 /*
1364   Quoted-printable decoding (according to RFC 2045)
1365 */
1366 size_t
udm_quoted_printable_decode(const char * src,size_t srclen,char * dst,size_t dstlen)1367 udm_quoted_printable_decode(const char *src, size_t srclen,
1368                             char *dst, size_t dstlen)
1369 {
1370   const char *srcend= src + srclen;
1371   const char *dstend= dst + dstlen, *dst0= dst;
1372 
1373   while (src < srcend && dst < dstend)
1374   {
1375     if (*src != '=')
1376     {
1377       *dst++= *src++;
1378       continue;
1379     }
1380 
1381     if (src + 2 < srcend && udm_isxdigit(src[1]) && udm_isxdigit(src[2]))
1382     {
1383       *dst++= ch2x((int) src[1]) * 16 + ch2x((int) src[2]);
1384       src+= 3;
1385     }
1386     else  /* Test soft line-break */
1387     {
1388       const char *lb;
1389       for (lb= src + 1; lb < srcend && (*lb == ' ' || *lb == '\t'); )
1390       {
1391         /* Possibly, skip spaces/tabs at the end of line */
1392         lb++;
1393       }
1394       if (lb == srcend) /* End of line */
1395       {
1396         src= lb;
1397         break;
1398       }
1399       else if (lb[0] == '\r' && lb + 1 < srcend && lb[1] == '\n') /* CRLF */
1400       {
1401         src= lb + 2;
1402       }
1403       else if (*lb == '\r' || *lb == '\n') /* CR or LF */
1404       {
1405         src= lb + 1;
1406       }
1407       else
1408       {
1409         *dst++= *src++;
1410       }
1411     }
1412   }
1413   return dst - dst0;
1414 }
1415 
1416 /***************************************************************/
1417 
1418 
1419 /**
1420   Convert a string representing a number with
1421   an optional size multiplier (K, M, G) to size_t.
1422   Returns 0xFFFFFFFF if multiplication would overlow.
1423   Returns the result of conversion.
1424 */
1425 size_t
UdmStrToSize(const char * str,char ** endptr,int * error)1426 UdmStrToSize(const char *str, char **endptr, int *error)
1427 {
1428   size_t mul;
1429   unsigned long int tmp;
1430   unsigned long int overflow;
1431   errno= 0;
1432   tmp= strtoul(str, endptr, 10);
1433   if ((*error= errno))
1434     return (size_t) tmp;
1435   if (*endptr == str) /* There were no digits to convert */
1436   {
1437     *error= EINVAL;
1438     return 0;
1439   }
1440   switch (endptr[0][0]) /* Handle size multipliers */
1441   {
1442   case 'k':
1443   case 'K':
1444     overflow= 4194304;
1445     mul= 1024;
1446     break;
1447   case 'm':
1448   case 'M':
1449     overflow= 4096;
1450     mul= 1024 * 1024;
1451     break;
1452   case 'g':
1453   case 'G':
1454     overflow= 4;
1455     mul= 1024 * 1024 * 1024;
1456     break;
1457   default:
1458     return (size_t) tmp;
1459   }
1460   if (tmp >= overflow)
1461   {
1462     *error= ERANGE;
1463     return 0xFFFFFFFFUL;
1464   }
1465   (*endptr)++;
1466   return tmp * mul;
1467 }
1468 
1469 
UdmProcessCurrentResidentSize(void)1470 size_t UdmProcessCurrentResidentSize(void)
1471 {
1472 #if defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
1473   long rss= 0L;
1474   FILE* fp;
1475   if (!(fp= fopen( "/proc/self/statm", "r" )))
1476     return (size_t) 0L;
1477   fscanf(fp, "%*s%ld", &rss );
1478   fclose( fp );
1479   return (size_t)rss * (size_t)sysconf( _SC_PAGESIZE);
1480 #endif
1481   return 0;
1482 }
1483 
1484 
1485 /************************************************************************/
1486 
UdmMemrootInit(UDM_MEMROOT * root,size_t page_size)1487 void UdmMemrootInit(UDM_MEMROOT *root, size_t page_size)
1488 {
1489   bzero((void*) root, sizeof(*root));
1490   root->page_size= page_size;
1491 }
1492 
1493 
UdmMemrootFree(UDM_MEMROOT * root)1494 void UdmMemrootFree(UDM_MEMROOT *root)
1495 {
1496   size_t i;
1497   for (i= 0; i < root->nitems; i++)
1498     UdmFree(root->Item[i].ptr);
1499   UdmFree(root->Item);
1500 }
1501 
1502 
UdmMemrootReset(UDM_MEMROOT * root)1503 void UdmMemrootReset(UDM_MEMROOT *root)
1504 {
1505   UdmMemrootFree(root);
1506   UdmMemrootInit(root, root->page_size);
1507 }
1508 
1509 
1510 static udm_rc_t
UdmMemrootNewPage(UDM_MEMROOT * root)1511 UdmMemrootNewPage(UDM_MEMROOT *root)
1512 {
1513   if (root->nitems >= root->mitems)
1514   {
1515     root->mitems= root->nitems + 256;
1516     if (!(root->Item= (UDM_MEMROOT_PAGE*) UdmRealloc(root->Item,
1517                                                      root->mitems *
1518                                                      sizeof(UDM_MEMROOT_PAGE))))
1519       return UDM_ERROR;
1520   }
1521   if (!(root->Item[root->nitems].ptr= UdmMalloc(root->page_size)))
1522     return UDM_ERROR;
1523   root->nitems++;
1524   root->last_page_used_size= 0;
1525   return UDM_OK;
1526 }
1527 
1528 
UdmMemrootAlloc(UDM_MEMROOT * root,size_t size)1529 char *UdmMemrootAlloc(UDM_MEMROOT *root, size_t size)
1530 {
1531   void *ret;
1532   UDM_ASSERT(root->page_size >= size);
1533   if (!root->nitems || root->last_page_used_size + size > root->page_size)
1534   {
1535     if (UDM_OK != UdmMemrootNewPage(root))
1536       return NULL;
1537   }
1538   ret= root->Item[root->nitems - 1].ptr + root->last_page_used_size;
1539   root->last_page_used_size+= size;
1540   return ret;
1541 }
1542 
1543 
UdmMemrootStrndup(UDM_MEMROOT * root,const char * str,size_t length)1544 char *UdmMemrootStrndup(UDM_MEMROOT *root, const char *str, size_t length)
1545 {
1546   char *ptr= UdmMemrootAlloc(root, length + 1);
1547   if (ptr)
1548   {
1549     memcpy(ptr, str, length);
1550     ptr[length]= '\0';
1551   }
1552   return ptr;
1553 }
1554 
1555 
UdmMemrootAllocedMemory(const UDM_MEMROOT * root)1556 size_t UdmMemrootAllocedMemory(const UDM_MEMROOT *root)
1557 {
1558   return root->page_size * root->nitems;
1559 }
1560 
1561 
UdmMemrootUsedMemory(const UDM_MEMROOT * root)1562 size_t UdmMemrootUsedMemory(const UDM_MEMROOT *root)
1563 {
1564   return root->last_page_used_size  +
1565          (root->nitems ? (root->nitems - 1) * root->page_size : 0);
1566 }
1567