1 /*
2  *	binkleyforce -- unix FTN mailer project
3  *
4  *	Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11
5  *
6  *	This program is free software; you can redistribute it and/or modify
7  *	it under the terms of the GNU General Public License as published by
8  *	the Free Software Foundation; either version 2 of the License, or
9  *	(at your option) any later version.
10  *
11  *	$Id: u_string.c,v 1.1.1.1 2004/09/09 09:52:39 kstepanenkov Exp $
12  */
13 
14 #ifndef TEST
15 #include "includes.h"
16 #include "confread.h"
17 #include "logger.h"
18 #include "util.h"
19 #else
20 #include <stdio.h>
21 #include <stdarg.h>
22 #define TRUE     1
23 #define FALSE    0
24 #define bool     int
25 #define xmalloc  malloc
26 #define xrealloc realloc
27 #define ASSERT
28 #endif
29 
30 /*
31  * Maximum number of quoted-printable strings we will store together
32  */
33 #define PRINTABLE_MAXITEMS 5
34 
35 /*
36  * Cyclic buffer for quoted-printable strings
37  */
38 static char *printable_storage[PRINTABLE_MAXITEMS];
39 
40 /*
41  * Position of next entry to use in printable_storage[]
42  */
43 static int printable_pos = -1;
44 
45 
46 /*****************************************************************************
47  * Allocate memory for the copy of a string pointed by src
48  *
49  * Arguments:
50  * 	src       pointer to the null-terminated string
51  *
52  * Return value:
53  * 	Pointer to the resulting string (must be freed)
54  */
xstrcpy(const char * src)55 char *xstrcpy(const char *src)
56 {
57 	char *tmp;
58 
59 	if( !src )
60 		return NULL;
61 
62 	tmp = xmalloc(strlen(src)+1);
63 	strcpy(tmp, src);
64 
65 	return tmp;
66 }
67 
68 /*****************************************************************************
69  * Append string pointed by add to the string src, allocate memory for result
70  *
71  * Arguments:
72  * 	src       pointer to the null-terminated string (will be freed)
73  * 	add       this one will be appended to the src
74  *
75  * Return value:
76  * 	Pointer to the resulting string (must be freed)
77  */
xstrcat(char * src,const char * add)78 char *xstrcat(char *src, const char *add)
79 {
80 	char *tmp;
81 	size_t size;
82 
83 	if( !add || *add == '\0' )
84 		return src;
85 
86 	size = (src ? strlen(src) : 0) + strlen(add);
87 	tmp  = (char*)xmalloc(size+1);
88 
89 	if( src )
90 	{
91 		strcpy(tmp, src);
92 		free(src);
93 	} else
94 		*tmp = '\0';
95 
96 	strcat(tmp, add);
97 
98 	return tmp;
99 }
100 
101 /*****************************************************************************
102  * Copy a string to the buffer. Checks for the destination buffer overflow and
103  * terminating '\0' character.
104  *
105  * Arguments:
106  * 	dst       pointer to the destination buffer
107  * 	src       string to copy from
108  * 	len       destination buffer size
109  *
110  * Return value:
111  * 	Pointer to the resulting string
112  */
strnxcpy(char * dst,const char * src,size_t len)113 char *strnxcpy(char *dst, const char *src, size_t len)
114 {
115 	ASSERT(src != NULL && dst != NULL && len >= 0);
116 
117 	dst[len - 1] = 0;
118 
119 	return strncpy(dst, src, len - 1);
120 }
121 
122 /*****************************************************************************
123  * Add one string to the end of another. Checks for destination buffer
124  * overflow and terminating '\0' character.
125  *
126  * Arguments:
127  * 	dst       pointer to the destination buffer (append to the string
128  * 	          stored in it)
129  * 	src       append this string
130  * 	len       destination buffer size
131  *
132  * Return value:
133  * 	Pointer to the resulting string
134  */
strnxcat(char * dst,const char * src,size_t len)135 char *strnxcat(char *dst, const char *src, size_t len)
136 {
137 	int pos;
138 
139 	ASSERT(src != NULL && dst != NULL && len >= 0);
140 
141 	pos = strlen(dst);
142 
143 	return strnxcpy(dst + pos, src, len - pos);
144 }
145 
146 /*****************************************************************************
147  * Get next substring from the string.
148  *
149  * Arguments:
150  * 	str       pointer to a null-terminated string
151  * 	next      points to the pointer where you want store address of
152  * 	          the next substring for next calls
153  * 	delim     delimiter characters, if NULL than the isspace() call used
154  * 	          to check for the delimiter characters
155  * 	quoted    ignore spaces in the quoted substrings
156  *
157  * Return value:
158  * 	Pointer to the new substring or NULL if no more available
159  */
string_token(char * str,char ** next,const char * delim,int quoted)160 char *string_token(char *str, char **next, const char *delim, int quoted)
161 {
162 	char *yield;
163 	char *p;
164 
165 	ASSERT(next != NULL);
166 
167 	yield = str ? str : *next;
168 
169 	if( yield )
170 	{
171 		if( delim && *delim )
172 			while( *yield && strchr(delim, *yield) ) yield++;
173 		else
174 			while( isspace(*yield) ) yield++;
175 
176 		if( *yield )
177 		{
178 			if( quoted && *yield == '"' )
179 			{
180 				p = ++yield;
181 				while( *p && *p != '"' ) p++;
182 			}
183 			else
184 			{
185 				p = yield;
186 				if( delim && *delim )
187 					while( *p && !strchr(delim, *p) ) p++;
188 				else
189 					while( *p && !isspace(*p) ) p++;
190 			}
191 			if( *p )
192 			{
193 				*p = '\0';
194 				*next = p+1;
195 			} else
196 				*next = NULL;
197 		} else
198 			yield = *next = NULL;
199 	}
200 
201 	return yield;
202 }
203 
204 /*****************************************************************************
205  * Remove trailing CR and LF characters
206  *
207  * Arguments:
208  * 	str       pointer to the null-terminated string
209  *
210  * Return value:
211  * 	Pointer to the string
212  */
string_chomp(char * str)213 char *string_chomp(char *str)
214 {
215 	char *p;
216 
217 	ASSERT(str != NULL);
218 
219 	if( str && *str )
220 	{
221 		p = str + strlen(str + 1);
222 		if( *p == '\n' )
223 			*p-- = '\0';
224 		if( *p == '\r' && p >= str )
225 			*p = '\0';
226 	}
227 
228 	return str;
229 }
230 
231 /*****************************************************************************
232  * Find the firtst occurance of substring into the string
233  *
234  * Arguments:
235  * 	substr    pointer to the null-terminated substring
236  * 	string    pointer to the null-terminated string
237  *
238  * Return value:
239  * 	Pointer to the first occurrence of the substring in the string,
240  * 	and NULL if substring is not found
241  */
string_casestr(const char * string,const char * substr)242 const char *string_casestr(const char *string, const char *substr)
243 {
244 	size_t subln = strlen(substr);
245 	size_t strln = strlen(string);
246 
247 	while( *string && strln >= subln )
248 	{
249 		if( !strncasecmp(substr, string, subln) )
250 			return string;
251 
252 		++string;
253 		--strln;
254 	}
255 
256 	return NULL;
257 }
258 
259 /*****************************************************************************
260  * Find character in the string (It is like strchr(), but case insensitive)
261  *
262  * Arguments:
263  * 	str       pointer to the null-terminated string
264  * 	ch        character you want to find
265  *
266  * Return value:
267  * 	Pointer to the first occurrence of the character in the string,
268  * 	and NULL if character is not found
269  */
string_casechr(const char * str,int ch)270 const char *string_casechr(const char *str, int ch)
271 {
272 	ch = tolower(ch);
273 
274 	while( *str )
275 	{
276 		if( tolower(*str) == ch )
277 			return str;
278 
279 		++str;
280 	}
281 
282 	return NULL;
283 }
284 
285 /*****************************************************************************
286  * Convert string to the upper case
287  *
288  * Arguments:
289  * 	str       pointer to the null-terminated string
290  *
291  * Return value:
292  * 	Pointer to the string
293  */
string_toupper(char * str)294 char *string_toupper(char *str)
295 {
296 	char *p;
297 
298 	ASSERT(str != NULL);
299 
300 	for( p = str; *p; p++ ) *p = toupper(*p);
301 
302 	return(str);
303 }
304 
305 /*****************************************************************************
306  * Convert string to the lower case
307  *
308  * Arguments:
309  * 	str       pointer to the null-terminated string
310  *
311  * Return value:
312  * 	Pointer to the string
313  */
string_tolower(char * str)314 char *string_tolower(char *str)
315 {
316 	char *p;
317 
318 	ASSERT(str != NULL);
319 
320 	for( p = str; *p; p++ ) *p = tolower(*p);
321 
322 	return(str);
323 }
324 
325 /*****************************************************************************
326  * Check wheather string doesn't contain lower case characters
327  *
328  * Arguments:
329  * 	str       pointer to the null-terminated string
330  *
331  * Return value:
332  * 	Return TRUE if string conforms our requirements, and FALSE if not
333  */
string_isupper(const char * str)334 bool string_isupper(const char *str)
335 {
336 	const char *p;
337 
338 	ASSERT(str != NULL);
339 
340 	for( p = str; *p; p++ )
341 	{
342 		if( isalpha(*p) && islower(*p) ) break;
343 	}
344 
345 	return (*p == '\0') ? TRUE : FALSE;
346 }
347 
348 /*****************************************************************************
349  * Check wheather string doesn't contain upper case characters
350  *
351  * Arguments:
352  * 	str       pointer to the null-terminated string
353  *
354  * Return value:
355  * 	Return TRUE if string conforms our requirements, and FALSE if not
356  */
string_islower(const char * str)357 bool string_islower(const char *str)
358 {
359 	const char *p;
360 
361 	ASSERT(str != NULL);
362 
363 	for( p = str; *p; p++ )
364 	{
365 		if( isalpha(*p) && isupper(*p) ) break;
366 	}
367 
368 	return (*p == '\0') ? TRUE : FALSE;
369 }
370 
371 /*****************************************************************************
372  * Remove spaces at the end of string
373  *
374  * Arguments:
375  * 	str       pointer to the null-terminated string
376  *
377  * Return value:
378  * 	Pointer to the string
379  */
string_trimright(char * str)380 char *string_trimright(char *str)
381 {
382 	char *p;
383 
384 	ASSERT(str != NULL);
385 
386 	if( str && *str )
387 	{
388 		p = str + strlen(str+1);
389 		while( p >= str && isspace(*p) ) *p-- = '\0';
390 	}
391 
392 	return str;
393 }
394 
395 /*****************************************************************************
396  * Remove spaces at the begining of string
397  *
398  * Arguments:
399  * 	str       pointer to the null-terminated string
400  *
401  * Return value:
402  * 	pointer to the string
403  */
string_trimleft(char * str)404 char *string_trimleft(char *str)
405 {
406 	char *p;
407 
408 	ASSERT(str != NULL);
409 
410 	if( str && *str )
411 	{
412 		p = str;
413 		while( isspace(*p) ) p++;
414 		if( p > str )
415 			memmove(str, p, strlen(p)+1);
416 	}
417 
418 	return str;
419 }
420 
421 /*****************************************************************************
422  * Remove white spaces at the begining and at the end of string
423  *
424  * Arguments:
425  * 	str       pointer to the null-terminated string
426  *
427  * Return value:
428  * 	pointer to the string
429  */
string_trimboth(char * str)430 char *string_trimboth(char *str)
431 {
432 	char *p;
433 
434 	ASSERT(str != NULL);
435 
436 	if( str && *str )
437 	{
438 		/* Remove leading spaces */
439 		p = str;
440 		while( isspace(*p) ) p++;
441 		if( p > str )
442 			memmove(str, p, strlen(p)+1);
443 
444 		/* Remove trailing spaces */
445 		p = str + strlen(str+1);
446 		while( p >= str && isspace(*p) ) *p-- = '\0';
447 	}
448 
449 	return str;
450 }
451 
452 /*****************************************************************************
453  * Quote all unprintable characters in the buffer (e.g. "\xff\xfe")
454  *
455  * Arguments:
456  * 	buffer    pointer to the buffer to process
457  * 	buflen    buffer size
458  *
459  * Return value:
460  * 	Pointer to the quoted-printable string (must be freed)
461  */
string_printable_buffer(const char * buffer,size_t buflen)462 char *string_printable_buffer(const char *buffer, size_t buflen)
463 {
464 	char *dest, *p;
465 	const char *bp;
466 	int nonprintcount = 0;
467 	size_t pos = 0;
468 
469 	for( bp = buffer, pos = 0; pos < buflen; bp++, pos++ )
470 	{
471 		if( !isprint((unsigned char)*bp) )
472 			nonprintcount++;
473 	}
474 
475 	dest = xmalloc(buflen + nonprintcount * 4 + 1);
476 
477 	if( nonprintcount == 0 )
478 	{
479 		memcpy(dest, buffer, buflen);
480 		dest[buflen] = '\0';
481 	}
482 	else
483 	{
484 		p = dest;
485 		for( pos = 0; pos < buflen; buffer++, pos++ )
486 		{
487 			if( !isprint((unsigned char)*buffer) )
488 			{
489 				sprintf(p, "\\x%02x", (unsigned char)*buffer);
490 				p += 4;
491 			} else
492 				*p++ = *buffer;
493 		}
494 		*p = '\0';
495 	}
496 
497 	return dest;
498 }
499 
500 /*****************************************************************************
501  * Quote all unprintable characters in the string (e.g. "\xff\xfe")
502  *
503  * Arguments:
504  * 	str       pointer to the null-terminated string
505  *
506  * Return value:
507  * 	Pointer to the quoted-printable string. Memory allocated for the
508  * 	resulting string will be freed automatically. So don't use more
509  * 	than last PRINTABLE_MAXITEMS pointers returned by this function.
510  */
string_printable(const char * str)511 const char *string_printable(const char *str)
512 {
513 	char *p;
514 	const char *q;
515 	int nonprintcount = 0;
516 	size_t pos = 0;
517 	size_t len = 0;
518 
519 	if( printable_pos == -1 )
520 	{
521 		memset(printable_storage, '\0', sizeof(printable_storage));
522 		printable_pos = 0;
523 	}
524 
525 	if( str == NULL ) return "(null)";
526 
527 	len = strlen(str);
528 
529 	for( q = str, pos = 0; pos < len; q++, pos++ )
530 	{
531 		if( iscntrl((unsigned char)*q) || !isprint((unsigned char)*q) )
532 			nonprintcount++;
533 	}
534 
535 	if( !nonprintcount )
536 		return str;
537 
538 	if( printable_pos >= PRINTABLE_MAXITEMS )
539 		printable_pos = 0;
540 
541 	if( printable_storage[printable_pos] )
542 		free(printable_storage[printable_pos]);
543 
544 	p = printable_storage[printable_pos] = xmalloc(len + nonprintcount * 4 + 1);
545 
546 	for( pos = 0; pos < len; str++, pos++ )
547 	{
548 		if( iscntrl((unsigned char)*str) || !isprint((unsigned char)*str) )
549 		{
550 			sprintf(p, "\\x%02x", (unsigned char)*str);
551 			p += 4;
552 		} else
553 			*p++ = *str;
554 	}
555 	*p = '\0';
556 
557 	return printable_storage[printable_pos++];
558 }
559 
560 /*****************************************************************************
561  * Replace all chracters 'oldchar' by the 'newchar'
562  *
563  * Arguments:
564  * 	str       pointer to the null-terminated string
565  * 	oldchar   old chracter
566  * 	newchar   character to put istead of 'oldchar'
567  *
568  * Return value:
569  * 	Pointer to the string
570  */
string_replchar(char * str,char oldchar,char newchar)571 char *string_replchar(char *str, char oldchar, char newchar)
572 {
573 	char *p = str;
574 
575 	while( *p )
576 	{
577 		if( *p == oldchar ) *p = newchar;
578 		++p;
579 	}
580 
581 	return str;
582 }
583 
584 /*****************************************************************************
585  * Devide string on substrings and put pointers to them into the
586  * dest[] array.
587  *
588  * Arguments:
589  * 	dest      destination array where we should put substrings
590  * 	items     number of entries in dest[]
591  * 	str       string to parse (will be destroyed)
592  * 	separator separator character
593  *
594  * Return value:
595  * 	Number of substrings in the dest[]
596  */
string_parse(char ** dest,int items,char * str,int separator)597 int string_parse(char **dest, int items, char *str, int separator)
598 {
599 	int count = 0;
600 	char *p = str;
601 
602 	dest[count++] = str;
603 
604 	while( *p && count < items )
605 	{
606 		if( *((unsigned char *)p) == separator )
607 		{
608 			*p++ = '\0';
609 			dest[count++] = p;
610 		} else
611 			++p;
612 	}
613 
614 	return count;
615 }
616 
617 /*****************************************************************************
618  * Devide string on substrings separated by white-space characters and put
619  * pointers to them into the dest[] array. Also it will ignore spaces in
620  * quoted strings (quote characters will be removed)
621  *
622  * Arguments:
623  * 	dest      destination array where we should put substrings
624  * 	items     number of entries in dest[]
625  * 	str       string to parse (will be destroyed)
626  *
627  * Return value:
628  * 	Number of substrings in the dest[]
629  */
string_parse_regular(char ** dest,int items,char * str)630 int string_parse_regular(char **dest, int items, char *str)
631 {
632 	int count = 0;
633 	char *p = str;
634 
635 	while( *p )
636 	{
637 		while( *p && isspace(*p) )
638 			++p;
639 
640 		if( *((unsigned char *)p) == '"' && *++p )
641 		{
642 			dest[count++] = p;
643 			while( *p && *((unsigned char *)p) != '"' ) p++;
644 		}
645 		else if( *p )
646 		{
647 			dest[count++] = p;
648 			while( *p && !isspace(*p) ) p++;
649 		}
650 
651 		if( *p && count < items )
652 			*p++ = '\0';
653 		else
654 			break;
655 	}
656 
657 	return count;
658 }
659 
660 /*****************************************************************************
661  * Replace all substrings 'find' by the 'repl' in the string 'str'
662  *
663  * Arguments:
664  * 	str       null-terminated string to process (will be unchanged)
665  * 	find      substring to find
666  * 	repl      replace substring
667  *
668  * Return value:
669  * 	Pointer to the new string (must be freed)
670  */
string_translate(const char * str,const char * find,const char * repl)671 char *string_translate(const char *str, const char *find, const char *repl)
672 {
673 	size_t sz_find = strlen(find);
674 	size_t sz_repl = strlen(repl);
675 	size_t sz_dest = strlen(str);
676 	char *dest, *p;
677 
678 	p = dest = xstrcpy(str);
679 
680 	if( !sz_find ) return dest;
681 
682 	while( *p )
683 	{
684 		if( memcmp(p, find, sz_find) == 0 )
685 		{
686 			size_t offset = p - dest;
687 			size_t newsize = sz_dest + (sz_repl - sz_find);
688 
689 			if( newsize > sz_dest )
690 				dest = xrealloc(dest, newsize+1);
691 
692 			if( sz_repl > sz_find )
693 				memmove(dest + offset + (sz_repl - sz_find), dest + offset, sz_dest - offset + 1);
694 			else if( sz_repl < sz_find )
695 				memmove(dest + offset, dest + offset + (sz_find - sz_repl), sz_dest - offset + 1);
696 
697 			memcpy(dest + offset, repl, sz_repl);
698 
699 			sz_dest = newsize;
700 			p = dest + offset + sz_repl;
701 		} else
702 			++p;
703 	}
704 
705 	return dest;
706 }
707 
708 /*****************************************************************************
709  * Convert size into human readable format (e.g. 100,256Kb or 20.7Mb)
710  *
711  * Arguments:
712  * 	buffer    pointer to the buffer for resulting string
713  * 	size      size in bytes that you want to print
714  *
715  * Return value:
716  * 	Pointer to the string
717  */
string_humansize(char * buffer,size_t size)718 char *string_humansize(char *buffer, size_t size)
719 {
720 	if( size < 1024 )
721 		sprintf(buffer, "%ldb", (long)size);
722 	else if( size < 100*1024 )
723 		sprintf(buffer, "%.1fK", ((double)size)/1024.0);
724 	else if( size < 1000*1024 )
725 		sprintf(buffer, "%ldK", (long)(size/1024));
726 	else if( size < 100*1024*1024 )
727 		sprintf(buffer, "%.1fM", ((double)size)/(1024.0*1024.0));
728 	else if( size < 1000*1024*1024 )
729 		sprintf(buffer, "%ldM", (long)(size/(1024*1024)));
730 	else
731 		sprintf(buffer, "%.1fG", ((double)size)/(1024.0*1024.0*1024.0));
732 
733 	return string_replchar(buffer, ',', '.');
734 }
735 
736 /*****************************************************************************
737  * Interpret escape sequence (\xNN, \NNN, \r, \n, etc.)
738  *
739  * Arguments:
740  * 	pptr      points a pointer to the first character after '\'
741  *
742  * Return value:
743  * 	Value of the escaped character
744  */
string_get_escape(char ** pptr)745 int string_get_escape(char **pptr)
746 {
747 	int ch = 0;
748 	static const char *hexdigits = "0123456789abcdef";
749 	char *p = *pptr;
750 
751 	if( *p == 'x' )
752 	{
753 		const char *q;
754 
755 		if( (q = string_casechr(hexdigits, *(++p))) )
756 		{
757 			ch = q - hexdigits;
758 			if( (q = string_casechr(hexdigits, *(++p))) )
759 			{
760 				ch = ch * 16 + (q - hexdigits);
761 			}
762 		}
763 	}
764 	else if( *p == '0' || *p == '1' || *p == '2' || *p == '3' )
765 	{
766 		ch = *(p++) - '0';
767 		if( isdigit(*p) && *p != '8' && *p != '9' )
768 		{
769 			ch = ch * 8 + (*(p++) - '0');
770 			if( isdigit(*p) && *p != '8' && *p != '9' )
771 			{
772 				ch = ch * 8 + (*p - '0');
773 			}
774 		}
775 	}
776 	else switch(*p) {
777 	case 'a':
778 		ch = '\a'; break;
779 	case 'b':
780 		ch = '\b'; break;
781 	case 'f':
782 		ch = '\f'; break;
783 	case 'n':
784 		ch = '\n'; break;
785 	case 'r':
786 		ch = '\r'; break;
787 	case 't':
788 		ch = '\t'; break;
789 	case '\\':
790 		ch = '\\'; break;
791 	default:
792 		ch = *p;
793 	}
794 
795 	*pptr = p + 1;
796 
797 	return (ch > 0) ? (ch & 0xff) : -1;
798 }
799 
string_dequote(char * dst,char * src)800 int string_dequote(char *dst, char *src)
801 {
802 	char *d = dst;
803 	char *s = src;
804 	int ch;
805 
806 	while( *s )
807 	{
808 		if( s[0] == '\\' && s[1] )
809 		{
810 			++s;
811 			ch = string_get_escape(&s);
812 			if( ch != -1 )
813 				*d++ = ch;
814 		}
815 		else
816 			*d++ = *s++;
817 	}
818 
819 	*d = '\0';
820 
821 	return 0;
822 }
823 
string_concat(const char * str,...)824 char *string_concat(const char *str, ...)
825 {
826 	va_list args;
827 	size_t yield_len;
828 	char  *yield_ptr;
829 	char  *yield;
830 	char  *p;
831 
832 	/*
833 	 * Calculate total length of yielding string
834 	 */
835 	yield_len = strlen(str);
836 	va_start(args, str);
837 	while( (p = va_arg(args, char *)) )
838 		yield_len += strlen(p);
839 	va_end(args);
840 
841 	yield = xmalloc(yield_len + 1);
842 	strncpy(yield, str, yield_len);
843 	yield[yield_len] = '\0';
844 	yield_ptr = yield + strlen(yield);
845 
846 	va_start(args, str);
847 	while( (p = va_arg(args, char *)) )
848 	{
849 		strcpy(yield_ptr, p);
850 		yield_ptr += strlen(p);
851 	}
852 	va_end(args);
853 
854 	return yield;
855 }
856 
string_bin_to_hex(char * string,const char * binptr,int binlen)857 void string_bin_to_hex(char *string, const char *binptr, int binlen)
858 {
859 	static const char *hexdigits = "0123456789abcdef";
860 	int i;
861 
862 	for( i = 0; i < binlen; i++ )
863 	{
864 		*string++ = hexdigits[(*binptr >> 4) & 0x0f];
865 		*string++ = hexdigits[(*binptr     ) & 0x0f];
866 		++binptr;
867 	}
868 	*string = '\0';
869 }
870 
string_hex_to_bin(char * binptr,const char * string)871 int string_hex_to_bin(char *binptr, const char *string)
872 {
873 	static const char *hexdigits = "0123456789abcdef";
874 	int len = (int)strlen(string);
875 	int i, val;
876 	const char *p;
877 	char *dest = binptr;
878 
879 	for( i = 0; 2*i < len; i++ )
880 	{
881 		if( (p = string_casechr(hexdigits, *(string++))) )
882 		{
883 			val = (int)(p - hexdigits);
884 			if( (p = string_casechr(hexdigits, *(string++))) )
885 			{
886 				val = val * 16 + (int)(p - hexdigits);
887 				*dest++ = (unsigned char)(val & 0xff);
888 			}
889 			else
890 				return 0;
891 		}
892 		else
893 			return 0;
894 	}
895 
896 	return (int)(dest - binptr);
897 }
898 
string_is_empty(const char * string)899 bool string_is_empty(const char *string)
900 {
901 	const char *p;
902 
903 	for( p = string; *p; p++ )
904 		if( !isspace((int)(unsigned char)*p) )
905 			return FALSE;
906 
907 	return TRUE;
908 }
909 
910 #ifdef TEST
main(void)911 int main(void)
912 {
913 	char *hexstr = "0406ff2354124e6a9b2f6ed6ff00411287";
914 	char binbuf[64];
915 	int binlen;
916 	char newhex[64];
917 
918 	/*
919 	 * string_hex_to_bin() and string_bin_to_hex()
920 	 */
921 	printf("*** Checking string_hex_to_bin() and string_bin_to_hex()\n");
922 	printf("Original string  : \"%s\"\n", hexstr);
923 	binlen = string_hex_to_bin(binbuf, hexstr);
924 	string_bin_to_hex(newhex, binbuf, binlen);
925 	printf("Resulting string : \"%s\"\n", newhex);
926 	if( strcmp(hexstr, newhex) )
927 		printf("<<< ERROR!!! >>>\n");
928 
929 	return 0;
930 }
931 #endif /* TEST */
932 
933