55f950bf49f9df5fb02319b901240507ee632ab1
[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 #include "time_support.h"
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include <unistd.h>
40
41 int fast_and_dangerous = 0;
42
43 void command_print_help_line(command_context_t* context, struct command_s *command, int indent);
44
45 int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
46 int handle_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
47 int handle_fast_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
48
49 /* forward declaration of jim_command */
50 extern int jim_command(command_context_t *context, char *line);
51
52 int build_unique_lengths(command_context_t *context, command_t *commands)
53 {
54 command_t *c, *p;
55
56 /* iterate through all commands */
57 for (c = commands; c; c = c->next)
58 {
59 /* find out how many characters are required to uniquely identify a command */
60 for (c->unique_len = 1; c->unique_len <= strlen(c->name); c->unique_len++)
61 {
62 int foundmatch = 0;
63
64 /* for every command, see if the current length is enough */
65 for (p = commands; p; p = p->next)
66 {
67 /* ignore the command itself */
68 if (c == p)
69 continue;
70
71 /* compare commands up to the current length */
72 if (strncmp(p->name, c->name, c->unique_len) == 0)
73 foundmatch++;
74 }
75
76 /* when none of the commands matched, we've found the minimum length required */
77 if (!foundmatch)
78 break;
79 }
80
81 /* if the current command has children, build the unique lengths for them */
82 if (c->children)
83 build_unique_lengths(context, c->children);
84 }
85
86 return ERROR_OK;
87 }
88
89 /* Avoid evaluating this each time we add a command. Reduces overhead from O(n^2) to O(n).
90 * Makes a difference on ARM7 types machines and is not observable on GHz machines.
91 */
92 static int unique_length_dirty = 1;
93
94 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)
95 {
96 command_t *c, *p;
97 unique_length_dirty = 1;
98
99 if (!context || !name)
100 return NULL;
101
102 c = malloc(sizeof(command_t));
103
104 c->name = strdup(name);
105 c->parent = parent;
106 c->children = NULL;
107 c->handler = handler;
108 c->mode = mode;
109 if (help)
110 c->help = strdup(help);
111 else
112 c->help = NULL;
113 c->unique_len = 0;
114 c->next = NULL;
115
116 /* place command in tree */
117 if (parent)
118 {
119 if (parent->children)
120 {
121 /* find last child */
122 for (p = parent->children; p && p->next; p = p->next);
123 if (p)
124 p->next = c;
125 }
126 else
127 {
128 parent->children = c;
129 }
130 }
131 else
132 {
133 if (context->commands)
134 {
135 /* find last command */
136 for (p = context->commands; p && p->next; p = p->next);
137 if (p)
138 p->next = c;
139 }
140 else
141 {
142 context->commands = c;
143 }
144 }
145
146 return c;
147 }
148
149 int unregister_all_commands(command_context_t *context)
150 {
151 command_t *c, *c2;
152
153 unique_length_dirty = 1;
154
155 if (context == NULL)
156 return ERROR_OK;
157
158
159 while(NULL != context->commands)
160 {
161 c = context->commands;
162
163 while(NULL != c->children)
164 {
165 c2 = c->children;
166 c->children = c->children->next;
167 free(c2->name);
168 c2->name = NULL;
169 free(c2->help);
170 c2->help = NULL;
171 free(c2);
172 c2 = NULL;
173 }
174
175 context->commands = context->commands->next;
176
177 free(c->name);
178 c->name = NULL;
179 free(c->help);
180 c->help = NULL;
181 free(c);
182 c = NULL;
183 }
184
185 return ERROR_OK;
186 }
187
188 int unregister_command(command_context_t *context, char *name)
189 {
190 command_t *c, *p = NULL, *c2;
191
192 unique_length_dirty = 1;
193
194 if ((!context) || (!name))
195 return ERROR_INVALID_ARGUMENTS;
196
197 /* find command */
198 for (c = context->commands; c; c = c->next)
199 {
200 if (strcmp(name, c->name) == 0)
201 {
202 /* unlink command */
203 if (p)
204 {
205 p->next = c->next;
206 }
207 else
208 {
209 context->commands = c->next;
210 }
211
212 /* unregister children */
213 if (c->children)
214 {
215 for (c2 = c->children; c2; c2 = c2->next)
216 {
217 free(c2->name);
218 if (c2->help)
219 free(c2->help);
220 free(c2);
221 }
222 }
223
224 /* delete command */
225 free(c->name);
226 if (c->help)
227 free(c->help);
228 free(c);
229 }
230
231 /* remember the last command for unlinking */
232 p = c;
233 }
234
235 return ERROR_OK;
236 }
237
238 int parse_line(char *line, char *words[], int max_words)
239 {
240 int nwords = 0;
241 char *p = line;
242 char *word_start = line;
243 int inquote = 0;
244
245 while (nwords < max_words - 1)
246 {
247 /* check if we reached
248 * a terminating NUL
249 * a matching closing quote character " or '
250 * we're inside a word but not a quote, and the current character is whitespace
251 */
252 if (!*p || *p == inquote || (word_start && !inquote && isspace(*p)))
253 {
254 /* we're inside a word or quote, and reached its end*/
255 if (word_start)
256 {
257 int len;
258 char *word_end=p;
259
260 /* This will handle extra whitespace within quotes */
261 while (isspace(*word_start)&&(word_start<word_end))
262 word_start++;
263 while (isspace(*(word_end-1))&&(word_start<word_end))
264 word_end--;
265 len = word_end - word_start;
266
267 if (len>0)
268 {
269 /* copy the word */
270 memcpy(words[nwords] = malloc(len + 1), word_start, len);
271 /* add terminating NUL */
272 words[nwords++][len] = 0;
273 }
274 }
275 /* we're done parsing the line */
276 if (!*p)
277 break;
278
279 /* skip over trailing quote or whitespace*/
280 if (inquote || isspace(*p))
281 p++;
282 while (isspace(*p))
283 p++;
284
285 inquote = 0;
286 word_start = 0;
287 }
288 else if (*p == '"' || *p == '\'')
289 {
290 /* we've reached the beginning of a quote */
291 inquote = *p++;
292 word_start = p;
293 }
294 else
295 {
296 /* we've reached the beginning of a new word */
297 if (!word_start)
298 word_start = p;
299
300 /* normal character, skip */
301 p++;
302 }
303 }
304
305 return nwords;
306 }
307
308 void command_output_text( command_context_t *context, const char *data )
309 {
310 if( context && context->output_handler && data ){
311 context->output_handler( context, data );
312 }
313 }
314
315
316 void command_print_n(command_context_t *context, char *format, ...)
317 {
318 char *string;
319
320 va_list ap;
321 va_start(ap, format);
322
323 string = alloc_vprintf(format, ap);
324 if (string != NULL)
325 {
326 context->output_handler(context, string);
327 free(string);
328 }
329
330 va_end(ap);
331 }
332
333 void command_print(command_context_t *context, char *format, ...)
334 {
335 char *string;
336
337 va_list ap;
338 va_start(ap, format);
339
340 string = alloc_vprintf(format, ap);
341 if (string != NULL)
342 {
343 strcat(string, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one char longer */
344 context->output_handler(context, string);
345 free(string);
346 }
347
348 va_end(ap);
349 }
350
351 command_t *find_command(command_context_t *context, command_t *commands, char *words[], int num_words, int start_word, int *new_start_word)
352 {
353 command_t *c;
354
355 if (unique_length_dirty)
356 {
357 unique_length_dirty = 0;
358 /* update unique lengths */
359 build_unique_lengths(context, context->commands);
360 }
361
362 for (c = commands; c; c = c->next)
363 {
364 if (strncasecmp(c->name, words[start_word], c->unique_len))
365 continue;
366
367 if (strncasecmp(c->name, words[start_word], strlen(words[start_word])))
368 continue;
369
370 if ((context->mode == COMMAND_CONFIG) || (c->mode == COMMAND_ANY) || (c->mode == context->mode) )
371 {
372 if (!c->children)
373 {
374 if (!c->handler)
375 {
376 return NULL;
377 }
378 else
379 {
380 *new_start_word=start_word;
381 return c;
382 }
383 }
384 else
385 {
386 if (start_word == num_words - 1)
387 {
388 return NULL;
389 }
390 return find_command(context, c->children, words, num_words, start_word + 1, new_start_word);
391 }
392 }
393 }
394 return NULL;
395 }
396
397 int find_and_run_command(command_context_t *context, command_t *commands, char *words[], int num_words)
398 {
399 int start_word=0;
400 command_t *c;
401 c=find_command(context, commands, words, num_words, start_word, &start_word);
402 if (c==NULL)
403 {
404 command_print(context, "Command %s not found", words[start_word]);
405 return ERROR_COMMAND_SYNTAX_ERROR;
406 }
407
408 int retval = c->handler(context, c->name, words + start_word + 1, num_words - start_word - 1);
409 if (retval == ERROR_COMMAND_SYNTAX_ERROR)
410 {
411 command_print(context, "Syntax error:");
412 command_print_help_line(context, c, 0);
413 }
414 else if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
415 {
416 /* just fall through for a shutdown request */
417 }
418 else if (retval != ERROR_OK)
419 {
420 /* we do not print out an error message because the command *should*
421 * have printed out an error
422 */
423 LOG_DEBUG("Command failed with error code %d", retval);
424 }
425 return retval;
426 }
427
428 int command_run_line_internal_op(command_context_t *context, char *line, int run)
429 {
430 LOG_USER_N("%s", ""); /* Keep GDB connection alive*/
431
432 int nwords;
433 char *words[128] = {0};
434 int retval;
435 int i;
436
437 /* skip preceding whitespace */
438 while (isspace(*line))
439 line++;
440
441 /* empty line, ignore */
442 if (!*line)
443 return ERROR_OK;
444
445 /* ignore comments */
446 if (*line && (line[0] == '#'))
447 return ERROR_OK;
448
449 LOG_DEBUG("%s", line);
450
451 nwords = parse_line(line, words, sizeof(words) / sizeof(words[0]));
452
453 if (nwords > 0)
454 if (run)
455 {
456 retval = find_and_run_command(context, context->commands, words, nwords);
457 } else
458 {
459 int t;
460 return (find_command(context, context->commands, words, nwords, 0, &t)!=NULL)?ERROR_OK:ERROR_FAIL;
461 }
462 else
463 return ERROR_INVALID_ARGUMENTS;
464
465 for (i = 0; i < nwords; i++)
466 free(words[i]);
467
468 return retval;
469 }
470
471 int command_run_line_internal(command_context_t *context, char *line)
472 {
473 return command_run_line_internal_op(context, line, 1);
474 }
475
476 int command_run_line(command_context_t *context, char *line)
477 {
478 if ((!context) || (!line))
479 return ERROR_INVALID_ARGUMENTS;
480
481 if (command_run_line_internal_op(context, line, 0)!=ERROR_OK)
482 {
483 /* If we can't find a command, then try the interpreter.
484 * If there is no interpreter implemented, then this will
485 * simply print a syntax error.
486 *
487 * These hooks were left in to reduce patch size for
488 * wip to add scripting language.
489 */
490 return jim_command(context, line);
491 }
492
493 return command_run_line_internal(context, line);
494 }
495
496 int command_run_file(command_context_t *context, FILE *file, enum command_mode mode)
497 {
498 int retval = ERROR_OK;
499 int old_command_mode;
500 char *buffer=malloc(4096);
501 if (buffer==NULL)
502 {
503 return ERROR_INVALID_ARGUMENTS;
504 }
505
506 old_command_mode = context->mode;
507 context->mode = mode;
508
509 while (fgets(buffer, 4096, file))
510 {
511 char *p;
512 char *cmd, *end;
513
514 /* stop processing line after a comment (#, !) or a LF, CR were encountered */
515 if ((p = strpbrk(buffer, "#!\r\n")))
516 *p = 0;
517
518 /* skip over leading whitespace */
519 cmd = buffer;
520 while (isspace(*cmd))
521 cmd++;
522
523 /* empty (all whitespace) line? */
524 if (!*cmd)
525 continue;
526
527 /* search the end of the current line, ignore trailing whitespace */
528 for (p = end = cmd; *p; p++)
529 if (!isspace(*p))
530 end = p;
531
532 /* terminate end */
533 *++end = 0;
534 if (strcasecmp(cmd, "quit") == 0)
535 break;
536
537 /* run line */
538 if ((retval = command_run_line(context, cmd)) == ERROR_COMMAND_CLOSE_CONNECTION)
539 break;
540 }
541
542 context->mode = old_command_mode;
543
544
545 free(buffer);
546
547 return retval;
548 }
549
550 int command_run_linef(command_context_t *context, char *format, ...)
551 {
552 int retval=ERROR_FAIL;
553 char *string;
554 va_list ap;
555 va_start(ap, format);
556 string = alloc_vprintf(format, ap);
557 if (string!=NULL)
558 {
559 retval=command_run_line(context, string);
560 }
561 va_end(ap);
562 return retval;
563 }
564
565 void command_print_help_line(command_context_t* context, struct command_s *command, int indent)
566 {
567 command_t *c;
568 char *indent_text=malloc(indent + 2);
569
570 char *help = "no help available";
571 char name_buf[64];
572
573 if (indent)
574 {
575 indent_text[0] = ' ';
576 memset(indent_text + 1, '-', indent);
577 indent_text[indent + 1] = 0;
578 }
579
580 if (command->help)
581 help = command->help;
582
583 snprintf(name_buf, 64, command->name);
584
585 if (indent)
586 strncat(name_buf, indent_text, 64);
587
588 command_print(context, "%20s\t%s", name_buf, help, indent);
589
590 if (command->children)
591 {
592 for (c = command->children; c; c = c->next)
593 {
594 command_print_help_line(context, c, indent + 1);
595 }
596 }
597 free(indent_text);
598 }
599
600 int command_print_help_match(command_context_t* context, command_t* c_first, char* name, char** args, int argc)
601 {
602 command_t * c;
603
604 for (c = c_first; c; c = c->next)
605 {
606 if (argc > 0)
607 {
608 if (strncasecmp(c->name, args[0], c->unique_len))
609 continue;
610
611 if (strncasecmp(c->name, args[0], strlen(args[0])))
612 continue;
613
614 if (argc > 1)
615 {
616 command_print_help_match(context, c->children, name, args + 1, argc - 1);
617 continue;
618 }
619 }
620
621 command_print_help_line(context, c, 0);
622 }
623
624 return ERROR_OK;
625 }
626
627 int command_print_help(command_context_t* context, char* name, char** args, int argc)
628 {
629 return command_print_help_match(context, context->commands, name, args, argc);
630 }
631
632 void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, const char* line), void *priv)
633 {
634 context->output_handler = output_handler;
635 context->output_handler_priv = priv;
636 }
637
638 command_context_t* copy_command_context(command_context_t* context)
639 {
640 command_context_t* copy_context = malloc(sizeof(command_context_t));
641
642 *copy_context = *context;
643
644 return copy_context;
645 }
646
647 int command_done(command_context_t *context)
648 {
649 free(context);
650 context = NULL;
651
652 return ERROR_OK;
653 }
654
655 command_context_t* command_init()
656 {
657 command_context_t* context = malloc(sizeof(command_context_t));
658
659 context->mode = COMMAND_EXEC;
660 context->commands = NULL;
661 context->current_target = 0;
662 context->output_handler = NULL;
663 context->output_handler_priv = NULL;
664
665 register_command(context, NULL, "help", command_print_help,
666 COMMAND_EXEC, "display this help");
667
668 register_command(context, NULL, "sleep", handle_sleep_command,
669 COMMAND_ANY, "sleep for <n> milliseconds");
670
671 register_command(context, NULL, "time", handle_time_command,
672 COMMAND_ANY, "time <cmd + args> - execute <cmd + args> and print time it took");
673
674 register_command(context, NULL, "fast", handle_fast_command,
675 COMMAND_ANY, "fast <enable/disable> - place at beginning of config files. Sets defaults to fast and dangerous.");
676
677 return context;
678 }
679
680 /* sleep command sleeps for <n> miliseconds
681 * this is useful in target startup scripts
682 */
683 int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
684 {
685 unsigned long duration = 0;
686
687 if (argc == 1)
688 {
689 duration = strtoul(args[0], NULL, 0);
690 usleep(duration * 1000);
691 }
692
693 return ERROR_OK;
694 }
695
696 int handle_fast_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
697 {
698 if (argc!=1)
699 return ERROR_COMMAND_SYNTAX_ERROR;
700
701 fast_and_dangerous = strcmp("enable", args[0])==0;
702
703 return ERROR_OK;
704 }
705
706
707 int handle_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
708 {
709 duration_t duration;
710 char *duration_text;
711 int retval;
712 float t;
713
714 if (argc<1)
715 return ERROR_COMMAND_SYNTAX_ERROR;
716
717 duration_start_measure(&duration);
718
719 retval = find_and_run_command(cmd_ctx, cmd_ctx->commands, args, argc);
720
721 duration_stop_measure(&duration, &duration_text);
722
723 t=duration.duration.tv_sec;
724 t+=((float)duration.duration.tv_usec / 1000000.0);
725 command_print(cmd_ctx, "%s took %fs", args[0], t);
726
727 free(duration_text);
728
729 return retval;
730 }
731 /*
732 * Local Variables: **
733 * tab-width: 4 **
734 * c-basic-offset: 4 **
735 * End: **
736 */
737

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)