xref: /dpdk/lib/cfgfile/rte_cfgfile.c (revision 0f1dc8cb671203d52488fd66936f2fe6dcca03cc)
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 					&section->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