Annotation of embedaddon/bird/client/commands.c, revision 1.1.1.2

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: 
1.1.1.2 ! misho      39: #define isspace_(X) isspace((unsigned char) (X))
        !            40: 
1.1       misho      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;
1.1.1.2 ! misho      58:          while (*c && !isspace_(*c))
1.1       misho      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;
1.1.1.2 ! misho      76:          while (isspace_(*c))
1.1       misho      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)
1.1.1.2 ! misho     137:     if (m->len > len && !memcmp(m->token, cmd, len))
1.1       misho     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:     {
1.1.1.2 ! misho     152:       if (isspace_(*cmd))
1.1       misho     153:        {
                    154:          cmd++;
                    155:          continue;
                    156:        }
                    157:       z = cmd;
1.1.1.2 ! misho     158:       while (cmd < end && !isspace_(*cmd))
1.1       misho     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 */
1.1.1.2 ! misho     227:   for(fin=end; fin > start && !isspace_(fin[-1]); fin--)
1.1       misho     228:     ;
                    229: 
                    230:   /* Find the context */
                    231:   n = &cmd_root;
                    232:   while (cmd < fin && n->son)
                    233:     {
1.1.1.2 ! misho     234:       if (isspace_(*cmd))
1.1       misho     235:        {
                    236:          cmd++;
                    237:          continue;
                    238:        }
                    239:       z = cmd;
1.1.1.2 ! misho     240:       while (cmd < fin && !isspace_(*cmd))
1.1       misho     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:     {
1.1.1.2 ! misho     295:       if (isspace_(*c))
1.1       misho     296:        {
                    297:          c++;
                    298:          continue;
                    299:        }
                    300:       b = c;
1.1.1.2 ! misho     301:       while (*c && !isspace_(*c))
1.1       misho     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: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>