source: trunk/src/sh_string.c

Last change on this file was 516, checked in by katerina, 5 years ago

Fix for ticket #409 and #410 (unprivileged suidcheck and gcc 6.2 compiler warnings).

File size: 25.7 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                  &(s->str[ovector[last]]) )
648                {
649                  memcpy(p, &(s->str[ovector[last]]), (size_t)len);
650                  p += len;
651                  r->len += len; 
652                }
653             
654              /* The replacement */
655              if (r->siz > (r->len + rlen)) {
656                memcpy(p, replacement, rlen);       
657                p += rlen;
658                r->len += rlen;
659              }
660             
661              /* null terminate */
662              *p = '\0';
663
664              last = curr + 1;
665            }
666        }
667
668      /* Last part, after last replacement; includes terminating null
669       */
670      if (last > 0)
671        {
672          /* If not, nothing has been replaced, and r is still a copy of s
673           */
674          tlen = (long)((s->len + 1) - ovector[last]);
675          if (tlen > 0)
676            {
677              len = (size_t)tlen;
678              if (r->siz >= (r->len + len) &&
679                  &(s->str[ovector[2*i -1]]) ) {
680                memcpy(p, &(s->str[ovector[2*i -1]]), (size_t)len);
681                p += (len - 1); 
682                r->len += (len - 1);
683                *p = '\0'; 
684              }
685            }
686        }
687
688    }
689
690  return r;
691}
692
693
694#ifdef SH_CUTEST
695#include <stdlib.h>
696#include "CuTest.h"
697
698void Test_string (CuTest *tc) {
699  int status, i, max = 120;
700  FILE * fp;
701  sh_string * s = NULL;
702  sh_string * t;
703  static char template[] = "/tmp/xtest.XXXXXX";
704  char ** array;
705  char test[128];
706  size_t lengths[16];
707  unsigned int iarr;
708  int ovector[16];
709  int ovecnum;
710
711  s = sh_string_new(0);
712  CuAssertPtrNotNull(tc, s);
713  sh_string_destroy(&s);
714  CuAssertTrue(tc, s == NULL);
715
716  s = sh_string_new(0);
717  CuAssertPtrNotNull(tc, s);
718
719  status = mkstemp(template);
720  CuAssertTrue(tc, status >= 0);
721
722  fp = fdopen(status, "r+");
723  CuAssertPtrNotNull(tc, fp);
724
725  for (i = 0; i <  80; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 0 */
726  for (i = 0; i < 118; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 1 */
727  for (i = 0; i < 119; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 2 */
728  for (i = 0; i < 120; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 3 */
729  for (i = 0; i < 121; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 4 */
730  for (i = 0; i < 238; ++i) { fputc ('a', fp); } fputc ('\n', fp);
731  for (i = 0; i < 239; ++i) { fputc ('a', fp); } fputc ('\n', fp);
732  for (i = 0; i < 240; ++i) { fputc ('a', fp); } fputc ('\n', fp);
733  for (i = 0; i < 241; ++i) { fputc ('a', fp); } fputc ('\n', fp);
734
735  rewind(fp);
736
737  for (i = 0; i < 9; ++i)
738    {
739      status = sh_string_read(s, fp, max);
740
741      switch (i) {
742      case 0:
743        CuAssertTrue(tc, s->len ==  80);
744        CuAssertTrue(tc, s->siz == 120);
745        CuAssertTrue(tc, status ==  81);
746        break;
747      case 1:
748        CuAssertTrue(tc, s->len == 118);
749        CuAssertTrue(tc, s->siz == 120);
750        CuAssertTrue(tc, status == 119);
751        break;
752      case 2:
753        CuAssertTrue(tc, s->len == 119);
754        CuAssertTrue(tc, s->siz == 120);
755        CuAssertTrue(tc, status ==  -2); /* no terminating '\n', truncated */
756        break;
757      case 3:
758        CuAssertTrue(tc, s->len == 120);
759        CuAssertTrue(tc, s->siz == 240);
760        CuAssertTrue(tc, status == 121);
761        break;
762      case 4:
763        CuAssertTrue(tc, s->len == 121);
764        CuAssertTrue(tc, s->siz == 240);
765        CuAssertTrue(tc, status == 122);
766        break;
767      case 5:
768        CuAssertTrue(tc, s->len == 238);
769        CuAssertTrue(tc, s->siz == 240);
770        CuAssertTrue(tc, status == 239);
771        break;
772      case 6:
773        CuAssertTrue(tc, s->len == 239);
774        CuAssertTrue(tc, s->siz == 240);
775        CuAssertTrue(tc, status ==  -2); /* no terminating '\n', truncated */
776        break;
777      default:
778        CuAssertTrue(tc, s->len == 239);
779        CuAssertTrue(tc, s->siz == 240);
780        CuAssertTrue(tc, status ==  -2);
781      }
782      if (status == -2) /* read in rest of string */
783        { max = 240; sh_string_read(s, fp, max); }
784    }
785
786  rewind(fp);
787
788  sh_string_truncate(s, 0);
789  CuAssertTrue(tc, s->len == 0);
790
791  for (i = 0; i < 9; ++i)
792    {
793      status = sh_string_read(s, fp, 240);
794      if (status == -2)
795        sh_string_read(s, fp, 240);
796      else
797        {
798          for (status = 0; status < (int)s->len; ++status)
799            {
800              if (s->str[status] != 'a')
801                {
802                  CuFail(tc, "unexpected character");
803                }
804            }
805        }
806    }
807
808  status = fclose(fp); 
809  CuAssertTrue(tc, status == 0);
810  status = remove(template);
811  CuAssertTrue(tc, status == 0);
812
813  iarr = 10; strcpy(test, "|a1|| a2| |a3 |a4|a5|");
814  array  = split_array(test, &iarr, '|', lengths);
815  CuAssertIntEquals(tc,9,(int)iarr);
816  CuAssertStrEquals(tc,"",   array[0]);
817  CuAssertStrEquals(tc,"a1", array[1]);
818  CuAssertStrEquals(tc,"",   array[2]);
819  CuAssertStrEquals(tc,"a2", array[3]);
820  CuAssertStrEquals(tc,"",   array[4]);
821  CuAssertStrEquals(tc,"a3", array[5]);
822  CuAssertStrEquals(tc,"a4", array[6]);
823  CuAssertStrEquals(tc,"a5", array[7]);
824  CuAssertStrEquals(tc,"",   array[8]);
825
826  CuAssertIntEquals(tc, 0, (int)lengths[0]);
827  CuAssertIntEquals(tc, 2, (int)lengths[1]);
828  CuAssertIntEquals(tc, 0, (int)lengths[2]);
829  CuAssertIntEquals(tc, 2, (int)lengths[3]);
830  CuAssertIntEquals(tc, 0, (int)lengths[4]);
831  CuAssertIntEquals(tc, 2, (int)lengths[5]);
832  CuAssertIntEquals(tc, 2, (int)lengths[6]);
833  CuAssertIntEquals(tc, 2, (int)lengths[7]);
834  CuAssertIntEquals(tc, 0, (int)lengths[8]);
835
836  iarr = 10; strcpy(test, "a1|| a2| |a3 |a4|a5|");
837  array  = split_array(test, &iarr, '|', lengths);
838  CuAssertIntEquals(tc,8,(int)iarr);
839  CuAssertStrEquals(tc,"a1", array[0]);
840  CuAssertStrEquals(tc,"",   array[1]);
841  CuAssertStrEquals(tc,"a2", array[2]);
842  CuAssertStrEquals(tc,"",   array[3]);
843  CuAssertStrEquals(tc,"a3", array[4]);
844  CuAssertStrEquals(tc,"a4", array[5]);
845  CuAssertStrEquals(tc,"a5", array[6]);
846  CuAssertStrEquals(tc,"",   array[7]);
847
848  CuAssertIntEquals(tc, 2, (int)lengths[0]);
849  CuAssertIntEquals(tc, 0, (int)lengths[1]);
850  CuAssertIntEquals(tc, 2, (int)lengths[2]);
851  CuAssertIntEquals(tc, 0, (int)lengths[3]);
852  CuAssertIntEquals(tc, 2, (int)lengths[4]);
853  CuAssertIntEquals(tc, 2, (int)lengths[5]);
854  CuAssertIntEquals(tc, 2, (int)lengths[6]);
855  CuAssertIntEquals(tc, 0, (int)lengths[7]);
856
857  iarr = 10; strcpy(test, "  a1|| a2  | |a3 |a4|a5");
858  array  = split_array(test, &iarr, '|', lengths);
859  CuAssertIntEquals(tc,7,(int)iarr);
860  CuAssertStrEquals(tc,"a1", array[0]);
861  CuAssertStrEquals(tc,"",   array[1]);
862  CuAssertStrEquals(tc,"a2", array[2]);
863  CuAssertStrEquals(tc,"",   array[3]);
864  CuAssertStrEquals(tc,"a3", array[4]);
865  CuAssertStrEquals(tc,"a4", array[5]);
866  CuAssertStrEquals(tc,"a5", array[6]);
867
868  CuAssertIntEquals(tc, 2, (int)lengths[0]);
869  CuAssertIntEquals(tc, 0, (int)lengths[1]);
870  CuAssertIntEquals(tc, 2, (int)lengths[2]);
871  CuAssertIntEquals(tc, 0, (int)lengths[3]);
872  CuAssertIntEquals(tc, 2, (int)lengths[4]);
873  CuAssertIntEquals(tc, 2, (int)lengths[5]);
874  CuAssertIntEquals(tc, 2, (int)lengths[6]);
875
876  iarr = 10; strcpy(test, "a1|| a2  | |a3 |a4|a5  ");
877  array  = split_array(test, &iarr, '|', lengths);
878  CuAssertIntEquals(tc,7,(int)iarr);
879  CuAssertStrEquals(tc,"a1", array[0]);
880  CuAssertStrEquals(tc,"",   array[1]);
881  CuAssertStrEquals(tc,"a2", array[2]);
882  CuAssertStrEquals(tc,"",   array[3]);
883  CuAssertStrEquals(tc,"a3", array[4]);
884  CuAssertStrEquals(tc,"a4", array[5]);
885  CuAssertStrEquals(tc,"a5", array[6]);
886
887  CuAssertIntEquals(tc, 2, (int)lengths[0]);
888  CuAssertIntEquals(tc, 0, (int)lengths[1]);
889  CuAssertIntEquals(tc, 2, (int)lengths[2]);
890  CuAssertIntEquals(tc, 0, (int)lengths[3]);
891  CuAssertIntEquals(tc, 2, (int)lengths[4]);
892  CuAssertIntEquals(tc, 2, (int)lengths[5]);
893  CuAssertIntEquals(tc, 2, (int)lengths[6]);
894
895  iarr = 10; strcpy(test, "|");
896  array  = split_array(test, &iarr, '|', lengths);
897  CuAssertIntEquals(tc,2,(int)iarr);
898  CuAssertStrEquals(tc,"",   array[0]);
899  CuAssertStrEquals(tc,"",   array[1]);
900
901  CuAssertIntEquals(tc, 0, (int)lengths[0]);
902  CuAssertIntEquals(tc, 0, (int)lengths[1]);
903
904  iarr = 10; strcpy(test, "|||");
905  array  = split_array(test, &iarr, '|', lengths);
906  CuAssertIntEquals(tc,4,(int)iarr);
907  CuAssertStrEquals(tc,"",   array[0]);
908  CuAssertStrEquals(tc,"",   array[1]);
909  CuAssertStrEquals(tc,"",   array[2]);
910  CuAssertStrEquals(tc,"",   array[3]);
911
912  CuAssertIntEquals(tc, 0, (int)lengths[0]);
913  CuAssertIntEquals(tc, 0, (int)lengths[1]);
914  CuAssertIntEquals(tc, 0, (int)lengths[2]);
915  CuAssertIntEquals(tc, 0, (int)lengths[3]);
916
917  iarr = 10; strcpy(test, " a1 ");
918  array  = split_array(test, &iarr, '|', lengths);
919  CuAssertIntEquals(tc,1,(int)iarr);
920  CuAssertStrEquals(tc,"a1",   array[0]);
921
922  CuAssertIntEquals(tc, 2, (int)lengths[0]);
923
924  iarr = 10; strcpy(test, "");
925  array  = split_array(test, &iarr, '|', lengths);
926  CuAssertIntEquals(tc,1,(int)iarr);
927  CuAssertStrEquals(tc,"",   array[0]);
928
929  CuAssertIntEquals(tc, 0, (int)lengths[0]);
930
931  /* WS separated */
932
933  iarr = 10; strcpy(test, "a1");
934  array  = split_array_ws (test, &iarr, lengths);
935  CuAssertIntEquals(tc,1,(int)iarr);
936  CuAssertStrEquals(tc,"a1",   array[0]);
937
938  CuAssertIntEquals(tc, 2, (int)lengths[0]);
939
940  iarr = 10; strcpy(test, " a1");
941  array  = split_array_ws (test, &iarr, lengths);
942  CuAssertIntEquals(tc,1,(int)iarr);
943  CuAssertStrEquals(tc,"a1",   array[0]);
944
945  CuAssertIntEquals(tc, 2, (int)lengths[0]);
946
947  iarr = 10; strcpy(test, " a1 ");
948  array  = split_array_ws (test, &iarr, lengths);
949  CuAssertIntEquals(tc,1,(int)iarr);
950  CuAssertStrEquals(tc,"a1",   array[0]);
951
952  CuAssertIntEquals(tc, 2, (int)lengths[0]);
953
954  iarr = 10; strcpy(test, "   ");
955  array  = split_array_ws (test, &iarr, lengths);
956  CuAssertIntEquals(tc,0,(int)iarr);
957  CuAssertTrue(tc, array[0] == NULL);
958
959  iarr = 10; strcpy(test, " a1 a2");
960  array  = split_array_ws (test, &iarr, lengths);
961  CuAssertIntEquals(tc,2,(int)iarr);
962  CuAssertStrEquals(tc,"a1",   array[0]);
963  CuAssertStrEquals(tc,"a2",   array[1]);
964
965  CuAssertIntEquals(tc, 2, (int)lengths[0]);
966  CuAssertIntEquals(tc, 2, (int)lengths[1]);
967
968  iarr = 10; strcpy(test, " a1  a2  ");
969  array  = split_array_ws (test, &iarr, lengths);
970  CuAssertIntEquals(tc,2,(int)iarr);
971  CuAssertStrEquals(tc,"a1",   array[0]);
972  CuAssertStrEquals(tc,"a2",   array[1]);
973
974  CuAssertIntEquals(tc, 2, (int)lengths[0]);
975  CuAssertIntEquals(tc, 2, (int)lengths[1]);
976
977  iarr = 10; strcpy(test, "");
978  array  = split_array_ws (test, &iarr, lengths);
979  CuAssertIntEquals(tc,0,(int)iarr);
980  CuAssertTrue(tc, array[0] == NULL);
981
982  iarr = 3; strcpy(test, " this is a test for remainder");
983  array  = split_array_ws (test, &iarr, lengths);
984  CuAssertIntEquals(tc,3,(int)iarr);
985  CuAssertStrEquals(tc,"this",   array[0]);
986  CuAssertStrEquals(tc,"is",     array[1]);
987  CuAssertStrEquals(tc,"a test for remainder",     array[2]);
988  for (i = 0; i < 3; ++i)
989    {
990      CuAssertIntEquals(tc, (int)strlen(array[i]), lengths[i] );
991    }
992
993  /* split_array_list */
994  iarr = 6; strcpy(test, " this(a) is_a(test);for(b),remainder(test)foo(bar)");
995  array  = split_array_list (test, &iarr, lengths);
996  CuAssertIntEquals(tc,3,(int)iarr);
997  CuAssertStrEquals(tc,"this(a)",   array[0]);
998  CuAssertStrEquals(tc,"is_a(test);for(b)",     array[1]);
999  CuAssertStrEquals(tc,"remainder(test)foo(bar)",     array[2]);
1000  for (i = 0; i < 3; ++i)
1001    {
1002      CuAssertIntEquals(tc, (int)strlen(array[i]), lengths[i] );
1003    }
1004
1005 
1006  /* string replace */
1007  s = sh_string_new_from_lchar3 ("abc ", 4, "def ", 4, "ghi ", 4);
1008  ovecnum = 2;
1009  ovector[0] = 0;  ovector[1] = 2;
1010  ovector[2] = 4;  ovector[3] = 11;
1011
1012  t = sh_string_replace(s, ovector, ovecnum, 
1013                        "___", 3);
1014  CuAssertPtrNotNull(tc, t);
1015  CuAssertStrEquals(tc, "___c ___ ",   t->str);
1016  CuAssertIntEquals(tc, 9, (int)t->len);
1017
1018  ovector[0] = 0;  ovector[1] = 2;
1019  ovector[2] = 4;  ovector[3] = 12; 
1020  t = sh_string_replace(s, ovector, ovecnum, 
1021                        "___", 3);
1022  CuAssertPtrNotNull(tc, t);
1023  CuAssertStrEquals(tc, "___c ___",   t->str);
1024  CuAssertIntEquals(tc, 8, (int)t->len);
1025
1026  ovector[0] = 0;  ovector[1] = 0;
1027  ovector[2] = 0;  ovector[3] = 0; 
1028  t = sh_string_replace(s, ovector, ovecnum, 
1029                        "___", 3);
1030  CuAssertTrue(tc, t == NULL);
1031
1032  ovector[0] = 0;  ovector[1] = 3;
1033  ovector[2] = 3;  ovector[3] = 6; 
1034  t = sh_string_replace(s, ovector, ovecnum, 
1035                        "___", 3);
1036 
1037  CuAssertPtrNotNull(tc, t);
1038  CuAssertStrEquals(tc, "______f ghi ",   t->str);
1039  CuAssertIntEquals(tc, 12, (int)t->len);
1040
1041  ovector[0] = 4;  ovector[1] = 5;
1042  ovector[2] = 11;  ovector[3] = 12; 
1043  t = sh_string_replace(s, ovector, ovecnum, 
1044                        "___", 3);
1045  CuAssertPtrNotNull(tc, t);
1046  CuAssertStrEquals(tc, "abc ___ef ghi___",   t->str);
1047  CuAssertIntEquals(tc, 16, (int)t->len);
1048
1049  t = sh_string_replace(s, ovector, 0, 
1050                        "___", 3);
1051  CuAssertPtrNotNull(tc, t);
1052  CuAssertStrEquals(tc, s->str,   t->str);
1053  CuAssertIntEquals(tc, (int)s->len, (int)t->len);
1054
1055}
1056
1057#endif
Note: See TracBrowser for help on using the repository browser.