LCOV - code coverage report
Current view: top level - shared - dlt_config_file_parser.c (source / functions) Coverage Total Hit
Test: dlt_final_coverage.info Lines: 83.8 % 167 140
Test Date: 2026-08-27 10:11:10 Functions: 100.0 % 15 15

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

Generated by: LCOV version 2.0-1