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@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 
find_cmd(const struct cmd * cmds,char * str)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 
find_opt(struct opt * opts,char * str)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 
get_opt(struct opt * opts,char * key)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 
has_opt(struct opt * opts,char * key)65 bool has_opt(struct opt *opts, char *key)
66 {
67 	return get_opt(opts, key) ? true : false;
68 }
69 
shift_cmdl(struct cmdl * cmdl)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 */
parse_opts(struct opt * opts,struct cmdl * cmdl)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 
run_cmd(struct nlmsghdr * nlh,const struct cmd * caller,const struct cmd * cmds,struct cmdl * cmdl,void * data)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