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