Update version to 0.16
[ust.git] / ustctl / cli.c
CommitLineData
0c89df6c
NC
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 */
27static int _dummy(int argc, char *argv[]) {
28 return 0;
29}
30
31/* Define a dummy cmd to guarantee existence of the builtin variables */
32struct 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
43extern struct cli_cmd __start___cli_cmds[] __attribute__((visibility("hidden")));
44extern struct cli_cmd __stop___cli_cmds[] __attribute__((visibility("hidden")));
45
46static struct cli_cmd **cli_cmd_list;
47static int cli_cmd_list_size;
48
49static char *process_name;
50
51static 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
61static 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
90struct 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
103static 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
111static 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
131void 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
158int 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
172static 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
188print_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
197void 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.032361 seconds and 4 git commands to generate.