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