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>