Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2014 Intel Corporation
3 : : */
4 : :
5 : : #include <assert.h>
6 : : #include <stdio.h>
7 : : #include <stdlib.h>
8 : : #include <string.h>
9 : : #include <ctype.h>
10 : : #include <errno.h>
11 : : #include <limits.h>
12 : : #include <stdint.h>
13 : :
14 : : #ifndef LINE_MAX
15 : : #define LINE_MAX 2048
16 : : #endif
17 : :
18 : : #include <eal_export.h>
19 : : #include <rte_string_fns.h>
20 : : #include <rte_common.h>
21 : : #include <rte_log.h>
22 : :
23 : : #include "rte_cfgfile.h"
24 : :
25 : : struct rte_cfgfile_section {
26 : : char name[CFG_NAME_LEN];
27 : : size_t num_entries;
28 : : size_t allocated_entries;
29 : : struct rte_cfgfile_entry *entries;
30 : : };
31 : :
32 : : struct rte_cfgfile {
33 : : int flags;
34 : : size_t num_sections;
35 : : size_t allocated_sections;
36 : : struct rte_cfgfile_section *sections;
37 : : };
38 : :
39 : : /* Setting up dynamic logging 8< */
40 [ - + ]: 286 : RTE_LOG_REGISTER_DEFAULT(cfgfile_logtype, INFO);
41 : : #define RTE_LOGTYPE_CFGFILE cfgfile_logtype
42 : :
43 : : #define CFG_LOG(level, ...) \
44 : : RTE_LOG_LINE_PREFIX(level, CFGFILE, "%s(): ", __func__, __VA_ARGS__)
45 : : /* >8 End of setting up dynamic logging */
46 : :
47 : : /* Define a max allocation limit for entry and section types.
48 : : * For 64-bit systems, this is based on INT_MAX since API work on int values.
49 : : * For 32-bit systems, this is based on SIZE_MAX / sizeof(type) to prevent overflow on allocation.
50 : : */
51 : : #define CFG_ALLOC_MAX(type) \
52 : : (sizeof(int) == sizeof(size_t) ? (SIZE_MAX / sizeof(type)) : ((size_t)INT_MAX))
53 : :
54 : : /** when we resize a file structure, how many extra entries
55 : : * for new sections do we add in */
56 : : #define CFG_ALLOC_SECTION_BATCH 8
57 : :
58 : : /* Max number of section entries we can possibly have.
59 : : * Used to prevent overflow on allocation.
60 : : * Based on INT_MAX since API work on int values.
61 : : */
62 : : #define CFG_ALLOC_SECTION_MAX CFG_ALLOC_MAX(struct rte_cfgfile_section)
63 : :
64 : : /** when we resize a section structure, how many extra entries
65 : : * for new entries do we add in */
66 : : #define CFG_ALLOC_ENTRY_BATCH 16
67 : :
68 : : /* Max number of data entries we can possibly have.
69 : : * Used to prevent overflow on allocation.
70 : : * Based on INT_MAX since API work on int values.
71 : : */
72 : : #define CFG_ALLOC_ENTRY_MAX CFG_ALLOC_MAX(struct rte_cfgfile_entry)
73 : :
74 : : /**
75 : : * Default cfgfile load parameters.
76 : : */
77 : : static const struct rte_cfgfile_parameters default_cfgfile_params = {
78 : : .comment_character = CFG_DEFAULT_COMMENT_CHARACTER,
79 : : };
80 : :
81 : : /**
82 : : * Defines the list of acceptable comment characters supported by this
83 : : * library.
84 : : */
85 : : static const char valid_comment_chars[] = {
86 : : '!',
87 : : '#',
88 : : '%',
89 : : ';',
90 : : '@'
91 : : };
92 : :
93 : : static unsigned
94 : 420 : _strip(char *str, unsigned len)
95 : : {
96 : 420 : int newlen = len;
97 [ + + ]: 420 : if (len == 0)
98 : : return 0;
99 : :
100 [ + + ]: 406 : if (isspace(str[len-1])) {
101 : : /* strip trailing whitespace */
102 [ + + + + ]: 302 : while (newlen > 0 && isspace(str[newlen - 1]))
103 : 151 : str[--newlen] = '\0';
104 : : }
105 : :
106 [ - + ]: 406 : if (isspace(str[0])) {
107 : : /* strip leading whitespace */
108 : : int i, start = 1;
109 [ # # # # ]: 0 : while (isspace(str[start]) && start < newlen)
110 : 0 : start++
111 : : ; /* do nothing */
112 : 0 : newlen -= start;
113 [ # # ]: 0 : for (i = 0; i < newlen; i++)
114 : 0 : str[i] = str[i+start];
115 : 0 : str[i] = '\0';
116 : : }
117 : 406 : return newlen;
118 : : }
119 : :
120 : : static struct rte_cfgfile_section *
121 : 24 : _get_section(struct rte_cfgfile *cfg, const char *sectionname)
122 : : {
123 [ + - ]: 58 : for (size_t i = 0; i < cfg->num_sections; i++) {
124 [ + + ]: 58 : if (strncmp(cfg->sections[i].name, sectionname,
125 : : sizeof(cfg->sections[0].name)) == 0)
126 : 24 : return &cfg->sections[i];
127 : : }
128 : : return NULL;
129 : : }
130 : :
131 : : static int
132 : 119 : _add_entry(struct rte_cfgfile_section *section, const char *entryname,
133 : : const char *entryvalue)
134 : : {
135 [ + - + - ]: 119 : if (strlen(entryname) >= CFG_NAME_LEN || strlen(entryvalue) >= CFG_VALUE_LEN)
136 : : return -ENAMETOOLONG;
137 : :
138 : : /* resize entry structure if we don't have room for more entries */
139 [ + + ]: 119 : if (section->num_entries == section->allocated_entries) {
140 [ + - ]: 4 : if (section->allocated_entries > CFG_ALLOC_ENTRY_MAX - CFG_ALLOC_ENTRY_BATCH)
141 : : return -ENOMEM;
142 : :
143 : 4 : struct rte_cfgfile_entry *n_entries = realloc(
144 : 4 : section->entries,
145 : : sizeof(struct rte_cfgfile_entry) *
146 : : ((section->allocated_entries) +
147 : : CFG_ALLOC_ENTRY_BATCH));
148 : :
149 [ + - ]: 4 : if (n_entries == NULL)
150 : : return -ENOMEM;
151 : :
152 : 4 : section->entries = n_entries;
153 : 4 : section->allocated_entries += CFG_ALLOC_ENTRY_BATCH;
154 : : }
155 : : /* fill up entry fields with key name and value */
156 : 119 : struct rte_cfgfile_entry *curr_entry =
157 : 119 : §ion->entries[section->num_entries];
158 : :
159 : 119 : strlcpy(curr_entry->name, entryname, sizeof(curr_entry->name));
160 : 119 : strlcpy(curr_entry->value, entryvalue, sizeof(curr_entry->value));
161 : 119 : section->num_entries++;
162 : :
163 : 119 : return 0;
164 : : }
165 : :
166 : : static int
167 : 10 : rte_cfgfile_check_params(const struct rte_cfgfile_parameters *params)
168 : : {
169 : : unsigned int valid_comment;
170 : : unsigned int i;
171 : :
172 [ - + ]: 10 : if (!params) {
173 : 0 : CFG_LOG(ERR, "missing cfgfile parameters");
174 : 0 : return -EINVAL;
175 : : }
176 : :
177 : : valid_comment = 0;
178 [ + + ]: 40 : for (i = 0; i < RTE_DIM(valid_comment_chars); i++) {
179 [ + + ]: 39 : if (params->comment_character == valid_comment_chars[i]) {
180 : : valid_comment = 1;
181 : : break;
182 : : }
183 : : }
184 : :
185 [ + + ]: 10 : if (valid_comment == 0) {
186 : 1 : CFG_LOG(ERR, "invalid comment characters %c",
187 : : params->comment_character);
188 : 1 : return -ENOTSUP;
189 : : }
190 : :
191 : : return 0;
192 : : }
193 : :
194 : : RTE_EXPORT_SYMBOL(rte_cfgfile_load)
195 : : struct rte_cfgfile *
196 : 8 : rte_cfgfile_load(const char *filename, int flags)
197 : : {
198 : 8 : return rte_cfgfile_load_with_params(filename, flags,
199 : : &default_cfgfile_params);
200 : : }
201 : :
202 : : /* Need enough space for largest name and value */
203 : : static_assert(CFG_NAME_LEN + CFG_VALUE_LEN + 4 < LINE_MAX,
204 : : "not enough space for cfgfile name/value");
205 : :
206 : : RTE_EXPORT_SYMBOL(rte_cfgfile_load_with_params)
207 : : struct rte_cfgfile *
208 : 10 : rte_cfgfile_load_with_params(const char *filename, int flags,
209 : : const struct rte_cfgfile_parameters *params)
210 : : {
211 : : char buffer[LINE_MAX];
212 : : int lineno = 0;
213 : : struct rte_cfgfile *cfg;
214 : :
215 [ + + ]: 10 : if (rte_cfgfile_check_params(params))
216 : : return NULL;
217 : :
218 : 9 : FILE *f = fopen(filename, "r");
219 [ + - ]: 9 : if (f == NULL)
220 : : return NULL;
221 : :
222 : 9 : cfg = rte_cfgfile_create(flags);
223 [ - + ]: 9 : if (cfg == NULL) {
224 : 0 : fclose(f);
225 : 0 : return NULL;
226 : : }
227 : :
228 [ + + ]: 169 : while (fgets(buffer, sizeof(buffer), f) != NULL) {
229 : : char *pos;
230 : 163 : size_t len = strnlen(buffer, sizeof(buffer));
231 : 163 : lineno++;
232 [ - + - - ]: 163 : if ((len >= sizeof(buffer) - 1) && (buffer[len-1] != '\n')) {
233 : 0 : CFG_LOG(ERR, " line %d - no \\n found on string. "
234 : : "Check if line too long", lineno);
235 : 0 : goto error1;
236 : : }
237 : : /* skip parsing if comment character found */
238 : 163 : pos = memchr(buffer, params->comment_character, len);
239 [ + + + + ]: 163 : if (pos != NULL &&
240 [ + - ]: 2 : (pos == buffer || *(pos-1) != '\\')) {
241 : 14 : *pos = '\0';
242 : 14 : len = pos - buffer;
243 : : }
244 : :
245 : 163 : len = _strip(buffer, len);
246 : : /* skip lines without useful content */
247 [ + + + + ]: 163 : if (buffer[0] != '[' && memchr(buffer, '=', len) == NULL)
248 : 26 : continue;
249 : :
250 [ + + ]: 137 : if (buffer[0] == '[') {
251 : : /* section heading line */
252 : 16 : char *end = memchr(buffer, ']', len);
253 [ + + ]: 16 : if (end == NULL) {
254 : 1 : CFG_LOG(ERR,
255 : : "line %d - no terminating ']' character found",
256 : : lineno);
257 : 1 : goto error1;
258 : : }
259 : 15 : *end = '\0';
260 : 15 : _strip(&buffer[1], end - &buffer[1]);
261 : :
262 : 15 : int ret = rte_cfgfile_add_section(cfg, &buffer[1]);
263 [ - + ]: 15 : if (ret != 0) {
264 : 0 : CFG_LOG(ERR,
265 : : "line %d - add section failed: %s",
266 : : lineno, strerror(-ret));
267 : 0 : goto error1;
268 : : }
269 : : } else {
270 : : /* key and value line */
271 : : char *split[2] = {NULL};
272 : :
273 : : split[0] = buffer;
274 : 121 : split[1] = memchr(buffer, '=', len);
275 [ - + ]: 121 : if (split[1] == NULL) {
276 : 0 : CFG_LOG(ERR,
277 : : "line %d - no '=' character found",
278 : : lineno);
279 : 0 : goto error1;
280 : : }
281 : 121 : *split[1] = '\0';
282 : 121 : split[1]++;
283 : :
284 : 121 : _strip(split[0], strlen(split[0]));
285 : 121 : _strip(split[1], strlen(split[1]));
286 : 121 : char *end = memchr(split[1], '\\', strlen(split[1]));
287 : :
288 : 121 : size_t split_len = strlen(split[1]) + 1;
289 [ - + ]: 121 : while (end != NULL) {
290 [ # # ]: 0 : if (*(end+1) == params->comment_character) {
291 : 0 : *end = '\0';
292 : 0 : strlcat(split[1], end+1, split_len);
293 : : } else
294 : 0 : end++;
295 : 0 : end = memchr(end, '\\', strlen(end));
296 : : }
297 : :
298 [ + + ]: 121 : if (!(flags & CFG_FLAG_EMPTY_VALUES) &&
299 [ + + ]: 120 : (*split[1] == '\0')) {
300 : 1 : CFG_LOG(ERR,
301 : : "line %d - cannot use empty values",
302 : : lineno);
303 : 1 : goto error1;
304 : : }
305 : :
306 [ + + ]: 120 : if (cfg->num_sections == 0)
307 : 1 : goto error1;
308 : :
309 : 119 : int ret = _add_entry(&cfg->sections[cfg->num_sections - 1],
310 : : split[0], split[1]);
311 [ - + ]: 119 : if (ret != 0) {
312 : 0 : CFG_LOG(ERR,
313 : : "line %d - add entry failed: %s", lineno, strerror(-ret));
314 : 0 : goto error1;
315 : : }
316 : : }
317 : : }
318 : 6 : fclose(f);
319 : 6 : return cfg;
320 : 3 : error1:
321 : 3 : rte_cfgfile_close(cfg);
322 : 3 : fclose(f);
323 : 3 : return NULL;
324 : : }
325 : :
326 : : RTE_EXPORT_SYMBOL(rte_cfgfile_create)
327 : : struct rte_cfgfile *
328 : 9 : rte_cfgfile_create(int flags)
329 : : {
330 : : struct rte_cfgfile *cfg;
331 : :
332 : : /* future proof flags usage */
333 [ + - ]: 9 : if (flags & ~(CFG_FLAG_GLOBAL_SECTION | CFG_FLAG_EMPTY_VALUES))
334 : : return NULL;
335 : :
336 : 9 : cfg = malloc(sizeof(*cfg));
337 : :
338 [ + - ]: 9 : if (cfg == NULL)
339 : : return NULL;
340 : :
341 : 9 : cfg->flags = flags;
342 : 9 : cfg->num_sections = 0;
343 : :
344 : : /* allocate first batch of sections and entries */
345 : 9 : cfg->sections = calloc(CFG_ALLOC_SECTION_BATCH,
346 : : sizeof(struct rte_cfgfile_section));
347 [ - + ]: 9 : if (cfg->sections == NULL)
348 : 0 : goto error1;
349 : :
350 : 9 : cfg->allocated_sections = CFG_ALLOC_SECTION_BATCH;
351 : :
352 [ + + ]: 81 : for (size_t i = 0; i < CFG_ALLOC_SECTION_BATCH; i++) {
353 : 72 : cfg->sections[i].entries = calloc(CFG_ALLOC_ENTRY_BATCH,
354 : : sizeof(struct rte_cfgfile_entry));
355 : :
356 [ - + ]: 72 : if (cfg->sections[i].entries == NULL)
357 : 0 : goto error1;
358 : :
359 : 72 : cfg->sections[i].num_entries = 0;
360 : 72 : cfg->sections[i].allocated_entries = CFG_ALLOC_ENTRY_BATCH;
361 : : }
362 : :
363 [ + + ]: 9 : if (flags & CFG_FLAG_GLOBAL_SECTION)
364 : 1 : rte_cfgfile_add_section(cfg, "GLOBAL");
365 : :
366 : : return cfg;
367 : 0 : error1:
368 [ # # ]: 0 : if (cfg->sections != NULL) {
369 [ # # ]: 0 : for (size_t i = 0; i < cfg->allocated_sections; i++) {
370 [ # # ]: 0 : if (cfg->sections[i].entries != NULL) {
371 : 0 : free(cfg->sections[i].entries);
372 : 0 : cfg->sections[i].entries = NULL;
373 : : }
374 : : }
375 : 0 : free(cfg->sections);
376 : : cfg->sections = NULL;
377 : : }
378 : 0 : free(cfg);
379 : 0 : return NULL;
380 : : }
381 : :
382 : : RTE_EXPORT_SYMBOL(rte_cfgfile_add_section)
383 : : int
384 : 16 : rte_cfgfile_add_section(struct rte_cfgfile *cfg, const char *sectionname)
385 : : {
386 [ + - ]: 16 : if (cfg == NULL)
387 : : return -EINVAL;
388 : :
389 [ + - ]: 16 : if (sectionname == NULL)
390 : : return -EINVAL;
391 : :
392 [ + - ]: 16 : if (strlen(sectionname) >= CFG_NAME_LEN)
393 : : return -ENAMETOOLONG;
394 : :
395 : : /* resize overall struct if we don't have room for more sections */
396 [ + + ]: 16 : if (cfg->num_sections == cfg->allocated_sections) {
397 [ + - ]: 1 : if (cfg->allocated_sections > CFG_ALLOC_SECTION_MAX - CFG_ALLOC_SECTION_BATCH)
398 : : return -ENOMEM;
399 : :
400 : : struct rte_cfgfile_section *n_sections =
401 : 1 : realloc(cfg->sections,
402 : : sizeof(struct rte_cfgfile_section) *
403 : : ((cfg->allocated_sections) +
404 : : CFG_ALLOC_SECTION_BATCH));
405 : :
406 [ + - ]: 1 : if (n_sections == NULL)
407 : : return -ENOMEM;
408 : :
409 [ + + ]: 9 : for (size_t i = 0; i < CFG_ALLOC_SECTION_BATCH; i++) {
410 : 8 : n_sections[i + cfg->allocated_sections].num_entries = 0;
411 : : n_sections[i +
412 : 8 : cfg->allocated_sections].allocated_entries = 0;
413 : 8 : n_sections[i + cfg->allocated_sections].entries = NULL;
414 : : }
415 : 1 : cfg->sections = n_sections;
416 : 1 : cfg->allocated_sections += CFG_ALLOC_SECTION_BATCH;
417 : : }
418 : :
419 : 16 : strlcpy(cfg->sections[cfg->num_sections].name, sectionname,
420 : : sizeof(cfg->sections[0].name));
421 : 16 : cfg->sections[cfg->num_sections].num_entries = 0;
422 : 16 : cfg->num_sections++;
423 : :
424 : 16 : return 0;
425 : : }
426 : :
427 : : RTE_EXPORT_SYMBOL(rte_cfgfile_add_entry)
428 : 0 : int rte_cfgfile_add_entry(struct rte_cfgfile *cfg,
429 : : const char *sectionname, const char *entryname,
430 : : const char *entryvalue)
431 : : {
432 [ # # ]: 0 : if ((cfg == NULL) || (sectionname == NULL) || (entryname == NULL)
433 [ # # ]: 0 : || (entryvalue == NULL))
434 : : return -EINVAL;
435 : :
436 [ # # ]: 0 : if (rte_cfgfile_has_entry(cfg, sectionname, entryname) != 0)
437 : : return -EEXIST;
438 : :
439 : : /* search for section pointer by sectionname */
440 : 0 : struct rte_cfgfile_section *curr_section = _get_section(cfg,
441 : : sectionname);
442 [ # # ]: 0 : if (curr_section == NULL)
443 : : return -EINVAL;
444 : :
445 : 0 : return _add_entry(curr_section, entryname, entryvalue);
446 : : }
447 : :
448 : : RTE_EXPORT_SYMBOL(rte_cfgfile_set_entry)
449 : 0 : int rte_cfgfile_set_entry(struct rte_cfgfile *cfg, const char *sectionname,
450 : : const char *entryname, const char *entryvalue)
451 : : {
452 [ # # # # ]: 0 : if ((cfg == NULL) || (sectionname == NULL) || (entryname == NULL))
453 : : return -EINVAL;
454 : :
455 : : /* search for section pointer by sectionname */
456 : 0 : struct rte_cfgfile_section *curr_section = _get_section(cfg,
457 : : sectionname);
458 [ # # ]: 0 : if (curr_section == NULL)
459 : : return -EINVAL;
460 : :
461 [ # # ]: 0 : if (entryvalue == NULL)
462 : : entryvalue = "";
463 : :
464 [ # # ]: 0 : for (size_t i = 0; i < curr_section->num_entries; i++)
465 [ # # ]: 0 : if (!strcmp(curr_section->entries[i].name, entryname)) {
466 : 0 : strlcpy(curr_section->entries[i].value, entryvalue,
467 : : sizeof(curr_section->entries[i].value));
468 : 0 : return 0;
469 : : }
470 : :
471 : 0 : CFG_LOG(ERR, "entry name doesn't exist");
472 : 0 : return -EINVAL;
473 : : }
474 : :
475 : : RTE_EXPORT_SYMBOL(rte_cfgfile_save)
476 : 1 : int rte_cfgfile_save(struct rte_cfgfile *cfg, const char *filename)
477 : : {
478 [ + - ]: 1 : if ((cfg == NULL) || (filename == NULL))
479 : : return -EINVAL;
480 : :
481 : 1 : FILE *f = fopen(filename, "w");
482 : :
483 [ + - ]: 1 : if (f == NULL)
484 : : return -EINVAL;
485 : :
486 [ + + ]: 10 : for (size_t i = 0; i < cfg->num_sections; i++) {
487 : 9 : fprintf(f, "[%s]\n", cfg->sections[i].name);
488 : :
489 [ + + ]: 120 : for (size_t j = 0; j < cfg->sections[i].num_entries; j++) {
490 : : fprintf(f, "%s=%s\n",
491 : 111 : cfg->sections[i].entries[j].name,
492 : 111 : cfg->sections[i].entries[j].value);
493 : : }
494 : : }
495 : 1 : return fclose(f);
496 : : }
497 : :
498 : : RTE_EXPORT_SYMBOL(rte_cfgfile_close)
499 : 9 : int rte_cfgfile_close(struct rte_cfgfile *cfg)
500 : : {
501 [ + - ]: 9 : if (cfg == NULL)
502 : : return -1;
503 : :
504 [ + - ]: 9 : if (cfg->sections != NULL) {
505 [ + + ]: 89 : for (size_t i = 0; i < cfg->allocated_sections; i++) {
506 [ + + ]: 80 : if (cfg->sections[i].entries != NULL) {
507 : 73 : free(cfg->sections[i].entries);
508 : 73 : cfg->sections[i].entries = NULL;
509 : : }
510 : : }
511 : 9 : free(cfg->sections);
512 : : cfg->sections = NULL;
513 : : }
514 : 9 : free(cfg);
515 : : cfg = NULL;
516 : :
517 : 9 : return 0;
518 : : }
519 : :
520 : : RTE_EXPORT_SYMBOL(rte_cfgfile_num_sections)
521 : : int
522 : 6 : rte_cfgfile_num_sections(struct rte_cfgfile *cfg, const char *sectionname,
523 : : size_t length)
524 : : {
525 : : size_t num_sections = 0;
526 : :
527 [ + - ]: 6 : if (cfg == NULL)
528 : : return -1;
529 : :
530 [ + - ]: 6 : if (sectionname == NULL)
531 : 6 : return (int)cfg->num_sections;
532 : :
533 [ # # ]: 0 : for (size_t i = 0; i < cfg->num_sections; i++) {
534 [ # # ]: 0 : if (strncmp(cfg->sections[i].name, sectionname, length) == 0)
535 : 0 : num_sections++;
536 : : }
537 : :
538 : 0 : return (int)num_sections;
539 : : }
540 : :
541 : : RTE_EXPORT_SYMBOL(rte_cfgfile_sections)
542 : : int
543 : 0 : rte_cfgfile_sections(struct rte_cfgfile *cfg, char *sections[],
544 : : int max_sections)
545 : : {
546 : : int i;
547 : :
548 [ # # # # ]: 0 : if (cfg == NULL || sections == NULL || max_sections < 0)
549 : : return -1;
550 : :
551 [ # # # # ]: 0 : for (i = 0; (size_t)i < cfg->num_sections && i < max_sections; i++) {
552 [ # # ]: 0 : if (sections[i] == NULL)
553 : : return -1;
554 : 0 : strlcpy(sections[i], cfg->sections[i].name, CFG_NAME_LEN);
555 : : }
556 : :
557 : : return i;
558 : : }
559 : :
560 : : RTE_EXPORT_SYMBOL(rte_cfgfile_has_section)
561 : : int
562 : 7 : rte_cfgfile_has_section(struct rte_cfgfile *cfg, const char *sectionname)
563 : : {
564 [ + - ]: 7 : if (cfg == NULL || sectionname == NULL)
565 : : return 0;
566 : :
567 : 7 : return _get_section(cfg, sectionname) != NULL;
568 : : }
569 : :
570 : : RTE_EXPORT_SYMBOL(rte_cfgfile_section_num_entries)
571 : : int
572 : 8 : rte_cfgfile_section_num_entries(struct rte_cfgfile *cfg,
573 : : const char *sectionname)
574 : : {
575 [ + - ]: 8 : if (cfg == NULL || sectionname == NULL)
576 : : return -1;
577 : :
578 : 8 : const struct rte_cfgfile_section *s = _get_section(cfg, sectionname);
579 [ + - ]: 8 : if (s == NULL)
580 : : return -1;
581 : :
582 : 8 : return (int)s->num_entries;
583 : : }
584 : :
585 : : RTE_EXPORT_SYMBOL(rte_cfgfile_section_num_entries_by_index)
586 : : int
587 : 0 : rte_cfgfile_section_num_entries_by_index(struct rte_cfgfile *cfg,
588 : : char *sectionname, int index)
589 : : {
590 [ # # ]: 0 : if (cfg == NULL || sectionname == NULL)
591 : : return -1;
592 : :
593 [ # # # # ]: 0 : if (index < 0 || (size_t)index >= cfg->num_sections)
594 : : return -1;
595 : :
596 : 0 : const struct rte_cfgfile_section *sect = &(cfg->sections[index]);
597 : :
598 : 0 : strlcpy(sectionname, sect->name, CFG_NAME_LEN);
599 : 0 : return (int)sect->num_entries;
600 : : }
601 : : RTE_EXPORT_SYMBOL(rte_cfgfile_section_entries)
602 : : int
603 : 0 : rte_cfgfile_section_entries(struct rte_cfgfile *cfg, const char *sectionname,
604 : : struct rte_cfgfile_entry *entries, int max_entries)
605 : : {
606 : : int i;
607 : :
608 [ # # # # ]: 0 : if (cfg == NULL || sectionname == NULL || entries == NULL)
609 : : return -1;
610 : :
611 : 0 : const struct rte_cfgfile_section *sect = _get_section(cfg, sectionname);
612 [ # # ]: 0 : if (sect == NULL)
613 : : return -1;
614 [ # # # # ]: 0 : for (i = 0; i < max_entries && (size_t)i < sect->num_entries; i++)
615 : 0 : entries[i] = sect->entries[i];
616 : : return i;
617 : : }
618 : :
619 : : RTE_EXPORT_SYMBOL(rte_cfgfile_section_entries_by_index)
620 : : int
621 : 0 : rte_cfgfile_section_entries_by_index(struct rte_cfgfile *cfg, int index,
622 : : char *sectionname,
623 : : struct rte_cfgfile_entry *entries, int max_entries)
624 : : {
625 : : int i;
626 : : const struct rte_cfgfile_section *sect;
627 : :
628 [ # # # # ]: 0 : if (cfg == NULL || sectionname == NULL || entries == NULL)
629 : : return -1;
630 [ # # ]: 0 : if (max_entries < 0)
631 : : return -1;
632 : :
633 [ # # # # ]: 0 : if (index < 0 || (size_t)index >= cfg->num_sections)
634 : : return -1;
635 : 0 : sect = &cfg->sections[index];
636 : 0 : strlcpy(sectionname, sect->name, CFG_NAME_LEN);
637 [ # # # # ]: 0 : for (i = 0; i < max_entries && (size_t)i < sect->num_entries; i++)
638 : 0 : entries[i] = sect->entries[i];
639 : : return i;
640 : : }
641 : :
642 : : RTE_EXPORT_SYMBOL(rte_cfgfile_get_entry)
643 : : const char *
644 : 9 : rte_cfgfile_get_entry(struct rte_cfgfile *cfg, const char *sectionname,
645 : : const char *entryname)
646 : : {
647 [ + - + - ]: 9 : if (cfg == NULL || sectionname == NULL || entryname == NULL)
648 : : return NULL;
649 : :
650 : 9 : const struct rte_cfgfile_section *sect = _get_section(cfg, sectionname);
651 [ + - ]: 9 : if (sect == NULL)
652 : : return NULL;
653 [ + - ]: 18 : for (size_t i = 0; i < sect->num_entries; i++)
654 [ + + ]: 18 : if (strncmp(sect->entries[i].name, entryname, CFG_NAME_LEN)
655 : : == 0)
656 : 9 : return sect->entries[i].value;
657 : : return NULL;
658 : : }
659 : :
660 : : RTE_EXPORT_SYMBOL(rte_cfgfile_has_entry)
661 : : int
662 : 0 : rte_cfgfile_has_entry(struct rte_cfgfile *cfg, const char *sectionname,
663 : : const char *entryname)
664 : : {
665 : 0 : return rte_cfgfile_get_entry(cfg, sectionname, entryname) != NULL;
666 : : }
|