199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson * Copyright(c) 2010-2014 Intel Corporation
399a2dd95SBruce Richardson */
499a2dd95SBruce Richardson
599a2dd95SBruce Richardson #include <stdio.h>
699a2dd95SBruce Richardson #include <stdlib.h>
799a2dd95SBruce Richardson #include <string.h>
899a2dd95SBruce Richardson #include <ctype.h>
999a2dd95SBruce Richardson #include <errno.h>
1099a2dd95SBruce Richardson #include <rte_string_fns.h>
1199a2dd95SBruce Richardson #include <rte_common.h>
1299a2dd95SBruce Richardson #include <rte_log.h>
1399a2dd95SBruce Richardson
1499a2dd95SBruce Richardson #include "rte_cfgfile.h"
1599a2dd95SBruce Richardson
1699a2dd95SBruce Richardson struct rte_cfgfile_section {
1799a2dd95SBruce Richardson char name[CFG_NAME_LEN];
1899a2dd95SBruce Richardson int num_entries;
1999a2dd95SBruce Richardson int allocated_entries;
2099a2dd95SBruce Richardson struct rte_cfgfile_entry *entries;
2199a2dd95SBruce Richardson };
2299a2dd95SBruce Richardson
2399a2dd95SBruce Richardson struct rte_cfgfile {
2499a2dd95SBruce Richardson int flags;
2599a2dd95SBruce Richardson int num_sections;
2699a2dd95SBruce Richardson int allocated_sections;
2799a2dd95SBruce Richardson struct rte_cfgfile_section *sections;
2899a2dd95SBruce Richardson };
2999a2dd95SBruce Richardson
301f6f9526SBruce Richardson /* Setting up dynamic logging 8< */
31eeded204SDavid Marchand RTE_LOG_REGISTER_DEFAULT(cfgfile_logtype, INFO);
3297433132SDavid Marchand #define RTE_LOGTYPE_CFGFILE cfgfile_logtype
3399a2dd95SBruce Richardson
34*0f1dc8cbSTyler Retzlaff #define CFG_LOG(level, ...) \
35*0f1dc8cbSTyler Retzlaff RTE_LOG_LINE_PREFIX(level, CFGFILE, "%s(): ", __func__, __VA_ARGS__)
361f6f9526SBruce Richardson /* >8 End of setting up dynamic logging */
3799a2dd95SBruce Richardson
3899a2dd95SBruce Richardson /** when we resize a file structure, how many extra entries
3999a2dd95SBruce Richardson * for new sections do we add in */
4099a2dd95SBruce Richardson #define CFG_ALLOC_SECTION_BATCH 8
4199a2dd95SBruce Richardson /** when we resize a section structure, how many extra entries
4299a2dd95SBruce Richardson * for new entries do we add in */
4399a2dd95SBruce Richardson #define CFG_ALLOC_ENTRY_BATCH 16
4499a2dd95SBruce Richardson
4599a2dd95SBruce Richardson /**
4699a2dd95SBruce Richardson * Default cfgfile load parameters.
4799a2dd95SBruce Richardson */
4899a2dd95SBruce Richardson static const struct rte_cfgfile_parameters default_cfgfile_params = {
4999a2dd95SBruce Richardson .comment_character = CFG_DEFAULT_COMMENT_CHARACTER,
5099a2dd95SBruce Richardson };
5199a2dd95SBruce Richardson
5299a2dd95SBruce Richardson /**
5399a2dd95SBruce Richardson * Defines the list of acceptable comment characters supported by this
5499a2dd95SBruce Richardson * library.
5599a2dd95SBruce Richardson */
5699a2dd95SBruce Richardson static const char valid_comment_chars[] = {
5799a2dd95SBruce Richardson '!',
5899a2dd95SBruce Richardson '#',
5999a2dd95SBruce Richardson '%',
6099a2dd95SBruce Richardson ';',
6199a2dd95SBruce Richardson '@'
6299a2dd95SBruce Richardson };
6399a2dd95SBruce Richardson
6499a2dd95SBruce Richardson static unsigned
_strip(char * str,unsigned len)6599a2dd95SBruce Richardson _strip(char *str, unsigned len)
6699a2dd95SBruce Richardson {
6799a2dd95SBruce Richardson int newlen = len;
6899a2dd95SBruce Richardson if (len == 0)
6999a2dd95SBruce Richardson return 0;
7099a2dd95SBruce Richardson
7199a2dd95SBruce Richardson if (isspace(str[len-1])) {
7299a2dd95SBruce Richardson /* strip trailing whitespace */
7399a2dd95SBruce Richardson while (newlen > 0 && isspace(str[newlen - 1]))
7499a2dd95SBruce Richardson str[--newlen] = '\0';
7599a2dd95SBruce Richardson }
7699a2dd95SBruce Richardson
7799a2dd95SBruce Richardson if (isspace(str[0])) {
7899a2dd95SBruce Richardson /* strip leading whitespace */
7999a2dd95SBruce Richardson int i, start = 1;
8099a2dd95SBruce Richardson while (isspace(str[start]) && start < newlen)
8199a2dd95SBruce Richardson start++
8299a2dd95SBruce Richardson ; /* do nothing */
8399a2dd95SBruce Richardson newlen -= start;
8499a2dd95SBruce Richardson for (i = 0; i < newlen; i++)
8599a2dd95SBruce Richardson str[i] = str[i+start];
8699a2dd95SBruce Richardson str[i] = '\0';
8799a2dd95SBruce Richardson }
8899a2dd95SBruce Richardson return newlen;
8999a2dd95SBruce Richardson }
9099a2dd95SBruce Richardson
9199a2dd95SBruce Richardson static struct rte_cfgfile_section *
_get_section(struct rte_cfgfile * cfg,const char * sectionname)9299a2dd95SBruce Richardson _get_section(struct rte_cfgfile *cfg, const char *sectionname)
9399a2dd95SBruce Richardson {
9499a2dd95SBruce Richardson int i;
9599a2dd95SBruce Richardson
9699a2dd95SBruce Richardson for (i = 0; i < cfg->num_sections; i++) {
9799a2dd95SBruce Richardson if (strncmp(cfg->sections[i].name, sectionname,
9899a2dd95SBruce Richardson sizeof(cfg->sections[0].name)) == 0)
9999a2dd95SBruce Richardson return &cfg->sections[i];
10099a2dd95SBruce Richardson }
10199a2dd95SBruce Richardson return NULL;
10299a2dd95SBruce Richardson }
10399a2dd95SBruce Richardson
10499a2dd95SBruce Richardson static int
_add_entry(struct rte_cfgfile_section * section,const char * entryname,const char * entryvalue)10599a2dd95SBruce Richardson _add_entry(struct rte_cfgfile_section *section, const char *entryname,
10699a2dd95SBruce Richardson const char *entryvalue)
10799a2dd95SBruce Richardson {
10899a2dd95SBruce Richardson /* resize entry structure if we don't have room for more entries */
10999a2dd95SBruce Richardson if (section->num_entries == section->allocated_entries) {
11099a2dd95SBruce Richardson struct rte_cfgfile_entry *n_entries = realloc(
11199a2dd95SBruce Richardson section->entries,
11299a2dd95SBruce Richardson sizeof(struct rte_cfgfile_entry) *
11399a2dd95SBruce Richardson ((section->allocated_entries) +
11499a2dd95SBruce Richardson CFG_ALLOC_ENTRY_BATCH));
11599a2dd95SBruce Richardson
11699a2dd95SBruce Richardson if (n_entries == NULL)
11799a2dd95SBruce Richardson return -ENOMEM;
11899a2dd95SBruce Richardson
11999a2dd95SBruce Richardson section->entries = n_entries;
12099a2dd95SBruce Richardson section->allocated_entries += CFG_ALLOC_ENTRY_BATCH;
12199a2dd95SBruce Richardson }
12299a2dd95SBruce Richardson /* fill up entry fields with key name and value */
12399a2dd95SBruce Richardson struct rte_cfgfile_entry *curr_entry =
12499a2dd95SBruce Richardson §ion->entries[section->num_entries];
12599a2dd95SBruce Richardson
12699a2dd95SBruce Richardson strlcpy(curr_entry->name, entryname, sizeof(curr_entry->name));
12799a2dd95SBruce Richardson strlcpy(curr_entry->value, entryvalue, sizeof(curr_entry->value));
12899a2dd95SBruce Richardson section->num_entries++;
12999a2dd95SBruce Richardson
13099a2dd95SBruce Richardson return 0;
13199a2dd95SBruce Richardson }
13299a2dd95SBruce Richardson
13399a2dd95SBruce Richardson static int
rte_cfgfile_check_params(const struct rte_cfgfile_parameters * params)13499a2dd95SBruce Richardson rte_cfgfile_check_params(const struct rte_cfgfile_parameters *params)
13599a2dd95SBruce Richardson {
13699a2dd95SBruce Richardson unsigned int valid_comment;
13799a2dd95SBruce Richardson unsigned int i;
13899a2dd95SBruce Richardson
13999a2dd95SBruce Richardson if (!params) {
140ae282b06SDavid Marchand CFG_LOG(ERR, "missing cfgfile parameters");
14199a2dd95SBruce Richardson return -EINVAL;
14299a2dd95SBruce Richardson }
14399a2dd95SBruce Richardson
14499a2dd95SBruce Richardson valid_comment = 0;
14599a2dd95SBruce Richardson for (i = 0; i < RTE_DIM(valid_comment_chars); i++) {
14699a2dd95SBruce Richardson if (params->comment_character == valid_comment_chars[i]) {
14799a2dd95SBruce Richardson valid_comment = 1;
14899a2dd95SBruce Richardson break;
14999a2dd95SBruce Richardson }
15099a2dd95SBruce Richardson }
15199a2dd95SBruce Richardson
15299a2dd95SBruce Richardson if (valid_comment == 0) {
153ae282b06SDavid Marchand CFG_LOG(ERR, "invalid comment characters %c",
15499a2dd95SBruce Richardson params->comment_character);
15599a2dd95SBruce Richardson return -ENOTSUP;
15699a2dd95SBruce Richardson }
15799a2dd95SBruce Richardson
15899a2dd95SBruce Richardson return 0;
15999a2dd95SBruce Richardson }
16099a2dd95SBruce Richardson
16199a2dd95SBruce Richardson struct rte_cfgfile *
rte_cfgfile_load(const char * filename,int flags)16299a2dd95SBruce Richardson rte_cfgfile_load(const char *filename, int flags)
16399a2dd95SBruce Richardson {
16499a2dd95SBruce Richardson return rte_cfgfile_load_with_params(filename, flags,
16599a2dd95SBruce Richardson &default_cfgfile_params);
16699a2dd95SBruce Richardson }
16799a2dd95SBruce Richardson
16899a2dd95SBruce Richardson struct rte_cfgfile *
rte_cfgfile_load_with_params(const char * filename,int flags,const struct rte_cfgfile_parameters * params)16999a2dd95SBruce Richardson rte_cfgfile_load_with_params(const char *filename, int flags,
17099a2dd95SBruce Richardson const struct rte_cfgfile_parameters *params)
17199a2dd95SBruce Richardson {
17299a2dd95SBruce Richardson char buffer[CFG_NAME_LEN + CFG_VALUE_LEN + 4];
17399a2dd95SBruce Richardson int lineno = 0;
17499a2dd95SBruce Richardson struct rte_cfgfile *cfg;
17599a2dd95SBruce Richardson
17699a2dd95SBruce Richardson if (rte_cfgfile_check_params(params))
17799a2dd95SBruce Richardson return NULL;
17899a2dd95SBruce Richardson
17999a2dd95SBruce Richardson FILE *f = fopen(filename, "r");
18099a2dd95SBruce Richardson if (f == NULL)
18199a2dd95SBruce Richardson return NULL;
18299a2dd95SBruce Richardson
18399a2dd95SBruce Richardson cfg = rte_cfgfile_create(flags);
18499a2dd95SBruce Richardson
18599a2dd95SBruce Richardson while (fgets(buffer, sizeof(buffer), f) != NULL) {
18699a2dd95SBruce Richardson char *pos;
18799a2dd95SBruce Richardson size_t len = strnlen(buffer, sizeof(buffer));
18899a2dd95SBruce Richardson lineno++;
18999a2dd95SBruce Richardson if ((len >= sizeof(buffer) - 1) && (buffer[len-1] != '\n')) {
19099a2dd95SBruce Richardson CFG_LOG(ERR, " line %d - no \\n found on string. "
191ae282b06SDavid Marchand "Check if line too long", lineno);
19299a2dd95SBruce Richardson goto error1;
19399a2dd95SBruce Richardson }
19499a2dd95SBruce Richardson /* skip parsing if comment character found */
19599a2dd95SBruce Richardson pos = memchr(buffer, params->comment_character, len);
19699a2dd95SBruce Richardson if (pos != NULL &&
19799a2dd95SBruce Richardson (pos == buffer || *(pos-1) != '\\')) {
19899a2dd95SBruce Richardson *pos = '\0';
19999a2dd95SBruce Richardson len = pos - buffer;
20099a2dd95SBruce Richardson }
20199a2dd95SBruce Richardson
20299a2dd95SBruce Richardson len = _strip(buffer, len);
20399a2dd95SBruce Richardson /* skip lines without useful content */
20499a2dd95SBruce Richardson if (buffer[0] != '[' && memchr(buffer, '=', len) == NULL)
20599a2dd95SBruce Richardson continue;
20699a2dd95SBruce Richardson
20799a2dd95SBruce Richardson if (buffer[0] == '[') {
20899a2dd95SBruce Richardson /* section heading line */
20999a2dd95SBruce Richardson char *end = memchr(buffer, ']', len);
21099a2dd95SBruce Richardson if (end == NULL) {
21199a2dd95SBruce Richardson CFG_LOG(ERR,
212ae282b06SDavid Marchand "line %d - no terminating ']' character found",
21399a2dd95SBruce Richardson lineno);
21499a2dd95SBruce Richardson goto error1;
21599a2dd95SBruce Richardson }
21699a2dd95SBruce Richardson *end = '\0';
21799a2dd95SBruce Richardson _strip(&buffer[1], end - &buffer[1]);
21899a2dd95SBruce Richardson
21999a2dd95SBruce Richardson rte_cfgfile_add_section(cfg, &buffer[1]);
22099a2dd95SBruce Richardson } else {
22199a2dd95SBruce Richardson /* key and value line */
22299a2dd95SBruce Richardson char *split[2] = {NULL};
22399a2dd95SBruce Richardson
22499a2dd95SBruce Richardson split[0] = buffer;
22599a2dd95SBruce Richardson split[1] = memchr(buffer, '=', len);
22699a2dd95SBruce Richardson if (split[1] == NULL) {
22799a2dd95SBruce Richardson CFG_LOG(ERR,
228ae282b06SDavid Marchand "line %d - no '=' character found",
22999a2dd95SBruce Richardson lineno);
23099a2dd95SBruce Richardson goto error1;
23199a2dd95SBruce Richardson }
23299a2dd95SBruce Richardson *split[1] = '\0';
23399a2dd95SBruce Richardson split[1]++;
23499a2dd95SBruce Richardson
23599a2dd95SBruce Richardson _strip(split[0], strlen(split[0]));
23699a2dd95SBruce Richardson _strip(split[1], strlen(split[1]));
23799a2dd95SBruce Richardson char *end = memchr(split[1], '\\', strlen(split[1]));
23899a2dd95SBruce Richardson
23999a2dd95SBruce Richardson size_t split_len = strlen(split[1]) + 1;
24099a2dd95SBruce Richardson while (end != NULL) {
24199a2dd95SBruce Richardson if (*(end+1) == params->comment_character) {
24299a2dd95SBruce Richardson *end = '\0';
24399a2dd95SBruce Richardson strlcat(split[1], end+1, split_len);
24499a2dd95SBruce Richardson } else
24599a2dd95SBruce Richardson end++;
24699a2dd95SBruce Richardson end = memchr(end, '\\', strlen(end));
24799a2dd95SBruce Richardson }
24899a2dd95SBruce Richardson
24999a2dd95SBruce Richardson if (!(flags & CFG_FLAG_EMPTY_VALUES) &&
25099a2dd95SBruce Richardson (*split[1] == '\0')) {
25199a2dd95SBruce Richardson CFG_LOG(ERR,
252ae282b06SDavid Marchand "line %d - cannot use empty values",
25399a2dd95SBruce Richardson lineno);
25499a2dd95SBruce Richardson goto error1;
25599a2dd95SBruce Richardson }
25699a2dd95SBruce Richardson
25799a2dd95SBruce Richardson if (cfg->num_sections == 0)
25899a2dd95SBruce Richardson goto error1;
25999a2dd95SBruce Richardson
26099a2dd95SBruce Richardson _add_entry(&cfg->sections[cfg->num_sections - 1],
26199a2dd95SBruce Richardson split[0], split[1]);
26299a2dd95SBruce Richardson }
26399a2dd95SBruce Richardson }
26499a2dd95SBruce Richardson fclose(f);
26599a2dd95SBruce Richardson return cfg;
26699a2dd95SBruce Richardson error1:
26799a2dd95SBruce Richardson rte_cfgfile_close(cfg);
26899a2dd95SBruce Richardson fclose(f);
26999a2dd95SBruce Richardson return NULL;
27099a2dd95SBruce Richardson }
27199a2dd95SBruce Richardson
27299a2dd95SBruce Richardson struct rte_cfgfile *
rte_cfgfile_create(int flags)27399a2dd95SBruce Richardson rte_cfgfile_create(int flags)
27499a2dd95SBruce Richardson {
27599a2dd95SBruce Richardson int i;
27699a2dd95SBruce Richardson struct rte_cfgfile *cfg;
27799a2dd95SBruce Richardson
27899a2dd95SBruce Richardson /* future proof flags usage */
27999a2dd95SBruce Richardson if (flags & ~(CFG_FLAG_GLOBAL_SECTION | CFG_FLAG_EMPTY_VALUES))
28099a2dd95SBruce Richardson return NULL;
28199a2dd95SBruce Richardson
28299a2dd95SBruce Richardson cfg = malloc(sizeof(*cfg));
28399a2dd95SBruce Richardson
28499a2dd95SBruce Richardson if (cfg == NULL)
28599a2dd95SBruce Richardson return NULL;
28699a2dd95SBruce Richardson
28799a2dd95SBruce Richardson cfg->flags = flags;
28899a2dd95SBruce Richardson cfg->num_sections = 0;
28999a2dd95SBruce Richardson
29099a2dd95SBruce Richardson /* allocate first batch of sections and entries */
29199a2dd95SBruce Richardson cfg->sections = calloc(CFG_ALLOC_SECTION_BATCH,
29299a2dd95SBruce Richardson sizeof(struct rte_cfgfile_section));
29399a2dd95SBruce Richardson if (cfg->sections == NULL)
29499a2dd95SBruce Richardson goto error1;
29599a2dd95SBruce Richardson
29699a2dd95SBruce Richardson cfg->allocated_sections = CFG_ALLOC_SECTION_BATCH;
29799a2dd95SBruce Richardson
29899a2dd95SBruce Richardson for (i = 0; i < CFG_ALLOC_SECTION_BATCH; i++) {
29999a2dd95SBruce Richardson cfg->sections[i].entries = calloc(CFG_ALLOC_ENTRY_BATCH,
30099a2dd95SBruce Richardson sizeof(struct rte_cfgfile_entry));
30199a2dd95SBruce Richardson
30299a2dd95SBruce Richardson if (cfg->sections[i].entries == NULL)
30399a2dd95SBruce Richardson goto error1;
30499a2dd95SBruce Richardson
30599a2dd95SBruce Richardson cfg->sections[i].num_entries = 0;
30699a2dd95SBruce Richardson cfg->sections[i].allocated_entries = CFG_ALLOC_ENTRY_BATCH;
30799a2dd95SBruce Richardson }
30899a2dd95SBruce Richardson
30999a2dd95SBruce Richardson if (flags & CFG_FLAG_GLOBAL_SECTION)
31099a2dd95SBruce Richardson rte_cfgfile_add_section(cfg, "GLOBAL");
31199a2dd95SBruce Richardson
31299a2dd95SBruce Richardson return cfg;
31399a2dd95SBruce Richardson error1:
31499a2dd95SBruce Richardson if (cfg->sections != NULL) {
31599a2dd95SBruce Richardson for (i = 0; i < cfg->allocated_sections; i++) {
31699a2dd95SBruce Richardson if (cfg->sections[i].entries != NULL) {
31799a2dd95SBruce Richardson free(cfg->sections[i].entries);
31899a2dd95SBruce Richardson cfg->sections[i].entries = NULL;
31999a2dd95SBruce Richardson }
32099a2dd95SBruce Richardson }
32199a2dd95SBruce Richardson free(cfg->sections);
32299a2dd95SBruce Richardson cfg->sections = NULL;
32399a2dd95SBruce Richardson }
32499a2dd95SBruce Richardson free(cfg);
32599a2dd95SBruce Richardson return NULL;
32699a2dd95SBruce Richardson }
32799a2dd95SBruce Richardson
32899a2dd95SBruce Richardson int
rte_cfgfile_add_section(struct rte_cfgfile * cfg,const char * sectionname)32999a2dd95SBruce Richardson rte_cfgfile_add_section(struct rte_cfgfile *cfg, const char *sectionname)
33099a2dd95SBruce Richardson {
33199a2dd95SBruce Richardson int i;
33299a2dd95SBruce Richardson
33399a2dd95SBruce Richardson if (cfg == NULL)
33499a2dd95SBruce Richardson return -EINVAL;
33599a2dd95SBruce Richardson
33699a2dd95SBruce Richardson if (sectionname == NULL)
33799a2dd95SBruce Richardson return -EINVAL;
33899a2dd95SBruce Richardson
33999a2dd95SBruce Richardson /* resize overall struct if we don't have room for more sections */
34099a2dd95SBruce Richardson if (cfg->num_sections == cfg->allocated_sections) {
34199a2dd95SBruce Richardson
34299a2dd95SBruce Richardson struct rte_cfgfile_section *n_sections =
34399a2dd95SBruce Richardson realloc(cfg->sections,
34499a2dd95SBruce Richardson sizeof(struct rte_cfgfile_section) *
34599a2dd95SBruce Richardson ((cfg->allocated_sections) +
34699a2dd95SBruce Richardson CFG_ALLOC_SECTION_BATCH));
34799a2dd95SBruce Richardson
34899a2dd95SBruce Richardson if (n_sections == NULL)
34999a2dd95SBruce Richardson return -ENOMEM;
35099a2dd95SBruce Richardson
35199a2dd95SBruce Richardson for (i = 0; i < CFG_ALLOC_SECTION_BATCH; i++) {
35299a2dd95SBruce Richardson n_sections[i + cfg->allocated_sections].num_entries = 0;
35399a2dd95SBruce Richardson n_sections[i +
35499a2dd95SBruce Richardson cfg->allocated_sections].allocated_entries = 0;
35599a2dd95SBruce Richardson n_sections[i + cfg->allocated_sections].entries = NULL;
35699a2dd95SBruce Richardson }
35799a2dd95SBruce Richardson cfg->sections = n_sections;
35899a2dd95SBruce Richardson cfg->allocated_sections += CFG_ALLOC_SECTION_BATCH;
35999a2dd95SBruce Richardson }
36099a2dd95SBruce Richardson
36199a2dd95SBruce Richardson strlcpy(cfg->sections[cfg->num_sections].name, sectionname,
36299a2dd95SBruce Richardson sizeof(cfg->sections[0].name));
36399a2dd95SBruce Richardson cfg->sections[cfg->num_sections].num_entries = 0;
36499a2dd95SBruce Richardson cfg->num_sections++;
36599a2dd95SBruce Richardson
36699a2dd95SBruce Richardson return 0;
36799a2dd95SBruce Richardson }
36899a2dd95SBruce Richardson
rte_cfgfile_add_entry(struct rte_cfgfile * cfg,const char * sectionname,const char * entryname,const char * entryvalue)36999a2dd95SBruce Richardson int rte_cfgfile_add_entry(struct rte_cfgfile *cfg,
37099a2dd95SBruce Richardson const char *sectionname, const char *entryname,
37199a2dd95SBruce Richardson const char *entryvalue)
37299a2dd95SBruce Richardson {
37399a2dd95SBruce Richardson int ret;
37499a2dd95SBruce Richardson
37599a2dd95SBruce Richardson if ((cfg == NULL) || (sectionname == NULL) || (entryname == NULL)
37699a2dd95SBruce Richardson || (entryvalue == NULL))
37799a2dd95SBruce Richardson return -EINVAL;
37899a2dd95SBruce Richardson
37999a2dd95SBruce Richardson if (rte_cfgfile_has_entry(cfg, sectionname, entryname) != 0)
38099a2dd95SBruce Richardson return -EEXIST;
38199a2dd95SBruce Richardson
38299a2dd95SBruce Richardson /* search for section pointer by sectionname */
38399a2dd95SBruce Richardson struct rte_cfgfile_section *curr_section = _get_section(cfg,
38499a2dd95SBruce Richardson sectionname);
38599a2dd95SBruce Richardson if (curr_section == NULL)
38699a2dd95SBruce Richardson return -EINVAL;
38799a2dd95SBruce Richardson
38899a2dd95SBruce Richardson ret = _add_entry(curr_section, entryname, entryvalue);
38999a2dd95SBruce Richardson
39099a2dd95SBruce Richardson return ret;
39199a2dd95SBruce Richardson }
39299a2dd95SBruce Richardson
rte_cfgfile_set_entry(struct rte_cfgfile * cfg,const char * sectionname,const char * entryname,const char * entryvalue)39399a2dd95SBruce Richardson int rte_cfgfile_set_entry(struct rte_cfgfile *cfg, const char *sectionname,
39499a2dd95SBruce Richardson const char *entryname, const char *entryvalue)
39599a2dd95SBruce Richardson {
39699a2dd95SBruce Richardson int i;
39799a2dd95SBruce Richardson
39899a2dd95SBruce Richardson if ((cfg == NULL) || (sectionname == NULL) || (entryname == NULL))
39999a2dd95SBruce Richardson return -EINVAL;
40099a2dd95SBruce Richardson
40199a2dd95SBruce Richardson /* search for section pointer by sectionname */
40299a2dd95SBruce Richardson struct rte_cfgfile_section *curr_section = _get_section(cfg,
40399a2dd95SBruce Richardson sectionname);
40499a2dd95SBruce Richardson if (curr_section == NULL)
40599a2dd95SBruce Richardson return -EINVAL;
40699a2dd95SBruce Richardson
40799a2dd95SBruce Richardson if (entryvalue == NULL)
40899a2dd95SBruce Richardson entryvalue = "";
40999a2dd95SBruce Richardson
41099a2dd95SBruce Richardson for (i = 0; i < curr_section->num_entries; i++)
41199a2dd95SBruce Richardson if (!strcmp(curr_section->entries[i].name, entryname)) {
41299a2dd95SBruce Richardson strlcpy(curr_section->entries[i].value, entryvalue,
41399a2dd95SBruce Richardson sizeof(curr_section->entries[i].value));
41499a2dd95SBruce Richardson return 0;
41599a2dd95SBruce Richardson }
41699a2dd95SBruce Richardson
417ae282b06SDavid Marchand CFG_LOG(ERR, "entry name doesn't exist");
41899a2dd95SBruce Richardson return -EINVAL;
41999a2dd95SBruce Richardson }
42099a2dd95SBruce Richardson
rte_cfgfile_save(struct rte_cfgfile * cfg,const char * filename)42199a2dd95SBruce Richardson int rte_cfgfile_save(struct rte_cfgfile *cfg, const char *filename)
42299a2dd95SBruce Richardson {
42399a2dd95SBruce Richardson int i, j;
42499a2dd95SBruce Richardson
42599a2dd95SBruce Richardson if ((cfg == NULL) || (filename == NULL))
42699a2dd95SBruce Richardson return -EINVAL;
42799a2dd95SBruce Richardson
42899a2dd95SBruce Richardson FILE *f = fopen(filename, "w");
42999a2dd95SBruce Richardson
43099a2dd95SBruce Richardson if (f == NULL)
43199a2dd95SBruce Richardson return -EINVAL;
43299a2dd95SBruce Richardson
43399a2dd95SBruce Richardson for (i = 0; i < cfg->num_sections; i++) {
43499a2dd95SBruce Richardson fprintf(f, "[%s]\n", cfg->sections[i].name);
43599a2dd95SBruce Richardson
43699a2dd95SBruce Richardson for (j = 0; j < cfg->sections[i].num_entries; j++) {
43799a2dd95SBruce Richardson fprintf(f, "%s=%s\n",
43899a2dd95SBruce Richardson cfg->sections[i].entries[j].name,
43999a2dd95SBruce Richardson cfg->sections[i].entries[j].value);
44099a2dd95SBruce Richardson }
44199a2dd95SBruce Richardson }
44299a2dd95SBruce Richardson return fclose(f);
44399a2dd95SBruce Richardson }
44499a2dd95SBruce Richardson
rte_cfgfile_close(struct rte_cfgfile * cfg)44599a2dd95SBruce Richardson int rte_cfgfile_close(struct rte_cfgfile *cfg)
44699a2dd95SBruce Richardson {
44799a2dd95SBruce Richardson int i;
44899a2dd95SBruce Richardson
44999a2dd95SBruce Richardson if (cfg == NULL)
45099a2dd95SBruce Richardson return -1;
45199a2dd95SBruce Richardson
45299a2dd95SBruce Richardson if (cfg->sections != NULL) {
45399a2dd95SBruce Richardson for (i = 0; i < cfg->allocated_sections; i++) {
45499a2dd95SBruce Richardson if (cfg->sections[i].entries != NULL) {
45599a2dd95SBruce Richardson free(cfg->sections[i].entries);
45699a2dd95SBruce Richardson cfg->sections[i].entries = NULL;
45799a2dd95SBruce Richardson }
45899a2dd95SBruce Richardson }
45999a2dd95SBruce Richardson free(cfg->sections);
46099a2dd95SBruce Richardson cfg->sections = NULL;
46199a2dd95SBruce Richardson }
46299a2dd95SBruce Richardson free(cfg);
46399a2dd95SBruce Richardson cfg = NULL;
46499a2dd95SBruce Richardson
46599a2dd95SBruce Richardson return 0;
46699a2dd95SBruce Richardson }
46799a2dd95SBruce Richardson
46899a2dd95SBruce Richardson int
rte_cfgfile_num_sections(struct rte_cfgfile * cfg,const char * sectionname,size_t length)46999a2dd95SBruce Richardson rte_cfgfile_num_sections(struct rte_cfgfile *cfg, const char *sectionname,
47099a2dd95SBruce Richardson size_t length)
47199a2dd95SBruce Richardson {
47299a2dd95SBruce Richardson int i;
47399a2dd95SBruce Richardson int num_sections = 0;
47499a2dd95SBruce Richardson for (i = 0; i < cfg->num_sections; i++) {
47599a2dd95SBruce Richardson if (strncmp(cfg->sections[i].name, sectionname, length) == 0)
47699a2dd95SBruce Richardson num_sections++;
47799a2dd95SBruce Richardson }
47899a2dd95SBruce Richardson return num_sections;
47999a2dd95SBruce Richardson }
48099a2dd95SBruce Richardson
48199a2dd95SBruce Richardson int
rte_cfgfile_sections(struct rte_cfgfile * cfg,char * sections[],int max_sections)48299a2dd95SBruce Richardson rte_cfgfile_sections(struct rte_cfgfile *cfg, char *sections[],
48399a2dd95SBruce Richardson int max_sections)
48499a2dd95SBruce Richardson {
48599a2dd95SBruce Richardson int i;
48699a2dd95SBruce Richardson
48799a2dd95SBruce Richardson for (i = 0; i < cfg->num_sections && i < max_sections; i++)
48899a2dd95SBruce Richardson strlcpy(sections[i], cfg->sections[i].name, CFG_NAME_LEN);
48999a2dd95SBruce Richardson
49099a2dd95SBruce Richardson return i;
49199a2dd95SBruce Richardson }
49299a2dd95SBruce Richardson
49399a2dd95SBruce Richardson int
rte_cfgfile_has_section(struct rte_cfgfile * cfg,const char * sectionname)49499a2dd95SBruce Richardson rte_cfgfile_has_section(struct rte_cfgfile *cfg, const char *sectionname)
49599a2dd95SBruce Richardson {
49699a2dd95SBruce Richardson return _get_section(cfg, sectionname) != NULL;
49799a2dd95SBruce Richardson }
49899a2dd95SBruce Richardson
49999a2dd95SBruce Richardson int
rte_cfgfile_section_num_entries(struct rte_cfgfile * cfg,const char * sectionname)50099a2dd95SBruce Richardson rte_cfgfile_section_num_entries(struct rte_cfgfile *cfg,
50199a2dd95SBruce Richardson const char *sectionname)
50299a2dd95SBruce Richardson {
50399a2dd95SBruce Richardson const struct rte_cfgfile_section *s = _get_section(cfg, sectionname);
50499a2dd95SBruce Richardson if (s == NULL)
50599a2dd95SBruce Richardson return -1;
50699a2dd95SBruce Richardson return s->num_entries;
50799a2dd95SBruce Richardson }
50899a2dd95SBruce Richardson
50999a2dd95SBruce Richardson int
rte_cfgfile_section_num_entries_by_index(struct rte_cfgfile * cfg,char * sectionname,int index)51099a2dd95SBruce Richardson rte_cfgfile_section_num_entries_by_index(struct rte_cfgfile *cfg,
51199a2dd95SBruce Richardson char *sectionname, int index)
51299a2dd95SBruce Richardson {
51399a2dd95SBruce Richardson if (index < 0 || index >= cfg->num_sections)
51499a2dd95SBruce Richardson return -1;
51599a2dd95SBruce Richardson
51699a2dd95SBruce Richardson const struct rte_cfgfile_section *sect = &(cfg->sections[index]);
51799a2dd95SBruce Richardson
51899a2dd95SBruce Richardson strlcpy(sectionname, sect->name, CFG_NAME_LEN);
51999a2dd95SBruce Richardson return sect->num_entries;
52099a2dd95SBruce Richardson }
52199a2dd95SBruce Richardson int
rte_cfgfile_section_entries(struct rte_cfgfile * cfg,const char * sectionname,struct rte_cfgfile_entry * entries,int max_entries)52299a2dd95SBruce Richardson rte_cfgfile_section_entries(struct rte_cfgfile *cfg, const char *sectionname,
52399a2dd95SBruce Richardson struct rte_cfgfile_entry *entries, int max_entries)
52499a2dd95SBruce Richardson {
52599a2dd95SBruce Richardson int i;
52699a2dd95SBruce Richardson const struct rte_cfgfile_section *sect = _get_section(cfg, sectionname);
52799a2dd95SBruce Richardson if (sect == NULL)
52899a2dd95SBruce Richardson return -1;
52999a2dd95SBruce Richardson for (i = 0; i < max_entries && i < sect->num_entries; i++)
53099a2dd95SBruce Richardson entries[i] = sect->entries[i];
53199a2dd95SBruce Richardson return i;
53299a2dd95SBruce Richardson }
53399a2dd95SBruce Richardson
53499a2dd95SBruce Richardson int
rte_cfgfile_section_entries_by_index(struct rte_cfgfile * cfg,int index,char * sectionname,struct rte_cfgfile_entry * entries,int max_entries)53599a2dd95SBruce Richardson rte_cfgfile_section_entries_by_index(struct rte_cfgfile *cfg, int index,
53699a2dd95SBruce Richardson char *sectionname,
53799a2dd95SBruce Richardson struct rte_cfgfile_entry *entries, int max_entries)
53899a2dd95SBruce Richardson {
53999a2dd95SBruce Richardson int i;
54099a2dd95SBruce Richardson const struct rte_cfgfile_section *sect;
54199a2dd95SBruce Richardson
54299a2dd95SBruce Richardson if (index < 0 || index >= cfg->num_sections)
54399a2dd95SBruce Richardson return -1;
54499a2dd95SBruce Richardson sect = &cfg->sections[index];
54599a2dd95SBruce Richardson strlcpy(sectionname, sect->name, CFG_NAME_LEN);
54699a2dd95SBruce Richardson for (i = 0; i < max_entries && i < sect->num_entries; i++)
54799a2dd95SBruce Richardson entries[i] = sect->entries[i];
54899a2dd95SBruce Richardson return i;
54999a2dd95SBruce Richardson }
55099a2dd95SBruce Richardson
55199a2dd95SBruce Richardson const char *
rte_cfgfile_get_entry(struct rte_cfgfile * cfg,const char * sectionname,const char * entryname)55299a2dd95SBruce Richardson rte_cfgfile_get_entry(struct rte_cfgfile *cfg, const char *sectionname,
55399a2dd95SBruce Richardson const char *entryname)
55499a2dd95SBruce Richardson {
55599a2dd95SBruce Richardson int i;
55699a2dd95SBruce Richardson const struct rte_cfgfile_section *sect = _get_section(cfg, sectionname);
55799a2dd95SBruce Richardson if (sect == NULL)
55899a2dd95SBruce Richardson return NULL;
55999a2dd95SBruce Richardson for (i = 0; i < sect->num_entries; i++)
56099a2dd95SBruce Richardson if (strncmp(sect->entries[i].name, entryname, CFG_NAME_LEN)
56199a2dd95SBruce Richardson == 0)
56299a2dd95SBruce Richardson return sect->entries[i].value;
56399a2dd95SBruce Richardson return NULL;
56499a2dd95SBruce Richardson }
56599a2dd95SBruce Richardson
56699a2dd95SBruce Richardson int
rte_cfgfile_has_entry(struct rte_cfgfile * cfg,const char * sectionname,const char * entryname)56799a2dd95SBruce Richardson rte_cfgfile_has_entry(struct rte_cfgfile *cfg, const char *sectionname,
56899a2dd95SBruce Richardson const char *entryname)
56999a2dd95SBruce Richardson {
57099a2dd95SBruce Richardson return rte_cfgfile_get_entry(cfg, sectionname, entryname) != NULL;
57199a2dd95SBruce Richardson }
572