Statistics
| Branch: | Revision:

iof-bird / bird-2.0.1 / client / commands.c @ 6b3f1a54

History | View | Annotate | Download (5.9 KB)

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 <stdlib.h>
11
#include <ctype.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
#define isspace_(X) isspace((unsigned char) (X))
40

    
41
void
42
cmd_build_tree(void)
43
{
44
  uint i;
45

    
46
  cmd_root.plastson = &cmd_root.son;
47

    
48
  for(i=0; i<ARRAY_SIZE(command_table); i++)
49
    {
50
      struct cmd_info *cmd = &command_table[i];
51
      struct cmd_node *old, *new;
52
      char *c = cmd->command;
53

    
54
      old = &cmd_root;
55
      while (*c)
56
        {
57
          char *d = c;
58
          while (*c && !isspace_(*c))
59
            c++;
60
          for(new=old->son; new; new=new->sibling)
61
            if (new->len == c-d && !memcmp(new->token, d, c-d))
62
              break;
63
          if (!new)
64
            {
65
              int size = sizeof(struct cmd_node) + c-d;
66
              new = malloc(size);
67
              bzero(new, size);
68
              *old->plastson = new;
69
              old->plastson = &new->sibling;
70
              new->plastson = &new->son;
71
              new->len = c-d;
72
              memcpy(new->token, d, c-d);
73
              new->prio = (new->len == 3 && (!memcmp(new->token, "roa", 3) || !memcmp(new->token, "rip", 3))) ? 0 : 1; /* Hack */
74
            }
75
          old = new;
76
          while (isspace_(*c))
77
            c++;
78
        }
79
      if (cmd->is_real_cmd)
80
        old->cmd = cmd;
81
      else
82
        old->help = cmd;
83
    }
84
}
85

    
86
static void
87
cmd_do_display_help(struct cmd_info *c)
88
{
89
  char buf[strlen(c->command) + strlen(c->args) + 4];
90

    
91
  sprintf(buf, "%s %s", c->command, c->args);
92
  printf("%-45s  %s\n", buf, c->help);
93
}
94

    
95
static void
96
cmd_display_help(struct cmd_info *c1, struct cmd_info *c2)
97
{
98
  if (c1)
99
    cmd_do_display_help(c1);
100
  else if (c2)
101
    cmd_do_display_help(c2);
102
}
103

    
104
static struct cmd_node *
105
cmd_find_abbrev(struct cmd_node *root, char *cmd, int len, int *pambiguous)
106
{
107
  struct cmd_node *m, *best = NULL, *best2 = NULL;
108

    
109
  *pambiguous = 0;
110
  for(m=root->son; m; m=m->sibling)
111
    {
112
      if (m->len == len && !memcmp(m->token, cmd, len))
113
        return m;
114
      if (m->len > len && !memcmp(m->token, cmd, len))
115
        {
116
          if (best && best->prio > m->prio)
117
            continue;
118
          if (best && best->prio == m->prio)
119
            best2 = best;
120
          best = m;
121
        }
122
    }
123
  if (best2)
124
    {
125
      *pambiguous = 1;
126
      return NULL;
127
    }
128
  return best;
129
}
130

    
131
static void
132
cmd_list_ambiguous(struct cmd_node *root, char *cmd, int len)
133
{
134
  struct cmd_node *m;
135

    
136
  for(m=root->son; m; m=m->sibling)
137
    if (m->len > len && !memcmp(m->token, cmd, len))
138
      cmd_display_help(m->help, m->cmd);
139
}
140

    
141
void
142
cmd_help(char *cmd, int len)
143
{
144
  char *end = cmd + len;
145
  struct cmd_node *n, *m;
146
  char *z;
147
  int ambig;
148

    
149
  n = &cmd_root;
150
  while (cmd < end)
151
    {
152
      if (isspace_(*cmd))
153
        {
154
          cmd++;
155
          continue;
156
        }
157
      z = cmd;
158
      while (cmd < end && !isspace_(*cmd))
159
        cmd++;
160
      m = cmd_find_abbrev(n, z, cmd-z, &ambig);
161
      if (ambig)
162
        {
163
          cmd_list_ambiguous(n, z, cmd-z);
164
          return;
165
        }
166
      if (!m)
167
        break;
168
      n = m;
169
    }
170
  cmd_display_help(n->cmd, NULL);
171
  for (m=n->son; m; m=m->sibling)
172
    cmd_display_help(m->help, m->cmd);
173
}
174

    
175
static int
176
cmd_find_common_match(struct cmd_node *root, char *cmd, int len, int *pcount, char *buf)
177
{
178
  struct cmd_node *m;
179
  int best, best_prio, i;
180

    
181
  *pcount = 0;
182
  best = -1;
183
  best_prio = -1;
184
  for(m=root->son; m; m=m->sibling)
185
    {
186
      if (m->len < len || memcmp(m->token, cmd, len))
187
        continue;
188

    
189
      if (best_prio > m->prio)
190
        continue;
191

    
192
      if (best_prio < m->prio)
193
        {
194
          *pcount = 0;
195
          best = -1;
196
        }
197

    
198
      (*pcount)++;
199
      if (best < 0)
200
        {
201
          strcpy(buf, m->token + len);
202
          best = m->len - len;
203
          best_prio = m->prio;
204
        }
205
      else
206
        {
207
          i = 0;
208
          while (i < best && i < m->len - len && buf[i] == m->token[len+i])
209
            i++;
210
          best = i;
211
        }
212
    }
213
  return best;
214
}
215

    
216
int
217
cmd_complete(char *cmd, int len, char *buf, int again)
218
{
219
  char *start = cmd;
220
  char *end = cmd + len;
221
  char *fin;
222
  struct cmd_node *n, *m;
223
  char *z;
224
  int ambig, cnt = 0, common;
225

    
226
  /* Find the last word we want to complete */
227
  for(fin=end; fin > start && !isspace_(fin[-1]); fin--)
228
    ;
229

    
230
  /* Find the context */
231
  n = &cmd_root;
232
  while (cmd < fin && n->son)
233
    {
234
      if (isspace_(*cmd))
235
        {
236
          cmd++;
237
          continue;
238
        }
239
      z = cmd;
240
      while (cmd < fin && !isspace_(*cmd))
241
        cmd++;
242
      m = cmd_find_abbrev(n, z, cmd-z, &ambig);
243
      if (ambig)
244
        {
245
          if (!again)
246
            return -1;
247
          input_start_list();
248
          cmd_list_ambiguous(n, z, cmd-z);
249
          input_stop_list();
250
          return 0;
251
        }
252
      if (!m)
253
        return -1;
254
      n = m;
255
    }
256

    
257
  /* Completion of parameters is not yet supported */
258
  if (!n->son)
259
    return -1;
260

    
261
  /* We know the context, let's try to complete */
262
  common = cmd_find_common_match(n, fin, end-fin, &cnt, buf);
263
  if (!cnt)
264
    return -1;
265
  if (cnt == 1)
266
    {
267
      buf[common++] = ' ';
268
      buf[common] = 0;
269
      return 1;
270
    }
271
  if (common > 0)
272
    {
273
      buf[common] = 0;
274
      return 1;
275
    }
276
  if (!again)
277
    return -1;
278
  input_start_list();
279
  cmd_list_ambiguous(n, fin, end-fin);
280
  input_stop_list();
281
  return 0;
282
}
283

    
284
char *
285
cmd_expand(char *cmd)
286
{
287
  struct cmd_node *n, *m;
288
  char *c, *b, *args;
289
  int ambig;
290

    
291
  args = c = cmd;
292
  n = &cmd_root;
293
  while (*c)
294
    {
295
      if (isspace_(*c))
296
        {
297
          c++;
298
          continue;
299
        }
300
      b = c;
301
      while (*c && !isspace_(*c))
302
        c++;
303
      m = cmd_find_abbrev(n, b, c-b, &ambig);
304
      if (!m)
305
        {
306
          if (!ambig)
307
            break;
308
          puts("Ambiguous command, possible expansions are:");
309
          cmd_list_ambiguous(n, b, c-b);
310
          return NULL;
311
        }
312
      args = c;
313
      n = m;
314
    }
315
  if (!n->cmd)
316
    {
317
      puts("No such command. Press `?' for help.");
318
      return NULL;
319
    }
320
  b = malloc(strlen(n->cmd->command) + strlen(args) + 1);
321
  sprintf(b, "%s%s", n->cmd->command, args);
322
  return b;
323
}