parser.c

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