Skip to content

Commit 2517c81

Browse files
matthiasrichterktf
authored andcommitted
Argument parsing based on boost program_options
1 parent 6a6b124 commit 2517c81

2 files changed

Lines changed: 119 additions & 63 deletions

File tree

Utilities/aliceHLTwrapper/include/aliceHLTwrapper/Component.h

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
//****************************************************************************
66
//* This file is free software: you can redistribute it and/or modify *
77
//* it under the terms of the GNU General Public License as published by *
8-
//* the Free Software Foundation, either version 3 of the License, or *
9-
//* (at your option) any later version. *
8+
//* the Free Software Foundation, either version 3 of the License, or *
9+
//* (at your option) any later version. *
1010
//* *
1111
//* Primary Authors: Matthias Richter <richterm@scieq.net> *
1212
//* *
@@ -23,9 +23,12 @@
2323
#include "MessageFormat.h"
2424
#include <vector>
2525
#include <boost/signals2.hpp>
26+
#include <boost/program_options.hpp>
2627
//using boost::signals2::signal;
2728
typedef boost::signals2::signal<unsigned char* (unsigned int)> cballoc_signal_t;
2829

30+
namespace bpo = boost::program_options;
31+
2932
namespace ALICE {
3033
namespace HLT {
3134
class SystemInterface;
@@ -66,6 +69,39 @@ class Component {
6669
/// destructor
6770
~Component();
6871

72+
/// get description of options
73+
static bpo::options_description GetOptionsDescription();
74+
75+
// TODO: have been trying to use strongly typed enums, however
76+
// the problem starts with the iteration over all elements (which
77+
// doen't seem to work without specialized coding in the enum class)
78+
// Furthermore, one would need to use a map which can not be used in
79+
// a constexpr because of the non-trivial destructor
80+
// Keep the solution with the simple const char array for the OptionKeys
81+
// and live with the fact that changing the sequence causes a runtime
82+
// error, and a compile time check is not possible
83+
enum /*class*/ OptionKeyIds /*: int*/ {
84+
OptionKeyLibrary = 0,
85+
OptionKeyComponent,
86+
OptionKeyParameter,
87+
OptionKeyRun,
88+
OptionKeyMsgsize,
89+
OptionKeyOutputMode,
90+
OptionKeyInstanceId,
91+
OptionKeyLast
92+
};
93+
94+
constexpr static const char* OptionKeys[] = {
95+
"library",
96+
"component",
97+
"parameter",
98+
"run",
99+
"msgsize",
100+
"output-mode",
101+
"instance-id",
102+
nullptr
103+
};
104+
69105
/// Init the component
70106
int init(int argc, char** argv);
71107

Utilities/aliceHLTwrapper/src/Component.cxx

Lines changed: 81 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//****************************************************************************
22
//* This file is free software: you can redistribute it and/or modify *
33
//* it under the terms of the GNU General Public License as published by *
4-
//* the Free Software Foundation, either version 3 of the License, or *
5-
//* (at your option) any later version. *
4+
//* the Free Software Foundation, either version 3 of the License, or *
5+
//* (at your option) any later version. *
66
//* *
77
//* Primary Authors: Matthias Richter <richterm@scieq.net> *
88
//* *
@@ -22,6 +22,7 @@
2222
#include <cstdlib>
2323
#include <cerrno>
2424
#include <cstring>
25+
#include <sstream>
2526
#include <iostream>
2627
#include <sstream>
2728
#include <getopt.h>
@@ -34,6 +35,7 @@ using std::endl;
3435
using std::string;
3536
using std::unique_ptr;
3637
using std::vector;
38+
using std::stringstream;
3739

3840
Component::Component()
3941
: mOutputBuffer()
@@ -47,78 +49,95 @@ Component::Component()
4749
Component::~Component()
4850
= default;
4951

52+
constexpr const char* Component::OptionKeys[];
53+
54+
bpo::options_description Component::GetOptionsDescription()
55+
{
56+
bpo::options_description od("HLT Component options");
57+
od.add_options()
58+
((std::string(OptionKeys[OptionKeyLibrary]) + ",l").c_str(),
59+
bpo::value<string>()->required(),
60+
"component library")
61+
((std::string(OptionKeys[OptionKeyComponent]) + ",c").c_str(),
62+
bpo::value<string>()->required(),
63+
"component id")
64+
((std::string(OptionKeys[OptionKeyParameter]) + ",p").c_str(),
65+
bpo::value<string>()->default_value(""),
66+
"component command line parameter")
67+
((std::string(OptionKeys[OptionKeyRun]) + ",r").c_str(),
68+
bpo::value<string>()->default_value("-1"),
69+
"run number")
70+
((std::string(OptionKeys[OptionKeyMsgsize]) + ",s").c_str(),
71+
bpo::value<string>()->default_value("0"),
72+
"maximum size of output buffer/msg")
73+
((std::string(OptionKeys[OptionKeyOutputMode]) + ",m").c_str(),
74+
bpo::value<string>()->default_value("2"),
75+
"output mode");
76+
77+
return od;
78+
}
79+
5080
int Component::init(int argc, char** argv)
5181
{
5282
/// initialize: scan arguments, setup system interface and create component
5383

54-
// parse options
55-
static struct option programOptions[] = {
56-
{"library", required_argument, nullptr, 'l'},
57-
{"component", required_argument, nullptr, 'c'},
58-
{"parameter", required_argument, nullptr, 'p'},
59-
{"run", required_argument, nullptr, 'r'},
60-
{"msgsize", required_argument, nullptr, 's'},
61-
{"output-mode", required_argument, nullptr, 'm'},
62-
{"instance-id", required_argument, nullptr, 'i'},
63-
{nullptr, 0, nullptr, 0}
64-
};
65-
66-
/* getopt_long stores the option index here. */
67-
char c = 0;
68-
int iOption = 0;
84+
// the hidden options are not exposed to the outside
85+
bpo::options_description od("component options");
86+
od.add_options()
87+
(OptionKeys[OptionKeyInstanceId],
88+
bpo::value<string>()->required(),
89+
"internal instance id");
90+
// now add all the visible options
91+
od.add(GetOptionsDescription());
6992

7093
// HLT components are implemented in shared libraries, the library name
7194
// and component id are used to factorize a component
7295
// optionally, a list of configuration parameters can be specified as
7396
// one single string which is translated in an array of string in the
7497
// argc/argv format
75-
const char* componentLibrary = "";
76-
const char* componentId = "";
77-
const char* componentParameter = "";
78-
const char* instanceId="";
98+
string componentParameter;
99+
string instanceId;
79100

80101
// the configuration and calibration is fixed for every run and identified
81102
// by the run no
82103
int runNumber = 0;
83104

84-
optind = 1; // indicate new start of scanning, especially when getop has been used in a higher layer already
85-
while ((c = getopt_long(argc, argv, "l:c:p:r:s:m:i:", programOptions, &iOption)) != -1) {
86-
switch (c) {
87-
case 'l':
88-
componentLibrary = optarg;
89-
break;
90-
case 'c':
91-
componentId = optarg;
92-
break;
93-
case 'p':
94-
componentParameter = optarg;
95-
break;
96-
case 'r':
97-
std::stringstream(optarg) >> runNumber;
98-
break;
99-
case 's': {
100-
unsigned size = 0;
101-
std::stringstream(optarg) >> size;
102-
mOutputBuffer.resize(size);
103-
} break;
104-
case 'm': {
105-
unsigned outputMode;
106-
std::stringstream(optarg) >> outputMode;
107-
mFormatHandler.setOutputMode(outputMode);
108-
} break;
109-
case 'i': {
110-
instanceId=optarg;
111-
break;
112-
}
113-
case '?':
114-
// TODO: more error handling
115-
break;
116-
default:
117-
cerr << "unknown option: '" << c << "'" << endl;
105+
bpo::variables_map varmap;
106+
bpo::store(bpo::parse_command_line(argc, argv, od), varmap);
107+
108+
for (int option = 0; option < OptionKeyLast; ++option) {
109+
if (varmap.count(OptionKeys[option]) == 0) continue;
110+
switch (option) {
111+
case OptionKeyLibrary: break;
112+
case OptionKeyComponent: break;
113+
case OptionKeyParameter:
114+
componentParameter = varmap[OptionKeys[option]].as<string>();
115+
break;
116+
case OptionKeyRun:
117+
stringstream(varmap[OptionKeys[option]].as<string>()) >> runNumber;
118+
break;
119+
case OptionKeyMsgsize: {
120+
unsigned size = 0;
121+
stringstream(varmap[OptionKeys[option]].as<string>()) >> size;
122+
mOutputBuffer.resize(size);
123+
} break;
124+
case OptionKeyOutputMode: {
125+
unsigned mode;
126+
stringstream(varmap[OptionKeys[option]].as<string>()) >> mode;
127+
mFormatHandler.setOutputMode(mode);
128+
} break;
129+
case OptionKeyInstanceId: break;
130+
instanceId = varmap[OptionKeys[option]].as<string>();
131+
break;
118132
}
119133
}
120134

121-
if (componentLibrary == nullptr || componentLibrary[0] == 0 || componentId == nullptr || componentId[0] == 0 ||
135+
// TODO: this can be a loop over all required options
136+
// probably we won't come here anyhow as the parser will detect
137+
// the absence of a required parameter, check and handle the parser
138+
// exception
139+
if (varmap.count(OptionKeys[OptionKeyLibrary]) == 0 ||
140+
varmap.count(OptionKeys[OptionKeyComponent]) == 0 ||
122141
runNumber < 0) {
123142
cerr << "missing argument" << endl;
124143
return -EINVAL;
@@ -136,14 +155,15 @@ int Component::init(int argc, char** argv)
136155
mpSystem = iface.release();
137156

138157
// load the component library
139-
if ((iResult = mpSystem->loadLibrary(componentLibrary)) != 0) return iResult > 0 ? -iResult : iResult;
158+
if ((iResult = mpSystem->loadLibrary(varmap[OptionKeys[OptionKeyLibrary]].as<string>().c_str())) != 0)
159+
return iResult > 0 ? -iResult : iResult;
140160

141161
// chop the parameter string in order to provide parameters in the argc/argv format
142162
vector<const char*> parameters;
143-
unsigned parameterLength = strlen(componentParameter);
163+
unsigned parameterLength = componentParameter.length();
144164
unique_ptr<char> parameterBuffer(new char[parameterLength + 1]);
145165
if (parameterLength > 0 && parameterBuffer.get() != nullptr) {
146-
strcpy(parameterBuffer.get(), componentParameter);
166+
strcpy(parameterBuffer.get(), componentParameter.c_str());
147167
char* iterator = parameterBuffer.get();
148168
parameters.push_back(iterator);
149169
for (; *iterator != 0; iterator++) {
@@ -155,8 +175,8 @@ int Component::init(int argc, char** argv)
155175

156176
// create component
157177
string description;
158-
description+=" chainid="; description+=instanceId;
159-
if ((iResult=mpSystem->createComponent(componentId, nullptr, parameters.size(), &parameters[0], &mProcessor, description.c_str()))<0) {
178+
description+=" chainid=" + instanceId;
179+
if ((iResult=mpSystem->createComponent(varmap[OptionKeys[OptionKeyComponent]].as<string>().c_str(), nullptr, parameters.size(), &parameters[0], &mProcessor, description.c_str()))<0) {
160180
// the ALICE HLT external interface uses the following error definition
161181
// 0 success
162182
// >0 error number

0 commit comments

Comments
 (0)