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