All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jacek Piasecki <jacekx.piasecki@intel.com>
To: dev@dpdk.org
Cc: bruce.richardson@intel.com, deepak.k.jain@intel.com,
	Jacek Piasecki <jacekx.piasecki@intel.com>
Subject: [PATCH v2 2/7] cfgfile: add new functions to API
Date: Mon, 26 Jun 2017 12:59:14 +0200	[thread overview]
Message-ID: <1498474759-102089-3-git-send-email-jacekx.piasecki@intel.com> (raw)
In-Reply-To: <1498474759-102089-1-git-send-email-jacekx.piasecki@intel.com>

Extend existing cfgfile library with providing new API functions:

rte_cfgfile_create() - create new cfgfile object
rte_cfgfile_add_section() - add new section to existing cfgfile
object
rte_cfgfile_add_entry() - add new entry to existing cfgfile
object in specified section
rte_cfgfile_set_entry() - update existing entry in cfgfile object
rte_cfgfile_save() - save existing cfgfile object to INI file

This modification allows to create a cfgfile on
runtime and opens up the possibility to have applications
dynamically build up a proper DPDK configuration, rather than having
to have a pre-existing one.

Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com>
---
 lib/librte_cfgfile/rte_cfgfile.c           | 249 +++++++++++++++++++++++++++--
 lib/librte_cfgfile/rte_cfgfile.h           |  76 +++++++++
 lib/librte_cfgfile/rte_cfgfile_version.map |  11 ++
 3 files changed, 323 insertions(+), 13 deletions(-)

diff --git a/lib/librte_cfgfile/rte_cfgfile.c b/lib/librte_cfgfile/rte_cfgfile.c
index c6ae3e3..518b6ab 100644
--- a/lib/librte_cfgfile/rte_cfgfile.c
+++ b/lib/librte_cfgfile/rte_cfgfile.c
@@ -35,6 +35,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
+#include <errno.h>
 #include <rte_common.h>
 
 #include "rte_cfgfile.h"
@@ -42,13 +43,17 @@
 struct rte_cfgfile_section {
 	char name[CFG_NAME_LEN];
 	int num_entries;
-	struct rte_cfgfile_entry *entries[0];
+	int free_entries;
+	int allocated_entries;
+	struct rte_cfgfile_entry **entries;
 };
 
 struct rte_cfgfile {
 	int flags;
 	int num_sections;
-	struct rte_cfgfile_section *sections[0];
+	int free_sections;
+	int allocated_sections;
+	struct rte_cfgfile_section **sections;
 };
 
 /** when we resize a file structure, how many extra entries
@@ -104,6 +109,65 @@ _strip(char *str, unsigned len)
 	return newlen;
 }
 
+static struct rte_cfgfile_section *
+_get_section(struct rte_cfgfile *cfg, const char *sectionname)
+{
+	int i;
+
+	for (i = 0; i < cfg->num_sections; i++) {
+		if (strncmp(cfg->sections[i]->name, sectionname,
+				sizeof(cfg->sections[0]->name)) == 0)
+			return cfg->sections[i];
+	}
+	return NULL;
+}
+
+static int
+_add_entry(struct rte_cfgfile_section *section, const char *entryname,
+		const char *entryvalue)
+{
+	int i;
+
+	/* resize entry structure if we don't have room for more entries */
+	if (section->free_entries == 0) {
+
+		struct rte_cfgfile_entry **n_entries =
+				realloc(section->entries,
+				sizeof(section->entries[0]) *
+				((section->allocated_entries) +
+						CFG_ALLOC_ENTRY_BATCH));
+
+		if (n_entries == NULL)
+			return -ENOMEM;
+
+		section->entries = n_entries;
+
+		for (i = section->allocated_entries;
+				i < (section->allocated_entries) +
+						CFG_ALLOC_ENTRY_BATCH; i++) {
+			section->entries[i] =
+				malloc(sizeof(struct rte_cfgfile_entry));
+
+			if (section->entries[i] == NULL)
+				return -ENOMEM;
+		}
+		section->allocated_entries += CFG_ALLOC_ENTRY_BATCH;
+		section->free_entries += CFG_ALLOC_ENTRY_BATCH;
+	}
+
+	/* fill up entry fields with key name and value */
+	struct rte_cfgfile_entry *curr_entry =
+			section->entries[section->num_entries];
+
+	snprintf(curr_entry->name, sizeof(curr_entry->name), "%s", entryname);
+	snprintf(curr_entry->value, sizeof(curr_entry->value), "%s",
+								entryvalue);
+	section->num_entries++;
+	section->free_entries--;
+
+	return 0;
+}
+
 static int
 rte_cfgfile_check_params(const struct rte_cfgfile_parameters *params)
 {
@@ -332,6 +396,176 @@ rte_cfgfile_load_with_params(const char *filename, int flags,
 	return NULL;
 }
 
+struct rte_cfgfile *
+rte_cfgfile_create(int flags)
+{
+	int i, j;
+	struct rte_cfgfile *cfg = NULL;
+
+	cfg = malloc(sizeof(*cfg));
+	if (cfg == NULL)
+		return NULL;
+
+	memset(cfg, 0, sizeof((*cfg)));
+
+	cfg->flags = flags;
+
+	/* allocate first batch of sections and entries */
+	cfg->sections = malloc(sizeof(cfg->sections[0]) *
+						CFG_ALLOC_SECTION_BATCH);
+	if (cfg->sections == NULL)
+		return NULL;
+
+	for (i = 0; i < CFG_ALLOC_SECTION_BATCH; i++) {
+		cfg->sections[i] = malloc(sizeof(struct rte_cfgfile_section));
+		if (cfg->sections[i] == NULL)
+			return NULL;
+
+		memset(cfg->sections[i], 0,
+					sizeof(struct rte_cfgfile_section));
+
+		cfg->sections[i]->entries =
+				malloc(sizeof(cfg->sections[i]->entries[0])
+						* CFG_ALLOC_ENTRY_BATCH);
+		if (cfg->sections[i]->entries == NULL)
+			return NULL;
+
+		for (j = 0; j < CFG_ALLOC_ENTRY_BATCH; j++) {
+			cfg->sections[i]->entries[j] = malloc(sizeof(struct
+							rte_cfgfile_entry));
+			if (cfg->sections[i]->entries[j] == NULL)
+				return NULL;
+		}
+		cfg->sections[i]->allocated_entries = CFG_ALLOC_ENTRY_BATCH;
+		cfg->sections[i]->free_entries = CFG_ALLOC_ENTRY_BATCH;
+	}
+	cfg->allocated_sections = CFG_ALLOC_SECTION_BATCH;
+	cfg->free_sections = CFG_ALLOC_SECTION_BATCH;
+
+	if (flags & CFG_FLAG_GLOBAL_SECTION)
+		rte_cfgfile_add_section(cfg, "GLOBAL");
+	return cfg;
+}
+
+int
+rte_cfgfile_add_section(struct rte_cfgfile *cfg, const char *sectionname)
+{
+	int i;
+	/* resize overall struct if we don't have room for more	sections */
+	if (cfg->free_sections == 0) {
+
+		struct rte_cfgfile_section **n_sections =
+				realloc(cfg->sections,
+				sizeof(cfg->sections[0]) *
+				((cfg->allocated_sections) +
+						CFG_ALLOC_SECTION_BATCH));
+
+		if (n_sections == NULL)
+			return -ENOMEM;
+
+		cfg->sections = n_sections;
+
+		for (i = cfg->allocated_sections;
+				i < (cfg->allocated_sections) +
+						CFG_ALLOC_SECTION_BATCH; i++) {
+			cfg->sections[i] =
+				malloc(sizeof(struct rte_cfgfile_section));
+
+			if (cfg->sections[i] == NULL)
+				return -ENOMEM;
+
+			memset(cfg->sections[i], 0,
+					sizeof(struct rte_cfgfile_section));
+		}
+		cfg->allocated_sections += CFG_ALLOC_SECTION_BATCH;
+		cfg->free_sections += CFG_ALLOC_SECTION_BATCH;
+	}
+
+	snprintf(cfg->sections[cfg->num_sections]->name,
+			sizeof(cfg->sections[0]->name), "%s", sectionname);
+	cfg->sections[cfg->num_sections]->num_entries = 0;
+
+	cfg->num_sections++;
+	cfg->free_sections--;
+
+	return 0;
+}
+
+int rte_cfgfile_add_entry(struct rte_cfgfile *cfg,
+		const char *sectionname, const char *entryname,
+		const char *entryvalue)
+{
+	int ret;
+
+	if (cfg == NULL)
+		return -EINVAL;
+
+	if (rte_cfgfile_has_entry(cfg, sectionname, entryname) != 0)
+		return -EEXIST;
+
+	/* search for section pointer by sectionname */
+	struct rte_cfgfile_section *curr_section = _get_section(cfg,
+								sectionname);
+	if (curr_section == NULL)
+		return -EINVAL;
+
+	ret = _add_entry(curr_section, entryname, entryvalue);
+
+	return ret;
+}
+
+int rte_cfgfile_set_entry(struct rte_cfgfile *cfg, const char *sectionname,
+		const char *entryname, const char *entryvalue)
+{
+	int i;
+
+	if (cfg == NULL)
+		return -EINVAL;
+
+	/* search for section pointer by sectionname */
+	struct rte_cfgfile_section *curr_section = _get_section(cfg,
+								sectionname);
+	if (curr_section == NULL)
+		return -EINVAL;
+
+	if (entryvalue == NULL)
+		entryvalue = "";
+
+	for (i = 0; i < curr_section->num_entries; i++)
+		if (!strcmp(curr_section->entries[i]->name, entryname)) {
+			strcpy(curr_section->entries[i]->value, entryvalue);
+			return 0;
+		}
+	return -1;
+}
+
+int rte_cfgfile_save(struct rte_cfgfile *cfg, const char *filename)
+{
+	char buffer[CFG_NAME_LEN + CFG_VALUE_LEN + 4] = {0};
+	int i, j;
+
+	if ((cfg == NULL) || (filename == NULL))
+		return -EINVAL;
+
+	FILE *f = fopen(filename, "w");
+
+	if (f == NULL)
+		return -EINVAL;
+
+	for (i = 0; i < cfg->num_sections; i++) {
+		snprintf(buffer, sizeof(buffer), "[%s]\n",
+					cfg->sections[i]->name);
+		fputs(buffer, f);
+
+		for (j = 0; j < cfg->sections[i]->num_entries; j++) {
+			snprintf(buffer, sizeof(buffer), "%s=%s\n",
+				cfg->sections[i]->entries[j]->name,
+				cfg->sections[i]->entries[j]->value);
+			fputs(buffer, f);
+		}
+	}
+	return fclose(f);
+}
 
 int rte_cfgfile_close(struct rte_cfgfile *cfg)
 {
@@ -385,17 +619,6 @@ rte_cfgfile_sections(struct rte_cfgfile *cfg, char *sections[],
 	return i;
 }
 
-static const struct rte_cfgfile_section *
-_get_section(struct rte_cfgfile *cfg, const char *sectionname)
-{
-	int i;
-	for (i = 0; i < cfg->num_sections; i++) {
-		if (strncmp(cfg->sections[i]->name, sectionname,
-				sizeof(cfg->sections[0]->name)) == 0)
-			return cfg->sections[i];
-	}
-	return NULL;
-}
 
 int
 rte_cfgfile_has_section(struct rte_cfgfile *cfg, const char *sectionname)
diff --git a/lib/librte_cfgfile/rte_cfgfile.h b/lib/librte_cfgfile/rte_cfgfile.h
index fa10d40..6245c7e 100644
--- a/lib/librte_cfgfile/rte_cfgfile.h
+++ b/lib/librte_cfgfile/rte_cfgfile.h
@@ -121,6 +121,82 @@ struct rte_cfgfile *rte_cfgfile_load_with_params(const char *filename,
 	int flags, const struct rte_cfgfile_parameters *params);
 
 /**
+ * Create new cfgfile instance with empty sections and entries
+ *
+ * @param flags
+ *   - CFG_FLAG_GLOBAL_SECTION
+ *     Indicates that the file supports key value entries before the first
+ *     defined section.  These entries can be accessed in the "GLOBAL"
+ *     section.
+ *   - CFG_FLAG_EMPTY_VALUES
+ *     Indicates that file supports key value entries where the value can
+ *     be zero length (e.g., "key=").
+ * @return
+ *   Handle to cfgfile instance on success, NULL otherwise
+ */
+struct rte_cfgfile *rte_cfgfile_create(int flags);
+
+/**
+ * Add section in cfgfile instance.
+ *
+ * @param cfg
+ *   Pointer to the cfgfile structure.
+ * @param sectionname
+ *   Section name which will be add to cfgfile.
+ * @return
+ *   0 on success, -ENOMEM if can't add section
+ */
+int
+rte_cfgfile_add_section(struct rte_cfgfile *cfg, const char *sectionname);
+
+/**
+ * Add entry to specified section in cfgfile instance.
+ *
+ * @param cfg
+ *   Pointer to the cfgfile structure.
+ * @param sectionname
+ *   Given section name to add an entry.
+ * @param entryname
+ *   Entry name to add.
+ * @entryvalue
+ *   Entry value to add.
+ * @return
+ *   0 on success, -EEXIST if entry already exist, -EINVAL if bad argument
+ */
+int rte_cfgfile_add_entry(struct rte_cfgfile *cfg,
+		const char *sectionname, const char *entryname,
+		const char *entryvalue);
+
+/**
+ * Update value of specified entry name in given section in config file
+ *
+ * @param cfg
+ *   Config file
+ * @param sectionname
+ *   Section name
+ * @param entryname
+ *   Entry name to look for the value change
+ * @param entryvalue
+ *   New entry value. Can be also an empty string if CFG_FLAG_EMPTY_VALUES = 1
+ * @return
+ *   0 on success, -EINVAL if bad argument
+ */
+int rte_cfgfile_set_entry(struct rte_cfgfile *cfg, const char *sectionname,
+		const char *entryname, const char *entryvalue);
+
+/**
+ * Save object cfgfile to file on disc
+ *
+ * @param cfg
+ *   Config file structure
+ * @param filename
+ *   File name to save data
+ * @return
+ *   0 on success, errno otherwise
+ */
+int rte_cfgfile_save(struct rte_cfgfile *cfg, const char *filename);
+
+/**
 * Get number of sections in config file
 *
 * @param cfg
diff --git a/lib/librte_cfgfile/rte_cfgfile_version.map b/lib/librte_cfgfile/rte_cfgfile_version.map
index 5fe60f7..de68ff6 100644
--- a/lib/librte_cfgfile/rte_cfgfile_version.map
+++ b/lib/librte_cfgfile/rte_cfgfile_version.map
@@ -27,3 +27,14 @@ DPDK_17.05 {
     rte_cfgfile_load_with_params;
 
 } DPDK_16.04;
+
+DPDK_17.08 {
+	global:
+
+	rte_cfgfile_add_entry;
+	rte_cfgfile_add_section;
+	rte_cfgfile_create;
+	rte_cfgfile_save;
+	rte_cfgfile_set_entry;
+
+} DPDK_17.05;
\ No newline at end of file
-- 
2.7.4

  parent reply	other threads:[~2017-06-26 11:17 UTC|newest]

Thread overview: 70+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-05-30  8:30 [PATCH 0/3] Add support for using a config file for DPDK Jacek Piasecki
2017-05-30  8:30 ` [PATCH 1/3] cfgfile: add new API functions Jacek Piasecki
2017-05-31 14:20   ` Bruce Richardson
2017-05-31 14:22     ` Bruce Richardson
2017-06-26 10:59   ` [PATCH v2 0/7] Add support for using a config file for DPDK Jacek Piasecki
2017-06-26 10:59     ` [PATCH v2 1/7] cfgfile: remove EAL dependency Jacek Piasecki
2017-06-26 13:12       ` Dumitrescu, Cristian
2017-06-27 10:26       ` [PATCH v3 0/4] Rework cfgfile API to enable apps config file support Jacek Piasecki
2017-06-27 10:26         ` [PATCH v3 1/4] cfgfile: remove EAL dependency Jacek Piasecki
2017-06-30  9:44           ` Bruce Richardson
2017-06-30 11:16             ` Bruce Richardson
2017-06-27 10:26         ` [PATCH v3 2/4] cfgfile: add new functions to API Jacek Piasecki
2017-06-30  9:55           ` Bruce Richardson
2017-06-30 10:28           ` Bruce Richardson
2017-06-27 10:26         ` [PATCH v3 3/4] cfgfile: rework of load function Jacek Piasecki
2017-06-30 11:18           ` Bruce Richardson
2017-06-27 10:26         ` [PATCH v3 4/4] test/cfgfile: add new unit test Jacek Piasecki
2017-06-30 11:20         ` [PATCH v3 0/4] Rework cfgfile API to enable apps config file support Bruce Richardson
2017-06-26 10:59     ` Jacek Piasecki [this message]
2017-06-26 10:59     ` [PATCH v2 3/7] cfgfile: rework of load function Jacek Piasecki
2017-06-26 10:59     ` [PATCH v2 4/7] test/cfgfile: add new unit test Jacek Piasecki
2017-06-26 10:59     ` [PATCH v2 5/7] eal: add functions parsing EAL arguments Jacek Piasecki
2017-06-27 10:52       ` [PATCH v3 0/3] EAL change for using a config file for DPDK Jacek Piasecki
2017-06-27 10:52         ` [PATCH v3 1/3] eal: add functions parsing EAL arguments Jacek Piasecki
2017-06-30 16:04           ` Bruce Richardson
2017-07-10 12:44           ` [PATCH v4 0/5] Rework cfgfile API to enable apps config file support Jacek Piasecki
2017-07-10 12:44             ` [PATCH v4 1/5] cfgfile: remove EAL dependency Jacek Piasecki
2017-08-30 17:58               ` Bruce Richardson
2017-07-10 12:44             ` [PATCH v4 2/5] cfgfile: change existing API functions Jacek Piasecki
2017-08-30 20:07               ` Bruce Richardson
2017-07-10 12:44             ` [PATCH v4 3/5] cfgfile: add new functions to API Jacek Piasecki
2017-08-30 20:18               ` Bruce Richardson
2017-07-10 12:44             ` [PATCH v4 4/5] cfgfile: rework of load function Jacek Piasecki
2017-08-30 20:24               ` Bruce Richardson
2017-07-10 12:44             ` [PATCH v4 5/5] test/cfgfile: add new unit test Jacek Piasecki
2017-08-30 20:25               ` Bruce Richardson
2017-09-04  9:21                 ` Bruce Richardson
2017-09-04  9:30               ` Bruce Richardson
2017-09-15 13:56                 ` Thomas Monjalon
2017-09-18 13:49                   ` Jastrzebski, MichalX K
2017-07-10 15:13             ` [PATCH v4 0/5] Rework cfgfile API to enable apps config file support Thomas Monjalon
2017-07-20 21:48               ` Thomas Monjalon
2017-07-10 12:51           ` [PATCH v4 0/3] EAL change for using a config file for DPDK Kuba Kozak
2017-07-10 12:51             ` [PATCH v4 1/3] eal: add functions parsing EAL arguments Kuba Kozak
2017-07-13  9:26               ` [PATCH v5 0/3] EAL change for using a config file for DPDK Kuba Kozak
2017-07-13 10:07               ` Kuba Kozak
2017-07-13 10:07                 ` [PATCH v5 1/3] eal: add functions parsing EAL arguments Kuba Kozak
2017-07-13 10:07                 ` [PATCH v5 2/3] app/testpmd: add parse options from cfg file Kuba Kozak
2017-07-13 10:07                 ` [PATCH v5 3/3] app/testpmd: add parse options from JSON " Kuba Kozak
2019-01-23 19:31                 ` [PATCH v5 0/3] EAL change for using a config file for DPDK Ferruh Yigit
2019-01-23 20:26                   ` Thomas Monjalon
2019-01-24 13:54                     ` Ferruh Yigit
2019-01-24 14:32                       ` Thomas Monjalon
2019-01-24 14:46                         ` Ferruh Yigit
2019-01-24 16:06                           ` Thomas Monjalon
2019-01-24 16:18                             ` Ferruh Yigit
2019-01-24 17:45                               ` Thomas Monjalon
2019-01-28 14:43                                 ` Ferruh Yigit
2017-07-10 12:51             ` [PATCH v4 2/3] app/testpmd: add parse options from cfg file Kuba Kozak
2017-07-10 12:51             ` [PATCH v4 3/3] app/testpmd: add parse options from JSON " Kuba Kozak
2017-06-27 10:52         ` [PATCH v3 2/3] app/testpmd: changed example to parse options from " Jacek Piasecki
2017-06-27 10:52         ` [PATCH v3 3/3] app/testpmd: add parse arguments from JSON config file Jacek Piasecki
2017-07-05  0:00         ` [PATCH v3 0/3] EAL change for using a config file for DPDK Thomas Monjalon
2017-06-26 10:59     ` [PATCH v2 6/7] app/testpmd: changed example to parse options from cfg file Jacek Piasecki
2017-06-26 10:59     ` [PATCH v2 7/7] app/testpmd: add parse arguments from JSON config file Jacek Piasecki
2017-05-30  8:30 ` [PATCH 2/3] eal: add functions parsing EAL arguments Jacek Piasecki
2017-05-31 15:46   ` Bruce Richardson
2017-05-30  8:30 ` [PATCH 3/3] app/testpmd: changed example to parse options from cfg file Jacek Piasecki
2017-06-20  2:13   ` Wu, Jingjing
2017-06-20 10:10     ` Kozak, KubaX

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1498474759-102089-3-git-send-email-jacekx.piasecki@intel.com \
    --to=jacekx.piasecki@intel.com \
    --cc=bruce.richardson@intel.com \
    --cc=deepak.k.jain@intel.com \
    --cc=dev@dpdk.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.