]> git.ipfire.org Git - thirdparty/bird.git/blame - client/commands.c
Client: Includes stdlib.h for malloc()
[thirdparty/bird.git] / client / commands.c
CommitLineData
9fac310d
MM
1/*
2 * BIRD Client -- Command Handling
3 *
4 * (c) 1999--2000 Martin Mares <mj@ucw.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
0223d4ff 9#include <stdio.h>
044e123f 10#include <stdlib.h>
fae0396e 11#include <ctype.h>
0223d4ff 12
9fac310d 13#include "nest/bird.h"
0223d4ff 14#include "lib/resource.h"
221135d6 15#include "lib/string.h"
9fac310d
MM
16#include "client/client.h"
17
18struct cmd_info {
19 char *command;
20 char *args;
21 char *help;
0223d4ff 22 int is_real_cmd;
9fac310d
MM
23};
24
0223d4ff 25static struct cmd_info command_table[] = {
9fac310d
MM
26#include "conf/commands.h"
27};
0223d4ff 28
0223d4ff
MM
29struct cmd_node {
30 struct cmd_node *sibling, *son, **plastson;
fae0396e 31 struct cmd_info *cmd, *help;
0223d4ff 32 int len;
c47d037e 33 signed char prio;
0223d4ff
MM
34 char token[1];
35};
36
37static struct cmd_node cmd_root;
38
39void
40cmd_build_tree(void)
41{
ae80a2de 42 uint i;
0223d4ff
MM
43
44 cmd_root.plastson = &cmd_root.son;
45
77506349 46 for(i=0; i<ARRAY_SIZE(command_table); i++)
0223d4ff
MM
47 {
48 struct cmd_info *cmd = &command_table[i];
49 struct cmd_node *old, *new;
50 char *c = cmd->command;
51
52 old = &cmd_root;
53 while (*c)
54 {
55 char *d = c;
e69e4ed9 56 while (*c && !isspace(*c))
0223d4ff
MM
57 c++;
58 for(new=old->son; new; new=new->sibling)
59 if (new->len == c-d && !memcmp(new->token, d, c-d))
60 break;
61 if (!new)
62 {
fae0396e 63 int size = sizeof(struct cmd_node) + c-d;
3f2c7600 64 new = malloc(size);
fae0396e 65 bzero(new, size);
0223d4ff
MM
66 *old->plastson = new;
67 old->plastson = &new->sibling;
0223d4ff 68 new->plastson = &new->son;
0223d4ff
MM
69 new->len = c-d;
70 memcpy(new->token, d, c-d);
8465dccb 71 new->prio = (new->len == 3 && (!memcmp(new->token, "roa", 3) || !memcmp(new->token, "rip", 3))) ? 0 : 1; /* Hack */
0223d4ff
MM
72 }
73 old = new;
e69e4ed9 74 while (isspace(*c))
0223d4ff
MM
75 c++;
76 }
fae0396e
MM
77 if (cmd->is_real_cmd)
78 old->cmd = cmd;
79 else
80 old->help = cmd;
0223d4ff
MM
81 }
82}
83
84static void
fae0396e 85cmd_do_display_help(struct cmd_info *c)
0223d4ff
MM
86{
87 char buf[strlen(c->command) + strlen(c->args) + 4];
88
89 sprintf(buf, "%s %s", c->command, c->args);
90 printf("%-45s %s\n", buf, c->help);
91}
92
fae0396e
MM
93static void
94cmd_display_help(struct cmd_info *c1, struct cmd_info *c2)
95{
96 if (c1)
97 cmd_do_display_help(c1);
98 else if (c2)
99 cmd_do_display_help(c2);
100}
101
0223d4ff 102static struct cmd_node *
fae0396e 103cmd_find_abbrev(struct cmd_node *root, char *cmd, int len, int *pambiguous)
0223d4ff
MM
104{
105 struct cmd_node *m, *best = NULL, *best2 = NULL;
106
fae0396e 107 *pambiguous = 0;
0223d4ff
MM
108 for(m=root->son; m; m=m->sibling)
109 {
110 if (m->len == len && !memcmp(m->token, cmd, len))
111 return m;
112 if (m->len > len && !memcmp(m->token, cmd, len))
113 {
c47d037e
OZ
114 if (best && best->prio > m->prio)
115 continue;
116 if (best && best->prio == m->prio)
117 best2 = best;
0223d4ff
MM
118 best = m;
119 }
120 }
fae0396e
MM
121 if (best2)
122 {
123 *pambiguous = 1;
124 return NULL;
125 }
126 return best;
127}
128
129static void
130cmd_list_ambiguous(struct cmd_node *root, char *cmd, int len)
131{
132 struct cmd_node *m;
133
134 for(m=root->son; m; m=m->sibling)
135 if (m->len > len && !memcmp(m->token, cmd, len))
136 cmd_display_help(m->help, m->cmd);
0223d4ff
MM
137}
138
139void
140cmd_help(char *cmd, int len)
141{
142 char *end = cmd + len;
143 struct cmd_node *n, *m;
144 char *z;
fae0396e 145 int ambig;
0223d4ff
MM
146
147 n = &cmd_root;
148 while (cmd < end)
149 {
e69e4ed9 150 if (isspace(*cmd))
0223d4ff
MM
151 {
152 cmd++;
153 continue;
154 }
155 z = cmd;
e69e4ed9 156 while (cmd < end && !isspace(*cmd))
0223d4ff 157 cmd++;
fae0396e
MM
158 m = cmd_find_abbrev(n, z, cmd-z, &ambig);
159 if (ambig)
160 {
161 cmd_list_ambiguous(n, z, cmd-z);
162 return;
163 }
0223d4ff
MM
164 if (!m)
165 break;
166 n = m;
167 }
fae0396e 168 cmd_display_help(n->cmd, NULL);
0223d4ff 169 for (m=n->son; m; m=m->sibling)
fae0396e
MM
170 cmd_display_help(m->help, m->cmd);
171}
172
173static int
174cmd_find_common_match(struct cmd_node *root, char *cmd, int len, int *pcount, char *buf)
175{
176 struct cmd_node *m;
c47d037e 177 int best, best_prio, i;
fae0396e
MM
178
179 *pcount = 0;
180 best = -1;
c47d037e 181 best_prio = -1;
fae0396e
MM
182 for(m=root->son; m; m=m->sibling)
183 {
184 if (m->len < len || memcmp(m->token, cmd, len))
185 continue;
c47d037e
OZ
186
187 if (best_prio > m->prio)
188 continue;
189
190 if (best_prio < m->prio)
191 {
192 *pcount = 0;
193 best = -1;
194 }
195
fae0396e
MM
196 (*pcount)++;
197 if (best < 0)
198 {
199 strcpy(buf, m->token + len);
200 best = m->len - len;
c47d037e 201 best_prio = m->prio;
fae0396e
MM
202 }
203 else
204 {
205 i = 0;
206 while (i < best && i < m->len - len && buf[i] == m->token[len+i])
207 i++;
208 best = i;
209 }
210 }
211 return best;
212}
213
214int
215cmd_complete(char *cmd, int len, char *buf, int again)
216{
217 char *start = cmd;
218 char *end = cmd + len;
219 char *fin;
220 struct cmd_node *n, *m;
221 char *z;
222 int ambig, cnt = 0, common;
223
224 /* Find the last word we want to complete */
225 for(fin=end; fin > start && !isspace(fin[-1]); fin--)
226 ;
227
228 /* Find the context */
229 n = &cmd_root;
230 while (cmd < fin && n->son)
231 {
e69e4ed9 232 if (isspace(*cmd))
fae0396e
MM
233 {
234 cmd++;
235 continue;
236 }
237 z = cmd;
238 while (cmd < fin && !isspace(*cmd))
239 cmd++;
240 m = cmd_find_abbrev(n, z, cmd-z, &ambig);
241 if (ambig)
242 {
243 if (!again)
244 return -1;
245 input_start_list();
246 cmd_list_ambiguous(n, z, cmd-z);
247 input_stop_list();
248 return 0;
249 }
250 if (!m)
251 return -1;
252 n = m;
253 }
254
255 /* Completion of parameters is not yet supported */
256 if (!n->son)
257 return -1;
258
259 /* We know the context, let's try to complete */
260 common = cmd_find_common_match(n, fin, end-fin, &cnt, buf);
261 if (!cnt)
262 return -1;
263 if (cnt == 1)
264 {
265 buf[common++] = ' ';
266 buf[common] = 0;
267 return 1;
268 }
269 if (common > 0)
270 {
271 buf[common] = 0;
272 return 1;
273 }
274 if (!again)
275 return -1;
276 input_start_list();
277 cmd_list_ambiguous(n, fin, end-fin);
278 input_stop_list();
279 return 0;
0223d4ff 280}
e69e4ed9
MM
281
282char *
283cmd_expand(char *cmd)
284{
285 struct cmd_node *n, *m;
286 char *c, *b, *args;
287 int ambig;
288
289 args = c = cmd;
290 n = &cmd_root;
291 while (*c)
292 {
293 if (isspace(*c))
294 {
295 c++;
296 continue;
297 }
298 b = c;
299 while (*c && !isspace(*c))
300 c++;
301 m = cmd_find_abbrev(n, b, c-b, &ambig);
302 if (!m)
303 {
304 if (!ambig)
305 break;
306 puts("Ambiguous command, possible expansions are:");
307 cmd_list_ambiguous(n, b, c-b);
308 return NULL;
309 }
310 args = c;
311 n = m;
312 }
313 if (!n->cmd)
314 {
2983460b 315 puts("No such command. Press `?' for help.");
e69e4ed9
MM
316 return NULL;
317 }
3f2c7600 318 b = malloc(strlen(n->cmd->command) + strlen(args) + 1);
e69e4ed9
MM
319 sprintf(b, "%s%s", n->cmd->command, args);
320 return b;
321}