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