1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * part of this file is taken from libcli (libcli.sourceforge.net) *
6 * Copyright (C) David Parrish (david@dparrish.com) *
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. *
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. *
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 ***************************************************************************/
27 #include "replacements.h"
40 int handle_sleep_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
);
42 int build_unique_lengths(command_context_t
*context
, command_t
*commands
)
46 /* iterate through all commands */
47 for (c
= commands
; c
; c
= c
->next
)
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
++)
54 /* for every command, see if the current length is enough */
55 for (p
= commands
; p
; p
= p
->next
)
57 /* ignore the command itself */
61 /* compare commands up to the current length */
62 if (strncmp(p
->name
, c
->name
, c
->unique_len
) == 0)
66 /* when none of the commands matched, we've found the minimum length required */
71 /* if the current command has children, build the unique lengths for them */
73 build_unique_lengths(context
, c
->children
);
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
)
83 if (!context
|| !name
)
86 c
= malloc(sizeof(command_t
));
88 c
->name
= strdup(name
);
94 c
->help
= strdup(help
);
100 /* place command in tree */
103 if (parent
->children
)
105 /* find last child */
106 for (p
= parent
->children
; p
&& p
->next
; p
= p
->next
);
112 parent
->children
= c
;
117 if (context
->commands
)
119 /* find last command */
120 for (p
= context
->commands
; p
&& p
->next
; p
= p
->next
);
126 context
->commands
= c
;
130 /* update unique lengths */
131 build_unique_lengths(context
, (parent
) ? parent
: context
->commands
);
136 int unregister_command(command_context_t
*context
, char *name
)
138 command_t
*c
, *p
= NULL
, *c2
;
140 if ((!context
) || (!name
))
141 return ERROR_INVALID_ARGUMENTS
;
144 for (c
= context
->commands
; c
; c
= c
->next
)
146 if (strcmp(name
, c
->name
) == 0)
155 context
->commands
= c
->next
;
158 /* unregister children */
161 for (c2
= c
->children
; c2
; c2
= c2
->next
)
177 /* remember the last command for unlinking */
184 int parse_line(char *line
, char *words
[], int max_words
)
188 char *word_start
= line
;
191 while (nwords
< max_words
- 1)
193 /* check if we reached
195 * a matching closing quote character " or '
196 * we're inside a word but not a quote, and the current character is whitespace
198 if (!*p
|| *p
== inquote
|| (word_start
&& !inquote
&& isspace(*p
)))
200 /* we're inside a word or quote, and reached its end*/
205 /* This will handle extra whitespace within quotes */
206 while (isspace(*word_start
)&&(word_start
<word_end
))
208 while (isspace(*(word_end
-1))&&(word_start
<word_end
))
211 len
= word_end
- word_start
;
216 memcpy(words
[nwords
] = malloc(len
+ 1), word_start
, len
);
217 /* add terminating NUL */
218 words
[nwords
++][len
] = 0;
222 /* we're done parsing the line */
226 /* skip over trailing quote or whitespace*/
227 if (inquote
|| isspace(*p
))
235 else if (*p
== '"' || *p
== '\'')
237 /* we've reached the beginning of a quote */
243 /* we've reached the beginning of a new word */
247 /* normal character, skip */
255 void command_print(command_context_t
*context
, char *format
, ...)
262 va_start(ap
, format
);
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
)
268 /* increase buffer until it fits the whole string */
269 if (!(p
= realloc(buffer
, size
+= 4096)))
275 /* vsnprintf failed */
281 /* process lines in buffer */
283 char *next
= strchr(p
, '\n');
288 if (context
->output_handler
)
289 context
->output_handler(context
, p
);
300 int find_and_run_command(command_context_t
*context
, command_t
*commands
, char *words
[], int num_words
, int start_word
)
304 for (c
= commands
; c
; c
= c
->next
)
306 if (strncasecmp(c
->name
, words
[start_word
], c
->unique_len
))
309 if (strncasecmp(c
->name
, words
[start_word
], strlen(words
[start_word
])))
312 if ((c
->mode
== context
->mode
) || (c
->mode
== COMMAND_ANY
))
318 command_print(context
, "No handler for command");
323 return c
->handler(context
, c
->name
, words
+ start_word
+ 1, num_words
- start_word
- 1);
328 if (start_word
== num_words
- 1)
330 command_print(context
, "Incomplete command");
333 return find_and_run_command(context
, c
->children
, words
, num_words
, start_word
+ 1);
338 command_print(context
, "Command %s not found", words
[start_word
]);
342 int command_run_line(command_context_t
*context
, char *line
)
345 char *words
[128] = {0};
349 if ((!context
) || (!line
))
350 return ERROR_INVALID_ARGUMENTS
;
352 /* skip preceding whitespace */
353 while (isspace(*line
))
356 /* empty line, ignore */
362 command_print(context
, "%s", line
);
365 nwords
= parse_line(line
, words
, sizeof(words
) / sizeof(words
[0]));
368 retval
= find_and_run_command(context
, context
->commands
, words
, nwords
, 0);
370 return ERROR_INVALID_ARGUMENTS
;
372 for (i
= 0; i
< nwords
; i
++)
378 int command_run_file(command_context_t
*context
, FILE *file
, enum command_mode mode
)
380 int retval
= ERROR_OK
;
381 int old_command_mode
;
384 old_command_mode
= context
->mode
;
385 context
->mode
= mode
;
387 while (fgets(buffer
, 4096, file
))
392 /* stop processing line after a comment (#, !) or a LF, CR were encountered */
393 if ((p
= strpbrk(buffer
, "#!\r\n")))
396 /* skip over leading whitespace */
398 while (isspace(*cmd
))
401 /* empty (all whitespace) line? */
405 /* search the end of the current line, ignore trailing whitespace */
406 for (p
= end
= cmd
; *p
; p
++)
412 if (strcasecmp(cmd
, "quit") == 0)
416 if ((retval
= command_run_line(context
, cmd
)) == ERROR_COMMAND_CLOSE_CONNECTION
)
420 context
->mode
= old_command_mode
;
425 void command_print_help_line(command_context_t
* context
, struct command_s
*command
, int indent
)
428 char indents
[32] = {0};
429 char *help
= "no help available";
433 for (i
= 0; i
< indent
; i
+=2)
436 indents
[i
*2+1] = '-';
440 if ((command
->mode
== COMMAND_EXEC
) || (command
->mode
== COMMAND_ANY
))
443 help
= command
->help
;
445 snprintf(name_buf
, 64, command
->name
);
446 strncat(name_buf
, indents
, 64);
447 command_print(context
, "%20s\t%s", name_buf
, help
);
450 if (command
->children
)
452 for (c
= command
->children
; c
; c
= c
->next
)
454 command_print_help_line(context
, c
, indent
+ 1);
459 int command_print_help(command_context_t
* context
, char* name
, char** args
, int argc
)
463 for (c
= context
->commands
; c
; c
= c
->next
)
467 if (strncasecmp(c
->name
, args
[0], c
->unique_len
))
470 if (strncasecmp(c
->name
, args
[0], strlen(args
[0])))
474 command_print_help_line(context
, c
, 0);
480 void command_set_output_handler(command_context_t
* context
, int (*output_handler
)(struct command_context_s
*context
, char* line
), void *priv
)
482 context
->output_handler
= output_handler
;
483 context
->output_handler_priv
= priv
;
486 command_context_t
* copy_command_context(command_context_t
* context
)
488 command_context_t
* copy_context
= malloc(sizeof(command_context_t
));
490 *copy_context
= *context
;
495 int command_done(command_context_t
*context
)
502 command_context_t
* command_init()
504 command_context_t
* context
= malloc(sizeof(command_context_t
));
506 context
->mode
= COMMAND_EXEC
;
507 context
->commands
= NULL
;
508 context
->current_target
= 0;
510 context
->output_handler
= NULL
;
511 context
->output_handler_priv
= NULL
;
513 register_command(context
, NULL
, "help", command_print_help
,
514 COMMAND_EXEC
, "display this help");
516 register_command(context
, NULL
, "sleep", handle_sleep_command
,
517 COMMAND_ANY
, "sleep for <n> milliseconds");
522 /* sleep command sleeps for <n> miliseconds
523 * this is useful in target startup scripts
525 int handle_sleep_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
527 unsigned long duration
= 0;
531 duration
= strtoul(args
[0], NULL
, 0);
532 usleep(duration
* 1000);