thoughts and shit
[dana/openbox.git] / obcl / README
1 Note: this is not really a README but more of a thought dump, for now.
2
3 overall
4 -------
5
6 obcl wants to be a generic configuration file loader. generic not in
7 the sense that it will parse every single configuration format on the
8 planet, but in the sense that it will parse a versatile, multi purpose
9 format.
10
11 parser
12 ------
13
14 this is the part of obcl that when given a configuration file, it will
15 return a parse tree. the parse tree can be mucked with by the
16 programmer, or it can be checked and processed using the handy checker
17 and processor. (for the most part; the programmer will do some
18 processing work.)
19
20   GList *config = cl_parse_file("foo.conf");
21
22 checker
23 -------
24
25 the checker is supposed to help the programmer/application ensure that
26 the configuration file is in the correct format. since obcl has a very
27 general, the parser itself cannot guarantee that the user will enter a
28 correct config file:
29
30   foo { }
31   fpp { }
32
33 will both be parsed, but 'fpp' might be a mistake. the checker is
34 intended to fix this.
35
36   foo  5;
37   blef "foo";
38   bar  5, "foo", "hi", 43.4;
39
40   woop "hello" {
41     foo 5;
42   }
43
44   CLChecker *check = cl_checker_new();
45   cl_checker_add(check, "foo", CL_NUM, 0);
46   cl_checker_add(check, "blef", CL_STRING, 0);
47   cl_checker_add(check, "bar", CL_NUM, CL_STRING, CL_STRING, CL_NUM, 0);
48   cl_checker_add(check, "woop", CL_STRING, CL_BLOCK, 0);
49   cl_checker_add_checker(check, "woop", check); /* add checker for block */
50
51   int val = cl_check(checker, config, stderr); /* write errors to stderr */
52   if (!val) {
53     fprintf(stderr, "Parse errors found. Loading default settings\n");
54     ...
55   }
56
57   cl_checker_free(check);
58
59 processor
60 ---------
61
62 the processor is intended to be run after the checker, to do actual
63 'stuff' with the parse tree. once the parse tree has been checked, we
64 know that we can just access stuff in the parse tree willy nilly
65 without sprinkling asserts all over the code. the processing is done
66 via callbacks.
67
68   typedef gpointer (*CLCallback)(CLNode *node, gpointer val);
69
70   gpointer handle_foo(CLNode *node, gpointer conf)
71   {
72     /* here numval is a macro that expands to something like
73        node->u.num. we know we can access this safely since the checker
74        has verified that 'foo' nodes indeed contain numbers.
75        same with NTH. it expands to somethign that we don't have to
76        worry about. */
77     ((Config*)conf)->foo = NUMVAL(NTH(node, 1));
78     return 0;
79   }
80
81   gpointer handle_woop(CLNode *node, gpointer conf, CLProc *proc)
82   {
83     Config *conf1 = new_conf();
84     conf1->name = STRVAL(NTH(node,1));
85     cl_process(proc, BLOCK(node), conf1);
86     conf_add_child((Config*)conf, conf1);
87     return 0;
88   }
89
90   ...
91
92   Config *process_config_file(char *file)
93   {
94     Config *conf;
95     GList *parse_tree;
96     CLProc *proc;
97     CLChecker *check;
98     int err;
99
100     config = new_conf();
101     parse_tree = cl_parse_file(file);
102
103     if (!parse_tree) {
104       fprintf(stderr, "your config file is completely borked. loading defaults\n");
105       conf_load_defaults(conf);
106       return conf;
107     }
108
109     checker = checker_new();
110     ...
111     /* add checker stuff to checker, as per above */
112
113     err = cl_check(checker, parse_tree);
114
115     if (err) {
116       fprintf(stderr, "you fucked up. loading defaults\n");
117       config_load_defaults(conf);
118       return conf;
119     }
120
121     CLProc *proc = cl_proc_new();
122     cl_proc_add(proc, "foo", handle_foo, conf); /* conf will be passed to callback */
123     ...
124     cl_proc_add_block(proc, "woop", handle_woop, conf, proc);
125     cl_process(proc, parse_tree);
126
127     return conf;
128   }
129
130 something like that. lalala.