File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird / client / commands.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 19:50:23 2021 UTC (3 years, 4 months ago) by misho
Branches: bird, MAIN
CVS tags: v1_6_8p3, HEAD
bird 1.6.8

    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: #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>