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
23 #include <libvscmisc/assert.h>
24 #include <libvscmisc/error.h>
25 #include <libvscmisc/list.h>
26 #include <libvscmisc/memory.h>
27 #include <libvscmisc/string.h>
29 #include "../include/libvsccli/command.h"
30 #include "../include/libvsccli/option.h"
35 extern const struct VscCliCommandInfo **_vsc_cli_command_infos;
37 const struct VscCliCommandInfo *
38 _vsc_cli_command_info_lookup (const char *command_name)
42 VSC__ASSERT (command_name != NULL);
44 for (i = 0; _vsc_cli_command_infos[i] != NULL; i++) {
45 if (strcmp (command_name, _vsc_cli_command_infos[i]->name) == 0) {
46 return _vsc_cli_command_infos[i];
54 _command_free (struct VscCliCommand **command)
56 VSC__ASSERT (command != NULL);
58 if (*command != NULL) {
59 vsc_cli_option_list_free (&(*command)->option_list);
65 static struct VscCliCommand *
66 _command_duplicate (struct VscError *error,
67 const struct VscCliCommand *command)
69 struct VscCliCommand *command_duplicate = NULL;
71 VSC__ASSERT (error != NULL);
72 VSC__ASSERT (! error->occured);
73 VSC__ASSERT (command != NULL);
75 command_duplicate = vsc_memdup (error, command,
76 sizeof (struct VscCliCommand));
79 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
83 command_duplicate->option_list =
84 _vsc_cli_option_list_duplicate (error, command->option_list);
87 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
91 command_duplicate->next = NULL;
93 return command_duplicate;
96 _command_free (&command_duplicate);
102 _vsc_cli_command_list_append (struct VscError *error,
103 struct VscCliCommand **command_list,
104 const struct VscCliCommand *command)
106 VSC__ASSERT (error != NULL);
107 VSC__ASSERT (! error->occured);
108 VSC__ASSERT (command_list != NULL);
109 VSC__ASSERT (command != NULL);
112 (error, (struct VscList **) command_list,
113 (struct VscList *) command,
114 (VscList_DuplicateFunction) _command_duplicate);
116 if (error->occured) {
117 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
123 vsc_cli_command_list_free (struct VscCliCommand **command_list)
125 VSC__ASSERT (command_list != NULL);
127 vsc_list_free ((struct VscList **) command_list,
128 (VscList_FreeFunction) _command_free);
131 int /* command_parsed */
132 vsc_cli_command_parse (struct VscError *error,
133 const char *input, const char **input_tail,
134 struct VscCliCommand *command)
137 int command_parsed = TRUE;
138 char *command_name = NULL;
139 const struct VscCliCommandInfo *command_info;
140 const struct VscCliOptionInfo *option_info;
141 struct VscCliOption option;
143 int untagged_option_index = 0;
145 VSC__ASSERT (error != NULL);
146 VSC__ASSERT (! error->occured);
147 VSC__ASSERT (input != NULL);
148 VSC__ASSERT (input_tail != NULL);
149 VSC__ASSERT (command != NULL);
153 memset (command, 0, sizeof (struct VscCliCommand));
156 * Parse command name.
159 _vsc_cli_token_parse (error, *input_tail, &command_name, input_tail);
161 if (error->occured) {
162 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
165 } while (command_name == NULL && *input_tail != NULL);
167 if (command_name == NULL) {
168 if (*input_tail != NULL) {
169 VSC__ERROR2 (error, VSC__ERROR_CODE__INTERNAL_ERROR,
170 "Expecting command in '%s'", input);
176 command_info = _vsc_cli_command_info_lookup (command_name);
178 if (command_info == NULL) {
179 VSC__ERROR2 (error, VSC__ERROR_CODE__INTERNAL_ERROR,
180 "Command '%s' is unknown", command_name);
185 command->info = command_info;
188 * Parse command options.
192 _vsc_cli_option_parse (error, command_info->option_infos,
193 untagged_option_index, command_name,
194 *input_tail, input_tail, &option);
196 if (error->occured) {
197 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
202 if (! (option.info->flags & VSC_CLI__OPTION_FLAG__TAGGED)) {
203 ++untagged_option_index;
206 _vsc_cli_option_list_append (error, &command->option_list,
208 vsc_free (&option.string);
210 if (error->occured) {
211 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
220 * Check required options.
222 for (i = 0; command_info->option_infos[i].long_name != NULL; ++i) {
223 option_info = &command_info->option_infos[i];
225 if (! (option_info->flags & VSC_CLI__OPTION_FLAG__REQUIRED)) {
229 if (_vsc_cli_option_list_lookup (command->option_list,
230 option_info->long_name) == NULL) {
231 VSC__ERROR2 (error, VSC__ERROR_CODE__INTERNAL_ERROR,
232 "Command '%s' requires %s option",
234 _vsc_cli_option_syntax (option_info, FALSE));
241 vsc_free (&command_name);
243 return command_parsed;
246 vsc_cli_option_list_free (&command->option_list);
248 command_parsed = FALSE;