Merge branch 'master' of ssh://git.dorsal.polymtl.ca/home/git/ust
[lttng-ust.git] / ustctl / cli.c
1 /* Copyright (C) 2011 Ericsson AB, Nils Carlson <nils.carlson@ericsson.com>
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17
18 #define _GNU_SOURCE
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include "cli.h"
23
24 /* This dummy command is needed to create the sections in cli.o before
25 * other .o files have these sections, usefull for development.
26 */
27 static int _dummy(int argc, char *argv[]) {
28 return 0;
29 }
30
31 /* Define a dummy cmd to guarantee existence of the builtin variables */
32 struct cli_cmd __cli_cmds __dummy_cli_cmd[] = {
33 {
34 .name = "_dummy",
35 .description = NULL,
36 .help_text = NULL,
37 .function = _dummy,
38 .desired_args = 0,
39 .desired_args_op = 0,
40 },
41 };
42
43 extern struct cli_cmd __start___cli_cmds[] __attribute__((visibility("hidden")));
44 extern struct cli_cmd __stop___cli_cmds[] __attribute__((visibility("hidden")));
45
46 static struct cli_cmd **cli_cmd_list;
47 static int cli_cmd_list_size;
48
49 static char *process_name;
50
51 static int compute_cli_cmds_size(void)
52 {
53 long cli_cmds_start, cli_cmds_end;
54
55 cli_cmds_start = (long)__start___cli_cmds;
56 cli_cmds_end = (long)__stop___cli_cmds;
57
58 return (cli_cmds_end - cli_cmds_start) / sizeof(struct cli_cmd);
59 }
60
61 static void __attribute__((constructor)) generate_cli_cmd_list(int argc, char *argv[])
62 {
63 struct cli_cmd *cli_cmd;
64 int section_size, i;
65
66 process_name = basename(argv[0]);
67
68 section_size = compute_cli_cmds_size();
69
70 cli_cmd_list = malloc(section_size * sizeof(void *));
71 if (!cli_cmd_list) {
72 fprintf(stderr, "Failed to allocate command list!");
73 exit(EXIT_FAILURE);
74 }
75
76 cli_cmd_list_size = 0;
77
78 cli_cmd = __start___cli_cmds;
79 for (i = 0; i < section_size; i++) {
80 if (&cli_cmd[i] == &__dummy_cli_cmd[0]) {
81 continue;
82 }
83
84 if (cli_cmd[i].name) {
85 cli_cmd_list[cli_cmd_list_size++] = &cli_cmd[i];
86 }
87 }
88 }
89
90 struct cli_cmd *find_cli_cmd(const char *command)
91 {
92 int i;
93
94 for (i = 0; i < cli_cmd_list_size; i++) {
95 if (!strcmp(cli_cmd_list[i]->name, command)) {
96 return cli_cmd_list[i];
97 }
98 }
99
100 return NULL;
101 }
102
103 static int cmpcli_cmds(const void *p1, const void *p2)
104 {
105 return strcmp(* (char * const *) ((struct cli_cmd *)p1)->name,
106 * (char * const *) ((struct cli_cmd *)p2)->name);
107 }
108
109 #define HELP_BUFFER_SIZE 4096
110
111 static void print_cmd_help(const char *prefix, const char *infix,
112 struct cli_cmd *cli_cmd)
113 {
114 if (cli_cmd->help_text) {
115 fprintf(stderr, "%s%s%s",
116 prefix,
117 infix,
118 cli_cmd->help_text);
119 } else if (cli_cmd->description) {
120 fprintf(stderr, "%s%s%s\n%s\n",
121 prefix,
122 infix,
123 cli_cmd->name,
124 cli_cmd->description);
125 } else {
126 fprintf(stderr, "No help available for %s\n",
127 cli_cmd->name);
128 }
129 }
130
131 void list_cli_cmds(int option)
132 {
133 int i;
134
135 qsort(cli_cmd_list, cli_cmd_list_size, sizeof(void *), cmpcli_cmds);
136
137 for (i = 0; i < cli_cmd_list_size; i++) {
138 switch (option) {
139 case CLI_SIMPLE_LIST:
140 fprintf(stderr, "%s ", cli_cmd_list[i]->name);
141 break;
142 case CLI_DESCRIPTIVE_LIST:
143 fprintf(stderr, " %-25s%s\n", cli_cmd_list[i]->name,
144 cli_cmd_list[i]->description);
145 break;
146 case CLI_EXTENDED_LIST:
147 print_cmd_help("", "", cli_cmd_list[i]);
148 fprintf(stderr, "\n");
149 break;
150 }
151 }
152
153 if (option == CLI_SIMPLE_LIST) {
154 fprintf(stderr, "\n");
155 }
156 }
157
158 int cli_print_help(const char *command)
159 {
160 struct cli_cmd *cli_cmd;
161
162 cli_cmd = find_cli_cmd(command);
163 if (!cli_cmd) {
164 return -1;
165 }
166
167 print_cmd_help(process_name, " ", cli_cmd);
168
169 return 0;
170 }
171
172 static void cli_check_argc(const char *command, int args,
173 int operator, int desired_args)
174 {
175 switch(operator) {
176 case CLI_EQ:
177 if (args != desired_args)
178 goto print_error;
179 break;
180 case CLI_GE:
181 if (args < desired_args)
182 goto print_error;
183 break;
184 }
185
186 return;
187
188 print_error:
189 fprintf(stderr, "%s %s requires %s%d argument%s, see usage.\n",
190 process_name, command, operator == CLI_EQ ? "" : "at least ",
191 desired_args, desired_args > 1 ? "s" : "");
192 cli_print_help(command);
193 exit(EXIT_FAILURE);
194 }
195
196
197 void cli_dispatch_cmd(struct cli_cmd *cmd, int argc, char *argv[])
198 {
199 cli_check_argc(cmd->name, argc - 1, cmd->desired_args_op,
200 cmd->desired_args);
201
202 if (cmd->function(argc, argv)) {
203 exit(EXIT_FAILURE);
204 }
205
206 exit(EXIT_SUCCESS);
207 }
This page took 0.034944 seconds and 5 git commands to generate.