source: trunk/src/sh_string.c @ 481

Last change on this file since 481 was 481, checked in by katerina, 6 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.