2009-07-01 02:01:20 +04:00
/*
* ( c ) 2009 Arnaldo Carvalho de Melo < acme @ redhat . com >
*
* Licensed under the GPLv2 .
*/
# include "strlist.h"
# include <errno.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
static struct str_node * str_node__new ( const char * s , bool dupstr )
{
struct str_node * self = malloc ( sizeof ( * self ) ) ;
if ( self ! = NULL ) {
if ( dupstr ) {
s = strdup ( s ) ;
if ( s = = NULL )
goto out_delete ;
}
self - > s = s ;
}
return self ;
out_delete :
free ( self ) ;
return NULL ;
}
static void str_node__delete ( struct str_node * self , bool dupstr )
{
if ( dupstr )
free ( ( void * ) self - > s ) ;
free ( self ) ;
}
int strlist__add ( struct strlist * self , const char * new_entry )
{
struct rb_node * * p = & self - > entries . rb_node ;
struct rb_node * parent = NULL ;
struct str_node * sn ;
while ( * p ! = NULL ) {
int rc ;
parent = * p ;
sn = rb_entry ( parent , struct str_node , rb_node ) ;
rc = strcmp ( sn - > s , new_entry ) ;
if ( rc > 0 )
p = & ( * p ) - > rb_left ;
else if ( rc < 0 )
p = & ( * p ) - > rb_right ;
else
return - EEXIST ;
}
sn = str_node__new ( new_entry , self - > dupstr ) ;
if ( sn = = NULL )
return - ENOMEM ;
rb_link_node ( & sn - > rb_node , parent , p ) ;
rb_insert_color ( & sn - > rb_node , & self - > entries ) ;
2009-07-11 19:18:34 +04:00
+ + self - > nr_entries ;
2009-07-01 02:01:20 +04:00
return 0 ;
}
int strlist__load ( struct strlist * self , const char * filename )
{
char entry [ 1024 ] ;
int err ;
FILE * fp = fopen ( filename , " r " ) ;
if ( fp = = NULL )
return errno ;
while ( fgets ( entry , sizeof ( entry ) , fp ) ! = NULL ) {
const size_t len = strlen ( entry ) ;
if ( len = = 0 )
continue ;
entry [ len - 1 ] = ' \0 ' ;
err = strlist__add ( self , entry ) ;
if ( err ! = 0 )
goto out ;
}
err = 0 ;
out :
fclose ( fp ) ;
return err ;
}
void strlist__remove ( struct strlist * self , struct str_node * sn )
{
rb_erase ( & sn - > rb_node , & self - > entries ) ;
str_node__delete ( sn , self - > dupstr ) ;
}
2009-12-15 18:31:49 +03:00
struct str_node * strlist__find ( struct strlist * self , const char * entry )
2009-07-01 02:01:20 +04:00
{
struct rb_node * * p = & self - > entries . rb_node ;
struct rb_node * parent = NULL ;
while ( * p ! = NULL ) {
struct str_node * sn ;
int rc ;
parent = * p ;
sn = rb_entry ( parent , struct str_node , rb_node ) ;
rc = strcmp ( sn - > s , entry ) ;
if ( rc > 0 )
p = & ( * p ) - > rb_left ;
else if ( rc < 0 )
p = & ( * p ) - > rb_right ;
else
2009-12-15 18:31:49 +03:00
return sn ;
2009-07-01 02:01:20 +04:00
}
2009-12-15 18:31:49 +03:00
return NULL ;
2009-07-01 02:01:20 +04:00
}
static int strlist__parse_list_entry ( struct strlist * self , const char * s )
{
if ( strncmp ( s , " file:// " , 7 ) = = 0 )
return strlist__load ( self , s + 7 ) ;
return strlist__add ( self , s ) ;
}
int strlist__parse_list ( struct strlist * self , const char * s )
{
char * sep ;
int err ;
while ( ( sep = strchr ( s , ' , ' ) ) ! = NULL ) {
* sep = ' \0 ' ;
err = strlist__parse_list_entry ( self , s ) ;
* sep = ' , ' ;
if ( err ! = 0 )
return err ;
s = sep + 1 ;
}
return * s ? strlist__parse_list_entry ( self , s ) : 0 ;
}
struct strlist * strlist__new ( bool dupstr , const char * slist )
{
struct strlist * self = malloc ( sizeof ( * self ) ) ;
if ( self ! = NULL ) {
2009-07-11 19:18:34 +04:00
self - > entries = RB_ROOT ;
self - > dupstr = dupstr ;
self - > nr_entries = 0 ;
2009-07-01 02:01:20 +04:00
if ( slist & & strlist__parse_list ( self , slist ) ! = 0 )
goto out_error ;
}
return self ;
out_error :
free ( self ) ;
return NULL ;
}
void strlist__delete ( struct strlist * self )
{
if ( self ! = NULL ) {
struct str_node * pos ;
struct rb_node * next = rb_first ( & self - > entries ) ;
while ( next ) {
pos = rb_entry ( next , struct str_node , rb_node ) ;
next = rb_next ( & pos - > rb_node ) ;
strlist__remove ( self , pos ) ;
}
self - > entries = RB_ROOT ;
free ( self ) ;
}
}
2009-07-11 19:18:34 +04:00
struct str_node * strlist__entry ( const struct strlist * self , unsigned int idx )
{
struct rb_node * nd ;
for ( nd = rb_first ( & self - > entries ) ; nd ; nd = rb_next ( nd ) ) {
struct str_node * pos = rb_entry ( nd , struct str_node , rb_node ) ;
if ( ! idx - - )
return pos ;
}
return NULL ;
}