2 * Copyright (c) 2005 Christophe Varoqui
9 #include <readline/readline.h>
16 return (struct key *)MALLOC(sizeof(struct key));
19 static struct handler *
22 return (struct handler *)MALLOC(sizeof(struct handler));
26 add_key (vector vec, char * str, int code, int has_param)
36 kw->has_param = has_param;
37 kw->str = STRDUP(str);
42 if (!vector_alloc_slot(vec))
45 vector_set_slot(vec, kw);
57 add_handler (int fp, int (*fn)(void *, char **, int *, void *))
66 if (!vector_alloc_slot(handlers)) {
71 vector_set_slot(handlers, h);
78 static struct handler *
84 vector_foreach_slot (handlers, h, i)
85 if (h->fingerprint == fp)
92 set_handler_callback (int fp, int (*fn)(void *, char **, int *, void *))
94 struct handler * h = find_handler(fp);
103 free_key (struct key * kw)
115 free_keys (vector vec)
120 vector_foreach_slot (vec, kw, i)
127 free_handlers (vector vec)
132 vector_foreach_slot (vec, h, i)
142 keys = vector_alloc();
147 r += add_key(keys, "list", LIST, 0);
148 r += add_key(keys, "show", LIST, 0);
149 r += add_key(keys, "add", ADD, 0);
150 r += add_key(keys, "remove", DEL, 0);
151 r += add_key(keys, "del", DEL, 0);
152 r += add_key(keys, "switch", SWITCH, 0);
153 r += add_key(keys, "switchgroup", SWITCH, 0);
154 r += add_key(keys, "suspend", SUSPEND, 0);
155 r += add_key(keys, "resume", RESUME, 0);
156 r += add_key(keys, "reinstate", REINSTATE, 0);
157 r += add_key(keys, "fail", FAIL, 0);
158 r += add_key(keys, "paths", PATHS, 0);
159 r += add_key(keys, "maps", MAPS, 0);
160 r += add_key(keys, "multipaths", MAPS, 0);
161 r += add_key(keys, "path", PATH, 1);
162 r += add_key(keys, "map", MAP, 1);
163 r += add_key(keys, "multipath", MAP, 1);
164 r += add_key(keys, "group", GROUP, 1);
165 r += add_key(keys, "reconfigure", RECONFIGURE, 0);
166 r += add_key(keys, "status", STATUS, 0);
167 r += add_key(keys, "stats", STATS, 0);
168 r += add_key(keys, "topology", TOPOLOGY, 0);
169 r += add_key(keys, "config", CONFIG, 0);
170 r += add_key(keys, "blacklist", BLACKLIST, 0);
171 r += add_key(keys, "devices", DEVICES, 0);
172 r += add_key(keys, "format", FMT, 1);
173 r += add_key(keys, "wildcards", WILDCARDS, 0);
184 find_key (const char * str)
188 struct key * kw = NULL;
189 struct key * foundkw = NULL;
193 vector_foreach_slot (keys, kw, i) {
194 if (strncmp(kw->str, str, len))
196 klen = strlen(kw->str);
198 return kw; /* exact match */
201 foundkw = kw; /* shortcut match */
203 return NULL; /* ambiguous word */
214 get_cmdvec (char * cmd, vector *v)
220 struct key * kw = NULL;
221 struct key * cmdkw = NULL;
222 vector cmdvec, strvec;
224 strvec = alloc_strvec(cmd);
228 cmdvec = vector_alloc();
234 vector_foreach_slot(strvec, buff, i) {
239 cmdkw->param = strdup(buff);
252 if (!vector_alloc_slot(cmdvec)) {
257 vector_set_slot(cmdvec, cmdkw);
258 cmdkw->code = kw->code;
259 cmdkw->has_param = kw->has_param;
277 fingerprint(vector vec)
286 vector_foreach_slot(vec, kw, i)
293 alloc_handlers (void)
295 handlers = vector_alloc();
304 genhelp_sprint_aliases (char * reply, vector keys, struct key * refkw)
309 vector_foreach_slot (keys, kw, i)
310 if (kw->code == refkw->code && kw != refkw)
311 fwd += sprintf(reply, "|%s", kw->str);
317 genhelp_handler (void)
326 reply = MALLOC(INITIAL_REPLY_LEN);
332 p += sprintf(p, VERSION_STRING);
333 p += sprintf(p, "CLI commands reference:\n");
335 vector_foreach_slot (handlers, h, i) {
337 vector_foreach_slot (keys, kw, j) {
338 if ((kw->code & fp)) {
340 p += sprintf(p, " %s", kw->str);
341 p += genhelp_sprint_aliases(p, keys, kw);
344 p += sprintf(p, " $%s", kw->str);
347 p += sprintf(p, "\n");
354 parse_cmd (char * cmd, char ** reply, int * len, void * data)
360 r = get_cmdvec(cmd, &cmdvec);
365 *reply = genhelp_handler();
366 *len = strlen(*reply) + 1;
370 h = find_handler(fingerprint(cmdvec));
373 *reply = genhelp_handler();
374 *len = strlen(*reply) + 1;
381 r = h->fn(cmdvec, reply, len, data);
388 get_keyparam (vector v, int code)
393 vector_foreach_slot(v, kw, i)
394 if (kw->code == code)
405 if (alloc_handlers())
408 add_handler(LIST+PATHS, NULL);
409 add_handler(LIST+PATHS+FMT, NULL);
410 add_handler(LIST+STATUS, NULL);
411 add_handler(LIST+MAPS, NULL);
412 add_handler(LIST+MAPS+STATUS, NULL);
413 add_handler(LIST+MAPS+STATS, NULL);
414 add_handler(LIST+MAPS+TOPOLOGY, NULL);
415 add_handler(LIST+TOPOLOGY, NULL);
416 add_handler(LIST+MAP+TOPOLOGY, NULL);
417 add_handler(LIST+CONFIG, NULL);
418 add_handler(LIST+BLACKLIST, NULL);
419 add_handler(LIST+DEVICES, NULL);
420 add_handler(LIST+WILDCARDS, NULL);
421 add_handler(ADD+PATH, NULL);
422 add_handler(DEL+PATH, NULL);
423 add_handler(ADD+MAP, NULL);
424 add_handler(DEL+MAP, NULL);
425 add_handler(SWITCH+MAP+GROUP, NULL);
426 add_handler(RECONFIGURE, NULL);
427 add_handler(SUSPEND+MAP, NULL);
428 add_handler(RESUME+MAP, NULL);
429 add_handler(REINSTATE+PATH, NULL);
430 add_handler(FAIL+PATH, NULL);
436 key_match_fingerprint (struct key * kw, int fp)
441 return ((fp & kw->code) == kw->code);
445 * This is the readline completion handler
448 key_generator (const char * str, int state)
450 static int index, len, rlfp, has_param;
461 int r = get_cmdvec(rl_line_buffer, &v);
463 * If a word completion is in progess, we don't want
464 * to take an exact keyword match in the fingerprint.
465 * For ex "show map[tab]" would validate "map" and discard
466 * "maps" as a valid candidate.
469 vector_del_slot(v, VECTOR_SIZE(v) - 1);
471 * Clean up the mess if we dropped the last slot of a 1-slot
474 if (v && !VECTOR_SIZE(v)) {
479 * If last keyword takes a param, don't even try to guess
483 return (strdup("(value)"));
486 * Compute a command fingerprint to find out possible completions.
487 * Once done, the vector is useless. Free it.
490 rlfp = fingerprint(v);
495 * No more completions for parameter placeholder.
496 * Brave souls might try to add parameter completion by walking paths and
497 * multipaths vectors.
500 return ((char *)NULL);
502 * Loop through keywords for completion candidates
504 vector_foreach_slot_after (keys, kw, index) {
505 if (!strncmp(kw->str, str, len)) {
507 * Discard keywords already in the command line
509 if (key_match_fingerprint(kw, rlfp)) {
510 struct key * curkw = find_key(str);
511 if (!curkw || (curkw != kw))
515 * Discard keywords making syntax errors.
517 * nfp is the candidate fingerprint we try to
518 * validate against all known command fingerprints.
520 int nfp = rlfp | kw->code;
521 vector_foreach_slot(handlers, h, i) {
522 if (!rlfp || ((h->fingerprint & nfp) == nfp)) {
524 * At least one full command is
525 * possible with this keyword :
526 * Consider it validated
529 return (strdup(kw->str));
537 return ((char *)NULL);