| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 
 | /*
    mtr  --  a network diagnostic tool
    Copyright (C) 2016  Matt Kimball
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License version 2 as
    published by the Free Software Foundation.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "cmdparse.h"
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
/*
    NUL terminate the whitespace separated tokens in the command string.
    This modifies command_string in-place with NUL characters.
    Fill the tokens array with pointers to the tokens, and return the
    number of tokens found.
*/
static
int tokenize_command(
    char **tokens,
    int max_tokens,
    char *command_string)
{
    int token_count = 0;
    int on_space = 1;
    int i;
    for (i = 0; command_string[i]; i++) {
        if (on_space) {
            if (!isspace((unsigned char) command_string[i])) {
                /*  Take care not to exceed the token array length  */
                if (token_count >= max_tokens) {
                    return -1;
                }
                tokens[token_count++] = &command_string[i];
                on_space = 0;
            }
        } else {
            if (isspace((unsigned char) command_string[i])) {
                command_string[i] = 0;
                on_space = 1;
            }
        }
    }
    return token_count;
}
/*
    Parse a command string (or command reply string) into a command_t
    structure for later semantic interpretation.  Returns EINVAL if the
    command string is unparseable or zero for success.
    command_string will be modified in-place with NUL characters terminating
    tokens, and the command_t will use pointers to the contents of
    command_string without copying, so any interpretation of the
    command_t structure requires that the command_string memory has not yet
    been freed or otherwise reused.
*/
int parse_command(
    struct command_t *command,
    char *command_string)
{
    char *tokens[MAX_COMMAND_TOKENS];
    int token_count;
    int i;
    memset(command, 0, sizeof(struct command_t));
    /*  Tokenize the string using whitespace  */
    token_count =
        tokenize_command(tokens, MAX_COMMAND_TOKENS, command_string);
    if (token_count < 2) {
        errno = EINVAL;
        return -1;
    }
    /*  Expect the command token to be a numerical value  */
    errno = 0;
    command->token = strtol(tokens[0], NULL, 10);
    if (errno) {
        errno = EINVAL;
        return -1;
    }
    command->command_name = tokens[1];
    /*
       The tokens beyond the command name are expected to be in
       name, value pairs.
     */
    i = 2;
    command->argument_count = 0;
    while (i < token_count) {
        /*  It's an error if we get a name without a key  */
        if (i + 1 >= token_count) {
            errno = EINVAL;
            return -1;
        }
        /*  It's an error if we get more arguments than we have space for  */
        if (command->argument_count >= MAX_COMMAND_ARGUMENTS) {
            errno = EINVAL;
            return -1;
        }
        command->argument_name[command->argument_count] = tokens[i];
        command->argument_value[command->argument_count] = tokens[i + 1];
        command->argument_count++;
        i += 2;
    }
    return 0;
}
 |