ed0a82e6218946c51a6b683a1604f4be20136a42
[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_print_n(command_context_t *context, char *format, ...)
309 {
310 char *string;
311
312 va_list ap;
313 va_start(ap, format);
314
315 string = alloc_vprintf(format, ap);
316 if (string != NULL)
317 {
318 context->output_handler(context, string);
319 free(string);
320 }
321
322 va_end(ap);
323 }
324
325 void command_print(command_context_t *context, char *format, ...)
326 {
327 char *string;
328
329 va_list ap;
330 va_start(ap, format);
331
332 string = alloc_vprintf(format, ap);
333 if (string != NULL)
334 {
335 strcat(string, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one char longer */
336 context->output_handler(context, string);
337 free(string);
338 }
339
340 va_end(ap);
341 }
342
343 command_t *find_command(command_context_t *context, command_t *commands, char *words[], int num_words, int start_word, int *new_start_word)
344 {
345 command_t *c;
346
347 if (unique_length_dirty)
348 {
349 unique_length_dirty = 0;
350 /* update unique lengths */
351 build_unique_lengths(context, context->commands);
352 }
353
354 for (c = commands; c; c = c->next)
355 {
356 if (strncasecmp(c->name, words[start_word], c->unique_len))
357 continue;
358
359 if (strncasecmp(c->name, words[start_word], strlen(words[start_word])))
360 continue;
361
362 if ((context->mode == COMMAND_CONFIG) || (c->mode == COMMAND_ANY) || (c->mode == context->mode) )
363 {
364 if (!c->children)
365 {
366 if (!c->handler)
367 {
368 return NULL;
369 }
370 else
371 {
372 *new_start_word=start_word;
373 return c;
374 }
375 }
376 else
377 {
378 if (start_word == num_words - 1)
379 {
380 return NULL;
381 }
382 return find_command(context, c->children, words, num_words, start_word + 1, new_start_word);
383 }
384 }
385 }
386 return NULL;
387 }
388
389 int find_and_run_command(command_context_t *context, command_t *commands, char *words[], int num_words)
390 {
391 int start_word=0;
392 command_t *c;
393 c=find_command(context, commands, words, num_words, start_word, &start_word);
394 if (c==NULL)
395 {
396 command_print(context, "Command %s not found", words[start_word]);
397 return ERROR_COMMAND_SYNTAX_ERROR;
398 }
399
400 int retval = c->handler(context, c->name, words + start_word + 1, num_words - start_word - 1);
401 if (retval == ERROR_COMMAND_SYNTAX_ERROR)
402 {
403 command_print(context, "Syntax error:");
404 command_print_help_line(context, c, 0);
405 }
406 else if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
407 {
408 /* just fall through for a shutdown request */
409 }
410 else if (retval != ERROR_OK)
411 {
412 /* we do not print out an error message because the command *should*
413 * have printed out an error
414 */
415 LOG_DEBUG("Command failed with error code %d", retval);
416 }
417 return retval;
418 }
419
420 int command_run_line_internal_op(command_context_t *context, char *line, int run)
421 {
422 LOG_USER_N("%s", ""); /* Keep GDB connection alive*/
423
424 int nwords;
425 char *words[128] = {0};
426 int retval;
427 int i;
428
429 /* skip preceding whitespace */
430 while (isspace(*line))
431 line++;
432
433 /* empty line, ignore */
434 if (!*line)
435 return ERROR_OK;
436
437 /* ignore comments */
438 if (*line && (line[0] == '#'))
439 return ERROR_OK;
440
441 LOG_DEBUG("%s", line);
442
443 nwords = parse_line(line, words, sizeof(words) / sizeof(words[0]));
444
445 if (nwords > 0)
446 if (run)
447 {
448 retval = find_and_run_command(context, context->commands, words, nwords);
449 } else
450 {
451 int t;
452 return (find_command(context, context->commands, words, nwords, 0, &t)!=NULL)?ERROR_OK:ERROR_FAIL;
453 }
454 else
455 return ERROR_INVALID_ARGUMENTS;
456
457 for (i = 0; i < nwords; i++)
458 free(words[i]);
459
460 return retval;
461 }
462
463 int command_run_line_internal(command_context_t *context, char *line)
464 {
465 return command_run_line_internal_op(context, line, 1);
466 }
467
468 int command_run_line(command_context_t *context, char *line)
469 {
470 if ((!context) || (!line))
471 return ERROR_INVALID_ARGUMENTS;
472
473 if (command_run_line_internal_op(context, line, 0)!=ERROR_OK)
474 {
475 /* If we can't find a command, then try the interpreter.
476 * If there is no interpreter implemented, then this will
477 * simply print a syntax error.
478 *
479 * These hooks were left in to reduce patch size for
480 * wip to add scripting language.
481 */
482 return jim_command(context, line);
483 }
484
485 return command_run_line_internal(context, line);
486 }
487
488 int command_run_file(command_context_t *context, FILE *file, enum command_mode mode)
489 {
490 int retval = ERROR_OK;
491 int old_command_mode;
492 char *buffer=malloc(4096);
493 if (buffer==NULL)
494 {
495 return ERROR_INVALID_ARGUMENTS;
496 }
497
498 old_command_mode = context->mode;
499 context->mode = mode;
500
501 while (fgets(buffer, 4096, file))
502 {
503 char *p;
504 char *cmd, *end;
505
506 /* stop processing line after a comment (#, !) or a LF, CR were encountered */
507 if ((p = strpbrk(buffer, "#!\r\n")))
508 *p = 0;
509
510 /* skip over leading whitespace */
511 cmd = buffer;
512 while (isspace(*cmd))
513 cmd++;
514
515 /* empty (all whitespace) line? */
516 if (!*cmd)
517 continue;
518
519 /* search the end of the current line, ignore trailing whitespace */
520 for (p = end = cmd; *p; p++)
521 if (!isspace(*p))
522 end = p;
523
524 /* terminate end */
525 *++end = 0;
526 if (strcasecmp(cmd, "quit") == 0)
527 break;
528
529 /* run line */
530 if ((retval = command_run_line(context, cmd)) == ERROR_COMMAND_CLOSE_CONNECTION)
531 break;
532 }
533
534 context->mode = old_command_mode;
535
536
537 free(buffer);
538
539 return retval;
540 }
541
542 int command_run_linef(command_context_t *context, char *format, ...)
543 {
544 int retval=ERROR_FAIL;
545 char *string;
546 va_list ap;
547 va_start(ap, format);
548 string = alloc_vprintf(format, ap);
549 if (string!=NULL)
550 {
551 retval=command_run_line(context, string);
552 }
553 va_end(ap);
554 return retval;
555 }
556
557 void command_print_help_line(command_context_t* context, struct command_s *command, int indent)
558 {
559 command_t *c;
560 char *indent_text=malloc(indent + 2);
561
562 char *help = "no help available";
563 char name_buf[64];
564
565 if (indent)
566 {
567 indent_text[0] = ' ';
568 memset(indent_text + 1, '-', indent);
569 indent_text[indent + 1] = 0;
570 }
571
572 if (command->help)
573 help = command->help;
574
575 snprintf(name_buf, 64, command->name);
576
577 if (indent)
578 strncat(name_buf, indent_text, 64);
579
580 command_print(context, "%20s\t%s", name_buf, help, indent);
581
582 if (command->children)
583 {
584 for (c = command->children; c; c = c->next)
585 {
586 command_print_help_line(context, c, indent + 1);
587 }
588 }
589 free(indent_text);
590 }
591
592 int command_print_help_match(command_context_t* context, command_t* c_first, char* name, char** args, int argc)
593 {
594 command_t * c;
595
596 for (c = c_first; c; c = c->next)
597 {
598 if (argc > 0)
599 {
600 if (strncasecmp(c->name, args[0], c->unique_len))
601 continue;
602
603 if (strncasecmp(c->name, args[0], strlen(args[0])))
604 continue;
605
606 if (argc > 1)
607 {
608 command_print_help_match(context, c->children, name, args + 1, argc - 1);
609 continue;
610 }
611 }
612
613 command_print_help_line(context, c, 0);
614 }
615
616 return ERROR_OK;
617 }
618
619 int command_print_help(command_context_t* context, char* name, char** args, int argc)
620 {
621 return command_print_help_match(context, context->commands, name, args, argc);
622 }
623
624 void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, char* line), void *priv)
625 {
626 context->output_handler = output_handler;
627 context->output_handler_priv = priv;
628 }
629
630 command_context_t* copy_command_context(command_context_t* context)
631 {
632 command_context_t* copy_context = malloc(sizeof(command_context_t));
633
634 *copy_context = *context;
635
636 return copy_context;
637 }
638
639 int command_done(command_context_t *context)
640 {
641 free(context);
642 context = NULL;
643
644 return ERROR_OK;
645 }
646
647 command_context_t* command_init()
648 {
649 command_context_t* context = malloc(sizeof(command_context_t));
650
651 context->mode = COMMAND_EXEC;
652 context->commands = NULL;
653 context->current_target = 0;
654 context->output_handler = NULL;
655 context->output_handler_priv = NULL;
656
657 register_command(context, NULL, "help", command_print_help,
658 COMMAND_EXEC, "display this help");
659
660 register_command(context, NULL, "sleep", handle_sleep_command,
661 COMMAND_ANY, "sleep for <n> milliseconds");
662
663 register_command(context, NULL, "time", handle_time_command,
664 COMMAND_ANY, "time <cmd + args> - execute <cmd + args> and print time it took");
665
666 register_command(context, NULL, "fast", handle_fast_command,
667 COMMAND_ANY, "fast <enable/disable> - place at beginning of config files. Sets defaults to fast and dangerous.");
668
669 return context;
670 }
671
672 /* sleep command sleeps for <n> miliseconds
673 * this is useful in target startup scripts
674 */
675 int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
676 {
677 unsigned long duration = 0;
678
679 if (argc == 1)
680 {
681 duration = strtoul(args[0], NULL, 0);
682 usleep(duration * 1000);
683 }
684
685 return ERROR_OK;
686 }
687
688 int handle_fast_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
689 {
690 if (argc!=1)
691 return ERROR_COMMAND_SYNTAX_ERROR;
692
693 fast_and_dangerous = strcmp("enable", args[0])==0;
694
695 return ERROR_OK;
696 }
697
698
699 int handle_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
700 {
701 duration_t duration;
702 char *duration_text;
703 int retval;
704 float t;
705
706 if (argc<1)
707 return ERROR_COMMAND_SYNTAX_ERROR;
708
709 duration_start_measure(&duration);
710
711 retval = find_and_run_command(cmd_ctx, cmd_ctx->commands, args, argc);
712
713 duration_stop_measure(&duration, &duration_text);
714
715 t=duration.duration.tv_sec;
716 t+=((float)duration.duration.tv_usec / 1000000.0);
717 command_print(cmd_ctx, "%s took %fs", args[0], t);
718
719 free(duration_text);
720
721 return retval;
722 }

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)