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 bool get_word(const char **begin, const char **end)
00093 {
00094     const char *cur = *end;
00095     bool open_quote = false;
00096
00097     while ((*cur == ' ' || *cur == '\t') && *cur)
00098         ++cur;
00099
00100     if (*cur == '"')
00101         open_quote = true;
00102
00103     *begin = cur;
00104
00105     if (open_quote)
00106     {
00107         ++cur;
00108         while (*cur != '"' && *cur)
00109             ++cur;
00110         if (*cur != '"')
00111             return false;
00112         ++cur;
00113     }
00114     else
00115         while ((*cur != ' ' && *cur != '\t') && *cur)
00116             ++cur;
00117
00118     *end = cur;
00119
00120     return (*end != *begin);
00121 }
00122
00123
00137 static bool parseArgs(const char *fmt, const char *input, parms argv[])
00138 {
00139     const char *begin = input, *end = input;
00140
00141     while (*fmt)
00142     {
00143         // Extract the argument
00144         if (!get_word(&begin, &end))
00145             return false;
00146
00147         switch (*fmt)
00148         {
00149             case 'd':
00150                 (*argv++).l = atol(begin);
00151                 break;
00152
00153             case 's':
00154                 (*argv).s.p = begin;
00155                 (*argv).s.sz = end - begin;
00156                 /* Remove the quotes from argument */
00157                 if (*begin == '"' && *(end - 1) == '"')
00158                 {
00159                     (*argv).s.p += 1;
00160                     (*argv).s.sz -= 2;
00161                 }
00162                 argv++;
00163                 break;
00164
00165             default:
00166                 ASSERT2(0, "Unknown format for argument");
00167                 return false;
00168         }
00169
00170         ++fmt;
00171     }
00172
00173     /* check if there are remaining args */
00174     if (get_word(&begin, &end))
00175         return false;
00176
00177     return true;
00178 }
00179
00181 const char* parser_rl_match(UNUSED_ARG(void *,dummy), const char *word, int word_len)
00182 {
00183     HashIterator cur;
00184     HashIterator end = ht_iter_end(&commands);
00185     const char *found = NULL;
00186
00187     for (cur = ht_iter_begin(&commands);
00188          !ht_iter_cmp(cur, end);
00189          cur = ht_iter_next(cur))
00190     {
00191         const struct CmdTemplate* cmdp = (const struct CmdTemplate*)ht_iter_get(cur);
00192         if (strncmp(cmdp->name, word, word_len) == 0)
00193         {
00194             // If there was another matching word, it means that we have a multiple
00195             //  match: then return NULL.
00196             if (found)
00197                 return NULL;
00198
00199             found = cmdp->name;
00200         }
00201     }
00202
00203     return found;
00204 }
00205
00206 #if CONFIG_ENABLE_COMPAT_BEHAVIOUR
00207 bool parser_get_cmd_id(const char* line, unsigned long* ID)
00208 {
00209     const char *begin = line, *end = line;
00210     char *end2;
00211
00212     // The first word is the ID
00213     if (!get_word(&begin, &end))
00214         return false;
00215
00216     *ID = strtoul(begin, &end2, 10);
00217     if (end2 != end)
00218         return false;
00219
00220     return true;
00221 }
00222 #endif
00223 
00238 const struct CmdTemplate* parser_get_cmd_template(const char *input)
00239 {
00240     const char *begin = input, *end = input;
00241
00242 #if CONFIG_ENABLE_COMPAT_BEHAVIOUR
00243     // Skip the ID, and get the command
00244     if (!get_word(&begin, &end))
00245         return NULL;
00246 #endif
00247 
00248     if (!get_word(&begin, &end))
00249         return NULL;
00250
00251     return (const struct CmdTemplate*)ht_find(&commands, begin, end-begin);
00252 }
00253
00254 static const char *skip_to_params(const char *input, const struct CmdTemplate *cmdp)
00255 {
00256     const char *begin = input, *end = input;
00257
00258 #if CONFIG_ENABLE_COMPAT_BEHAVIOUR
00259     // Skip the ID, and get the command
00260     if (!get_word(&begin, &end))
00261         return NULL;
00262 #endif
00263 
00264     if (!get_word(&begin, &end))
00265         return NULL;
00266
00267     ASSERT2(strlen(cmdp->name) == (size_t)(end-begin), "Invalid command template specified");
00268     ASSERT2(!strncmp(begin, cmdp->name, end-begin), "Invalid command template specified");
00269
00270     return end;
00271 }
00272
00285 bool parser_get_cmd_arguments(const char* input, const struct CmdTemplate* cmdp, parms args[CONFIG_PARSER_MAX_ARGS])
00286 {
00287     input = skip_to_params(input, cmdp);
00288     if (!input)
00289         return false;
00290
00291     args[0].s.p = cmdp->name;
00292     if (!parseArgs(cmdp->arg_fmt, input, args + 1))
00293         return false;
00294
00295     return true;
00296 }
00297
00298 static const void* get_key_from_command(const void* cmd, uint8_t* length)
00299 {
00300     const struct CmdTemplate* c = cmd;
00301     *length = strlen(c->name);
00302     return c->name;
00303 }
00304
00314 bool parser_process_line(const char* input)
00315 {
00316     const struct CmdTemplate *cmdp;
00317     parms args[CONFIG_PARSER_MAX_ARGS];
00318
00319     cmdp = parser_get_cmd_template(input);
00320     if (!cmdp)
00321         return false;
00322
00323     if (!parser_get_cmd_arguments(input, cmdp, args))
00324         return false;
00325
00326     if (!parser_execute_cmd(cmdp, args))
00327         return false;
00328
00329     return true;
00330 }
00331
00338 bool parser_register_cmd(const struct CmdTemplate* cmd)
00339 {
00340     return ht_insert(&commands, cmd);
00341 }
00342
00343 void parser_init(void)
00344 {
00345     // Initialize the hashtable used to store the command description
00346     ht_init(&commands);
00347 }