Statistics
| Branch: | Revision:

iof-bird-daemon / client / commands.c @ ae80a2de

History | View | Annotate | Download (5.79 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 <ctype.h>
11

    
12
#include "nest/bird.h"
13
#include "lib/resource.h"
14
#include "lib/string.h"
15
#include "client/client.h"
16

    
17
struct cmd_info {
18
  char *command;
19
  char *args;
20
  char *help;
21
  int is_real_cmd;
22
};
23

    
24
static struct cmd_info command_table[] = {
25
#include "conf/commands.h"
26
};
27

    
28
struct cmd_node {
29
  struct cmd_node *sibling, *son, **plastson;
30
  struct cmd_info *cmd, *help;
31
  int len;
32
  signed char prio;
33
  char token[1];
34
};
35

    
36
static struct cmd_node cmd_root;
37

    
38
void
39
cmd_build_tree(void)
40
{
41
  uint i;
42

    
43
  cmd_root.plastson = &cmd_root.son;
44

    
45
  for(i=0; i<ARRAY_SIZE(command_table); i++)
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;
55
          while (*c && !isspace(*c))
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
            {
62
              int size = sizeof(struct cmd_node) + c-d;
63
              new = xmalloc(size);
64
              bzero(new, size);
65
              *old->plastson = new;
66
              old->plastson = &new->sibling;
67
              new->plastson = &new->son;
68
              new->len = c-d;
69
              memcpy(new->token, d, c-d);
70
              new->prio = (new->len == 3 && !memcmp(new->token, "roa", 3)) ? 0 : 1; /* Hack */
71
            }
72
          old = new;
73
          while (isspace(*c))
74
            c++;
75
        }
76
      if (cmd->is_real_cmd)
77
        old->cmd = cmd;
78
      else
79
        old->help = cmd;
80
    }
81
}
82

    
83
static void
84
cmd_do_display_help(struct cmd_info *c)
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

    
92
static void
93
cmd_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

    
101
static struct cmd_node *
102
cmd_find_abbrev(struct cmd_node *root, char *cmd, int len, int *pambiguous)
103
{
104
  struct cmd_node *m, *best = NULL, *best2 = NULL;
105

    
106
  *pambiguous = 0;
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
        {
113
          if (best && best->prio > m->prio)
114
            continue;
115
          if (best && best->prio == m->prio)
116
            best2 = best;
117
          best = m;
118
        }
119
    }
120
  if (best2)
121
    {
122
      *pambiguous = 1;
123
      return NULL;
124
    }
125
  return best;
126
}
127

    
128
static void
129
cmd_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);
136
}
137

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

    
146
  n = &cmd_root;
147
  while (cmd < end)
148
    {
149
      if (isspace(*cmd))
150
        {
151
          cmd++;
152
          continue;
153
        }
154
      z = cmd;
155
      while (cmd < end && !isspace(*cmd))
156
        cmd++;
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
        }
163
      if (!m)
164
        break;
165
      n = m;
166
    }
167
  cmd_display_help(n->cmd, NULL);
168
  for (m=n->son; m; m=m->sibling)
169
    cmd_display_help(m->help, m->cmd);
170
}
171

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

    
178
  *pcount = 0;
179
  best = -1;
180
  best_prio = -1;
181
  for(m=root->son; m; m=m->sibling)
182
    {
183
      if (m->len < len || memcmp(m->token, cmd, len))
184
        continue;
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

    
195
      (*pcount)++;
196
      if (best < 0)
197
        {
198
          strcpy(buf, m->token + len);
199
          best = m->len - len;
200
          best_prio = m->prio;
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

    
213
int
214
cmd_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
    {
231
      if (isspace(*cmd))
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;
279
}
280

    
281
char *
282
cmd_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
    {
314
      puts("No such command. Press `?' for help.");
315
      return NULL;
316
    }
317
  b = xmalloc(strlen(n->cmd->command) + strlen(args) + 1);
318
  sprintf(b, "%s%s", n->cmd->command, args);
319
  return b;
320
}