Home | History | Annotate | Download | only in util
      1 /*
      2  * (c) 2009 Arnaldo Carvalho de Melo <acme (at) redhat.com>
      3  *
      4  * Licensed under the GPLv2.
      5  */
      6 
      7 #include "strlist.h"
      8 #include <errno.h>
      9 #include <stdio.h>
     10 #include <stdlib.h>
     11 #include <string.h>
     12 
     13 static struct str_node *str_node__new(const char *s, bool dupstr)
     14 {
     15 	struct str_node *self = malloc(sizeof(*self));
     16 
     17 	if (self != NULL) {
     18 		if (dupstr) {
     19 			s = strdup(s);
     20 			if (s == NULL)
     21 				goto out_delete;
     22 		}
     23 		self->s = s;
     24 	}
     25 
     26 	return self;
     27 
     28 out_delete:
     29 	free(self);
     30 	return NULL;
     31 }
     32 
     33 static void str_node__delete(struct str_node *self, bool dupstr)
     34 {
     35 	if (dupstr)
     36 		free((void *)self->s);
     37 	free(self);
     38 }
     39 
     40 int strlist__add(struct strlist *self, const char *new_entry)
     41 {
     42 	struct rb_node **p = &self->entries.rb_node;
     43 	struct rb_node *parent = NULL;
     44 	struct str_node *sn;
     45 
     46 	while (*p != NULL) {
     47 		int rc;
     48 
     49 		parent = *p;
     50 		sn = rb_entry(parent, struct str_node, rb_node);
     51 		rc = strcmp(sn->s, new_entry);
     52 
     53 		if (rc > 0)
     54 			p = &(*p)->rb_left;
     55 		else if (rc < 0)
     56 			p = &(*p)->rb_right;
     57 		else
     58 			return -EEXIST;
     59 	}
     60 
     61 	sn = str_node__new(new_entry, self->dupstr);
     62 	if (sn == NULL)
     63 		return -ENOMEM;
     64 
     65 	rb_link_node(&sn->rb_node, parent, p);
     66 	rb_insert_color(&sn->rb_node, &self->entries);
     67 	++self->nr_entries;
     68 
     69 	return 0;
     70 }
     71 
     72 int strlist__load(struct strlist *self, const char *filename)
     73 {
     74 	char entry[1024];
     75 	int err;
     76 	FILE *fp = fopen(filename, "r");
     77 
     78 	if (fp == NULL)
     79 		return errno;
     80 
     81 	while (fgets(entry, sizeof(entry), fp) != NULL) {
     82 		const size_t len = strlen(entry);
     83 
     84 		if (len == 0)
     85 			continue;
     86 		entry[len - 1] = '\0';
     87 
     88 		err = strlist__add(self, entry);
     89 		if (err != 0)
     90 			goto out;
     91 	}
     92 
     93 	err = 0;
     94 out:
     95 	fclose(fp);
     96 	return err;
     97 }
     98 
     99 void strlist__remove(struct strlist *self, struct str_node *sn)
    100 {
    101 	rb_erase(&sn->rb_node, &self->entries);
    102 	str_node__delete(sn, self->dupstr);
    103 }
    104 
    105 struct str_node *strlist__find(struct strlist *self, const char *entry)
    106 {
    107 	struct rb_node **p = &self->entries.rb_node;
    108 	struct rb_node *parent = NULL;
    109 
    110 	while (*p != NULL) {
    111 		struct str_node *sn;
    112 		int rc;
    113 
    114 		parent = *p;
    115 		sn = rb_entry(parent, struct str_node, rb_node);
    116 		rc = strcmp(sn->s, entry);
    117 
    118 		if (rc > 0)
    119 			p = &(*p)->rb_left;
    120 		else if (rc < 0)
    121 			p = &(*p)->rb_right;
    122 		else
    123 			return sn;
    124 	}
    125 
    126 	return NULL;
    127 }
    128 
    129 static int strlist__parse_list_entry(struct strlist *self, const char *s)
    130 {
    131 	if (strncmp(s, "file://", 7) == 0)
    132 		return strlist__load(self, s + 7);
    133 
    134 	return strlist__add(self, s);
    135 }
    136 
    137 int strlist__parse_list(struct strlist *self, const char *s)
    138 {
    139 	char *sep;
    140 	int err;
    141 
    142 	while ((sep = strchr(s, ',')) != NULL) {
    143 		*sep = '\0';
    144 		err = strlist__parse_list_entry(self, s);
    145 		*sep = ',';
    146 		if (err != 0)
    147 			return err;
    148 		s = sep + 1;
    149 	}
    150 
    151 	return *s ? strlist__parse_list_entry(self, s) : 0;
    152 }
    153 
    154 struct strlist *strlist__new(bool dupstr, const char *slist)
    155 {
    156 	struct strlist *self = malloc(sizeof(*self));
    157 
    158 	if (self != NULL) {
    159 		self->entries	 = RB_ROOT;
    160 		self->dupstr	 = dupstr;
    161 		self->nr_entries = 0;
    162 		if (slist && strlist__parse_list(self, slist) != 0)
    163 			goto out_error;
    164 	}
    165 
    166 	return self;
    167 out_error:
    168 	free(self);
    169 	return NULL;
    170 }
    171 
    172 void strlist__delete(struct strlist *self)
    173 {
    174 	if (self != NULL) {
    175 		struct str_node *pos;
    176 		struct rb_node *next = rb_first(&self->entries);
    177 
    178 		while (next) {
    179 			pos = rb_entry(next, struct str_node, rb_node);
    180 			next = rb_next(&pos->rb_node);
    181 			strlist__remove(self, pos);
    182 		}
    183 		self->entries = RB_ROOT;
    184 		free(self);
    185 	}
    186 }
    187 
    188 struct str_node *strlist__entry(const struct strlist *self, unsigned int idx)
    189 {
    190 	struct rb_node *nd;
    191 
    192 	for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
    193 		struct str_node *pos = rb_entry(nd, struct str_node, rb_node);
    194 
    195 		if (!idx--)
    196 			return pos;
    197 	}
    198 
    199 	return NULL;
    200 }
    201