xref: /linux/tools/perf/util/strlist.c (revision 2277ab4a1df50e05bc732fe9488d4e902bb8399a)
1 /*
2  * (c) 2009 Arnaldo Carvalho de Melo <acme@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 
68 	return 0;
69 }
70 
71 int strlist__load(struct strlist *self, const char *filename)
72 {
73 	char entry[1024];
74 	int err;
75 	FILE *fp = fopen(filename, "r");
76 
77 	if (fp == NULL)
78 		return errno;
79 
80 	while (fgets(entry, sizeof(entry), fp) != NULL) {
81 		const size_t len = strlen(entry);
82 
83 		if (len == 0)
84 			continue;
85 		entry[len - 1] = '\0';
86 
87 		err = strlist__add(self, entry);
88 		if (err != 0)
89 			goto out;
90 	}
91 
92 	err = 0;
93 out:
94 	fclose(fp);
95 	return err;
96 }
97 
98 void strlist__remove(struct strlist *self, struct str_node *sn)
99 {
100 	rb_erase(&sn->rb_node, &self->entries);
101 	str_node__delete(sn, self->dupstr);
102 }
103 
104 bool strlist__has_entry(struct strlist *self, const char *entry)
105 {
106 	struct rb_node **p = &self->entries.rb_node;
107 	struct rb_node *parent = NULL;
108 
109 	while (*p != NULL) {
110 		struct str_node *sn;
111 		int rc;
112 
113 		parent = *p;
114 		sn = rb_entry(parent, struct str_node, rb_node);
115 		rc = strcmp(sn->s, entry);
116 
117 		if (rc > 0)
118 			p = &(*p)->rb_left;
119 		else if (rc < 0)
120 			p = &(*p)->rb_right;
121 		else
122 			return true;
123 	}
124 
125 	return false;
126 }
127 
128 static int strlist__parse_list_entry(struct strlist *self, const char *s)
129 {
130 	if (strncmp(s, "file://", 7) == 0)
131 		return strlist__load(self, s + 7);
132 
133 	return strlist__add(self, s);
134 }
135 
136 int strlist__parse_list(struct strlist *self, const char *s)
137 {
138 	char *sep;
139 	int err;
140 
141 	while ((sep = strchr(s, ',')) != NULL) {
142 		*sep = '\0';
143 		err = strlist__parse_list_entry(self, s);
144 		*sep = ',';
145 		if (err != 0)
146 			return err;
147 		s = sep + 1;
148 	}
149 
150 	return *s ? strlist__parse_list_entry(self, s) : 0;
151 }
152 
153 struct strlist *strlist__new(bool dupstr, const char *slist)
154 {
155 	struct strlist *self = malloc(sizeof(*self));
156 
157 	if (self != NULL) {
158 		self->entries = RB_ROOT;
159 		self->dupstr = dupstr;
160 		if (slist && strlist__parse_list(self, slist) != 0)
161 			goto out_error;
162 	}
163 
164 	return self;
165 out_error:
166 	free(self);
167 	return NULL;
168 }
169 
170 void strlist__delete(struct strlist *self)
171 {
172 	if (self != NULL) {
173 		struct str_node *pos;
174 		struct rb_node *next = rb_first(&self->entries);
175 
176 		while (next) {
177 			pos = rb_entry(next, struct str_node, rb_node);
178 			next = rb_next(&pos->rb_node);
179 			strlist__remove(self, pos);
180 		}
181 		self->entries = RB_ROOT;
182 		free(self);
183 	}
184 }
185