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, "resize", RESIZE, 0);
159 r += add_key(keys, "disablequeueing", DISABLEQ, 0);
160 r += add_key(keys, "restorequeueing", RESTOREQ, 0);
161 r += add_key(keys, "paths", PATHS, 0);
162 r += add_key(keys, "maps", MAPS, 0);
163 r += add_key(keys, "multipaths", MAPS, 0);
164 r += add_key(keys, "path", PATH, 1);
165 r += add_key(keys, "map", MAP, 1);
166 r += add_key(keys, "multipath", MAP, 1);
167 r += add_key(keys, "group", GROUP, 1);
168 r += add_key(keys, "reconfigure", RECONFIGURE, 0);
169 r += add_key(keys, "status", STATUS, 0);
170 r += add_key(keys, "stats", STATS, 0);
171 r += add_key(keys, "topology", TOPOLOGY, 0);
172 r += add_key(keys, "config", CONFIG, 0);
173 r += add_key(keys, "blacklist", BLACKLIST, 0);
174 r += add_key(keys, "devices", DEVICES, 0);
175 r += add_key(keys, "format", FMT, 1);
176 r += add_key(keys, "wildcards", WILDCARDS, 0);
177 r += add_key(keys, "quit", QUIT, 0);
178 r += add_key(keys, "exit", QUIT, 0);
189 find_key (const char * str)
193 struct key * kw = NULL;
194 struct key * foundkw = NULL;
198 vector_foreach_slot (keys, kw, i) {
199 if (strncmp(kw->str, str, len))
201 klen = strlen(kw->str);
203 return kw; /* exact match */
206 foundkw = kw; /* shortcut match */
208 return NULL; /* ambiguous word */
219 get_cmdvec (char * cmd, vector *v)
225 struct key * kw = NULL;
226 struct key * cmdkw = NULL;
227 vector cmdvec, strvec;
229 strvec = alloc_strvec(cmd);
233 cmdvec = vector_alloc();
239 vector_foreach_slot(strvec, buff, i) {
244 cmdkw->param = strdup(buff);
257 if (!vector_alloc_slot(cmdvec)) {
262 vector_set_slot(cmdvec, cmdkw);
263 cmdkw->code = kw->code;
264 cmdkw->has_param = kw->has_param;
282 fingerprint(vector vec)
291 vector_foreach_slot(vec, kw, i)
298 alloc_handlers (void)
300 handlers = vector_alloc();
309 genhelp_sprint_aliases (char * reply, vector keys, struct key * refkw)
314 vector_foreach_slot (keys, kw, i)
315 if (kw->code == refkw->code && kw != refkw)
316 fwd += sprintf(reply, "|%s", kw->str);
322 genhelp_handler (void)
331 reply = MALLOC(INITIAL_REPLY_LEN);
337 p += sprintf(p, VERSION_STRING);
338 p += sprintf(p, "CLI commands reference:\n");
340 vector_foreach_slot (handlers, h, i) {
342 vector_foreach_slot (keys, kw, j) {
343 if ((kw->code & fp)) {
345 p += sprintf(p, " %s", kw->str);
346 p += genhelp_sprint_aliases(p, keys, kw);
349 p += sprintf(p, " $%s", kw->str);
352 p += sprintf(p, "\n");
359 parse_cmd (char * cmd, char ** reply, int * len, void * data)
365 r = get_cmdvec(cmd, &cmdvec);
370 *reply = genhelp_handler();
371 *len = strlen(*reply) + 1;
375 h = find_handler(fingerprint(cmdvec));
378 *reply = genhelp_handler();
379 *len = strlen(*reply) + 1;
386 r = h->fn(cmdvec, reply, len, data);
393 get_keyparam (vector v, int code)
398 vector_foreach_slot(v, kw, i)
399 if (kw->code == code)
410 if (alloc_handlers())
413 add_handler(LIST+PATHS, NULL);
414 add_handler(LIST+PATHS+FMT, NULL);
415 add_handler(LIST+STATUS, NULL);
416 add_handler(LIST+MAPS, NULL);
417 add_handler(LIST+MAPS+STATUS, NULL);
418 add_handler(LIST+MAPS+STATS, NULL);
419 add_handler(LIST+MAPS+FMT, NULL);
420 add_handler(LIST+MAPS+TOPOLOGY, NULL);
421 add_handler(LIST+TOPOLOGY, NULL);
422 add_handler(LIST+MAP+TOPOLOGY, NULL);
423 add_handler(LIST+CONFIG, NULL);
424 add_handler(LIST+BLACKLIST, NULL);
425 add_handler(LIST+DEVICES, NULL);
426 add_handler(LIST+WILDCARDS, NULL);
427 add_handler(ADD+PATH, NULL);
428 add_handler(DEL+PATH, NULL);
429 add_handler(ADD+MAP, NULL);
430 add_handler(DEL+MAP, NULL);
431 add_handler(SWITCH+MAP+GROUP, NULL);
432 add_handler(RECONFIGURE, NULL);
433 add_handler(SUSPEND+MAP, NULL);
434 add_handler(RESUME+MAP, NULL);
435 add_handler(RESIZE+MAP, NULL);
436 add_handler(DISABLEQ+MAP, NULL);
437 add_handler(RESTOREQ+MAP, NULL);
438 add_handler(DISABLEQ+MAPS, NULL);
439 add_handler(RESTOREQ+MAPS, NULL);
440 add_handler(REINSTATE+PATH, NULL);
441 add_handler(FAIL+PATH, NULL);
442 add_handler(QUIT, NULL);
448 key_match_fingerprint (struct key * kw, int fp)
453 return ((fp & kw->code) == kw->code);
457 * This is the readline completion handler
460 key_generator (const char * str, int state)
462 static int index, len, rlfp, has_param;
473 int r = get_cmdvec(rl_line_buffer, &v);
475 * If a word completion is in progess, we don't want
476 * to take an exact keyword match in the fingerprint.
477 * For ex "show map[tab]" would validate "map" and discard
478 * "maps" as a valid candidate.
481 vector_del_slot(v, VECTOR_SIZE(v) - 1);
483 * Clean up the mess if we dropped the last slot of a 1-slot
486 if (v && !VECTOR_SIZE(v)) {
491 * If last keyword takes a param, don't even try to guess
495 return (strdup("(value)"));
498 * Compute a command fingerprint to find out possible completions.
499 * Once done, the vector is useless. Free it.
502 rlfp = fingerprint(v);
507 * No more completions for parameter placeholder.
508 * Brave souls might try to add parameter completion by walking paths and
509 * multipaths vectors.
512 return ((char *)NULL);
514 * Loop through keywords for completion candidates
516 vector_foreach_slot_after (keys, kw, index) {
517 if (!strncmp(kw->str, str, len)) {
519 * Discard keywords already in the command line
521 if (key_match_fingerprint(kw, rlfp)) {
522 struct key * curkw = find_key(str);
523 if (!curkw || (curkw != kw))
527 * Discard keywords making syntax errors.
529 * nfp is the candidate fingerprint we try to
530 * validate against all known command fingerprints.
532 int nfp = rlfp | kw->code;
533 vector_foreach_slot(handlers, h, i) {
534 if (!rlfp || ((h->fingerprint & nfp) == nfp)) {
536 * At least one full command is
537 * possible with this keyword :
538 * Consider it validated
541 return (strdup(kw->str));
549 return ((char *)NULL);