parser.c

Go to the documentation of this file.
00001 
00058 #include "parser.h"
00059 
00060 #include "cfg/cfg_parser.h"
00061 
00062 #include <drv/ser.h>
00063 #include <struct/hashtable.h>
00064 
00065 #include <stdlib.h> // atol(), NULL
00066 #include <string.h> // strchr(), strcmp()
00067 
00068 
00069 
00070 #define ARG_SEP_S " "
00071 #define ARG_SEP_C ' '
00072 
00073 #define MAX_COMMANDS_NUMBER  128  // 64
00074 
00076 static const void* get_key_from_command(const void* cmd, uint8_t* length);
00077 
00079 DECLARE_HASHTABLE_STATIC(commands, MAX_COMMANDS_NUMBER, get_key_from_command);
00080 
00081 
00101 static bool get_word(const char **begin, const char **end)
00102 {
00103     const char *cur = *end;
00104 
00105     while ((*cur == ' ' || *cur == '\t') && *cur)
00106         ++cur;
00107 
00108     *begin = cur;
00109 
00110     while ((*cur != ' ' && *cur != '\t') && *cur)
00111         ++cur;
00112 
00113     *end = cur;
00114 
00115     return (*end != *begin);
00116 }
00117 
00118 
00132 static bool parseArgs(const char *fmt, const char *input, parms argv[])
00133 {
00134     const char *begin = input, *end = input;
00135 
00136     while (*fmt)
00137     {
00138         // Extract the argument
00139         if (!get_word(&begin, &end))
00140             return false;
00141 
00142         switch (*fmt)
00143         {
00144             case 'd':
00145                 (*argv++).l = atol(begin);
00146                 break;
00147 
00148             case 's':
00149                 (*argv++).s = begin;
00150                 break;
00151 
00152             default:
00153                 ASSERT2(0, "Unknown format for argument");
00154                 return false;
00155         }
00156 
00157         ++fmt;
00158     }
00159 
00160     /* check if there are remaining args */
00161     if (get_word(&begin, &end))
00162         return false;
00163 
00164     return true;
00165 }
00166 
00167 
00168 #ifdef UNUSED_CODE
00169 
00182 static int printResult(struct Serial *ser, const char *fmt, parms result[])
00183 {
00184     long n;
00185     char repeat_cnt = 0;
00186 
00187     while (*fmt)
00188     {
00189         if (*fmt >= '0' && *fmt <= '9')
00190         {
00191             /* Collect repeat count digit (left to right order) */
00192             repeat_cnt = (repeat_cnt * 10) + (*fmt - '0');
00193         }
00194         else
00195         {
00196             /* Set default repeat cnt of 1 when not specified */
00197             if (repeat_cnt == 0)
00198                 repeat_cnt = 1;
00199 
00200             /* Loop repeat_cnt times */
00201             do
00202             {
00203                 switch (*fmt)
00204                 {
00205                     case 'd':
00206                         ser_printf(ser, ARG_SEP_S "%ld", (*result).l);
00207                         result++;
00208                         break;
00209                     case 'c':
00210                         ser_print(ser, ARG_SEP_S);
00211                         ser_print(ser, (*result).s);
00212                         result++;
00213                         break;
00214                     case 's':
00215                         ser_printf(ser, ARG_SEP_S "%s", (*result).s);
00216                         result++;
00217                         break;
00218                     case 'n':
00219                         n = (*result++).l;
00220                         ser_printf(ser, ARG_SEP_S "%ld", n);
00221                         while (n--) {
00222                             ser_printf(ser, ARG_SEP_S "%ld", (*result).l);
00223                             result++;
00224                         }
00225                         break;
00226                     default:
00227                         break;
00228                 }
00229             }
00230             while (--repeat_cnt);
00231         }
00232 
00233         /* Skip to next format char */
00234         ++fmt;
00235 
00236     } /* while (*fmt) */
00237 
00238 
00239     ser_print(ser, "\r\n");
00240     return 0;
00241 }
00242 #endif /* UNUSED_CODE */
00243 
00245 const char* parser_rl_match(UNUSED_ARG(void *,dummy), const char *word, int word_len)
00246 {
00247     HashIterator cur;
00248     HashIterator end = ht_iter_end(&commands);
00249     const char *found = NULL;
00250 
00251     for (cur = ht_iter_begin(&commands);
00252          !ht_iter_cmp(cur, end);
00253          cur = ht_iter_next(cur))
00254     {
00255         const struct CmdTemplate* cmdp = (const struct CmdTemplate*)ht_iter_get(cur);
00256         if (strncmp(cmdp->name, word, word_len) == 0)
00257         {
00258             // If there was another matching word, it means that we have a multiple
00259             //  match: then return NULL.
00260             if (found)
00261                 return NULL;
00262 
00263             found = cmdp->name;
00264         }
00265     }
00266 
00267     return found;
00268 }
00269 
00270 bool parser_get_cmd_id(const char* line, unsigned long* ID)
00271 {
00272     const char *begin = line, *end = line;
00273     char *end2;
00274 
00275     // The first word is the ID
00276     if (!get_word(&begin, &end))
00277         return false;
00278 
00279     *ID = strtoul(begin, &end2, 10);
00280     if (end2 != end)
00281         return false;
00282 
00283     return true;
00284 }
00285 
00286 const struct CmdTemplate* parser_get_cmd_template(const char *input)
00287 {
00288 //  const struct CmdTemplate *cmdp;
00289 //  int cmdlen;
00290     const char *begin = input, *end = input;
00291 
00292     // Skip the ID, and get the command
00293     if (!get_word(&begin, &end))
00294         return NULL;
00295     if (!get_word(&begin, &end))
00296         return NULL;
00297 
00298     return (const struct CmdTemplate*)ht_find(&commands, begin, end-begin);
00299 }
00300 
00301 static const char *skip_to_params(const char *input, const struct CmdTemplate *cmdp)
00302 {
00303     const char *begin = input, *end = input;
00304 
00305     // Skip the ID, and get the command
00306     if (!get_word(&begin, &end))
00307         return NULL;
00308     if (!get_word(&begin, &end))
00309         return NULL;
00310 
00311     ASSERT2(strlen(cmdp->name) == (size_t)(end-begin), "Invalid command template specified");
00312     ASSERT2(!strncmp(begin, cmdp->name, end-begin), "Invalid command template specified");
00313 
00314     return end;
00315 }
00316 
00317 bool parser_get_cmd_arguments(const char* input, const struct CmdTemplate* cmdp, parms args[PARSER_MAX_ARGS])
00318 {
00319     input = skip_to_params(input, cmdp);
00320     if (!input)
00321         return false;
00322 
00323     args[0].s = cmdp->name;
00324     if (!parseArgs(cmdp->arg_fmt, input, args + 1))
00325         return false;
00326 
00327     return true;
00328 }
00329 
00330 static const void* get_key_from_command(const void* cmd, uint8_t* length)
00331 {
00332     const struct CmdTemplate* c = cmd;
00333     *length = strlen(c->name);
00334     return c->name;
00335 }
00336 
00337 bool parser_process_line(const char* input)
00338 {
00339     const struct CmdTemplate *cmdp;
00340     parms args[PARSER_MAX_ARGS];
00341 
00342     cmdp = parser_get_cmd_template(input);
00343     if (!cmdp)
00344         return false;
00345 
00346     if (!parser_get_cmd_arguments(input, cmdp, args))
00347         return false;
00348 
00349     if (!parser_execute_cmd(cmdp, args))
00350         return false;
00351 
00352     return true;
00353 }
00354 
00355 void parser_register_cmd(const struct CmdTemplate* cmd)
00356 {
00357     ht_insert(&commands, cmd);
00358 }
00359 
00360 #if CONFIG_INTERNAL_COMMANDS
00361 #warning FIXME:This code use boost lib, if you compile with internal command you must fix it.
00362 static ResultCode cmd_help(void)
00363 {
00364 #ifdef _DEBUG
00365 
00366     // FIXME: There is no way at the moment to access the serial port. Dump
00367     //  this through JTAG for now
00368     for (HashIterator iter = ht_iter_begin(&commands);
00369         !ht_iter_cmp(iter, ht_iter_end(&commands));
00370         iter = ht_iter_next(iter))
00371     {
00372         struct CmdTemplate* cmd = (struct CmdTemplate*)ht_iter_get(iter);
00373         kprintf("%-20s", cmd->name);
00374         for (unsigned j = 0; cmd->arg_fmt[j]; ++j)
00375             kprintf("%c ", 'a' + j);
00376         kprintf("\r\n");
00377     }
00378 #endif
00379 
00380     return RC_OK;
00381 }
00382 
00383 #include "cmd_hunk.h"
00384 DECLARE_CMD_HUNK(help, (NIL), (NIL));
00385 
00386 #endif // CONFIG_INTERNAL_COMMANDS
00387 
00388 
00389 void parser_init(void)
00390 {
00391     // Initialize the hashtable used to store the command description
00392     ht_init(&commands);
00393 
00394 #if CONFIG_INTERNAL_COMMANDS
00395     parser_register_cmd(&CMD_HUNK_TEMPLATE(help));
00396 #endif
00397 }