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

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)