Visual Servoing Platform
version 3.7.0
Toggle main menu visibility
Loading...
Searching...
No Matches
vpJsonArgumentParser.cpp
1
/*
2
* ViSP, open source Visual Servoing Platform software.
3
* Copyright (C) 2005 - 2025 by Inria. All rights reserved.
4
*
5
* This software is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
9
* See the file LICENSE.txt at the root directory of this source
10
* distribution for additional information about the GNU GPL.
11
*
12
* For using ViSP with software that can not be combined with the GNU
13
* GPL, please contact Inria about acquiring a ViSP Professional
14
* Edition License.
15
*
16
* See https://visp.inria.fr for more information.
17
*
18
* This software was developed at:
19
* Inria Rennes - Bretagne Atlantique
20
* Campus Universitaire de Beaulieu
21
* 35042 Rennes Cedex
22
* France
23
*
24
* If you have questions regarding the use of this file, please contact
25
* Inria at visp@inria.fr
26
*
27
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28
* WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29
*/
30
31
#include <visp3/core/vpConfig.h>
32
#include <visp3/io/vpJsonArgumentParser.h>
33
#include <visp3/core/vpException.h>
34
#include <fstream>
35
36
#if defined(VISP_HAVE_NLOHMANN_JSON)
37
BEGIN_VISP_NAMESPACE
38
39
using
json = nlohmann::json;
40
41
vpJsonArgumentParser::vpJsonArgumentParser
(
const
std::string &description,
const
std::string &jsonFileArgumentName,
42
const
std::string &nestSeparator) :
43
m_description(description),
44
m_jsonFileArgumentName(jsonFileArgumentName),
45
m_nestSeparator(nestSeparator)
46
{
47
if
(m_jsonFileArgumentName.empty()) {
48
throw vpException(vpException::badValue,
"The JSON file argument must not be empty"
);
49
}
50
51
if (m_nestSeparator.empty()) {
52
throw vpException(vpException::badValue,
"You must provide a JSON nesting delimiter to be able to parse JSON"
);
53
}
54
55
m_helpers[m_jsonFileArgumentName] = []() -> std::string {
56
return
"Path to the JSON configuration file. Values in this files are loaded, and can be overridden by command line arguments.\nOptional"
;
57
};
58
}
59
60
std::string
vpJsonArgumentParser::help
()
const
61
{
62
std::stringstream ss;
63
64
ss <<
"Program description: "
<< m_description << std::endl;
65
ss <<
"Arguments: "
<< std::endl;
66
unsigned
spacesBetweenArgAndDescription = 0;
67
for
(
const
auto
&helper : m_helpers) {
68
if
(helper.first.size() > spacesBetweenArgAndDescription) {
69
spacesBetweenArgAndDescription =
static_cast<
unsigned
int
>
(helper.first.size());
70
}
71
}
72
spacesBetweenArgAndDescription += 4;
73
74
for
(
const
auto
&helper : m_helpers) {
75
std::stringstream argss(helper.second());
76
std::string line;
77
bool
first =
true
;
78
while
(getline(argss, line,
'\n'
)) {
79
const
unsigned
lineSpace = first ? spacesBetweenArgAndDescription -
static_cast<
unsigned
>
(helper.first.size()) : spacesBetweenArgAndDescription;
80
const
std::string spaceBetweenArgAndDescription(lineSpace,
' '
);
81
if
(first) {
82
ss <<
"\t"
<< helper.first << spaceBetweenArgAndDescription << line << std::endl;
83
}
84
else
{
85
ss <<
"\t"
<< spaceBetweenArgAndDescription << line << std::endl;
86
}
87
first =
false
;
88
89
}
90
ss << std::endl;
91
}
92
ss <<
"Example JSON configuration file: "
<< std::endl << std::endl;
93
ss << m_exampleJson.dump(2) << std::endl;
94
return
ss.str();
95
}
96
97
vpJsonArgumentParser
&
vpJsonArgumentParser::addFlag
(
const
std::string &name,
bool
¶meter,
const
std::string &
help
)
98
{
99
m_argumentType[name] =
FLAG
;
100
const
auto
getter = [name,
this
](nlohmann::json &j,
bool
create) -> nlohmann::json * {
101
size_t
pos = 0;
102
nlohmann::json *f = &j;
103
std::string token;
104
std::string name_copy = name;
105
106
while
((pos = name_copy.find(m_nestSeparator)) != std::string::npos) {
107
token = name_copy.substr(0, pos);
108
109
name_copy.erase(0, pos + m_nestSeparator.length());
110
if
(create && !f->contains(token)) {
111
(*f)[token] = {};
112
}
113
else
if
(!f->contains(token)) {
114
return
nullptr
;
115
}
116
f = &(f->at(token));
117
}
118
if
(create && !f->contains(name_copy)) {
119
(*f)[name_copy] = {};
120
}
121
else
if
(!f->contains(name_copy)) {
122
return
nullptr
;
123
}
124
f = &(f->at(name_copy));
125
return
f;
126
};
127
128
m_parsers[name] = [¶meter, getter, name](nlohmann::json &j) {
129
const
nlohmann::json *field = getter(j,
false
);
130
const
bool
fieldHasNoValue = ((field ==
nullptr
) || (field !=
nullptr
&& field->is_null()));
131
if
(!fieldHasNoValue && (field->type() == json::value_t::boolean && (*field) ==
true
)) {
132
parameter = !parameter;
133
}
134
};
135
136
m_updaters[name] = [getter](nlohmann::json &j,
const
std::string &) {
137
nlohmann::json *field = getter(j,
true
);
138
*field =
true
;
139
};
140
141
m_helpers[name] = [
help
, parameter]() -> std::string {
142
std::stringstream ss;
143
nlohmann::json repr = parameter;
144
ss <<
help
<< std::endl <<
"Default: "
<< repr;
145
return
ss.str();
146
};
147
148
nlohmann::json *exampleField = getter(m_exampleJson,
true
);
149
*exampleField = parameter;
150
151
return
*
this
;
152
}
153
154
bool
vpJsonArgumentParser::parse
(
int
argc,
const
char
*argv[])
155
{
156
json j;
157
const
std::vector<std::string> arguments(argv + 1, argv + argc);
158
std::vector<unsigned> ignoredArguments;
159
const
auto
jsonFileArgumentPos = std::find(arguments.begin(), arguments.end(), m_jsonFileArgumentName);
160
// Load JSON file if present
161
if
(jsonFileArgumentPos != arguments.end()) {
162
ignoredArguments.push_back(
static_cast<
unsigned
>
(jsonFileArgumentPos - arguments.begin() + 1));
163
ignoredArguments.push_back(
static_cast<
unsigned
>
(jsonFileArgumentPos - arguments.begin() + 2));
164
165
if
(jsonFileArgumentPos == arguments.end() - 1) {
166
throw
vpException
(
vpException::ioError
,
"No JSON file was provided"
);
167
}
168
const
std::string jsonFileName = *(jsonFileArgumentPos + 1);
169
std::ifstream jsonFile(jsonFileName);
170
if
(!jsonFile.good()) {
171
std::stringstream ss;
172
ss <<
"Could not open JSON file "
<< jsonFileName <<
"! Make sure it exists and is readable"
<< std::endl;
173
throw
vpException
(
vpException::ioError
, ss.str());
174
}
175
j = json::parse(jsonFile);
176
jsonFile.close();
177
}
178
// Parse command line arguments
179
for
(
int
i = 1; i < argc; ++i) {
180
const
std::string arg = argv[i];
181
bool
stop_for_loop =
false
;
182
if
(std::find(ignoredArguments.begin(), ignoredArguments.end(), i) != ignoredArguments.end()) {
183
stop_for_loop =
true
;
184
}
185
if
(!stop_for_loop) {
186
if
(arg ==
"-h"
|| arg ==
"--help"
) {
187
std::cout <<
help
() << std::endl;
188
return
false
;
189
}
190
191
if
(m_parsers.find(arg) != m_parsers.end()) {
192
if
(m_argumentType[arg] ==
WITH_FIELD
) {
193
if
(i < argc - 1) {
194
m_updaters[arg](j, std::string(argv[i + 1]));
195
++i;
196
}
197
else
{
198
std::stringstream ss;
199
ss <<
"Argument "
<< arg <<
" was passed but no value was provided"
<< std::endl;
200
throw
vpException
(
vpException::ioError
, ss.str());
201
}
202
}
203
else
if
(m_argumentType[arg] ==
FLAG
) {
204
m_updaters[arg](j, std::string());
205
}
206
}
207
else
{
208
std::cerr <<
"Unknown parameter when parsing: "
<< arg << std::endl;
209
}
210
}
211
}
212
213
// Get the values from json document and store them in the arguments passed by ref in addArgument
214
for
(
const
auto
&parser : m_parsers) {
215
parser.second(j);
216
}
217
218
return
true
;
219
}
220
221
END_VISP_NAMESPACE
222
223
#endif
vpException
error that can be emitted by ViSP classes.
Definition
vpException.h:60
vpException::ioError
@ ioError
I/O error.
Definition
vpException.h:67
vpJsonArgumentParser::help
std::string help() const
Generate a help message, containing the description of the arguments, their default value and whether...
Definition
vpJsonArgumentParser.cpp:60
vpJsonArgumentParser::parse
bool parse(int argc, const char *argv[])
Parse command line arguments and load values into the provided parameters.
Definition
vpJsonArgumentParser.cpp:154
vpJsonArgumentParser::vpJsonArgumentParser
vpJsonArgumentParser(const std::string &description, const std::string &jsonFileArgumentName, const std::string &nestSeparator)
Create a new argument parser, that can take into account both a JSON configuration file and command l...
Definition
vpJsonArgumentParser.cpp:41
vpJsonArgumentParser::addFlag
vpJsonArgumentParser & addFlag(const std::string &name, bool ¶meter, const std::string &help="No description")
Add an argument that acts as a flag when specified on the command line. When this flag is specified,...
Definition
vpJsonArgumentParser.cpp:97
vpJsonArgumentParser::FLAG
@ FLAG
Definition
vpJsonArgumentParser.h:144
vpJsonArgumentParser::WITH_FIELD
@ WITH_FIELD
Definition
vpJsonArgumentParser.h:143
BEGIN_VISP_NAMESPACE
Definition
vpMbtDistanceCircle.cpp:55
modules
io
src
tools
vpJsonArgumentParser.cpp
Generated by
1.17.0