strlist.c 3.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
/*
 * (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>

13 14
static
struct rb_node *strlist__node_new(struct rblist *rblist, const void *entry)
15
{
16 17 18 19
	const char *s = entry;
	struct rb_node *rc = NULL;
	struct strlist *strlist = container_of(rblist, struct strlist, rblist);
	struct str_node *snode = malloc(sizeof(*snode));
20

21 22
	if (snode != NULL) {
		if (strlist->dupstr) {
23 24 25 26
			s = strdup(s);
			if (s == NULL)
				goto out_delete;
		}
27 28
		snode->s = s;
		rc = &snode->rb_node;
29 30
	}

31
	return rc;
32 33

out_delete:
34
	free(snode);
35 36 37 38 39 40 41 42 43 44
	return NULL;
}

static void str_node__delete(struct str_node *self, bool dupstr)
{
	if (dupstr)
		free((void *)self->s);
	free(self);
}

45 46
static
void strlist__node_delete(struct rblist *rblist, struct rb_node *rb_node)
47
{
48 49
	struct strlist *slist = container_of(rblist, struct strlist, rblist);
	struct str_node *snode = container_of(rb_node, struct str_node, rb_node);
50

51 52
	str_node__delete(snode, slist->dupstr);
}
53

54 55 56 57 58 59 60
static int strlist__node_cmp(struct rb_node *rb_node, const void *entry)
{
	const char *str = entry;
	struct str_node *snode = container_of(rb_node, struct str_node, rb_node);

	return strcmp(snode->s, str);
}
61

62 63 64
int strlist__add(struct strlist *self, const char *new_entry)
{
	return rblist__add_node(&self->rblist, new_entry);
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
}

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;
}

94
void strlist__remove(struct strlist *slist, struct str_node *snode)
95
{
96
	str_node__delete(snode, slist->dupstr);
97 98
}

99
struct str_node *strlist__find(struct strlist *slist, const char *entry)
100
{
101 102
	struct str_node *snode = NULL;
	struct rb_node *rb_node = rblist__find(&slist->rblist, entry);
103

104 105 106 107
	if (rb_node)
		snode = container_of(rb_node, struct str_node, rb_node);

	return snode;
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
}

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) {
140 141 142 143 144
		rblist__init(&self->rblist);
		self->rblist.node_cmp    = strlist__node_cmp;
		self->rblist.node_new    = strlist__node_new;
		self->rblist.node_delete = strlist__node_delete;

145
		self->dupstr	 = dupstr;
146 147 148 149 150 151 152 153 154 155 156 157
		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)
{
158 159
	if (self != NULL)
		rblist__delete(&self->rblist);
160
}
161

162
struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx)
163
{
164 165
	struct str_node *snode = NULL;
	struct rb_node *rb_node;
166

167 168 169
	rb_node = rblist__entry(&slist->rblist, idx);
	if (rb_node)
		snode = container_of(rb_node, struct str_node, rb_node);
170

171
	return snode;
172
}