1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation
10 #include <rte_string_fns.h>
11 #include <rte_common.h>
14 #include "rte_cfgfile.h"
16 struct rte_cfgfile_section
{
17 char name
[CFG_NAME_LEN
];
19 int allocated_entries
;
20 struct rte_cfgfile_entry
*entries
;
26 int allocated_sections
;
27 struct rte_cfgfile_section
*sections
;
30 static int cfgfile_logtype
;
32 #define CFG_LOG(level, fmt, args...) \
33 rte_log(RTE_LOG_ ## level, cfgfile_logtype, "%s(): " fmt "\n", \
36 /** when we resize a file structure, how many extra entries
37 * for new sections do we add in */
38 #define CFG_ALLOC_SECTION_BATCH 8
39 /** when we resize a section structure, how many extra entries
40 * for new entries do we add in */
41 #define CFG_ALLOC_ENTRY_BATCH 16
44 * Default cfgfile load parameters.
46 static const struct rte_cfgfile_parameters default_cfgfile_params
= {
47 .comment_character
= CFG_DEFAULT_COMMENT_CHARACTER
,
51 * Defines the list of acceptable comment characters supported by this
54 static const char valid_comment_chars
[] = {
63 _strip(char *str
, unsigned len
)
69 if (isspace(str
[len
-1])) {
70 /* strip trailing whitespace */
71 while (newlen
> 0 && isspace(str
[newlen
- 1]))
75 if (isspace(str
[0])) {
76 /* strip leading whitespace */
78 while (isspace(str
[start
]) && start
< newlen
)
82 for (i
= 0; i
< newlen
; i
++)
83 str
[i
] = str
[i
+start
];
89 static struct rte_cfgfile_section
*
90 _get_section(struct rte_cfgfile
*cfg
, const char *sectionname
)
94 for (i
= 0; i
< cfg
->num_sections
; i
++) {
95 if (strncmp(cfg
->sections
[i
].name
, sectionname
,
96 sizeof(cfg
->sections
[0].name
)) == 0)
97 return &cfg
->sections
[i
];
103 _add_entry(struct rte_cfgfile_section
*section
, const char *entryname
,
104 const char *entryvalue
)
106 /* resize entry structure if we don't have room for more entries */
107 if (section
->num_entries
== section
->allocated_entries
) {
108 struct rte_cfgfile_entry
*n_entries
= realloc(
110 sizeof(struct rte_cfgfile_entry
) *
111 ((section
->allocated_entries
) +
112 CFG_ALLOC_ENTRY_BATCH
));
114 if (n_entries
== NULL
)
117 section
->entries
= n_entries
;
118 section
->allocated_entries
+= CFG_ALLOC_ENTRY_BATCH
;
120 /* fill up entry fields with key name and value */
121 struct rte_cfgfile_entry
*curr_entry
=
122 §ion
->entries
[section
->num_entries
];
124 strlcpy(curr_entry
->name
, entryname
, sizeof(curr_entry
->name
));
125 strlcpy(curr_entry
->value
, entryvalue
, sizeof(curr_entry
->value
));
126 section
->num_entries
++;
132 rte_cfgfile_check_params(const struct rte_cfgfile_parameters
*params
)
134 unsigned int valid_comment
;
138 CFG_LOG(ERR
, "missing cfgfile parameters\n");
143 for (i
= 0; i
< RTE_DIM(valid_comment_chars
); i
++) {
144 if (params
->comment_character
== valid_comment_chars
[i
]) {
150 if (valid_comment
== 0) {
151 CFG_LOG(ERR
, "invalid comment characters %c\n",
152 params
->comment_character
);
160 rte_cfgfile_load(const char *filename
, int flags
)
162 return rte_cfgfile_load_with_params(filename
, flags
,
163 &default_cfgfile_params
);
167 rte_cfgfile_load_with_params(const char *filename
, int flags
,
168 const struct rte_cfgfile_parameters
*params
)
170 char buffer
[CFG_NAME_LEN
+ CFG_VALUE_LEN
+ 4];
172 struct rte_cfgfile
*cfg
;
174 if (rte_cfgfile_check_params(params
))
177 FILE *f
= fopen(filename
, "r");
181 cfg
= rte_cfgfile_create(flags
);
183 while (fgets(buffer
, sizeof(buffer
), f
) != NULL
) {
185 size_t len
= strnlen(buffer
, sizeof(buffer
));
187 if ((len
>= sizeof(buffer
) - 1) && (buffer
[len
-1] != '\n')) {
188 CFG_LOG(ERR
, " line %d - no \\n found on string. "
189 "Check if line too long\n", lineno
);
192 /* skip parsing if comment character found */
193 pos
= memchr(buffer
, params
->comment_character
, len
);
194 if (pos
!= NULL
&& (*(pos
-1) != '\\')) {
199 len
= _strip(buffer
, len
);
200 /* skip lines without useful content */
201 if (buffer
[0] != '[' && memchr(buffer
, '=', len
) == NULL
)
204 if (buffer
[0] == '[') {
205 /* section heading line */
206 char *end
= memchr(buffer
, ']', len
);
209 "line %d - no terminating ']' character found\n",
214 _strip(&buffer
[1], end
- &buffer
[1]);
216 rte_cfgfile_add_section(cfg
, &buffer
[1]);
218 /* key and value line */
219 char *split
[2] = {NULL
};
222 split
[1] = memchr(buffer
, '=', len
);
223 if (split
[1] == NULL
) {
225 "line %d - no '=' character found\n",
232 _strip(split
[0], strlen(split
[0]));
233 _strip(split
[1], strlen(split
[1]));
234 char *end
= memchr(split
[1], '\\', strlen(split
[1]));
236 size_t split_len
= strlen(split
[1]) + 1;
237 while (end
!= NULL
) {
238 if (*(end
+1) == params
->comment_character
) {
240 strlcat(split
[1], end
+1, split_len
);
243 end
= memchr(end
, '\\', strlen(end
));
246 if (!(flags
& CFG_FLAG_EMPTY_VALUES
) &&
247 (*split
[1] == '\0')) {
249 "line %d - cannot use empty values\n",
254 if (cfg
->num_sections
== 0)
257 _add_entry(&cfg
->sections
[cfg
->num_sections
- 1],
264 rte_cfgfile_close(cfg
);
270 rte_cfgfile_create(int flags
)
273 struct rte_cfgfile
*cfg
;
275 cfg
= malloc(sizeof(*cfg
));
281 cfg
->num_sections
= 0;
283 /* allocate first batch of sections and entries */
284 cfg
->sections
= calloc(CFG_ALLOC_SECTION_BATCH
,
285 sizeof(struct rte_cfgfile_section
));
286 if (cfg
->sections
== NULL
)
289 cfg
->allocated_sections
= CFG_ALLOC_SECTION_BATCH
;
291 for (i
= 0; i
< CFG_ALLOC_SECTION_BATCH
; i
++) {
292 cfg
->sections
[i
].entries
= calloc(CFG_ALLOC_ENTRY_BATCH
,
293 sizeof(struct rte_cfgfile_entry
));
295 if (cfg
->sections
[i
].entries
== NULL
)
298 cfg
->sections
[i
].num_entries
= 0;
299 cfg
->sections
[i
].allocated_entries
= CFG_ALLOC_ENTRY_BATCH
;
302 if (flags
& CFG_FLAG_GLOBAL_SECTION
)
303 rte_cfgfile_add_section(cfg
, "GLOBAL");
307 if (cfg
->sections
!= NULL
) {
308 for (i
= 0; i
< cfg
->allocated_sections
; i
++) {
309 if (cfg
->sections
[i
].entries
!= NULL
) {
310 free(cfg
->sections
[i
].entries
);
311 cfg
->sections
[i
].entries
= NULL
;
315 cfg
->sections
= NULL
;
322 rte_cfgfile_add_section(struct rte_cfgfile
*cfg
, const char *sectionname
)
329 if (sectionname
== NULL
)
332 /* resize overall struct if we don't have room for more sections */
333 if (cfg
->num_sections
== cfg
->allocated_sections
) {
335 struct rte_cfgfile_section
*n_sections
=
336 realloc(cfg
->sections
,
337 sizeof(struct rte_cfgfile_section
) *
338 ((cfg
->allocated_sections
) +
339 CFG_ALLOC_SECTION_BATCH
));
341 if (n_sections
== NULL
)
344 for (i
= 0; i
< CFG_ALLOC_SECTION_BATCH
; i
++) {
345 n_sections
[i
+ cfg
->allocated_sections
].num_entries
= 0;
347 cfg
->allocated_sections
].allocated_entries
= 0;
348 n_sections
[i
+ cfg
->allocated_sections
].entries
= NULL
;
350 cfg
->sections
= n_sections
;
351 cfg
->allocated_sections
+= CFG_ALLOC_SECTION_BATCH
;
354 strlcpy(cfg
->sections
[cfg
->num_sections
].name
, sectionname
,
355 sizeof(cfg
->sections
[0].name
));
356 cfg
->sections
[cfg
->num_sections
].num_entries
= 0;
362 int rte_cfgfile_add_entry(struct rte_cfgfile
*cfg
,
363 const char *sectionname
, const char *entryname
,
364 const char *entryvalue
)
368 if ((cfg
== NULL
) || (sectionname
== NULL
) || (entryname
== NULL
)
369 || (entryvalue
== NULL
))
372 if (rte_cfgfile_has_entry(cfg
, sectionname
, entryname
) != 0)
375 /* search for section pointer by sectionname */
376 struct rte_cfgfile_section
*curr_section
= _get_section(cfg
,
378 if (curr_section
== NULL
)
381 ret
= _add_entry(curr_section
, entryname
, entryvalue
);
386 int rte_cfgfile_set_entry(struct rte_cfgfile
*cfg
, const char *sectionname
,
387 const char *entryname
, const char *entryvalue
)
391 if ((cfg
== NULL
) || (sectionname
== NULL
) || (entryname
== NULL
))
394 /* search for section pointer by sectionname */
395 struct rte_cfgfile_section
*curr_section
= _get_section(cfg
,
397 if (curr_section
== NULL
)
400 if (entryvalue
== NULL
)
403 for (i
= 0; i
< curr_section
->num_entries
; i
++)
404 if (!strcmp(curr_section
->entries
[i
].name
, entryname
)) {
405 strlcpy(curr_section
->entries
[i
].value
, entryvalue
,
406 sizeof(curr_section
->entries
[i
].value
));
410 CFG_LOG(ERR
, "entry name doesn't exist\n");
414 int rte_cfgfile_save(struct rte_cfgfile
*cfg
, const char *filename
)
418 if ((cfg
== NULL
) || (filename
== NULL
))
421 FILE *f
= fopen(filename
, "w");
426 for (i
= 0; i
< cfg
->num_sections
; i
++) {
427 fprintf(f
, "[%s]\n", cfg
->sections
[i
].name
);
429 for (j
= 0; j
< cfg
->sections
[i
].num_entries
; j
++) {
430 fprintf(f
, "%s=%s\n",
431 cfg
->sections
[i
].entries
[j
].name
,
432 cfg
->sections
[i
].entries
[j
].value
);
438 int rte_cfgfile_close(struct rte_cfgfile
*cfg
)
445 if (cfg
->sections
!= NULL
) {
446 for (i
= 0; i
< cfg
->allocated_sections
; i
++) {
447 if (cfg
->sections
[i
].entries
!= NULL
) {
448 free(cfg
->sections
[i
].entries
);
449 cfg
->sections
[i
].entries
= NULL
;
453 cfg
->sections
= NULL
;
462 rte_cfgfile_num_sections(struct rte_cfgfile
*cfg
, const char *sectionname
,
466 int num_sections
= 0;
467 for (i
= 0; i
< cfg
->num_sections
; i
++) {
468 if (strncmp(cfg
->sections
[i
].name
, sectionname
, length
) == 0)
475 rte_cfgfile_sections(struct rte_cfgfile
*cfg
, char *sections
[],
480 for (i
= 0; i
< cfg
->num_sections
&& i
< max_sections
; i
++)
481 strlcpy(sections
[i
], cfg
->sections
[i
].name
, CFG_NAME_LEN
);
487 rte_cfgfile_has_section(struct rte_cfgfile
*cfg
, const char *sectionname
)
489 return _get_section(cfg
, sectionname
) != NULL
;
493 rte_cfgfile_section_num_entries(struct rte_cfgfile
*cfg
,
494 const char *sectionname
)
496 const struct rte_cfgfile_section
*s
= _get_section(cfg
, sectionname
);
499 return s
->num_entries
;
503 rte_cfgfile_section_num_entries_by_index(struct rte_cfgfile
*cfg
,
504 char *sectionname
, int index
)
506 if (index
< 0 || index
>= cfg
->num_sections
)
509 const struct rte_cfgfile_section
*sect
= &(cfg
->sections
[index
]);
511 strlcpy(sectionname
, sect
->name
, CFG_NAME_LEN
);
512 return sect
->num_entries
;
515 rte_cfgfile_section_entries(struct rte_cfgfile
*cfg
, const char *sectionname
,
516 struct rte_cfgfile_entry
*entries
, int max_entries
)
519 const struct rte_cfgfile_section
*sect
= _get_section(cfg
, sectionname
);
522 for (i
= 0; i
< max_entries
&& i
< sect
->num_entries
; i
++)
523 entries
[i
] = sect
->entries
[i
];
528 rte_cfgfile_section_entries_by_index(struct rte_cfgfile
*cfg
, int index
,
530 struct rte_cfgfile_entry
*entries
, int max_entries
)
533 const struct rte_cfgfile_section
*sect
;
535 if (index
< 0 || index
>= cfg
->num_sections
)
537 sect
= &cfg
->sections
[index
];
538 strlcpy(sectionname
, sect
->name
, CFG_NAME_LEN
);
539 for (i
= 0; i
< max_entries
&& i
< sect
->num_entries
; i
++)
540 entries
[i
] = sect
->entries
[i
];
545 rte_cfgfile_get_entry(struct rte_cfgfile
*cfg
, const char *sectionname
,
546 const char *entryname
)
549 const struct rte_cfgfile_section
*sect
= _get_section(cfg
, sectionname
);
552 for (i
= 0; i
< sect
->num_entries
; i
++)
553 if (strncmp(sect
->entries
[i
].name
, entryname
, CFG_NAME_LEN
)
555 return sect
->entries
[i
].value
;
560 rte_cfgfile_has_entry(struct rte_cfgfile
*cfg
, const char *sectionname
,
561 const char *entryname
)
563 return rte_cfgfile_get_entry(cfg
, sectionname
, entryname
) != NULL
;
566 RTE_INIT(cfgfile_init
)
568 cfgfile_logtype
= rte_log_register("lib.cfgfile");
569 if (cfgfile_logtype
>= 0)
570 rte_log_set_level(cfgfile_logtype
, RTE_LOG_INFO
);