summaryrefslogtreecommitdiffstats
path: root/src/bin/perfdhcp/tests/command_options_helper.h
blob: 7469076f362edf80efffe15163827fcf9fd32445 (plain)
1
2
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
130
131
132
133
134
135
// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef COMMAND_OPTIONS_HELPER_H
#define COMMAND_OPTIONS_HELPER_H

#include "../command_options.h"
#include <exceptions/exceptions.h>

#include <assert.h>
#include <iterator>
#include <cstring>
#include <string>
#include <vector>


namespace isc {
namespace perfdhcp {

/// \brief Command Options Helper class.
///
/// This helper class can be shared between unit tests that
/// need to initialize CommandOptions objects and feed it with
/// specific command line. The command line can be given as a
/// string representing program name, options and arguments.
/// The static method exposed by this class can be used to
/// tokenize this string into array of C-strings that are later
/// consumed by \ref CommandOptions::parse. The state of the
/// CommandOptions object is reset every time the process
/// function is invoked. Also, when command line parsing is
/// ended the array of C-string is freed from the memory.
class CommandOptionsHelper {
public:

    /// \brief Wrapper class for allocated argv[] array.
    ///
    /// This class wraps allocated char** array and ensures that memory
    /// allocated for this array is freed at the end o the scope.
    class ArgvPtr {
    public:
        /// \brief Constructor.
        ///
        /// \param argv array of C-strings.
        /// \param number of C-strings in the array.
        ArgvPtr(char** argv, int argc) : argv_(argv), argc_(argc) { }

        /// \brief Destructor.
        ///
        /// Deallocates wrapped array of C-strings.
        ~ArgvPtr() {
            if (argv_ != NULL) {
                for(int i = 0; i < argc_; ++i) {
                    delete[] (argv_[i]);
                    argv_[i] = NULL;
                }
                delete[] (argv_);
            }
        }

        /// \brief Return the array of C-strings.
        ///
        /// \return array of C-strings.
        char** getArgv() const { return (argv_); }

        /// \brief Return C-strings counter.
        ///
        /// \return C-strings counter.
        int getArgc() const { return(argc_); }

    public:
        char** argv_; ///< array of C-strings being wrapped.
        int argc_;    ///< number of C-strings.
    };

    /// \brief Parse command line provided as string.
    ///
    /// Method transforms the string representing command line
    /// to the array of C-strings consumed by the
    /// \ref CommandOptions::parse function and performs
    /// parsing.
    ///
    /// \param cmdline command line provided as single string.
    /// \return true if program has been run in help or version mode ('h' or 'v' flag).
    static bool process(const std::string& cmdline) {
        CommandOptions& opt = CommandOptions::instance();
        int argc = 0;
        char** argv = tokenizeString(cmdline, argc);
        ArgvPtr args(argv, argc);
        opt.reset();
        return (opt.parse(args.getArgc(), args.getArgv()));
    }

private:

    /// \brief Split string to the array of C-strings.
    ///
    /// \param text_to_split string to be split.
    /// \param [out] num number of substrings returned.
    /// \param std::bad_alloc if allocation of C-strings failed.
    /// \return array of C-strings created from split.
    static char** tokenizeString(const std::string& text_to_split, int& num) {
        char** results = NULL;
        // Tokenization with std streams
        std::stringstream text_stream(text_to_split);
        // Iterators to be used for tokenization
        std::istream_iterator<std::string> text_iterator(text_stream);
        std::istream_iterator<std::string> text_end;
        // Tokenize string (space is a separator) using begin and end iterators
        std::vector<std::string> tokens(text_iterator, text_end);

        if (!tokens.empty()) {
            // Allocate array of C-strings where we will store tokens
            results = new char*[tokens.size()];
            // Store tokens in C-strings array
            for (size_t i = 0; i < tokens.size(); ++i) {
                size_t cs_size = tokens[i].length() + 1;
                char* cs = new char[cs_size];
                strncpy(cs, tokens[i].c_str(), cs_size);
                assert(cs[cs_size - 1] == '\0');
                results[i] = cs;
            }
            // Return number of tokens to calling function
            num = tokens.size();
        }
        return results;
    }
};

} // namespace isc::perfdhcp
} // namespace isc

#endif // COMMAND_OPTIONS_HELPER_H