Initial import from http://www.droids-corp.org/hg/libcmdline/rev/db316e4289a1
[libcmdline.git] / src / genconf / parse_confnode.c
1 /*
2  * Copyright (c) 2009, 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 #include <stdio.h>
29 #include <inttypes.h>
30 #include <ctype.h>
31 #include <string.h>
32 #include <netinet/in.h>
33 #include <sys/queue.h>
34
35 #include <cmdline_parse_ipaddr.h>
36 #include <cmdline_parse.h>
37
38 #include "expression.h"
39 #include "conf_parser.h"
40 #include "confnode.h"
41 #include "conf_htable.h"
42 #include "parse_confnode.h"
43
44 struct cmdline_token_ops token_conf_node_ops = {
45         .parse = parse_conf_node,
46         .complete_get_nb = complete_get_nb_conf_node,
47         .complete_get_elt = complete_get_elt_conf_node,
48         .get_help = get_help_conf_node,
49 };
50
51 /* return 0 if string matches pattern (string must not contain '*')*/
52 static int strcmp_joker(const char *s, const char *pattern)
53 {
54         if (s == pattern)
55                 return 0;
56
57         while (*s == *pattern && *pattern != '*') {
58                 if (*s == '\0')
59                         return 0;
60                 s ++;
61                 pattern ++;
62         }
63         if (*pattern != '*')
64                 return -1;
65         if (*(pattern + 1) == '\0')
66                 return 0;
67         while (*s) {
68                 if (strcmp_joker(s, pattern + 1) == 0)
69                         return 0;
70                 s ++;
71         }
72         return -1;
73 }
74
75 static void
76 find_in_children(struct confnode_list *l, struct confnode *n,
77                  const char *pattern, int flags, int mask, int recurs)
78 {
79         struct confnode *c;
80
81         TAILQ_FOREACH(c, &n->children, next) {
82                 /* if it's a "if" node, parse children */
83                 if (c->flags & CONFNODE_F_INVISIBLE)
84                         find_in_children(l, c, pattern, flags, mask, recurs);
85
86                 else {
87                         if ((c->flags & mask) == flags &&
88                             !strcmp_joker(c->name, pattern))
89                                 TAILQ_INSERT_TAIL(l, c, user_next);
90
91                         if (recurs)
92                                 find_in_children(l, c, pattern, flags, mask, recurs);
93                 }
94         }
95 }
96
97 static int
98 count_children(struct confnode *n, int flags, int mask)
99 {
100         struct confnode *c;
101         int i = 0;
102
103         TAILQ_FOREACH(c, &n->children, next) {
104                 /* if it's a "if" node, parse children */
105                 if (c->flags & CONFNODE_F_INVISIBLE)
106                         i += count_children(c, flags, mask);
107                 else if ((c->flags & mask) == flags)
108                         i ++;
109         }
110         return i;
111 }
112
113 static struct confnode *
114 get_from_idx(struct confnode *n, unsigned int *cur, unsigned int idx,
115              int flags, int mask)
116 {
117         struct confnode *c, *tmp;
118
119         TAILQ_FOREACH(c, &n->children, next) {
120                 /* if it's a "if" node, parse children */
121                 if (c->flags & CONFNODE_F_INVISIBLE) {
122                         tmp = get_from_idx(c, cur, idx, flags, mask);
123                         if (tmp)
124                                 return tmp;
125                 }
126                 else {
127                         if ((c->flags & mask) != flags)
128                                 continue;
129                         if (*cur == idx)
130                                 return c;
131                         *cur = *cur + 1;
132                 }
133         }
134         return NULL;
135 }
136
137 int
138 parse_conf_node(cmdline_parse_token_hdr_t *tk, const char *buf, void *res)
139 {
140         struct token_conf_node *tk2 = (struct token_conf_node *)tk;
141         struct token_conf_node_data *tkd = &tk2->conf_node_data;
142         struct confnode *n;
143         struct confnode_list l;
144         unsigned int token_len = 0;
145         char token[BUFSIZ];
146
147         if (*buf == 0)
148                 return -1;
149
150         while(!cmdline_isendoftoken(buf[token_len]))
151                 token_len++;
152
153         if (token_len > sizeof(token) - 1)
154                 return -1;
155
156         memcpy(token, buf, token_len);
157         token[token_len] = '\0';
158
159         TAILQ_INIT(&l);
160
161         /* absolute path */
162         if (token[0] == '/' && token[1] == '/') {
163                 /* if contains joker */
164                 if (strchr(token + 2, '*'))
165                         find_in_children(&l, *tkd->root, token+2, tkd->flags,
166                                          tkd->mask, 1);
167                 else {
168                         n = conf_htable_lookup(token + 2);
169                         if ((n->flags & tkd->mask) != tkd->flags)
170                                 return -1;
171                         TAILQ_INSERT_TAIL(&l, n, user_next);
172                 }
173         }
174         /* relative path */
175         else
176                 find_in_children(&l, *tkd->cur, token, tkd->flags, tkd->mask, 0);
177         if (TAILQ_EMPTY(&l))
178                 return -1;
179
180         /* store the address of object in structure */
181         if (res)
182                 *(struct confnode **)res = TAILQ_FIRST(&l);
183
184         return token_len;
185 }
186
187 int complete_get_nb_conf_node(cmdline_parse_token_hdr_t *tk)
188 {
189         struct token_conf_node *tk2 = (struct token_conf_node *)tk;
190         struct token_conf_node_data *tkd = &tk2->conf_node_data;
191
192         return count_children(*tkd->cur, tkd->flags, tkd->mask);
193 }
194
195 int complete_get_elt_conf_node(cmdline_parse_token_hdr_t *tk, int idx,
196                                char *dstbuf, unsigned int size)
197 {
198         struct token_conf_node *tk2 = (struct token_conf_node *)tk;
199         struct token_conf_node_data *tkd = &tk2->conf_node_data;
200         struct confnode *n;
201         unsigned int i = 0, len;
202
203         n = get_from_idx(*tkd->cur, &i, idx, tkd->flags, tkd->mask);
204         if (n == NULL)
205                 return -1;
206
207         len = strlen(n->name) + 1;
208         if (len > size)
209                 return -1;
210
211         strcpy(dstbuf, n->name);
212         return 0;
213 }
214
215
216 int get_help_conf_node(cmdline_parse_token_hdr_t *tk, char *dstbuf, unsigned int size)
217 {
218         snprintf(dstbuf, size, "conf-node");
219         return 0;
220 }