Home | History | Annotate | Download | only in tipc
      1 /*
      2  * cmdl.c	Framework for handling command line options.
      3  *
      4  *		This program is free software; you can redistribute it and/or
      5  *		modify it under the terms of the GNU General Public License
      6  *		as published by the Free Software Foundation; either version
      7  *		2 of the License, or (at your option) any later version.
      8  *
      9  * Authors:	Richard Alpe <richard.alpe (at) ericsson.com>
     10  */
     11 
     12 #include <stdio.h>
     13 #include <string.h>
     14 #include <errno.h>
     15 
     16 #include <libmnl/libmnl.h>
     17 
     18 #include "cmdl.h"
     19 
     20 const struct cmd *find_cmd(const struct cmd *cmds, char *str)
     21 {
     22 	const struct cmd *c;
     23 	const struct cmd *match = NULL;
     24 
     25 	for (c = cmds; c->cmd; c++) {
     26 		if (strstr(c->cmd, str) != c->cmd)
     27 			continue;
     28 		if (match)
     29 			return NULL;
     30 		match = c;
     31 	}
     32 
     33 	return match;
     34 }
     35 
     36 static struct opt *find_opt(struct opt *opts, char *str)
     37 {
     38 	struct opt *o;
     39 	struct opt *match = NULL;
     40 
     41 	for (o = opts; o->key; o++) {
     42 		if (strstr(o->key, str) != o->key)
     43 			continue;
     44 		if (match)
     45 			return NULL;
     46 
     47 		match = o;
     48 	}
     49 
     50 	return match;
     51 }
     52 
     53 struct opt *get_opt(struct opt *opts, char *key)
     54 {
     55 	struct opt *o;
     56 
     57 	for (o = opts; o->key; o++) {
     58 		if (strcmp(o->key, key) == 0 && o->val)
     59 			return o;
     60 	}
     61 
     62 	return NULL;
     63 }
     64 
     65 bool has_opt(struct opt *opts, char *key)
     66 {
     67 	return get_opt(opts, key) ? true : false;
     68 }
     69 
     70 char *shift_cmdl(struct cmdl *cmdl)
     71 {
     72 	int next;
     73 
     74 	if (cmdl->optind < cmdl->argc)
     75 		next = (cmdl->optind)++;
     76 	else
     77 		next = cmdl->argc;
     78 
     79 	return cmdl->argv[next];
     80 }
     81 
     82 /* Returns the number of options parsed or a negative error code upon failure */
     83 int parse_opts(struct opt *opts, struct cmdl *cmdl)
     84 {
     85 	int i;
     86 	int cnt = 0;
     87 
     88 	for (i = cmdl->optind; i < cmdl->argc; i++) {
     89 		struct opt *o;
     90 
     91 		o = find_opt(opts, cmdl->argv[i]);
     92 		if (!o) {
     93 			fprintf(stderr, "error, invalid option \"%s\"\n",
     94 					cmdl->argv[i]);
     95 			return -EINVAL;
     96 		}
     97 		if (o->flag & OPT_KEYVAL) {
     98 			cmdl->optind++;
     99 			i++;
    100 		}
    101 		cnt++;
    102 		o->val = cmdl->argv[i];
    103 		cmdl->optind++;
    104 	}
    105 
    106 	return cnt;
    107 }
    108 
    109 int run_cmd(struct nlmsghdr *nlh, const struct cmd *caller,
    110 	    const struct cmd *cmds, struct cmdl *cmdl, void *data)
    111 {
    112 	char *name;
    113 	const struct cmd *cmd;
    114 
    115 	if ((cmdl->optind) >= cmdl->argc) {
    116 		if (caller->help)
    117 			(caller->help)(cmdl);
    118 		return -EINVAL;
    119 	}
    120 	name = cmdl->argv[cmdl->optind];
    121 	(cmdl->optind)++;
    122 
    123 	cmd = find_cmd(cmds, name);
    124 	if (!cmd) {
    125 		/* Show help about last command if we don't find this one */
    126 		if (help_flag && caller->help) {
    127 			(caller->help)(cmdl);
    128 		} else {
    129 			fprintf(stderr, "error, invalid command \"%s\"\n", name);
    130 			fprintf(stderr, "use --help for command help\n");
    131 		}
    132 		return -EINVAL;
    133 	}
    134 
    135 	return (cmd->func)(nlh, cmd, cmdl, data);
    136 }
    137