File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird / client / commands.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Aug 22 12:33:54 2017 UTC (6 years, 10 months ago) by misho
Branches: bird, MAIN
CVS tags: v1_6_3p0, v1_6_3, HEAD
bird 1.6.3

    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>