Statistics
| Branch: | Revision:

iof-bird-daemon / client / commands.c @ 2983460b

History | View | Annotate | Download (5.44 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
  char token[1];
33
};
34

    
35
static struct cmd_node cmd_root;
36

    
37
void
38
cmd_build_tree(void)
39
{
40
  unsigned int i;
41

    
42
  cmd_root.plastson = &cmd_root.son;
43

    
44
  for(i=0; i<ARRAY_SIZE(command_table); i++)
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;
54
          while (*c && !isspace(*c))
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
            {
61
              int size = sizeof(struct cmd_node) + c-d;
62
              new = xmalloc(size);
63
              bzero(new, size);
64
              *old->plastson = new;
65
              old->plastson = &new->sibling;
66
              new->plastson = &new->son;
67
              new->len = c-d;
68
              memcpy(new->token, d, c-d);
69
            }
70
          old = new;
71
          while (isspace(*c))
72
            c++;
73
        }
74
      if (cmd->is_real_cmd)
75
        old->cmd = cmd;
76
      else
77
        old->help = cmd;
78
    }
79
}
80

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

    
90
static void
91
cmd_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

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

    
104
  *pambiguous = 0;
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
    }
115
  if (best2)
116
    {
117
      *pambiguous = 1;
118
      return NULL;
119
    }
120
  return best;
121
}
122

    
123
static void
124
cmd_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);
131
}
132

    
133
void
134
cmd_help(char *cmd, int len)
135
{
136
  char *end = cmd + len;
137
  struct cmd_node *n, *m;
138
  char *z;
139
  int ambig;
140

    
141
  n = &cmd_root;
142
  while (cmd < end)
143
    {
144
      if (isspace(*cmd))
145
        {
146
          cmd++;
147
          continue;
148
        }
149
      z = cmd;
150
      while (cmd < end && !isspace(*cmd))
151
        cmd++;
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
        }
158
      if (!m)
159
        break;
160
      n = m;
161
    }
162
  cmd_display_help(n->cmd, NULL);
163
  for (m=n->son; m; m=m->sibling)
164
    cmd_display_help(m->help, m->cmd);
165
}
166

    
167
static int
168
cmd_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

    
196
int
197
cmd_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
    {
214
      if (isspace(*cmd))
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;
262
}
263

    
264
char *
265
cmd_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
    {
297
      puts("No such command. Press `?' for help.");
298
      return NULL;
299
    }
300
  b = xmalloc(strlen(n->cmd->command) + strlen(args) + 1);
301
  sprintf(b, "%s%s", n->cmd->command, args);
302
  return b;
303
}