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(¤t);
1466 tm_ptr = localtime(¤t);
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