- added patch for new flash functionality like:
[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=malloc(4096);
387 if (buffer==NULL)
388 {
389 return ERROR_INVALID_ARGUMENTS;
390 }
391
392 old_command_mode = context->mode;
393 context->mode = mode;
394
395 while (fgets(buffer, 4096, file))
396 {
397 char *p;
398 char *cmd, *end;
399
400 /* stop processing line after a comment (#, !) or a LF, CR were encountered */
401 if ((p = strpbrk(buffer, "#!\r\n")))
402 *p = 0;
403
404 /* skip over leading whitespace */
405 cmd = buffer;
406 while (isspace(*cmd))
407 cmd++;
408
409 /* empty (all whitespace) line? */
410 if (!*cmd)
411 continue;
412
413 /* search the end of the current line, ignore trailing whitespace */
414 for (p = end = cmd; *p; p++)
415 if (!isspace(*p))
416 end = p;
417
418 /* terminate end */
419 *++end = 0;
420 if (strcasecmp(cmd, "quit") == 0)
421 break;
422
423 /* run line */
424 if ((retval = command_run_line(context, cmd)) == ERROR_COMMAND_CLOSE_CONNECTION)
425 break;
426 }
427
428 context->mode = old_command_mode;
429
430
431 free(buffer);
432
433 return retval;
434 }
435
436 void command_print_help_line(command_context_t* context, struct command_s *command, int indent)
437 {
438 command_t *c;
439 char indents[32] = {0};
440 char *help = "no help available";
441 char name_buf[64];
442 int i;
443
444 for (i = 0; i < indent; i+=2)
445 {
446 indents[i*2] = ' ';
447 indents[i*2+1] = '-';
448 }
449 indents[i*2] = 0;
450
451 if ((command->mode == COMMAND_EXEC) || (command->mode == COMMAND_ANY))
452 {
453 if (command->help)
454 help = command->help;
455
456 snprintf(name_buf, 64, command->name);
457 strncat(name_buf, indents, 64);
458 command_print(context, "%20s\t%s", name_buf, help);
459 }
460
461 if (command->children)
462 {
463 for (c = command->children; c; c = c->next)
464 {
465 command_print_help_line(context, c, indent + 1);
466 }
467 }
468 }
469
470 int command_print_help(command_context_t* context, char* name, char** args, int argc)
471 {
472 command_t *c;
473
474 for (c = context->commands; c; c = c->next)
475 {
476 if (argc == 1)
477 {
478 if (strncasecmp(c->name, args[0], c->unique_len))
479 continue;
480
481 if (strncasecmp(c->name, args[0], strlen(args[0])))
482 continue;
483 }
484
485 command_print_help_line(context, c, 0);
486 }
487
488 return ERROR_OK;
489 }
490
491 void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, char* line), void *priv)
492 {
493 context->output_handler = output_handler;
494 context->output_handler_priv = priv;
495 }
496
497 command_context_t* copy_command_context(command_context_t* context)
498 {
499 command_context_t* copy_context = malloc(sizeof(command_context_t));
500
501 *copy_context = *context;
502
503 return copy_context;
504 }
505
506 int command_done(command_context_t *context)
507 {
508 free(context);
509 context = NULL;
510
511 return ERROR_OK;
512 }
513
514 command_context_t* command_init()
515 {
516 command_context_t* context = malloc(sizeof(command_context_t));
517
518 context->mode = COMMAND_EXEC;
519 context->commands = NULL;
520 context->current_target = 0;
521 context->echo = 0;
522 context->output_handler = NULL;
523 context->output_handler_priv = NULL;
524
525 register_command(context, NULL, "help", command_print_help,
526 COMMAND_EXEC, "display this help");
527
528 register_command(context, NULL, "sleep", handle_sleep_command,
529 COMMAND_ANY, "sleep for <n> milliseconds");
530
531 return context;
532 }
533
534 /* sleep command sleeps for <n> miliseconds
535 * this is useful in target startup scripts
536 */
537 int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
538 {
539 unsigned long duration = 0;
540
541 if (argc == 1)
542 {
543 duration = strtoul(args[0], NULL, 0);
544 usleep(duration * 1000);
545 }
546
547 return ERROR_OK;
548 }

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)