1 /*
2 * slist.c
3 *
4 * version: 2019-01-14
5 *
6 * Copyright (c) Chris Putnam 2004-2020
7 *
8 * Source code released under the GPL version 2
9 *
10 * Implements a simple managed array of strs.
11 *
12 */
13 #include "slist.h"
14
15 /* Do not use asserts in VPLIST_NOASSERT defined */
16 #ifdef VPLIST_NOASSERT
17 #define NDEBUG
18 #endif
19 #include <assert.h>
20
21 #define SLIST_MINALLOC (20)
22
23 #define SLIST_EXACT_SIZE (0)
24 #define SLIST_DOUBLE_SIZE (1)
25
26 /*
27 * returns 1 if n is valid string in slist
28 */
29 static inline int
slist_valid_num(slist * a,slist_index n)30 slist_valid_num( slist *a, slist_index n )
31 {
32 if ( n < 0 || n >= a->n ) return 0;
33 return 1;
34 }
35
36 void
slist_init(slist * a)37 slist_init( slist *a )
38 {
39 assert( a );
40
41 a->strs = NULL;
42 a->max = 0;
43 a->n = 0;
44 a->sorted = 1;
45 }
46
47 int
slist_init_values(slist * a,...)48 slist_init_values( slist *a, ... )
49 {
50 int status = SLIST_OK;
51 va_list ap;
52 str *s;
53
54 slist_init( a );
55
56 va_start( ap, a );
57 do {
58 s = va_arg( ap, str * );
59 if ( s ) {
60 status = slist_add( a, s );
61 if ( status!=SLIST_OK ) goto out;
62 }
63 } while ( s );
64 out:
65 va_end( ap );
66
67 return status;
68 }
69
70 int
slist_init_valuesc(slist * a,...)71 slist_init_valuesc( slist *a, ... )
72 {
73 int status = SLIST_OK;
74 va_list ap;
75 char *s;
76
77 slist_init( a );
78
79 va_start( ap, a );
80 do {
81 s = va_arg( ap, char * );
82 if ( s ) {
83 status = slist_addc( a, s );
84 if ( status!=SLIST_OK ) goto out;
85 }
86 } while ( s );
87 out:
88 va_end( ap );
89
90 return status;
91 }
92
93 void
slist_empty(slist * a)94 slist_empty( slist *a )
95 {
96 slist_index i;
97
98 assert( a );
99
100 for ( i=0; i<a->max; ++i )
101 str_empty( &(a->strs[i]) );
102
103 a->n = 0;
104 a->sorted = 1;
105 }
106
107 void
slist_free(slist * a)108 slist_free( slist *a )
109 {
110 slist_index i;
111
112 assert( a );
113
114 for ( i=0; i<a->max; ++i )
115 str_free( &(a->strs[i]) );
116
117 free( a->strs );
118 slist_init( a );
119 }
120
121 slist *
slist_new(void)122 slist_new( void )
123 {
124 slist *a;
125
126 a = ( slist * ) malloc( sizeof ( slist ) );
127 if ( a ) slist_init( a );
128
129 return a;
130 }
131
132 void
slist_delete(slist * a)133 slist_delete( slist *a )
134 {
135 assert( a );
136
137 slist_free( a );
138 free( a );
139 }
140
141 void
slist_deletev(void * v)142 slist_deletev( void *v )
143 {
144 slist_delete( (slist*) v );
145 }
146
147 void
slist_swap(slist * a,slist_index n1,slist_index n2)148 slist_swap( slist *a, slist_index n1, slist_index n2 )
149 {
150 assert( a );
151
152 if ( slist_valid_num( a, n1 ) && slist_valid_num( a, n2 ) )
153 str_swapstrings( &(a->strs[n1]), &(a->strs[n2]) );
154 }
155
156 static int
slist_revcomp(const void * v1,const void * v2)157 slist_revcomp( const void *v1, const void *v2 )
158 {
159 str *s1 = ( str *) v1;
160 str *s2 = ( str *) v2;
161 int n;
162
163 if ( !s1->len && !s2->len ) return 0;
164 else if ( !s1->len ) return 1;
165 else if ( !s2->len ) return -1;
166
167 n = str_strcmp( s1, s2 );
168 if ( n==0 ) return 0;
169 else if ( n > 0 ) return -1;
170 else return 1;
171 }
172
173 static int
slist_comp(const void * v1,const void * v2)174 slist_comp( const void *v1, const void *v2 )
175 {
176 str *s1 = ( str *) v1;
177 str *s2 = ( str *) v2;
178 if ( !s1->len && !s2->len ) return 0;
179 else if ( !s1->len ) return -1;
180 else if ( !s2->len ) return 1;
181 else return str_strcmp( s1, s2 );
182 }
183
184 static int
slist_comp_step(slist * a,slist_index n1,slist_index n2)185 slist_comp_step( slist *a, slist_index n1, slist_index n2 )
186 {
187 return slist_comp( (const void*) &(a->strs[n1]), (const void*) &(a->strs[n2]) );
188 }
189
190 static str *
slist_set_cleanup(slist * a,slist_index n)191 slist_set_cleanup( slist *a, slist_index n )
192 {
193 if ( str_memerr( &(a->strs[n]) ) ) return NULL;
194 if ( a->sorted ) {
195 if ( n>0 && slist_comp_step( a, n-1, n )>0 )
196 a->sorted = 0;
197 }
198 if ( a->sorted ) {
199 if ( n<a->n-1 && slist_comp_step( a, n, n+1 )>0 )
200 a->sorted = 0;
201 }
202 return &(a->strs[n]);
203 }
204
205 str *
slist_setc(slist * a,slist_index n,const char * s)206 slist_setc( slist *a, slist_index n, const char *s )
207 {
208 assert( a );
209 assert( s );
210
211 if ( !slist_valid_num( a, n ) ) return NULL;
212 str_strcpyc( &(a->strs[n]), s );
213 return slist_set_cleanup( a, n );
214 }
215
216 str *
slist_set(slist * a,slist_index n,str * s)217 slist_set( slist *a, slist_index n, str *s )
218 {
219 assert( s );
220
221 return slist_setc( a, n, str_cstr( s ) );
222 }
223
224 /*
225 * return pointer to str 'n'
226 */
227 str *
slist_str(slist * a,slist_index n)228 slist_str( slist *a, slist_index n )
229 {
230 assert( a );
231
232 if ( !slist_valid_num( a, n ) ) return NULL;
233 else return &(a->strs[n]);
234 }
235
236 /*
237 * return pointer to C string 'n'
238 *
239 * So long as the index is a valid number ensure
240 * that a pointer is returned even if the newstr isn't
241 * allocated. Only return NULL if the index
242 * is invalid. Thus we can convert loops like:
243 *
244 * for ( i=0; i<a->n; ++i ) {
245 * p = slist_cstr( a, i );
246 * if ( p==NULL ) continue; // empty string
247 * ...
248 * }
249 *
250 * to
251 *
252 * i = 0;
253 * while ( ( p = slist_cstr( a, i ) ) ) {
254 * ...
255 * i++;
256 * }
257 *
258 */
259 char *
slist_cstr(slist * a,slist_index n)260 slist_cstr( slist *a, slist_index n )
261 {
262 static char empty[] = "";
263 char *p;
264
265 assert( a );
266
267 if ( !slist_valid_num( a, n ) ) return NULL;
268 p = str_cstr( &(a->strs[n]) );
269 if ( p ) return p;
270 else return empty;
271 }
272
273 static inline int
slist_alloc(slist * a,slist_index alloc)274 slist_alloc( slist *a, slist_index alloc )
275 {
276 slist_index i;
277
278 a->strs = ( str* ) malloc( sizeof( str ) * alloc );
279 if ( !(a->strs) ) return SLIST_ERR_MEMERR;
280
281 a->max = alloc;
282 a->n = 0;
283
284 for ( i=0; i<alloc; ++i )
285 str_init( &(a->strs[i]) );
286
287 return SLIST_OK;
288 }
289
290 static inline int
slist_realloc(slist * a,slist_index alloc)291 slist_realloc( slist *a, slist_index alloc )
292 {
293 slist_index i;
294 str *more;
295
296 more = ( str* ) realloc( a->strs, sizeof( str ) * alloc );
297 if ( !more ) return SLIST_ERR_MEMERR;
298
299 a->strs = more;
300
301 for ( i=a->max; i<alloc; ++i )
302 str_init( &(a->strs[i]) );
303
304 a->max = alloc;
305
306 return SLIST_OK;
307 }
308
309 #define SLIST_EXACT_SIZE (0)
310 #define SLIST_DOUBLE_SIZE (1)
311
312 static int
slist_ensure_space(slist * a,slist_index n,int mode)313 slist_ensure_space( slist *a, slist_index n, int mode )
314 {
315 int status = SLIST_OK;
316 int alloc = n;
317
318 if ( a->max==0 ) {
319 if ( mode == SLIST_DOUBLE_SIZE && alloc < SLIST_MINALLOC ) alloc = SLIST_MINALLOC;
320 status = slist_alloc( a, alloc );
321 }
322
323 else if ( a->max < n ) {
324 if ( mode == SLIST_DOUBLE_SIZE && alloc < a->max * 2 ) alloc = a->max * 2;
325 status = slist_realloc( a, alloc );
326 }
327
328 return status;
329 }
330
331 int
slist_addvp(slist * a,int mode,void * vp)332 slist_addvp( slist *a, int mode, void *vp )
333 {
334 str *s = NULL;
335 int status;
336
337 status = slist_ensure_space( a, a->n+1, SLIST_DOUBLE_SIZE );
338
339 if ( status==SLIST_OK ) {
340
341 s = &( a->strs[a->n] );
342
343 if ( mode==SLIST_CHR )
344 str_strcpyc( s, (const char*) vp );
345 else
346 str_strcpy( s, (str*) vp );
347
348 if ( str_memerr( s ) ) return SLIST_ERR_MEMERR;
349 a->n++;
350 if ( a->sorted && a->n > 1 ) {
351 if ( slist_comp_step( a, a->n-2, a->n-1 ) > 0 )
352 a->sorted = 0;
353 }
354
355 }
356
357 return SLIST_OK;
358 }
359 int
slist_addc(slist * a,const char * s)360 slist_addc( slist *a, const char *s )
361 {
362 return slist_addvp( a, SLIST_CHR, (void*)s );
363 }
364 int
slist_add(slist * a,str * s)365 slist_add( slist *a, str *s )
366 {
367 return slist_addvp( a, SLIST_STR, (void*)s );
368 }
369
370 int
slist_addvp_ret(slist * a,int mode,void * vp,int retok,int reterr)371 slist_addvp_ret( slist *a, int mode, void *vp, int retok, int reterr )
372 {
373 int status = slist_addvp( a, mode, vp );
374 if ( status==SLIST_OK ) return retok;
375 else return reterr;
376 }
377 int
slist_addc_ret(slist * a,const char * value,int retok,int reterr)378 slist_addc_ret( slist *a, const char *value, int retok, int reterr )
379 {
380 int status = slist_addc( a, value );
381 if ( status==SLIST_OK ) return retok;
382 else return reterr;
383 }
384 int
slist_add_ret(slist * a,str * value,int retok,int reterr)385 slist_add_ret( slist *a, str *value, int retok, int reterr )
386 {
387 int status = slist_add( a, value );
388 if ( status==SLIST_OK ) return retok;
389 else return reterr;
390 }
391
392 int
slist_addvp_unique(slist * a,int mode,void * vp)393 slist_addvp_unique( slist *a, int mode, void *vp )
394 {
395 int n;
396
397 if ( mode==SLIST_CHR )
398 n = slist_findc( a, (const char*) vp );
399 else
400 n = slist_find( a, (str*) vp );
401
402 if ( slist_wasfound( a, n ) )
403 return SLIST_OK;
404 else
405 return slist_addvp( a, mode, vp );
406 }
407 int
slist_addc_unique(slist * a,const char * s)408 slist_addc_unique( slist *a, const char *s )
409 {
410 return slist_addvp_unique( a, SLIST_CHR, (void*)s );
411 }
412 int
slist_add_unique(slist * a,str * s)413 slist_add_unique( slist *a, str *s )
414 {
415 return slist_addvp_unique( a, SLIST_STR, (void*)s );
416 }
417
418 int
slist_addvp_unique_ret(slist * a,int mode,void * vp,int retok,int reterr)419 slist_addvp_unique_ret( slist *a, int mode, void *vp, int retok, int reterr )
420 {
421 int status = slist_addvp_unique( a, mode, vp );
422 if ( status==SLIST_OK ) return retok;
423 else return reterr;
424 }
425 int
slist_addc_unique_ret(slist * a,const char * s,int retok,int reterr)426 slist_addc_unique_ret( slist *a, const char *s, int retok, int reterr )
427 {
428 int status = slist_addc_unique( a, s );
429 if ( status==SLIST_OK ) return retok;
430 else return reterr;
431 }
432 int
slist_add_unique_ret(slist * a,str * s,int retok,int reterr)433 slist_add_unique_ret( slist *a, str *s, int retok, int reterr )
434 {
435 int status = slist_add_unique( a, s );
436 if ( status==SLIST_OK ) return retok;
437 else return reterr;
438 }
439
440 int
slist_addvp_all(slist * a,int mode,...)441 slist_addvp_all( slist *a, int mode, ... )
442 {
443 int status = SLIST_OK;
444 va_list ap;
445 void *v;
446
447 va_start( ap, mode );
448
449 do {
450
451 if ( mode==SLIST_CHR )
452 v = va_arg( ap, char * );
453 else
454 v = va_arg( ap, str * );
455
456 if ( v ) {
457 status = slist_addvp( a, mode, v );
458 if ( status!=SLIST_OK ) goto out;
459 }
460
461 } while ( v );
462
463 out:
464 va_end( ap );
465 return status;
466 }
467
468 int
slist_add_all(slist * a,...)469 slist_add_all( slist *a, ... )
470 {
471 int status = SLIST_OK;
472 va_list ap;
473 str *v;
474
475 va_start( ap, a );
476
477 do {
478 v = va_arg( ap, str * );
479
480 if ( v ) {
481 status = slist_addvp( a, SLIST_STR, (void*)v );
482 if ( status!=SLIST_OK ) goto out;
483 }
484
485 } while ( v );
486 out:
487 va_end( ap );
488 return status;
489 }
490
491 int
slist_addc_all(slist * a,...)492 slist_addc_all( slist *a, ... )
493 {
494 int status = SLIST_OK;
495 const char *v;
496 va_list ap;
497
498 va_start( ap, a );
499
500 do {
501
502 v = va_arg( ap, const char * );
503
504 if ( v ) {
505 status = slist_addvp( a, SLIST_CHR, (void*)v );
506 if ( status!=SLIST_OK ) goto out;
507 }
508
509 } while ( v );
510 out:
511 va_end( ap );
512 return status;
513 }
514
515 int
slist_append(slist * a,slist * toadd)516 slist_append( slist *a, slist *toadd )
517 {
518 int i, status;
519
520 assert( a );
521 assert( toadd );
522
523 status = slist_ensure_space( a, a->n + toadd->n, SLIST_EXACT_SIZE );
524
525 if ( status == SLIST_OK ) {
526
527 for ( i=0; i<toadd->n; ++i ) {
528 str_strcpy( &(a->strs[a->n+i]), &(toadd->strs[i]) );
529 if ( str_memerr( &(a->strs[a->n+i]) ) ) return SLIST_ERR_MEMERR;
530 }
531
532 if ( a->sorted && toadd->sorted == 0 ) a->sorted = 0;
533 if ( a->sorted && a->n > 0 ) {
534 if ( slist_comp_step( a, a->n-1, a->n ) > 0 ) {
535 a->sorted = 0;
536 }
537 }
538
539 a->n += toadd->n;
540
541 }
542
543 return status;
544 }
545
546 int
slist_append_unique(slist * a,slist * toadd)547 slist_append_unique( slist *a, slist *toadd )
548 {
549 int i, status;
550
551 assert( a );
552 assert( toadd );
553
554 for ( i=0; i<toadd->n; ++i ) {
555 status = slist_add_unique( a, &(toadd->strs[i]) );
556 if ( status!=SLIST_OK ) return status;
557 }
558
559 return SLIST_OK;
560 }
561
562 int
slist_append_ret(slist * a,slist * toadd,int retok,int reterr)563 slist_append_ret( slist *a, slist *toadd, int retok, int reterr )
564 {
565 int status;
566
567 status = slist_append( a, toadd );
568 if ( status==SLIST_OK ) return retok;
569 else return reterr;
570 }
571
572 int
slist_append_unique_ret(slist * a,slist * toadd,int retok,int reterr)573 slist_append_unique_ret( slist *a, slist *toadd, int retok, int reterr )
574 {
575 int status;
576
577 status = slist_append_unique( a, toadd );
578 if ( status==SLIST_OK ) return retok;
579 else return reterr;
580 }
581
582 int
slist_remove(slist * a,slist_index n)583 slist_remove( slist *a, slist_index n )
584 {
585 int i;
586
587 assert( a );
588
589 if ( !slist_valid_num( a, n ) ) return SLIST_ERR_BADPARAM;
590
591 for ( i=n+1; i<a->n; ++i ) {
592 str_strcpy( &(a->strs[i-1]), &(a->strs[i]) );
593 if ( str_memerr( &(a->strs[i-1]) ) ) return SLIST_ERR_MEMERR;
594 }
595
596 a->n--;
597
598 return SLIST_OK;
599 }
600
601 void
slist_sort(slist * a)602 slist_sort( slist *a )
603 {
604 qsort( a->strs, a->n, sizeof( str ), slist_comp );
605 a->sorted = 1;
606 }
607
608 void
slist_revsort(slist * a)609 slist_revsort( slist *a )
610 {
611 qsort( a->strs, a->n, sizeof( str ), slist_revcomp );
612 a->sorted = 0;
613 }
614
615 static slist_index
slist_find_sorted(slist * a,const char * searchstr)616 slist_find_sorted( slist *a, const char *searchstr )
617 {
618 slist_index min, max, mid;
619 str s, *cs;
620 int comp;
621
622 assert( a );
623 assert( searchstr );
624
625 str_initstrc( &s, searchstr );
626 min = 0;
627 max = a->n - 1;
628 while ( min <= max ) {
629 mid = ( min + max ) / 2;
630 cs = slist_str( a, mid );
631 comp = slist_comp( (void*)cs, (void*) (&s) );
632 if ( comp==0 ) {
633 str_free( &s );
634 return mid;
635 }
636 else if ( comp > 0 ) max = mid - 1;
637 else if ( comp < 0 ) min = mid + 1;
638 }
639 str_free( &s );
640 return -1;
641 }
642
643 static slist_index
slist_find_simple(slist * a,const char * searchstr,int nocase)644 slist_find_simple( slist *a, const char *searchstr, int nocase )
645 {
646 slist_index i;
647
648 assert( a );
649 assert( searchstr );
650
651 if ( nocase ) {
652 for ( i=0; i<a->n; ++i )
653 if ( !str_strcasecmpc( &(a->strs[i]), searchstr ) )
654 return i;
655 } else {
656 for ( i=0; i<a->n; ++i )
657 if ( !str_strcmpc( &(a->strs[i]), searchstr ) )
658 return i;
659 }
660 return -1;
661 }
662
663 slist_index
slist_findc(slist * a,const char * searchstr)664 slist_findc( slist *a, const char *searchstr )
665 {
666 assert( a );
667
668 if ( a->n==0 ) return -1;
669 if ( a->sorted )
670 return slist_find_sorted( a, searchstr );
671 else
672 return slist_find_simple( a, searchstr, 0 );
673 }
674
675 slist_index
slist_find(slist * a,str * searchstr)676 slist_find( slist *a, str *searchstr )
677 {
678 if ( searchstr->len==0 ) return -1;
679 return slist_findc( a, str_cstr( searchstr ) );
680 }
681
682 slist_index
slist_findnocasec(slist * a,const char * searchstr)683 slist_findnocasec( slist *a, const char *searchstr )
684 {
685 assert( a );
686
687 return slist_find_simple( a, searchstr, 1 );
688 }
689
690 slist_index
slist_findnocase(slist * a,str * searchstr)691 slist_findnocase( slist *a, str *searchstr )
692 {
693 if ( searchstr->len==0 ) return -1;
694 return slist_findnocasec( a, str_cstr( searchstr ) );
695 }
696
697 int
slist_wasfound(slist * a,slist_index n)698 slist_wasfound( slist *a, slist_index n )
699 {
700 return ( n!=-1 );
701 }
702
703 int
slist_wasnotfound(slist * a,slist_index n)704 slist_wasnotfound( slist *a, slist_index n )
705 {
706 return ( n==-1 );
707 }
708
709 int
slist_fillfp(slist * a,FILE * fp,unsigned char skip_blank_lines)710 slist_fillfp( slist *a, FILE *fp, unsigned char skip_blank_lines )
711 {
712 int status, ret = SLIST_OK;
713 str line;
714
715 assert( a );
716 assert( fp );
717
718 slist_empty( a );
719 str_init( &line );
720
721 while ( str_fgetline( &line, fp ) ) {
722 if ( skip_blank_lines && line.len==0 ) continue;
723 status = slist_add( a, &line );
724 if ( status!=SLIST_OK ) {
725 ret = SLIST_ERR_MEMERR;
726 goto out;
727 }
728 }
729
730 out:
731 str_free( &line );
732 return ret;
733 }
734
735 int
slist_fill(slist * a,const char * filename,unsigned char skip_blank_lines)736 slist_fill( slist *a, const char *filename, unsigned char skip_blank_lines )
737 {
738 FILE *fp;
739 int ret;
740
741 fp = fopen( filename, "r" );
742 if ( !fp ) return SLIST_ERR_CANTOPEN;
743
744 ret = slist_fillfp( a, fp, skip_blank_lines );
745
746 fclose( fp );
747
748 return ret;
749 }
750
751 int
slist_copy(slist * to,slist * from)752 slist_copy( slist *to, slist *from )
753 {
754 slist_index i;
755 int status;
756
757 assert( to );
758 assert( from );
759
760 slist_free( to );
761
762 if ( from->n==0 ) return SLIST_OK;
763
764 status = slist_ensure_space( to, from->n, SLIST_EXACT_SIZE );
765
766 if ( status == SLIST_OK ) {
767
768 to->sorted = from->sorted;
769 to->n = from->n;
770
771 for ( i=0; i<from->n; i++ ) {
772 str_strcpy( &(to->strs[i]), &(from->strs[i]) );
773 if ( str_memerr( &(to->strs[i]) ) ) return SLIST_ERR_MEMERR;
774 }
775
776 }
777 return SLIST_OK;
778 }
779
780 int
slist_copy_ret(slist * to,slist * from,int retok,int reterr)781 slist_copy_ret( slist *to, slist *from, int retok, int reterr )
782 {
783 int status = slist_copy( to, from );
784 if ( status==SLIST_OK ) return retok;
785 else return reterr;
786 }
787
788 slist *
slist_dup(slist * from)789 slist_dup( slist *from )
790 {
791 int status;
792 slist *to;
793
794 to = slist_new();
795 if ( to ) {
796 status = slist_copy( to, from );
797 if ( status!=SLIST_OK ) {
798 slist_delete( to );
799 to = NULL;
800 }
801 }
802
803 return to;
804 }
805
806 unsigned long
slist_get_maxlen(slist * a)807 slist_get_maxlen( slist *a )
808 {
809 unsigned long max = 0;
810 slist_index i;
811 str *s;
812
813 assert( a );
814
815 for ( i=0; i<a->n; ++i ) {
816 s = slist_str( a, i );
817 if ( s->len > max ) max = s->len;
818 }
819
820 return max;
821 }
822
823 void
slist_dump(slist * a,FILE * fp,int newline)824 slist_dump( slist *a, FILE *fp, int newline )
825 {
826 slist_index i;
827
828 assert( a );
829 assert( fp );
830
831 if ( newline ) {
832 for ( i=0; i<a->n; ++i )
833 fprintf( fp, "%s\n", slist_cstr( a, i ) );
834 }
835
836 else {
837 for ( i=0; i<a->n; ++i )
838 fprintf( fp, "%s", slist_cstr( a, i ) );
839 }
840 }
841
842 int
slist_match_entry(slist * a,int n,const char * s)843 slist_match_entry( slist *a, int n, const char *s )
844 {
845 assert( a );
846
847 if ( !slist_valid_num( a, n ) ) return 0;
848 if ( str_strcmpc( &(a->strs[n]), s ) ) return 0;
849 return 1;
850 }
851
852 void
slist_trimend(slist * a,int n)853 slist_trimend( slist *a, int n )
854 {
855 slist_index i;
856
857 assert( a );
858
859 if ( a->n - n < 1 ) {
860 slist_empty( a );
861 } else {
862 for ( i=a->n -n; i<a->n; ++i ) {
863 str_empty( &(a->strs[i]) );
864 }
865 a->n -= n;
866 }
867 }
868
869 int
slist_tokenizec(slist * tokens,char * p,const char * delim,int merge_delim)870 slist_tokenizec( slist *tokens, char *p, const char *delim, int merge_delim )
871 {
872 int status, ret = SLIST_OK;
873 char *q;
874 str s;
875
876 assert( tokens );
877
878 slist_empty( tokens );
879 str_init( &s );
880 while ( p && *p ) {
881 q = p;
882 while ( *q && !strchr( delim, *q ) ) q++;
883 str_segcpy( &s, p, q );
884 if ( str_memerr( &s ) ) { ret = SLIST_ERR_MEMERR; goto out; }
885 if ( s.len ) {
886 status = slist_addvp( tokens, SLIST_STR, (void*) &s );
887 if ( status!=SLIST_OK ) { ret = SLIST_ERR_MEMERR; goto out; }
888 } else if ( !merge_delim ) {
889 status = slist_addvp( tokens, SLIST_CHR, (void*) "" );
890 if ( status!=SLIST_OK ) { ret = SLIST_ERR_MEMERR; goto out; }
891 }
892 p = q;
893 if ( *p ) p++;
894 }
895 out:
896 str_free( &s );
897 return ret;
898 }
899
900 int
slist_tokenize(slist * tokens,str * in,const char * delim,int merge_delim)901 slist_tokenize( slist *tokens, str *in, const char *delim, int merge_delim )
902 {
903 return slist_tokenizec( tokens, str_cstr( in ), delim, merge_delim );
904 }
905
906 void
slists_init(slist * a,...)907 slists_init( slist *a, ... )
908 {
909 slist *a2;
910 va_list ap;
911 slist_init( a );
912 va_start( ap, a );
913 do {
914 a2 = va_arg( ap, slist * );
915 if ( a2 ) slist_init( a2 );
916 } while ( a2 );
917 va_end( ap );
918 }
919
920 void
slists_free(slist * a,...)921 slists_free( slist *a, ... )
922 {
923 slist *a2;
924 va_list ap;
925 slist_free( a );
926 va_start( ap, a );
927 do {
928 a2 = va_arg( ap, slist * );
929 if ( a2 ) slist_free( a2 );
930 } while ( a2 );
931 va_end( ap );
932 }
933
934 void
slists_empty(slist * a,...)935 slists_empty( slist *a, ... )
936 {
937 slist *a2;
938 va_list ap;
939 slist_empty( a );
940 va_start( ap, a );
941 do {
942 a2 = va_arg( ap, slist * );
943 if ( a2 ) slist_empty( a2 );
944 } while ( a2 );
945 va_end( ap );
946 }
947