]> git.sur5r.net Git - openocd/blob - src/helper/command.c
- retired variable stuff.
[openocd] / 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 }