- Fixed bug in pathmove for XScale
[fw/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
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 }