initial revision
[ucgine.git] / tools / cfzy / libconfizery / cfzy_confnode.h
1 /*
2  * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
3  * All rights reserved.
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of the University of California, Berkeley nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 /**
29  * @file
30  * Confizery configuration node
31  *
32  * This module provides functions related to configuration nodes. A
33  * configuration node is a structure that stores a part of the
34  * information of the configuration tree. For instance, a "config" or
35  * "menuconfig" option is stored in a configuration node structure.
36  *
37  * It contains among other fields the name of the node (CONFIG_XYZ),
38  * the prompt and the help. Each node references its parent and a list
39  * of children as some nodes can contains some other nodes (menu, if,
40  * choice, ...). It also contains the default values, the user value,
41  * and the effective value of the node. Some nodes have no values (if,
42  * comment, ...).
43  */
44
45 #ifndef _CFZY_CONFNODE_H_
46 #define _CFZY_CONFNODE_H_
47
48 #include <stdio.h>
49
50 #include "cfzy_confnode_ops.h"
51 #include "cfzy_conftree_parser.h"
52
53 /* confnode flags */
54 #define CFZY_F_IS_DIR             0x0001 /**< node can contain other nodes */
55 #define CFZY_F_NO_SET_DEPS        0x0002 /**< does not support the "requires" attribute */
56 #define CFZY_F_NO_SET_PROMPT      0x0004 /**< does not support the "prompt" attribute */
57 #define CFZY_F_NO_SET_DEFAULT     0x0008 /**< does not support the "default" attribute */
58 #define CFZY_F_IS_ROOT            0x0010 /**< the root node */
59 #define CFZY_F_VAL_IS_BOOL        0x0020 /**< value is a boolean */
60 #define CFZY_F_INVISIBLE          0x0040 /**< never seen from cmdline (like the IF node) */
61 #define CFZY_F_NO_NAME            0x0080 /**< node has no name (if, comments, ...) */
62 #define CFZY_F_NO_SET_VALUE       0x0100 /**< user cannot set value (if, comments, ...) */
63 #define CFZY_F_QUOTE_VAL          0x0200 /**< quote value */
64 #define CFZY_F_DOTCONF_SHOW_TITLE 0x0400 /**< show title as a comment in dotconfig file  */
65
66 struct cfzy_conftree;
67
68 /**
69  * Structure storing a conditional default value
70  */
71 struct cfzy_confnode_defvalue {
72         struct cfzy_expr *expr; /**< expression (condition) */
73         char *val;              /**< value */
74 };
75
76 /**
77  * List of cfzy_node, used to chain children together
78  */
79 TAILQ_HEAD(cfzy_confnode_list, cfzy_confnode);
80
81 /**
82  * This structure defines a configuration node in the configration
83  * tree, for instance a "menu" entry, or a "bool" entry.
84  */
85 struct cfzy_confnode {
86         /* pointer to other nodes in conf tree */
87         struct cfzy_confnode *parent;          /**< pointer to parent */
88         struct cfzy_confnode_list children;    /**< list of children */
89         TAILQ_ENTRY(cfzy_confnode) child_next; /**< next in children list */
90         struct cfzy_conftree *conftree;        /**< back pointer to conftree */
91
92         /* node attributes */
93         char *name;                        /**< node name (dynamic alloc) */
94         char *prompt;                      /**< node prompt (dynamic alloc) */
95         char *help;                        /**< node help (dynamic alloc) */
96         unsigned flags;                    /**< node flags */
97         struct cfzy_list_head *expr_deps;  /**< list of prereq expressions */
98
99         /* where it was parsed */
100         char *filename;                    /**< name of conftree file */
101         int linenum;                       /**< line where node was declared */
102
103         /* specific to a node type */
104         const struct cfzy_confnode_ops *ops;   /**< specific ops on node */
105         void *private;
106
107         /* values */
108         char *default_value; /**< default value for this node */
109         struct cfzy_list_head *default_val_list; /* conditional default vals */
110         char *user_value;             /**< value wanted by the user */
111         char *effective_value;        /**< real value, taking care of deps */
112         char *old_user_value;         /**< saved user value */
113         char *old_effective_value;    /**< saved effective value */
114
115         /* allow to chain this node in a priority ordered list */
116         TAILQ_ENTRY(cfzy_confnode) prio_next;  /**< next in ordered list */
117         int in_prio_list;             /**< true if present in prio list */
118
119         struct cfzy_list_head *node_deps; /**< list of nodes that must be
120                                            * evaluated before this one */
121 };
122
123 /**
124  * Get the name of a node
125  *
126  * @param n
127  *   configuration node
128  * @return
129  *   pointer to the node name (hosted in the node structure)
130  */
131 static inline const char *cfzy_confnode_name(const struct cfzy_confnode *n)
132 {
133         if (n->name == NULL)
134                 return "no-name";
135         return n->name;
136 }
137
138 /**
139  * Allocate a new node
140  *
141  * Allocate a new empty node, with no specific ops.
142  *
143  * @param conftree
144  *   configuration tree
145  * @return
146  *   the allocated configuration node, or NULL on error
147  */
148 struct cfzy_confnode *cfzy_confnode_alloc(struct cfzy_conftree *conftree);
149
150 /**
151  * Free the node given as argument, and all its associated data
152  *
153  * This function will free the children of the nodes, then the node
154  * itself, first by calling the specific function n->ops->free() if
155  * defined, then by doing the generic operations.
156  *
157  * @param n
158  *   configuration node
159  */
160 void cfzy_confnode_free(struct cfzy_confnode *n);
161
162 /**
163  * Get the prerequisites for this node
164  *
165  * Return the list of nodes required to evaluate the value of the
166  * given node. Indeed, each node has a 'expr_deps' field storing a
167  * list of expressions and a list of default value associated to
168  * expressions. This function returns the list of all nodes referenced
169  * in these expressions and all the ancestor nodes.
170  *
171  * The returned list must be freed by the user with
172  * cfzy_list_free(list, NULL).
173  *
174  * @param n
175  *   configuration node
176  * @return
177  *   list of nodes, or NULL on error
178  */
179 struct cfzy_list_head *
180 cfzy_confnode_get_deplist(const struct cfzy_confnode *n);
181
182 /**
183  * Add a conditional default value to a node
184  *
185  * @param n
186  *   configuration node
187  * @param val
188  *   value to be used as default value
189  * @param expr_buf
190  *   condition string to enable the default value
191  * @return
192  *   0 on success, negative on error
193  */
194 int cfzy_confnode_add_defval(struct cfzy_confnode *n, const char *val,
195                              const char *expr_buf);
196
197 /**
198  * Parse a line of configuration tree file, expecting an attribute
199  *
200  * This function first tries to match specific node attributes, using
201  * the specific operation n->ops->add_attr() if registered. Then it
202  * tries to match generic attributes (prompt, requires, default).
203  *
204  * This function is internal to the confizery library (called by the
205  * configuration tree parser).
206  *
207  * @param n
208  *   configuration node
209  * @param tklist
210  *   list of tokens for this line
211  * @return
212  *   SUCCESS if it matches an attribute of this node, NO_MATCH if the line
213  *   is not an attribute for this node, ERROR on error
214  */
215 enum cfzy_parse_return
216 cfzy_confnode_add_attr(struct cfzy_confnode *n,
217                        const struct cfzy_token_list *tklist);
218
219 /**
220  * Write .config-like configuration in a file
221  *
222  * Write in a file the configuration values of this node and its
223  * descendants. The format of this file is like .config: it can be
224  * sourced by a shell or a Makefile.
225  *
226  * The function calls the specific node operation
227  * n->ops->dotconfig_write() if defined. Else, it uses the defaut
228  * behavior, which varies depending on node flags.
229  *
230  * This function is internal and is called by the public function
231  * cfzy_dotconfig_write().
232  *
233  * @param n
234  *   configuration node
235  * @param f
236  *   open file with write permissions where config will be written
237  * @return
238  *   0 on success, negative on error
239  */
240 int cfzy_confnode_dotconfig_write(const struct cfzy_confnode *n, FILE *f);
241
242 /**
243  * Write the configuration in a C header file
244  *
245  * Write in a file the configuration values of this node and its
246  * descendants. The format of this file is a C header, so it can be
247  * included by a C application.
248  *
249  * The function calls the specific node operation
250  * n->ops->c_hdr_write() if defined. Else, it uses the defaut
251  * behavior, which varies depending on node flags.
252  *
253  * This function is internal and is called by the public function
254  * cfzy_c_hdr_write().
255  *
256  * @param n
257  *   configuration node
258  * @param f
259  *   open file with write permissions where config will be written
260  * @return
261  *   0 on success, negative on error
262  */
263 int cfzy_confnode_c_hdr_write(const struct cfzy_confnode *n, FILE *f);
264
265 /**
266  * Return a string identifying the node type
267  *
268  * The function calls the specific node operation
269  * n->ops->get_type_str().
270  *
271  * The returned string points to static memory and contains the type
272  * of the node (ex: "config", "menuconfig", "choice", ...)
273  *
274  * @param n
275  *   configuration node
276  * @return
277  *   pointer to a node type string
278  */
279 const char *cfzy_confnode_get_type_str(const struct cfzy_confnode *n);
280
281 /**
282  * Return the boolean value of the node given the string value
283  *
284  * Convert the string value given as parameter to a boolean value. It
285  * calls the specific node operation n->ops->str2bool() if
286  * defined. Else, it uses the defaut behavior: return 0 for value=NULL
287  * or 1 for any other value.
288  *
289  * The specific function (if defined) can also return a negative value
290  * to indicate that the given value is not valid for this node.
291  *
292  * @param n
293  *   configuration node
294  * @param value
295  *   string containing the value
296  * @return
297  *   the boolean value (0 or 1) if the string value is valid,
298  *   else -1
299  */
300 int cfzy_confnode_str2bool(const struct cfzy_confnode *n, const char *value);
301
302 /**
303  * Get the path of the node
304  *
305  * @param n
306  *   configuration node
307  * @param buf
308  *   buffer where the path should be written
309  * @param len
310  *   length of the buffer
311  * @return
312  *   0 on success, negative on error
313  */
314 int cfzy_confnode_path(const struct cfzy_confnode *n, char *buf, int len);
315
316 /* dump modes */
317 #define CFZY_DUMP_MODE_MINIMAL        0x0
318 #define CFZY_DUMP_MODE_STANDARD       0x1
319 #define CFZY_DUMP_MODE_FULL           0x2
320 #define CFZY_DUMP_MODE_FULL_RECURSIVE 0x3
321
322 /**
323  * Dump a human-readable configuration in a file
324  *
325  * Write in a file the structure fields of this node and its
326  * descendants.
327  *
328  * @param n
329  *   configuration node
330  * @param f
331  *   open file with write permissions where configuration will be written
332  * @param mode
333  *   behavior of dump (CFZY_DUMP_MODE_MINIMAL, CFZY_DUMP_MODE_STANDARD, ...)
334  * @return
335  *   0 on success, negative on error
336  */
337 int cfzy_confnode_dump(const struct cfzy_confnode *n, FILE *f, int mode);
338
339 /**
340  * Check prerequisites for a node
341  *
342  * @param n
343  *   configuration node to be checked
344  * @return
345  *  0 if a parent node is disabled or if a prerequisite expression is
346  *  false, 1 if node can be enable. On error, return -1.
347  */
348 int cfzy_confnode_check_deps(struct cfzy_confnode *n);
349
350 /**
351  * Evaluate the effective value of a node
352  *
353  * Set the new value of n->effective_value, assuming all prerequisites
354  * are already evaluated. This function is used as a callback by
355  * cfzy_expr_parse() when parsing an expression for
356  * cfzy_confnode_evaluate().
357  *
358  * @return n
359  *   configuration node
360  * @return
361  *   0 on success, negative on error
362  */
363 int cfzy_confnode_evaluate(struct cfzy_confnode *n);
364
365 /**
366  * Get the boolean value of a node, given its name
367  *
368  * Return the effective value of a node (assuming it has been
369  * evaluated previously).
370  *
371  * @param name
372  *   configuration node name
373  * @param conftree
374  *   configuration tree
375  * @return
376  *   the boolean value (0 or 1) if the string value is valid,
377  *   else -1
378  */
379 int cfzy_confnode_get_boolvalue(const char *name,
380                                 const struct cfzy_conftree *conftree);
381
382 /**
383  * Set user value of a configuration node
384  *
385  * To set the user value of a node, the user must not access to the
386  * field directly but use this function. Indeed, a node may want to do
387  * a specific operation (like a check, or modifying children nodes)
388  * stored in n->ops->set_uservalue().
389  *
390  * @return n
391  *   configuration node
392  * @param value
393  *   value to be set as user value
394  * @return
395  *   0 on success, negative on error
396  */
397 int cfzy_confnode_set_uservalue(struct cfzy_confnode *n, const char *value);
398
399 /**
400  * Create a new root node
401  *
402  * @param conftree
403  *   configuration tree
404  * @return
405  *   a pointer to the configuration node, or NULL on error
406  */
407 struct cfzy_confnode *cfzy_confnode_root_new(struct cfzy_conftree *conftree);
408
409 /**
410  * Parse a line of configuration tree file, expecting new choice node
411  *
412  * @param n
413  *   configuration node
414  * @param tklist
415  *   list of tokens for this line
416  * @return
417  *   SUCCESS if it matches an attribute of this node, NO_MATCH if the line
418  *   is not an attribute for this node, ERROR on error
419  */
420 enum cfzy_parse_return
421 cfzy_confnode_choice_new(struct cfzy_confnode *n,
422                          const struct cfzy_token_list *tklist);
423 /**
424  * Parse a line of configuration tree file, expecting new choiceconfig node
425  *
426  * @param n
427  *   configuration node
428  * @param tklist
429  *   list of tokens for this line
430  * @return
431  *   SUCCESS if it matches an attribute of this node, NO_MATCH if the line
432  *   is not an attribute for this node, ERROR on error
433  */
434 enum cfzy_parse_return
435 cfzy_confnode_choiceconfig_new(struct cfzy_confnode *n,
436                                const struct cfzy_token_list *tklist);
437
438 /**
439  * Parse a line of configuration tree file, expecting new comment node
440  *
441  * @param n
442  *   configuration node
443  * @param tklist
444  *   list of tokens for this line
445  * @return
446  *   SUCCESS if it matches an attribute of this node, NO_MATCH if the line
447  *   is not an attribute for this node, ERROR on error
448  */
449 enum cfzy_parse_return
450 cfzy_confnode_comment_new(struct cfzy_confnode *n,
451                           const struct cfzy_token_list *tklist);
452
453 /**
454  * Parse a line of configuration tree file, expecting new config node
455  *
456  * @param n
457  *   configuration node
458  * @param tklist
459  *   list of tokens for this line
460  * @return
461  *   SUCCESS if it matches an attribute of this node, NO_MATCH if the line
462  *   is not an attribute for this node, ERROR on error
463  */
464 enum cfzy_parse_return
465 cfzy_confnode_config_new(struct cfzy_confnode *n,
466                          const struct cfzy_token_list *tklist);
467
468 /**
469  * Parse a line of configuration tree file, expecting new if node
470  *
471  * @param n
472  *   configuration node
473  * @param tklist
474  *   list of tokens for this line
475  * @return
476  *   SUCCESS if it matches an attribute of this node, NO_MATCH if the line
477  *   is not an attribute for this node, ERROR on error
478  */
479 enum cfzy_parse_return
480 cfzy_confnode_if_new(struct cfzy_confnode *n,
481                      const struct cfzy_token_list *tklist);
482
483 /**
484  * Parse a line of configuration tree file, expecting new intconfig node
485  *
486  * @param n
487  *   configuration node
488  * @param tklist
489  *   list of tokens for this line
490  * @return
491  *   SUCCESS if it matches an attribute of this node, NO_MATCH if the line
492  *   is not an attribute for this node, ERROR on error
493  */
494 enum cfzy_parse_return
495 cfzy_confnode_intconfig_new(struct cfzy_confnode *n,
496                             const struct cfzy_token_list *tklist);
497
498 /**
499  * Parse a line of configuration tree file, expecting new menu node
500  *
501  * @param n
502  *   configuration node
503  * @param tklist
504  *   list of tokens for this line
505  * @return
506  *   SUCCESS if it matches an attribute of this node, NO_MATCH if the line
507  *   is not an attribute for this node, ERROR on error
508  */
509 enum cfzy_parse_return
510 cfzy_confnode_menu_new(struct cfzy_confnode *n,
511                        const struct cfzy_token_list *tklist);
512
513 /**
514  * Parse a line of configuration tree file, expecting new menuconfig node
515  *
516  * @param n
517  *   configuration node
518  * @param tklist
519  *   list of tokens for this line
520  * @return
521  *   SUCCESS if it matches an attribute of this node, NO_MATCH if the line
522  *   is not an attribute for this node, ERROR on error
523  */
524 enum cfzy_parse_return
525 cfzy_confnode_menuconfig_new(struct cfzy_confnode *n,
526                              const struct cfzy_token_list *tklist);
527
528 /**
529  * Parse a line of configuration tree file, expecting new strconfig node
530  *
531  * @param n
532  *   configuration node
533  * @param tklist
534  *   list of tokens for this line
535  * @return
536  *   SUCCESS if it matches an attribute of this node, NO_MATCH if the line
537  *   is not an attribute for this node, ERROR on error
538  */
539 enum cfzy_parse_return
540 cfzy_confnode_strconfig_new(struct cfzy_confnode *n,
541                             const struct cfzy_token_list *tklist);
542
543 /**
544  * Close the node beeing parsed
545  *
546  * Some nodes can contains other nodes (menu, menuconfig, ...). When
547  * the parser has finished to parse the descendants of the node, it
548  * calls this function to close the node. This can trigger some
549  * specific operations (like checks) if the node type registers a
550  * n->ops->close(). If no specific function is registered, it does
551  * nothing.
552  *
553  * This function is internal to the confizery library (called by the
554  * configuration tree parser).
555  *
556  * @param n
557  *   configuration node
558  * @return
559  *   0 on success, negative on error
560  */
561 int cfzy_confnode_close(struct cfzy_confnode *n);
562
563
564 #endif /* _CFZY_CONFNODE_H_ */