|
Packit |
b802ec |
/*
|
|
Packit |
b802ec |
mtr -- a network diagnostic tool
|
|
Packit |
b802ec |
Copyright (C) 2016 Matt Kimball
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
This program is free software; you can redistribute it and/or modify
|
|
Packit |
b802ec |
it under the terms of the GNU General Public License version 2 as
|
|
Packit |
b802ec |
published by the Free Software Foundation.
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
This program is distributed in the hope that it will be useful,
|
|
Packit |
b802ec |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
b802ec |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
b802ec |
GNU General Public License for more details.
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
You should have received a copy of the GNU General Public License
|
|
Packit |
b802ec |
along with this program; if not, write to the Free Software
|
|
Packit |
b802ec |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
Packit |
b802ec |
*/
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
#include "cmdparse.h"
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
#include <ctype.h>
|
|
Packit |
b802ec |
#include <errno.h>
|
|
Packit |
b802ec |
#include <stdlib.h>
|
|
Packit |
b802ec |
#include <string.h>
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
/*
|
|
Packit |
b802ec |
NUL terminate the whitespace separated tokens in the command string.
|
|
Packit |
b802ec |
This modifies command_string in-place with NUL characters.
|
|
Packit |
b802ec |
Fill the tokens array with pointers to the tokens, and return the
|
|
Packit |
b802ec |
number of tokens found.
|
|
Packit |
b802ec |
*/
|
|
Packit |
b802ec |
static
|
|
Packit |
b802ec |
int tokenize_command(
|
|
Packit |
b802ec |
char **tokens,
|
|
Packit |
b802ec |
int max_tokens,
|
|
Packit |
b802ec |
char *command_string)
|
|
Packit |
b802ec |
{
|
|
Packit |
b802ec |
int token_count = 0;
|
|
Packit |
b802ec |
int on_space = 1;
|
|
Packit |
b802ec |
int i;
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
for (i = 0; command_string[i]; i++) {
|
|
Packit |
b802ec |
if (on_space) {
|
|
Packit |
b802ec |
if (!isspace((unsigned char) command_string[i])) {
|
|
Packit |
b802ec |
/* Take care not to exceed the token array length */
|
|
Packit |
b802ec |
if (token_count >= max_tokens) {
|
|
Packit |
b802ec |
return -1;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
tokens[token_count++] = &command_string[i];
|
|
Packit |
b802ec |
on_space = 0;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
} else {
|
|
Packit |
b802ec |
if (isspace((unsigned char) command_string[i])) {
|
|
Packit |
b802ec |
command_string[i] = 0;
|
|
Packit |
b802ec |
on_space = 1;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
return token_count;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
/*
|
|
Packit |
b802ec |
Parse a command string (or command reply string) into a command_t
|
|
Packit |
b802ec |
structure for later semantic interpretation. Returns EINVAL if the
|
|
Packit |
b802ec |
command string is unparseable or zero for success.
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
comamnd_string will be modified in-place with NUL characters terminating
|
|
Packit |
b802ec |
tokens, and the command_t will use pointers to the conents of
|
|
Packit |
b802ec |
command_string without copying, so any interpretation of the
|
|
Packit |
b802ec |
command_t structure requires that the command_string memory has not yet
|
|
Packit |
b802ec |
been freed or otherwise reused.
|
|
Packit |
b802ec |
*/
|
|
Packit |
b802ec |
int parse_command(
|
|
Packit |
b802ec |
struct command_t *command,
|
|
Packit |
b802ec |
char *command_string)
|
|
Packit |
b802ec |
{
|
|
Packit |
b802ec |
char *tokens[MAX_COMMAND_TOKENS];
|
|
Packit |
b802ec |
int token_count;
|
|
Packit |
b802ec |
int i;
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
memset(command, 0, sizeof(struct command_t));
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
/* Tokenize the string using whitespace */
|
|
Packit |
b802ec |
token_count =
|
|
Packit |
b802ec |
tokenize_command(tokens, MAX_COMMAND_TOKENS, command_string);
|
|
Packit |
b802ec |
if (token_count < 2) {
|
|
Packit |
b802ec |
errno = EINVAL;
|
|
Packit |
b802ec |
return -1;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
/* Expect the command token to be a numerical value */
|
|
Packit |
b802ec |
errno = 0;
|
|
Packit |
b802ec |
command->token = strtol(tokens[0], NULL, 10);
|
|
Packit |
b802ec |
if (errno) {
|
|
Packit |
b802ec |
errno = EINVAL;
|
|
Packit |
b802ec |
return -1;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
command->command_name = tokens[1];
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
/*
|
|
Packit |
b802ec |
The tokens beyond the command name are expected to be in
|
|
Packit |
b802ec |
name, value pairs.
|
|
Packit |
b802ec |
*/
|
|
Packit |
b802ec |
i = 2;
|
|
Packit |
b802ec |
command->argument_count = 0;
|
|
Packit |
b802ec |
while (i < token_count) {
|
|
Packit |
b802ec |
/* It's an error if we get a name without a key */
|
|
Packit |
b802ec |
if (i + 1 >= token_count) {
|
|
Packit |
b802ec |
errno = EINVAL;
|
|
Packit |
b802ec |
return -1;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
/* It's an error if we get more arguments than we have space for */
|
|
Packit |
b802ec |
if (command->argument_count >= MAX_COMMAND_ARGUMENTS) {
|
|
Packit |
b802ec |
errno = EINVAL;
|
|
Packit |
b802ec |
return -1;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
command->argument_name[command->argument_count] = tokens[i];
|
|
Packit |
b802ec |
command->argument_value[command->argument_count] = tokens[i + 1];
|
|
Packit |
b802ec |
command->argument_count++;
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
i += 2;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
return 0;
|
|
Packit |
b802ec |
}
|