xref: /OK3568_Linux_fs/kernel/tools/perf/util/strlist.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com>
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include "strlist.h"
7*4882a593Smuzhiyun #include <errno.h>
8*4882a593Smuzhiyun #include <stdio.h>
9*4882a593Smuzhiyun #include <stdlib.h>
10*4882a593Smuzhiyun #include <string.h>
11*4882a593Smuzhiyun #include <unistd.h>
12*4882a593Smuzhiyun #include <linux/zalloc.h>
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun static
strlist__node_new(struct rblist * rblist,const void * entry)15*4882a593Smuzhiyun struct rb_node *strlist__node_new(struct rblist *rblist, const void *entry)
16*4882a593Smuzhiyun {
17*4882a593Smuzhiyun 	const char *s = entry;
18*4882a593Smuzhiyun 	struct rb_node *rc = NULL;
19*4882a593Smuzhiyun 	struct strlist *strlist = container_of(rblist, struct strlist, rblist);
20*4882a593Smuzhiyun 	struct str_node *snode = malloc(sizeof(*snode));
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun 	if (snode != NULL) {
23*4882a593Smuzhiyun 		if (strlist->dupstr) {
24*4882a593Smuzhiyun 			s = strdup(s);
25*4882a593Smuzhiyun 			if (s == NULL)
26*4882a593Smuzhiyun 				goto out_delete;
27*4882a593Smuzhiyun 		}
28*4882a593Smuzhiyun 		snode->s = s;
29*4882a593Smuzhiyun 		rc = &snode->rb_node;
30*4882a593Smuzhiyun 	}
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	return rc;
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun out_delete:
35*4882a593Smuzhiyun 	free(snode);
36*4882a593Smuzhiyun 	return NULL;
37*4882a593Smuzhiyun }
38*4882a593Smuzhiyun 
str_node__delete(struct str_node * snode,bool dupstr)39*4882a593Smuzhiyun static void str_node__delete(struct str_node *snode, bool dupstr)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun 	if (dupstr)
42*4882a593Smuzhiyun 		zfree((char **)&snode->s);
43*4882a593Smuzhiyun 	free(snode);
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun static
strlist__node_delete(struct rblist * rblist,struct rb_node * rb_node)47*4882a593Smuzhiyun void strlist__node_delete(struct rblist *rblist, struct rb_node *rb_node)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun 	struct strlist *slist = container_of(rblist, struct strlist, rblist);
50*4882a593Smuzhiyun 	struct str_node *snode = container_of(rb_node, struct str_node, rb_node);
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	str_node__delete(snode, slist->dupstr);
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun 
strlist__node_cmp(struct rb_node * rb_node,const void * entry)55*4882a593Smuzhiyun static int strlist__node_cmp(struct rb_node *rb_node, const void *entry)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun 	const char *str = entry;
58*4882a593Smuzhiyun 	struct str_node *snode = container_of(rb_node, struct str_node, rb_node);
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	return strcmp(snode->s, str);
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun 
strlist__add(struct strlist * slist,const char * new_entry)63*4882a593Smuzhiyun int strlist__add(struct strlist *slist, const char *new_entry)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun 	return rblist__add_node(&slist->rblist, new_entry);
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun 
strlist__load(struct strlist * slist,const char * filename)68*4882a593Smuzhiyun int strlist__load(struct strlist *slist, const char *filename)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun 	char entry[1024];
71*4882a593Smuzhiyun 	int err;
72*4882a593Smuzhiyun 	FILE *fp = fopen(filename, "r");
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	if (fp == NULL)
75*4882a593Smuzhiyun 		return -errno;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	while (fgets(entry, sizeof(entry), fp) != NULL) {
78*4882a593Smuzhiyun 		const size_t len = strlen(entry);
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 		if (len == 0)
81*4882a593Smuzhiyun 			continue;
82*4882a593Smuzhiyun 		entry[len - 1] = '\0';
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 		err = strlist__add(slist, entry);
85*4882a593Smuzhiyun 		if (err != 0)
86*4882a593Smuzhiyun 			goto out;
87*4882a593Smuzhiyun 	}
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	err = 0;
90*4882a593Smuzhiyun out:
91*4882a593Smuzhiyun 	fclose(fp);
92*4882a593Smuzhiyun 	return err;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun 
strlist__remove(struct strlist * slist,struct str_node * snode)95*4882a593Smuzhiyun void strlist__remove(struct strlist *slist, struct str_node *snode)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun 	rblist__remove_node(&slist->rblist, &snode->rb_node);
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun 
strlist__find(struct strlist * slist,const char * entry)100*4882a593Smuzhiyun struct str_node *strlist__find(struct strlist *slist, const char *entry)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun 	struct str_node *snode = NULL;
103*4882a593Smuzhiyun 	struct rb_node *rb_node = rblist__find(&slist->rblist, entry);
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	if (rb_node)
106*4882a593Smuzhiyun 		snode = container_of(rb_node, struct str_node, rb_node);
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	return snode;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun 
strlist__parse_list_entry(struct strlist * slist,const char * s,const char * subst_dir)111*4882a593Smuzhiyun static int strlist__parse_list_entry(struct strlist *slist, const char *s,
112*4882a593Smuzhiyun 				     const char *subst_dir)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun 	int err;
115*4882a593Smuzhiyun 	char *subst = NULL;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	if (strncmp(s, "file://", 7) == 0)
118*4882a593Smuzhiyun 		return strlist__load(slist, s + 7);
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	if (subst_dir) {
121*4882a593Smuzhiyun 		err = -ENOMEM;
122*4882a593Smuzhiyun 		if (asprintf(&subst, "%s/%s", subst_dir, s) < 0)
123*4882a593Smuzhiyun 			goto out;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 		if (access(subst, F_OK) == 0) {
126*4882a593Smuzhiyun 			err = strlist__load(slist, subst);
127*4882a593Smuzhiyun 			goto out;
128*4882a593Smuzhiyun 		}
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 		if (slist->file_only) {
131*4882a593Smuzhiyun 			err = -ENOENT;
132*4882a593Smuzhiyun 			goto out;
133*4882a593Smuzhiyun 		}
134*4882a593Smuzhiyun 	}
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	err = strlist__add(slist, s);
137*4882a593Smuzhiyun out:
138*4882a593Smuzhiyun 	free(subst);
139*4882a593Smuzhiyun 	return err;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun 
strlist__parse_list(struct strlist * slist,const char * s,const char * subst_dir)142*4882a593Smuzhiyun static int strlist__parse_list(struct strlist *slist, const char *s, const char *subst_dir)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun 	char *sep;
145*4882a593Smuzhiyun 	int err;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	while ((sep = strchr(s, ',')) != NULL) {
148*4882a593Smuzhiyun 		*sep = '\0';
149*4882a593Smuzhiyun 		err = strlist__parse_list_entry(slist, s, subst_dir);
150*4882a593Smuzhiyun 		*sep = ',';
151*4882a593Smuzhiyun 		if (err != 0)
152*4882a593Smuzhiyun 			return err;
153*4882a593Smuzhiyun 		s = sep + 1;
154*4882a593Smuzhiyun 	}
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	return *s ? strlist__parse_list_entry(slist, s, subst_dir) : 0;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun 
strlist__new(const char * list,const struct strlist_config * config)159*4882a593Smuzhiyun struct strlist *strlist__new(const char *list, const struct strlist_config *config)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun 	struct strlist *slist = malloc(sizeof(*slist));
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	if (slist != NULL) {
164*4882a593Smuzhiyun 		bool dupstr = true;
165*4882a593Smuzhiyun 		bool file_only = false;
166*4882a593Smuzhiyun 		const char *dirname = NULL;
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 		if (config) {
169*4882a593Smuzhiyun 			dupstr = !config->dont_dupstr;
170*4882a593Smuzhiyun 			dirname = config->dirname;
171*4882a593Smuzhiyun 			file_only = config->file_only;
172*4882a593Smuzhiyun 		}
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 		rblist__init(&slist->rblist);
175*4882a593Smuzhiyun 		slist->rblist.node_cmp    = strlist__node_cmp;
176*4882a593Smuzhiyun 		slist->rblist.node_new    = strlist__node_new;
177*4882a593Smuzhiyun 		slist->rblist.node_delete = strlist__node_delete;
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 		slist->dupstr	 = dupstr;
180*4882a593Smuzhiyun 		slist->file_only = file_only;
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 		if (list && strlist__parse_list(slist, list, dirname) != 0)
183*4882a593Smuzhiyun 			goto out_error;
184*4882a593Smuzhiyun 	}
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	return slist;
187*4882a593Smuzhiyun out_error:
188*4882a593Smuzhiyun 	free(slist);
189*4882a593Smuzhiyun 	return NULL;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
strlist__delete(struct strlist * slist)192*4882a593Smuzhiyun void strlist__delete(struct strlist *slist)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun 	if (slist != NULL)
195*4882a593Smuzhiyun 		rblist__delete(&slist->rblist);
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun 
strlist__entry(const struct strlist * slist,unsigned int idx)198*4882a593Smuzhiyun struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun 	struct str_node *snode = NULL;
201*4882a593Smuzhiyun 	struct rb_node *rb_node;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	rb_node = rblist__entry(&slist->rblist, idx);
204*4882a593Smuzhiyun 	if (rb_node)
205*4882a593Smuzhiyun 		snode = container_of(rb_node, struct str_node, rb_node);
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	return snode;
208*4882a593Smuzhiyun }
209