LCOV - code coverage report
Current view: top level - shared - dlt_config_file_parser.c (source / functions) Hit Total Coverage
Test: dlt_final_coverage.info Lines: 142 170 83.5 %
Date: 2024-12-06 04:41:42 Functions: 15 15 100.0 %

          Line data    Source code
       1             : /*
       2             :  * SPDX license identifier: MPL-2.0
       3             :  *
       4             :  * Copyright (C) 2015, Advanced Driver Information Technology
       5             :  * This code is developed by Advanced Driver Information Technology.
       6             :  * Copyright of Advanced Driver Information Technology, Bosch and DENSO.
       7             :  *
       8             :  * This file is part of COVESA Project DLT - Diagnostic Log and Trace.
       9             :  *
      10             :  * This Source Code Form is subject to the terms of the
      11             :  * Mozilla Public License (MPL), v. 2.0.
      12             :  * If a copy of the MPL was not distributed with this file,
      13             :  * You can obtain one at http://mozilla.org/MPL/2.0/.
      14             :  *
      15             :  * For further information see http://www.covesa.org/.
      16             :  */
      17             : 
      18             : /*!
      19             :  * \author
      20             :  * Christoph Lipka <clipka@jp.adit-jv.com>
      21             :  *
      22             :  * \copyright Copyright © 2015 Advanced Driver Information Technology. \n
      23             :  * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/.
      24             :  *
      25             :  * \file dlt_config_file_parser.c
      26             :  */
      27             : 
      28             : #include "dlt_config_file_parser.h"
      29             : #include <stdlib.h>
      30             : #include <stdio.h>
      31             : #include <string.h>
      32             : #include <ctype.h>
      33             : #include <syslog.h>
      34             : #include "dlt_common.h"
      35             : #include "dlt_log.h"
      36             : #include "dlt-daemon_cfg.h"
      37             : 
      38             : /* internal defines */
      39             : #define DLT_CONFIG_FILE_NEW_SECTION 0x0a
      40             : #define DLT_CONFIG_FILE_NEW_DATA    0x0b
      41             : 
      42             : 
      43             : /* internal helper functions */
      44             : 
      45             : /**
      46             :  * dlt_config_file_trim_line
      47             :  *
      48             :  * Trim all whitespace from a string
      49             :  *
      50             :  * @param line  String to remove whitespace from
      51             :  */
      52         379 : static void dlt_config_file_trim_line(char *line)
      53             : {
      54         379 :     if (line == NULL)
      55             :         return;
      56             : 
      57             :     char *i = line;
      58             :     char *j = line;
      59             : 
      60        6683 :     while (*j != '\0') {
      61        6304 :         *i = *j++;
      62             : 
      63        6304 :         if (!isspace(*i))
      64        5925 :             i++;
      65             :     }
      66             : 
      67         379 :     *i = '\0';
      68             : }
      69             : 
      70             : /**
      71             :  * dlt_config_file_ignore_line
      72             :  *
      73             :  * Check if a line has to be ignored, because it contains a comment or is empty
      74             :  *
      75             :  * @param line  Line of configuration file
      76             :  * @return 0 if ignore, -1 do not ignore
      77             :  */
      78             : static int dlt_config_file_ignore_line(char *line)
      79             : {
      80         406 :     if ((line[0] == '#') || (line[0] == ';') || (line[0] == '\n') ||
      81             :         (line[0] == '\0'))
      82             :         return 0; /* ignore */
      83             :     else
      84             :         return -1; /* do not ignore */
      85             : }
      86             : 
      87             : /**
      88             :  * dlt_config_file_is_section_name
      89             :  *
      90             :  * Check if section name already used
      91             :  *
      92             :  * @param file  DltConfigFile
      93             :  * @param name  Name of section
      94             :  * @return 0, section name not used, -1 section name already used
      95             :  */
      96          40 : static int dlt_config_file_is_section_name(DltConfigFile *file, char *name)
      97             : {
      98             :     int i = 0;
      99             : 
     100          40 :     if ((file == NULL) || (name == NULL))
     101             :         return -1;
     102             : 
     103         179 :     for (i = 0; i < file->num_sections; i++) {
     104         139 :         DltConfigFileSection *s = &file->sections[i];
     105             : 
     106         139 :         if (strncmp(s->name, name, DLT_CONFIG_FILE_ENTRY_MAX_LEN) == 0)
     107             :             return -1;
     108             :     }
     109             : 
     110             :     return 0; /* section name not used */
     111             : }
     112             : 
     113             : /**
     114             :  * dlt_config_file_set_section
     115             :  *
     116             :  * Store section in internal data structure
     117             :  *
     118             :  * @param file  DltConfigFile
     119             :  * @param name  Name of section
     120             :  * @return 0 on success, else -1
     121             :  */
     122          40 : static int dlt_config_file_set_section(DltConfigFile *file, char *name)
     123             : {
     124          40 :     int section = file->num_sections;
     125             : 
     126             :     /* check if adding another section would exceed max number of sections */
     127          40 :     if (section >= DLT_CONFIG_FILE_SECTIONS_MAX) {
     128           0 :         dlt_log(LOG_WARNING, "Cannot store more sections\n");
     129           0 :         return -1; /* reached max number of sections */
     130             :     }
     131             : 
     132             :     /* do not store section with same name again */
     133          40 :     if (dlt_config_file_is_section_name(file, name) != 0) {
     134           0 :         dlt_log(LOG_WARNING, "Cannot store section name again\n");
     135           0 :         return -1;
     136             :     }
     137             : 
     138          40 :     DltConfigFileSection *s = &file->sections[section];
     139             : 
     140             :     /* alloc data for entries */
     141          40 :     s->name = calloc(sizeof(char), DLT_CONFIG_FILE_ENTRY_MAX_LEN + 1);
     142             : 
     143          40 :     if (s->name == NULL) {
     144           0 :         dlt_log(LOG_ERR, "Cannot allocate memory for internal data structure\n");
     145           0 :         return -1;
     146             :     }
     147             : 
     148          40 :     s->keys = calloc(sizeof(char), DLT_CONFIG_FILE_ENTRY_MAX_LEN * DLT_CONFIG_FILE_KEYS_MAX + 1);
     149             : 
     150          40 :     if (s->keys == NULL) {
     151           0 :         free(s->name);
     152           0 :         s->name = NULL;
     153           0 :         dlt_log(LOG_ERR, "Cannot allocate memory for internal data structure\n");
     154           0 :         return -1;
     155             :     }
     156             : 
     157             :     strncpy(file->sections[section].name, name, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
     158          40 :     file->num_sections += 1;
     159          40 :     return 0;
     160             : }
     161             : 
     162             : /**
     163             :  * dlt_config_file_set_section_data
     164             :  *
     165             :  * Store data pair of a section
     166             :  *
     167             :  * @param file DltConfigFile
     168             :  * @param str1 string used for key
     169             :  * @param str2 string used for value
     170             :  * @return 0 on success, else -1
     171             :  */
     172         339 : static int dlt_config_file_set_section_data(DltConfigFile *file, char *str1, char *str2)
     173             : {
     174             :     DltConfigKeyData **tmp = NULL;
     175             : 
     176         339 :     if ((file == NULL) || (str1 == NULL) || (str2 == NULL))
     177             :         return -1;
     178             : 
     179         339 :     DltConfigFileSection *s = &file->sections[file->num_sections - 1];
     180         339 :     int key_number = s->num_entries;
     181             : 
     182         339 :     if (key_number + 1 >= DLT_CONFIG_FILE_KEYS_MAX) {
     183           0 :         dlt_log(LOG_WARNING, "Cannot store more keys in section\n");
     184           0 :         return -1; /* reached max number of keys per section */
     185             :     }
     186             : 
     187             :     /* copy data into structure */
     188         339 :     strncpy(&s->keys[key_number * DLT_CONFIG_FILE_ENTRY_MAX_LEN], str1, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
     189             : 
     190         339 :     if (s->list == NULL) {
     191             :         /* creating a list if it doesnt exists */
     192          40 :         s->list = malloc(sizeof(DltConfigKeyData));
     193             : 
     194          40 :         if (s->list == NULL) {
     195           0 :             dlt_log(LOG_WARNING, "Could not allocate initial memory to list \n");
     196           0 :             return -1;
     197             :         }
     198             : 
     199          40 :         tmp = &s->list;
     200             :     }
     201             :     else {
     202         299 :         tmp = &s->list;
     203             : 
     204        1589 :         while (*(tmp) != NULL)
     205        1290 :             tmp = &(*tmp)->next;
     206             : 
     207             :         /* Adding new entry to the list */
     208         299 :         *tmp = malloc(sizeof(DltConfigKeyData));
     209             : 
     210         299 :         if (*tmp == NULL) {
     211           0 :             dlt_log(LOG_WARNING, "Could not allocate memory to list \n");
     212           0 :             return -1;
     213             :         }
     214             :     }
     215             : 
     216         339 :     (*tmp)->key = strdup(str1);
     217         339 :     (*tmp)->data = strdup(str2);
     218         339 :     (*tmp)->next = NULL;
     219             : 
     220         339 :     s->num_entries += 1;
     221             : 
     222         339 :     return 0;
     223             : }
     224             : 
     225             : /**
     226             :  * dlt_config_file_has_section
     227             :  *
     228             :  * Check if a certain line in config file is a section header
     229             :  *
     230             :  * @param line  Line in configuration file
     231             :  * @return 0 if section header, else -1
     232             :  */
     233             : static int dlt_config_file_line_has_section(char *line)
     234             : {
     235             :     (void)line; /* avoid compiler warnings */
     236             : 
     237         379 :     if (line[0] == '[') /* section found */
     238             :         return 0;
     239             :     else
     240             :         return -1;
     241             : }
     242             : 
     243             : /**
     244             :  * dlt_config_file_get_section_name_from_string
     245             :  *
     246             :  * Extract section name from line
     247             :  *
     248             :  * @param line  Line in configuration file containing a section header
     249             :  * @param name  Section name
     250             :  * @return 0 on success, else -1
     251             :  */
     252          40 : static int dlt_config_file_get_section_name_from_string(char *line, char *name)
     253             : {
     254             :     int i = 0;
     255             :     int j = 0;
     256             : 
     257          40 :     if ((line == NULL) || (name == NULL))
     258             :         return -1;
     259             : 
     260         386 :     for (i = 0; i < DLT_CONFIG_FILE_ENTRY_MAX_LEN; i++) {
     261         386 :         if ((line[i] == '[') || isspace(line[i]))
     262          40 :             continue;
     263         346 :         else if ((line[i] == ']') || (line[i] == '\n') || (line[i] == '\0'))
     264             :             break;
     265             :         else
     266         306 :             name[j++] = line[i];
     267             :     }
     268             : 
     269             :     return 0;
     270             : }
     271             : 
     272             : /**
     273             :  * dlt_config_file_get_key_value
     274             :  *
     275             :  * Get key and value from a line of configuration file
     276             :  *
     277             :  * @param line      Line on configuration file
     278             :  * @param[out] str1 String to be used as key
     279             :  * @param[out] str2 String to be used as value
     280             :  * @return 0 on success, else -1
     281             :  */
     282         339 : static int dlt_config_file_get_key_value(char *line, char *str1, char *str2)
     283             : {
     284             :     char *delimiter = "=";
     285             :     char *ptr;
     286             :     char *save_ptr;
     287             : 
     288         339 :     if ((line == NULL) || (str1 == NULL) || (str2 == NULL))
     289             :         return -1;
     290             : 
     291         339 :     ptr = strtok_r(line, delimiter, &save_ptr);
     292             : 
     293         339 :     if (ptr != NULL) { /* get key */
     294             :         strncpy(str1, ptr, DLT_CONFIG_FILE_ENTRY_MAX_LEN - 1);
     295         339 :         str1[DLT_CONFIG_FILE_ENTRY_MAX_LEN - 1] = '\0';
     296             :     } else {
     297             :         return -1;
     298             :     }
     299             : 
     300         339 :     ptr = strtok_r(NULL, delimiter, &save_ptr);
     301             : 
     302         339 :     if (ptr != NULL) {
     303             :         strncpy(str2, ptr, DLT_CONFIG_FILE_ENTRY_MAX_LEN - 1);
     304         339 :         str2[DLT_CONFIG_FILE_ENTRY_MAX_LEN - 1] = '\0';
     305             :     } else {
     306             :         return -1;
     307             :     }
     308             : 
     309         339 :     return 0;
     310             : }
     311             : 
     312             : /**
     313             :  * dlt_config_file_read_line
     314             :  *
     315             :  * Read line from configuration file
     316             :  *
     317             :  * @param       line Line from configuration file
     318             :  * @param[out]  str1 String contains section header or key
     319             :  * @param[out]  str2 String contains value or is empty
     320             :  * @return 0 on success, else -1
     321             :  */
     322         379 : static int dlt_config_file_read_line(char *line, char *str1, char *str2)
     323             : {
     324         379 :     if ((line == NULL) || (str1 == NULL) || (str2 == NULL))
     325             :         return -1;
     326             : 
     327             :     /* reset values to zero */
     328             :     memset(str1, 0, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
     329             :     memset(str2, 0, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
     330             : 
     331             :     /* check if line contains a section */
     332             :     if ((dlt_config_file_line_has_section(line)) == 0) {
     333             :         /* retrieve section name */
     334          40 :         if (dlt_config_file_get_section_name_from_string(line, str1) != 0)
     335             :             return -1;
     336             : 
     337          40 :         return DLT_CONFIG_FILE_NEW_SECTION;
     338             :     }
     339             : 
     340             :     /* copy strings as key value pair into str1, str2 */
     341         339 :     if (dlt_config_file_get_key_value(line, str1, str2) != 0)
     342           0 :         return -1;
     343             : 
     344             :     return DLT_CONFIG_FILE_NEW_DATA;
     345             : }
     346             : 
     347             : /**
     348             :  * dlt_config_file_read_file
     349             :  *
     350             :  * Read configuration file line by line and fill internal structures
     351             :  *
     352             :  * @param file DltConfigFile
     353             :  * @param hdl  FILE handle of opened configuration file
     354             :  */
     355          14 : static void dlt_config_file_read_file(DltConfigFile *file, FILE *hdl)
     356             : {
     357             :     int ret = 0;
     358          14 :     char line[DLT_CONFIG_FILE_LINE_MAX_LEN] = { '\0' };
     359          14 :     char str1[DLT_CONFIG_FILE_ENTRY_MAX_LEN] = { '\0' };
     360          14 :     char str2[DLT_CONFIG_FILE_ENTRY_MAX_LEN] = { '\0' };
     361             :     int line_number = 0;
     362             :     int is_section_valid = -1; /* to check if section name is given twice or invalid */
     363             : 
     364             :     /* read configuration file line by line */
     365         434 :     while (fgets(line, DLT_CONFIG_FILE_LINE_MAX_LEN, hdl) != NULL) {
     366         406 :         line_number++;
     367             : 
     368             :         /* ignore empty and comment lines */
     369          27 :         if (dlt_config_file_ignore_line(line) == 0)
     370          27 :             continue;
     371             : 
     372             :         /* trim line end */
     373         379 :         dlt_config_file_trim_line(line);
     374             : 
     375             :         /* parse content of line */
     376         379 :         ret = dlt_config_file_read_line(line, str1, str2);
     377             : 
     378         379 :         switch (ret) {
     379          40 :         case DLT_CONFIG_FILE_NEW_SECTION:     /* store str1 as new section */
     380             :             is_section_valid = -1;
     381             : 
     382          40 :             if ((ret = dlt_config_file_set_section(file, str1)) == 0)
     383             :                 is_section_valid = 0;
     384             : 
     385             :             break;
     386         339 :         case DLT_CONFIG_FILE_NEW_DATA:     /* store str1 and str2 as new data for section */
     387             : 
     388         339 :             if (is_section_valid == 0)
     389         339 :                 dlt_config_file_set_section_data(file, str1, str2);
     390             : 
     391             :             break;
     392           0 :         default:     /* something is wrong with the line */
     393           0 :             dlt_vlog(LOG_WARNING, "Line (%d) \"%s\" is invalid\n", line_number,
     394             :                      line);
     395             :         }
     396             :     }
     397          14 : }
     398             : 
     399             : /**
     400             :  * dlt_config_file_find_section
     401             :  *
     402             :  * Find a section
     403             :  *
     404             :  * @param file      DltConfigFile
     405             :  * @param section   Name of section
     406             :  * @return number of section on success, else -1
     407             :  */
     408         540 : static int dlt_config_file_find_section(const DltConfigFile *file,
     409             :                                         const char *section)
     410             : {
     411             :     int i = 0;
     412             : 
     413         540 :     if ((file == NULL) || (section == NULL) || (file->num_sections <= 0)) {
     414           0 :         dlt_log(LOG_WARNING, "Section cannot be found due to invalid parameters\n");
     415           0 :         return -1;
     416             :     }
     417             : 
     418        2490 :     for (i = 0; i < file->num_sections; i++) {
     419        2486 :         DltConfigFileSection *s = &file->sections[i];
     420             : 
     421        2486 :         if (strncmp(s->name, section, DLT_CONFIG_FILE_ENTRY_MAX_LEN) == 0)
     422         536 :             return i;
     423             :     }
     424             : 
     425             :     return -1;
     426             : }
     427             : 
     428             : /************************** interface implementation ***************************/
     429          14 : DltConfigFile *dlt_config_file_init(char *file_name)
     430             : {
     431             :     DltConfigFile *file;
     432             :     FILE *hdl = NULL;
     433             : 
     434          14 :     if ((file_name == NULL) || (strlen(file_name) >= DLT_PATH_MAX)) {
     435           0 :         dlt_log(LOG_ERR, "Given configuration file invalid\n");
     436           0 :         return NULL;
     437             :     }
     438             : 
     439          14 :     file = calloc(sizeof(DltConfigFile), 1);
     440             : 
     441          14 :     if (file == NULL) {
     442           0 :         dlt_log(LOG_ERR, "Setup internal data structure to parse config file failed\n");
     443           0 :         return NULL;
     444             :     }
     445             : 
     446          14 :     file->sections = calloc(sizeof(DltConfigFileSection), DLT_CONFIG_FILE_SECTIONS_MAX);
     447             : 
     448             :     /* open file */
     449          14 :     if ((hdl = fopen(file_name, "r")) == NULL) {
     450           0 :         dlt_log(LOG_ERR, "Cannot open configuration file\n");
     451           0 :         free(file);
     452           0 :         return NULL;
     453             :     }
     454             : 
     455          14 :     dlt_config_file_read_file(file, hdl);
     456             : 
     457             :     /* all information stored internally */
     458          14 :     fclose(hdl);
     459             : 
     460          14 :     return file;
     461             : }
     462             : 
     463          14 : void dlt_config_file_release(DltConfigFile *file)
     464             : {
     465             :     int i = 0;
     466             : 
     467          14 :     if (file != NULL) {
     468          14 :         int max = file->num_sections;
     469             : 
     470          54 :         for (i = 0; i < max; i++) {
     471          40 :             DltConfigFileSection *s = &file->sections[i];
     472          40 :             DltConfigKeyData *node = file->sections[i].list;
     473          40 :             free(s->name);
     474             : 
     475          40 :             if (s->keys != NULL)
     476          40 :                 free(s->keys);
     477             : 
     478         379 :             while (node) {
     479             :                 DltConfigKeyData *tmp = node;
     480         339 :                 node = node->next;
     481         339 :                 free(tmp->key);
     482         339 :                 free(tmp->data);
     483         339 :                 free(tmp);
     484             :             }
     485             :         }
     486             : 
     487          14 :         free(file->sections);
     488          14 :         free(file);
     489             :     }
     490          14 : }
     491             : 
     492          40 : int dlt_config_file_get_section_name(const DltConfigFile *file,
     493             :                                      int num,
     494             :                                      char *name)
     495             : {
     496          40 :     if ((file == NULL) || (name == NULL) || (num < 0) || (num >= file->num_sections))
     497             :         return -1;
     498             : 
     499          40 :     strncpy(name, (file->sections + num)->name, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
     500          40 :     name[DLT_CONFIG_FILE_ENTRY_MAX_LEN - 1] = '\0';
     501             : 
     502          40 :     return 0;
     503             : }
     504             : 
     505          14 : int dlt_config_file_get_num_sections(const DltConfigFile *file, int *num)
     506             : {
     507          14 :     if ((file == NULL) || (file->num_sections < 0))
     508             :         return -1;
     509             : 
     510             :     /*
     511             :      * Note: Since General section could be used in configuration file,
     512             :      * this number could be also containing General section.
     513             :      */
     514          14 :     *num = file->num_sections;
     515             : 
     516          14 :     return 0;
     517             : }
     518             : 
     519         536 : int dlt_config_file_get_value(const DltConfigFile *file,
     520             :                               const char *section,
     521             :                               const char *key, char *value)
     522             : {
     523             :     DltConfigFileSection *s = NULL;
     524             :     DltConfigKeyData **tmp = NULL;
     525             :     int num_section = 0;
     526             : 
     527         536 :     if ((file == NULL) || (section == NULL) || (key == NULL) || (value == NULL))
     528             :         return -1;
     529             : 
     530             :     /* clean value */
     531             :     memset(value, 0, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
     532             : 
     533         536 :     num_section = dlt_config_file_find_section(file, section);
     534             : 
     535         536 :     if (num_section == -1)
     536             :         return -1;
     537             : 
     538         536 :     s = (file->sections + num_section);
     539             : 
     540         536 :     tmp = &s->list;
     541             : 
     542        3465 :     while (*(tmp) != NULL) {
     543        3264 :         if (strncmp((*tmp)->key, key, DLT_CONFIG_FILE_ENTRY_MAX_LEN) == 0) {
     544         335 :             strncpy(value, (*tmp)->data, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
     545         335 :             return 0;
     546             :         }
     547             :         else { /* not found yet see list for more */
     548        2929 :             tmp = &(*tmp)->next;
     549             :         }
     550             :     }
     551             : 
     552         201 :     dlt_vlog(LOG_WARNING, "Entry does not exist in section: %s\n", key);
     553         201 :     return -1;
     554             : }
     555             : 
     556           4 : int dlt_config_file_check_section_name_exists(const DltConfigFile *file,
     557             :                                              const char *name)
     558             : {
     559             :     int ret = 0;
     560             : 
     561           4 :     if ((file == NULL) || (file->num_sections <= 0) || (name == NULL))
     562             :         return -1;
     563             : 
     564           4 :     ret = dlt_config_file_find_section(file, name);
     565           4 :     if (ret == -1)
     566           4 :         return ret;
     567             : 
     568             :     return 0;
     569             : }

Generated by: LCOV version 1.14