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

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)