4 * This file is part of BeRTOS.
6 * Bertos is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program 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
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * As a special exception, you may use this file as part of a free software
21 * library without restriction. Specifically, if other files instantiate
22 * templates or use macros or inline functions from this file, or you compile
23 * this file and link it with other files to produce an executable, this
24 * file does not by itself cause the resulting executable to be covered by
25 * the GNU General Public License. This exception does not however
26 * invalidate any other reasons why the executable file might be covered by
27 * the GNU General Public License.
29 * Copyright 2003, 2006 Develer S.r.l. (http://www.develer.com/)
30 * All Rights Reserved.
33 * \brief Channel protocol parser and commands.
35 * This file contains the channel protocol parser and
36 * the definition of the protocol commands. Commands are defined
37 * in a "CmdTemplate" type array, containing:
38 * - the name of the command,
39 * - the arguments it expects to receive,
40 * - the output values,
41 * - the name of the function implementing the command.
43 * The arguments and results are passed to command function
44 * using an union: the element of the union to use for each
45 * argument is determined by format strings present in the
48 * \author Bernie Innocenti <bernie@codewiz.org>
49 * \author Stefano Fedrigo <aleph@develer.com>
50 * \author Giovanni Bajo <rasky@develer.com>
58 #include "cfg/cfg_parser.h"
61 #include <struct/hashtable.h>
63 #include <stdlib.h> // atol(), NULL
64 #include <string.h> // strchr(), strcmp()
66 /// Hashtable hook to extract the key from a command
67 static const void* get_key_from_command(const void* cmd, uint8_t* length);
69 /// Hashtable that handles the commands that can be executed
70 DECLARE_HASHTABLE_STATIC(commands, CONFIG_MAX_COMMANDS_NUMBER, get_key_from_command);
74 * \brief Tokenize one word at a time from a text.
76 * This function is similar to strtok, but does not use any implicit
77 * context, nor it does modify the input buffer in any form.
78 * The word is returned as a STL-like [begin,end) range.
80 * To extract the first word, make both begin and end point at the
81 * start of the text, and call the function. Then, subsequent
82 * calls will return the following words (assuming the begin/end
83 * variable are not modified between calls).
85 * \param begin Will contain the index of the first character of the word
86 * \param end Will contain the index of the character after the last
87 * character of the word
89 * \return True if a word was extracted, false if we got to the end
90 * of the string without extracting any word.
92 bool get_word(const char **begin, const char **end)
94 const char *cur = *end;
95 bool open_quote = false;
97 while ((*cur == ' ' || *cur == '\t') && *cur)
108 while (*cur != '"' && *cur)
115 while ((*cur != ' ' && *cur != '\t') && *cur)
120 return (*end != *begin);
125 * \brief Command arguments parser.
127 * Using the format pointed by the argument fmt
128 * parses the input string filling the array argv
129 * with input parameters of the correct type.
131 * \param fmt Parameters format string.
132 * \param input Input string.
133 * \param argv Array filled with parameters.
135 * \return False in case of errors, otherwise true.
137 static bool parseArgs(const char *fmt, const char *input, parms argv[])
139 const char *begin = input, *end = input;
143 // Extract the argument
144 if (!get_word(&begin, &end))
150 (*argv++).l = atol(begin);
155 (*argv).s.sz = end - begin;
156 /* Remove the quotes from argument */
157 if (*begin == '"' && *(end - 1) == '"')
166 ASSERT2(0, "Unknown format for argument");
173 /* check if there are remaining args */
174 if (get_word(&begin, &end))
180 /// Hook provided by the parser for matching of command names (TAB completion) for readline
181 const char* parser_rl_match(UNUSED_ARG(void *,dummy), const char *word, int word_len)
184 HashIterator end = ht_iter_end(&commands);
185 const char *found = NULL;
187 for (cur = ht_iter_begin(&commands);
188 !ht_iter_cmp(cur, end);
189 cur = ht_iter_next(cur))
191 const struct CmdTemplate* cmdp = (const struct CmdTemplate*)ht_iter_get(cur);
192 if (strncmp(cmdp->name, word, word_len) == 0)
194 // If there was another matching word, it means that we have a multiple
195 // match: then return NULL.
206 #if CONFIG_ENABLE_COMPAT_BEHAVIOUR
207 bool parser_get_cmd_id(const char* line, unsigned long* ID)
209 const char *begin = line, *end = line;
212 // The first word is the ID
213 if (!get_word(&begin, &end))
216 *ID = strtoul(begin, &end2, 10);
225 * Find the template for the command contained in the text line.
226 * The template can be used to tokenize the command and interpret
229 * This function can be used to find out which command is contained
230 * in a given text line without parsing all the parameters and
233 * \param input Text line to be processed (ASCIIZ)
235 * \return The command template associated with the command contained
236 * in the line, or NULL if the command is invalid.
238 const struct CmdTemplate* parser_get_cmd_template(const char *input)
240 const char *begin = input, *end = input;
242 #if CONFIG_ENABLE_COMPAT_BEHAVIOUR
243 // Skip the ID, and get the command
244 if (!get_word(&begin, &end))
247 if (!get_word(&begin, &end))
250 return (const struct CmdTemplate*)ht_find(&commands, begin, end-begin);
253 static const char *skip_to_params(const char *input, const struct CmdTemplate *cmdp)
255 const char *begin = input, *end = input;
257 #if CONFIG_ENABLE_COMPAT_BEHAVIOUR
258 // Skip the ID, and get the command
259 if (!get_word(&begin, &end))
262 if (!get_word(&begin, &end))
265 ASSERT2(strlen(cmdp->name) == (size_t)(end-begin), "Invalid command template specified");
266 ASSERT2(!strncmp(begin, cmdp->name, end-begin), "Invalid command template specified");
272 * Extract the arguments for the command contained in the text line.
274 * The first argument will always be the command name, so the actual arguments
275 * will start at index 1.
277 * \param input Text line to be processed (ASCIIZ)
278 * \param cmdp Command template for this line
279 * \param args Will contain the extracted parameters
281 * \return True if everything OK, false in case of parsing error.
283 bool parser_get_cmd_arguments(const char* input, const struct CmdTemplate* cmdp, parms args[CONFIG_PARSER_MAX_ARGS])
285 input = skip_to_params(input, cmdp);
289 args[0].s.p = cmdp->name;
290 if (!parseArgs(cmdp->arg_fmt, input, args + 1))
296 static const void* get_key_from_command(const void* cmd, uint8_t* length)
298 const struct CmdTemplate* c = cmd;
299 *length = strlen(c->name);
304 * \brief Command input handler.
306 * Process the input, calling the requested command (if found).
308 * \param input Text line to be processed (ASCIIZ)
310 * \return true if everything is OK, false in case of errors
312 bool parser_process_line(const char* input)
314 const struct CmdTemplate *cmdp;
315 parms args[CONFIG_PARSER_MAX_ARGS];
317 cmdp = parser_get_cmd_template(input);
321 if (!parser_get_cmd_arguments(input, cmdp, args))
324 if (!parser_execute_cmd(cmdp, args))
331 * Register a new command into the parser
333 * \param cmd Command template describing the command
334 * \return true if registration was successful, false otherwise
336 bool parser_register_cmd(const struct CmdTemplate* cmd)
338 return ht_insert(&commands, cmd);
341 void parser_init(void)
343 // Initialize the hashtable used to store the command description