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);
174 r += add_key(keys, "quit", QUIT, 0);
175 r += add_key(keys, "exit", QUIT, 0);
186 find_key (const char * str)
190 struct key * kw = NULL;
191 struct key * foundkw = NULL;
195 vector_foreach_slot (keys, kw, i) {
196 if (strncmp(kw->str, str, len))
198 klen = strlen(kw->str);
200 return kw; /* exact match */
203 foundkw = kw; /* shortcut match */
205 return NULL; /* ambiguous word */
216 get_cmdvec (char * cmd, vector *v)
222 struct key * kw = NULL;
223 struct key * cmdkw = NULL;
224 vector cmdvec, strvec;
226 strvec = alloc_strvec(cmd);
230 cmdvec = vector_alloc();
236 vector_foreach_slot(strvec, buff, i) {
241 cmdkw->param = strdup(buff);
254 if (!vector_alloc_slot(cmdvec)) {
259 vector_set_slot(cmdvec, cmdkw);
260 cmdkw->code = kw->code;
261 cmdkw->has_param = kw->has_param;
279 fingerprint(vector vec)
288 vector_foreach_slot(vec, kw, i)
295 alloc_handlers (void)
297 handlers = vector_alloc();
306 genhelp_sprint_aliases (char * reply, vector keys, struct key * refkw)
311 vector_foreach_slot (keys, kw, i)
312 if (kw->code == refkw->code && kw != refkw)
313 fwd += sprintf(reply, "|%s", kw->str);
319 genhelp_handler (void)
328 reply = MALLOC(INITIAL_REPLY_LEN);
334 p += sprintf(p, VERSION_STRING);
335 p += sprintf(p, "CLI commands reference:\n");
337 vector_foreach_slot (handlers, h, i) {
339 vector_foreach_slot (keys, kw, j) {
340 if ((kw->code & fp)) {
342 p += sprintf(p, " %s", kw->str);
343 p += genhelp_sprint_aliases(p, keys, kw);
346 p += sprintf(p, " $%s", kw->str);
349 p += sprintf(p, "\n");
356 parse_cmd (char * cmd, char ** reply, int * len, void * data)
362 r = get_cmdvec(cmd, &cmdvec);
367 *reply = genhelp_handler();
368 *len = strlen(*reply) + 1;
372 h = find_handler(fingerprint(cmdvec));
375 *reply = genhelp_handler();
376 *len = strlen(*reply) + 1;
383 r = h->fn(cmdvec, reply, len, data);
390 get_keyparam (vector v, int code)
395 vector_foreach_slot(v, kw, i)
396 if (kw->code == code)
407 if (alloc_handlers())
410 add_handler(LIST+PATHS, NULL);
411 add_handler(LIST+PATHS+FMT, NULL);
412 add_handler(LIST+STATUS, NULL);
413 add_handler(LIST+MAPS, NULL);
414 add_handler(LIST+MAPS+STATUS, NULL);
415 add_handler(LIST+MAPS+STATS, NULL);
416 add_handler(LIST+MAPS+TOPOLOGY, NULL);
417 add_handler(LIST+TOPOLOGY, NULL);
418 add_handler(LIST+MAP+TOPOLOGY, NULL);
419 add_handler(LIST+CONFIG, NULL);
420 add_handler(LIST+BLACKLIST, NULL);
421 add_handler(LIST+DEVICES, NULL);
422 add_handler(LIST+WILDCARDS, NULL);
423 add_handler(ADD+PATH, NULL);
424 add_handler(DEL+PATH, NULL);
425 add_handler(ADD+MAP, NULL);
426 add_handler(DEL+MAP, NULL);
427 add_handler(SWITCH+MAP+GROUP, NULL);
428 add_handler(RECONFIGURE, NULL);
429 add_handler(SUSPEND+MAP, NULL);
430 add_handler(RESUME+MAP, NULL);
431 add_handler(REINSTATE+PATH, NULL);
432 add_handler(FAIL+PATH, NULL);
433 add_handler(QUIT, NULL);
439 key_match_fingerprint (struct key * kw, int fp)
444 return ((fp & kw->code) == kw->code);
448 * This is the readline completion handler
451 key_generator (const char * str, int state)
453 static int index, len, rlfp, has_param;
464 int r = get_cmdvec(rl_line_buffer, &v);
466 * If a word completion is in progess, we don't want
467 * to take an exact keyword match in the fingerprint.
468 * For ex "show map[tab]" would validate "map" and discard
469 * "maps" as a valid candidate.
472 vector_del_slot(v, VECTOR_SIZE(v) - 1);
474 * Clean up the mess if we dropped the last slot of a 1-slot
477 if (v && !VECTOR_SIZE(v)) {
482 * If last keyword takes a param, don't even try to guess
486 return (strdup("(value)"));
489 * Compute a command fingerprint to find out possible completions.
490 * Once done, the vector is useless. Free it.
493 rlfp = fingerprint(v);
498 * No more completions for parameter placeholder.
499 * Brave souls might try to add parameter completion by walking paths and
500 * multipaths vectors.
503 return ((char *)NULL);
505 * Loop through keywords for completion candidates
507 vector_foreach_slot_after (keys, kw, index) {
508 if (!strncmp(kw->str, str, len)) {
510 * Discard keywords already in the command line
512 if (key_match_fingerprint(kw, rlfp)) {
513 struct key * curkw = find_key(str);
514 if (!curkw || (curkw != kw))
518 * Discard keywords making syntax errors.
520 * nfp is the candidate fingerprint we try to
521 * validate against all known command fingerprints.
523 int nfp = rlfp | kw->code;
524 vector_foreach_slot(handlers, h, i) {
525 if (!rlfp || ((h->fingerprint & nfp) == nfp)) {
527 * At least one full command is
528 * possible with this keyword :
529 * Consider it validated
532 return (strdup(kw->str));
540 return ((char *)NULL);