- added support for error handlers to JTAG scan commands (jtag_[plain_][ir|dr]_scan)
[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
33 #include <stdlib.h>
34 #include <string.h>
35 #include <ctype.h>
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <unistd.h>
39
40 int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
41
42 int build_unique_lengths(command_context_t *context, command_t *commands)
43 {
44 command_t *c, *p;
45
46 /* iterate through all commands */
47 for (c = commands; c; c = c->next)
48 {
49 /* find out how many characters are required to uniquely identify a command */
50 for (c->unique_len = 1; c->unique_len <= strlen(c->name); c->unique_len++)
51 {
52 int foundmatch = 0;
53
54 /* for every command, see if the current length is enough */
55 for (p = commands; p; p = p->next)
56 {
57 /* ignore the command itself */
58 if (c == p)
59 continue;
60
61 /* compare commands up to the current length */
62 if (strncmp(p->name, c->name, c->unique_len) == 0)
63 foundmatch++;
64 }
65
66 /* when none of the commands matched, we've found the minimum length required */
67 if (!foundmatch)
68 break;
69 }
70
71 /* if the current command has children, build the unique lengths for them */
72 if (c->children)
73 build_unique_lengths(context, c->children);
74 }
75
76 return ERROR_OK;
77 }
78
79 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)
80 {
81 command_t *c, *p;
82
83 if (!context || !name)
84 return NULL;
85
86 c = malloc(sizeof(command_t));
87
88 c->name = strdup(name);
89 c->parent = parent;
90 c->children = NULL;
91 c->handler = handler;
92 c->mode = mode;
93 if (help)
94 c->help = strdup(help);
95 else
96 c->help = NULL;
97 c->unique_len = 0;
98 c->next = NULL;
99
100 /* place command in tree */
101 if (parent)
102 {
103 if (parent->children)
104 {
105 /* find last child */
106 for (p = parent->children; p && p->next; p = p->next);
107 if (p)
108 p->next = c;
109 }
110 else
111 {
112 parent->children = c;
113 }
114 }
115 else
116 {
117 if (context->commands)
118 {
119 /* find last command */
120 for (p = context->commands; p && p->next; p = p->next);
121 if (p)
122 p->next = c;
123 }
124 else
125 {
126 context->commands = c;
127 }
128 }
129
130 /* update unique lengths */
131 build_unique_lengths(context, (parent) ? parent : context->commands);
132
133 return c;
134 }
135
136 int unregister_command(command_context_t *context, char *name)
137 {
138 command_t *c, *p = NULL, *c2;
139
140 if ((!context) || (!name))
141 return ERROR_INVALID_ARGUMENTS;
142
143 /* find command */
144 for (c = context->commands; c; c = c->next)
145 {
146 if (strcmp(name, c->name) == 0)
147 {
148 /* unlink command */
149 if (p)
150 {
151 p->next = c->next;
152 }
153 else
154 {
155 context->commands = c->next;
156 }
157
158 /* unregister children */
159 if (c->children)
160 {
161 for (c2 = c->children; c2; c2 = c2->next)
162 {
163 free(c2->name);
164 if (c2->help)
165 free(c2->help);
166 free(c2);
167 }
168 }
169
170 /* delete command */
171 free(c->name);
172 if (c->help)
173 free(c->help);
174 free(c);
175 }
176
177 /* remember the last command for unlinking */
178 p = c;
179 }
180
181 return ERROR_OK;
182 }
183
184 int parse_line(char *line, char *words[], int max_words)
185 {
186 int nwords = 0;
187 char *p = line;
188 char *word_start = line;
189 int inquote = 0;
190
191 while (nwords < max_words - 1)
192 {
193 /* check if we reached
194 * a terminating NUL
195 * a matching closing quote character " or '
196 * we're inside a word but not a quote, and the current character is whitespace
197 */
198 if (!*p || *p == inquote || (word_start && !inquote && isspace(*p)))
199 {
200 /* we're inside a word or quote, and reached its end*/
201 if (word_start)
202 {
203 int len;
204 char *word_end=p;
205 /* This will handle extra whitespace within quotes */
206 while (isspace(*word_start)&&(word_start<word_end))
207 word_start++;
208 while (isspace(*(word_end-1))&&(word_start<word_end))
209 word_end--;
210
211 len = word_end - word_start;
212
213 if (len>0)
214 {
215 /* copy the word */
216 memcpy(words[nwords] = malloc(len + 1), word_start, len);
217 /* add terminating NUL */
218 words[nwords++][len] = 0;
219 }
220 }
221
222 /* we're done parsing the line */
223 if (!*p)
224 break;
225
226 /* skip over trailing quote or whitespace*/
227 if (inquote || isspace(*p))
228 p++;
229 while (isspace(*p))
230 p++;
231
232 inquote = 0;
233 word_start = 0;
234 }
235 else if (*p == '"' || *p == '\'')
236 {
237 /* we've reached the beginning of a quote */
238 inquote = *p++;
239 word_start = p;
240 }
241 else
242 {
243 /* we've reached the beginning of a new word */
244 if (!word_start)
245 word_start = p;
246
247 /* normal character, skip */
248 p++;
249 }
250 }
251
252 return nwords;
253 }
254
255 void command_print(command_context_t *context, char *format, ...)
256 {
257 va_list ap;
258 char *buffer = NULL;
259 int n, size = 0;
260 char *p;
261
262 va_start(ap, format);
263
264 /* process format string */
265 /* TODO: possible bug. va_list is undefined after the first call to vsnprintf */
266 while (!buffer || (n = vsnprintf(buffer, size, format, ap)) >= size)
267 {
268 /* increase buffer until it fits the whole string */
269 if (!(p = realloc(buffer, size += 4096)))
270 return;
271
272 buffer = p;
273 }
274
275 /* vsnprintf failed */
276 if (n < 0)
277 return;
278
279 p = buffer;
280
281 /* process lines in buffer */
282 do {
283 char *next = strchr(p, '\n');
284
285 if (next)
286 *next++ = 0;
287
288 if (context->output_handler)
289 context->output_handler(context, p);
290
291 p = next;
292 } while (p);
293
294 if (buffer)
295 free(buffer);
296
297 va_end(ap);
298 }
299
300 int find_and_run_command(command_context_t *context, command_t *commands, char *words[], int num_words, int start_word)
301 {
302 command_t *c;
303
304 for (c = commands; c; c = c->next)
305 {
306 if (strncasecmp(c->name, words[start_word], c->unique_len))
307 continue;
308
309 if (strncasecmp(c->name, words[start_word], strlen(words[start_word])))
310 continue;
311
312 if ((c->mode == context->mode) || (c->mode == COMMAND_ANY))
313 {
314 if (!c->children)
315 {
316 if (!c->handler)
317 {
318 command_print(context, "No handler for command");
319 break;
320 }
321 else
322 {
323 return c->handler(context, c->name, words + start_word + 1, num_words - start_word - 1);
324 }
325 }
326 else
327 {
328 if (start_word == num_words - 1)
329 {
330 command_print(context, "Incomplete command");
331 break;
332 }
333 return find_and_run_command(context, c->children, words, num_words, start_word + 1);
334 }
335 }
336 }
337
338 command_print(context, "Command %s not found", words[start_word]);
339 return ERROR_OK;
340 }
341
342 int command_run_line(command_context_t *context, char *line)
343 {
344 int nwords;
345 char *words[128] = {0};
346 int retval;
347 int i;
348
349 if ((!context) || (!line))
350 return ERROR_INVALID_ARGUMENTS;
351
352 /* skip preceding whitespace */
353 while (isspace(*line))
354 line++;
355
356 /* empty line, ignore */
357 if (!*line)
358 return ERROR_OK;
359
360 /* ignore comments */
361 if (*line && (line[0] == '#'))
362 return ERROR_OK;
363
364 if (context->echo)
365 {
366 command_print(context, "%s", line);
367 }
368
369 nwords = parse_line(line, words, sizeof(words) / sizeof(words[0]));
370
371 if (nwords > 0)
372 retval = find_and_run_command(context, context->commands, words, nwords, 0);
373 else
374 return ERROR_INVALID_ARGUMENTS;
375
376 for (i = 0; i < nwords; i++)
377 free(words[i]);
378
379 return retval;
380 }
381
382 int command_run_file(command_context_t *context, FILE *file, enum command_mode mode)
383 {
384 int retval = ERROR_OK;
385 int old_command_mode;
386 char buffer[4096];
387
388 old_command_mode = context->mode;
389 context->mode = mode;
390
391 while (fgets(buffer, 4096, file))
392 {
393 char *p;
394 char *cmd, *end;
395
396 /* stop processing line after a comment (#, !) or a LF, CR were encountered */
397 if ((p = strpbrk(buffer, "#!\r\n")))
398 *p = 0;
399
400 /* skip over leading whitespace */
401 cmd = buffer;
402 while (isspace(*cmd))
403 cmd++;
404
405 /* empty (all whitespace) line? */
406 if (!*cmd)
407 continue;
408
409 /* search the end of the current line, ignore trailing whitespace */
410 for (p = end = cmd; *p; p++)
411 if (!isspace(*p))
412 end = p;
413
414 /* terminate end */
415 *++end = 0;
416 if (strcasecmp(cmd, "quit") == 0)
417 break;
418
419 /* run line */
420 if ((retval = command_run_line(context, cmd)) == ERROR_COMMAND_CLOSE_CONNECTION)
421 break;
422 }
423
424 context->mode = old_command_mode;
425
426 return retval;
427 }
428
429 void command_print_help_line(command_context_t* context, struct command_s *command, int indent)
430 {
431 command_t *c;
432 char indents[32] = {0};
433 char *help = "no help available";
434 char name_buf[64];
435 int i;
436
437 for (i = 0; i < indent; i+=2)
438 {
439 indents[i*2] = ' ';
440 indents[i*2+1] = '-';
441 }
442 indents[i*2] = 0;
443
444 if ((command->mode == COMMAND_EXEC) || (command->mode == COMMAND_ANY))
445 {
446 if (command->help)
447 help = command->help;
448
449 snprintf(name_buf, 64, command->name);
450 strncat(name_buf, indents, 64);
451 command_print(context, "%20s\t%s", name_buf, help);
452 }
453
454 if (command->children)
455 {
456 for (c = command->children; c; c = c->next)
457 {
458 command_print_help_line(context, c, indent + 1);
459 }
460 }
461 }
462
463 int command_print_help(command_context_t* context, char* name, char** args, int argc)
464 {
465 command_t *c;
466
467 for (c = context->commands; c; c = c->next)
468 {
469 if (argc == 1)
470 {
471 if (strncasecmp(c->name, args[0], c->unique_len))
472 continue;
473
474 if (strncasecmp(c->name, args[0], strlen(args[0])))
475 continue;
476 }
477
478 command_print_help_line(context, c, 0);
479 }
480
481 return ERROR_OK;
482 }
483
484 void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, char* line), void *priv)
485 {
486 context->output_handler = output_handler;
487 context->output_handler_priv = priv;
488 }
489
490 command_context_t* copy_command_context(command_context_t* context)
491 {
492 command_context_t* copy_context = malloc(sizeof(command_context_t));
493
494 *copy_context = *context;
495
496 return copy_context;
497 }
498
499 int command_done(command_context_t *context)
500 {
501 free(context);
502
503 return ERROR_OK;
504 }
505
506 command_context_t* command_init()
507 {
508 command_context_t* context = malloc(sizeof(command_context_t));
509
510 context->mode = COMMAND_EXEC;
511 context->commands = NULL;
512 context->current_target = 0;
513 context->echo = 0;
514 context->output_handler = NULL;
515 context->output_handler_priv = NULL;
516
517 register_command(context, NULL, "help", command_print_help,
518 COMMAND_EXEC, "display this help");
519
520 register_command(context, NULL, "sleep", handle_sleep_command,
521 COMMAND_ANY, "sleep for <n> milliseconds");
522
523 return context;
524 }
525
526 /* sleep command sleeps for <n> miliseconds
527 * this is useful in target startup scripts
528 */
529 int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
530 {
531 unsigned long duration = 0;
532
533 if (argc == 1)
534 {
535 duration = strtoul(args[0], NULL, 0);
536 usleep(duration * 1000);
537 }
538
539 return ERROR_OK;
540 }

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)