]> mj.ucw.cz Git - libucw.git/blob - ucw/conf-test.c
Another attempt to do the fix right
[libucw.git] / ucw / conf-test.c
1 /*
2  *      Insane tester of reading configuration files
3  *
4  *      (c) 2006 Robert Spalek <robert@ucw.cz>
5  */
6
7 #include "ucw/lib.h"
8 #include "ucw/conf.h"
9 #include "ucw/getopt.h"
10 #include "ucw/clists.h"
11 #include "ucw/fastbuf.h"
12
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <time.h>
16
17 static int verbose;
18
19 struct sub_sect_1 {
20   cnode n;
21   char *name;
22   time_t t;
23   char *level;
24   int confidence[2];
25   double *list;
26 };
27
28 static struct sub_sect_1 sec1 = { {}, "Charlie", 0, "WBAFC", { 0, -1}, DARY_ALLOC(double, 3, 1e4, -1e-4, 8) };
29
30 static char *
31 init_sec_1(struct sub_sect_1 *s)
32 {
33   if (s == &sec1)                       // this is a static variable; skip clearing
34     return NULL;
35   s->name = "unknown";
36   s->level = "default";
37   s->confidence[0] = 5;
38   s->confidence[1] = 6;
39   // leave s->list==NULL
40   return NULL;
41 }
42
43 static char *
44 commit_sec_1(struct sub_sect_1 *s)
45 {
46   if (s->confidence[0] < 0 || s->confidence[0] > 10)
47     return "Well, this can't be";
48   return NULL;
49 }
50
51 static char *
52 time_parser(uns number, char **pars, time_t *ptr)
53 {
54   *ptr = number ? atoi(pars[0]) : time(NULL);
55   return NULL;
56 }
57
58 static struct cf_section cf_sec_1 = {
59   CF_TYPE(struct sub_sect_1),
60   CF_INIT(init_sec_1),
61   CF_COMMIT(commit_sec_1),
62 #define F(x)    PTR_TO(struct sub_sect_1, x)
63   CF_ITEMS {
64     CF_STRING("name", F(name)),
65     //CF_PARSER("t", F(t), time_parser, 0),
66     CF_STRING("level", F(level)),
67     CF_INT_ARY("confidence", F(confidence[0]), 2),              // XXX: the [0] is needed for the sake of type checking
68     CF_DOUBLE_DYN("list", F(list), 100),
69     CF_END
70   }
71 #undef F
72 };
73
74 static uns nr1 = 15;
75 static int *nrs1 = DARY_ALLOC(int, 5, 5, 4, 3, 2, 1);
76 static int nrs2[5];
77 static char *str1 = "no worries";
78 static char **str2 = DARY_ALLOC(char *, 2, "Alice", "Bob");
79 static u64 u1 = 0xCafeBeefDeadC00ll;
80 static double d1 = -1.1;
81 static clist secs;
82 static time_t t1, t2;
83 static u32 ip;
84 static int *look = DARY_ALLOC(int, 2, 2, 1);
85 static u16 numbers[10] = { 2, 100, 1, 5 };
86 static u32 bitmap1 = 0xff;
87 static u32 bitmap2 = 3;
88
89 static char *
90 parse_u16(char *string, u16 *ptr)
91 {
92   uns a;
93   char *msg = cf_parse_int(string, &a);
94   if (msg)
95     return msg;
96   if (a >= (1<<16))
97     return "Come on, man, this doesn't fit to 16 bits";
98   *ptr = a;
99   return NULL;
100 }
101
102 static void
103 dump_u16(struct fastbuf *fb, u16 *ptr)
104 {
105   bprintf(fb, "%d ", *ptr);
106 }
107
108 static struct cf_user_type u16_type = {
109   .size = sizeof(u16),
110   .name = "u16",
111   .parser = (cf_parser1*) parse_u16,
112   .dumper = (cf_dumper1*) dump_u16
113 };
114
115 static char *
116 init_top(void *ptr UNUSED)
117 {
118   for (uns i=0; i<5; i++)
119   {
120     struct sub_sect_1 *s = xmalloc(sizeof(struct sub_sect_1));  // XXX: cannot by cf_malloc(), because it's deleted when cf_reload()'ed
121     cf_init_section("slaves", &cf_sec_1, s, 1);
122     s->confidence[1] = i;
123     clist_add_tail(&secs, &s->n);
124   }
125   return NULL;
126 }
127
128 static char *
129 commit_top(void *ptr UNUSED)
130 {
131   if (nr1 != 15)
132     return "Don't touch my variable!";
133   return NULL;
134 }
135
136 static char *alphabet[] = { "alpha", "beta", "gamma", "delta", NULL };
137 static struct cf_section cf_top = {
138   CF_INIT(init_top),
139   CF_COMMIT(commit_top),
140   CF_ITEMS {
141     CF_UNS("nr1", &nr1),
142     CF_INT_DYN("nrs1", &nrs1, 1000),
143     CF_INT_ARY("nrs2", nrs2, 5),
144     CF_STRING("str1", &str1),
145     CF_STRING_DYN("str2", &str2, 20),
146     CF_U64("u1", &u1),
147     CF_DOUBLE("d1", &d1),
148     CF_PARSER("FirstTime", &t1, time_parser, -1),
149     CF_PARSER("SecondTime", &t2, time_parser, 1),
150     CF_SECTION("master", &sec1, &cf_sec_1),
151     CF_LIST("slaves", &secs, &cf_sec_1),
152     CF_IP("ip", &ip),
153     CF_LOOKUP_DYN("look", &look, alphabet, 1000),
154     CF_USER_ARY("numbers", numbers, &u16_type, 10),
155     CF_BITMAP_INT("bitmap1", &bitmap1),
156     CF_BITMAP_LOOKUP("bitmap2", &bitmap2, ((char*[]) {
157           "one", "two", "three", "four", "five", "six", "seven", "eight", 
158           "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "seventeen", 
159           "eighteen", "nineteen", "twenty", NULL        // hidden joke here
160           })),
161     CF_END
162   }
163 };
164
165 static char short_opts[] = CF_SHORT_OPTS "v";
166 static struct option long_opts[] = {
167         CF_LONG_OPTS
168         {"verbose",     0, 0, 'v'},
169         {NULL,          0, 0, 0}
170 };
171
172 static char *help = "\
173 Usage: conf-test <options>\n\
174 \n\
175 Options:\n"
176 CF_USAGE
177 "-v\t\t\tBe verbose\n\
178 ";
179
180 static void NONRET
181 usage(char *msg, ...)
182 {
183   va_list va;
184   va_start(va, msg);
185   if (msg)
186     vfprintf(stderr, msg, va);
187   fputs(help, stderr);
188   exit(1);
189 }
190
191 int
192 main(int argc, char *argv[])
193 {
194   log_init(argv[0]);
195   cf_declare_section("top", &cf_top, 0);
196   cf_def_file = "ucw/conf-test.cf";
197
198   int opt;
199   while ((opt = cf_getopt(argc, argv, short_opts, long_opts, NULL)) >= 0)
200     switch (opt) {
201       case 'v': verbose++; break;
202       default: usage("unknown option %c\n", opt);
203     }
204   if (optind < argc)
205     usage("too many parameters (%d more)\n", argc-optind);
206
207   /*
208   cf_load("non-existent file");
209   //cf_reload("non-existent file");
210   cf_load("non-existent file");
211   cf_set("top.d1 -1.1; top.master b");
212   */
213
214   struct fastbuf *out = bfdopen(1, 1<<14);
215   cf_dump_sections(out);
216   bclose(out);
217
218   return 0;
219 }