Annotation of embedaddon/bird/client/commands.c, revision 1.1.1.1
1.1 misho 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:
9: #include <stdio.h>
10: #include <ctype.h>
11: #include <stdlib.h>
12:
13: #include "nest/bird.h"
14: #include "lib/resource.h"
15: #include "lib/string.h"
16: #include "client/client.h"
17:
18: struct cmd_info {
19: char *command;
20: char *args;
21: char *help;
22: int is_real_cmd;
23: };
24:
25: static struct cmd_info command_table[] = {
26: #include "conf/commands.h"
27: };
28:
29: struct cmd_node {
30: struct cmd_node *sibling, *son, **plastson;
31: struct cmd_info *cmd, *help;
32: int len;
33: signed char prio;
34: char token[1];
35: };
36:
37: static struct cmd_node cmd_root;
38:
39: void
40: cmd_build_tree(void)
41: {
42: uint i;
43:
44: cmd_root.plastson = &cmd_root.son;
45:
46: for(i=0; i<ARRAY_SIZE(command_table); i++)
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;
56: while (*c && !isspace(*c))
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: {
63: int size = sizeof(struct cmd_node) + c-d;
64: new = malloc(size);
65: bzero(new, size);
66: *old->plastson = new;
67: old->plastson = &new->sibling;
68: new->plastson = &new->son;
69: new->len = c-d;
70: memcpy(new->token, d, c-d);
71: new->prio = (new->len == 3 && (!memcmp(new->token, "roa", 3) || !memcmp(new->token, "rip", 3))) ? 0 : 1; /* Hack */
72: }
73: old = new;
74: while (isspace(*c))
75: c++;
76: }
77: if (cmd->is_real_cmd)
78: old->cmd = cmd;
79: else
80: old->help = cmd;
81: }
82: }
83:
84: static void
85: cmd_do_display_help(struct cmd_info *c)
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:
93: static void
94: cmd_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:
102: static struct cmd_node *
103: cmd_find_abbrev(struct cmd_node *root, char *cmd, int len, int *pambiguous)
104: {
105: struct cmd_node *m, *best = NULL, *best2 = NULL;
106:
107: *pambiguous = 0;
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: {
114: if (best && best->prio > m->prio)
115: continue;
116: if (best && best->prio == m->prio)
117: best2 = best;
118: best = m;
119: }
120: }
121: if (best2)
122: {
123: *pambiguous = 1;
124: return NULL;
125: }
126: return best;
127: }
128:
129: static void
130: cmd_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);
137: }
138:
139: void
140: cmd_help(char *cmd, int len)
141: {
142: char *end = cmd + len;
143: struct cmd_node *n, *m;
144: char *z;
145: int ambig;
146:
147: n = &cmd_root;
148: while (cmd < end)
149: {
150: if (isspace(*cmd))
151: {
152: cmd++;
153: continue;
154: }
155: z = cmd;
156: while (cmd < end && !isspace(*cmd))
157: cmd++;
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: }
164: if (!m)
165: break;
166: n = m;
167: }
168: cmd_display_help(n->cmd, NULL);
169: for (m=n->son; m; m=m->sibling)
170: cmd_display_help(m->help, m->cmd);
171: }
172:
173: static int
174: cmd_find_common_match(struct cmd_node *root, char *cmd, int len, int *pcount, char *buf)
175: {
176: struct cmd_node *m;
177: int best, best_prio, i;
178:
179: *pcount = 0;
180: best = -1;
181: best_prio = -1;
182: for(m=root->son; m; m=m->sibling)
183: {
184: if (m->len < len || memcmp(m->token, cmd, len))
185: continue;
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:
196: (*pcount)++;
197: if (best < 0)
198: {
199: strcpy(buf, m->token + len);
200: best = m->len - len;
201: best_prio = m->prio;
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:
214: int
215: cmd_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: {
232: if (isspace(*cmd))
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;
280: }
281:
282: char *
283: cmd_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: {
315: puts("No such command. Press `?' for help.");
316: return NULL;
317: }
318: b = malloc(strlen(n->cmd->command) + strlen(args) + 1);
319: sprintf(b, "%s%s", n->cmd->command, args);
320: return b;
321: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>