1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * part of this file is taken from libcli (libcli.sourceforge.net) *
6 * Copyright (C) David Parrish (david@dparrish.com) *
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. *
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. *
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 ***************************************************************************/
27 #include "replacements.h"
32 #include "time_support.h"
41 int fast_and_dangerous
= 0;
43 void command_print_help_line(command_context_t
* context
, struct command_s
*command
, int indent
);
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
);
49 int build_unique_lengths(command_context_t
*context
, command_t
*commands
)
53 /* iterate through all commands */
54 for (c
= commands
; c
; c
= c
->next
)
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
++)
61 /* for every command, see if the current length is enough */
62 for (p
= commands
; p
; p
= p
->next
)
64 /* ignore the command itself */
68 /* compare commands up to the current length */
69 if (strncmp(p
->name
, c
->name
, c
->unique_len
) == 0)
73 /* when none of the commands matched, we've found the minimum length required */
78 /* if the current command has children, build the unique lengths for them */
80 build_unique_lengths(context
, c
->children
);
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.
89 static int unique_length_dirty
= 1;
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
)
94 unique_length_dirty
= 1;
96 if (!context
|| !name
)
99 c
= malloc(sizeof(command_t
));
101 c
->name
= strdup(name
);
104 c
->handler
= handler
;
107 c
->help
= strdup(help
);
113 /* place command in tree */
116 if (parent
->children
)
118 /* find last child */
119 for (p
= parent
->children
; p
&& p
->next
; p
= p
->next
);
125 parent
->children
= c
;
130 if (context
->commands
)
132 /* find last command */
133 for (p
= context
->commands
; p
&& p
->next
; p
= p
->next
);
139 context
->commands
= c
;
146 int unregister_all_commands(command_context_t
*context
)
150 unique_length_dirty
= 1;
156 while(NULL
!= context
->commands
)
158 c
= context
->commands
;
160 while(NULL
!= c
->children
)
163 c
->children
= c
->children
->next
;
172 context
->commands
= context
->commands
->next
;
185 int unregister_command(command_context_t
*context
, char *name
)
187 command_t
*c
, *p
= NULL
, *c2
;
189 unique_length_dirty
= 1;
191 if ((!context
) || (!name
))
192 return ERROR_INVALID_ARGUMENTS
;
195 for (c
= context
->commands
; c
; c
= c
->next
)
197 if (strcmp(name
, c
->name
) == 0)
206 context
->commands
= c
->next
;
209 /* unregister children */
212 for (c2
= c
->children
; c2
; c2
= c2
->next
)
228 /* remember the last command for unlinking */
235 int parse_line(char *line
, char *words
[], int max_words
)
239 char *word_start
= line
;
242 while (nwords
< max_words
- 1)
244 /* check if we reached
246 * a matching closing quote character " or '
247 * we're inside a word but not a quote, and the current character is whitespace
249 if (!*p
|| *p
== inquote
|| (word_start
&& !inquote
&& isspace(*p
)))
251 /* we're inside a word or quote, and reached its end*/
257 /* This will handle extra whitespace within quotes */
258 while (isspace(*word_start
)&&(word_start
<word_end
))
260 while (isspace(*(word_end
-1))&&(word_start
<word_end
))
262 len
= word_end
- word_start
;
267 memcpy(words
[nwords
] = malloc(len
+ 1), word_start
, len
);
268 /* add terminating NUL */
269 words
[nwords
++][len
] = 0;
272 /* we're done parsing the line */
276 /* skip over trailing quote or whitespace*/
277 if (inquote
|| isspace(*p
))
285 else if (*p
== '"' || *p
== '\'')
287 /* we've reached the beginning of a quote */
293 /* we've reached the beginning of a new word */
297 /* normal character, skip */
305 void command_print_n(command_context_t
*context
, char *format
, ...)
310 va_start(ap
, format
);
312 string
= alloc_vprintf(format
, ap
);
315 context
->output_handler(context
, string
);
322 void command_print(command_context_t
*context
, char *format
, ...)
327 va_start(ap
, format
);
329 string
= alloc_vprintf(format
, ap
);
332 strcat(string
, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one char longer */
333 context
->output_handler(context
, string
);
340 command_t
*find_command(command_context_t
*context
, command_t
*commands
, char *words
[], int num_words
, int start_word
, int *new_start_word
)
344 if (unique_length_dirty
)
346 unique_length_dirty
= 0;
347 /* update unique lengths */
348 build_unique_lengths(context
, context
->commands
);
351 for (c
= commands
; c
; c
= c
->next
)
353 if (strncasecmp(c
->name
, words
[start_word
], c
->unique_len
))
356 if (strncasecmp(c
->name
, words
[start_word
], strlen(words
[start_word
])))
359 if ((context
->mode
== COMMAND_CONFIG
) || (c
->mode
== COMMAND_ANY
) || (c
->mode
== context
->mode
) )
369 *new_start_word
=start_word
;
375 if (start_word
== num_words
- 1)
379 return find_command(context
, c
->children
, words
, num_words
, start_word
+ 1, new_start_word
);
386 int find_and_run_command(command_context_t
*context
, command_t
*commands
, char *words
[], int num_words
)
390 c
=find_command(context
, commands
, words
, num_words
, start_word
, &start_word
);
393 command_print(context
, "Command %s not found", words
[start_word
]);
394 return ERROR_COMMAND_SYNTAX_ERROR
;
397 int retval
= c
->handler(context
, c
->name
, words
+ start_word
+ 1, num_words
- start_word
- 1);
398 if (retval
== ERROR_COMMAND_SYNTAX_ERROR
)
400 command_print(context
, "Syntax error:");
401 command_print_help_line(context
, c
, 0);
403 else if (retval
== ERROR_COMMAND_CLOSE_CONNECTION
)
405 /* just fall through for a shutdown request */
407 else if (retval
!= ERROR_OK
)
409 /* we do not print out an error message because the command *should*
410 * have printed out an error
412 LOG_DEBUG("Command failed with error code %d", retval
);
417 int command_run_line_internal_op(command_context_t
*context
, char *line
, int run
)
419 LOG_USER_N("%s", ""); /* Keep GDB connection alive*/
422 char *words
[128] = {0};
426 /* skip preceding whitespace */
427 while (isspace(*line
))
430 /* empty line, ignore */
434 /* ignore comments */
435 if (*line
&& (line
[0] == '#'))
438 LOG_DEBUG("%s", line
);
440 nwords
= parse_line(line
, words
, sizeof(words
) / sizeof(words
[0]));
445 retval
= find_and_run_command(context
, context
->commands
, words
, nwords
);
449 return (find_command(context
, context
->commands
, words
, nwords
, 0, &t
)!=NULL
)?ERROR_OK
:ERROR_FAIL
;
452 return ERROR_INVALID_ARGUMENTS
;
454 for (i
= 0; i
< nwords
; i
++)
460 int command_run_line_internal(command_context_t
*context
, char *line
)
462 return command_run_line_internal_op(context
, line
, 1);
465 int command_run_line(command_context_t
*context
, char *line
)
468 if ((!context
) || (!line
))
469 return ERROR_INVALID_ARGUMENTS
;
471 if (command_run_line_internal_op(context
, line
, 0)!=ERROR_OK
)
473 /* If we can't find a command, then try the interpreter.
474 * If there is no interpreter implemented, then this will
475 * simply print a syntax error.
477 * These hooks were left in to reduce patch size for
478 * wip to add scripting language.
480 return jim_command(context
, line
);
483 return command_run_line_internal(context
, line
);
486 int command_run_file(command_context_t
*context
, FILE *file
, enum command_mode mode
)
488 int retval
= ERROR_OK
;
489 int old_command_mode
;
490 char *buffer
=malloc(4096);
493 return ERROR_INVALID_ARGUMENTS
;
496 old_command_mode
= context
->mode
;
497 context
->mode
= mode
;
499 while (fgets(buffer
, 4096, file
))
504 /* stop processing line after a comment (#, !) or a LF, CR were encountered */
505 if ((p
= strpbrk(buffer
, "#!\r\n")))
508 /* skip over leading whitespace */
510 while (isspace(*cmd
))
513 /* empty (all whitespace) line? */
517 /* search the end of the current line, ignore trailing whitespace */
518 for (p
= end
= cmd
; *p
; p
++)
524 if (strcasecmp(cmd
, "quit") == 0)
528 if ((retval
= command_run_line(context
, cmd
)) == ERROR_COMMAND_CLOSE_CONNECTION
)
532 context
->mode
= old_command_mode
;
540 void command_print_help_line(command_context_t
* context
, struct command_s
*command
, int indent
)
543 char *indent_text
=malloc(indent
+ 2);
545 char *help
= "no help available";
550 indent_text
[0] = ' ';
551 memset(indent_text
+ 1, '-', indent
);
552 indent_text
[indent
+ 1] = 0;
556 help
= command
->help
;
558 snprintf(name_buf
, 64, command
->name
);
561 strncat(name_buf
, indent_text
, 64);
563 command_print(context
, "%20s\t%s", name_buf
, help
, indent
);
565 if (command
->children
)
567 for (c
= command
->children
; c
; c
= c
->next
)
569 command_print_help_line(context
, c
, indent
+ 1);
575 int command_print_help_match(command_context_t
* context
, command_t
* c_first
, char* name
, char** args
, int argc
)
579 for (c
= c_first
; c
; c
= c
->next
)
583 if (strncasecmp(c
->name
, args
[0], c
->unique_len
))
586 if (strncasecmp(c
->name
, args
[0], strlen(args
[0])))
591 command_print_help_match(context
, c
->children
, name
, args
+ 1, argc
- 1);
596 command_print_help_line(context
, c
, 0);
602 int command_print_help(command_context_t
* context
, char* name
, char** args
, int argc
)
604 return command_print_help_match(context
, context
->commands
, name
, args
, argc
);
607 void command_set_output_handler(command_context_t
* context
, int (*output_handler
)(struct command_context_s
*context
, char* line
), void *priv
)
609 context
->output_handler
= output_handler
;
610 context
->output_handler_priv
= priv
;
613 command_context_t
* copy_command_context(command_context_t
* context
)
615 command_context_t
* copy_context
= malloc(sizeof(command_context_t
));
617 *copy_context
= *context
;
622 int command_done(command_context_t
*context
)
630 command_context_t
* command_init()
632 command_context_t
* context
= malloc(sizeof(command_context_t
));
634 context
->mode
= COMMAND_EXEC
;
635 context
->commands
= NULL
;
636 context
->current_target
= 0;
637 context
->output_handler
= NULL
;
638 context
->output_handler_priv
= NULL
;
640 register_command(context
, NULL
, "help", command_print_help
,
641 COMMAND_EXEC
, "display this help");
643 register_command(context
, NULL
, "sleep", handle_sleep_command
,
644 COMMAND_ANY
, "sleep for <n> milliseconds");
646 register_command(context
, NULL
, "time", handle_time_command
,
647 COMMAND_ANY
, "time <cmd + args> - execute <cmd + args> and print time it took");
649 register_command(context
, NULL
, "fast", handle_fast_command
,
650 COMMAND_ANY
, "fast <enable/disable> - place at beginning of config files. Sets defaults to fast and dangerous.");
655 /* sleep command sleeps for <n> miliseconds
656 * this is useful in target startup scripts
658 int handle_sleep_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
660 unsigned long duration
= 0;
664 duration
= strtoul(args
[0], NULL
, 0);
665 usleep(duration
* 1000);
671 int handle_fast_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
674 return ERROR_COMMAND_SYNTAX_ERROR
;
676 fast_and_dangerous
= strcmp("enable", args
[0])==0;
682 int handle_time_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
690 return ERROR_COMMAND_SYNTAX_ERROR
;
692 duration_start_measure(&duration
);
694 retval
= find_and_run_command(cmd_ctx
, cmd_ctx
->commands
, args
, argc
);
696 duration_stop_measure(&duration
, &duration_text
);
698 t
=duration
.duration
.tv_sec
;
699 t
+=((float)duration
.duration
.tv_usec
/ 1000000.0);
700 command_print(cmd_ctx
, "%s took %fs", args
[0], t
);
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)