* All Rights Reserved.
* -->
*
- * \brief Serial protocol parser and commands.
+ * \brief Channel protocol parser and commands.
*
- * This file contains the serial protocol parser and
+ * This file contains the channel protocol parser and
* the definition of the protocol commands. Commands are defined
* in a "CmdTemplate" type array, containing:
* - the name of the command,
* argument is determined by format strings present in the
* CmdTemplate table.
*
- * \version $Id$
- *
- * \author Bernardo Innocenti <bernie@develer.com>
+ * \author Bernie Innocenti <bernie@codewiz.org>
* \author Stefano Fedrigo <aleph@develer.com>
* \author Giovanni Bajo <rasky@develer.com>
*
#include "parser.h"
-#include <cfg/cfg_parser.h>
+#include "cfg/cfg_parser.h"
-#include <drv/ser.h>
-#include <mware/hashtable.h>
+#include <io/kfile.h>
+#include <struct/hashtable.h>
#include <stdlib.h> // atol(), NULL
#include <string.h> // strchr(), strcmp()
-
-
-#define ARG_SEP_S " "
-#define ARG_SEP_C ' '
-
-#define MAX_COMMANDS_NUMBER 128 // 64
-
/// Hashtable hook to extract the key from a command
static const void* get_key_from_command(const void* cmd, uint8_t* length);
/// Hashtable that handles the commands that can be executed
-DECLARE_HASHTABLE_STATIC(commands, MAX_COMMANDS_NUMBER, get_key_from_command);
+DECLARE_HASHTABLE_STATIC(commands, CONFIG_MAX_COMMANDS_NUMBER, get_key_from_command);
/**
* \return True if a word was extracted, false if we got to the end
* of the string without extracting any word.
*/
-static bool get_word(const char **begin, const char **end)
+bool get_word(const char **begin, const char **end)
{
const char *cur = *end;
+ bool open_quote = false;
while ((*cur == ' ' || *cur == '\t') && *cur)
++cur;
+ if (*cur == '"')
+ open_quote = true;
+
*begin = cur;
- while ((*cur != ' ' && *cur != '\t') && *cur)
+ if (open_quote)
+ {
+ ++cur;
+ while (*cur != '"' && *cur)
+ ++cur;
+ if (*cur != '"')
+ return false;
++cur;
+ }
+ else
+ while ((*cur != ' ' && *cur != '\t') && *cur)
+ ++cur;
*end = cur;
break;
case 's':
- (*argv++).s = begin;
+ (*argv).s.p = begin;
+ (*argv).s.sz = end - begin;
+ /* Remove the quotes from argument */
+ if (*begin == '"' && *(end - 1) == '"')
+ {
+ (*argv).s.p += 1;
+ (*argv).s.sz -= 2;
+ }
+ argv++;
break;
default:
return true;
}
-
-#ifdef UNUSED_CODE
-/**
- * \brief Command result formatting and printing.
- *
- * Prints out on device fd the values contained
- * in the array result, using the format specified
- * in fmt.
- *
- * \param ser Serial handle.
- * \param fmt Values format string.
- * \param result Array containing result to be printed.
- *
- * \return -1 in case of errors, otherwise 0.
- */
-static int printResult(struct Serial *ser, const char *fmt, parms result[])
-{
- long n;
- char repeat_cnt = 0;
-
- while (*fmt)
- {
- if (*fmt >= '0' && *fmt <= '9')
- {
- /* Collect repeat count digit (left to right order) */
- repeat_cnt = (repeat_cnt * 10) + (*fmt - '0');
- }
- else
- {
- /* Set default repeat cnt of 1 when not specified */
- if (repeat_cnt == 0)
- repeat_cnt = 1;
-
- /* Loop repeat_cnt times */
- do
- {
- switch (*fmt)
- {
- case 'd':
- ser_printf(ser, ARG_SEP_S "%ld", (*result).l);
- result++;
- break;
- case 'c':
- ser_print(ser, ARG_SEP_S);
- ser_print(ser, (*result).s);
- result++;
- break;
- case 's':
- ser_printf(ser, ARG_SEP_S "%s", (*result).s);
- result++;
- break;
- case 'n':
- n = (*result++).l;
- ser_printf(ser, ARG_SEP_S "%ld", n);
- while (n--) {
- ser_printf(ser, ARG_SEP_S "%ld", (*result).l);
- result++;
- }
- break;
- default:
- break;
- }
- }
- while (--repeat_cnt);
- }
-
- /* Skip to next format char */
- ++fmt;
-
- } /* while (*fmt) */
-
-
- ser_print(ser, "\r\n");
- return 0;
-}
-#endif /* UNUSED_CODE */
-
/// Hook provided by the parser for matching of command names (TAB completion) for readline
const char* parser_rl_match(UNUSED_ARG(void *,dummy), const char *word, int word_len)
{
return found;
}
+#if CONFIG_ENABLE_COMPAT_BEHAVIOUR
bool parser_get_cmd_id(const char* line, unsigned long* ID)
{
const char *begin = line, *end = line;
return true;
}
+#endif
+/**
+ * Find the template for the command contained in the text line.
+ * The template can be used to tokenize the command and interpret
+ * it.
+ *
+ * This function can be used to find out which command is contained
+ * in a given text line without parsing all the parameters and
+ * executing it.
+ *
+ * \param input Text line to be processed (ASCIIZ)
+ *
+ * \return The command template associated with the command contained
+ * in the line, or NULL if the command is invalid.
+ */
const struct CmdTemplate* parser_get_cmd_template(const char *input)
{
-// const struct CmdTemplate *cmdp;
-// int cmdlen;
const char *begin = input, *end = input;
+#if CONFIG_ENABLE_COMPAT_BEHAVIOUR
// Skip the ID, and get the command
if (!get_word(&begin, &end))
return NULL;
+#endif
if (!get_word(&begin, &end))
return NULL;
{
const char *begin = input, *end = input;
+#if CONFIG_ENABLE_COMPAT_BEHAVIOUR
// Skip the ID, and get the command
if (!get_word(&begin, &end))
return NULL;
+#endif
if (!get_word(&begin, &end))
return NULL;
return end;
}
-bool parser_get_cmd_arguments(const char* input, const struct CmdTemplate* cmdp, parms args[PARSER_MAX_ARGS])
+/**
+ * Extract the arguments for the command contained in the text line.
+ *
+ * The first argument will always be the command name, so the actual arguments
+ * will start at index 1.
+ *
+ * \param input Text line to be processed (ASCIIZ)
+ * \param cmdp Command template for this line
+ * \param args Will contain the extracted parameters
+ *
+ * \return True if everything OK, false in case of parsing error.
+ */
+bool parser_get_cmd_arguments(const char* input, const struct CmdTemplate* cmdp, parms args[CONFIG_PARSER_MAX_ARGS])
{
input = skip_to_params(input, cmdp);
if (!input)
return false;
- args[0].s = cmdp->name;
+ args[0].s.p = cmdp->name;
if (!parseArgs(cmdp->arg_fmt, input, args + 1))
return false;
return c->name;
}
+/**
+ * \brief Command input handler.
+ *
+ * Process the input, calling the requested command (if found).
+ *
+ * \param input Text line to be processed (ASCIIZ)
+ *
+ * \return true if everything is OK, false in case of errors
+ */
bool parser_process_line(const char* input)
{
const struct CmdTemplate *cmdp;
- parms args[PARSER_MAX_ARGS];
+ parms args[CONFIG_PARSER_MAX_ARGS];
cmdp = parser_get_cmd_template(input);
if (!cmdp)
return true;
}
-void parser_register_cmd(const struct CmdTemplate* cmd)
+/**
+ * Register a new command into the parser
+ *
+ * \param cmd Command template describing the command
+ * \return true if registration was successful, false otherwise
+ */
+bool parser_register_cmd(const struct CmdTemplate* cmd)
{
- ht_insert(&commands, cmd);
+ return ht_insert(&commands, cmd);
}
-#if CONFIG_INTERNAL_COMMANDS
-#warning FIXME:This code use boost lib, if you compile with internal command you must fix it.
-static ResultCode cmd_help(void)
-{
-#ifdef _DEBUG
-
- // FIXME: There is no way at the moment to access the serial port. Dump
- // this through JTAG for now
- for (HashIterator iter = ht_iter_begin(&commands);
- !ht_iter_cmp(iter, ht_iter_end(&commands));
- iter = ht_iter_next(iter))
- {
- struct CmdTemplate* cmd = (struct CmdTemplate*)ht_iter_get(iter);
- kprintf("%-20s", cmd->name);
- for (unsigned j = 0; cmd->arg_fmt[j]; ++j)
- kprintf("%c ", 'a' + j);
- kprintf("\r\n");
- }
-#endif
-
- return RC_OK;
-}
-
-#include "cmd_hunk.h"
-DECLARE_CMD_HUNK(help, (NIL), (NIL));
-
-#endif // CONFIG_INTERNAL_COMMANDS
-
-
void parser_init(void)
{
// Initialize the hashtable used to store the command description
ht_init(&commands);
-
-#if CONFIG_INTERNAL_COMMANDS
- parser_register_cmd(&CMD_HUNK_TEMPLATE(help));
-#endif
}