comparison th_string.c @ 0:728243125263

Import.
author Matti Hamalainen <ccr@tnsp.org>
date Thu, 20 Mar 2008 00:15:03 +0000
parents
children ecfa4e3597e3
comparison
equal deleted inserted replaced
-1:000000000000 0:728243125263
1 /*
2 * Miscellaneous string-handling related utility-functions
3 * Programmed and designed by Matti 'ccr' Hamalainen
4 * (C) Copyright 2002-2008 Tecnic Software productions (TNSP)
5 *
6 * Please read file 'COPYING' for information on license and distribution.
7 */
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11 #include "th_string.h"
12
13 #define LPREV (pNode->pPrev)
14 #define LNEXT (pNode->pNext)
15
16 /* Allocate memory for a string with given length
17 */
18 char_t *th_stralloc(const size_t l)
19 {
20 assert(l > 0);
21 return th_malloc(sizeof(char_t) * l);
22 }
23
24
25 char_t *th_strrealloc(char_t * s, const size_t l)
26 {
27 assert(l > 0);
28 return th_realloc(s, sizeof(char_t) * l);
29 }
30
31
32 /* Calculate the length of a string [strlen]
33 */
34 size_t th_strlen(char_t * pStr)
35 {
36 size_t l = 0;
37 char_t *s = pStr;
38 assert(pStr);
39
40 while (*s) {
41 s++;
42 l++;
43 }
44
45 return l;
46 }
47
48
49 /* Duplicate a string [strdup]
50 */
51 char_t *th_strdup(char_t * pStr)
52 {
53 char_t *pResult, *s, *d;
54
55 if (!pStr) return NULL;
56
57 /* Allocate memory for destination */
58 pResult = th_stralloc(th_strlen(pStr) + 1);
59 if (!pResult)
60 return NULL;
61
62 /* Copy to the destination */
63 s = pStr;
64 d = pResult;
65 while (*s) {
66 *(d++) = *(s++);
67 }
68 *d = 0;
69
70 return pResult;
71 }
72
73
74 /* Concatenate a string [strcat]
75 */
76 char_t *th_strcat(char_t * pDest, char_t * pSource)
77 {
78 char_t *s, *d;
79 assert(pSource);
80 assert(pDest);
81
82 /* Copy to the destination */
83 s = pSource;
84 d = pDest;
85
86 while (*d) d++;
87
88 while (*s) {
89 *(d++) = *(s++);
90 }
91 *d = 0;
92
93 return pDest;
94 }
95
96
97 /* Copy a string [strcpy, strncpy]
98 */
99 char_t *th_strcpy(char_t * pDest, char_t * pSource)
100 {
101 char_t *s, *d;
102 assert(pSource);
103 assert(pDest);
104
105 /* Copy to the destination */
106 s = pSource;
107 d = pDest;
108
109 while (*s) {
110 *(d++) = *(s++);
111 }
112 *d = 0;
113
114 return pDest;
115 }
116
117
118 char_t *th_strncpy(char_t * pDest, char_t * pSource, size_t n)
119 {
120 char_t *s, *d;
121 size_t i;
122 assert(pSource);
123 assert(pDest);
124
125 /* Copy to the destination */
126 i = n;
127 s = pSource;
128 d = pDest;
129 while (*s && (i > 0)) {
130 *(d++) = *(s++);
131 i--;
132 }
133
134 /* Fill rest of space with zeros */
135 while (i > 0) {
136 *(d++) = 0;
137 i--;
138 }
139
140 /* Ensure that last is always zero */
141 pDest[n - 1] = 0;
142
143 return pDest;
144 }
145
146
147 /* Compare given strings [strcmp, strncmp]
148 */
149 int th_strcmp(char_t * pStr1, char_t * pStr2)
150 {
151 char_t *s1, *s2;
152 assert(pStr1);
153 assert(pStr2);
154
155 /* Check the string pointers */
156 if (pStr1 == pStr2)
157 return 0;
158
159 /* Go through the string */
160 s1 = pStr1;
161 s2 = pStr2;
162 while (*s1 && *s2 && (*s1 == *s2)) {
163 s1++;
164 s2++;
165 }
166
167 return ((*s1) - (*s2));
168 }
169
170
171 int th_strncmp(char_t * pStr1, char_t * pStr2, size_t n)
172 {
173 char_t *s1, *s2;
174 assert(pStr1);
175 assert(pStr2);
176
177 /* Check the string pointers */
178 if (pStr1 == pStr2)
179 return 0;
180
181 /* Go through the string */
182 s1 = pStr1;
183 s2 = pStr2;
184 while ((n > 0) && *s1 && *s2 && (*s1 == *s2)) {
185 s1++;
186 s2++;
187 n--;
188 }
189
190 if (n > 0)
191 return ((*s1) - (*s2));
192 else
193 return 0;
194 }
195
196
197 /* Compare two strings ignoring case [strcasecmp, strncasecmp]
198 */
199 int th_strcasecmp(char_t * pStr1, char_t * pStr2)
200 {
201 char_t *s1, *s2;
202 assert(pStr1);
203 assert(pStr2);
204
205 /* Check the string pointers */
206 if (pStr1 == pStr2)
207 return 0;
208
209 /* Go through the string */
210 s1 = pStr1;
211 s2 = pStr2;
212 while (*s1 && *s2 && (th_tolower(*s1) == th_tolower(*s2))) {
213 s1++;
214 s2++;
215 }
216
217 return (th_tolower(*s1) - th_tolower(*s2));
218 }
219
220
221 int th_strncasecmp(char_t * pStr1, char_t * pStr2, size_t n)
222 {
223 char_t *s1, *s2;
224 assert(pStr1);
225 assert(pStr2);
226
227 /* Check the string pointers */
228 if (pStr1 == pStr2)
229 return 0;
230
231 /* Go through the string */
232 s1 = pStr1;
233 s2 = pStr2;
234 while ((n > 0) && *s1 && *s2 && (th_tolower(*s1) == th_tolower(*s2))) {
235 s1++;
236 s2++;
237 n--;
238 }
239
240 if (n > 0)
241 return (th_tolower(*s1) - th_tolower(*s2));
242 else
243 return 0;
244 }
245
246
247 /* Remove all occurences of control characters, in-place.
248 * Resulting string is always shorter or same length than original.
249 */
250 void th_strip_ctrlchars(char_t * pStr)
251 {
252 char_t *i, *j;
253 assert(pStr);
254
255 i = pStr;
256 j = pStr;
257 while (*i) {
258 if (!th_iscntrl(*i))
259 *(j++) = *i;
260 i++;
261 }
262
263 *j = 0;
264 }
265
266
267 /* Locate a substring [strstr]
268 */
269 char_t *th_strstr(char_t * haystack, char_t * needle)
270 {
271 char_t *h, *n, *s;
272 assert(haystack);
273 assert(needle);
274
275 /* If 'needle' is empty, we return 'haystack' */
276 if (!*needle)
277 return haystack;
278
279 /* Search for 'needle' in 'haystack' */
280 h = haystack;
281 n = needle;
282 while (*h) {
283 /* Find possible start of 'needle' */
284 while (*h && (*h != *n))
285 h++;
286
287 if (*h == *n) {
288 /* Found, check rest */
289 s = h;
290 n = needle;
291 while (*h) {
292 if (!*n)
293 return s;
294 else
295 if (*h != *n)
296 break;
297 n++;
298 h++;
299 }
300 h = s;
301 h++;
302 }
303 }
304
305 return NULL;
306 }
307
308
309 /* Copy a given string over in *ppResult.
310 */
311 int th_pstrcpy(char_t ** ppResult, char_t * pStr)
312 {
313 assert(ppResult);
314
315 /* Check the string pointers */
316 if (!pStr)
317 return -1;
318
319 /* Allocate memory for destination */
320 th_free(*ppResult);
321 *ppResult = th_stralloc(th_strlen(pStr) + 1);
322 if (!*ppResult)
323 return -2;
324
325 /* Copy to the destination */
326 th_strcpy(*ppResult, pStr);
327
328 return 0;
329 }
330
331
332 /* Concatenates a given string into string pointed by *ppResult.
333 */
334 int th_pstrcat(char_t ** ppResult, char_t * pStr)
335 {
336 assert(ppResult);
337
338 /* Check the string pointers */
339 if (!pStr)
340 return -1;
341
342 if (*ppResult != NULL) {
343 *ppResult = th_strrealloc(*ppResult, th_strlen(*ppResult) + th_strlen(pStr) + 1);
344 if (*ppResult == NULL)
345 return -1;
346
347 th_strcat(*ppResult, pStr);
348 } else {
349 *ppResult = th_stralloc(th_strlen(pStr) + 1);
350 if (*ppResult == NULL)
351 return -1;
352
353 th_strcpy(*ppResult, pStr);
354 }
355
356 return 0;
357 }
358
359
360 /* Find next non-whitespace character in string.
361 * Updates iPos into the position of such character and
362 * returns pointer to the string.
363 */
364 char_t *th_findnext(char_t * pStr, size_t * iPos)
365 {
366 assert(pStr);
367
368 /* Terminating NULL-character is not whitespace! */
369 while (th_isspace(pStr[*iPos]))
370 (*iPos)++;
371 return &pStr[*iPos];
372 }
373
374
375 /* Find next chSep-character from string
376 */
377 char_t *th_findsep(char_t * pStr, size_t * iPos, char_t chSep)
378 {
379 assert(pStr);
380
381 /* Terminating NULL-character is not digit! */
382 while (pStr[*iPos] && (pStr[*iPos] != chSep))
383 (*iPos)++;
384 return &pStr[*iPos];
385 }
386
387
388 /* Find next chSep- or whitespace from string
389 */
390 char_t *th_findseporspace(char_t * pStr, size_t * iPos, char_t chSep)
391 {
392 assert(pStr);
393
394 /* Terminating NULL-character is not digit! */
395 while (!th_isspace(pStr[*iPos]) && (pStr[*iPos] != chSep))
396 (*iPos)++;
397 return &pStr[*iPos];
398 }
399
400
401 /* Compare a string to a pattern. Case-SENSITIVE version.
402 * The matching pattern can consist of any normal characters plus
403 * wildcards ? and *. "?" matches any character and "*" matches
404 * any number of characters.
405 */
406 BOOL th_strmatch(char_t * pStr, char_t * pPattern)
407 {
408 BOOL didMatch, isAnyMode, isEnd;
409 char_t *tmpPattern;
410
411 /* Check given pattern and string */
412 if (!pStr)
413 return FALSE;
414 if (!pPattern)
415 return FALSE;
416
417 /* Initialize */
418 tmpPattern = NULL;
419 didMatch = TRUE;
420 isEnd = FALSE;
421 isAnyMode = FALSE;
422
423 /* Start comparision */
424 do {
425 didMatch = FALSE;
426 switch (*pPattern) {
427 case '?':
428 /* Any single character matches */
429 if (*pStr) {
430 didMatch = TRUE;
431 pPattern++;
432 pStr++;
433 }
434 break;
435
436 case '*':
437 didMatch = TRUE;
438 pPattern++;
439 if (!*pPattern)
440 isEnd = TRUE;
441 isAnyMode = TRUE;
442 tmpPattern = pPattern;
443 break;
444
445 case 0:
446 if (isAnyMode) {
447 if (*pStr)
448 pStr++;
449 else
450 isEnd = TRUE;
451 } else {
452 if (*pStr) {
453 if (tmpPattern) {
454 isAnyMode = TRUE;
455 pPattern = tmpPattern;
456 } else
457 didMatch = FALSE;
458 } else
459 isEnd = TRUE;
460 }
461 break;
462 default:
463 if (isAnyMode) {
464 if ((*pPattern) == (*pStr)) {
465 isAnyMode = FALSE;
466 didMatch = TRUE;
467 } else {
468 if (*pStr) {
469 didMatch = TRUE;
470 pStr++;
471 }
472 }
473 } else {
474 if ((*pPattern) == (*pStr)) {
475 didMatch = TRUE;
476 if (*pPattern)
477 pPattern++;
478 if (*pStr)
479 pStr++;
480 } else {
481 if (tmpPattern) {
482 didMatch = TRUE;
483 isAnyMode = TRUE;
484 pPattern = tmpPattern;
485 }
486 }
487 }
488
489 if (!*pStr && !*pPattern)
490 isEnd = TRUE;
491 break;
492
493 } /* switch */
494
495 } while ((didMatch) && (!isEnd));
496
497 return didMatch;
498 }
499
500
501 /* Compare a string to a pattern. Case-INSENSITIVE version.
502 */
503 BOOL th_strcasematch(char_t * pStr, char_t * pPattern)
504 {
505 BOOL didMatch, isAnyMode, isEnd;
506 char_t *tmpPattern;
507
508 /* Check given pattern and string */
509 if (!pStr)
510 return FALSE;
511 if (!pPattern)
512 return FALSE;
513
514 /* Initialize */
515 tmpPattern = NULL;
516 didMatch = TRUE;
517 isEnd = FALSE;
518 isAnyMode = FALSE;
519
520 /* Start comparision */
521 do {
522 switch (*pPattern) {
523 case '?':
524 /* Any single character matches */
525 if (*pStr) {
526 pPattern++;
527 pStr++;
528 } else
529 didMatch = FALSE;
530 break;
531
532 case '*':
533 pPattern++;
534 if (!*pPattern || (*pPattern == '?'))
535 isEnd = TRUE;
536 isAnyMode = TRUE;
537 tmpPattern = pPattern;
538 break;
539
540 case 0:
541 if (isAnyMode) {
542 if (*pStr)
543 pStr++;
544 else
545 isEnd = TRUE;
546 } else {
547 if (*pStr) {
548 if (tmpPattern) {
549 isAnyMode = TRUE;
550 pPattern = tmpPattern;
551 } else
552 didMatch = FALSE;
553 } else
554 isEnd = TRUE;
555 }
556 break;
557
558 default:
559 if (isAnyMode) {
560 if (th_tolower(*pPattern) == th_tolower(*pStr)) {
561 isAnyMode = FALSE;
562 } else {
563 if (*pStr)
564 pStr++;
565 else
566 didMatch = FALSE;
567 }
568 } else {
569 if (th_tolower(*pPattern) == th_tolower(*pStr)) {
570 if (*pPattern)
571 pPattern++;
572 if (*pStr)
573 pStr++;
574 } else {
575 if (tmpPattern) {
576 isAnyMode = TRUE;
577 pPattern = tmpPattern;
578 } else
579 didMatch = FALSE;
580 }
581 }
582
583 if (!*pStr && !*pPattern)
584 isEnd = TRUE;
585 break;
586
587 } /* switch */
588
589 } while ((didMatch) && (!isEnd));
590
591 return didMatch;
592 }
593
594
595 /*
596 * Handling of string-lists and hashes
597 */
598 t_str_node *th_strnode_new(char_t * pcStr, ulint_t nUsed, void *pData)
599 {
600 t_str_node *pResult;
601
602 /* Allocate memory for new node */
603 pResult = (t_str_node *) th_calloc(1, sizeof(t_str_node));
604 if (!pResult)
605 return NULL;
606
607 /* Set fields */
608 th_pstrcpy(&pResult->pcStr, pcStr);
609 pResult->nUsed = nUsed;
610 pResult->pData = pData;
611
612 return pResult;
613 }
614
615
616 void th_strnode_free(t_str_node * pNode)
617 {
618 assert(pNode);
619
620 th_free(pNode->pcStr);
621 th_free(pNode);
622 }
623
624
625 /* Insert a new node into strlist
626 */
627 void th_strlist_insert(t_str_node ** strList, t_str_node * pNode)
628 {
629 assert(strList);
630 assert(pNode);
631
632 /* Insert into linked list */
633 if (*strList) {
634 /* The first node's pPrev points to last node */
635 LPREV = (*strList)->pPrev; /* New node's prev = Previous last node */
636 (*strList)->pPrev->pNext = pNode; /* Previous last node's next = New node */
637 (*strList)->pPrev = pNode; /* New last node = New node */
638 LNEXT = NULL; /* But next is NULL! */
639 } else {
640 (*strList) = pNode; /* First node ... */
641 LPREV = pNode; /* ... it's also last */
642 LNEXT = NULL; /* But next is NULL! */
643 }
644
645 }
646
647
648 /* Free a given strlist
649 */
650 void th_strlist_free(t_str_node * strList)
651 {
652 t_str_node *pNode, *nNode;
653
654 pNode = strList;
655 while (pNode) {
656 nNode = pNode->pNext;
657 th_strnode_free(pNode);
658 pNode = nNode;
659 }
660 }
661
662
663 /* Create a strIndex from strlist
664 */
665 t_str_index *th_strlist_makeindex(t_str_node * strList)
666 {
667 t_str_index *pResult;
668 t_str_node *pCurr;
669 ulint_t n;
670 assert(strList);
671
672 /* Computer number of nodes */
673 for (n = 0, pCurr = strList; pCurr; pCurr = pCurr->pNext)
674 n++;
675
676 /* Check number of nodes */
677 if (n == 0)
678 return NULL;
679
680 /* Allocate memory for index */
681 pResult = (t_str_index *) th_calloc(1, sizeof(t_str_index));
682 if (!pResult)
683 return NULL;
684
685 pResult->n = n;
686 pResult->ppIndex = (t_str_node **) th_calloc(n, sizeof(t_str_node *));
687 if (!pResult->ppIndex) {
688 th_free(pResult);
689 return NULL;
690 }
691
692 /* Create the index */
693 for (n = 0, pCurr = strList; pCurr && (n < pResult->n); pCurr = pCurr->pNext)
694 pResult->ppIndex[n++] = pCurr;
695
696 return pResult;
697 }
698
699
700 /* Insert a node into given strhash
701 */
702 int th_strhash_insert(t_str_hash strHash, t_str_node * pNode, BOOL ignoreCase)
703 {
704 int i;
705 assert(strHash);
706 assert(pNode);
707 assert(pNode->pcStr);
708
709 if (ignoreCase)
710 i = th_tolower(pNode->pcStr[0]);
711 else
712 i = pNode->pcStr[0];
713
714 /* Check the hashcode */
715 if ((i < 0) && (i >= SET_HASH_MAXINDEX))
716 return -1;
717
718 if (strHash[i]) {
719 /* The first node's pPrev points to last node */
720 pNode->pPrev = strHash[i]->pPrev; /* New node's prev = Previous last node */
721 strHash[i]->pPrev->pNext = pNode; /* Previous last node's next = New node */
722 strHash[i]->pPrev = pNode; /* New last node = New node */
723 pNode->pNext = NULL; /* But next is NULL! */
724 } else {
725 strHash[i] = pNode; /* First node */
726 pNode->pPrev = pNode; /* But also last */
727 pNode->pNext = NULL; /* But next is NULL! */
728 }
729
730 return 0;
731 }
732
733
734 /* Free a given strhash
735 */
736 void th_strhash_free(t_str_hash strHash)
737 {
738 int i;
739 assert(strHash);
740
741 for (i = 0; i < SET_HASH_MAXINDEX; i++)
742 th_strlist_free(strHash[i]);
743 }
744
745
746 /* Change pData for matching entries to new value
747 */
748 void th_strhash_change_pdata(t_str_hash strHash, void *pFind, void *pNew)
749 {
750 t_str_node *pCurr;
751 int i;
752 assert(strHash);
753
754 for (i = 0; i < SET_HASH_MAXINDEX; i++) {
755 /* Find from linked list */
756 pCurr = strHash[i];
757 while (pCurr) {
758 if (pCurr->pData == pFind)
759 pCurr->pData = pNew;
760
761 pCurr = pCurr->pNext;
762 }
763 }
764 }
765
766
767 /* Search a string from a given stringhash, either case-sensitive or insensitive
768 */
769 t_str_node *th_strhash_search(t_str_hash strHash, char_t * findStr, BOOL ignoreCase)
770 {
771 t_str_node *pCurr;
772 int i;
773 BOOL isFound;
774 assert(strHash);
775 assert(findStr);
776
777 isFound = FALSE;
778 pCurr = NULL;
779
780 /* Check hashcode */
781 if (ignoreCase)
782 i = ((unsigned char) th_tolower(findStr[0]));
783 else
784 i = ((unsigned char) findStr[0]);
785
786 if ((i < 0) && (i >= SET_HASH_MAXINDEX))
787 return NULL;
788
789 /* Find from linked list */
790 pCurr = strHash[i];
791
792 if (ignoreCase) {
793 /* Case in-sensitive search */
794 while (pCurr && !isFound) {
795 if (th_strcasecmp(findStr, pCurr->pcStr) == 0)
796 isFound = TRUE;
797 else
798 pCurr = pCurr->pNext;
799 }
800 } else {
801 /* Case sensitive search */
802 while (pCurr && !isFound) {
803 if (th_strcmp(findStr, pCurr->pcStr) == 0)
804 isFound = TRUE;
805 else
806 pCurr = pCurr->pNext;
807 }
808 }
809
810 /* Return result */
811 if (isFound)
812 return pCurr;
813 else
814 return NULL;
815 }
816
817
818 /* Create a strIndex from strHash
819 */
820 t_str_index *th_strhash_makeindex(t_str_hash strHash)
821 {
822 t_str_index *pResult;
823 t_str_node *pCurr;
824 unsigned int n, i;
825 assert(strHash);
826
827 /* Computer number of nodes */
828 for (n = i = 0; i < SET_HASH_MAXINDEX; i++) {
829 pCurr = strHash[i];
830 while (pCurr) {
831 n++;
832 pCurr = pCurr->pNext;
833 }
834 }
835
836 /* Check number of nodes */
837 if (n <= 0)
838 return NULL;
839
840 /* Allocate memory for index */
841 pResult = (t_str_index *) th_calloc(1, sizeof(t_str_index));
842 if (!pResult)
843 return NULL;
844
845 pResult->n = n;
846 pResult->ppIndex = (t_str_node **) th_calloc(n, sizeof(t_str_node *));
847 if (!pResult->ppIndex) {
848 th_free(pResult);
849 return NULL;
850 }
851
852 /* Create the index */
853 for (n = i = 0; (i < SET_HASH_MAXINDEX) && (n < pResult->n); i++) {
854 pCurr = strHash[i];
855 while (pCurr && (n < pResult->n)) {
856 pResult->ppIndex[n++] = pCurr;
857 pCurr = pCurr->pNext;
858 }
859 }
860
861 return pResult;
862 }
863
864
865 /* Free a given strIndex
866 */
867 void th_strindex_free(t_str_index * strIndex)
868 {
869 if (strIndex) {
870 th_free(strIndex->ppIndex);
871 th_free(strIndex);
872 }
873 }
874
875
876 /* Compare two t_str_nodes by nUsed
877 */
878 int th_strindex_cmp_used(const void *pNode1, const void *pNode2)
879 {
880 t_str_node *pStr1, *pStr2;
881
882 pStr1 = *(t_str_node **) pNode1;
883 pStr2 = *(t_str_node **) pNode2;
884
885 if (pStr1->nUsed > pStr2->nUsed)
886 return -1;
887 else if (pStr1->nUsed < pStr2->nUsed)
888 return 1;
889 else
890 return 0;
891 }
892
893
894 /* Sort an strIndex by nUsed, using th_strindex_cmp_used()
895 */
896 void th_strindex_sort_nused(t_str_index * strIndex)
897 {
898 assert(strIndex);
899 assert(strIndex->ppIndex);
900
901 qsort(strIndex->ppIndex, strIndex->n, sizeof(t_str_node *), th_strindex_cmp_used);
902 }
903
904
905 /* Compare two t_str_nodes via strcmp()
906 */
907 int th_strindex_cmp_alpha(const void *pNode1, const void *pNode2)
908 {
909 t_str_node *pStr1, *pStr2;
910
911 pStr1 = *(t_str_node **) pNode1;
912 pStr2 = *(t_str_node **) pNode2;
913
914 return th_strcmp(pStr1->pcStr, pStr2->pcStr);
915 }
916
917
918 /* Sort an strIndex by nUsed, using th_strindex_cmp_used()
919 */
920 void th_strindex_sort_alpha(t_str_index * strIndex)
921 {
922 assert(strIndex);
923 assert(strIndex->ppIndex);
924
925 qsort(strIndex->ppIndex, strIndex->n, sizeof(t_str_node *), th_strindex_cmp_alpha);
926 }