5c8202bdf99e694df64e31211e3fe0d6faf8050f
[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[CMDLINE_MAX_TOKEN_SIZE];
146
147         /* if token is too big... */
148         token_len = snprintf(token, sizeof(token), "%s", buf);
149         if (token_len >= sizeof(token))
150                 return -1;
151
152         TAILQ_INIT(&l);
153
154         /* absolute path */
155         if (token[0] == '/' && token[1] == '/') {
156                 /* if contains joker */
157                 if (strchr(token + 2, '*'))
158                         find_in_children(&l, *tkd->root, token+2, tkd->flags,
159                                          tkd->mask, 1);
160                 else {
161                         n = conf_htable_lookup(token + 2);
162                         if ((n->flags & tkd->mask) != tkd->flags)
163                                 return -1;
164                         TAILQ_INSERT_TAIL(&l, n, user_next);
165                 }
166         }
167         /* relative path */
168         else
169                 find_in_children(&l, *tkd->cur, token, tkd->flags, tkd->mask, 0);
170         if (TAILQ_EMPTY(&l))
171                 return -1;
172
173         /* store the address of object in structure */
174         if (res)
175                 *(struct confnode **)res = TAILQ_FIRST(&l);
176
177         return token_len;
178 }
179
180 int complete_get_nb_conf_node(cmdline_parse_token_hdr_t *tk)
181 {
182         struct token_conf_node *tk2 = (struct token_conf_node *)tk;
183         struct token_conf_node_data *tkd = &tk2->conf_node_data;
184
185         return count_children(*tkd->cur, tkd->flags, tkd->mask);
186 }
187
188 int complete_get_elt_conf_node(cmdline_parse_token_hdr_t *tk, int idx,
189                                char *dstbuf, unsigned int size)
190 {
191         struct token_conf_node *tk2 = (struct token_conf_node *)tk;
192         struct token_conf_node_data *tkd = &tk2->conf_node_data;
193         struct confnode *n;
194         unsigned int i = 0, len;
195
196         n = get_from_idx(*tkd->cur, &i, idx, tkd->flags, tkd->mask);
197         if (n == NULL)
198                 return -1;
199
200         len = strlen(n->name) + 1;
201         if (len > size)
202                 return -1;
203
204         strcpy(dstbuf, n->name);
205         return 0;
206 }
207
208
209 int get_help_conf_node(cmdline_parse_token_hdr_t *tk, char *dstbuf, unsigned int size)
210 {
211         snprintf(dstbuf, size, "conf-node");
212         return 0;
213 }