1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <ctype.h>
5 
6 //Commented out to fix Debian bug 377175.
7 //extern char *tzname[2];
8 
9 #include <time.h>
10 #include "../include/os.h"
11 
12 #ifdef __MSW__
13 
14 #else
15 # include <sys/time.h>
16 #endif
17 
18 #include "../include/cfgfmt.h"
19 #include "../include/cs.h"
20 #include "../include/string.h"
21 
22 
23 /* Line Checking */
24 int strlinelen(const char *s);
25 int strlongestline(const char *s);
26 int strlines(const char *s);
27 
28 /* Comparing */
29 #ifdef __MSW__
30 int strcasecmp(const char *s1, const char *s2);
31 #endif
32 #ifndef _GNU_SOURCE
33 char *strcasestr(const char *haystack, const char *needle);
34 #endif /* _GNU_SOURCE not defined */
35 int strpfx(const char *s, const char *pfx);
36 int strcasepfx(const char *s, const char *pfx);
37 
38 /* Editing */
39 char *strinsstr(char *s, int i, const char *s2);
40 char *strinschr(char *s, int i, char c);
41 char *strdelchrs(char *s, int i, int n);
42 char *strdelchr(char *s, int i);
43 void strtoupper(char *s);
44 void strtolower(char *s);
45 char *strcatalloc(char *orig, const char *new_str);
46 void substr(char *s, const char *token, const char *val);
47 #ifndef __MSW__
48 void strset(char *s, char c, int n);
49 #endif
50 void strpad(char *s, int n);
51 void straddflag(char *s, const char *flag, char operation, int len);
52 void strstriplead(char *s);
53 void strstriptail(char *s);
54 void strstrip(char *s);
55 
56 /* Lists */
57 char **strlistinsert(char **strv, int *strc, const char *s, int i);
58 char **strlistappend(char **strv, int *strc, const char *s);
59 char **strlistdelete(char **strv, int *strc, int i);
60 char **strlistcopy(const char **strv, int strc);
61 void strlistfree(char **strv, int strc);
62 
63 /* Sorting */
64 static int SORT(const void *a, const void *b);
65 char **StringQSort(char **strings, int nitems);
66 
67 /* Decorating */
68 char *StringTailSpaces(char *s, int len);
69 void StringShortenFL(char *s, int limit);
70 
71 /* Configuration Checking */
72 int StringIsYes(const char *s);
73 int StringIsComment(const char *s, char c);
74 char *StringCfgParseParm(const char *s);
75 char *StringCfgParseValue(const char *s);
76 
77 /* Value Parsing */
78 int StringParseStdColor(
79 	const char *s,
80 	u_int8_t *r_rtn, u_int8_t *g_rtn, u_int8_t *b_rtn
81 );
82 int StringParseIP(
83 	const char *s,
84 	u_int8_t *c1, u_int8_t *c2, u_int8_t *c3, u_int8_t *c4
85 );
86 
87 /* ShipWars CyberSpace protocol string parsing */
88 int StringGetNetCommand(const char *str);
89 char *StringGetNetArgument(const char *str);
90 
91 /* Time Formatting */
92 char *StringCurrentTimeFormat(const char *format);
93 char *StringTimeFormat(const char *format, time_t seconds);
94 char *StringFormatTimePeriod(time_t seconds);
95 
96 
97 #define ATOI(s)         (((s) != NULL) ? atoi(s) : 0)
98 #define ATOL(s)         (((s) != NULL) ? atol(s) : 0)
99 #define ATOF(s)         (((s) != NULL) ? atof(s) : 0.0f)
100 #define STRDUP(s)       (((s) != NULL) ? strdup(s) : NULL)
101 
102 #define MAX(a,b)        (((a) > (b)) ? (a) : (b))
103 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
104 #define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
105 #define STRLEN(s)       (((s) != NULL) ? strlen(s) : 0)
106 #define STRISEMPTY(s)   (((s) != NULL) ? (*(s) == '\0') : 1)
107 
108 
109 /*
110  *	Returns the length in bytes, of the line s.
111  *	The end point character must be either a '\n', '\r', or
112  *	'\0'.
113  */
strlinelen(const char * s)114 int strlinelen(const char *s)
115 {
116 	int i = 0;
117 
118 
119 	if(s == NULL)
120 	    return(0);
121 
122 	while((*s != '\0') &&
123 	      (*s != '\n') &&
124 	      (*s != '\r')
125 	)
126 	{
127 	    i++;
128 	    s++;
129 	}
130 
131 	return(i);
132 }
133 
134 
135 /*
136  *	Returns the length of the longest line in string s.
137  */
strlongestline(const char * s)138 int strlongestline(const char *s)
139 {
140 	int n, longest = 0;
141 
142 
143 	if(s == NULL)
144 	    return(longest);
145 
146 	while(1)
147 	{
148 	    n = strlinelen(s);
149 
150 	    if(n > longest)
151 		longest = n;
152 
153 	    s += n;
154 
155 	    if(*s == '\0')
156 		break;
157 
158 	    s++;
159 	}
160 
161 	return(longest);
162 }
163 
164 /*
165  *	Returns the number of '\n' or '\r' characters + 1
166  *	in string s.
167  *
168  *	If the first character is '\0' in string s or string s
169  *	is NULL, then 0 will be returned.
170  */
strlines(const char * s)171 int strlines(const char *s)
172 {
173 	int lines = 0;
174 
175 
176 	if(s == NULL)
177 	    return(lines);
178 	if(*s == '\0')
179 	    return(lines);
180 
181 	lines++;	/* Count first line */
182 
183 	/* Iterate through string, counting number of lines */
184 	while(*s != '\0')
185 	{
186 	    if((*s == '\n') || (*s == '\r'))
187 		lines++;
188 	    s++;
189 	}
190 
191 	return(lines);
192 }
193 
194 #ifdef __MSW__
195 /*
196  *	Works just like the UNIX strcasecmp(). Returns 1 for no match
197  *	and 0 for match.
198  */
strcasecmp(const char * s1,const char * s2)199 int strcasecmp(const char *s1, const char *s2)
200 {
201 	if((s1 == NULL) || (s2 == NULL))
202 	    return(1);	/* False */
203 
204 	while(*s1 && *s2)
205 	{
206 	    if(toupper(*s1) != toupper(*s2))
207 		return(1);	/* False */
208 
209 	    s1++;
210 	    s2++;
211 	}
212 	if(*s1 == *s2)
213 	    return(0);	/* True */
214 	else
215 	    return(1);	/* False */
216 }
217 #endif
218 
219 #ifndef _GNU_SOURCE
220 /*
221  *	Case insensitive version of strstr(). Returns the pointer to
222  *	needle in haystack if found or NULL on no match.
223  */
strcasestr(const char * haystack,const char * needle)224 char *strcasestr(const char *haystack, const char *needle)
225 {
226 	const char *strptr1, *strptr2, *strptr3;
227 
228 	if((haystack == NULL) || (needle == NULL))
229 	    return(NULL);
230 
231 	/* Get starting position in haystack as strptr1 */
232 	strptr1 = haystack;
233 	/* Iterate strptr1 in haystack till end of string */
234 	while((*strptr1) != '\0')
235 	{
236 	    strptr2 = needle;	/* Get starting position of needle */
237 
238 	    /* Character in needle and haystack at same position the same
239 	     * (case insensitive ofcourse).
240 	     */
241 	    if(toupper(*strptr1) == toupper(*strptr2))
242 	    {
243 		strptr3 = strptr1;      /* Record starting position */
244 
245 		strptr1++;
246 		strptr2++;
247 
248 		/* Continue iterating through haystack */
249 		while((*strptr1) != '\0')
250 		{
251 		    /* Needle string ended? */
252 		    if((*strptr2) == '\0')
253 		    {
254 			return((char *)strptr3);
255 		    }
256 		    /* Characters differ (case insensitive)? */
257 		    else if(toupper(*strptr1) != toupper(*strptr2))
258 		    {
259 			strptr1++;
260 			break;
261 		    }
262 		    /* Characters are still matching */
263 		    else
264 		    {
265 			strptr1++;
266 			strptr2++;
267 		    }
268 		}
269 		/* End of needle reached, we got a match */
270 		if((*strptr2) == '\0')
271 		    return((char *)strptr3);
272 	    }
273 	    else
274 	    {
275 		strptr1++;
276 	    }
277 	}
278 
279 	return(NULL);
280 }
281 #endif /* _GNU_SOURCE not defined */
282 
283 /*
284  *	Checks if string pfx is a prefix of string s.
285  */
strpfx(const char * s,const char * pfx)286 int strpfx(const char *s, const char *pfx)
287 {
288 	if((s == NULL) || STRISEMPTY(pfx))
289 	    return(0);
290 
291 	/* Iterate through string and pfx to see if all characters
292 	 * match up to the end of pfx
293 	 */
294 	while(*pfx != '\0')
295 	{
296 	    if(*s != *pfx)
297 		return(0);
298 
299 	    s++;
300 	    pfx++;
301 	}
302 
303 	return(1);
304 }
305 
strcasepfx(const char * s,const char * pfx)306 int strcasepfx(const char *s, const char *pfx)
307 {
308 	if((s == NULL) || STRISEMPTY(pfx))
309 	    return(0);
310 
311 	/* Iterate through string and pfx to see if all characters
312 	 * match up to the end of pfx
313 	 */
314 	while(*pfx != '\0')
315 	{
316 	    if(toupper(*s) != toupper(*pfx))
317 		return(0);
318 
319 	    s++;
320 	    pfx++;
321 	}
322 
323 	return(1);
324 }
325 
326 /*
327  *	Inserts string s2 at position i in string s.
328  *
329  *	Returns the new base pointer of s due to realloc().
330  */
strinsstr(char * s,int i,const char * s2)331 char *strinsstr(char *s, int i, const char *s2)
332 {
333 	int slen, dlen = STRLEN(s2);
334 	char *ps, *pt, *pend;
335 	const char *ps2;
336 
337 	if((s == NULL) || (dlen <= 0))
338 	    return(s);
339 
340 	slen = STRLEN(s);
341 
342 	/* Append? */
343 	if(i < 0)
344 	    i = slen;
345 	else if(i > slen)
346 	    i = slen;
347 
348 	/* Increase allocation of string s */
349 	slen += dlen;
350 	s = (char *)realloc(s, (slen + 1) * sizeof(char));
351 	if(s == NULL)
352 	    return(s);
353 
354 	/* Shift string s */
355 	for(pt = s + slen,
356 	    ps = pt - dlen,
357 	    pend = s + i;
358 	    ps >= pend;
359 	    *pt-- = *ps--
360 	);
361 
362 	/* Insert string s2 into string s */
363 	for(pt = s + i,
364 	    ps2 = s2,
365 	    pend = pt + dlen;
366 	    pt < pend;
367 	    *pt++ = *ps2++
368 	);
369 
370 	return(s);
371 }
372 
373 /*
374  *	Inserts character c at position i in string s.
375  *
376  *	Returns the new base pointer of s due to realloc().
377  */
strinschr(char * s,int i,char c)378 char *strinschr(char *s, int i, char c)
379 {
380 	int slen;
381 	char *ps, *pt, *pend;
382 
383 	if(s == NULL)
384 	    return(s);
385 
386 	slen = STRLEN(s);
387 
388 	/* Append? */
389 	if(i < 0)
390 	    i = slen;
391 	else if(i > slen)
392 	    i = slen;
393 
394 	/* Increase allocation of string s */
395 	slen++;
396 	s = (char *)realloc(s, (slen + 1) * sizeof(char));
397 	if(s == NULL)
398 	    return(s);
399 
400 	/* Shift string s */
401 	for(pt = s + slen,
402 	    ps = pt - 1,
403 	    pend = s + i;
404 	    ps >= pend;
405 	    *pt-- = *ps--
406 	);
407 
408 	/* Insert character c into string s */
409 	s[i] = c;
410 
411 	return(s);
412 }
413 
414 /*
415  *	Deletes the specified number of characters at position i in
416  *	string s.
417  *
418  *	Returns the new base pointer of s due to realloc().
419  */
strdelchrs(char * s,int i,int n)420 char *strdelchrs(char *s, int i, int n)
421 {
422 	int slen;
423 	char *ps, *pt, *pend;
424 
425 	if((s == NULL) || (n <= 0))
426 	    return(s);
427 
428 	slen = STRLEN(s);
429 	if(slen <= 0)
430 	    return(s);
431 
432 	if((i < 0) || (i >= slen))
433 	    return(s);
434 
435 	/* Sanitize number of characters to delete */
436 	if((i + n) > slen)
437 	    n = slen - i;
438 
439 	/* Shift string s */
440 	for(pt = s + i,
441 	    ps = pt + n,
442 	    pend = s + slen;
443 	    ps <= pend;
444 	    *pt++ = *ps++
445 	);
446 
447 	/* Decrease allocation of string s */
448 	slen -= n;
449 	if(slen > 0)
450 	{
451 	    s = (char *)realloc(s, (slen + 1) * sizeof(char));
452 	    if(s == NULL)
453 		return(s);
454 	}
455 	else
456 	{
457 	    s = (char *)realloc(s, 1 * sizeof(char));
458 	    if(s == NULL)
459 		return(s);
460 
461 	    *s = '\0';
462 	}
463 	return(s);
464 }
465 
466 /*
467  *	Deletes one character at position i in string s.
468  *
469  *	Returns the new base pointer of s due to realloc().
470  */
strdelchr(char * s,int i)471 char *strdelchr(char *s, int i)
472 {
473 	return(strdelchrs(s, i, 1));
474 }
475 
476 /*
477  *	Sets all characters in string s to upper.
478  */
strtoupper(char * s)479 void strtoupper(char *s)
480 {
481 	if(s == NULL)
482 	    return;
483 
484         /* confuses the compiler
485 	while(*s != '\0')
486 	    *s++ = toupper(*s);
487         */
488         while ( s[0] )
489         {
490            s[0] = toupper(s[0]);
491            s++;
492         }
493 }
494 
495 /*
496  *      Sets all characters in string s to lower.
497  */
strtolower(char * s)498 void strtolower(char *s)
499 {
500 	if(s == NULL)
501 	    return;
502 
503        /* this also confuses the compiler
504 	while(*s != '\0')
505 	    *s++ = tolower(*s);
506        */
507        while ( s[0] )
508        {
509           s[0] = tolower(s[0]);
510           s++;
511        }
512 }
513 
514 /*
515  *	Takes the given string orig and reallocates it with enough
516  *	memory to hold itself and the new string plus a null terminating
517  *	byte at the end.
518  *
519  *	Returns the new pointer which needs to be free()'ed by the calling
520  *	function.
521  *
522  *	The given pointer orig should never be referenced again after this
523  *	call.
524  */
strcatalloc(char * orig,const char * new_str)525 char *strcatalloc(char *orig, const char *new_str)
526 {
527 	int orig_len, new_len, rtn_len;
528 	char *new_rtn = NULL;
529 
530 
531 	/* If new string is NULL, then return original pointer since
532 	 * there is nothing to do
533 	 */
534 	if(new_str == NULL)
535 	    return(orig);
536 
537 	/* Calculate lengths of original and new */
538 	orig_len = (orig != NULL) ? strlen(orig) : 0;
539 	new_len = strlen(new_str);
540 	rtn_len = orig_len + new_len;
541 	if(rtn_len < 0)
542 	    rtn_len = 0;
543 
544 	/* Reallocate string */
545 	new_rtn = (char *)realloc(
546 	    orig,
547 	    (rtn_len + 1) * sizeof(char)
548 	);
549 	if(new_rtn != NULL)
550 	{
551 	    /* If original string was NULL then it means a new string
552 	     * has been allocated so we need to set the first character
553 	     * to null in order to strcat() properly
554 	     */
555 	    if(orig == NULL)
556 		*new_rtn = '\0';
557 
558 	    /* Cat new string to the new return string */
559 	    strcat(new_rtn, new_str);
560 	}
561 
562 	return(new_rtn);
563 }
564 
565 /*
566  *	Substitutes all occurances of string token in string s
567  *	with string val.  String s must have enough capacity for
568  *	all substitutions.
569  *
570  *	Example: substr("Hi there %name!", "%name", "Kattie")
571  *	Turns into: "Hi there Kattie!"
572  */
substr(char * s,const char * token,const char * val)573 void substr(char *s, const char *token, const char *val)
574 {
575 	int i, tl, vl;
576 	char *strptr1, *strptr2, *strptr3, *strptr4;
577 
578 
579 	if((s == NULL) ||
580 	   (token == NULL)
581 	)
582 	    return;
583 
584 	if(val == NULL)
585 	    val = "";
586 
587 	/* Token string must not be empty */
588 	if(*token == '\0')
589 	    return;
590 
591 	/* Token and value strings may not have the same content */
592 	if(!strcmp(val, token))
593 	    return;
594 
595 	/* Get lengths of token and value strings */
596 	tl = strlen(token);
597 	vl = strlen(val);
598 
599 	/* Set strptr1 to begining of string s */
600 	strptr1 = s;
601 
602 	/* Begin substituting */
603 	while(1)
604 	{
605 	    /* Seek next instance of token string */
606 	    strptr1 = strstr(strptr1, token);
607 	    if(strptr1 == NULL)
608 		break;
609 
610 	    /* Calculate end pointer of strptr1 */
611 	    i = strlen(strptr1);
612 	    strptr2 = strptr1 + i;
613 
614 	    if(tl > vl)
615 	    {
616 		/* Token string is longer than value string */
617 
618 		/* Calculate starting pointer positions */
619 		strptr3 = strptr1 + vl;
620 		strptr4 = strptr1 + tl;
621 
622 		/* Shift tailing portion of string */
623 		while(strptr4 <= strptr2)
624 		    *strptr3++ = *strptr4++;
625 	    }
626 	    else if(tl < vl)
627 	    {
628 		/* Token string is less than value string */
629 
630 		/* Calculate starting pointer positions */
631 		strptr3 = strptr2;
632 		strptr4 = strptr2 + vl - tl;
633 
634 		/* Shift tailing portion of string */
635 		while(strptr3 > strptr1)
636 		    *strptr4-- = *strptr3--;
637 	    }
638 
639 	    memcpy(strptr1, val, vl);
640 
641 	    /* Increment strptr1 past length of value */
642 	    strptr1 = strptr1 + vl;
643 	}
644 }
645 
646 #ifndef __MSW__
647 /*
648  *	Sets the first n characters of string s to be the
649  *	value of c.  A null character will be tacked on at the end.
650  *
651  *	String s must have enough storage for n characters plus the
652  *	null terminating character tacked on at the end.
653  */
strset(char * s,char c,int n)654 void strset(char *s, char c, int n)
655 {
656 	int i;
657 
658 
659 	if(s == NULL)
660 	    return;
661 
662 	for(i = 0; i < n; i++)
663 	    s[i] = c;
664 
665 	s[i] = '\0';
666 
667 	return;
668 }
669 #endif
670 
671 #ifndef __MSW__
672 /*
673  *	Same as strset(), except always sets the first n characters
674  *	of string s to the ' ' character. Tacks on a null terminating
675  *	character at the end.
676  */
strpad(char * s,int n)677 void strpad(char *s, int n)
678 {
679 	strset(s, ' ', n);
680 
681 	return;
682 }
683 #endif
684 
685 /*
686  *      Concatonates flag string, putting in the operation character
687  *      if there is one or more flags already existing in s.
688  *
689  *      "Close | Open" "Inventory" '|'
690  *
691  *      Becomes:
692  *
693  *      "Close | Open | Inventory"
694  *	Dan S: Renaming arg 3 from "operator" to "operation", "operator" is a C+ key word.
695  */
straddflag(char * s,const char * flag,char operation,int len)696 void straddflag(char *s, const char *flag, char operation, int len)
697 {
698 	int s_len, flag_len;
699 
700 	if(STRISEMPTY(s) || STRISEMPTY(flag) || (len <= 0))
701 	    return;
702 
703 	s_len = STRLEN(s);
704 	flag_len = STRLEN(flag);
705 
706 	/* Put operation after last flag if there is one */
707 	if((s_len > 0) &&
708 	   ((len - s_len) > 3)
709 	)
710 	{
711 	    int i;
712 
713 	    i = s_len;
714 
715 	    s[i] = ' '; i++;
716 	    s[i] = operation; i++;
717 	    s[i] = ' '; i++;
718 	    s[i] = '\0';
719 
720 	    s_len += 3;
721 	}
722 
723 	/* Append flag string */
724 	if((len - s_len - 1) > 0)
725 	    strncat(s, flag, len - s_len - 1);
726 
727 	s[len - 1] = '\0';
728 }
729 
730 /*
731  *	Strips leading blank characters.
732  */
strstriplead(char * s)733 void strstriplead(char *s)
734 {
735 	char *s2 = s;
736 
737 	if(STRISEMPTY(s))
738 	    return;
739 
740 	while(ISBLANK(*s2))
741 	    s2++;
742 
743 	if(s2 == s)
744 	    return;
745 
746 	while(*s2 != '\0')
747 	    *s++ = *s2++;
748 	*s = *s2;
749 }
750 
751 /*
752  *	Strips tailing blank characters.
753  */
strstriptail(char * s)754 void strstriptail(char *s)
755 {
756 	char *s2;
757 
758 	if(STRISEMPTY(s))
759 	    return;
760 
761 	s2 = s + STRLEN(s) - 1;
762 	while(s2 >= s)
763 	{
764 	    if(!ISBLANK(*s2))
765 		break;
766 	    s2--;
767 	}
768 	s2++;
769 	*s2 = '\0';
770 }
771 
772 /*
773  *	Strips leading and tailing blank characters.
774  */
strstrip(char * s)775 void strstrip(char *s)
776 {
777 	strstriplead(s);
778 	strstriptail(s);
779 }
780 
781 
782 /*
783  *	Inserts string s into the string list at index i.
784  */
strlistinsert(char ** strv,int * strc,const char * s,int i)785 char **strlistinsert(char **strv, int *strc, const char *s, int i)
786 {
787 	if(strc == NULL)
788 	    return(NULL);
789 
790 	/* Append? */
791 	if(i < 0)
792 	{
793 	    i = MAX(*strc, 0);
794 	    *strc = i + 1;
795 	    strv = (char **)realloc(strv, (*strc) * sizeof(char *));
796 	    if(strv == NULL)
797 	    {
798 		*strc = 0;
799 		return(strv);
800 	    }
801 	    strv[i] = STRDUP(s);
802 	}
803 	else
804 	{
805 	    int n = MAX(*strc, 0);
806 	    *strc = n + 1;
807 	    strv = (char **)realloc(strv, (*strc) * sizeof(char *));
808 	    if(strv == NULL)
809 	    {
810 		*strc = 0;
811 		return(strv);
812 	    }
813 
814 	    if(i > n)
815 		i = n;
816 
817 	    for(; n > i; n--)
818 		strv[n] = strv[n - 1];
819 
820 	    strv[i] = STRDUP(s);
821 	}
822 
823 	return(strv);
824 }
825 
826 /*
827  *      Appends string s to the string list.
828  */
strlistappend(char ** strv,int * strc,const char * s)829 char **strlistappend(char **strv, int *strc, const char *s)
830 {
831 	return(strlistinsert(strv, strc, s, -1));
832 }
833 
834 /*
835  *      Deletes the string at index i in the string list.
836  */
strlistdelete(char ** strv,int * strc,int i)837 char **strlistdelete(char **strv, int *strc, int i)
838 {
839 	int n;
840 
841 	if((i < 0) || (i >= *strc))
842 	    return(strv);
843 
844 	/* Reduce total */
845 	*strc = (*strc) - 1;
846 
847 	/* Delete string */
848 	free(strv[i]);
849 
850 	/* Shift pointers */
851 	for(n = i; n < *strc; n++)
852 	    strv[n] = strv[n + 1];
853 
854 	/* Reduce allocation of string list pointer array */
855 	if(*strc > 0)
856 	{
857 	    strv = (char **)realloc(strv, (*strc) * sizeof(char *));
858 	    if(strv == NULL)
859 	    {
860 		*strv = 0;
861 	    }
862 	}
863 	else
864 	{
865 	    free(strv);
866 	    strv = NULL;
867 	    *strc = 0;
868 	}
869 
870 	return(strv);
871 }
872 
873 /*
874  *	Coppies the string list.
875  */
strlistcopy(const char ** strv,int strc)876 char **strlistcopy(const char **strv, int strc)
877 {
878 	char **strv2 = (char **)(
879 	    (strc > 0) ? malloc(strc * sizeof(char *)) : NULL
880 	);
881 	if(strv2 != NULL)
882 	{
883 	    int i;
884 	    for(i = 0; i < strc; i++)
885 		strv2[i] = STRDUP(strv[i]);
886 	}
887 	return(strv2);
888 }
889 
890 
891 /*
892  *	Deletes the string list.
893  */
strlistfree(char ** strv,int strc)894 void strlistfree(char **strv, int strc)
895 {
896 	int i;
897 
898 	for(i = 0; i < strc; i++)
899 	    free(strv[i]);
900 	free(strv);
901 }
902 
903 
904 /*
905  *	Used by StringQSort().
906  */
SORT(const void * a,const void * b)907 static int SORT(const void *a, const void *b)
908 {
909 	char *x, *y;
910 	x = *((char **)a);
911 	y = *((char **)b);
912 	return(strcmp(x, y));
913 }
914 
915 /*
916  *	Sorts given string array strings using the qsort() method.
917  *
918  *	Returns NULL on error and strings on success.
919  */
StringQSort(char ** strings,int nitems)920 char **StringQSort(char **strings, int nitems)
921 {
922 	if((strings == NULL) || (nitems <= 0))
923 	    return(NULL);
924 
925 	qsort(strings, nitems, sizeof(char *), SORT);
926 
927 	return(strings);
928 }
929 
930 
931 /*
932  *	Puts space characters at the end of the given string's current
933  *	contents up to the specified length len.
934  *
935  *	The allocation of string must be len + 1.
936  */
StringTailSpaces(char * s,int len)937 char *StringTailSpaces(char *s, int len)
938 {
939 	int i, prev_len;
940 
941 	if(s == NULL)
942 	    return(s);
943 
944 	s[len] = '\0';
945 	prev_len = STRLEN(s);
946 
947 	for(i = prev_len; i < len; i++)
948 	    s[i] = ' ';
949 
950 	return(s);
951 }
952 
953 
954 /*
955  *      Shortens string to number of characters specified by limit.
956  *
957  *      If the limit is greater than 3 then "..." is prepended to s.
958  *
959  *      If length of string is <= to limit, then nothing is done.
960  *
961  *	Example (limit=10):
962  *
963  *	"Hello there kitty!" becomes "... kitty!"
964  */
StringShortenFL(char * s,int limit)965 void StringShortenFL(char *s, int limit)
966 {
967 	int ol;
968 
969 	if(STRISEMPTY(s))
970 	    return;
971 
972 	if(limit < 0)
973 	{
974 	    if(*s != '\0')
975 		*s = '\0';
976 	    return;
977 	}
978 
979 	ol = STRLEN(s);
980 	if(ol > limit)
981 	{
982 	    char	*s1 = s,
983 			*s2 = &s[ol - limit];
984 
985 	    while(*s2 != '\0')
986 		*s1++ = *s2++;
987 
988 	    if(limit >= 3)
989 	    {
990 		s1 = s;
991 		s2 = &s[3];
992 		while(s1 < s2)
993 		    *s1++ = '.';
994 	   }
995 
996 	    s[limit] = '\0';
997 	}
998 }
999 
1000 
1001 /*
1002  *	Checks if the string is a "yes" (and standard variations
1003  *	accepted and checked as well).
1004  */
StringIsYes(const char * s)1005 int StringIsYes(const char *s)
1006 {
1007 	if(STRISEMPTY(s))
1008 	    return(0);
1009 
1010 	while(ISBLANK(*s))
1011 	    s++;
1012 
1013 	/* Is first char a number from 0 to 9 (for "0" or "1")? */
1014 	if(isdigit(*s))
1015 	{
1016 	    if(*s != '0')
1017 		return(1);
1018 	    else
1019 		return(0);
1020 	}
1021 	/* Is first char a 'o'? (for "on" or "off") */
1022 	else if(toupper(s[0]) == 'O')
1023 	{
1024 	    /* Check second char, is it an 'n'? */
1025 	    if(toupper(s[1]) == 'N')
1026 		return(1);
1027 	    else
1028 		return(0);
1029 	}
1030 	/* All else check first char for "yes" or "no" */
1031 	else
1032 	{
1033 	    if(toupper(s[0]) == 'Y')
1034 	        return(1);
1035 	    else
1036 	        return(0);
1037 	}
1038 }
1039 
1040 /*
1041  *	Returns true if string is a comment in accordance with
1042  *	the UNIX configuration file format.
1043  *
1044  *	The comment character c should be
1045  *	(but does not have to be) UNIXCFG_COMMENT_CHAR.
1046  */
StringIsComment(const char * s,char c)1047 int StringIsComment(const char *s, char c)
1048 {
1049 	if(STRISEMPTY(s))
1050 	    return(0);
1051 
1052 	while(ISBLANK(*s))
1053 	    s++;
1054 
1055 	return((*s == c) ? 1 : 0);
1056 }
1057 
1058 /*
1059  *	Returns the parameter section of string which should comform to
1060  *	the standard configuration format of "<parameter>=<value>" as
1061  *	a statically allocated string or NULL on error.
1062  */
StringCfgParseParm(const char * s)1063 char *StringCfgParseParm(const char *s)
1064 {
1065 	int x, y, got_parm_start;
1066 	static char parameter[CFG_PARAMETER_MAX];
1067 
1068 
1069 	if(s == NULL)
1070 	    return(NULL);
1071 
1072 	if((*s == '\0') || (*s == '\r') || (*s == '\n'))
1073 	    return(NULL);
1074 
1075 	/* Is comment? */
1076 	if(StringIsComment(s, UNIXCFG_COMMENT_CHAR))
1077 	    return(NULL);
1078 
1079 	/* Begin fetching parameter from string */
1080 	got_parm_start = 0;
1081 	for(x = 0, y = 0;
1082 	    (x < CFG_STRING_MAX) && (y < CFG_PARAMETER_MAX);
1083 	    x++
1084 	)
1085 	{
1086 	    /* Skip newline escape sequences */
1087 	    if((s[x] == '\\') &&
1088 	       ((x + 1) < CFG_STRING_MAX)
1089 	    )
1090 	    {
1091 		if((s[x + 1] == '\n') || (s[x + 1] == '\r'))
1092 	        {
1093 		    x++;
1094 	            continue;
1095 	        }
1096 	    }
1097 
1098 	    /* Skip other escape sequences */
1099 	    if(s[x] == '\\')
1100 	    {
1101 		x++;
1102 		if(x >= CFG_STRING_MAX)
1103 		    break;
1104 	    }
1105 
1106 
1107 	    /* End on NULL, new line, or delimiter */
1108 	    if((s[x] == '\0') ||
1109 	       (s[x] == '\r') ||
1110 	       (s[x] == '\n') ||
1111 	       (s[x] == CFG_PARAMETER_DELIMITER)
1112 	    )
1113 	    {
1114 		parameter[y] = '\0';
1115 		break;
1116 	    }
1117 
1118 	    if(got_parm_start == 0)
1119 	    {
1120 		if((s[x] == ' ') ||
1121 		   (s[x] == '\t')
1122 		)
1123 		    continue;
1124 		else
1125 		    got_parm_start = 1;
1126 	    }
1127 
1128 	    parameter[y] = s[x];
1129 	    y++;
1130 	}
1131 
1132 	/* Null terminate parameter */
1133 	parameter[sizeof(parameter) - 1] = '\0';
1134 	strstrip(parameter);
1135 
1136 	return(parameter);
1137 }
1138 
1139 /*
1140  *      Returns the value section of string which should comform to
1141  *      the standard configuration format of "<parameter>=<value>".
1142  *
1143  *      The returned string will never be NULL and will be striped of
1144  *      tailing or leading spaces.
1145  */
StringCfgParseValue(const char * s)1146 char *StringCfgParseValue(const char *s)
1147 {
1148 	int x, y, got_value;
1149 	static char value[CFG_VALUE_MAX];
1150 
1151 
1152 	*value = '\0';
1153 
1154 	if(s == NULL)
1155 	    return(value);
1156 
1157 	if((*s == '\0') || (*s == '\r') || (*s == '\n'))
1158 	    return(value);
1159 
1160 	/* Is s a comment? */
1161 	if(StringIsComment(s, UNIXCFG_COMMENT_CHAR))
1162 	    return(value);
1163 
1164 	/* Does not have a delimiter? */
1165 	if(strchr(s, CFG_PARAMETER_DELIMITER) == NULL)
1166 	    return(value);
1167 
1168 
1169 	/* Begin fetching value from string */
1170 	got_value = 0;
1171 	for(x = 0, y = 0;
1172 	    (x < CFG_STRING_MAX) && (y < CFG_VALUE_MAX);
1173 	    x++
1174 	)
1175 	{
1176 	    /* Skip newline escape sequences */
1177 	    if((s[x] == '\\') &&
1178 	       ((x + 1) < CFG_STRING_MAX)
1179 	    )
1180 	    {
1181 		if((s[x + 1] == '\n') || (s[x + 1] == '\r'))
1182 		{
1183 		    x++;
1184 		    continue;
1185 		}
1186 	    }
1187 
1188 	    /* Skip other escape sequences */
1189 	    if(s[x] == '\\')
1190 	    {
1191 		x++;
1192 		if(x >= CFG_STRING_MAX)
1193 		    break;
1194 	    }
1195 
1196 	    /* Stop on newline or NULL */
1197 	    if((s[x] == '\0') ||
1198 	       (s[x] == '\r') ||
1199 	       (s[x] == '\n')
1200 	    )
1201 	    {
1202 		value[y] = '\0';
1203 		break;
1204 	    }
1205 
1206 	    if(got_value == 0)
1207 	    {
1208 		if(s[x] == CFG_PARAMETER_DELIMITER)
1209 		{
1210 		    got_value = 1;
1211 		    continue;
1212 		}
1213 		else
1214 		{
1215 		    continue;
1216 		}
1217 	    }
1218 
1219 
1220 	    value[y] = s[x];
1221 	    y++;
1222 	}
1223 
1224 	/* Null terminate value */
1225 	value[sizeof(value) - 1] = '\0';
1226 	strstrip(value);
1227 
1228 	return(value);
1229 }
1230 
1231 /*
1232  *	Parses a standard color string "#rrggbb" where rr, gg,
1233  *	and bb are in hexidecimal notation.
1234  *
1235  *	Returns 0 on success, -1 on general error, and
1236  *	-2 for incomplete or ambiguous.
1237  */
StringParseStdColor(const char * s,u_int8_t * r_rtn,u_int8_t * g_rtn,u_int8_t * b_rtn)1238 int StringParseStdColor(
1239 	const char *s,
1240 	u_int8_t *r_rtn,
1241 	u_int8_t *g_rtn,
1242 	u_int8_t *b_rtn
1243 )
1244 {
1245 	int i, r = 0, g = 0, b = 0;
1246 
1247 	if(s == NULL)
1248 	    return(-1);
1249 
1250 	/* Red */
1251 	while((*s == '#') || ISBLANK(*s))
1252 	    s++;
1253 	if(!*s)
1254 	    return(-2);
1255 
1256 	i = 0;
1257 	while(isxdigit(*s) && (i < 2))
1258 	{
1259 	    if(isdigit(*s))
1260 		r = (r << 4) + (*s - '0');
1261 	    else
1262 		r = (r << 4) + (tolower(*s) - 'a' + 10);
1263 
1264 	    i++; s++;
1265 	}
1266 	if(r_rtn != NULL)
1267 	    *r_rtn = (u_int8_t)r;
1268 
1269 	/* Green */
1270 	i = 0;
1271 	while(isxdigit(*s) && (i < 2))
1272 	{
1273 	    if(isdigit(*s))
1274 		g = (g << 4) + (*s - '0');
1275 	    else
1276 		g = (g << 4) + (tolower(*s) - 'a' + 10);
1277 
1278 	    i++; s++;
1279 	}
1280 	if(g_rtn != NULL)
1281 	    *g_rtn = (u_int8_t)g;
1282 
1283 	/* Blue */
1284 	i = 0;
1285 	while(isxdigit(*s) && (i < 2))
1286 	{
1287 	    if(isdigit(*s))
1288 		b = (b << 4) + (*s - '0');
1289 	    else
1290 		b = (b << 4) + (tolower(*s) - 'a' + 10);
1291 
1292 	    i++; s++;
1293 	}
1294 	if(b_rtn != NULL)
1295 	    *b_rtn = (u_int8_t)b;
1296 
1297 	return(0);
1298 }
1299 
1300 /*
1301  *	Parse IP address.
1302  *
1303  *      Returns 0 on success, -1 on general error, and
1304  *      -2 for incomplete or ambiguous.
1305  */
StringParseIP(const char * s,u_int8_t * c1,u_int8_t * c2,u_int8_t * c3,u_int8_t * c4)1306 int StringParseIP(
1307 	const char *s,
1308 	u_int8_t *c1, u_int8_t *c2, u_int8_t *c3, u_int8_t *c4
1309 )
1310 {
1311 	const char *cstrptr;
1312 	char *strptr;
1313 	char ls[4];
1314 
1315 
1316 	if(s == NULL)
1317 	    return(-1);
1318 
1319 	while(ISBLANK(*s))
1320 	    s++;
1321 
1322 	if(*s == '\0')
1323 	    return(-2);
1324 
1325 	/* First number */
1326 	if(c1 != NULL)
1327 	{
1328 	    strncpy(ls, s, 4); ls[3] = '\0';
1329 
1330 	    strptr = strchr(ls, '.');
1331 	    if(strptr != NULL)
1332 		(*strptr) = '\0';
1333 
1334 	    (*c1) = (u_int8_t)atoi(ls);
1335 	}
1336 	cstrptr = strchr(s, '.');
1337 	if(cstrptr == NULL)
1338 	    return(-2);
1339 	s = cstrptr + 1;
1340 
1341 	/* Second number */
1342 	if(c2 != NULL)
1343 	{
1344 	    strncpy(ls, s, 4); ls[3] = '\0';
1345 
1346 	    strptr = strchr(ls, '.');
1347 	    if(strptr != NULL)
1348 		(*strptr) = '\0';
1349 
1350 	    (*c2) = (u_int8_t)atoi(ls);
1351 	}
1352 	cstrptr = strchr(s, '.');
1353 	if(cstrptr == NULL)
1354 	    return(-2);
1355 	s = cstrptr + 1;
1356 
1357 	/* Third number */
1358 	if(c3 != NULL)
1359 	{
1360 	    strncpy(ls, s, 4); ls[3] = '\0';
1361 
1362 	    strptr = strchr(ls, '.');
1363 	    if(strptr != NULL)
1364 		(*strptr) = '\0';
1365 
1366 	    (*c3) = (u_int8_t)atoi(ls);
1367 	}
1368 	cstrptr = strchr(s, '.');
1369 	if(cstrptr == NULL)
1370 	    return(-2);
1371 	s = cstrptr + 1;
1372 
1373 	/* Fourth number */
1374 	if(c4 != NULL)
1375 	{
1376 	    strncpy(ls, s, 4); ls[3] = '\0';
1377 
1378 	    strptr = strchr(ls, ' ');	/* Last, look for a space */
1379 	    if(strptr != NULL)
1380 		(*strptr) = '\0';
1381 
1382 	    (*c4) = (u_int8_t)atoi(ls);
1383 	}
1384 
1385 	return(0);
1386 }
1387 
1388 
1389 /*
1390  *	ShipWars CS protocol command parsing.
1391  */
StringGetNetCommand(const char * str)1392 int StringGetNetCommand(const char *str)
1393 {
1394 	char *strptr;
1395 	static char cmd_str[CS_DATA_MAX_LEN];
1396 
1397 	if(str == NULL)
1398 	    return(-1);
1399 
1400 	strncpy(cmd_str, str, CS_DATA_MAX_LEN);
1401 	cmd_str[CS_DATA_MAX_LEN - 1] = '\0';
1402 
1403 	/* Get command */
1404 	strptr = strchr(cmd_str, ' ');
1405 	if(strptr != NULL)
1406 	    *strptr = '\0';
1407 
1408 	return(atoi(cmd_str));
1409 }
1410 
1411 /*
1412  *	ShipWars CS protocol argument parsing.
1413  *
1414  *	Returns the argument from str with spaces stripped.
1415  *	This function never returns NULL.
1416  */
StringGetNetArgument(const char * str)1417 char *StringGetNetArgument(const char *str)
1418 {
1419 	char *strptr;
1420 	static char arg[CS_DATA_MAX_LEN];
1421 
1422 	if(str == NULL)
1423 	    return("");
1424 
1425 	strncpy(arg, str, CS_DATA_MAX_LEN);
1426 	arg[CS_DATA_MAX_LEN - 1] = '\0';
1427 
1428 	/* Get argument */
1429 	strptr = strchr(arg, ' ');
1430 	if(strptr != NULL)
1431 	{
1432 	    strptr += 1;
1433 	    strstrip(strptr);
1434 	    return(strptr);
1435 	}
1436 
1437 	return("");
1438 }
1439 
1440 
1441 #ifndef MAX_TIME_STR
1442 # define MAX_TIME_STR	256
1443 #endif
1444 
1445 /*
1446  *	Returns a formatted time string in accordance with given format
1447  *	format and returns the statically allocated string.
1448  *
1449  *	This function will never return NULL.
1450  */
StringCurrentTimeFormat(const char * format)1451 char *StringCurrentTimeFormat(const char *format)
1452 {
1453 	size_t len;
1454 	time_t current;
1455 	struct tm *tm_ptr;
1456 	static char s[MAX_TIME_STR];
1457 
1458 
1459 	if(format == NULL)
1460 	    return("");
1461 	if((*format) == '\0')
1462 	    return("");
1463 
1464 	/* Get current time */
1465 	time(&current);
1466 	tm_ptr = localtime(&current);
1467 	if(tm_ptr == NULL)
1468 	    return("");
1469 
1470 	/* Format time string */
1471 	len = strftime(s, sizeof(s), format, tm_ptr);
1472 	if(len >= sizeof(s))
1473 	    len = sizeof(s) - 1;
1474 	if(len < 0)
1475 	    len = 0;
1476 	/* Null terminate */
1477 	s[len] = '\0';
1478 
1479 	return(s);
1480 }
1481 
1482 /*
1483  *	Returns statically allocated string containing formatted
1484  *	values.
1485  */
StringTimeFormat(const char * format,time_t seconds)1486 char *StringTimeFormat(const char *format, time_t seconds)
1487 {
1488 	size_t len;
1489 	struct tm *tm_ptr;
1490 	static char s[MAX_TIME_STR];
1491 
1492 	*s = '\0';
1493 
1494 	if(STRISEMPTY(format))
1495 	    return(s);
1496 
1497 	tm_ptr = localtime(&seconds);
1498 	if(tm_ptr == NULL)
1499 	    return(s);
1500 
1501 	/* Format time string */
1502 	len = strftime(s, sizeof(s), format, tm_ptr);
1503 	if(len >= sizeof(s))
1504 	    len = sizeof(s) - 1;
1505 	if(len < 0)
1506 	    len = 0;
1507 	/* Null terminate */
1508 	s[len] = '\0';
1509 
1510 	return(s);
1511 }
1512 
1513 /*
1514  *	Returns a statically allocated string containing a verbose
1515  *	statement of the delta time seconds.
1516  */
StringFormatTimePeriod(time_t seconds)1517 char *StringFormatTimePeriod(time_t seconds)
1518 {
1519 	static char s[MAX_TIME_STR];
1520 
1521 	*s = '\0';
1522 
1523 	if(seconds < 60)
1524 	{
1525 	    sprintf(s, "%ld sec%s",
1526 		seconds,
1527 		((seconds > 1) ? "s" : "")
1528 	    );
1529 	}
1530 	else if(seconds < 3600)
1531 	{
1532 	    seconds = seconds / 60;
1533 	    sprintf(s, "%ld min%s",
1534 		seconds,
1535 		((seconds > 1) ? "s" : "")
1536 	    );
1537 	}
1538 	else if(seconds < 86400)
1539 	{
1540 	    seconds = seconds / 3600;
1541 	    sprintf(s, "%ld hour%s",
1542 		seconds,
1543 		((seconds > 1) ? "s" : "")
1544 	    );
1545 	}
1546 	else
1547 	{
1548 	    seconds = seconds / 86400;
1549 	    sprintf(s, "%ld day%s",
1550 		seconds,
1551 		((seconds > 1) ? "s" : "")
1552 	    );
1553 	}
1554 
1555 	s[sizeof(s) - 1] = '\0';
1556 
1557 	return(s);
1558 }
1559 
1560 
1561 
1562 
1563