]>
Commit | Line | Data |
---|---|---|
9a4c209c TT |
1 | /* |
2 | * profile_helpers.c -- Helper functions for the profile library | |
3 | * | |
4 | * These functions are not part of the "core" profile library, and do | |
5 | * not require access to the internal functions and data structures of | |
6 | * the profile library. They are mainly convenience functions for | |
7 | * programs that want to do something unusual such as obtaining the | |
8 | * list of sections or relations, or accessing multiple values from a | |
9 | * relation that is listed more than once. This functionality can all | |
10 | * be done using the profile_iterator abstraction, but it is less | |
11 | * convenient. | |
efc6f628 | 12 | * |
9a4c209c TT |
13 | * Copyright (C) 2006 by Theodore Ts'o. |
14 | * | |
15 | * %Begin-Header% | |
16 | * This file may be redistributed under the terms of the GNU Public | |
17 | * License. | |
18 | * %End-Header% | |
19 | */ | |
20 | ||
d1154eb4 | 21 | #include "config.h" |
9a4c209c TT |
22 | #include <stdlib.h> |
23 | #include <string.h> | |
24 | #include <errno.h> | |
25 | ||
26 | #include <et/com_err.h> | |
27 | #include "profile.h" | |
a701823a | 28 | #include "profile_helpers.h" |
9a4c209c TT |
29 | #include "prof_err.h" |
30 | ||
31 | /* | |
32 | * These functions --- init_list(), end_list(), and add_to_list() are | |
33 | * internal functions used to build up a null-terminated char ** list | |
34 | * of strings to be returned by functions like profile_get_values. | |
35 | * | |
36 | * The profile_string_list structure is used for internal booking | |
37 | * purposes to build up the list, which is returned in *ret_list by | |
38 | * the end_list() function. | |
39 | * | |
40 | * The publicly exported interface for freeing char** list is | |
41 | * profile_free_list(). | |
42 | */ | |
43 | ||
44 | struct profile_string_list { | |
45 | char **list; | |
46 | int num; | |
47 | int max; | |
48 | }; | |
49 | ||
50 | /* | |
51 | * Initialize the string list abstraction. | |
52 | */ | |
53 | static errcode_t init_list(struct profile_string_list *list) | |
54 | { | |
55 | list->num = 0; | |
56 | list->max = 10; | |
57 | list->list = malloc(list->max * sizeof(char *)); | |
58 | if (list->list == 0) | |
59 | return ENOMEM; | |
60 | list->list[0] = 0; | |
61 | return 0; | |
62 | } | |
63 | ||
64 | /* | |
65 | * Free any memory left over in the string abstraction, returning the | |
66 | * built up list in *ret_list if it is non-null. | |
67 | */ | |
68 | static void end_list(struct profile_string_list *list, char ***ret_list) | |
69 | { | |
70 | char **cp; | |
71 | ||
72 | if (list == 0) | |
73 | return; | |
74 | ||
75 | if (ret_list) { | |
76 | *ret_list = list->list; | |
77 | return; | |
78 | } else { | |
79 | for (cp = list->list; *cp; cp++) | |
80 | free(*cp); | |
81 | free(list->list); | |
82 | } | |
83 | list->num = list->max = 0; | |
84 | list->list = 0; | |
85 | } | |
86 | ||
87 | /* | |
88 | * Add a string to the list. | |
89 | */ | |
d6735822 | 90 | static errcode_t add_to_list(struct profile_string_list *list, char *str) |
9a4c209c TT |
91 | { |
92 | char **newlist; | |
93 | int newmax; | |
efc6f628 | 94 | |
9a4c209c TT |
95 | if (list->num+1 >= list->max) { |
96 | newmax = list->max + 10; | |
97 | newlist = realloc(list->list, newmax * sizeof(char *)); | |
98 | if (newlist == 0) | |
99 | return ENOMEM; | |
100 | list->max = newmax; | |
101 | list->list = newlist; | |
102 | } | |
103 | ||
104 | list->list[list->num++] = str; | |
105 | list->list[list->num] = 0; | |
106 | return 0; | |
107 | } | |
108 | ||
109 | /* | |
110 | * Return TRUE if the string is already a member of the list. | |
111 | */ | |
112 | static int is_list_member(struct profile_string_list *list, const char *str) | |
113 | { | |
114 | char **cpp; | |
115 | ||
116 | if (!list->list) | |
117 | return 0; | |
118 | ||
119 | for (cpp = list->list; *cpp; cpp++) { | |
120 | if (!strcmp(*cpp, str)) | |
121 | return 1; | |
122 | } | |
123 | return 0; | |
efc6f628 TT |
124 | } |
125 | ||
9a4c209c TT |
126 | /* |
127 | * This function frees a null-terminated list as returned by | |
128 | * profile_get_values. | |
129 | */ | |
130 | void profile_free_list(char **list) | |
131 | { | |
132 | char **cp; | |
133 | ||
134 | if (list == 0) | |
135 | return; | |
efc6f628 | 136 | |
9a4c209c TT |
137 | for (cp = list; *cp; cp++) |
138 | free(*cp); | |
139 | free(list); | |
140 | } | |
141 | ||
142 | errcode_t | |
143 | profile_get_values(profile_t profile, const char *const *names, | |
144 | char ***ret_values) | |
145 | { | |
146 | errcode_t retval; | |
147 | void *state; | |
148 | char *value; | |
149 | struct profile_string_list values; | |
150 | ||
151 | if ((retval = profile_iterator_create(profile, names, | |
152 | PROFILE_ITER_RELATIONS_ONLY, | |
153 | &state))) | |
154 | return retval; | |
155 | ||
156 | if ((retval = init_list(&values))) | |
37000b02 | 157 | goto cleanup_iterator; |
9a4c209c TT |
158 | |
159 | do { | |
160 | if ((retval = profile_iterator(&state, 0, &value))) | |
161 | goto cleanup; | |
162 | if (value) | |
163 | add_to_list(&values, value); | |
164 | } while (state); | |
165 | ||
166 | if (values.num == 0) { | |
167 | retval = PROF_NO_RELATION; | |
168 | goto cleanup; | |
169 | } | |
170 | ||
171 | end_list(&values, ret_values); | |
172 | return 0; | |
efc6f628 | 173 | |
9a4c209c TT |
174 | cleanup: |
175 | end_list(&values, 0); | |
37000b02 TT |
176 | cleanup_iterator: |
177 | profile_iterator_free(&state); | |
9a4c209c TT |
178 | return retval; |
179 | } | |
180 | ||
181 | /* | |
055866d8 | 182 | * This function will return the list of the names of subsections in the |
9a4c209c TT |
183 | * under the specified section name. |
184 | */ | |
efc6f628 | 185 | errcode_t |
9a4c209c TT |
186 | profile_get_subsection_names(profile_t profile, const char **names, |
187 | char ***ret_names) | |
188 | { | |
189 | errcode_t retval; | |
190 | void *state; | |
191 | char *name; | |
192 | struct profile_string_list values; | |
193 | ||
194 | if ((retval = profile_iterator_create(profile, names, | |
195 | PROFILE_ITER_LIST_SECTION | PROFILE_ITER_SECTIONS_ONLY, | |
196 | &state))) | |
197 | return retval; | |
198 | ||
199 | if ((retval = init_list(&values))) | |
37000b02 | 200 | goto cleanup_iterator; |
9a4c209c TT |
201 | |
202 | do { | |
203 | if ((retval = profile_iterator(&state, &name, 0))) | |
204 | goto cleanup; | |
205 | if (name) | |
206 | add_to_list(&values, name); | |
207 | } while (state); | |
208 | ||
209 | end_list(&values, ret_names); | |
210 | return 0; | |
efc6f628 | 211 | |
9a4c209c TT |
212 | cleanup: |
213 | end_list(&values, 0); | |
37000b02 TT |
214 | cleanup_iterator: |
215 | profile_iterator_free(&state); | |
9a4c209c TT |
216 | return retval; |
217 | } | |
218 | ||
219 | /* | |
220 | * This function will return the list of the names of relations in the | |
221 | * under the specified section name. | |
222 | */ | |
efc6f628 | 223 | errcode_t |
9a4c209c TT |
224 | profile_get_relation_names(profile_t profile, const char **names, |
225 | char ***ret_names) | |
226 | { | |
227 | errcode_t retval; | |
228 | void *state; | |
229 | char *name; | |
230 | struct profile_string_list values; | |
231 | ||
232 | if ((retval = profile_iterator_create(profile, names, | |
233 | PROFILE_ITER_LIST_SECTION | PROFILE_ITER_RELATIONS_ONLY, | |
234 | &state))) | |
235 | return retval; | |
236 | ||
237 | if ((retval = init_list(&values))) | |
37000b02 | 238 | goto cleanup_iterator; |
9a4c209c TT |
239 | |
240 | do { | |
241 | if ((retval = profile_iterator(&state, &name, 0))) | |
242 | goto cleanup; | |
243 | if (name) { | |
244 | if (is_list_member(&values, name)) | |
245 | free(name); | |
246 | else | |
247 | add_to_list(&values, name); | |
248 | } | |
249 | } while (state); | |
250 | ||
251 | end_list(&values, ret_names); | |
252 | return 0; | |
efc6f628 | 253 | |
9a4c209c TT |
254 | cleanup: |
255 | end_list(&values, 0); | |
37000b02 TT |
256 | cleanup_iterator: |
257 | profile_iterator_free(&state); | |
9a4c209c TT |
258 | return retval; |
259 | } | |
260 | ||
261 | ||
efc6f628 | 262 | void |
9a4c209c TT |
263 | profile_release_string(char *str) |
264 | { | |
265 | free(str); | |
266 | } | |
267 | ||
efc6f628 | 268 | errcode_t |
9a4c209c TT |
269 | profile_init_path(const char * filepath, |
270 | profile_t *ret_profile) | |
271 | { | |
272 | int n_entries, i; | |
273 | unsigned int ent_len; | |
274 | const char *s, *t; | |
275 | char **filenames; | |
276 | errcode_t retval; | |
277 | ||
278 | /* count the distinct filename components */ | |
279 | for(s = filepath, n_entries = 1; *s; s++) { | |
280 | if (*s == ':') | |
281 | n_entries++; | |
282 | } | |
efc6f628 | 283 | |
9a4c209c TT |
284 | /* the array is NULL terminated */ |
285 | filenames = (char **) malloc((n_entries+1) * sizeof(char*)); | |
286 | if (filenames == 0) | |
287 | return ENOMEM; | |
288 | ||
289 | /* measure, copy, and skip each one */ | |
290 | for(s = filepath, i=0; (t = strchr(s, ':')) || (t=s+strlen(s)); s=t+1, i++) { | |
291 | ent_len = t-s; | |
292 | filenames[i] = (char*) malloc(ent_len + 1); | |
293 | if (filenames[i] == 0) { | |
294 | /* if malloc fails, free the ones that worked */ | |
295 | while(--i >= 0) free(filenames[i]); | |
296 | free(filenames); | |
297 | return ENOMEM; | |
298 | } | |
299 | strncpy(filenames[i], s, ent_len); | |
300 | filenames[i][ent_len] = 0; | |
301 | if (*t == 0) { | |
302 | i++; | |
303 | break; | |
304 | } | |
305 | } | |
306 | /* cap the array */ | |
307 | filenames[i] = 0; | |
308 | ||
a701823a | 309 | retval = profile_init((const char * const *) filenames, |
9a4c209c TT |
310 | ret_profile); |
311 | ||
312 | /* count back down and free the entries */ | |
313 | while(--i >= 0) free(filenames[i]); | |
314 | free(filenames); | |
315 | ||
316 | return retval; | |
317 | } |