From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by dpdk.org (Postfix) with ESMTP id E5000C4CE for ; Wed, 17 Jun 2015 17:14:28 +0200 (CEST) Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga102.fm.intel.com with ESMTP; 17 Jun 2015 08:14:28 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.13,633,1427785200"; d="scan'208";a="748401747" Received: from unknown (HELO stargo) ([10.217.248.233]) by orsmga002.jf.intel.com with SMTP; 17 Jun 2015 08:14:26 -0700 Received: by stargo (sSMTP sendmail emulation); Wed, 17 Jun 2015 17:10:56 +0200 From: Maciej Gajdzica To: dev@dpdk.org Date: Wed, 17 Jun 2015 16:48:48 +0200 Message-Id: <1434552528-3576-7-git-send-email-maciejx.t.gajdzica@intel.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1434552528-3576-1-git-send-email-maciejx.t.gajdzica@intel.com> References: <1434552528-3576-1-git-send-email-maciejx.t.gajdzica@intel.com> Subject: [dpdk-dev] [PATCH v2 6/6] cfgfile: added new implementation of section parsing X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 17 Jun 2015 15:14:30 -0000 From: Pawel Wodkowski New implementation of section parsing changes the way section allocation is made. It protects against multiple sections with the same name and multiple entries in section with the same name. It also drop constraint on value length limited to 64 bytes. Now its size is unlimited. New features are part of bigger modification and they are hard to be split to several smaller patches. Signed-off-by: Pawel Wodkowski --- lib/librte_cfgfile/Makefile | 2 +- lib/librte_cfgfile/rte_cfgfile.c | 550 +++++++++++++++++++--------- lib/librte_cfgfile/rte_cfgfile.h | 31 +- lib/librte_cfgfile/rte_cfgfile_version.map | 8 + 4 files changed, 416 insertions(+), 175 deletions(-) diff --git a/lib/librte_cfgfile/Makefile b/lib/librte_cfgfile/Makefile index 032c240..616aef0 100644 --- a/lib/librte_cfgfile/Makefile +++ b/lib/librte_cfgfile/Makefile @@ -41,7 +41,7 @@ CFLAGS += $(WERROR_FLAGS) EXPORT_MAP := rte_cfgfile_version.map -LIBABIVER := 1 +LIBABIVER := 2 # # all source are stored in SRCS-y diff --git a/lib/librte_cfgfile/rte_cfgfile.c b/lib/librte_cfgfile/rte_cfgfile.c index 2ce5d70..a5867be 100644 --- a/lib/librte_cfgfile/rte_cfgfile.c +++ b/lib/librte_cfgfile/rte_cfgfile.c @@ -1,7 +1,7 @@ /*- * BSD LICENSE * - * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * Copyright(c) 2010-2015 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,22 +35,26 @@ #include #include #include -#include +#include +#include #include +#include #include "rte_cfgfile.h" struct rte_cfgfile_section { char name[CFG_NAME_LEN]; size_t num_entries; - struct rte_cfgfile_entry *entries[0]; + size_t allocated_entries; + struct rte_cfgfile_entry2 **entries; }; struct rte_cfgfile { int flags; size_t num_sections; - struct rte_cfgfile_section *sections[0]; + size_t allocated_sections; + struct rte_cfgfile_section **sections; }; /** when we resize a file structure, how many extra entries @@ -69,30 +73,47 @@ struct rte_cfgfile { p; \ }) -static unsigned -_strip(char *str, unsigned len) +static size_t +strip_leading_spaces(char *str, size_t len) { - int newlen = len; - if (len == 0) + char *start = _skip_spaceses(str); + + if (*start == '\0') { + str[0] = '\0'; return 0; + } else if (start == str) + return len; - if (isspace(str[len-1])) { - /* strip trailing whitespace */ - while (newlen > 0 && isspace(str[newlen - 1])) - str[--newlen] = '\0'; - } + len -= start - str; + memmove(str, start, len); + str[len] = '\0'; - if (isspace(str[0])) { - /* strip leading whitespace */ - int i, start = 1; - while (isspace(str[start]) && start < newlen) - start++ - ; /* do nothing */ - newlen -= start; - for (i = 0; i < newlen; i++) - str[i] = str[i+start]; - str[i] = '\0'; - } + return len; +} + +static size_t +strip_trailing_spaces(char *str, size_t len) +{ + size_t newlen = len; + + /* strip trailing whitespace */ + while (newlen > 0 && isspace(str[newlen - 1])) + str[--newlen] = '\0'; + + return newlen; +} + +static size_t +strip_white_spaces(char *str, size_t len) +{ + size_t newlen; + + if (len == 0) + return 0; + + /* strip trailing whitespace */ + newlen = strip_trailing_spaces(str, len); + newlen = strip_leading_spaces(str, len); return newlen; } @@ -241,6 +262,227 @@ error_exit: return status; } +/* Section functions */ + +static struct rte_cfgfile_section * +rte_cfgfile_find_section(struct rte_cfgfile *cfg, const char *sectionname) +{ + size_t i; + struct rte_cfgfile_section *sect; + + for (i = 0; i < cfg->num_sections; i++) { + sect = cfg->sections[i]; + if (strncmp(sect->name, sectionname, sizeof(sect->name)) == 0) + return sect; + } + + return NULL; +} + +static int +rte_cfgfile_create_section(struct rte_cfgfile_section **section, + const char *name) +{ + struct rte_cfgfile_section *s = NULL; + size_t name_len; + + if (name == NULL || section == NULL) + return -EINVAL; + + name_len = strlen(name); + + if (name_len == 0 || name_len >= sizeof(s->name) - 1) { + printf("Empty or too long section name\n"); + return -EINVAL; + } + + /* Create new section */ + s = malloc(sizeof(struct rte_cfgfile_section)); + if (s == NULL) + return -ENOMEM; + + memcpy(s->name, name, name_len); + s->name[name_len] = '\0'; + s->allocated_entries = 0; + s->num_entries = 0; + s->entries = NULL; + + *section = s; + return 0; +} + +static int +rte_cfgfile_add_section(struct rte_cfgfile *cfg, + struct rte_cfgfile_section *new_section) +{ + struct rte_cfgfile_section *s; + + if (cfg == NULL || new_section == NULL) + return -EINVAL; + + s = rte_cfgfile_find_section(cfg, new_section->name); + if (s != NULL) { + printf("Duplicate section '%s'\n", new_section->name); + return -EEXIST; + } + + if (cfg->num_sections == cfg->allocated_sections) { + size_t new_count = cfg->allocated_sections + CFG_ALLOC_SECTION_BATCH; + struct rte_cfgfile_section **entries = realloc(cfg->sections, + sizeof(struct rte_cfgfile_section *) * new_count); + + if (entries == NULL) + return -ENOMEM; + + cfg->allocated_sections = new_count; + cfg->sections = entries; + } + + cfg->sections[cfg->num_sections] = new_section; + cfg->num_sections++; + return 0; +} + +static int +rte_cfgfile_parse_section(struct rte_cfgfile_section **s, const char *buffer) +{ + const char *start, *end, *garbage; + struct rte_cfgfile_section *new_section = NULL; + char name[CFG_NAME_LEN]; + int status; + size_t name_len; + + /* Check input arguments and buffer if it contain section */ + if (s == NULL || buffer == NULL) + return -EINVAL; + + /* Find start and end of name */ + start = _skip_spaceses(buffer); + if (*start != '[') + return -EINVAL; + + start = _skip_spaceses(start + 1); + end = strchr(start, ']'); + if (end == NULL) { + printf("No section name delimiter ']' encoutered\n"); + return -EINVAL; + } + + garbage = _skip_spaceses(end + 1); + if (*garbage != '\0') { + printf("Garbage after section '%s' definition: %s\n", + buffer, garbage); + return -EINVAL; + } + + /* Check if name is proper size */ + if (start != end) { + for (end--; start != end; end--) + if (!isspace(*end)) + break; + end++; + } + + name_len = end - start; + if (name_len == 1 || name_len >= sizeof(new_section->name) - 1) { + printf("Empty or too long section name\n"); + return -EINVAL; + } + + memcpy(name, start, name_len); + name[name_len] = '\0'; + + status = rte_cfgfile_create_section(&new_section, name); + if (status != 0) + return status; + + *s = new_section; + return 0; +} + +/* Section entry functions */ + +static inline struct rte_cfgfile_entry2 * +rte_cfgfile_find_entry(struct rte_cfgfile_section *sect, const char *entryname) +{ + struct rte_cfgfile_entry2 *ret = NULL; + size_t i; + + for (i = 0; i < sect->num_entries; i++) { + if (strcmp(sect->entries[i]->name, entryname) == 0) { + ret = sect->entries[i]; + break; + } + } + + return ret; +} + +static int +rte_cfgfile_section_add_entry(struct rte_cfgfile_section *section, + const char *name, const char *value) +{ + struct rte_cfgfile_entry2 *entry = NULL; + int status = 0; + size_t name_length, value_length; + + if (section == NULL) { + status = -EINVAL; + goto error_exit; + } + + entry = rte_cfgfile_find_entry(section, name); + if (entry != NULL) { + status = -EEXIST; + goto error_exit; + } + + entry = malloc(sizeof(struct rte_cfgfile_entry2)); + if (entry == NULL) { + status = ENOMEM; + goto error_exit; + } + + name_length = snprintf(entry->name, sizeof(entry->name), "%s", name); + if (name_length >= RTE_DIM(entry->name)) { + status = EINVAL; + goto error_exit; + } + + entry->value = strdup(value); + if (entry->value == NULL) { + status = ENOMEM; + goto error_exit; + } + value_length = strlen(entry->value); + + strip_white_spaces(entry->name, name_length); + strip_white_spaces(entry->value, value_length); + + /* Add entry */ + if (section->num_entries == section->allocated_entries) { + size_t new_count = section->allocated_entries + CFG_ALLOC_ENTRY_BATCH; + struct rte_cfgfile_entry2 **new_entries = realloc(section->entries, + sizeof(section->entries[0]) * new_count); + + if (new_entries == NULL) { + status = ENOMEM; + goto error_exit; + } + section->entries = new_entries; + section->allocated_entries = new_count; + } + + section->entries[section->num_entries] = entry; + section->num_entries++; + + return 0; +error_exit: + printf("Error: %s\n", strerror(status)); + free(entry); + return -status; +} + /** * Create new apty config file object. * @@ -250,13 +492,12 @@ error_exit: * Handle to configuration file */ static struct rte_cfgfile * -rte_cfgfile_create(__rte_unused int flags, int allocated_sections) +rte_cfgfile_create(__rte_unused int flags) { - struct rte_cfgfile *cfg = malloc(sizeof(*cfg) + sizeof(cfg->sections[0]) * - allocated_sections); + struct rte_cfgfile *cfg = malloc(sizeof(struct rte_cfgfile)); if (cfg != NULL) - memset(cfg->sections, 0, sizeof(cfg->sections[0]) * allocated_sections); + memset(cfg, 0, sizeof(struct rte_cfgfile)); return cfg; } @@ -274,154 +515,84 @@ rte_cfgfile_create(__rte_unused int flags, int allocated_sections) static struct rte_cfgfile * rte_cfgfile_read(FILE *f, int flags) { - int allocated_sections = CFG_ALLOC_SECTION_BATCH; - int allocated_entries = 0; - int curr_section = -1; - int curr_entry = -1; - char *buffer = NULL; - size_t len; - size_t lineno = 0; + + char *line = NULL; + size_t line_size = 0; + char *pos; + struct rte_cfgfile *cfg = NULL; - int status; + struct rte_cfgfile_section *section = NULL; + size_t lineno = 0; + size_t current_lineno = 0; + int status = 0; if (f == NULL) return NULL; - cfg = rte_cfgfile_create(flags, allocated_sections); + cfg = rte_cfgfile_create(flags); if (cfg == NULL) goto error2; while (!feof(f)) { - status = rte_cfgfile_getline(&buffer, &len, f, &lineno); + current_lineno = lineno; + status = rte_cfgfile_getline(&line, &line_size, f, &lineno); if (status) break; - else if (!len) + else if (!line_size) continue; - len = _strip(buffer, len); - if (buffer[0] != '[' && memchr(buffer, '=', len) == NULL) - continue; - - if (buffer[0] == '[') { - /* section heading line */ - char *end = memchr(buffer, ']', len); - if (end == NULL) { - printf("Error line %zu - no terminating '['" - "character found\n", lineno); - goto error1; - } - *end = '\0'; - _strip(&buffer[1], end - &buffer[1]); - - /* close off old section and add start new one */ - if (curr_section >= 0) - cfg->sections[curr_section]->num_entries = - curr_entry + 1; - curr_section++; - - /* resize overall struct if we don't have room for more - sections */ - if (curr_section == allocated_sections) { - allocated_sections += CFG_ALLOC_SECTION_BATCH; - struct rte_cfgfile *n_cfg = realloc(cfg, - sizeof(*cfg) + sizeof(cfg->sections[0]) - * allocated_sections); - if (n_cfg == NULL) { - printf("Error - no more memory\n"); - goto error1; - } - cfg = n_cfg; - } - - /* allocate space for new section */ - allocated_entries = CFG_ALLOC_ENTRY_BATCH; - curr_entry = -1; - cfg->sections[curr_section] = malloc( - sizeof(*cfg->sections[0]) + - sizeof(cfg->sections[0]->entries[0]) * - allocated_entries); - if (cfg->sections[curr_section] == NULL) { - printf("Error - no more memory\n"); - goto error1; - } - - snprintf(cfg->sections[curr_section]->name, - sizeof(cfg->sections[0]->name), - "%s", &buffer[1]); - } else { - /* value line */ - if (curr_section < 0) { - printf("Error line %zu - value outside of" - "section\n", lineno); - goto error1; + pos = _skip_spaceses(line); + if (*pos == '[') { + status = rte_cfgfile_parse_section(§ion, pos); + if (status == 0) + status = rte_cfgfile_add_section(cfg, section); + } else if (isalpha(*pos)) { + if (section == NULL) { + printf("Error line %zu - value outside of section\n", + current_lineno); + status = -EINVAL; + break; } - struct rte_cfgfile_section *sect = - cfg->sections[curr_section]; char *split[2]; - if (rte_strsplit(buffer, sizeof(buffer), split, 2, '=') - != 2) { - printf("Error at line %zu - cannot split " - "string\n", lineno); - goto error1; - } - curr_entry++; - if (curr_entry == allocated_entries) { - allocated_entries += CFG_ALLOC_ENTRY_BATCH; - struct rte_cfgfile_section *n_sect = realloc( - sect, sizeof(*sect) + - sizeof(sect->entries[0]) * - allocated_entries); - if (n_sect == NULL) { - printf("Error - no more memory\n"); - goto error1; - } - sect = cfg->sections[curr_section] = n_sect; + if (rte_strsplit(pos, line_size - (pos - line), split, 2, '=') == 2) + status = rte_cfgfile_section_add_entry(section, + split[0], split[1]); + else { + printf("Error at line %zu - cannot split string\n", + current_lineno); + status = -EINVAL; } + } else if (*pos != '\0') { + printf("Invalid starting character '%c' on line %zu", + *pos, current_lineno); - sect->entries[curr_entry] = malloc( - sizeof(*sect->entries[0])); - if (sect->entries[curr_entry] == NULL) { - printf("Error - no more memory\n"); - goto error1; - } - - struct rte_cfgfile_entry *entry = sect->entries[ - curr_entry]; - snprintf(entry->name, sizeof(entry->name), "%s", - split[0]); - snprintf(entry->value, sizeof(entry->value), "%s", - split[1]); - _strip(entry->name, strnlen(entry->name, - sizeof(entry->name))); - _strip(entry->value, strnlen(entry->value, - sizeof(entry->value))); + status = -EINVAL; } + + if (status) + break; } if (status) goto error1; - fclose(f); + free(line); cfg->flags = flags; - cfg->num_sections = curr_section + 1; - /* curr_section will still be -1 if we have an empty file */ - if (curr_section >= 0) - cfg->sections[curr_section]->num_entries = curr_entry + 1; return cfg; error1: rte_cfgfile_close(cfg); error2: - fclose(f); + free(line); return NULL; } struct rte_cfgfile * rte_cfgfile_load(const char *filename, int flags) { - struct rte_cfgfile *cfg = NULL; + struct rte_cfgfile *cfg; FILE *file = fopen(filename, "r"); if (file == NULL) @@ -460,10 +631,17 @@ rte_cfgfile_close(struct rte_cfgfile *cfg) int rte_cfgfile_num_sections(struct rte_cfgfile *cfg, const char *sectionname, -size_t length) + size_t length) { size_t i; int num_sections = 0; + + if (cfg == NULL || (length > 0 && sectionname == NULL)) + return -EINVAL; + + if (length == 0) + return cfg->num_sections; + for (i = 0; i < cfg->num_sections; i++) { if (strncmp(cfg->sections[i]->name, sectionname, length) == 0) num_sections++; @@ -473,7 +651,7 @@ size_t length) int rte_cfgfile_sections(struct rte_cfgfile *cfg, char *sections[], - int max_sections) + int max_sections) { size_t i; @@ -484,66 +662,100 @@ 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) -{ - size_t 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) { - return (_get_section(cfg, sectionname) != NULL); + return rte_cfgfile_find_section(cfg, sectionname) != NULL; } int rte_cfgfile_section_num_entries(struct rte_cfgfile *cfg, const char *sectionname) { - const struct rte_cfgfile_section *s = _get_section(cfg, sectionname); + struct rte_cfgfile_section *s = rte_cfgfile_find_section(cfg, sectionname); + if (s == NULL) return -1; + return s->num_entries; } +int __vsym +rte_cfgfile_section_entries_v20(struct rte_cfgfile *cfg, + const char *sectionname, + struct rte_cfgfile_entry *entries, + int max_entries) +{ + size_t i; + struct rte_cfgfile_section *sect; -int -rte_cfgfile_section_entries(struct rte_cfgfile *cfg, const char *sectionname, - struct rte_cfgfile_entry *entries, int max_entries) + if (max_entries < 0 || (max_entries > 0 && entries == NULL)) + return -EINVAL; + + sect = rte_cfgfile_find_section(cfg, sectionname); + if (sect == NULL) + return -ENOENT; + + for (i = 0; (int)i < max_entries && i < sect->num_entries; i++) { + snprintf(entries[i].name, sizeof(entries[i].name), "%s", + sect->entries[i]->name); + + snprintf(entries[i].value, sizeof(entries[i].value), "%s", + sect->entries[i]->name); + } + + return i; +} + +VERSION_SYMBOL(rte_cfgfile_section_entries, _v20, 2.0); + +int __vsym +rte_cfgfile_section_entries_v21(struct rte_cfgfile *cfg, + const char *sectionname, const struct rte_cfgfile_entry2 **entries, + int max_entries) { size_t i; - const struct rte_cfgfile_section *sect = _get_section(cfg, sectionname); + struct rte_cfgfile_section *sect; + + if (max_entries < 0 || (max_entries > 0 && entries == NULL)) + return -EINVAL; + + sect = rte_cfgfile_find_section(cfg, sectionname); if (sect == NULL) - return -1; + return -ENOENT; + for (i = 0; (int)i < max_entries && i < sect->num_entries; i++) - entries[i] = *sect->entries[i]; + entries[i] = sect->entries[i]; + return i; } +BIND_DEFAULT_SYMBOL(rte_cfgfile_section_entries, _v21, 2.1); + const char * rte_cfgfile_get_entry(struct rte_cfgfile *cfg, const char *sectionname, const char *entryname) { - size_t i; - const struct rte_cfgfile_section *sect = _get_section(cfg, sectionname); + struct rte_cfgfile_section *sect; + struct rte_cfgfile_entry2 *entry; + + if (cfg == NULL) + return NULL; + + sect = rte_cfgfile_find_section(cfg, sectionname); if (sect == NULL) return NULL; - for (i = 0; i < sect->num_entries; i++) - if (strncmp(sect->entries[i]->name, entryname, CFG_NAME_LEN) - == 0) - return sect->entries[i]->value; - return NULL; + + entry = rte_cfgfile_find_entry(sect, entryname); + if (entry == NULL) + return NULL; + + return entry->value; } int rte_cfgfile_has_entry(struct rte_cfgfile *cfg, const char *sectionname, const char *entryname) { - return (rte_cfgfile_get_entry(cfg, sectionname, entryname) != NULL); + return rte_cfgfile_get_entry(cfg, sectionname, entryname) != NULL; } diff --git a/lib/librte_cfgfile/rte_cfgfile.h b/lib/librte_cfgfile/rte_cfgfile.h index 860ce44..546b3b8 100644 --- a/lib/librte_cfgfile/rte_cfgfile.h +++ b/lib/librte_cfgfile/rte_cfgfile.h @@ -34,6 +34,8 @@ #ifndef __INCLUDE_RTE_CFGFILE_H__ #define __INCLUDE_RTE_CFGFILE_H__ +#include + #ifdef __cplusplus extern "C" { #endif @@ -59,6 +61,12 @@ struct rte_cfgfile_entry { char value[CFG_VALUE_LEN]; /**< Value */ }; +/** Configuration file entry */ +struct rte_cfgfile_entry2 { + char name[CFG_NAME_LEN]; /**< Name */ + char *value; /**< Value */ +}; + /** * Open config file * @@ -73,7 +81,9 @@ struct rte_cfgfile * rte_cfgfile_load(const char *filename, int flags); /** -* Get number of sections in config file +* Get number of sections in config file which name start with *length* +* characters of *sec_name*. If *length* is 0 *sec_name* is ignored and total +* sections count is returned. * * @param cfg * Config file @@ -82,7 +92,7 @@ rte_cfgfile_load(const char *filename, int flags); * @param length * Maximum section name length * @return -* 0 on success, error code otherwise +* Number of sections, or negative error code otherwise. */ int rte_cfgfile_num_sections(struct rte_cfgfile *cfg, const char *sec_name, @@ -103,7 +113,7 @@ rte_cfgfile_num_sections(struct rte_cfgfile *cfg, const char *sec_name, * @param max_sections * Maximum number of section names to be stored in sections array * @return -* 0 on success, error code otherwise +* Number of section names in cfg on success, error code otherwise */ int rte_cfgfile_sections(struct rte_cfgfile *cfg, char *sections[], @@ -150,12 +160,23 @@ rte_cfgfile_section_num_entries(struct rte_cfgfile *cfg, * @return * 0 on success, error code otherwise */ -int -rte_cfgfile_section_entries(struct rte_cfgfile *cfg, +int rte_cfgfile_section_entries(struct rte_cfgfile *cfg, + const char *sectionname, + struct rte_cfgfile_entry **entries, + int max_entries); + +int __vsym +rte_cfgfile_section_entries_v20(struct rte_cfgfile *cfg, const char *sectionname, struct rte_cfgfile_entry *entries, int max_entries); +int __vsym +rte_cfgfile_section_entries_v21(struct rte_cfgfile *cfg, + const char *sectionname, + const struct rte_cfgfile_entry2 **entries, + int max_entries); + /** Get value of the named entry in named config file section * * @param cfg diff --git a/lib/librte_cfgfile/rte_cfgfile_version.map b/lib/librte_cfgfile/rte_cfgfile_version.map index bf6c6fd..959756b 100644 --- a/lib/librte_cfgfile/rte_cfgfile_version.map +++ b/lib/librte_cfgfile/rte_cfgfile_version.map @@ -13,3 +13,11 @@ DPDK_2.0 { local: *; }; + +DPDK_2.1 { + global: + + rte_cfgfile_section_entries; + + local: *; +} \ No newline at end of file -- 1.7.9.5