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