summaryrefslogtreecommitdiff
path: root/src/shared
diff options
context:
space:
mode:
authorChristoph Lipka <clipka@jp.adit-jv.com>2015-07-13 17:07:47 +0900
committerLutz Helwing <lutz_helwing@mentor.com>2015-11-24 09:48:41 +0100
commit188772ea0b3479352ae93552014d45fd1bc8e804 (patch)
treedbe104a788f2684ac5eb99a3faec9f592dc11c31 /src/shared
parent18f3332a363b98fca6345514c35fa10761e36c8e (diff)
downloadDLT-daemon-188772ea0b3479352ae93552014d45fd1bc8e804.tar.gz
Parse INI files
Offline Logstorage, Multinode and potentially other DLT extensions retrieve their configuration from a configuration file in INI file format. To avoid code duplications, this helper functionality should be used to read configuration files. Signed-off-by: Christoph Lipka <clipka@jp.adit-jv.com>
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/dlt_config_file_parser.c575
-rw-r--r--src/shared/dlt_config_file_parser.h147
2 files changed, 722 insertions, 0 deletions
diff --git a/src/shared/dlt_config_file_parser.c b/src/shared/dlt_config_file_parser.c
new file mode 100644
index 0000000..96a6ac2
--- /dev/null
+++ b/src/shared/dlt_config_file_parser.c
@@ -0,0 +1,575 @@
+/*
+ * @licence app begin@
+ * SPDX license identifier: MPL-2.0
+ *
+ * Copyright (C) 2015, Advanced Driver Information Technology
+ * This code is developed by Advanced Driver Information Technology.
+ * Copyright of Advanced Driver Information Technology, Bosch and DENSO.
+ *
+ * This file is part of GENIVI Project DLT - Diagnostic Log and Trace.
+ *
+ * This Source Code Form is subject to the terms of the
+ * Mozilla Public License (MPL), v. 2.0.
+ * If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * For further information see http://www.genivi.org/.
+ * @licence end@
+ */
+
+/*!
+ * \author
+ * Christoph Lipka <clipka@jp.adit-jv.com>
+ *
+ * \copyright Copyright © 2015 Advanced Driver Information Technology. \n
+ * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/.
+ *
+ * \file dlt_config_file_parser.c
+ */
+
+#include "dlt_config_file_parser.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <syslog.h>
+#include "dlt_common.h"
+#include "dlt-daemon_cfg.h"
+
+/* internal defines */
+#define DLT_CONFIG_FILE_NEW_SECTION 0x0a
+#define DLT_CONFIG_FILE_NEW_DATA 0x0b
+
+
+/* internal helper functions */
+
+/**
+ * dlt_config_file_trim_line
+ *
+ * Trim all whitespace from a string
+ *
+ * @param line String to remove whitespace from
+ */
+static void dlt_config_file_trim_line(char *line)
+{
+ if (line == NULL)
+ return;
+
+ char *i = line;
+ char *j = line;
+
+ while(*j != '\0')
+ {
+ *i = *j++;
+ if(!isspace(*i))
+ i++;
+ }
+ *i = '\0';
+}
+
+/**
+ * dlt_config_file_ignore_line
+ *
+ * Check if a line has to be ignored, because it contains a comment or is empty
+ *
+ * @param line Line of configuration file
+ * @return 0 if ignore, -1 do not ignore
+ */
+static int dlt_config_file_ignore_line(char *line)
+{
+ int i = 0;
+ int len = strlen(line);
+
+ for (i = 0; i < len; i++)
+ {
+ if (line[i] == '#' || line[i] == ';' || line[i] == '\n' || line[i] == '\0')
+ return 0; /* ignore */
+ else
+ return -1; /* do not ignore */
+ }
+
+ return -1;
+}
+
+/**
+ * dlt_config_file_is_section_name
+ *
+ * Check if section name already used
+ *
+ * @param file DltConfigFile
+ * @param name Name of section
+ * @return 0, section name not used, -1 section name already used
+ */
+static int dlt_config_file_is_section_name(DltConfigFile *file, char *name)
+{
+ int i = 0;
+
+ if (file == NULL || name == NULL)
+ return -1;
+
+ for (i = 0; i < file->num_sections; i++)
+ {
+ DltConfigFileSection *s = &file->sections[i];
+
+ if (strncmp(s->name, name, DLT_CONFIG_FILE_ENTRY_MAX_LEN) == 0)
+ return -1;
+ }
+
+ return 0; /* section name not used */
+}
+
+/**
+ * dlt_config_file_set_section
+ *
+ * Store section in internal data structure
+ *
+ * @param file DltConfigFile
+ * @param name Name of section
+ * @return 0 on success, else -1
+ */
+static int dlt_config_file_set_section(DltConfigFile *file, char *name)
+{
+ int section = file->num_sections;
+ /* check if adding another section would exceed max number of sections */
+ if (section+1 >= DLT_CONFIG_FILE_SECTIONS_MAX)
+ {
+ dlt_log(LOG_WARNING, "Cannot store more sections\n");
+ return -1; /* reached max number of sections */
+ }
+
+ /* do not store section with same name again */
+ if (dlt_config_file_is_section_name(file, name) != 0)
+ {
+ dlt_log(LOG_WARNING, "Cannot store section name again\n");
+ return -1;
+ }
+
+ DltConfigFileSection *s = &file->sections[section];
+
+ /* alloc data for entries */
+ s->name = calloc(sizeof(char), DLT_CONFIG_FILE_ENTRY_MAX_LEN + 1);
+ if (s->name == NULL)
+ {
+ dlt_log(LOG_ERR, "Cannot allocate memory for internal data structure\n");
+ return -1;
+ }
+
+ s->keys = calloc(sizeof(char), DLT_CONFIG_FILE_ENTRY_MAX_LEN * DLT_CONFIG_FILE_KEYS_MAX + 1);
+ if (s->keys == NULL)
+ {
+ free(s->name);
+ dlt_log(LOG_ERR, "Cannot allocate memory for internal data structure\n");
+ return -1;
+ }
+
+ /* create hsearch table for data inside the section */
+ if (hcreate_r(DLT_CONFIG_FILE_KEYS_MAX, &s->data) == 0)
+ {
+ dlt_log(LOG_ERR, "Cannot create hash table object\n");
+ free(s->name);
+ free(s->keys);
+ return -1;
+ }
+
+ strncpy(file->sections[section].name, name, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
+ file->num_sections += 1;
+ return 0;
+}
+
+/**
+ * dlt_config_file_set_section_data
+ *
+ * Store data pair of a section
+ *
+ * @param file DltConfigFile
+ * @param str1 string used for key
+ * @param str2 string used for value
+ * @return 0 on success, else -1
+ */
+static int dlt_config_file_set_section_data(DltConfigFile *file, char *str1, char *str2)
+{
+ ENTRY item;
+ ENTRY *ret;
+
+ if (file == NULL || str1 == NULL || str2 == NULL)
+ return -1;
+
+ DltConfigFileSection *s = &file->sections[file->num_sections-1];
+ int key_number = s->num_entries;
+
+ if (key_number+1 >= DLT_CONFIG_FILE_KEYS_MAX)
+ {
+ dlt_log(LOG_WARNING, "Cannot store more keys in section\n");
+ return -1; /* reached max number of keys per section */
+ }
+
+ /* copy data into structure */
+ strncpy(&s->keys[key_number * DLT_CONFIG_FILE_ENTRY_MAX_LEN], str1, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
+
+ item.key = strdup(str1);
+ item.data = strdup(str2);
+
+ /* check if already stored */
+ if (hsearch_r(item, FIND, &ret, &s->data) == 0)
+ {
+ if (hsearch_r(item, ENTER, &ret, &s->data) == 0)
+ {
+ free(item.key);
+ free(item.data);
+
+ dlt_log(LOG_ERR, "Cannot add data to hash table\n");
+ return -1;
+ }
+ }
+ else /* already exist, ignore */
+ {
+ char error_str[DLT_DAEMON_TEXTBUFSIZE] = {'\0'};
+ snprintf(error_str, DLT_DAEMON_TEXTBUFSIZE, "Key \"%s\" already exists! New data will be ignored\n", item.key);
+ dlt_log(LOG_WARNING, error_str);
+ return -1;
+ }
+
+ s->num_entries += 1;
+
+ return 0;
+}
+
+/**
+ * dlt_config_file_has_section
+ *
+ * Check if a certain line in config file is a section header
+ *
+ * @param line Line in configuration file
+ * @return 0 if section header, else -1
+ */
+static int dlt_config_file_line_has_section(char *line)
+{
+ line = line; /* avoid compiler warnings */
+ if(line[0] == '[') /* section found */
+ return 0;
+ else
+ return -1;
+}
+
+/**
+ * dlt_config_file_get_section_name_from_string
+ *
+ * Extract section name from line
+ *
+ * @param line Line in configuration file containing a section header
+ * @return 0 on success, else -1
+ */
+static int dlt_config_file_get_section_name_from_string(char *line, char *name)
+{
+ int i = 0;
+ int j = 0;
+
+ if (line == NULL || name == NULL)
+ return -1;
+
+ for(i = 0; i < DLT_CONFIG_FILE_ENTRY_MAX_LEN; i++)
+ {
+ if(line[i] == '[' || isspace(line[i]))
+ continue;
+ else if (line[i] == ']' || line[i] == '\n' || line[i] == '\0')
+ break;
+ else
+ name[j++] = line[i];
+ }
+
+ return 0;
+}
+
+/**
+ * dlt_config_file_get_key_value
+ *
+ * Get key and value from a line of configuration file
+ *
+ * @param line Line on configuration file
+ * @param[out] str1 String to be used as key
+ * @param[out] str2 String to be used as value
+ * @return 0 on success, else -1
+ */
+static int dlt_config_file_get_key_value(char *line, char *str1, char *str2)
+{
+ char *delimiter = "=";
+ char *ptr;
+ char *save_ptr;
+
+ if (line == NULL || str1 == NULL || str2 == NULL)
+ return -1;
+
+ ptr = strtok_r(line, delimiter, &save_ptr);
+
+ if (ptr != NULL) /* get key */
+ strncpy(str1, ptr, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
+ else
+ return -1;
+
+ ptr = strtok_r(NULL, delimiter, &save_ptr);
+
+ if (ptr != NULL)
+ strncpy(str2, ptr, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
+ else
+ return -1;
+
+ return 0;
+}
+
+/**
+ * dlt_config_file_read_line
+ *
+ * Read line from configuration file
+ *
+ * @param line Line from configuration file
+ * @param[out] str1 String contains section header or key
+ * @param[out] str2 String contains value or is empty
+ * @return 0 on success, else -1
+ */
+static int dlt_config_file_read_line(char *line, char *str1, char *str2)
+{
+ if (line == NULL || str1 == NULL || str2 == NULL)
+ return -1;
+
+ /* reset values to zero */
+ memset(str1, 0, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
+ memset(str2, 0, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
+
+ /* check if line contains a section */
+ if ((dlt_config_file_line_has_section(line)) == 0)
+ {
+ /* retrieve section name */
+ if (dlt_config_file_get_section_name_from_string(line, str1) != 0)
+ return -1;
+
+ return DLT_CONFIG_FILE_NEW_SECTION;
+ }
+
+ /* copy strings as key value pair into str1, str2 */
+ if (dlt_config_file_get_key_value(line, str1, str2) != 0)
+ return -1;
+
+ return DLT_CONFIG_FILE_NEW_DATA;
+}
+
+/**
+ * dlt_config_file_read_file
+ *
+ * Read configuration file line by line and fill internal structures
+ *
+ * @param file DltConfigFile
+ * @param hdl FILE handle of opened configuration file
+ */
+static void dlt_config_file_read_file(DltConfigFile *file, FILE *hdl)
+{
+ int ret = 0;
+ char error_str[DLT_DAEMON_TEXTBUFSIZE] = {'\0'};
+ char line[DLT_CONFIG_FILE_LINE_MAX_LEN] = {'\0'};
+ char str1[DLT_CONFIG_FILE_ENTRY_MAX_LEN] = {'\0'};
+ char str2[DLT_CONFIG_FILE_ENTRY_MAX_LEN] = {'\0'};
+ int line_number = 0;
+ int is_section_valid = -1; /* to check if section name is given twice or invalid */
+
+ /* read configuration file line by line */
+ while (fgets(line, DLT_CONFIG_FILE_LINE_MAX_LEN, hdl) != NULL)
+ {
+ line_number++;
+
+ /* ignore empty and comment lines */
+ if (dlt_config_file_ignore_line(line) == 0)
+ continue;
+
+ /* trim line end */
+ dlt_config_file_trim_line(line);
+
+ /* parse content of line */
+ ret = dlt_config_file_read_line(line, str1, str2);
+
+ switch(ret)
+ {
+ case DLT_CONFIG_FILE_NEW_SECTION: /* store str1 as new section */
+ is_section_valid = -1;
+ if ((ret = dlt_config_file_set_section(file, str1)) == 0)
+ {
+ is_section_valid = 0;
+ }
+ break;
+ case DLT_CONFIG_FILE_NEW_DATA: /* store str1 and str2 as new data for section */
+ if (is_section_valid == 0)
+ {
+ ret = dlt_config_file_set_section_data(file, str1, str2);
+ }
+ break;
+ default: /* something is wrong with the line */
+ snprintf(error_str, DLT_DAEMON_TEXTBUFSIZE, "Line (%d) \"%s\" is invalid\n", line_number, line);
+ dlt_log(LOG_WARNING, error_str);
+ }
+ }
+}
+
+/**
+ * dlt_config_file_find_section
+ *
+ * Find a section
+ *
+ * @param file DltConfigFile
+ * @param section Name of section
+ * @return number of section on success, else -1
+ */
+static int dlt_config_file_find_section(const DltConfigFile *file,
+ const char *section)
+{
+ int i = 0;
+
+ if (file == NULL || section == NULL || file->num_sections <= 0)
+ {
+ dlt_log(LOG_WARNING, "Section cannot be found due to invalid parameters\n");
+ return -1;
+ }
+
+ for (i = 0; i < file->num_sections; i++)
+ {
+ DltConfigFileSection *s = &file->sections[i];
+ if (strncmp(s->name, section, DLT_CONFIG_FILE_ENTRY_MAX_LEN) == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+/************************** interface implementation ***************************/
+DltConfigFile *dlt_config_file_init(char *file_name)
+{
+ DltConfigFile *file;
+ FILE *hdl = NULL;
+
+ if (file_name == NULL || (strlen(file_name) >= DLT_CONFIG_FILE_PATH_MAX_LEN))
+ {
+ dlt_log(LOG_ERR, "Given configuration file invalid\n");
+ return NULL;
+ }
+
+ file = calloc(sizeof(DltConfigFile), 1);
+ if (file == NULL)
+ {
+ dlt_log(LOG_ERR, "Setup internal data structure to parse config file failed\n");
+ return NULL;
+ }
+
+ file->sections = calloc(sizeof(DltConfigFileSection), DLT_CONFIG_FILE_SECTIONS_MAX);
+
+ /* open file */
+ if ((hdl = fopen(file_name, "r")) == NULL)
+ {
+ dlt_log(LOG_ERR, "Cannot open configuration file\n");
+ free(file);
+ return NULL;
+ }
+
+ dlt_config_file_read_file(file, hdl);
+
+ /* all information stored internally */
+ fclose(hdl);
+
+ return file;
+}
+
+void dlt_config_file_release(DltConfigFile *file)
+{
+ int i = 0;
+ int j = 0;
+ ENTRY entry;
+ ENTRY *found;
+
+ if(file != NULL){
+ int max = file->num_sections;
+ for (i = 0; i < max; i++)
+ {
+ DltConfigFileSection *s = &file->sections[i];
+ free(s->name);
+
+ /* free data in hashtable */
+ if (s->keys != NULL || &s->data != NULL)
+ {
+ for (j = 0; j < s->num_entries; j++)
+ {
+ entry.key = (s->keys + j * DLT_CONFIG_FILE_ENTRY_MAX_LEN);
+ hsearch_r (entry, FIND, &found, &s->data);
+ free(found->key);
+ free(found->data);
+ }
+
+ hdestroy_r(&s->data);
+ free(s->keys);
+ }
+ }
+
+ free(file->sections);
+ free(file);
+ }
+}
+
+int dlt_config_file_get_section_name(const DltConfigFile *file,
+ int num,
+ char *name)
+{
+ if (file == NULL || name == NULL || num < 0 || num >= file->num_sections)
+ return -1;
+
+ strncpy(name, (file->sections + num)->name, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
+
+ return 0;
+}
+
+int dlt_config_file_get_num_sections(const DltConfigFile *file, int *num)
+{
+ if(file == NULL || file->num_sections < 0)
+ return -1;
+
+ *num = file->num_sections;
+
+ return 0;
+}
+
+int dlt_config_file_get_value(const DltConfigFile *file,
+ const char *section,
+ const char *key, char *value)
+{
+ DltConfigFileSection *s = NULL;
+ int num_section = 0;
+ ENTRY entry;
+ ENTRY *found;
+
+ if (file == NULL || section == NULL || key == NULL || value == NULL)
+ return -1;
+
+ /* clean value */
+ memset(value, 0, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
+
+ num_section = dlt_config_file_find_section(file, section);
+ if (num_section == -1)
+ return -1;
+
+ s = (file->sections + num_section);
+
+ /* check if available */
+ entry.key = strdup(key);
+ if (entry.key == NULL)
+ {
+ dlt_log(LOG_CRIT, "Not enougth memory to duplicate key string\n");
+ return -1;
+ }
+
+ if (hsearch_r(entry, FIND, &found, &s->data) == 0) /* not found */
+ {
+ dlt_log(LOG_WARNING, "Entry does not exist in section\n");
+ free(entry.key);
+ return -1;
+ }
+ else /* found */
+ {
+ strncpy(value, (char *)found->data, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
+ free(entry.key);
+ return 0;
+ }
+}
diff --git a/src/shared/dlt_config_file_parser.h b/src/shared/dlt_config_file_parser.h
new file mode 100644
index 0000000..c38a8b8
--- /dev/null
+++ b/src/shared/dlt_config_file_parser.h
@@ -0,0 +1,147 @@
+/*
+ * @licence app begin@
+ * SPDX license identifier: MPL-2.0
+ *
+ * Copyright (C) 2015, Advanced Driver Information Technology
+ * This code is developed by Advanced Driver Information Technology.
+ * Copyright of Advanced Driver Information Technology, Bosch and DENSO.
+ *
+ * This file is part of GENIVI Project DLT - Diagnostic Log and Trace.
+ *
+ * This Source Code Form is subject to the terms of the
+ * Mozilla Public License (MPL), v. 2.0.
+ * If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * For further information see http://www.genivi.org/.
+ * @licence end@
+ */
+
+/*!
+ * \author Christoph Lipka <clipka@jp.adit-jv.com>
+ *
+ * \copyright Copyright © 2015 Advanced Driver Information Technology. \n
+ * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/.
+ *
+ * \file dlt_config_file_parser.h
+ */
+
+
+/*******************************************************************************
+** **
+** SRC-MODULE: dlt_config_file_parser.h **
+** **
+** TARGET : linux **
+** **
+** PROJECT : DLT **
+** **
+** AUTHOR : Christoph Lipka clipka@jp.adit-jv.com **
+** **
+** PURPOSE : **
+** **
+** REMARKS : **
+** **
+** PLATFORM DEPENDANT [yes/no]: yes **
+** **
+** TO BE CHANGED BY USER [yes/no]: no **
+** **
+*******************************************************************************/
+
+/*******************************************************************************
+** Author Identity **
+********************************************************************************
+** **
+** Initials Name Company **
+** -------- ------------------------- ---------------------------------- **
+** cl Christoph Lipka ADIT **
+*******************************************************************************/
+
+#ifndef _DLT_CONFIG_FILE_PARSER_H_
+#define _DLT_CONFIG_FILE_PARSER_H_
+
+#include <search.h>
+
+/* definitions */
+#define DLT_CONFIG_FILE_PATH_MAX_LEN 100 /* absolute path including filename */
+#define DLT_CONFIG_FILE_ENTRY_MAX_LEN 100 /* Entry for section, key and value */
+#define DLT_CONFIG_FILE_LINE_MAX_LEN 210
+#define DLT_CONFIG_FILE_SECTIONS_MAX 100
+#define DLT_CONFIG_FILE_KEYS_MAX 25 /* Maximal keys per section */
+
+/* Config file section structure */
+typedef struct
+{
+ int num_entries; /* number of entries */
+ char *name; /* name of section */
+ char *keys; /* keys */
+ struct hsearch_data data; /* hash table object used by hsearch_r */
+} DltConfigFileSection;
+
+typedef struct
+{
+ int num_sections; /* number of sections */
+ DltConfigFileSection *sections; /* sections */
+} DltConfigFile;
+
+/**
+ * dlt_config_file_init
+ *
+ * Load the configuration file and stores all data in
+ * internal data structures.
+ *
+ * @param file_name File to be opened
+ * @return Pointer to DltConfigFile object or NULL on error
+ */
+DltConfigFile *dlt_config_file_init(char *file_name);
+
+/**
+ * dlt_config_file_release
+ *
+ * Release config file and frees all internal data. Has to be called after
+ * after all data is read.
+ *
+ * @param file DltConfigFile
+ */
+void dlt_config_file_release(DltConfigFile *file);
+
+/**
+ * dlt_config_file_get_section_name
+ *
+ * Get name of section number.
+ *
+ * @param[in] file DltConfigFile
+ * @param[in] num Number of section
+ * @param[out] section Section name
+ * @return 0 on success, else -1
+ */
+int dlt_config_file_get_section_name(const DltConfigFile *file,
+ int num,
+ char *name);
+
+/**
+ * dlt_config_file_get_num_sections
+ *
+ * Get the number of sections inside configuration file
+ *
+ * @param[in] file DltConfigFile
+ * @param[out] num Number of sections inside configuration file
+ * @return 0 on success, else -1
+ */
+int dlt_config_file_get_num_sections(const DltConfigFile *file, int *num);
+
+/**
+ * dlt_config_file_get_value
+ *
+ * Get value of key in specified section.
+ *
+ * @param[in] file DltConfigFile
+ * @param[in] section Name of section
+ * @param[in] key Key
+ * @param[out] value Value
+ * @return 0 on success, else -1
+ */
+int dlt_config_file_get_value(const DltConfigFile *file,
+ const char *section,
+ const char *key,
+ char *value);
+#endif