automotive-dlt
dlt_config_file_parser.c
Go to the documentation of this file.
1 /*
2  * @licence app begin@
3  * SPDX license identifier: MPL-2.0
4  *
5  * Copyright (C) 2015, Advanced Driver Information Technology
6  * This code is developed by Advanced Driver Information Technology.
7  * Copyright of Advanced Driver Information Technology, Bosch and DENSO.
8  *
9  * This file is part of GENIVI Project DLT - Diagnostic Log and Trace.
10  *
11  * This Source Code Form is subject to the terms of the
12  * Mozilla Public License (MPL), v. 2.0.
13  * If a copy of the MPL was not distributed with this file,
14  * You can obtain one at http://mozilla.org/MPL/2.0/.
15  *
16  * For further information see http://www.genivi.org/.
17  * @licence end@
18  */
19 
30 #include "dlt_config_file_parser.h"
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <syslog.h>
36 #include "dlt_common.h"
37 #include "dlt-daemon_cfg.h"
38 
39 /* internal defines */
40 #define DLT_CONFIG_FILE_NEW_SECTION 0x0a
41 #define DLT_CONFIG_FILE_NEW_DATA 0x0b
42 
43 
44 /* internal helper functions */
45 
53 static void dlt_config_file_trim_line(char *line)
54 {
55  if (line == NULL)
56  return;
57 
58  char *i = line;
59  char *j = line;
60 
61  while(*j != '\0')
62  {
63  *i = *j++;
64  if(!isspace(*i))
65  i++;
66  }
67  *i = '\0';
68 }
69 
78 static int dlt_config_file_ignore_line(char *line)
79 {
80  int i = 0;
81  int len = strlen(line);
82 
83  for (i = 0; i < len; i++)
84  {
85  if (line[i] == '#' || line[i] == ';' || line[i] == '\n' || line[i] == '\0')
86  return 0; /* ignore */
87  else
88  return -1; /* do not ignore */
89  }
90 
91  return -1;
92 }
93 
103 static int dlt_config_file_is_section_name(DltConfigFile *file, char *name)
104 {
105  int i = 0;
106 
107  if (file == NULL || name == NULL)
108  return -1;
109 
110  for (i = 0; i < file->num_sections; i++)
111  {
112  DltConfigFileSection *s = &file->sections[i];
113 
114  if (strncmp(s->name, name, DLT_CONFIG_FILE_ENTRY_MAX_LEN) == 0)
115  return -1;
116  }
117 
118  return 0; /* section name not used */
119 }
120 
130 static int dlt_config_file_set_section(DltConfigFile *file, char *name)
131 {
132  int section = file->num_sections;
133  /* check if adding another section would exceed max number of sections */
134  if (section+1 >= DLT_CONFIG_FILE_SECTIONS_MAX)
135  {
136  dlt_log(LOG_WARNING, "Cannot store more sections\n");
137  return -1; /* reached max number of sections */
138  }
139 
140  /* do not store section with same name again */
141  if (dlt_config_file_is_section_name(file, name) != 0)
142  {
143  dlt_log(LOG_WARNING, "Cannot store section name again\n");
144  return -1;
145  }
146 
147  DltConfigFileSection *s = &file->sections[section];
148 
149  /* alloc data for entries */
150  s->name = calloc(sizeof(char), DLT_CONFIG_FILE_ENTRY_MAX_LEN + 1);
151  if (s->name == NULL)
152  {
153  dlt_log(LOG_ERR, "Cannot allocate memory for internal data structure\n");
154  return -1;
155  }
156 
157  s->keys = calloc(sizeof(char), DLT_CONFIG_FILE_ENTRY_MAX_LEN * DLT_CONFIG_FILE_KEYS_MAX + 1);
158  if (s->keys == NULL)
159  {
160  free(s->name);
161  dlt_log(LOG_ERR, "Cannot allocate memory for internal data structure\n");
162  return -1;
163  }
164 
165  /* create hsearch table for data inside the section */
166  if (hcreate_r(DLT_CONFIG_FILE_KEYS_MAX, &s->data) == 0)
167  {
168  dlt_log(LOG_ERR, "Cannot create hash table object\n");
169  free(s->name);
170  free(s->keys);
171  return -1;
172  }
173 
174  strncpy(file->sections[section].name, name, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
175  file->num_sections += 1;
176  return 0;
177 }
178 
189 static int dlt_config_file_set_section_data(DltConfigFile *file, char *str1, char *str2)
190 {
191  ENTRY item;
192  ENTRY *ret;
193 
194  if (file == NULL || str1 == NULL || str2 == NULL)
195  return -1;
196 
197  DltConfigFileSection *s = &file->sections[file->num_sections-1];
198  int key_number = s->num_entries;
199 
200  if (key_number+1 >= DLT_CONFIG_FILE_KEYS_MAX)
201  {
202  dlt_log(LOG_WARNING, "Cannot store more keys in section\n");
203  return -1; /* reached max number of keys per section */
204  }
205 
206  /* copy data into structure */
207  strncpy(&s->keys[key_number * DLT_CONFIG_FILE_ENTRY_MAX_LEN], str1, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
208 
209  item.key = strdup(str1);
210  item.data = strdup(str2);
211 
212  /* check if already stored */
213  if (hsearch_r(item, FIND, &ret, &s->data) == 0)
214  {
215  if (hsearch_r(item, ENTER, &ret, &s->data) == 0)
216  {
217  free(item.key);
218  free(item.data);
219 
220  dlt_log(LOG_ERR, "Cannot add data to hash table\n");
221  return -1;
222  }
223  }
224  else /* already exist, ignore */
225  {
226  char error_str[DLT_DAEMON_TEXTBUFSIZE] = {'\0'};
227  snprintf(error_str, DLT_DAEMON_TEXTBUFSIZE, "Key \"%s\" already exists! New data will be ignored\n", item.key);
228  dlt_log(LOG_WARNING, error_str);
229  return -1;
230  }
231 
232  s->num_entries += 1;
233 
234  return 0;
235 }
236 
245 static int dlt_config_file_line_has_section(char *line)
246 {
247  line = line; /* avoid compiler warnings */
248  if(line[0] == '[') /* section found */
249  return 0;
250  else
251  return -1;
252 }
253 
262 static int dlt_config_file_get_section_name_from_string(char *line, char *name)
263 {
264  int i = 0;
265  int j = 0;
266 
267  if (line == NULL || name == NULL)
268  return -1;
269 
270  for(i = 0; i < DLT_CONFIG_FILE_ENTRY_MAX_LEN; i++)
271  {
272  if(line[i] == '[' || isspace(line[i]))
273  continue;
274  else if (line[i] == ']' || line[i] == '\n' || line[i] == '\0')
275  break;
276  else
277  name[j++] = line[i];
278  }
279 
280  return 0;
281 }
282 
293 static int dlt_config_file_get_key_value(char *line, char *str1, char *str2)
294 {
295  char *delimiter = "=";
296  char *ptr;
297  char *save_ptr;
298 
299  if (line == NULL || str1 == NULL || str2 == NULL)
300  return -1;
301 
302  ptr = strtok_r(line, delimiter, &save_ptr);
303 
304  if (ptr != NULL) /* get key */
305  strncpy(str1, ptr, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
306  else
307  return -1;
308 
309  ptr = strtok_r(NULL, delimiter, &save_ptr);
310 
311  if (ptr != NULL)
312  strncpy(str2, ptr, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
313  else
314  return -1;
315 
316  return 0;
317 }
318 
329 static int dlt_config_file_read_line(char *line, char *str1, char *str2)
330 {
331  if (line == NULL || str1 == NULL || str2 == NULL)
332  return -1;
333 
334  /* reset values to zero */
335  memset(str1, 0, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
336  memset(str2, 0, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
337 
338  /* check if line contains a section */
339  if ((dlt_config_file_line_has_section(line)) == 0)
340  {
341  /* retrieve section name */
343  return -1;
344 
346  }
347 
348  /* copy strings as key value pair into str1, str2 */
349  if (dlt_config_file_get_key_value(line, str1, str2) != 0)
350  return -1;
351 
353 }
354 
363 static void dlt_config_file_read_file(DltConfigFile *file, FILE *hdl)
364 {
365  int ret = 0;
366  char error_str[DLT_DAEMON_TEXTBUFSIZE] = {'\0'};
367  char line[DLT_CONFIG_FILE_LINE_MAX_LEN] = {'\0'};
368  char str1[DLT_CONFIG_FILE_ENTRY_MAX_LEN] = {'\0'};
369  char str2[DLT_CONFIG_FILE_ENTRY_MAX_LEN] = {'\0'};
370  int line_number = 0;
371  int is_section_valid = -1; /* to check if section name is given twice or invalid */
372 
373  /* read configuration file line by line */
374  while (fgets(line, DLT_CONFIG_FILE_LINE_MAX_LEN, hdl) != NULL)
375  {
376  line_number++;
377 
378  /* ignore empty and comment lines */
379  if (dlt_config_file_ignore_line(line) == 0)
380  continue;
381 
382  /* trim line end */
384 
385  /* parse content of line */
386  ret = dlt_config_file_read_line(line, str1, str2);
387 
388  switch(ret)
389  {
390  case DLT_CONFIG_FILE_NEW_SECTION: /* store str1 as new section */
391  is_section_valid = -1;
392  if ((ret = dlt_config_file_set_section(file, str1)) == 0)
393  {
394  is_section_valid = 0;
395  }
396  break;
397  case DLT_CONFIG_FILE_NEW_DATA: /* store str1 and str2 as new data for section */
398  if (is_section_valid == 0)
399  {
400  ret = dlt_config_file_set_section_data(file, str1, str2);
401  }
402  break;
403  default: /* something is wrong with the line */
404  snprintf(error_str, DLT_DAEMON_TEXTBUFSIZE, "Line (%d) \"%s\" is invalid\n", line_number, line);
405  dlt_log(LOG_WARNING, error_str);
406  }
407  }
408 }
409 
420  const char *section)
421 {
422  int i = 0;
423 
424  if (file == NULL || section == NULL || file->num_sections <= 0)
425  {
426  dlt_log(LOG_WARNING, "Section cannot be found due to invalid parameters\n");
427  return -1;
428  }
429 
430  for (i = 0; i < file->num_sections; i++)
431  {
432  DltConfigFileSection *s = &file->sections[i];
433  if (strncmp(s->name, section, DLT_CONFIG_FILE_ENTRY_MAX_LEN) == 0)
434  return i;
435  }
436 
437  return -1;
438 }
439 
440 /************************** interface implementation ***************************/
442 {
443  DltConfigFile *file;
444  FILE *hdl = NULL;
445 
446  if (file_name == NULL || (strlen(file_name) >= DLT_CONFIG_FILE_PATH_MAX_LEN))
447  {
448  dlt_log(LOG_ERR, "Given configuration file invalid\n");
449  return NULL;
450  }
451 
452  file = calloc(sizeof(DltConfigFile), 1);
453  if (file == NULL)
454  {
455  dlt_log(LOG_ERR, "Setup internal data structure to parse config file failed\n");
456  return NULL;
457  }
458 
460 
461  /* open file */
462  if ((hdl = fopen(file_name, "r")) == NULL)
463  {
464  dlt_log(LOG_ERR, "Cannot open configuration file\n");
465  free(file);
466  return NULL;
467  }
468 
469  dlt_config_file_read_file(file, hdl);
470 
471  /* all information stored internally */
472  fclose(hdl);
473 
474  return file;
475 }
476 
478 {
479  int i = 0;
480  int j = 0;
481  ENTRY entry;
482  ENTRY *found;
483 
484  if(file != NULL){
485  int max = file->num_sections;
486  for (i = 0; i < max; i++)
487  {
488  DltConfigFileSection *s = &file->sections[i];
489  free(s->name);
490 
491  /* free data in hashtable */
492  if (s->keys != NULL || &s->data != NULL)
493  {
494  for (j = 0; j < s->num_entries; j++)
495  {
496  entry.key = (s->keys + j * DLT_CONFIG_FILE_ENTRY_MAX_LEN);
497  hsearch_r (entry, FIND, &found, &s->data);
498  free(found->key);
499  free(found->data);
500  }
501 
502  hdestroy_r(&s->data);
503  free(s->keys);
504  }
505  }
506 
507  free(file->sections);
508  free(file);
509  }
510 }
511 
513  int num,
514  char *name)
515 {
516  if (file == NULL || name == NULL || num < 0 || num >= file->num_sections)
517  return -1;
518 
519  strncpy(name, (file->sections + num)->name, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
520 
521  return 0;
522 }
523 
525 {
526  if(file == NULL || file->num_sections < 0)
527  return -1;
528 
529  *num = file->num_sections;
530 
531  return 0;
532 }
533 
535  const char *section,
536  const char *key, char *value)
537 {
539  int num_section = 0;
540  ENTRY entry;
541  ENTRY *found;
542 
543  if (file == NULL || section == NULL || key == NULL || value == NULL)
544  return -1;
545 
546  /* clean value */
547  memset(value, 0, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
548 
549  num_section = dlt_config_file_find_section(file, section);
550  if (num_section == -1)
551  return -1;
552 
553  s = (file->sections + num_section);
554 
555  /* check if available */
556  entry.key = strdup(key);
557  if (entry.key == NULL)
558  {
559  dlt_log(LOG_CRIT, "Not enougth memory to duplicate key string\n");
560  return -1;
561  }
562 
563  if (hsearch_r(entry, FIND, &found, &s->data) == 0) /* not found */
564  {
565  dlt_log(LOG_WARNING, "Entry does not exist in section\n");
566  free(entry.key);
567  return -1;
568  }
569  else /* found */
570  {
571  strncpy(value, (char *)found->data, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
572  free(entry.key);
573  return 0;
574  }
575 }
static int dlt_config_file_get_key_value(char *line, char *str1, char *str2)
int dlt_config_file_get_section_name(const DltConfigFile *file, int num, char *name)
#define DLT_CONFIG_FILE_NEW_SECTION
static int dlt_config_file_line_has_section(char *line)
int dlt_config_file_get_num_sections(const DltConfigFile *file, int *num)
static void dlt_config_file_trim_line(char *line)
static void dlt_config_file_read_file(DltConfigFile *file, FILE *hdl)
#define DLT_CONFIG_FILE_ENTRY_MAX_LEN
DltConfigFile * dlt_config_file_init(char *file_name)
#define DLT_CONFIG_FILE_SECTIONS_MAX
static int dlt_config_file_set_section(DltConfigFile *file, char *name)
DltReturnValue dlt_log(int prio, char *s)
Definition: dlt_common.c:2029
static int dlt_config_file_find_section(const DltConfigFile *file, const char *section)
DltConfigFileSection * sections
#define DLT_CONFIG_FILE_LINE_MAX_LEN
#define DLT_CONFIG_FILE_PATH_MAX_LEN
static int dlt_config_file_set_section_data(DltConfigFile *file, char *str1, char *str2)
struct hsearch_data data
static int dlt_config_file_ignore_line(char *line)
#define DLT_CONFIG_FILE_NEW_DATA
int dlt_config_file_get_value(const DltConfigFile *file, const char *section, const char *key, char *value)
static int dlt_config_file_get_section_name_from_string(char *line, char *name)
#define DLT_CONFIG_FILE_KEYS_MAX
static int dlt_config_file_is_section_name(DltConfigFile *file, char *name)
static int dlt_config_file_read_line(char *line, char *str1, char *str2)
#define DLT_DAEMON_TEXTBUFSIZE
void dlt_config_file_release(DltConfigFile *file)
#define NULL
Definition: dlt_common.h:232