New upstream version 18.11.2
[deb_dpdk.git] / lib / librte_cfgfile / rte_cfgfile.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <ctype.h>
9 #include <errno.h>
10 #include <rte_string_fns.h>
11 #include <rte_common.h>
12
13 #include "rte_cfgfile.h"
14
15 struct rte_cfgfile_section {
16         char name[CFG_NAME_LEN];
17         int num_entries;
18         int allocated_entries;
19         struct rte_cfgfile_entry *entries;
20 };
21
22 struct rte_cfgfile {
23         int flags;
24         int num_sections;
25         int allocated_sections;
26         struct rte_cfgfile_section *sections;
27 };
28
29 /** when we resize a file structure, how many extra entries
30  * for new sections do we add in */
31 #define CFG_ALLOC_SECTION_BATCH 8
32 /** when we resize a section structure, how many extra entries
33  * for new entries do we add in */
34 #define CFG_ALLOC_ENTRY_BATCH 16
35
36 /**
37  * Default cfgfile load parameters.
38  */
39 static const struct rte_cfgfile_parameters default_cfgfile_params = {
40         .comment_character = CFG_DEFAULT_COMMENT_CHARACTER,
41 };
42
43 /**
44  * Defines the list of acceptable comment characters supported by this
45  * library.
46  */
47 static const char valid_comment_chars[] = {
48         '!',
49         '#',
50         '%',
51         ';',
52         '@'
53 };
54
55 static unsigned
56 _strip(char *str, unsigned len)
57 {
58         int newlen = len;
59         if (len == 0)
60                 return 0;
61
62         if (isspace(str[len-1])) {
63                 /* strip trailing whitespace */
64                 while (newlen > 0 && isspace(str[newlen - 1]))
65                         str[--newlen] = '\0';
66         }
67
68         if (isspace(str[0])) {
69                 /* strip leading whitespace */
70                 int i, start = 1;
71                 while (isspace(str[start]) && start < newlen)
72                         start++
73                         ; /* do nothing */
74                 newlen -= start;
75                 for (i = 0; i < newlen; i++)
76                         str[i] = str[i+start];
77                 str[i] = '\0';
78         }
79         return newlen;
80 }
81
82 static struct rte_cfgfile_section *
83 _get_section(struct rte_cfgfile *cfg, const char *sectionname)
84 {
85         int i;
86
87         for (i = 0; i < cfg->num_sections; i++) {
88                 if (strncmp(cfg->sections[i].name, sectionname,
89                                 sizeof(cfg->sections[0].name)) == 0)
90                         return &cfg->sections[i];
91         }
92         return NULL;
93 }
94
95 static int
96 _add_entry(struct rte_cfgfile_section *section, const char *entryname,
97                 const char *entryvalue)
98 {
99         /* resize entry structure if we don't have room for more entries */
100         if (section->num_entries == section->allocated_entries) {
101                 struct rte_cfgfile_entry *n_entries = realloc(
102                                 section->entries,
103                                 sizeof(struct rte_cfgfile_entry) *
104                                 ((section->allocated_entries) +
105                                                 CFG_ALLOC_ENTRY_BATCH));
106
107                 if (n_entries == NULL)
108                         return -ENOMEM;
109
110                 section->entries = n_entries;
111                 section->allocated_entries += CFG_ALLOC_ENTRY_BATCH;
112         }
113         /* fill up entry fields with key name and value */
114         struct rte_cfgfile_entry *curr_entry =
115                                         &section->entries[section->num_entries];
116
117         snprintf(curr_entry->name, sizeof(curr_entry->name), "%s", entryname);
118         snprintf(curr_entry->value,
119                                 sizeof(curr_entry->value), "%s", entryvalue);
120         section->num_entries++;
121
122         return 0;
123 }
124
125 static int
126 rte_cfgfile_check_params(const struct rte_cfgfile_parameters *params)
127 {
128         unsigned int valid_comment;
129         unsigned int i;
130
131         if (!params) {
132                 printf("Error - missing cfgfile parameters\n");
133                 return -EINVAL;
134         }
135
136         valid_comment = 0;
137         for (i = 0; i < RTE_DIM(valid_comment_chars); i++) {
138                 if (params->comment_character == valid_comment_chars[i]) {
139                         valid_comment = 1;
140                         break;
141                 }
142         }
143
144         if (valid_comment == 0) {
145                 printf("Error - invalid comment characters %c\n",
146                        params->comment_character);
147                 return -ENOTSUP;
148         }
149
150         return 0;
151 }
152
153 struct rte_cfgfile *
154 rte_cfgfile_load(const char *filename, int flags)
155 {
156         return rte_cfgfile_load_with_params(filename, flags,
157                                             &default_cfgfile_params);
158 }
159
160 struct rte_cfgfile *
161 rte_cfgfile_load_with_params(const char *filename, int flags,
162                              const struct rte_cfgfile_parameters *params)
163 {
164         char buffer[CFG_NAME_LEN + CFG_VALUE_LEN + 4] = {0};
165         int lineno = 0;
166         struct rte_cfgfile *cfg = NULL;
167
168         if (rte_cfgfile_check_params(params))
169                 return NULL;
170
171         FILE *f = fopen(filename, "r");
172         if (f == NULL)
173                 return NULL;
174
175         cfg = rte_cfgfile_create(flags);
176
177         while (fgets(buffer, sizeof(buffer), f) != NULL) {
178                 char *pos = NULL;
179                 size_t len = strnlen(buffer, sizeof(buffer));
180                 lineno++;
181                 if ((len >= sizeof(buffer) - 1) && (buffer[len-1] != '\n')) {
182                         printf("Error line %d - no \\n found on string. "
183                                         "Check if line too long\n", lineno);
184                         goto error1;
185                 }
186                 /* skip parsing if comment character found */
187                 pos = memchr(buffer, params->comment_character, len);
188                 if (pos != NULL && (*(pos-1) != '\\')) {
189                         *pos = '\0';
190                         len = pos -  buffer;
191                 }
192
193                 len = _strip(buffer, len);
194                 /* skip lines without useful content */
195                 if (buffer[0] != '[' && memchr(buffer, '=', len) == NULL)
196                         continue;
197
198                 if (buffer[0] == '[') {
199                         /* section heading line */
200                         char *end = memchr(buffer, ']', len);
201                         if (end == NULL) {
202                                 printf("Error line %d - no terminating ']'"
203                                         "character found\n", lineno);
204                                 goto error1;
205                         }
206                         *end = '\0';
207                         _strip(&buffer[1], end - &buffer[1]);
208
209                         rte_cfgfile_add_section(cfg, &buffer[1]);
210                 } else {
211                         /* key and value line */
212                         char *split[2] = {NULL};
213
214                         split[0] = buffer;
215                         split[1] = memchr(buffer, '=', len);
216                         if (split[1] == NULL) {
217                                 printf("Error line %d - no '='"
218                                         "character found\n", lineno);
219                                 goto error1;
220                         }
221                         *split[1] = '\0';
222                         split[1]++;
223
224                         _strip(split[0], strlen(split[0]));
225                         _strip(split[1], strlen(split[1]));
226                         char *end = memchr(split[1], '\\', strlen(split[1]));
227
228                         size_t split_len = strlen(split[1]) + 1;
229                         while (end != NULL) {
230                                 if (*(end+1) == params->comment_character) {
231                                         *end = '\0';
232                                         strlcat(split[1], end+1, split_len);
233                                 } else
234                                         end++;
235                                 end = memchr(end, '\\', strlen(end));
236                         }
237
238                         if (!(flags & CFG_FLAG_EMPTY_VALUES) &&
239                                         (*split[1] == '\0')) {
240                                 printf("Error at line %d - cannot use empty "
241                                                         "values\n", lineno);
242                                 goto error1;
243                         }
244
245                         if (cfg->num_sections == 0)
246                                 goto error1;
247
248                         _add_entry(&cfg->sections[cfg->num_sections - 1],
249                                         split[0], split[1]);
250                 }
251         }
252         fclose(f);
253         return cfg;
254 error1:
255         rte_cfgfile_close(cfg);
256         fclose(f);
257         return NULL;
258 }
259
260 struct rte_cfgfile *
261 rte_cfgfile_create(int flags)
262 {
263         int i;
264         struct rte_cfgfile *cfg = NULL;
265
266         cfg = malloc(sizeof(*cfg));
267
268         if (cfg == NULL)
269                 return NULL;
270
271         cfg->flags = flags;
272         cfg->num_sections = 0;
273
274         /* allocate first batch of sections and entries */
275         cfg->sections = malloc(sizeof(struct rte_cfgfile_section) *
276                         CFG_ALLOC_SECTION_BATCH);
277
278         if (cfg->sections == NULL)
279                 goto error1;
280
281         cfg->allocated_sections = CFG_ALLOC_SECTION_BATCH;
282
283         for (i = 0; i < CFG_ALLOC_SECTION_BATCH; i++) {
284                 cfg->sections[i].entries = malloc(sizeof(
285                         struct rte_cfgfile_entry) * CFG_ALLOC_ENTRY_BATCH);
286
287                 if (cfg->sections[i].entries == NULL)
288                         goto error1;
289
290                 cfg->sections[i].num_entries = 0;
291                 cfg->sections[i].allocated_entries = CFG_ALLOC_ENTRY_BATCH;
292         }
293
294         if (flags & CFG_FLAG_GLOBAL_SECTION)
295                 rte_cfgfile_add_section(cfg, "GLOBAL");
296
297         return cfg;
298 error1:
299         if (cfg->sections != NULL) {
300                 for (i = 0; i < cfg->allocated_sections; i++) {
301                         if (cfg->sections[i].entries != NULL) {
302                                 free(cfg->sections[i].entries);
303                                 cfg->sections[i].entries = NULL;
304                         }
305                 }
306                 free(cfg->sections);
307                 cfg->sections = NULL;
308         }
309         free(cfg);
310         return NULL;
311 }
312
313 int
314 rte_cfgfile_add_section(struct rte_cfgfile *cfg, const char *sectionname)
315 {
316         int i;
317
318         if (cfg == NULL)
319                 return -EINVAL;
320
321         if (sectionname == NULL)
322                 return -EINVAL;
323
324         /* resize overall struct if we don't have room for more sections */
325         if (cfg->num_sections == cfg->allocated_sections) {
326
327                 struct rte_cfgfile_section *n_sections =
328                                 realloc(cfg->sections,
329                                 sizeof(struct rte_cfgfile_section) *
330                                 ((cfg->allocated_sections) +
331                                 CFG_ALLOC_SECTION_BATCH));
332
333                 if (n_sections == NULL)
334                         return -ENOMEM;
335
336                 for (i = 0; i < CFG_ALLOC_SECTION_BATCH; i++) {
337                         n_sections[i + cfg->allocated_sections].num_entries = 0;
338                         n_sections[i +
339                                  cfg->allocated_sections].allocated_entries = 0;
340                         n_sections[i + cfg->allocated_sections].entries = NULL;
341                 }
342                 cfg->sections = n_sections;
343                 cfg->allocated_sections += CFG_ALLOC_SECTION_BATCH;
344         }
345
346         snprintf(cfg->sections[cfg->num_sections].name,
347                         sizeof(cfg->sections[0].name), "%s", sectionname);
348         cfg->sections[cfg->num_sections].num_entries = 0;
349         cfg->num_sections++;
350
351         return 0;
352 }
353
354 int rte_cfgfile_add_entry(struct rte_cfgfile *cfg,
355                 const char *sectionname, const char *entryname,
356                 const char *entryvalue)
357 {
358         int ret;
359
360         if ((cfg == NULL) || (sectionname == NULL) || (entryname == NULL)
361                         || (entryvalue == NULL))
362                 return -EINVAL;
363
364         if (rte_cfgfile_has_entry(cfg, sectionname, entryname) != 0)
365                 return -EEXIST;
366
367         /* search for section pointer by sectionname */
368         struct rte_cfgfile_section *curr_section = _get_section(cfg,
369                                                                 sectionname);
370         if (curr_section == NULL)
371                 return -EINVAL;
372
373         ret = _add_entry(curr_section, entryname, entryvalue);
374
375         return ret;
376 }
377
378 int rte_cfgfile_set_entry(struct rte_cfgfile *cfg, const char *sectionname,
379                 const char *entryname, const char *entryvalue)
380 {
381         int i;
382
383         if ((cfg == NULL) || (sectionname == NULL) || (entryname == NULL))
384                 return -EINVAL;
385
386         /* search for section pointer by sectionname */
387         struct rte_cfgfile_section *curr_section = _get_section(cfg,
388                                                                 sectionname);
389         if (curr_section == NULL)
390                 return -EINVAL;
391
392         if (entryvalue == NULL)
393                 entryvalue = "";
394
395         for (i = 0; i < curr_section->num_entries; i++)
396                 if (!strcmp(curr_section->entries[i].name, entryname)) {
397                         snprintf(curr_section->entries[i].value,
398                                         sizeof(curr_section->entries[i].value),
399                                                         "%s", entryvalue);
400                         return 0;
401                 }
402         printf("Error - entry name doesn't exist\n");
403         return -EINVAL;
404 }
405
406 int rte_cfgfile_save(struct rte_cfgfile *cfg, const char *filename)
407 {
408         int i, j;
409
410         if ((cfg == NULL) || (filename == NULL))
411                 return -EINVAL;
412
413         FILE *f = fopen(filename, "w");
414
415         if (f == NULL)
416                 return -EINVAL;
417
418         for (i = 0; i < cfg->num_sections; i++) {
419                 fprintf(f, "[%s]\n", cfg->sections[i].name);
420
421                 for (j = 0; j < cfg->sections[i].num_entries; j++) {
422                         fprintf(f, "%s=%s\n",
423                                         cfg->sections[i].entries[j].name,
424                                         cfg->sections[i].entries[j].value);
425                 }
426         }
427         return fclose(f);
428 }
429
430 int rte_cfgfile_close(struct rte_cfgfile *cfg)
431 {
432         int i;
433
434         if (cfg == NULL)
435                 return -1;
436
437         if (cfg->sections != NULL) {
438                 for (i = 0; i < cfg->allocated_sections; i++) {
439                         if (cfg->sections[i].entries != NULL) {
440                                 free(cfg->sections[i].entries);
441                                 cfg->sections[i].entries = NULL;
442                         }
443                 }
444                 free(cfg->sections);
445                 cfg->sections = NULL;
446         }
447         free(cfg);
448         cfg = NULL;
449
450         return 0;
451 }
452
453 int
454 rte_cfgfile_num_sections(struct rte_cfgfile *cfg, const char *sectionname,
455 size_t length)
456 {
457         int i;
458         int num_sections = 0;
459         for (i = 0; i < cfg->num_sections; i++) {
460                 if (strncmp(cfg->sections[i].name, sectionname, length) == 0)
461                         num_sections++;
462         }
463         return num_sections;
464 }
465
466 int
467 rte_cfgfile_sections(struct rte_cfgfile *cfg, char *sections[],
468         int max_sections)
469 {
470         int i;
471
472         for (i = 0; i < cfg->num_sections && i < max_sections; i++)
473                 snprintf(sections[i], CFG_NAME_LEN, "%s",
474                 cfg->sections[i].name);
475
476         return i;
477 }
478
479 int
480 rte_cfgfile_has_section(struct rte_cfgfile *cfg, const char *sectionname)
481 {
482         return _get_section(cfg, sectionname) != NULL;
483 }
484
485 int
486 rte_cfgfile_section_num_entries(struct rte_cfgfile *cfg,
487         const char *sectionname)
488 {
489         const struct rte_cfgfile_section *s = _get_section(cfg, sectionname);
490         if (s == NULL)
491                 return -1;
492         return s->num_entries;
493 }
494
495 int
496 rte_cfgfile_section_num_entries_by_index(struct rte_cfgfile *cfg,
497         char *sectionname, int index)
498 {
499         if (index < 0 || index >= cfg->num_sections)
500                 return -1;
501
502         const struct rte_cfgfile_section *sect = &(cfg->sections[index]);
503
504         snprintf(sectionname, CFG_NAME_LEN, "%s", sect->name);
505         return sect->num_entries;
506 }
507 int
508 rte_cfgfile_section_entries(struct rte_cfgfile *cfg, const char *sectionname,
509                 struct rte_cfgfile_entry *entries, int max_entries)
510 {
511         int i;
512         const struct rte_cfgfile_section *sect = _get_section(cfg, sectionname);
513         if (sect == NULL)
514                 return -1;
515         for (i = 0; i < max_entries && i < sect->num_entries; i++)
516                 entries[i] = sect->entries[i];
517         return i;
518 }
519
520 int
521 rte_cfgfile_section_entries_by_index(struct rte_cfgfile *cfg, int index,
522                 char *sectionname,
523                 struct rte_cfgfile_entry *entries, int max_entries)
524 {
525         int i;
526         const struct rte_cfgfile_section *sect;
527
528         if (index < 0 || index >= cfg->num_sections)
529                 return -1;
530         sect = &cfg->sections[index];
531         snprintf(sectionname, CFG_NAME_LEN, "%s", sect->name);
532         for (i = 0; i < max_entries && i < sect->num_entries; i++)
533                 entries[i] = sect->entries[i];
534         return i;
535 }
536
537 const char *
538 rte_cfgfile_get_entry(struct rte_cfgfile *cfg, const char *sectionname,
539                 const char *entryname)
540 {
541         int i;
542         const struct rte_cfgfile_section *sect = _get_section(cfg, sectionname);
543         if (sect == NULL)
544                 return NULL;
545         for (i = 0; i < sect->num_entries; i++)
546                 if (strncmp(sect->entries[i].name, entryname, CFG_NAME_LEN)
547                                                                         == 0)
548                         return sect->entries[i].value;
549         return NULL;
550 }
551
552 int
553 rte_cfgfile_has_entry(struct rte_cfgfile *cfg, const char *sectionname,
554                 const char *entryname)
555 {
556         return rte_cfgfile_get_entry(cfg, sectionname, entryname) != NULL;
557 }