Visual Servoing Platform version 3.6.0
Loading...
Searching...
No Matches
vpJsonArgumentParser.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2023 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#include <visp3/io/vpJsonArgumentParser.h>
31#include <visp3/core/vpException.h>
32#include <visp3/core/vpConfig.h>
33#include <fstream>
34
35
36#if defined(VISP_HAVE_NLOHMANN_JSON)
37
38using json = nlohmann::json;
39
40
41vpJsonArgumentParser::vpJsonArgumentParser(const std::string &description, const std::string &jsonFileArgumentName,
42 const std::string &nestSeparator) :
43 description(description),
44 jsonFileArgumentName(jsonFileArgumentName),
45 nestSeparator(nestSeparator)
46{
47 if (jsonFileArgumentName.empty()) {
48 throw vpException(vpException::badValue, "The JSON file argument must not be empty");
49 }
50
51 if (nestSeparator.empty()) {
52 throw vpException(vpException::badValue, "You must provide a JSON nesting delimiter to be able to parse JSON");
53 }
54
55 helpers[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
60std::string vpJsonArgumentParser::help() const
61{
62 std::stringstream ss;
63
64 ss << "Program description: " << description << std::endl;
65 ss << "Arguments: " << std::endl;
66 unsigned spacesBetweenArgAndDescription = 0;
67 for (const auto &helper : 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 : 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 << exampleJson.dump(2) << std::endl;
94 return ss.str();
95}
96
97
98void vpJsonArgumentParser::parse(int argc, const char *argv [])
99{
100 json j;
101 const std::vector<std::string> arguments(argv + 1, argv + argc);
102 std::vector<unsigned> ignoredArguments;
103 const auto jsonFileArgumentPos = std::find(arguments.begin(), arguments.end(), jsonFileArgumentName);
104 // Load JSON file if present
105 if (jsonFileArgumentPos != arguments.end()) {
106 ignoredArguments.push_back(static_cast<unsigned>(jsonFileArgumentPos - arguments.begin() + 1));
107 ignoredArguments.push_back(static_cast<unsigned>(jsonFileArgumentPos - arguments.begin() + 2));
108
109 if (jsonFileArgumentPos == arguments.end() - 1) {
110 throw vpException(vpException::ioError, "No JSON file was provided");
111 }
112 const std::string jsonFileName = *(jsonFileArgumentPos + 1);
113 std::ifstream jsonFile(jsonFileName);
114 if (!jsonFile.good()) {
115 std::stringstream ss;
116 ss << "Could not open JSON file " << jsonFileName << "! Make sure it exists and is readable" << std::endl;
117 throw vpException(vpException::ioError, ss.str());
118 }
119 j = json::parse(jsonFile);
120 jsonFile.close();
121 }
122 // Parse command line arguments
123 for (int i = 1; i < argc; ++i) {
124 const std::string arg = argv[i];
125 if (std::find(ignoredArguments.begin(), ignoredArguments.end(), i) != ignoredArguments.end()) {
126 continue;
127 }
128 if (arg == "-h" || arg == "--help") {
129 std::cout << help() << std::endl;
130 exit(1);
131 }
132
133 if (parsers.find(arg) != parsers.end()) {
134 if (i < argc - 1) {
135 updaters[arg](j, std::string(argv[i + 1]));
136 ++i;
137 }
138 else {
139 std::stringstream ss;
140 ss << "Argument " << arg << " was passed but no value was provided" << std::endl;
141 throw vpException(vpException::ioError, ss.str());
142 }
143 }
144 else {
145 std::cerr << "Unknown parameter when parsing: " << arg << std::endl;
146 }
147 }
148
149 // Get the values from json document and store them in the arguments passed by ref in addArgument
150 for (const auto &parser : parsers) {
151 parser.second(j);
152 }
153}
154
155#endif
error that can be emitted by ViSP classes.
Definition vpException.h:59
@ ioError
I/O error.
Definition vpException.h:79
@ badValue
Used to indicate that a value is not in the allowed range.
Definition vpException.h:85
std::string help() const
Generate a help message, containing the description of the arguments, their default value and whether...
void parse(int argc, const char *argv[])
Parse the arguments.
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...