source: trunk/src/sh_string.c@ 482

Last change on this file since 482 was 481, checked in by katerina, 9 years ago

Enhancements and fixes for tickets #374, #375, #376, #377, #378, and #379.

File size: 25.2 KB
Line 
1
2#include "config_xor.h"
3
4#include <string.h>
5#include <stdio.h>
6#include <sys/types.h>
7
8#include "sh_string.h"
9#include "sh_mem.h"
10
11#undef FIL__
12#define FIL__ _("sh_string.c")
13
14extern int sl_ok_adds (size_t a, size_t b);
15#define S_TRUE 1
16#define S_FALSE 0
17
18#include <ctype.h>
19#include <errno.h>
20
21/* Split array at delim in at most nfields fields.
22 * Empty fields are returned as empty (zero-length) strings.
23 * Leading and trailing WS are removed from token.
24 * The number of fields is returned in 'nfields', their
25 * lengths in 'lengths'.
26 * A single delimiter will return two empty fields.
27 */
28char ** split_array(char *line, unsigned int * nfields,
29 char delim, size_t * lengths)
30{
31 char *a, *e, *s;
32 unsigned int i = 0;
33 int flag = 0;
34 char **arr;
35 unsigned int maxfields = (*nfields);
36
37 arr = SH_ALLOC((maxfields+1) * sizeof (char*));
38
39 e = line;
40
41 do
42 {
43 /* skip leading WS
44 */
45 for (s=e; *s && isspace((int)*s); ++s) /* nothing */;
46
47 if (*s)
48 {
49 /* move a to next delim
50 */
51 for (a=s; *a && *a != delim; ++a) /* nothing */;
52
53 /* set e to next after delim
54 */
55 if (*a == delim)
56 {
57 e = a+1;
58 flag = 1;
59 }
60 else /* (!*a) */
61 {
62 e = a;
63 flag = 0;
64 }
65
66 if (a != line)
67 {
68 if (i < (maxfields -1))
69 {
70
71 /* chop off trailing WS
72 */
73 for (a--; isspace((int)*a) && a > s; a--) /* do nothing */;
74
75 /* terminate string
76 */
77 ++a; *a = '\0';
78 }
79 else
80 {
81 /* If nfields < actual fields, last string
82 * will be remainder, therefore skip to end.
83 */
84 if ( *a )
85 {
86 do {
87 a++;
88 } while ( *a );
89 }
90 }
91 }
92 else
93 {
94 *a = '\0';
95 }
96 }
97 else /* (!*s) */
98 {
99 a = s;
100 /* (i == 0) handles the special case of splitting the empty string */
101 if (flag || i == 0)
102 {
103 flag = 0;
104 goto setnext;
105 }
106 break;
107 }
108
109 setnext:
110 lengths[i] = (size_t) (a-s); /* a >= s always */
111 arr[i] = s;
112 ++i;
113
114 } while (i < maxfields);
115
116 *nfields = i;
117 arr[i] = NULL;
118
119 return arr;
120}
121
122/* Split array at whitespace in at most nfields fields.
123 * Multiple whitespaces are collapsed.
124 * Empty fields are returned as empty (zero-length) strings.
125 * The number of fields is returned in nfields.
126 * An empty string will return zero fields.
127 * If nfields < actual fields, last string will be remainder.
128 */
129
130#define SH_SPLIT_LIST 0
131#define SH_SPLIT_WS 1
132
133char ** split_array_ws_int (char *line,
134 unsigned int * nfields, size_t * lengths,
135 const char *delim, int isList)
136{
137 char *a, *e, *s;
138 unsigned int i = 0;
139 char **arr;
140 unsigned int maxfields = (*nfields);
141
142 arr = SH_ALLOC((maxfields+1) * sizeof (char*));
143
144 e = line;
145
146 do
147 {
148 s = e;
149
150 /* skip leading WS
151 */
152 if (isList == SH_SPLIT_WS)
153 {
154 if ( *s && isspace((int)*s) )
155 {
156 do {
157 ++s;
158 } while ( *s && isspace((int)*s) );
159 }
160 }
161 else
162 {
163 if ( *s && strchr(delim, (int)*s))
164 {
165 do {
166 ++s;
167 } while ( *s && strchr(delim, (int)*s));
168 }
169
170 }
171
172 if (*s)
173 {
174
175 /* s is at non-ws, move a to next ws
176 */
177 a = s;
178 if (isList == SH_SPLIT_WS)
179 {
180 do {
181 a++;
182 } while ( *a && (!isspace((int)*a)) );
183 }
184 else
185 {
186 do {
187 a++;
188 } while ( *a && NULL == strchr(delim, (int)*a));
189 }
190
191 /* next token, *a is either ws or '\0'
192 */
193 e = ( (*a) ? a+1 : a);
194
195 /* terminate and set arr[i]
196 */
197 if (i < (maxfields-1))
198 {
199 *a = '\0';
200 }
201 else
202 {
203 /* If nfields < actual fields, last
204 * string will be remainder. Therefore
205 * skip to end.
206 */
207 if ( *a )
208 {
209 do {
210 a++;
211 } while ( *a );
212 }
213 }
214 lengths[i] = (size_t)(a-s); /* a >= s always */
215 arr[i] = s;
216 ++i;
217 }
218 else /* if (!*s) */
219 {
220 break;
221 }
222
223 } while (i < maxfields);
224
225 *nfields = i;
226 arr[i] = NULL;
227
228 return arr;
229}
230
231char ** split_array_ws (char *line,
232 unsigned int * nfields, size_t * lengths)
233{
234 return split_array_ws_int (line, nfields, lengths, NULL, SH_SPLIT_WS);
235}
236
237char ** split_array_list (char *line,
238 unsigned int * nfields, size_t * lengths)
239{
240 return split_array_ws_int (line, nfields, lengths, ", \t", SH_SPLIT_LIST);
241}
242
243char ** split_array_token (char *line,
244 unsigned int * nfields, size_t * lengths,
245 const char * token)
246{
247 return split_array_ws_int (line, nfields, lengths, token, SH_SPLIT_LIST);
248}
249
250/* return a split() of a list contained in 'PREFIX\s*( list ).*'
251 */
252char ** split_array_braced (char *line, const char * prefix,
253 unsigned int * nfields, size_t * lengths)
254{
255 char * s = line;
256 char * p;
257 unsigned int sind = (prefix) ? strlen(prefix) : 0;
258
259 while ( *s && isspace((int)*s) ) ++s;
260 if (prefix && 0 != strncmp(s, prefix, strlen(prefix)))
261 return NULL;
262 s = &s[sind];
263 while ( *s && isspace((int)*s) ) ++s;
264 if (!s || (*s != '('))
265 return NULL;
266 ++s;
267 p = strchr(s, ')');
268 if (!p || (*p == *s))
269 return NULL;
270 *p = '\0';
271 return split_array_list (s, nfields, lengths);
272}
273
274#define SH_STRING_PARCEL 120
275
276static
277size_t sh_string_read_int(sh_string * s, FILE * fp, size_t maxlen, char *start);
278
279size_t sh_string_read(sh_string * s, FILE * fp, size_t maxlen)
280{
281 return sh_string_read_int(s, fp, maxlen, NULL);
282}
283
284size_t sh_string_read_cont(sh_string * s, FILE * fp, size_t maxlen, char *cont)
285{
286 return sh_string_read_int(s, fp, maxlen, cont);
287}
288
289static char * sh_str_fgets (char *s, int size, FILE *fp)
290{
291 char * ret;
292 do {
293 clearerr(fp);
294 ret = fgets(s, size, fp);
295 } while (ret == NULL && ferror(fp) && errno == EAGAIN);
296
297 return ret;
298}
299
300size_t sh_string_read_int(sh_string * s, FILE * fp, size_t maxlen, char *start)
301{
302
303 /* case 0) start != NULL and first char not in 'start'
304 */
305 if (start)
306 {
307 int first;
308
309 do {
310 clearerr(fp);
311 first = fgetc(fp);
312 } while (first == EOF && ferror(fp) && errno == EAGAIN);
313
314 if (first == EOF)
315 {
316 sh_string_truncate(s, 0);
317 if (ferror(fp))
318 return -1;
319 return 0;
320 }
321
322 if (NULL == strchr(start, first))
323 {
324 ungetc(first, fp);
325 return 0;
326 }
327 ungetc(first, fp);
328 }
329
330 /* case 1) EOF or error
331 */
332 if (sh_str_fgets(s->str, s->siz, fp) == NULL)
333 {
334 sh_string_truncate(s, 0);
335 if (ferror(fp))
336 return -1;
337 return 0;
338 }
339
340 /* case 2) end of line reached. strlen should always be > 0
341 * because of the '\n', but we check.
342 */
343 s->len = strlen(s->str);
344 if (s->len > 0 && (s->str)[s->len-1] == '\n')
345 {
346 (s->str)[s->len-1] = '\0';
347 --(s->len);
348 return (s->len + 1);
349 }
350
351 /* case 3) incomplete string
352 */
353 for (;;) {
354
355 if (maxlen > 0 && (s->siz+SH_STRING_PARCEL) > maxlen)
356 {
357 if (s->siz < maxlen)
358 sh_string_grow(s, (maxlen-s->siz));
359 else
360 return -2;
361 }
362 else
363 {
364 sh_string_grow(s, 0);
365 }
366
367 if (sh_str_fgets(&(s->str[s->len]), (s->siz - s->len), fp) == NULL)
368 {
369 if (ferror(fp))
370 {
371 sh_string_truncate(s, 0);
372 return -1;
373 }
374 return s->len;
375 }
376
377 s->len += strlen( &(s->str[s->len]) );
378 if (s->len > 0 && s->str[s->len-1] == '\n')
379 {
380 (s->str)[s->len-1] = '\0';
381 --(s->len);
382 return (s->len + 1);
383 }
384 }
385
386 /* notreached */
387}
388
389sh_string * sh_string_cat_lchar(sh_string * s, const char * str, size_t len)
390{
391 if (sl_ok_adds(len, s->siz) == S_TRUE)
392 {
393 if ((len + 1 + s->len) > s->siz)
394 {
395 sh_string_grow(s, ((len+1+s->len) - s->siz) );
396 }
397 memcpy(&(s->str[s->len]), str, len);
398 s->len += len;
399 s->str[s->len] = '\0';
400 return s;
401 }
402
403 return NULL;
404}
405
406sh_string * sh_string_set_from_char(sh_string * s, const char * str)
407{
408 size_t len = strlen(str);
409
410 if ((len+1) > s->siz)
411 {
412 sh_string_grow(s, ((len+1) - s->siz) );
413 }
414 memcpy(s->str, str, (len+1));
415 s->len = len;
416 return s;
417}
418
419sh_string * sh_string_add_from_char(sh_string * s, const char * str)
420{
421 size_t len = strlen(str);
422 size_t avail = (s->siz - s->len);
423
424 if ((len+1) > avail)
425 {
426 (void) sh_string_grow(s, ((len+1) - avail) );
427 }
428 memcpy(&(s->str[s->len]), str, (len+1));
429 s->len += len;
430 return s;
431}
432
433sh_string * sh_string_new_from_lchar(const char * str, size_t len)
434{
435 sh_string * s;
436 s = SH_ALLOC(sizeof(sh_string));
437 s->str = SH_ALLOC(len+1);
438 if (str)
439 memcpy(s->str, str, len);
440 else
441 s->str[0] = '\0';
442 s->str[len] = '\0';
443 s->siz = len+1;
444 s->len = len;
445 return s;
446}
447
448sh_string * sh_string_new_from_lchar3(const char * str1, size_t len1,
449 const char * str2, size_t len2,
450 const char * str3, size_t len3)
451{
452 sh_string * s;
453 size_t len = 0;
454
455 if (sl_ok_adds(len1, len2) == S_TRUE)
456 len = len1 + len2;
457 else
458 return NULL;
459 if (sl_ok_adds( len, len3) == S_TRUE)
460 len = len + len3;
461 else
462 return NULL;
463
464 s = SH_ALLOC(sizeof(sh_string));
465 s->str = SH_ALLOC(len+1);
466
467 memcpy(s->str, str1, len1);
468 memcpy(&s->str[len1], str2, len2);
469 memcpy(&s->str[len1+len2], str3, len3);
470
471 s->str[len] = '\0';
472 s->siz = len+1;
473 s->len = len;
474 return s;
475}
476
477sh_string * sh_string_grow(sh_string * s, size_t increase)
478{
479 char * new;
480
481 if (increase == 0)
482 increase = SH_STRING_PARCEL;
483
484 if (s && sl_ok_adds(s->siz, increase) == S_TRUE)
485 {
486 new = SH_ALLOC(s->siz + increase);
487
488 if (s->str)
489 {
490 memcpy(new, s->str, s->len+1);
491 SH_FREE(s->str);
492 }
493 else
494 {
495 new[0] = '\0';
496 }
497 s->str = new;
498 s->siz += increase;
499 return s;
500 }
501 return NULL;
502}
503
504sh_string * sh_string_truncate(sh_string * s, size_t len)
505{
506 if (s)
507 {
508 if (s->str && (s->len > len) )
509 {
510 s->len = len;
511 (s->str)[len] = '\0';
512 }
513 return s;
514 }
515 return NULL;
516}
517
518void sh_string_destroy(sh_string ** s)
519{
520 if (s)
521 {
522 if ((*s) && (*s)->str)
523 SH_FREE ((*s)->str);
524 SH_FREE(*s);
525 *s = NULL;
526 }
527 return;
528}
529
530sh_string * sh_string_new(size_t size)
531{
532 sh_string * s;
533 s = SH_ALLOC (sizeof(sh_string));
534 if (size == 0)
535 size = SH_STRING_PARCEL;
536 s->str = SH_ALLOC (size);
537 s->str[0] = '\0';
538 s->siz = size;
539 s->len = 0;
540 return s;
541}
542
543/* Replaces fields in s with 'replacement'. Fields are given
544 * in the ordered array ovector, comprising ovecnum pairs
545 * ovector[i], ovector[i+1] which list offset of first char
546 * of field, offset of first char after field (this is how
547 * the pcre library does it).
548 */
549sh_string * sh_string_replace(const sh_string * s,
550 const int * ovector, int ovecnum,
551 const char * replacement, size_t rlen)
552{
553 sh_string * r = NULL;
554 char * p;
555 long tlen;
556 size_t len;
557 int end = 0;
558 int start = 0;
559 size_t oldlen = 0;
560 size_t newlen = 0;
561 long diff;
562 int i, curr, last;
563
564 for (i = 0; i < ovecnum; ++i)
565 {
566 start = ovector[2*i]; /* offset of first char of substring */
567 if (start >= end)
568 {
569 end = ovector[2*i+1]; /* offset of first char after substring end*/
570
571 if (end > start && (unsigned int)end <= (s->len + 1))
572 {
573 oldlen += (end - start);
574 newlen += rlen;
575 }
576 else /* inconsistency detected */
577 {
578 return NULL;
579 }
580 }
581 else /* overlap detected */
582 {
583 return NULL;
584 }
585 }
586
587 diff = newlen - oldlen;
588
589 if ((diff > 0) && ((s->len + 1 + diff) > s->siz))
590 {
591 r = sh_string_new_from_lchar(sh_string_str(s),
592 sh_string_len(s));
593 r = sh_string_grow(r, diff);
594 }
595 else
596 {
597 r = sh_string_new_from_lchar(sh_string_str(s),
598 sh_string_len(s));
599 }
600
601
602 curr = -1;
603
604 for (i = 0; i < ovecnum; ++i)
605 {
606 if (ovector[2*i] >= 0)
607 {
608 curr = 2*i;
609 break;
610 }
611 }
612
613 if (r && ovecnum > 0 && ovector[curr] >= 0)
614 {
615 r->len = 0; r->str[0] = '\0'; p = r->str;
616
617 /* First part, until start of first replacement
618 */
619 if (r->siz > (unsigned int)ovector[curr]) {
620 memcpy(p, s->str, (size_t)ovector[curr]);
621 p += ovector[curr];
622 r->len += ovector[curr];
623 }
624 if (r->siz > (r->len + rlen)) {
625 memcpy(p, replacement, rlen);
626 p += rlen;
627 r->len += rlen;
628 }
629 *p = '\0';
630
631 last = curr + 1;
632
633 for (i = 1; i < ovecnum; ++i)
634 {
635 if (ovector[2*i] < 0)
636 continue;
637
638 curr = 2*i;
639
640 /* From end of last replacement to start of this */
641 tlen = (long)(ovector[curr] - ovector[last]);
642 if (tlen >= 0)
643 {
644 len = (size_t) tlen;
645
646 if (tlen > 0 && r->siz > (r->len + len))
647 {
648 memcpy(p, &(s->str[ovector[last]]), (size_t)len);
649 p += len;
650 r->len += len;
651 }
652
653 /* The replacement */
654 if (r->siz > (r->len + rlen)) {
655 memcpy(p, replacement, rlen);
656 p += rlen;
657 r->len += rlen;
658 }
659
660 /* null terminate */
661 *p = '\0';
662
663 last = curr + 1;
664 }
665 }
666
667 /* Last part, after last replacement; includes terminating null
668 */
669 if (last > 0)
670 {
671 /* If not, nothing has been replaced, and r is still a copy of s
672 */
673 tlen = (long)((s->len + 1) - ovector[last]);
674 if (tlen > 0)
675 {
676 len = (size_t)tlen;
677 if (r->siz >= (r->len + len)) {
678 memcpy(p, &(s->str[ovector[2*i -1]]), (size_t)len);
679 p += (len - 1);
680 r->len += (len - 1);
681 *p = '\0';
682 }
683 }
684 }
685
686 }
687
688 return r;
689}
690
691
692#ifdef SH_CUTEST
693#include <stdlib.h>
694#include "CuTest.h"
695
696void Test_string (CuTest *tc) {
697 int status, i, max = 120;
698 FILE * fp;
699 sh_string * s = NULL;
700 sh_string * t;
701 static char template[] = "/tmp/xtest.XXXXXX";
702 char ** array;
703 char test[128];
704 size_t lengths[16];
705 unsigned int iarr;
706 int ovector[16];
707 int ovecnum;
708
709 s = sh_string_new(0);
710 CuAssertPtrNotNull(tc, s);
711 sh_string_destroy(&s);
712 CuAssertTrue(tc, s == NULL);
713
714 s = sh_string_new(0);
715 CuAssertPtrNotNull(tc, s);
716
717 status = mkstemp(template);
718 CuAssertTrue(tc, status >= 0);
719
720 fp = fdopen(status, "r+");
721 CuAssertPtrNotNull(tc, fp);
722
723 for (i = 0; i < 80; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 0 */
724 for (i = 0; i < 118; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 1 */
725 for (i = 0; i < 119; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 2 */
726 for (i = 0; i < 120; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 3 */
727 for (i = 0; i < 121; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 4 */
728 for (i = 0; i < 238; ++i) { fputc ('a', fp); } fputc ('\n', fp);
729 for (i = 0; i < 239; ++i) { fputc ('a', fp); } fputc ('\n', fp);
730 for (i = 0; i < 240; ++i) { fputc ('a', fp); } fputc ('\n', fp);
731 for (i = 0; i < 241; ++i) { fputc ('a', fp); } fputc ('\n', fp);
732
733 rewind(fp);
734
735 for (i = 0; i < 9; ++i)
736 {
737 status = sh_string_read(s, fp, max);
738
739 switch (i) {
740 case 0:
741 CuAssertTrue(tc, s->len == 80);
742 CuAssertTrue(tc, s->siz == 120);
743 CuAssertTrue(tc, status == 81);
744 break;
745 case 1:
746 CuAssertTrue(tc, s->len == 118);
747 CuAssertTrue(tc, s->siz == 120);
748 CuAssertTrue(tc, status == 119);
749 break;
750 case 2:
751 CuAssertTrue(tc, s->len == 119);
752 CuAssertTrue(tc, s->siz == 120);
753 CuAssertTrue(tc, status == -2); /* no terminating '\n', truncated */
754 break;
755 case 3:
756 CuAssertTrue(tc, s->len == 120);
757 CuAssertTrue(tc, s->siz == 240);
758 CuAssertTrue(tc, status == 121);
759 break;
760 case 4:
761 CuAssertTrue(tc, s->len == 121);
762 CuAssertTrue(tc, s->siz == 240);
763 CuAssertTrue(tc, status == 122);
764 break;
765 case 5:
766 CuAssertTrue(tc, s->len == 238);
767 CuAssertTrue(tc, s->siz == 240);
768 CuAssertTrue(tc, status == 239);
769 break;
770 case 6:
771 CuAssertTrue(tc, s->len == 239);
772 CuAssertTrue(tc, s->siz == 240);
773 CuAssertTrue(tc, status == -2); /* no terminating '\n', truncated */
774 break;
775 default:
776 CuAssertTrue(tc, s->len == 239);
777 CuAssertTrue(tc, s->siz == 240);
778 CuAssertTrue(tc, status == -2);
779 }
780 if (status == -2) /* read in rest of string */
781 { max = 240; sh_string_read(s, fp, max); }
782 }
783
784 rewind(fp);
785
786 sh_string_truncate(s, 0);
787 CuAssertTrue(tc, s->len == 0);
788
789 for (i = 0; i < 9; ++i)
790 {
791 status = sh_string_read(s, fp, 240);
792 if (status == -2)
793 sh_string_read(s, fp, 240);
794 else
795 {
796 for (status = 0; status < (int)s->len; ++status)
797 {
798 if (s->str[status] != 'a')
799 {
800 CuFail(tc, "unexpected character");
801 }
802 }
803 }
804 }
805
806 status = fclose(fp);
807 CuAssertTrue(tc, status == 0);
808 status = remove(template);
809 CuAssertTrue(tc, status == 0);
810
811 iarr = 10; strcpy(test, "|a1|| a2| |a3 |a4|a5|");
812 array = split_array(test, &iarr, '|', lengths);
813 CuAssertIntEquals(tc,9,(int)iarr);
814 CuAssertStrEquals(tc,"", array[0]);
815 CuAssertStrEquals(tc,"a1", array[1]);
816 CuAssertStrEquals(tc,"", array[2]);
817 CuAssertStrEquals(tc,"a2", array[3]);
818 CuAssertStrEquals(tc,"", array[4]);
819 CuAssertStrEquals(tc,"a3", array[5]);
820 CuAssertStrEquals(tc,"a4", array[6]);
821 CuAssertStrEquals(tc,"a5", array[7]);
822 CuAssertStrEquals(tc,"", array[8]);
823
824 CuAssertIntEquals(tc, 0, (int)lengths[0]);
825 CuAssertIntEquals(tc, 2, (int)lengths[1]);
826 CuAssertIntEquals(tc, 0, (int)lengths[2]);
827 CuAssertIntEquals(tc, 2, (int)lengths[3]);
828 CuAssertIntEquals(tc, 0, (int)lengths[4]);
829 CuAssertIntEquals(tc, 2, (int)lengths[5]);
830 CuAssertIntEquals(tc, 2, (int)lengths[6]);
831 CuAssertIntEquals(tc, 2, (int)lengths[7]);
832 CuAssertIntEquals(tc, 0, (int)lengths[8]);
833
834 iarr = 10; strcpy(test, "a1|| a2| |a3 |a4|a5|");
835 array = split_array(test, &iarr, '|', lengths);
836 CuAssertIntEquals(tc,8,(int)iarr);
837 CuAssertStrEquals(tc,"a1", array[0]);
838 CuAssertStrEquals(tc,"", array[1]);
839 CuAssertStrEquals(tc,"a2", array[2]);
840 CuAssertStrEquals(tc,"", array[3]);
841 CuAssertStrEquals(tc,"a3", array[4]);
842 CuAssertStrEquals(tc,"a4", array[5]);
843 CuAssertStrEquals(tc,"a5", array[6]);
844 CuAssertStrEquals(tc,"", array[7]);
845
846 CuAssertIntEquals(tc, 2, (int)lengths[0]);
847 CuAssertIntEquals(tc, 0, (int)lengths[1]);
848 CuAssertIntEquals(tc, 2, (int)lengths[2]);
849 CuAssertIntEquals(tc, 0, (int)lengths[3]);
850 CuAssertIntEquals(tc, 2, (int)lengths[4]);
851 CuAssertIntEquals(tc, 2, (int)lengths[5]);
852 CuAssertIntEquals(tc, 2, (int)lengths[6]);
853 CuAssertIntEquals(tc, 0, (int)lengths[7]);
854
855 iarr = 10; strcpy(test, " a1|| a2 | |a3 |a4|a5");
856 array = split_array(test, &iarr, '|', lengths);
857 CuAssertIntEquals(tc,7,(int)iarr);
858 CuAssertStrEquals(tc,"a1", array[0]);
859 CuAssertStrEquals(tc,"", array[1]);
860 CuAssertStrEquals(tc,"a2", array[2]);
861 CuAssertStrEquals(tc,"", array[3]);
862 CuAssertStrEquals(tc,"a3", array[4]);
863 CuAssertStrEquals(tc,"a4", array[5]);
864 CuAssertStrEquals(tc,"a5", array[6]);
865
866 CuAssertIntEquals(tc, 2, (int)lengths[0]);
867 CuAssertIntEquals(tc, 0, (int)lengths[1]);
868 CuAssertIntEquals(tc, 2, (int)lengths[2]);
869 CuAssertIntEquals(tc, 0, (int)lengths[3]);
870 CuAssertIntEquals(tc, 2, (int)lengths[4]);
871 CuAssertIntEquals(tc, 2, (int)lengths[5]);
872 CuAssertIntEquals(tc, 2, (int)lengths[6]);
873
874 iarr = 10; strcpy(test, "a1|| a2 | |a3 |a4|a5 ");
875 array = split_array(test, &iarr, '|', lengths);
876 CuAssertIntEquals(tc,7,(int)iarr);
877 CuAssertStrEquals(tc,"a1", array[0]);
878 CuAssertStrEquals(tc,"", array[1]);
879 CuAssertStrEquals(tc,"a2", array[2]);
880 CuAssertStrEquals(tc,"", array[3]);
881 CuAssertStrEquals(tc,"a3", array[4]);
882 CuAssertStrEquals(tc,"a4", array[5]);
883 CuAssertStrEquals(tc,"a5", array[6]);
884
885 CuAssertIntEquals(tc, 2, (int)lengths[0]);
886 CuAssertIntEquals(tc, 0, (int)lengths[1]);
887 CuAssertIntEquals(tc, 2, (int)lengths[2]);
888 CuAssertIntEquals(tc, 0, (int)lengths[3]);
889 CuAssertIntEquals(tc, 2, (int)lengths[4]);
890 CuAssertIntEquals(tc, 2, (int)lengths[5]);
891 CuAssertIntEquals(tc, 2, (int)lengths[6]);
892
893 iarr = 10; strcpy(test, "|");
894 array = split_array(test, &iarr, '|', lengths);
895 CuAssertIntEquals(tc,2,(int)iarr);
896 CuAssertStrEquals(tc,"", array[0]);
897 CuAssertStrEquals(tc,"", array[1]);
898
899 CuAssertIntEquals(tc, 0, (int)lengths[0]);
900 CuAssertIntEquals(tc, 0, (int)lengths[1]);
901
902 iarr = 10; strcpy(test, "|||");
903 array = split_array(test, &iarr, '|', lengths);
904 CuAssertIntEquals(tc,4,(int)iarr);
905 CuAssertStrEquals(tc,"", array[0]);
906 CuAssertStrEquals(tc,"", array[1]);
907 CuAssertStrEquals(tc,"", array[2]);
908 CuAssertStrEquals(tc,"", array[3]);
909
910 CuAssertIntEquals(tc, 0, (int)lengths[0]);
911 CuAssertIntEquals(tc, 0, (int)lengths[1]);
912 CuAssertIntEquals(tc, 0, (int)lengths[2]);
913 CuAssertIntEquals(tc, 0, (int)lengths[3]);
914
915 iarr = 10; strcpy(test, " a1 ");
916 array = split_array(test, &iarr, '|', lengths);
917 CuAssertIntEquals(tc,1,(int)iarr);
918 CuAssertStrEquals(tc,"a1", array[0]);
919
920 CuAssertIntEquals(tc, 2, (int)lengths[0]);
921
922 iarr = 10; strcpy(test, "");
923 array = split_array(test, &iarr, '|', lengths);
924 CuAssertIntEquals(tc,1,(int)iarr);
925 CuAssertStrEquals(tc,"", array[0]);
926
927 CuAssertIntEquals(tc, 0, (int)lengths[0]);
928
929 /* WS separated */
930
931 iarr = 10; strcpy(test, "a1");
932 array = split_array_ws (test, &iarr, lengths);
933 CuAssertIntEquals(tc,1,(int)iarr);
934 CuAssertStrEquals(tc,"a1", array[0]);
935
936 CuAssertIntEquals(tc, 2, (int)lengths[0]);
937
938 iarr = 10; strcpy(test, " a1");
939 array = split_array_ws (test, &iarr, lengths);
940 CuAssertIntEquals(tc,1,(int)iarr);
941 CuAssertStrEquals(tc,"a1", array[0]);
942
943 CuAssertIntEquals(tc, 2, (int)lengths[0]);
944
945 iarr = 10; strcpy(test, " a1 ");
946 array = split_array_ws (test, &iarr, lengths);
947 CuAssertIntEquals(tc,1,(int)iarr);
948 CuAssertStrEquals(tc,"a1", array[0]);
949
950 CuAssertIntEquals(tc, 2, (int)lengths[0]);
951
952 iarr = 10; strcpy(test, " ");
953 array = split_array_ws (test, &iarr, lengths);
954 CuAssertIntEquals(tc,0,(int)iarr);
955 CuAssertTrue(tc, array[0] == NULL);
956
957 iarr = 10; strcpy(test, " a1 a2");
958 array = split_array_ws (test, &iarr, lengths);
959 CuAssertIntEquals(tc,2,(int)iarr);
960 CuAssertStrEquals(tc,"a1", array[0]);
961 CuAssertStrEquals(tc,"a2", array[1]);
962
963 CuAssertIntEquals(tc, 2, (int)lengths[0]);
964 CuAssertIntEquals(tc, 2, (int)lengths[1]);
965
966 iarr = 10; strcpy(test, " a1 a2 ");
967 array = split_array_ws (test, &iarr, lengths);
968 CuAssertIntEquals(tc,2,(int)iarr);
969 CuAssertStrEquals(tc,"a1", array[0]);
970 CuAssertStrEquals(tc,"a2", array[1]);
971
972 CuAssertIntEquals(tc, 2, (int)lengths[0]);
973 CuAssertIntEquals(tc, 2, (int)lengths[1]);
974
975 iarr = 10; strcpy(test, "");
976 array = split_array_ws (test, &iarr, lengths);
977 CuAssertIntEquals(tc,0,(int)iarr);
978 CuAssertTrue(tc, array[0] == NULL);
979
980 iarr = 3; strcpy(test, " this is a test for remainder");
981 array = split_array_ws (test, &iarr, lengths);
982 CuAssertIntEquals(tc,3,(int)iarr);
983 CuAssertStrEquals(tc,"this", array[0]);
984 CuAssertStrEquals(tc,"is", array[1]);
985 CuAssertStrEquals(tc,"a test for remainder", array[2]);
986 for (i = 0; i < 3; ++i)
987 {
988 CuAssertIntEquals(tc, (int)strlen(array[i]), lengths[i] );
989 }
990
991 /* string replace */
992 s = sh_string_new_from_lchar3 ("abc ", 4, "def ", 4, "ghi ", 4);
993 ovecnum = 2;
994 ovector[0] = 0; ovector[1] = 2;
995 ovector[2] = 4; ovector[3] = 11;
996
997 t = sh_string_replace(s, ovector, ovecnum,
998 "___", 3);
999 CuAssertPtrNotNull(tc, t);
1000 CuAssertStrEquals(tc, "___c ___ ", t->str);
1001 CuAssertIntEquals(tc, 9, (int)t->len);
1002
1003 ovector[0] = 0; ovector[1] = 2;
1004 ovector[2] = 4; ovector[3] = 12;
1005 t = sh_string_replace(s, ovector, ovecnum,
1006 "___", 3);
1007 CuAssertPtrNotNull(tc, t);
1008 CuAssertStrEquals(tc, "___c ___", t->str);
1009 CuAssertIntEquals(tc, 8, (int)t->len);
1010
1011 ovector[0] = 0; ovector[1] = 0;
1012 ovector[2] = 0; ovector[3] = 0;
1013 t = sh_string_replace(s, ovector, ovecnum,
1014 "___", 3);
1015 CuAssertTrue(tc, t == NULL);
1016
1017 ovector[0] = 0; ovector[1] = 3;
1018 ovector[2] = 3; ovector[3] = 6;
1019 t = sh_string_replace(s, ovector, ovecnum,
1020 "___", 3);
1021
1022 CuAssertPtrNotNull(tc, t);
1023 CuAssertStrEquals(tc, "______f ghi ", t->str);
1024 CuAssertIntEquals(tc, 12, (int)t->len);
1025
1026 ovector[0] = 4; ovector[1] = 5;
1027 ovector[2] = 11; ovector[3] = 12;
1028 t = sh_string_replace(s, ovector, ovecnum,
1029 "___", 3);
1030 CuAssertPtrNotNull(tc, t);
1031 CuAssertStrEquals(tc, "abc ___ef ghi___", t->str);
1032 CuAssertIntEquals(tc, 16, (int)t->len);
1033
1034 t = sh_string_replace(s, ovector, 0,
1035 "___", 3);
1036 CuAssertPtrNotNull(tc, t);
1037 CuAssertStrEquals(tc, s->str, t->str);
1038 CuAssertIntEquals(tc, (int)s->len, (int)t->len);
1039
1040}
1041
1042#endif
Note: See TracBrowser for help on using the repository browser.