Line data Source code
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 */
36 24 : int get_config_item(const char *section,
37 : const char *name,
38 : struct collection_item *ini_config,
39 : struct collection_item **item)
40 : {
41 24 : int error = EOK;
42 24 : struct collection_item *section_handle = NULL;
43 : const char *to_find;
44 24 : char default_section[] = INI_DEFAULT_SECTION;
45 :
46 : TRACE_FLOW_STRING("get_config_item", "Entry");
47 :
48 : /* Do we have the accepting memory ? */
49 24 : 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 32 : if ((col_is_of_class(ini_config, COL_CLASS_INI_CONFIG) == 0) &&
56 8 : (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 24 : *item = NULL;
62 :
63 24 : if (section == NULL) to_find = default_section;
64 24 : else to_find = section;
65 :
66 : TRACE_INFO_STRING("Getting Name:", name);
67 : TRACE_INFO_STRING("In Section:", section);
68 :
69 : /* Get Subcollection */
70 24 : error = col_get_collection_reference(ini_config, §ion_handle, to_find);
71 : /* Check error */
72 24 : 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 24 : 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 23 : 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 23 : col_destroy_collection(section_handle);
90 :
91 : TRACE_FLOW_NUMBER("get_config_item returning", error);
92 23 : return error;
93 : }
94 :
95 : /* Get long long value from config item */
96 6 : 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 6 : long long val = 0;
105 :
106 : TRACE_FLOW_STRING("get_llong_config_value", "Entry");
107 :
108 : /* Do we have the item ? */
109 12 : if ((item == NULL) ||
110 6 : (col_get_item_type(item) != COL_TYPE_STRING)) {
111 : TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
112 0 : if (error) *error = EINVAL;
113 0 : return def;
114 : }
115 :
116 6 : if (error) *error = EOK;
117 :
118 : /* Try to parse the value */
119 6 : str = (const char *)col_get_item_data(item);
120 6 : errno = 0;
121 6 : val = strtoll(str, &endptr, 10);
122 6 : err = errno;
123 :
124 : /* Check for various possible errors */
125 6 : if (err != 0) {
126 : TRACE_ERROR_NUMBER("Conversion failed", err);
127 0 : if (error) *error = err;
128 0 : return def;
129 : }
130 :
131 : /* Other error cases */
132 6 : if ((endptr == str) || (strict && (*endptr != '\0'))) {
133 : TRACE_ERROR_NUMBER("More characters or nothing processed", EIO);
134 1 : if (error) *error = EIO;
135 1 : 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 */
143 12 : 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 12 : unsigned long long val = 0;
152 :
153 : TRACE_FLOW_STRING("get_ullong_config_value", "Entry");
154 :
155 : /* Do we have the item ? */
156 24 : if ((item == NULL) ||
157 12 : (col_get_item_type(item) != COL_TYPE_STRING)) {
158 : TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
159 0 : if (error) *error = EINVAL;
160 0 : return def;
161 : }
162 :
163 12 : if (error) *error = EOK;
164 :
165 : /* Try to parse the value */
166 12 : str = (const char *)col_get_item_data(item);
167 12 : errno = 0;
168 12 : val = strtoull(str, &endptr, 10);
169 12 : err = errno;
170 :
171 : /* Check for various possible errors */
172 12 : if (err != 0) {
173 : TRACE_ERROR_NUMBER("Conversion failed", err);
174 0 : if (error) *error = err;
175 0 : return def;
176 : }
177 :
178 : /* Other error cases */
179 12 : if ((endptr == str) || (strict && (*endptr != '\0'))) {
180 : TRACE_ERROR_NUMBER("More characters or nothing processed", EIO);
181 0 : if (error) *error = EIO;
182 0 : 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 */
191 4 : int get_int_config_value(struct collection_item *item,
192 : int strict,
193 : int def,
194 : int *error)
195 : {
196 4 : long long val = 0;
197 4 : int err = 0;
198 :
199 : TRACE_FLOW_STRING("get_int_config_value", "Entry");
200 :
201 4 : val = get_llong_config_value(item, strict, def, &err);
202 4 : if (err == 0) {
203 3 : if ((val > INT_MAX) || (val < INT_MIN)) {
204 0 : val = def;
205 0 : err = ERANGE;
206 : }
207 : }
208 :
209 4 : if (error) *error = err;
210 :
211 : TRACE_FLOW_NUMBER("get_int_config_value returning", (int)val);
212 4 : return (int)val;
213 : }
214 :
215 : /* Get unsigned integer value from config item */
216 2 : unsigned get_unsigned_config_value(struct collection_item *item,
217 : int strict,
218 : unsigned def,
219 : int *error)
220 : {
221 2 : unsigned long long val = 0;
222 2 : int err = 0;
223 :
224 : TRACE_FLOW_STRING("get_unsigned_config_value", "Entry");
225 :
226 2 : val = get_ullong_config_value(item, strict, def, &err);
227 2 : if (err == 0) {
228 2 : if (val > UINT_MAX) {
229 0 : val = def;
230 0 : err = ERANGE;
231 : }
232 : }
233 :
234 2 : if (error) *error = err;
235 :
236 : TRACE_FLOW_NUMBER("get_unsigned_config_value returning",
237 : (unsigned)val);
238 2 : return (unsigned)val;
239 : }
240 :
241 : /* Get long value from config item */
242 1 : long get_long_config_value(struct collection_item *item,
243 : int strict,
244 : long def,
245 : int *error)
246 : {
247 1 : long long val = 0;
248 1 : int err = 0;
249 :
250 : TRACE_FLOW_STRING("get_long_config_value", "Entry");
251 :
252 1 : 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 1 : if (error) *error = err;
261 :
262 : TRACE_FLOW_NUMBER("get_long_config_value returning",
263 : (long)val);
264 1 : return (long)val;
265 : }
266 :
267 : /* Get unsigned long value from config item */
268 9 : unsigned long get_ulong_config_value(struct collection_item *item,
269 : int strict,
270 : unsigned long def,
271 : int *error)
272 : {
273 9 : unsigned long long val = 0;
274 9 : int err = 0;
275 :
276 : TRACE_FLOW_STRING("get_ulong_config_value", "Entry");
277 :
278 9 : 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 9 : if (error) *error = err;
287 :
288 : TRACE_FLOW_NUMBER("get_ulong_config_value returning",
289 : (unsigned long)val);
290 9 : return (unsigned long)val;
291 : }
292 :
293 : /* Get int32_t value from config item */
294 1 : int32_t get_int32_config_value(struct collection_item *item,
295 : int strict,
296 : int32_t def,
297 : int *error)
298 : {
299 1 : int val = 0;
300 :
301 : TRACE_FLOW_STRING("get_int32_config_value", "Entry");
302 :
303 1 : val = get_int_config_value(item, strict, (int)def, error);
304 :
305 : TRACE_FLOW_SNUMBER("get_int32_config_value returning", (int32_t)val);
306 1 : return (int32_t)val;
307 : }
308 :
309 : /* Get uint32_t value from config item */
310 1 : uint32_t get_uint32_config_value(struct collection_item *item,
311 : int strict,
312 : uint32_t def,
313 : int *error)
314 : {
315 1 : unsigned val = 0;
316 :
317 : TRACE_FLOW_STRING("get_uint32_config_value", "Entry");
318 :
319 1 : val = get_unsigned_config_value(item, strict, (unsigned)def, error);
320 :
321 : TRACE_FLOW_NUMBER("get_uint32_config_value returning", (uint32_t)val);
322 1 : return (uint32_t)val;
323 : }
324 :
325 : /* Get int64_t value from config item */
326 1 : int64_t get_int64_config_value(struct collection_item *item,
327 : int strict,
328 : int64_t def,
329 : int *error)
330 : {
331 1 : long long val = 0;
332 :
333 : TRACE_FLOW_STRING("get_int64_config_value", "Entry");
334 :
335 1 : 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 1 : return (int64_t)val;
339 : }
340 :
341 : /* Get uint64_t value from config item */
342 1 : uint64_t get_uint64_config_value(struct collection_item *item,
343 : int strict,
344 : uint64_t def,
345 : int *error)
346 : {
347 1 : unsigned long long val = 0;
348 :
349 : TRACE_FLOW_STRING("get_uint64_config_value", "Entry");
350 :
351 1 : 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 1 : return (uint64_t)val;
358 : }
359 :
360 : /* Get double value */
361 1 : 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 1 : double val = 0;
367 :
368 : TRACE_FLOW_STRING("get_double_config_value", "Entry");
369 :
370 : /* Do we have the item ? */
371 2 : if ((item == NULL) ||
372 1 : (col_get_item_type(item) != COL_TYPE_STRING)) {
373 : TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
374 0 : if (error) *error = EINVAL;
375 0 : return def;
376 : }
377 :
378 1 : if (error) *error = EOK;
379 :
380 : /* Try to parse the value */
381 1 : str = (const char *)col_get_item_data(item);
382 1 : errno = 0;
383 1 : val = strtod(str, &endptr);
384 :
385 : /* Check for various possible errors */
386 1 : if ((errno == ERANGE) ||
387 1 : ((errno != 0) && (val == 0)) ||
388 1 : (endptr == str)) {
389 : TRACE_ERROR_NUMBER("Conversion failed", EIO);
390 0 : if (error) *error = EIO;
391 0 : return def;
392 : }
393 :
394 1 : if (strict && (*endptr != '\0')) {
395 : TRACE_ERROR_NUMBER("More characters than expected", EIO);
396 0 : if (error) *error = EIO;
397 0 : val = def;
398 : }
399 :
400 : TRACE_FLOW_DOUBLE("get_double_config_value returning", val);
401 1 : return val;
402 : }
403 :
404 : /* Get boolean value */
405 2 : 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 4 : if ((item == NULL) ||
415 2 : (col_get_item_type(item) != COL_TYPE_STRING)) {
416 : TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
417 0 : if (error) *error = EINVAL;
418 0 : return def;
419 : }
420 :
421 2 : if (error) *error = EOK;
422 :
423 2 : str = (const char *)col_get_item_data(item);
424 2 : len = col_get_item_length(item);
425 :
426 : /* Try to parse the value */
427 4 : if ((strncasecmp(str, "true", len) == 0) ||
428 2 : (strncasecmp(str, "yes", len) == 0)) {
429 : TRACE_FLOW_STRING("Returning", "true");
430 : return '\1';
431 : }
432 3 : else if ((strncasecmp(str, "false", len) == 0) ||
433 1 : (strncasecmp(str, "no", len) == 0)) {
434 : TRACE_FLOW_STRING("Returning", "false");
435 : return '\0';
436 : }
437 :
438 : TRACE_ERROR_STRING("Returning", "error");
439 1 : if (error) *error = EIO;
440 1 : return def;
441 : }
442 :
443 : /* Return a string out of the value */
444 1 : char *get_string_config_value(struct collection_item *item,
445 : int *error)
446 : {
447 1 : char *str = NULL;
448 :
449 : TRACE_FLOW_STRING("get_string_config_value", "Entry");
450 :
451 : /* Do we have the item ? */
452 2 : if ((item == NULL) ||
453 1 : (col_get_item_type(item) != COL_TYPE_STRING)) {
454 : TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
455 0 : if (error) *error = EINVAL;
456 : return NULL;
457 : }
458 :
459 1 : str = strdup((const char *)col_get_item_data(item));
460 1 : if (str == NULL) {
461 : TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
462 0 : if (error) *error = ENOMEM;
463 : return NULL;
464 : }
465 :
466 1 : if (error) *error = EOK;
467 :
468 : TRACE_FLOW_STRING("get_string_config_value returning", str);
469 1 : return str;
470 : }
471 :
472 : /* Get string from item */
473 2 : 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 3 : if ((item == NULL) ||
481 1 : (col_get_item_type(item) != COL_TYPE_STRING)) {
482 : TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
483 1 : if (error) *error = EINVAL;
484 : return NULL;
485 : }
486 :
487 1 : str = (const char *)col_get_item_data(item);
488 :
489 1 : if (error) *error = EOK;
490 :
491 : TRACE_FLOW_STRING("get_const_string_config_value returning", str);
492 1 : 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 : */
501 1 : char *get_bin_config_value(struct collection_item *item,
502 : int *length, int *error)
503 : {
504 : int i;
505 1 : char *value = NULL;
506 : const char *buff;
507 1 : int size = 0;
508 : unsigned char hex;
509 : int len;
510 : const char *str;
511 :
512 : TRACE_FLOW_STRING("get_bin_config_value", "Entry");
513 :
514 : /* Do we have the item ? */
515 2 : if ((item == NULL) ||
516 1 : (col_get_item_type(item) != COL_TYPE_STRING)) {
517 : TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
518 0 : if (error) *error = EINVAL;
519 : return NULL;
520 : }
521 :
522 : /* Check the length */
523 1 : len = col_get_item_length(item)-1;
524 1 : if ((len%2) != 0) {
525 : TRACE_ERROR_STRING("Invalid length for binary data", "");
526 0 : if (error) *error = EINVAL;
527 : return NULL;
528 : }
529 :
530 1 : str = (const char *)col_get_item_data(item);
531 :
532 : /* Is the format correct ? */
533 2 : if ((*str != '\'') ||
534 1 : (str[len -1] != '\'')) {
535 : TRACE_ERROR_STRING("String is not escaped","");
536 0 : if (error) *error = EIO;
537 : return NULL;
538 : }
539 :
540 : /* Check that all the symbols are ok */
541 1 : buff = str + 1;
542 1 : len -= 2;
543 4 : for (i = 0; i < len; i += 2) {
544 3 : if (!isxdigit(buff[i]) || !isxdigit(buff[i + 1])) {
545 : TRACE_ERROR_STRING("Invalid encoding for binary data", buff + i);
546 0 : if (error) *error = EIO;
547 : return NULL;
548 : }
549 : }
550 :
551 : /* The value is good so we can allocate memory for it */
552 1 : value = malloc(len / 2);
553 1 : if (value == NULL) {
554 : TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
555 0 : if (error) *error = ENOMEM;
556 : return NULL;
557 : }
558 :
559 : /* Convert the value */
560 3 : for (i = 0; i < len; i += 2) {
561 3 : if (isdigit(buff[i])) {
562 3 : if (isdigit(buff[i+1]))
563 3 : hex = 16 * (buff[i] - '0') + (buff[i+1] - '0');
564 : else
565 0 : hex = 16 * (buff[i] - '0') + (tolower(buff[i+1]) - 'a' + 10);
566 : }
567 : else {
568 0 : if (isdigit(buff[i+1]))
569 0 : hex = 16 * (tolower(buff[i]) - 'a') + (buff[i+1] - '0');
570 : else
571 0 : hex = 16 * (tolower(buff[i]) - 'a' + 10) + (tolower(buff[i+1]) - 'a' + 10);
572 : }
573 :
574 3 : value[size] = (char)(hex);
575 3 : size++;
576 : }
577 :
578 1 : if (error) *error = EOK;
579 1 : if (length) *length = size;
580 : TRACE_FLOW_STRING("get_bin_config_value", "Exit");
581 1 : return value;
582 : }
583 :
584 : /* Function to free binary configuration value */
585 1 : void free_bin_config_value(char *value)
586 : {
587 1 : if (value) free(value);
588 1 : }
|