BeRTOS
parser.c
Go to the documentation of this file.
00001 
00056 #include "parser.h"
00057 
00058 #include "cfg/cfg_parser.h"
00059 
00060 #include <io/kfile.h>
00061 #include <struct/hashtable.h>
00062 
00063 #include <stdlib.h> // atol(), NULL
00064 #include <string.h> // strchr(), strcmp()
00065 
00067 static const void* get_key_from_command(const void* cmd, uint8_t* length);
00068 
00070 DECLARE_HASHTABLE_STATIC(commands, CONFIG_MAX_COMMANDS_NUMBER, get_key_from_command);
00071 
00072 
00092 static bool get_word(const char **begin, const char **end)
00093 {
00094     const char *cur = *end;
00095 
00096     while ((*cur == ' ' || *cur == '\t') && *cur)
00097         ++cur;
00098 
00099     *begin = cur;
00100 
00101     while ((*cur != ' ' && *cur != '\t') && *cur)
00102         ++cur;
00103 
00104     *end = cur;
00105 
00106     return (*end != *begin);
00107 }
00108 
00109 
00123 static bool parseArgs(const char *fmt, const char *input, parms argv[])
00124 {
00125     const char *begin = input, *end = input;
00126 
00127     while (*fmt)
00128     {
00129         // Extract the argument
00130         if (!get_word(&begin, &end))
00131             return false;
00132 
00133         switch (*fmt)
00134         {
00135             case 'd':
00136                 (*argv++).l = atol(begin);
00137                 break;
00138 
00139             case 's':
00140                 (*argv++).s = begin;
00141                 break;
00142 
00143             default:
00144                 ASSERT2(0, "Unknown format for argument");
00145                 return false;
00146         }
00147 
00148         ++fmt;
00149     }
00150 
00151     /* check if there are remaining args */
00152     if (get_word(&begin, &end))
00153         return false;
00154 
00155     return true;
00156 }
00157 
00159 const char* parser_rl_match(UNUSED_ARG(void *,dummy), const char *word, int word_len)
00160 {
00161     HashIterator cur;
00162     HashIterator end = ht_iter_end(&commands);
00163     const char *found = NULL;
00164 
00165     for (cur = ht_iter_begin(&commands);
00166          !ht_iter_cmp(cur, end);
00167          cur = ht_iter_next(cur))
00168     {
00169         const struct CmdTemplate* cmdp = (const struct CmdTemplate*)ht_iter_get(cur);
00170         if (strncmp(cmdp->name, word, word_len) == 0)
00171         {
00172             // If there was another matching word, it means that we have a multiple
00173             //  match: then return NULL.
00174             if (found)
00175                 return NULL;
00176 
00177             found = cmdp->name;
00178         }
00179     }
00180 
00181     return found;
00182 }
00183 
00184 #if CONFIG_ENABLE_COMPAT_BEHAVIOUR
00185 bool parser_get_cmd_id(const char* line, unsigned long* ID)
00186 {
00187     const char *begin = line, *end = line;
00188     char *end2;
00189 
00190     // The first word is the ID
00191     if (!get_word(&begin, &end))
00192         return false;
00193 
00194     *ID = strtoul(begin, &end2, 10);
00195     if (end2 != end)
00196         return false;
00197 
00198     return true;
00199 }
00200 #endif
00201 
00216 const struct CmdTemplate* parser_get_cmd_template(const char *input)
00217 {
00218     const char *begin = input, *end = input;
00219 
00220 #if CONFIG_ENABLE_COMPAT_BEHAVIOUR
00221     // Skip the ID, and get the command
00222     if (!get_word(&begin, &end))
00223         return NULL;
00224 #endif
00225     if (!get_word(&begin, &end))
00226         return NULL;
00227 
00228     return (const struct CmdTemplate*)ht_find(&commands, begin, end-begin);
00229 }
00230 
00231 static const char *skip_to_params(const char *input, const struct CmdTemplate *cmdp)
00232 {
00233     const char *begin = input, *end = input;
00234 
00235 #if CONFIG_ENABLE_COMPAT_BEHAVIOUR
00236     // Skip the ID, and get the command
00237     if (!get_word(&begin, &end))
00238         return NULL;
00239 #endif
00240     if (!get_word(&begin, &end))
00241         return NULL;
00242 
00243     ASSERT2(strlen(cmdp->name) == (size_t)(end-begin), "Invalid command template specified");
00244     ASSERT2(!strncmp(begin, cmdp->name, end-begin), "Invalid command template specified");
00245 
00246     return end;
00247 }
00248 
00261 bool parser_get_cmd_arguments(const char* input, const struct CmdTemplate* cmdp, parms args[CONFIG_PARSER_MAX_ARGS])
00262 {
00263     input = skip_to_params(input, cmdp);
00264     if (!input)
00265         return false;
00266 
00267     args[0].s = cmdp->name;
00268     if (!parseArgs(cmdp->arg_fmt, input, args + 1))
00269         return false;
00270 
00271     return true;
00272 }
00273 
00274 static const void* get_key_from_command(const void* cmd, uint8_t* length)
00275 {
00276     const struct CmdTemplate* c = cmd;
00277     *length = strlen(c->name);
00278     return c->name;
00279 }
00280 
00290 bool parser_process_line(const char* input)
00291 {
00292     const struct CmdTemplate *cmdp;
00293     parms args[CONFIG_PARSER_MAX_ARGS];
00294 
00295     cmdp = parser_get_cmd_template(input);
00296     if (!cmdp)
00297         return false;
00298 
00299     if (!parser_get_cmd_arguments(input, cmdp, args))
00300         return false;
00301 
00302     if (!parser_execute_cmd(cmdp, args))
00303         return false;
00304 
00305     return true;
00306 }
00307 
00313 void parser_register_cmd(const struct CmdTemplate* cmd)
00314 {
00315     ht_insert(&commands, cmd);
00316 }
00317 
00318 void parser_init(void)
00319 {
00320     // Initialize the hashtable used to store the command description
00321     ht_init(&commands);
00322 }