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>