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