afd866729f19d60f96815ec0e0cd04b9d47f03bc
[openocd.git] / src / helper / command.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * part of this file is taken from libcli (libcli.sourceforge.net) *
6 * Copyright (C) David Parrish (david@dparrish.com) *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22 ***************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "replacements.h"
28
29 #include "command.h"
30
31 #include "log.h"
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <ctype.h>
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <unistd.h>
39
40 int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
41
42 int build_unique_lengths(command_context_t *context, command_t *commands)
43 {
44 command_t *c, *p;
45
46 /* iterate through all commands */
47 for (c = commands; c; c = c->next)
48 {
49 /* find out how many characters are required to uniquely identify a command */
50 for (c->unique_len = 1; c->unique_len <= strlen(c->name); c->unique_len++)
51 {
52 int foundmatch = 0;
53
54 /* for every command, see if the current length is enough */
55 for (p = commands; p; p = p->next)
56 {
57 /* ignore the command itself */
58 if (c == p)
59 continue;
60
61 /* compare commands up to the current length */
62 if (strncmp(p->name, c->name, c->unique_len) == 0)
63 foundmatch++;
64 }
65
66 /* when none of the commands matched, we've found the minimum length required */
67 if (!foundmatch)
68 break;
69 }
70
71 /* if the current command has children, build the unique lengths for them */
72 if (c->children)
73 build_unique_lengths(context, c->children);
74 }
75
76 return ERROR_OK;
77 }
78
79 /* Avoid evaluating this each time we add a command. Reduces overhead from O(n^2) to O(n).
80 * Makes a difference on ARM7 types machines and is not observable on GHz machines.
81 */
82 static int unique_length_dirty = 1;
83
84 command_t* register_command(command_context_t *context, command_t *parent, char *name, int (*handler)(struct command_context_s *context, char* name, char** args, int argc), enum command_mode mode, char *help)
85 {
86 command_t *c, *p;
87 unique_length_dirty = 1;
88
89 if (!context || !name)
90 return NULL;
91
92 c = malloc(sizeof(command_t));
93
94 c->name = strdup(name);
95 c->parent = parent;
96 c->children = NULL;
97 c->handler = handler;
98 c->mode = mode;
99 if (help)
100 c->help = strdup(help);
101 else
102 c->help = NULL;
103 c->unique_len = 0;
104 c->next = NULL;
105
106 /* place command in tree */
107 if (parent)
108 {
109 if (parent->children)
110 {
111 /* find last child */
112 for (p = parent->children; p && p->next; p = p->next);
113 if (p)
114 p->next = c;
115 }
116 else
117 {
118 parent->children = c;
119 }
120 }
121 else
122 {
123 if (context->commands)
124 {
125 /* find last command */
126 for (p = context->commands; p && p->next; p = p->next);
127 if (p)
128 p->next = c;
129 }
130 else
131 {
132 context->commands = c;
133 }
134 }
135
136 return c;
137 }
138
139 int unregister_command(command_context_t *context, char *name)
140 {
141 unique_length_dirty = 1;
142
143 command_t *c, *p = NULL, *c2;
144
145 if ((!context) || (!name))
146 return ERROR_INVALID_ARGUMENTS;
147
148 /* find command */
149 for (c = context->commands; c; c = c->next)
150 {
151 if (strcmp(name, c->name) == 0)
152 {
153 /* unlink command */
154 if (p)
155 {
156 p->next = c->next;
157 }
158 else
159 {
160 context->commands = c->next;
161 }
162
163 /* unregister children */
164 if (c->children)
165 {
166 for (c2 = c->children; c2; c2 = c2->next)
167 {
168 free(c2->name);
169 if (c2->help)
170 free(c2->help);
171 free(c2);
172 }
173 }
174
175 /* delete command */
176 free(c->name);
177 if (c->help)
178 free(c->help);
179 free(c);
180 }
181
182 /* remember the last command for unlinking */
183 p = c;
184 }
185
186 return ERROR_OK;
187 }
188
189 int parse_line(char *line, char *words[], int max_words)
190 {
191 int nwords = 0;
192 char *p = line;
193 char *word_start = line;
194 int inquote = 0;
195
196 while (nwords < max_words - 1)
197 {
198 /* check if we reached
199 * a terminating NUL
200 * a matching closing quote character " or '
201 * we're inside a word but not a quote, and the current character is whitespace
202 */
203 if (!*p || *p == inquote || (word_start && !inquote && isspace(*p)))
204 {
205 /* we're inside a word or quote, and reached its end*/
206 if (word_start)
207 {
208 int len;
209 char *word_end=p;
210
211 /* This will handle extra whitespace within quotes */
212 while (isspace(*word_start)&&(word_start<word_end))
213 word_start++;
214 while (isspace(*(word_end-1))&&(word_start<word_end))
215 word_end--;
216 len = word_end - word_start;
217
218 if (len>0)
219 {
220 /* copy the word */
221 memcpy(words[nwords] = malloc(len + 1), word_start, len);
222 /* add terminating NUL */
223 words[nwords++][len] = 0;
224 }
225 }
226 /* we're done parsing the line */
227 if (!*p)
228 break;
229
230 /* skip over trailing quote or whitespace*/
231 if (inquote || isspace(*p))
232 p++;
233 while (isspace(*p))
234 p++;
235
236 inquote = 0;
237 word_start = 0;
238 }
239 else if (*p == '"' || *p == '\'')
240 {
241 /* we've reached the beginning of a quote */
242 inquote = *p++;
243 word_start = p;
244 }
245 else
246 {
247 /* we've reached the beginning of a new word */
248 if (!word_start)
249 word_start = p;
250
251 /* normal character, skip */
252 p++;
253 }
254 }
255
256 return nwords;
257 }
258
259 void command_print(command_context_t *context, char *format, ...)
260 {
261 va_list ap;
262 char *buffer = NULL;
263 int n, size = 0;
264 char *p;
265
266 va_start(ap, format);
267
268 /* process format string */
269 /* TODO: possible bug. va_list is undefined after the first call to vsnprintf */
270 while (!buffer || (n = vsnprintf(buffer, size, format, ap)) >= size)
271 {
272 /* increase buffer until it fits the whole string */
273 if (!(p = realloc(buffer, size += 4096)))
274 {
275 /* gotta free up */
276 if (buffer)
277 free(buffer);
278 return;
279 }
280
281 buffer = p;
282 }
283
284 /* vsnprintf failed */
285 if (n < 0)
286 {
287 if (buffer)
288 free(buffer);
289 return;
290 }
291
292 p = buffer;
293
294 /* process lines in buffer */
295 do {
296 char *next = strchr(p, '\n');
297
298 if (next)
299 *next++ = 0;
300
301 if (context->output_handler)
302 context->output_handler(context, p);
303
304 p = next;
305 } while (p);
306
307 if (buffer)
308 free(buffer);
309
310 va_end(ap);
311 }
312
313 int find_and_run_command(command_context_t *context, command_t *commands, char *words[], int num_words, int start_word)
314 {
315 command_t *c;
316
317 if (unique_length_dirty)
318 {
319 unique_length_dirty = 0;
320 /* update unique lengths */
321 build_unique_lengths(context, context->commands);
322 }
323
324 for (c = commands; c; c = c->next)
325 {
326 if (strncasecmp(c->name, words[start_word], c->unique_len))
327 continue;
328
329 if (strncasecmp(c->name, words[start_word], strlen(words[start_word])))
330 continue;
331
332 if ((c->mode == context->mode) || (c->mode == COMMAND_ANY))
333 {
334 if (!c->children)
335 {
336 if (!c->handler)
337 {
338 command_print(context, "No handler for command");
339 break;
340 }
341 else
342 {
343 return c->handler(context, c->name, words + start_word + 1, num_words - start_word - 1);
344 }
345 }
346 else
347 {
348 if (start_word == num_words - 1)
349 {
350 command_print(context, "Incomplete command");
351 break;
352 }
353 return find_and_run_command(context, c->children, words, num_words, start_word + 1);
354 }
355 }
356 }
357
358 command_print(context, "Command %s not found", words[start_word]);
359 return ERROR_OK;
360 }
361
362 int command_run_line(command_context_t *context, char *line)
363 {
364 int nwords;
365 char *words[128] = {0};
366 int retval;
367 int i;
368
369 if ((!context) || (!line))
370 return ERROR_INVALID_ARGUMENTS;
371
372 /* skip preceding whitespace */
373 while (isspace(*line))
374 line++;
375
376 /* empty line, ignore */
377 if (!*line)
378 return ERROR_OK;
379
380 /* ignore comments */
381 if (*line && (line[0] == '#'))
382 return ERROR_OK;
383
384 if (context->echo)
385 {
386 command_print(context, "%s", line);
387 }
388
389 nwords = parse_line(line, words, sizeof(words) / sizeof(words[0]));
390
391 if (nwords > 0)
392 retval = find_and_run_command(context, context->commands, words, nwords, 0);
393 else
394 return ERROR_INVALID_ARGUMENTS;
395
396 for (i = 0; i < nwords; i++)
397 free(words[i]);
398
399 return retval;
400 }
401
402 int command_run_file(command_context_t *context, FILE *file, enum command_mode mode)
403 {
404 int retval = ERROR_OK;
405 int old_command_mode;
406 char *buffer=malloc(4096);
407 if (buffer==NULL)
408 {
409 return ERROR_INVALID_ARGUMENTS;
410 }
411
412 old_command_mode = context->mode;
413 context->mode = mode;
414
415 while (fgets(buffer, 4096, file))
416 {
417 char *p;
418 char *cmd, *end;
419
420 /* stop processing line after a comment (#, !) or a LF, CR were encountered */
421 if ((p = strpbrk(buffer, "#!\r\n")))
422 *p = 0;
423
424 /* skip over leading whitespace */
425 cmd = buffer;
426 while (isspace(*cmd))
427 cmd++;
428
429 /* empty (all whitespace) line? */
430 if (!*cmd)
431 continue;
432
433 /* search the end of the current line, ignore trailing whitespace */
434 for (p = end = cmd; *p; p++)
435 if (!isspace(*p))
436 end = p;
437
438 /* terminate end */
439 *++end = 0;
440 if (strcasecmp(cmd, "quit") == 0)
441 break;
442
443 /* run line */
444 if ((retval = command_run_line(context, cmd)) == ERROR_COMMAND_CLOSE_CONNECTION)
445 break;
446 }
447
448 context->mode = old_command_mode;
449
450
451 free(buffer);
452
453 return retval;
454 }
455
456 void command_print_help_line(command_context_t* context, struct command_s *command, int indent)
457 {
458 command_t *c;
459 char indents[32] = {0};
460 char *help = "no help available";
461 char name_buf[64];
462 int i;
463
464 for (i = 0; i < indent; i+=2)
465 {
466 indents[i*2] = ' ';
467 indents[i*2+1] = '-';
468 }
469 indents[i*2] = 0;
470
471 if ((command->mode == COMMAND_EXEC) || (command->mode == COMMAND_ANY))
472 {
473 if (command->help)
474 help = command->help;
475
476 snprintf(name_buf, 64, command->name);
477 strncat(name_buf, indents, 64);
478 command_print(context, "%20s\t%s", name_buf, help);
479 }
480
481 if (command->children)
482 {
483 for (c = command->children; c; c = c->next)
484 {
485 command_print_help_line(context, c, indent + 1);
486 }
487 }
488 }
489
490 int command_print_help(command_context_t* context, char* name, char** args, int argc)
491 {
492 command_t *c;
493
494 for (c = context->commands; c; c = c->next)
495 {
496 if (argc == 1)
497 {
498 if (strncasecmp(c->name, args[0], c->unique_len))
499 continue;
500
501 if (strncasecmp(c->name, args[0], strlen(args[0])))
502 continue;
503 }
504
505 command_print_help_line(context, c, 0);
506 }
507
508 return ERROR_OK;
509 }
510
511 void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, char* line), void *priv)
512 {
513 context->output_handler = output_handler;
514 context->output_handler_priv = priv;
515 }
516
517 command_context_t* copy_command_context(command_context_t* context)
518 {
519 command_context_t* copy_context = malloc(sizeof(command_context_t));
520
521 *copy_context = *context;
522
523 return copy_context;
524 }
525
526 int command_done(command_context_t *context)
527 {
528 free(context);
529 context = NULL;
530
531 return ERROR_OK;
532 }
533
534 command_context_t* command_init()
535 {
536 command_context_t* context = malloc(sizeof(command_context_t));
537
538 context->mode = COMMAND_EXEC;
539 context->commands = NULL;
540 context->current_target = 0;
541 context->echo = 0;
542 context->output_handler = NULL;
543 context->output_handler_priv = NULL;
544
545 register_command(context, NULL, "help", command_print_help,
546 COMMAND_EXEC, "display this help");
547
548 register_command(context, NULL, "sleep", handle_sleep_command,
549 COMMAND_ANY, "sleep for <n> milliseconds");
550
551 return context;
552 }
553
554 /* sleep command sleeps for <n> miliseconds
555 * this is useful in target startup scripts
556 */
557 int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
558 {
559 unsigned long duration = 0;
560
561 if (argc == 1)
562 {
563 duration = strtoul(args[0], NULL, 0);
564 usleep(duration * 1000);
565 }
566
567 return ERROR_OK;
568 }