1 /*
2 INI LIBRARY
3
4 Value interpretation functions for single values
5 and corresponding memory cleanup functions.
6
7 Copyright (C) Dmitri Pal <dpal@redhat.com> 2010
8
9 INI Library is free software: you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 INI Library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public License
20 along with INI Library. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "config.h"
24 #include <stdio.h>
25 #include <errno.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include "trace.h"
30 #include "collection.h"
31 #include "collection_tools.h"
32 #include "ini_defines.h"
33 #include "ini_config.h"
34
35 /* Function to get value from the configuration handle */
get_config_item(const char * section,const char * name,struct collection_item * ini_config,struct collection_item ** item)36 int get_config_item(const char *section,
37 const char *name,
38 struct collection_item *ini_config,
39 struct collection_item **item)
40 {
41 int error = EOK;
42 struct collection_item *section_handle = NULL;
43 const char *to_find;
44 char default_section[] = INI_DEFAULT_SECTION;
45
46 TRACE_FLOW_STRING("get_config_item", "Entry");
47
48 /* Do we have the accepting memory ? */
49 if (item == NULL) {
50 TRACE_ERROR_NUMBER("No buffer - invalid argument.", EINVAL);
51 return EINVAL;
52 }
53
54 /* Is the collection of a right type */
55 if ((col_is_of_class(ini_config, COL_CLASS_INI_CONFIG) == 0) &&
56 (col_is_of_class(ini_config, COL_CLASS_INI_META) == 0)) {
57 TRACE_ERROR_NUMBER("Wrong collection type", EINVAL);
58 return EINVAL;
59 }
60
61 *item = NULL;
62
63 if (section == NULL) to_find = default_section;
64 else to_find = section;
65
66 TRACE_INFO_STRING("Getting Name:", name);
67 TRACE_INFO_STRING("In Section:", section);
68
69 /* Get Subcollection */
70 error = col_get_collection_reference(ini_config, §ion_handle, to_find);
71 /* Check error */
72 if (error && (error != ENOENT)) {
73 TRACE_ERROR_NUMBER("Failed to get section", error);
74 return error;
75 }
76
77 /* Did we find a section */
78 if ((error == ENOENT) || (section_handle == NULL)) {
79 /* We have not found section - return success */
80 TRACE_FLOW_STRING("get_value_from_config", "No such section");
81 return EOK;
82 }
83
84 /* Get item */
85 error = col_get_item(section_handle, name,
86 COL_TYPE_STRING, COL_TRAVERSE_ONELEVEL, item);
87
88 /* Make sure we free the section we found */
89 col_destroy_collection(section_handle);
90
91 TRACE_FLOW_NUMBER("get_config_item returning", error);
92 return error;
93 }
94
95 /* Get long long value from config item */
get_llong_config_value(struct collection_item * item,int strict,long long def,int * error)96 static long long get_llong_config_value(struct collection_item *item,
97 int strict,
98 long long def,
99 int *error)
100 {
101 int err;
102 const char *str;
103 char *endptr;
104 long long val = 0;
105
106 TRACE_FLOW_STRING("get_llong_config_value", "Entry");
107
108 /* Do we have the item ? */
109 if ((item == NULL) ||
110 (col_get_item_type(item) != COL_TYPE_STRING)) {
111 TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
112 if (error) *error = EINVAL;
113 return def;
114 }
115
116 if (error) *error = EOK;
117
118 /* Try to parse the value */
119 str = (const char *)col_get_item_data(item);
120 errno = 0;
121 val = strtoll(str, &endptr, 10);
122 err = errno;
123
124 /* Check for various possible errors */
125 if (err != 0) {
126 TRACE_ERROR_NUMBER("Conversion failed", err);
127 if (error) *error = err;
128 return def;
129 }
130
131 /* Other error cases */
132 if ((endptr == str) || (strict && (*endptr != '\0'))) {
133 TRACE_ERROR_NUMBER("More characters or nothing processed", EIO);
134 if (error) *error = EIO;
135 return def;
136 }
137
138 TRACE_FLOW_NUMBER("get_llong_config_value returning", (long)val);
139 return val;
140 }
141
142 /* Get unsigned long long value from config item */
get_ullong_config_value(struct collection_item * item,int strict,unsigned long long def,int * error)143 static unsigned long long get_ullong_config_value(struct collection_item *item,
144 int strict,
145 unsigned long long def,
146 int *error)
147 {
148 int err;
149 const char *str;
150 char *endptr;
151 unsigned long long val = 0;
152
153 TRACE_FLOW_STRING("get_ullong_config_value", "Entry");
154
155 /* Do we have the item ? */
156 if ((item == NULL) ||
157 (col_get_item_type(item) != COL_TYPE_STRING)) {
158 TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
159 if (error) *error = EINVAL;
160 return def;
161 }
162
163 if (error) *error = EOK;
164
165 /* Try to parse the value */
166 str = (const char *)col_get_item_data(item);
167 errno = 0;
168 val = strtoull(str, &endptr, 10);
169 err = errno;
170
171 /* Check for various possible errors */
172 if (err != 0) {
173 TRACE_ERROR_NUMBER("Conversion failed", err);
174 if (error) *error = err;
175 return def;
176 }
177
178 /* Other error cases */
179 if ((endptr == str) || (strict && (*endptr != '\0'))) {
180 TRACE_ERROR_NUMBER("More characters or nothing processed", EIO);
181 if (error) *error = EIO;
182 return def;
183 }
184
185 TRACE_FLOW_NUMBER("get_ullong_config_value returning", val);
186 return val;
187 }
188
189
190 /* Get integer value from config item */
get_int_config_value(struct collection_item * item,int strict,int def,int * error)191 int get_int_config_value(struct collection_item *item,
192 int strict,
193 int def,
194 int *error)
195 {
196 long long val = 0;
197 int err = 0;
198
199 TRACE_FLOW_STRING("get_int_config_value", "Entry");
200
201 val = get_llong_config_value(item, strict, def, &err);
202 if (err == 0) {
203 if ((val > INT_MAX) || (val < INT_MIN)) {
204 val = def;
205 err = ERANGE;
206 }
207 }
208
209 if (error) *error = err;
210
211 TRACE_FLOW_NUMBER("get_int_config_value returning", (int)val);
212 return (int)val;
213 }
214
215 /* Get unsigned integer value from config item */
get_unsigned_config_value(struct collection_item * item,int strict,unsigned def,int * error)216 unsigned get_unsigned_config_value(struct collection_item *item,
217 int strict,
218 unsigned def,
219 int *error)
220 {
221 unsigned long long val = 0;
222 int err = 0;
223
224 TRACE_FLOW_STRING("get_unsigned_config_value", "Entry");
225
226 val = get_ullong_config_value(item, strict, def, &err);
227 if (err == 0) {
228 if (val > UINT_MAX) {
229 val = def;
230 err = ERANGE;
231 }
232 }
233
234 if (error) *error = err;
235
236 TRACE_FLOW_NUMBER("get_unsigned_config_value returning",
237 (unsigned)val);
238 return (unsigned)val;
239 }
240
241 /* Get long value from config item */
get_long_config_value(struct collection_item * item,int strict,long def,int * error)242 long get_long_config_value(struct collection_item *item,
243 int strict,
244 long def,
245 int *error)
246 {
247 long long val = 0;
248 int err = 0;
249
250 TRACE_FLOW_STRING("get_long_config_value", "Entry");
251
252 val = get_llong_config_value(item, strict, def, &err);
253 if (err == 0) {
254 if ((val > LONG_MAX) || (val < LONG_MIN)) {
255 val = def;
256 err = ERANGE;
257 }
258 }
259
260 if (error) *error = err;
261
262 TRACE_FLOW_NUMBER("get_long_config_value returning",
263 (long)val);
264 return (long)val;
265 }
266
267 /* Get unsigned long value from config item */
get_ulong_config_value(struct collection_item * item,int strict,unsigned long def,int * error)268 unsigned long get_ulong_config_value(struct collection_item *item,
269 int strict,
270 unsigned long def,
271 int *error)
272 {
273 unsigned long long val = 0;
274 int err = 0;
275
276 TRACE_FLOW_STRING("get_ulong_config_value", "Entry");
277
278 val = get_ullong_config_value(item, strict, def, &err);
279 if (err == 0) {
280 if (val > ULONG_MAX) {
281 val = def;
282 err = ERANGE;
283 }
284 }
285
286 if (error) *error = err;
287
288 TRACE_FLOW_NUMBER("get_ulong_config_value returning",
289 (unsigned long)val);
290 return (unsigned long)val;
291 }
292
293 /* Get int32_t value from config item */
get_int32_config_value(struct collection_item * item,int strict,int32_t def,int * error)294 int32_t get_int32_config_value(struct collection_item *item,
295 int strict,
296 int32_t def,
297 int *error)
298 {
299 int val = 0;
300
301 TRACE_FLOW_STRING("get_int32_config_value", "Entry");
302
303 val = get_int_config_value(item, strict, (int)def, error);
304
305 TRACE_FLOW_SNUMBER("get_int32_config_value returning", (int32_t)val);
306 return (int32_t)val;
307 }
308
309 /* Get uint32_t value from config item */
get_uint32_config_value(struct collection_item * item,int strict,uint32_t def,int * error)310 uint32_t get_uint32_config_value(struct collection_item *item,
311 int strict,
312 uint32_t def,
313 int *error)
314 {
315 unsigned val = 0;
316
317 TRACE_FLOW_STRING("get_uint32_config_value", "Entry");
318
319 val = get_unsigned_config_value(item, strict, (unsigned)def, error);
320
321 TRACE_FLOW_NUMBER("get_uint32_config_value returning", (uint32_t)val);
322 return (uint32_t)val;
323 }
324
325 /* Get int64_t value from config item */
get_int64_config_value(struct collection_item * item,int strict,int64_t def,int * error)326 int64_t get_int64_config_value(struct collection_item *item,
327 int strict,
328 int64_t def,
329 int *error)
330 {
331 long long val = 0;
332
333 TRACE_FLOW_STRING("get_int64_config_value", "Entry");
334
335 val = get_llong_config_value(item, strict, (long long)def, error);
336
337 TRACE_FLOW_SLNUMBER("get_int64_config_value returning", (int64_t)val);
338 return (int64_t)val;
339 }
340
341 /* Get uint64_t value from config item */
get_uint64_config_value(struct collection_item * item,int strict,uint64_t def,int * error)342 uint64_t get_uint64_config_value(struct collection_item *item,
343 int strict,
344 uint64_t def,
345 int *error)
346 {
347 unsigned long long val = 0;
348
349 TRACE_FLOW_STRING("get_uint64_config_value", "Entry");
350
351 val = get_ullong_config_value(item,
352 strict,
353 (unsigned long long)def,
354 error);
355
356 TRACE_FLOW_LNUMBER("get_uint64_config_value returning", (uint64_t)val);
357 return (uint64_t)val;
358 }
359
360 /* Get double value */
get_double_config_value(struct collection_item * item,int strict,double def,int * error)361 double get_double_config_value(struct collection_item *item,
362 int strict, double def, int *error)
363 {
364 const char *str;
365 char *endptr;
366 double val = 0;
367
368 TRACE_FLOW_STRING("get_double_config_value", "Entry");
369
370 /* Do we have the item ? */
371 if ((item == NULL) ||
372 (col_get_item_type(item) != COL_TYPE_STRING)) {
373 TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
374 if (error) *error = EINVAL;
375 return def;
376 }
377
378 if (error) *error = EOK;
379
380 /* Try to parse the value */
381 str = (const char *)col_get_item_data(item);
382 errno = 0;
383 val = strtod(str, &endptr);
384
385 /* Check for various possible errors */
386 if ((errno == ERANGE) ||
387 ((errno != 0) && (val == 0)) ||
388 (endptr == str)) {
389 TRACE_ERROR_NUMBER("Conversion failed", EIO);
390 if (error) *error = EIO;
391 return def;
392 }
393
394 if (strict && (*endptr != '\0')) {
395 TRACE_ERROR_NUMBER("More characters than expected", EIO);
396 if (error) *error = EIO;
397 val = def;
398 }
399
400 TRACE_FLOW_DOUBLE("get_double_config_value returning", val);
401 return val;
402 }
403
404 /* Get boolean value */
get_bool_config_value(struct collection_item * item,unsigned char def,int * error)405 unsigned char get_bool_config_value(struct collection_item *item,
406 unsigned char def, int *error)
407 {
408 const char *str;
409 int len;
410
411 TRACE_FLOW_STRING("get_bool_config_value", "Entry");
412
413 /* Do we have the item ? */
414 if ((item == NULL) ||
415 (col_get_item_type(item) != COL_TYPE_STRING)) {
416 TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
417 if (error) *error = EINVAL;
418 return def;
419 }
420
421 if (error) *error = EOK;
422
423 str = (const char *)col_get_item_data(item);
424 len = col_get_item_length(item);
425
426 /* Try to parse the value */
427 if ((strncasecmp(str, "true", len) == 0) ||
428 (strncasecmp(str, "yes", len) == 0)) {
429 TRACE_FLOW_STRING("Returning", "true");
430 return '\1';
431 }
432 else if ((strncasecmp(str, "false", len) == 0) ||
433 (strncasecmp(str, "no", len) == 0)) {
434 TRACE_FLOW_STRING("Returning", "false");
435 return '\0';
436 }
437
438 TRACE_ERROR_STRING("Returning", "error");
439 if (error) *error = EIO;
440 return def;
441 }
442
443 /* Return a string out of the value */
get_string_config_value(struct collection_item * item,int * error)444 char *get_string_config_value(struct collection_item *item,
445 int *error)
446 {
447 char *str = NULL;
448
449 TRACE_FLOW_STRING("get_string_config_value", "Entry");
450
451 /* Do we have the item ? */
452 if ((item == NULL) ||
453 (col_get_item_type(item) != COL_TYPE_STRING)) {
454 TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
455 if (error) *error = EINVAL;
456 return NULL;
457 }
458
459 str = strdup((const char *)col_get_item_data(item));
460 if (str == NULL) {
461 TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
462 if (error) *error = ENOMEM;
463 return NULL;
464 }
465
466 if (error) *error = EOK;
467
468 TRACE_FLOW_STRING("get_string_config_value returning", str);
469 return str;
470 }
471
472 /* Get string from item */
get_const_string_config_value(struct collection_item * item,int * error)473 const char *get_const_string_config_value(struct collection_item *item, int *error)
474 {
475 const char *str;
476
477 TRACE_FLOW_STRING("get_const_string_config_value", "Entry");
478
479 /* Do we have the item ? */
480 if ((item == NULL) ||
481 (col_get_item_type(item) != COL_TYPE_STRING)) {
482 TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
483 if (error) *error = EINVAL;
484 return NULL;
485 }
486
487 str = (const char *)col_get_item_data(item);
488
489 if (error) *error = EOK;
490
491 TRACE_FLOW_STRING("get_const_string_config_value returning", str);
492 return str;
493 }
494
495 /* A special hex format is assumed.
496 * The string should be taken in single quotes
497 * and consist of hex encoded value two hex digits per byte.
498 * Example: '0A2BFECC'
499 * Case does not matter.
500 */
get_bin_config_value(struct collection_item * item,int * length,int * error)501 char *get_bin_config_value(struct collection_item *item,
502 int *length, int *error)
503 {
504 unsigned i;
505 char *value = NULL;
506 const char *buff;
507 int size = 0;
508 unsigned char hex;
509 unsigned len;
510 const char *str;
511
512 TRACE_FLOW_STRING("get_bin_config_value", "Entry");
513
514 /* Do we have the item ? */
515 if ((item == NULL) ||
516 (col_get_item_type(item) != COL_TYPE_STRING)) {
517 TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
518 if (error) *error = EINVAL;
519 return NULL;
520 }
521
522 /* Check the length */
523 len = col_get_item_length(item)-1;
524 if ((len%2) != 0) {
525 TRACE_ERROR_STRING("Invalid length for binary data", "");
526 if (error) *error = EINVAL;
527 return NULL;
528 }
529
530 str = (const char *)col_get_item_data(item);
531
532 /* Is the format correct ? */
533 if ((*str != '\'') ||
534 (str[len -1] != '\'')) {
535 TRACE_ERROR_STRING("String is not escaped","");
536 if (error) *error = EIO;
537 return NULL;
538 }
539
540 /* Check that all the symbols are ok */
541 buff = str + 1;
542 len -= 2;
543 for (i = 0; i < len; i += 2) {
544 if (!isxdigit(buff[i]) || !isxdigit(buff[i + 1])) {
545 TRACE_ERROR_STRING("Invalid encoding for binary data", buff + i);
546 if (error) *error = EIO;
547 return NULL;
548 }
549 }
550
551 /* The value is good so we can allocate memory for it */
552 value = malloc(len / 2);
553 if (value == NULL) {
554 TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
555 if (error) *error = ENOMEM;
556 return NULL;
557 }
558
559 /* Convert the value */
560 for (i = 0; i < len; i += 2) {
561 if (isdigit(buff[i])) {
562 if (isdigit(buff[i+1]))
563 hex = 16 * (buff[i] - '0') + (buff[i+1] - '0');
564 else
565 hex = 16 * (buff[i] - '0') + (tolower(buff[i+1]) - 'a' + 10);
566 }
567 else {
568 if (isdigit(buff[i+1]))
569 hex = 16 * (tolower(buff[i]) - 'a') + (buff[i+1] - '0');
570 else
571 hex = 16 * (tolower(buff[i]) - 'a' + 10) + (tolower(buff[i+1]) - 'a' + 10);
572 }
573
574 value[size] = (char)(hex);
575 size++;
576 }
577
578 if (error) *error = EOK;
579 if (length) *length = size;
580 TRACE_FLOW_STRING("get_bin_config_value", "Exit");
581 return value;
582 }
583
584 /* Function to free binary configuration value */
free_bin_config_value(char * value)585 void free_bin_config_value(char *value)
586 {
587 if (value) free(value);
588 }
589