2 * command.c: Library for interactive commandline interfaces
4 * Copyright (C) 2009 Matthias Bolte <matthias.bolte@googlemail.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <libvscmisc/assert.h>
28 #include <libvscmisc/error.h>
29 #include <libvscmisc/list.h>
30 #include <libvscmisc/memory.h>
31 #include <libvscmisc/string.h>
33 #include "../include/libvsccli/command.h"
34 #include "../include/libvsccli/option.h"
39 extern const struct VscCliCommandInfo **_vsc_cli_command_infos;
41 const struct VscCliCommandInfo *
42 _vsc_cli_command_info_lookup (const char *command_name)
46 VSC__ASSERT (command_name != NULL);
48 for (i = 0; _vsc_cli_command_infos[i] != NULL; i++) {
49 if (strcmp (command_name, _vsc_cli_command_infos[i]->name) == 0) {
50 return _vsc_cli_command_infos[i];
58 _command_free (struct VscCliCommand **command)
60 VSC__ASSERT (command != NULL);
62 if (*command != NULL) {
63 vsc_cli_option_list_free (&(*command)->option_list);
69 static struct VscCliCommand *
70 _command_duplicate (struct VscError *error,
71 const struct VscCliCommand *command)
73 struct VscCliCommand *command_duplicate = NULL;
75 VSC__ASSERT (error != NULL);
76 VSC__ASSERT (! error->occured);
77 VSC__ASSERT (command != NULL);
79 command_duplicate = vsc_memdup (error, command,
80 sizeof (struct VscCliCommand));
83 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
87 command_duplicate->option_list =
88 _vsc_cli_option_list_duplicate (error, command->option_list);
91 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
95 command_duplicate->next = NULL;
97 return command_duplicate;
100 _command_free (&command_duplicate);
106 _vsc_cli_command_list_append (struct VscError *error,
107 struct VscCliCommand **command_list,
108 const struct VscCliCommand *command)
110 VSC__ASSERT (error != NULL);
111 VSC__ASSERT (! error->occured);
112 VSC__ASSERT (command_list != NULL);
113 VSC__ASSERT (command != NULL);
116 (error, (struct VscList **) command_list,
117 (struct VscList *) command,
118 (VscList_DuplicateFunction) _command_duplicate);
120 if (error->occured) {
121 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
127 vsc_cli_command_list_free (struct VscCliCommand **command_list)
129 VSC__ASSERT (command_list != NULL);
131 vsc_list_free ((struct VscList **) command_list,
132 (VscList_FreeFunction) _command_free);
135 int /* command_parsed */
136 vsc_cli_command_parse (struct VscError *error,
137 const char *input, const char **input_tail,
138 struct VscCliCommand *command)
141 int command_parsed = TRUE;
142 char *command_name = NULL;
143 const struct VscCliCommandInfo *command_info;
144 const struct VscCliOptionInfo *option_info;
145 struct VscCliOption option;
147 int untagged_option_index = 0;
149 VSC__ASSERT (error != NULL);
150 VSC__ASSERT (! error->occured);
151 VSC__ASSERT (input != NULL);
152 VSC__ASSERT (input_tail != NULL);
153 VSC__ASSERT (command != NULL);
157 memset (command, 0, sizeof (struct VscCliCommand));
160 * Parse command name.
163 _vsc_cli_token_parse (error, *input_tail, &command_name, input_tail);
165 if (error->occured) {
166 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
169 } while (command_name == NULL && *input_tail != NULL);
171 if (command_name == NULL) {
172 if (*input_tail != NULL) {
173 VSC__ERROR2 (error, VSC__ERROR_CODE__INTERNAL_ERROR,
174 "Expecting command in '%s'", input);
180 command_info = _vsc_cli_command_info_lookup (command_name);
182 if (command_info == NULL) {
183 VSC__ERROR2 (error, VSC__ERROR_CODE__INTERNAL_ERROR,
184 "Command '%s' is unknown", command_name);
189 command->info = command_info;
192 * Parse command options.
196 _vsc_cli_option_parse (error, command_info->option_infos,
197 untagged_option_index, command_name,
198 *input_tail, input_tail, &option);
200 if (error->occured) {
201 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
206 if (! (option.info->flags & VSC_CLI__OPTION_FLAG__TAGGED)) {
207 ++untagged_option_index;
210 _vsc_cli_option_list_append (error, &command->option_list,
212 vsc_free (&option.string);
214 if (error->occured) {
215 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
224 * Check required options.
226 for (i = 0; command_info->option_infos[i].long_name != NULL; ++i) {
227 option_info = &command_info->option_infos[i];
229 if (! (option_info->flags & VSC_CLI__OPTION_FLAG__REQUIRED)) {
233 if (_vsc_cli_option_list_lookup (command->option_list,
234 option_info->long_name) == NULL) {
235 VSC__ERROR2 (error, VSC__ERROR_CODE__INTERNAL_ERROR,
236 "Command '%s' requires %s option",
238 _vsc_cli_option_syntax (option_info, FALSE));
245 vsc_free (&command_name);
247 return command_parsed;
250 vsc_cli_option_list_free (&command->option_list);
252 command_parsed = FALSE;