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

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)