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

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)