fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * libini *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/libini/section.c *
7 * Created: 2001-08-24 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2001-2010 Hampa Hug <hampa@hampa.ch> *
9 *****************************************************************************/
10
11/*****************************************************************************
12 * This program is free software. You can redistribute it and / or modify it *
13 * under the terms of the GNU General Public License version 2 as published *
14 * by the Free Software Foundation. *
15 * *
16 * This program is distributed in the hope that it will be useful, but *
17 * WITHOUT ANY WARRANTY, without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
19 * Public License for more details. *
20 *****************************************************************************/
21
22
23#include <config.h>
24
25#include <stdlib.h>
26#include <string.h>
27
28#include <libini/libini.h>
29
30
31/*
32 * Check if c is a letter, a digit or both.
33 */
34static
35int ini_check_char (char c, int alpha, int num)
36{
37 if (alpha) {
38 if ((c >= 'a') && (c <= 'z')) {
39 return (1);
40 }
41
42 if ((c >= 'A') && (c <= 'Z')) {
43 return (1);
44 }
45
46 if (c == '_') {
47 return (1);
48 }
49 }
50
51 if (num) {
52 if ((c >= '0') && (c <= '9')) {
53 return (1);
54 }
55 }
56
57 return (0);
58}
59
60/*
61 * Extract the first name and index from a longer section name.
62 */
63static
64int ini_get_name_and_index (const char **str, char *name, unsigned max,
65 unsigned *idx, int *noidx, int *addnew, int *last)
66{
67 unsigned i;
68 const char *s;
69
70 s = *str;
71
72 *idx = 0;
73 *noidx = 1;
74 *addnew = 0;
75 *last = 0;
76
77 if (ini_check_char (*s, 1, 0) == 0) {
78 return (1);
79 }
80
81 name[0] = *(s++);
82 i = 1;
83
84 while ((*s != 0) && (i < max)) {
85 if (ini_check_char (*s, 1, 1) == 0) {
86 break;
87 }
88
89 name[i++] = *(s++);
90 }
91
92 if (i >= max) {
93 return (1);
94 }
95
96 name[i] = 0;
97
98 if (*s == 0) {
99 *str = s;
100 return (0);
101 }
102
103 if (*s == '.') {
104 *str = s + 1;
105 return (0);
106 }
107
108 if (*s != '[') {
109 return (1);
110 }
111
112 s += 1;
113
114 if (*s == '+') {
115 *addnew = 1;
116 s += 1;
117 }
118 else if (*s == '-') {
119 *last = 1;
120 s += 1;
121 }
122 else {
123 if (ini_check_char (*s, 0, 1) == 0) {
124 return (1);
125 }
126
127 while (ini_check_char (*s, 0, 1)) {
128 *idx = 10 * *idx + (*s - '0');
129 s += 1;
130 }
131 }
132
133 if (*s != ']') {
134 return (1);
135 }
136
137 s += 1 ;
138
139 if (*s == '.') {
140 s += 1 ;
141 }
142
143 *str = s;
144 *noidx = 0;
145
146 return (0);
147}
148
149ini_sct_t *ini_sct_new (const char *name)
150{
151 ini_sct_t *sct;
152
153 sct = malloc (sizeof (ini_sct_t));
154
155 if (sct == NULL) {
156 return (NULL);
157 }
158
159 sct->next = NULL;
160 sct->parent = NULL;
161
162 if (name == NULL) {
163 name = "";
164 }
165
166 if (name != NULL) {
167 sct->name = strdup (name);
168 }
169 else {
170 sct->name = NULL;
171 }
172
173 sct->sub_head = NULL;
174 sct->sub_tail = NULL;
175
176 sct->val_head = NULL;
177 sct->val_tail = NULL;
178
179 return (sct);
180}
181
182void ini_sct_del (ini_sct_t *sct)
183{
184 ini_sct_t *tmp;
185
186 while (sct != NULL) {
187 tmp = sct;
188 sct = sct->next;
189
190 ini_val_del (tmp->val_head);
191 ini_sct_del (tmp->sub_head);
192
193 free (tmp->name);
194 free (tmp);
195 }
196}
197
198static
199ini_sct_t *ini_new_sct (ini_sct_t *sct, const char *name)
200{
201 ini_sct_t *sub;
202
203 sub = ini_sct_new (name);
204
205 if (sub == NULL) {
206 return (NULL);
207 }
208
209 if (sct != NULL) {
210 sub->parent = sct;
211
212 if (sct->sub_head == NULL) {
213 sct->sub_head = sub;
214 }
215 else {
216 sct->sub_tail->next = sub;
217 }
218
219 sct->sub_tail = sub;
220 }
221
222 return (sub);
223}
224
225static
226ini_val_t *ini_new_val (ini_sct_t *sct, const char *name)
227{
228 ini_val_t *val;
229
230 val = ini_val_new (name);
231
232 if (val == NULL) {
233 return (NULL);
234 }
235
236 if (sct != NULL) {
237 if (sct->val_head == NULL) {
238 sct->val_head = val;
239 }
240 else {
241 sct->val_tail->next = val;
242 }
243
244 sct->val_tail = val;
245 }
246
247 return (val);
248}
249
250ini_sct_t *ini_next_sct (ini_sct_t *sct, ini_sct_t *val, const char *name)
251{
252 if (val == NULL) {
253 if (sct == NULL) {
254 return (NULL);
255 }
256
257 val = sct->sub_head;
258 }
259 else {
260 val = val->next;
261 }
262
263 if (val == NULL) {
264 return (NULL);
265 }
266
267 if (name == NULL) {
268 return (val);
269 }
270
271 while (val != NULL) {
272 if (strcmp (val->name, name) == 0) {
273 return (val);
274 }
275
276 val = val->next;
277 }
278
279 return (NULL);
280}
281
282ini_val_t *ini_next_val (ini_sct_t *sct, ini_val_t *val, const char *name)
283{
284 if (val == NULL) {
285 if (sct == NULL) {
286 return (NULL);
287 }
288
289 val = sct->val_head;
290 }
291 else {
292 val = val->next;
293 }
294
295 if (val == NULL) {
296 return (NULL);
297 }
298
299 if (name == NULL) {
300 return (NULL);
301 }
302
303 while (val != NULL) {
304 if (strcmp (val->name, name) == 0) {
305 return (val);
306 }
307
308 val = val->next;
309 }
310
311 return (NULL);
312}
313
314/*
315 * Get the last subsection of sct with name name. If there is no such
316 * subsection and add is true, add a new subsection and return it.
317 */
318static
319ini_sct_t *ini_get_last_sct (ini_sct_t *sct, const char *name, int add)
320{
321 ini_sct_t *sub, *ret;
322
323 sub = sct->sub_head;
324 ret = NULL;
325
326 while (sub != NULL) {
327 if (strcmp (sub->name, name) == 0) {
328 ret = sub;
329 }
330
331 sub = sub->next;
332 }
333
334 if ((add == 0) || (ret != NULL)) {
335 return (ret);
336 }
337
338 return (ini_new_sct (sct, name));
339}
340
341static
342ini_sct_t *ini_get_indexed_sct (ini_sct_t *sct, const char *name,
343 unsigned index, int add)
344{
345 ini_sct_t *sub;
346
347 sub = sct->sub_head;
348
349 while (sub != NULL) {
350 if (strcmp (sub->name, name) == 0) {
351 if (index == 0) {
352 return (sub);
353 }
354
355 index -= 1;
356 }
357
358 sub = sub->next;
359 }
360
361 if (add == 0) {
362 return (NULL);
363 }
364
365 while (index > 0) {
366 if (ini_new_sct (sct, name) == NULL) {
367 return (NULL);
368 }
369
370 index -= 1;
371 }
372
373 return (ini_new_sct (sct, name));
374}
375
376/*
377 * Get the last value of sct with name name. If there is no such value
378 * and add is true, add a new value and return it.
379 */
380static
381ini_val_t *ini_get_last_val (ini_sct_t *sct, const char *name, int add)
382{
383 ini_val_t *val, *ret;
384
385 val = sct->val_head;
386 ret = NULL;
387
388 while (val != NULL) {
389 if (strcmp (val->name, name) == 0) {
390 ret = val;
391 }
392
393 val = val->next;
394 }
395
396 if ((add == 0) || (ret != NULL)) {
397 return (ret);
398 }
399
400 return (ini_new_val (sct, name));
401}
402
403static
404ini_val_t *ini_get_indexed_val (ini_sct_t *sct, const char *name,
405 unsigned index, int add)
406{
407 ini_val_t *val;
408
409 val = sct->val_head;
410
411 while (val != NULL) {
412 if (strcmp (val->name, name) == 0) {
413 if (index == 0) {
414 return (val);
415 }
416
417 index -= 1;
418 }
419
420 val = val->next;
421 }
422
423 if (add == 0) {
424 return (NULL);
425 }
426
427 while (index > 0) {
428 if (ini_new_val (sct, name) == NULL) {
429 return (NULL);
430 }
431
432 index -= 1;
433 }
434
435 return (ini_new_val (sct, name));
436}
437
438ini_sct_t *ini_get_sct (ini_sct_t *sct, const char *name, int add)
439{
440 int simple, noidx, addnew, last;
441 unsigned index;
442 char name2[256];
443
444 if (sct == NULL) {
445 return (NULL);
446 }
447
448 simple = 1;
449
450 while (*name != 0) {
451 if (ini_get_name_and_index (&name, name2, 256, &index, &noidx, &addnew, &last)) {
452 return (NULL);
453 }
454
455 if (*name != 0) {
456 simple = 0;
457 }
458
459 if (addnew || (simple && add && noidx)) {
460 sct = ini_new_sct (sct, name2);
461 }
462 else if (last) {
463 sct = ini_get_last_sct (sct, name2, add);
464 }
465 else {
466 sct = ini_get_indexed_sct (sct, name2, index, add);
467
468 }
469
470 if (sct == NULL) {
471 return (NULL);
472 }
473 }
474
475 return (sct);
476}
477
478ini_val_t *ini_get_val (ini_sct_t *sct, const char *name, int add)
479{
480 int simple, noidx, addnew, last;
481 unsigned index;
482 char name2[256];
483
484 if (sct == NULL) {
485 return (NULL);
486 }
487
488 simple = 1;
489
490 while (*name != 0) {
491 if (ini_get_name_and_index (&name, name2, 256, &index, &noidx, &addnew, &last)) {
492 return (NULL);
493 }
494
495 if (*name == 0) {
496 if (addnew || (simple && add && noidx)) {
497 return (ini_new_val (sct, name2));
498 }
499 else if (last) {
500 return (ini_get_last_val (sct, name2, add));
501 }
502
503 return (ini_get_indexed_val (sct, name2, index, add));
504 }
505 else {
506 simple = 0;
507 }
508
509 if (addnew || (simple && add && noidx)) {
510 sct = ini_new_sct (sct, name2);
511 }
512 else if (last) {
513 sct = ini_get_last_sct (sct, name2, add);
514 }
515 else {
516 sct = ini_get_indexed_sct (sct, name2, index, add);
517 }
518
519 if (sct == NULL) {
520 return (NULL);
521 }
522 }
523
524 return (NULL);
525}
526
527
528int ini_set_uint32 (ini_sct_t *sct, const char *name, unsigned long v)
529{
530 ini_val_t *val;
531
532 val = ini_get_val (sct, name, 1);
533
534 if (val == NULL) {
535 return (1);
536 }
537
538 ini_val_set_uint32 (val, v);
539
540 return (0);
541}
542
543int ini_set_sint32 (ini_sct_t *sct, const char *name, long v)
544{
545 ini_val_t *val;
546
547 val = ini_get_val (sct, name, 1);
548
549 if (val == NULL) {
550 return (1);
551 }
552
553 ini_val_set_sint32 (val, v);
554
555 return (0);
556}
557
558int ini_set_str (ini_sct_t *sct, const char *name, const char *v)
559{
560 ini_val_t *val;
561
562 val = ini_get_val (sct, name, 1);
563
564 if (val == NULL) {
565 return (1);
566 }
567
568 ini_val_set_str (val, v);
569
570 return (0);
571}
572
573int ini_get_uint32 (const ini_sct_t *sct, const char *name, unsigned long *ret, unsigned long def)
574{
575 ini_val_t *val;
576
577 *ret = def;
578
579 val = ini_get_val ((ini_sct_t *) sct, name, 0);
580
581 if (val == NULL) {
582 return (1);
583 }
584
585 if (ini_val_get_uint32 (val, ret)) {
586 return (1);
587 }
588
589 return (0);
590}
591
592int ini_get_sint32 (const ini_sct_t *sct, const char *name, long *ret, long def)
593{
594 ini_val_t *val;
595
596 *ret = def;
597
598 val = ini_get_val ((ini_sct_t *) sct, name, 0);
599
600 if (val == NULL) {
601 return (1);
602 }
603
604 if (ini_val_get_sint32 (val, ret)) {
605 return (1);
606 }
607
608 return (0);
609}
610
611int ini_get_uint16 (const ini_sct_t *sct, const char *name, unsigned *ret, unsigned def)
612{
613 ini_val_t *val;
614
615 *ret = def;
616
617 val = ini_get_val ((ini_sct_t *) sct, name, 0);
618
619 if (val == NULL) {
620 return (1);
621 }
622
623 if (ini_val_get_uint16 (val, ret)) {
624 return (1);
625 }
626
627 return (0);
628}
629
630int ini_get_sint16 (const ini_sct_t *sct, const char *name, int *ret, int def)
631{
632 ini_val_t *val;
633
634 *ret = def;
635
636 val = ini_get_val ((ini_sct_t *) sct, name, 0);
637
638 if (val == NULL) {
639 return (1);
640 }
641
642 if (ini_val_get_sint16 (val, ret)) {
643 return (1);
644 }
645
646 return (0);
647}
648
649int ini_get_bool (const ini_sct_t *sct, const char *name, int *ret, int def)
650{
651 ini_val_t *val;
652
653 *ret = (def != 0);
654
655 val = ini_get_val ((ini_sct_t *) sct, name, 0);
656
657 if (val == NULL) {
658 return (1);
659 }
660
661 if (ini_val_get_bool (val, ret)) {
662 return (1);
663 }
664
665 return (0);
666}
667
668int ini_get_string (const ini_sct_t *sct, const char *name, const char **ret, const char *def)
669{
670 const char *tmp;
671 ini_val_t *val;
672
673 *ret = def;
674
675 val = ini_get_val ((ini_sct_t *) sct, name, 0);
676
677 if (val == NULL) {
678 return (1);
679 }
680
681 tmp = ini_val_get_str (val);
682
683 if (tmp != NULL) {
684 *ret = tmp;
685 }
686
687 return (0);
688}