parser.c

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