1 /*
2  * Copyright (c) 2015, 2021 Vladimir Kondratyev <vladimir@kondratyev.su>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 
28 #include <stddef.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 #include "libudev.h"
34 #include "udev-list.h"
35 #include "udev-utils.h"
36 #include "utils.h"
37 
38 struct udev_list_entry {
39 	struct udev_list *list;
40 	RB_ENTRY(udev_list_entry) link;
41 	char *value;
42 	char name[];
43 };
44 
45 void udev_list_entry_free(struct udev_list_entry *ule);
46 
47 RB_PROTOTYPE(udev_list, udev_list_entry, link, udev_list_entry_cmp);
48 
49 void
udev_list_init(struct udev_list * ul)50 udev_list_init(struct udev_list *ul)
51 {
52 
53 	RB_INIT(ul);
54 }
55 
56 int
udev_list_insert(struct udev_list * ul,char const * name,char const * value)57 udev_list_insert(struct udev_list *ul, char const *name, char const *value)
58 {
59 	struct udev_list_entry *ule, *old_ule;
60 	size_t namelen, valuelen;
61 
62 	namelen = strlen(name) + 1;
63 	valuelen = value == NULL ? 0 : strlen(value) + 1;
64 	ule = calloc
65 	    (1, offsetof(struct udev_list_entry, name) + namelen + valuelen);
66 	if (!ule)
67 		return (-1);
68 
69 	ule->list = ul;
70 	strcpy(ule->name, name);
71 	ule->value = NULL;
72 	if (value != NULL) {
73 		ule->value = ule->name + namelen;
74 		strcpy(ule->value, value);
75 	}
76 
77 	old_ule = RB_FIND(udev_list, ul, ule);
78 	if (old_ule != NULL) {
79 		RB_REMOVE(udev_list, ul, old_ule);
80 		udev_list_entry_free(old_ule);
81 	}
82 
83 	RB_INSERT(udev_list, ul, ule);
84 	return (0);
85 }
86 
87 void
udev_list_free(struct udev_list * ul)88 udev_list_free(struct udev_list *ul)
89 {
90 	struct udev_list_entry *ule1, *ule2;
91 
92 	RB_FOREACH_SAFE (ule1, udev_list, ul, ule2) {
93 		RB_REMOVE(udev_list, ul, ule1);
94 		udev_list_entry_free(ule1);
95 	}
96 
97 	RB_INIT(ul);
98 }
99 
100 void
udev_list_entry_free(struct udev_list_entry * ule)101 udev_list_entry_free(struct udev_list_entry *ule)
102 {
103 
104 	free(ule);
105 }
106 
107 struct udev_list_entry *
udev_list_entry_get_first(struct udev_list * ul)108 udev_list_entry_get_first(struct udev_list *ul)
109 {
110 
111 	return (RB_MIN(udev_list, ul));
112 }
113 
114 LIBUDEV_EXPORT struct udev_list_entry *
udev_list_entry_get_next(struct udev_list_entry * ule)115 udev_list_entry_get_next(struct udev_list_entry *ule)
116 {
117 
118 	return (RB_NEXT(udev_list,, ule));
119 }
120 
121 const char *
_udev_list_entry_get_name(struct udev_list_entry * ule)122 _udev_list_entry_get_name(struct udev_list_entry *ule)
123 {
124 
125 	return (ule->name);
126 }
127 
128 LIBUDEV_EXPORT const char *
udev_list_entry_get_name(struct udev_list_entry * ule)129 udev_list_entry_get_name(struct udev_list_entry *ule)
130 {
131 	const char *name;
132 
133 	name = _udev_list_entry_get_name(ule);
134 	TRC("() %s", name);
135 	return (name);
136 }
137 
138 const char *
_udev_list_entry_get_value(struct udev_list_entry * ule)139 _udev_list_entry_get_value(struct udev_list_entry *ule)
140 {
141 
142 	return (ule->value);
143 }
144 
145 LIBUDEV_EXPORT const char *
udev_list_entry_get_value(struct udev_list_entry * ule)146 udev_list_entry_get_value(struct udev_list_entry *ule)
147 {
148 	const char *value;
149 
150 	value = _udev_list_entry_get_value(ule);
151 	TRC("() %s", value);
152 	return (value);
153 }
154 
155 static int
udev_list_entry_cmp(struct udev_list_entry * le1,struct udev_list_entry * le2)156 udev_list_entry_cmp (struct udev_list_entry *le1, struct udev_list_entry *le2)
157 {
158 
159 	return (strcmp(le1->name, le2->name));
160 }
161 
162 LIBUDEV_EXPORT struct udev_list_entry *
udev_list_entry_get_by_name(struct udev_list_entry * ule,const char * name)163 udev_list_entry_get_by_name(struct udev_list_entry *ule, const char *name)
164 {
165 	struct udev_list_entry *find, *ret;
166 
167 	find = calloc
168 	    (1, offsetof(struct udev_list_entry, name) + strlen(name) + 1);
169 
170 	ret = RB_FIND(udev_list, ule->list, find);
171 	udev_list_entry_free(find);
172 
173 	return (ret);
174 }
175 
176 RB_GENERATE(udev_list, udev_list_entry, link, udev_list_entry_cmp);
177