Annotation of embedaddon/bird2/client/commands.c, revision 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 <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: }

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