00001
00056 #include "parser.h"
00057 #include <drv/ser.h>
00058
00059 #include <stdlib.h>
00060 #include <string.h>
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
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
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
00188 repeat_cnt = (repeat_cnt * 10) + (*fmt - '0');
00189 }
00190 else
00191 {
00192
00193 if (repeat_cnt == 0)
00194 repeat_cnt = 1;
00195
00196
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
00230 ++fmt;
00231
00232 }
00233
00234
00235 ser_print(ser, "\r\n");
00236 return 0;
00237 }
00238 #endif
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
00255
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
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
00285
00286 const char *begin = input, *end = input;
00287
00288
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
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
00362
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
00387 ht_init(&commands);
00388
00389 #if CONFIG_INTERNAL_COMMANDS
00390 parser_register_cmd(&CMD_HUNK_TEMPLATE(help));
00391 #endif
00392 }