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