2e73e7bc
David Mayerich
basic changes for...
|
1
2
|
#ifndef STIM_ARGUMENTS
#define STIM_ARGUMENTS
|
7a2d0012
David Mayerich
mirst1d updates
|
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#include <string>
#include <vector>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <iterator>
#include <algorithm>
#ifdef _WIN32
#include <Windows.h>
#endif
|
2e73e7bc
David Mayerich
basic changes for...
|
16
|
namespace stim{
|
7a2d0012
David Mayerich
mirst1d updates
|
17
|
|
81e0d221
David Mayerich
separated executa...
|
18
|
class cmd_option
|
7a2d0012
David Mayerich
mirst1d updates
|
19
20
21
22
23
24
25
26
27
28
29
|
{
private:
bool ansi;
//argument name
std::string name;
//description of the argument
std::vector<std::string> desc;
//argument values
|
3b012a80
David Mayerich
added code for co...
|
30
31
32
33
34
35
|
std::vector<std::string> vals;
//range or example
std::string range;
//flag is true when the argument is user-specified
|
7a2d0012
David Mayerich
mirst1d updates
|
36
37
38
39
|
bool flag;
void parse_val(const std::string &s){
|
3b012a80
David Mayerich
added code for co...
|
40
41
|
vals.clear();
|
7a2d0012
David Mayerich
mirst1d updates
|
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, ' ')) {
vals.push_back(item);
}
}
void parse_desc(const std::string &s){
desc.clear();
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, '\n')) {
desc.push_back(item);
}
}
|
3b012a80
David Mayerich
added code for co...
|
60
61
|
public:
void set_ansi(bool b){ ansi = b; }
|
81e0d221
David Mayerich
separated executa...
|
62
63
|
//create an option with a given name, description, and default value
cmd_option(std::string _name, std::string _desc, std::string _default = "", std::string _range = "")
|
7a2d0012
David Mayerich
mirst1d updates
|
64
65
66
|
{
name = _name;
parse_desc(_desc);
|
3b012a80
David Mayerich
added code for co...
|
67
68
69
70
71
72
73
74
75
|
parse_val(_default);
//if a default value is provided, set the flag
if(_default != "")
flag = true;
else flag = false;
range = _range;
|
7a2d0012
David Mayerich
mirst1d updates
|
76
|
|
3b012a80
David Mayerich
added code for co...
|
77
78
79
80
81
82
83
|
}
int nargs()
{
return vals.size();
}
|
81e0d221
David Mayerich
separated executa...
|
84
|
//return the value of a text option
|
2e73e7bc
David Mayerich
basic changes for...
|
85
|
std::string as_string(unsigned int n = 0)
|
3b012a80
David Mayerich
added code for co...
|
86
87
88
|
{
if(!flag)
{
|
81e0d221
David Mayerich
separated executa...
|
89
|
std::cout<<"ERROR - Option requested without being set: "<<name<<std::endl;
|
3b012a80
David Mayerich
added code for co...
|
90
91
92
93
94
95
96
97
98
|
exit(1);
}
if(vals.size() > n)
return vals[n];
else return "";
}
|
81e0d221
David Mayerich
separated executa...
|
99
|
//return the value of a floating point option
|
2e73e7bc
David Mayerich
basic changes for...
|
100
|
float as_float(unsigned int n = 0)
|
3b012a80
David Mayerich
added code for co...
|
101
102
103
|
{
if(!flag)
{
|
81e0d221
David Mayerich
separated executa...
|
104
|
std::cout<<"ERROR - option requested without being set: "<<name<<std::endl;
|
3b012a80
David Mayerich
added code for co...
|
105
106
107
108
109
110
|
exit(1);
}
if(vals.size() > n)
{
float r;
|
2e73e7bc
David Mayerich
basic changes for...
|
111
|
if ( ! (std::istringstream(vals[n]) >> r) ) r = 0;
|
3b012a80
David Mayerich
added code for co...
|
112
113
114
115
116
117
|
return r;
}
else return 0;
}
|
81e0d221
David Mayerich
separated executa...
|
118
|
//return the value of an integer option
|
2e73e7bc
David Mayerich
basic changes for...
|
119
|
int as_int(unsigned int n = 0)
|
3b012a80
David Mayerich
added code for co...
|
120
121
122
|
{
if(!flag)
{
|
81e0d221
David Mayerich
separated executa...
|
123
|
std::cout<<"ERROR - option requested without being set: "<<name<<std::endl;
|
3b012a80
David Mayerich
added code for co...
|
124
125
126
127
128
129
|
exit(1);
}
if(vals.size() > n)
{
int r;
|
2e73e7bc
David Mayerich
basic changes for...
|
130
|
if ( ! (std::istringstream(vals[n]) >> r) ) r = 0;
|
3b012a80
David Mayerich
added code for co...
|
131
132
133
134
135
136
137
138
139
140
|
return r;
}
else return 0;
}
//get the width of the left column
int col_width()
{
int n = 3;
|
81e0d221
David Mayerich
separated executa...
|
141
|
//add the length of the option name
|
3b012a80
David Mayerich
added code for co...
|
142
143
144
145
146
147
148
149
|
n += name.size();
//if there are any default parameters
if(vals.size() > 0)
{
//padding (parenthesis, =, etc.)
n += 6;
|
81e0d221
David Mayerich
separated executa...
|
150
|
//for each default option value
|
2e73e7bc
David Mayerich
basic changes for...
|
151
|
for(unsigned int v=0; v<vals.size(); v++)
|
3b012a80
David Mayerich
added code for co...
|
152
153
154
155
156
157
158
|
n += vals[v].size() + 1;
}
//add a buffer of 4 characters
n += 4;
return n;
|
7a2d0012
David Mayerich
mirst1d updates
|
159
160
161
162
163
164
|
}
//string output
std::string toStr(int width = 0)
{
|
3b012a80
David Mayerich
added code for co...
|
165
166
167
168
|
std::stringstream ss;
int color_size = 0;
|
7a2d0012
David Mayerich
mirst1d updates
|
169
170
171
172
|
//create the left column
std::string left_part = std::string(" --") + name;
if(vals.size() != 0)
|
3b012a80
David Mayerich
added code for co...
|
173
174
175
|
{
if(ansi)
left_part += "\033[1;32m";
|
7a2d0012
David Mayerich
mirst1d updates
|
176
|
left_part += " ( = ";
|
2e73e7bc
David Mayerich
basic changes for...
|
177
|
for(unsigned int v=0; v<vals.size(); v++)
|
7a2d0012
David Mayerich
mirst1d updates
|
178
|
left_part += vals[v] + std::string(" ");
|
3b012a80
David Mayerich
added code for co...
|
179
180
181
182
183
184
185
|
left_part += ")";
if(ansi)
left_part += "\033[0m";
if(ansi)
color_size = 11;
}
else
|
7a2d0012
David Mayerich
mirst1d updates
|
186
187
188
|
color_size = 0;
//if no width is passed, put 4 spaces between left and right columns
|
3b012a80
David Mayerich
added code for co...
|
189
|
if(width == 0) width = col_width();
|
7a2d0012
David Mayerich
mirst1d updates
|
190
191
192
193
|
ss<<std::left<<std::setw(width + color_size)<<left_part;
//output right column
|
2e73e7bc
David Mayerich
basic changes for...
|
194
|
for(unsigned int d=0; d<desc.size(); d++)
|
7a2d0012
David Mayerich
mirst1d updates
|
195
196
197
|
{
if(d == 0)
ss<<desc[0];
|
3b012a80
David Mayerich
added code for co...
|
198
|
else
|
0ef519a4
David Mayerich
optimized materia...
|
199
|
ss<<std::endl<<std::setfill(' ')<<std::setw(width)<<" "<<desc[d];
|
7a2d0012
David Mayerich
mirst1d updates
|
200
|
|
3b012a80
David Mayerich
added code for co...
|
201
202
203
204
|
}
//output the range in the right column
if(range != "" && ansi)
|
0ef519a4
David Mayerich
optimized materia...
|
205
|
ss<<std::endl<<std::setfill(' ')<<std::setw(width)<<" "<<" "<<std::string("\033[1;36m") + range + "\033[0m";
|
7a2d0012
David Mayerich
mirst1d updates
|
206
|
else if(range != "")
|
0ef519a4
David Mayerich
optimized materia...
|
207
|
ss<<std::endl<<std::setfill(' ')<<std::setw(width)<<" "<<" "<<range;
|
7a2d0012
David Mayerich
mirst1d updates
|
208
209
|
return ss.str();
|
3b012a80
David Mayerich
added code for co...
|
210
211
|
}
|
81e0d221
David Mayerich
separated executa...
|
212
|
//compare the name of the option to a string
|
3b012a80
David Mayerich
added code for co...
|
213
214
215
216
217
|
bool operator==(std::string rhs)
{
return (name == rhs);
}
|
81e0d221
David Mayerich
separated executa...
|
218
|
//set the option to a given value
|
3b012a80
David Mayerich
added code for co...
|
219
220
221
222
223
224
225
226
227
228
229
|
void set(std::string _value)
{
parse_val(_value);
//set the flag
flag = true;
}
bool is_set()
{
return flag;
|
7a2d0012
David Mayerich
mirst1d updates
|
230
231
|
}
|
3b012a80
David Mayerich
added code for co...
|
232
233
234
235
236
237
238
239
|
};
struct argsection
{
std::string name;
unsigned int index;
};
|
025d4bf3
David Mayerich
added documentati...
|
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
|
/**The arglist class implements command line arguments.
Example:
1) Create an arglist instance:
stim::arglist args;
2) Test to see if ANSI output is supported (arguments will use color if it is). Generally, Windows consoles don't support ANSI.
#ifdef _WIN32
args.set_ansi(false);
#endif
3) Add arguments:
args.add("help", "prints this help");
args.add("foo", "foo takes a single integer value", "", "[intval]");
args.add("bar", "bar takes two floating point values", "", "[value1], [value2]");
4) You generally want to immediately test for help and output available arguments:
if(args["help"].is_set())
std::cout<<args.str();
5) Parse the command line:
args.parse(argc, argv);
6) Retrieve values:
int foo;
float bar1, bar2;
if(args["foo"])
foo = args["foo"].as_int();
if(args["bar"]){
bar1 = args["bar"].as_float(0);
bar2 = args["bar"].as_float(1);
}
**/
|
3b012a80
David Mayerich
added code for co...
|
282
283
284
285
286
|
class arglist
{
private:
bool ansi;
|
81e0d221
David Mayerich
separated executa...
|
287
288
289
|
//vector of options
std::vector<cmd_option> opts;
std::vector<std::string> args;
|
3b012a80
David Mayerich
added code for co...
|
290
|
|
81e0d221
David Mayerich
separated executa...
|
291
|
//column width of the longest option
|
3b012a80
David Mayerich
added code for co...
|
292
293
294
295
296
297
298
|
int col_width;
//list of sections
std::vector<argsection> sections;
public:
|
0ef519a4
David Mayerich
optimized materia...
|
299
300
301
302
|
arglist(){
col_width = 0;
ansi = true;
}
|
3b012a80
David Mayerich
added code for co...
|
303
|
|
025d4bf3
David Mayerich
added documentati...
|
304
305
306
|
///Sets ANSI support (default is on), which allows colored values in the help output.
/// @param b is a boolean value specifying ANSI support (true is on, false is off)
|
3b012a80
David Mayerich
added code for co...
|
307
308
309
|
void set_ansi(bool b)
{
ansi = b;
|
81e0d221
David Mayerich
separated executa...
|
310
311
|
for(unsigned int i=0; i<opts.size(); i++)
opts[i].set_ansi(ansi);
|
3b012a80
David Mayerich
added code for co...
|
312
313
|
}
|
025d4bf3
David Mayerich
added documentati...
|
314
315
316
317
318
319
|
///Add a supported command line argument.
/// @param _name is the name of the command line argument (supplied as --name)
/// @param _desc is a text description of the argument
/// @param _default is the default value of the argument
/// @param _range is the supported range of values, list of values, etc. It will be displayed to the user.
|
3b012a80
David Mayerich
added code for co...
|
320
321
|
void add(std::string _name, std::string _desc, std::string _default = "", std::string _range = "")
{
|
81e0d221
David Mayerich
separated executa...
|
322
323
324
|
cmd_option opt(_name, _desc, _default, _range);
opt.set_ansi(ansi);
opts.push_back(opt);
|
3b012a80
David Mayerich
added code for co...
|
325
|
|
81e0d221
David Mayerich
separated executa...
|
326
|
col_width = std::max<int>(col_width, opt.col_width());
|
3b012a80
David Mayerich
added code for co...
|
327
328
|
}
|
025d4bf3
David Mayerich
added documentati...
|
329
330
331
|
///Specifies a section name that can be used to organize parameters in the output.
/// @param _name is the name of the section, which will be displayed to the user
|
3b012a80
David Mayerich
added code for co...
|
332
333
334
335
|
void section(std::string _name)
{
argsection s;
s.name = _name;
|
81e0d221
David Mayerich
separated executa...
|
336
|
s.index = opts.size();
|
3b012a80
David Mayerich
added code for co...
|
337
338
339
|
sections.push_back(s);
}
|
025d4bf3
David Mayerich
added documentati...
|
340
|
///Outputs supported arguments. If ANSI support is available, they will be color-coded. Generally this is called in response to "--help"
|
7a2d0012
David Mayerich
mirst1d updates
|
341
|
std::string str()
|
3b012a80
David Mayerich
added code for co...
|
342
343
344
345
346
347
348
349
|
{
std::stringstream ss;
int si = -1;
if(sections.size() > 0)
si = 0;
|
81e0d221
David Mayerich
separated executa...
|
350
351
|
//for each option
for(unsigned int a=0; a<opts.size(); a++)
|
3b012a80
David Mayerich
added code for co...
|
352
353
354
355
|
{
if(si != -1 && a == sections[si].index)
{
if(ansi)
|
0ef519a4
David Mayerich
optimized materia...
|
356
|
ss<<std::endl<<std::left<<std::setfill('=')<<std::setw(col_width)<<std::string("\033[1;31m") + sections[si].name<<"\033[0m"<<std::endl;
|
3b012a80
David Mayerich
added code for co...
|
357
|
else
|
0ef519a4
David Mayerich
optimized materia...
|
358
|
ss<<std::endl<<std::left<<std::setfill('=')<<std::setw(col_width)<<sections[si].name<<std::endl;
|
3b012a80
David Mayerich
added code for co...
|
359
|
si++;
|
2e73e7bc
David Mayerich
basic changes for...
|
360
|
if(si == (int)sections.size()) si = -1;
|
3b012a80
David Mayerich
added code for co...
|
361
362
|
}
|
81e0d221
David Mayerich
separated executa...
|
363
|
ss<<opts[a].toStr(col_width)<<std::endl;
|
3b012a80
David Mayerich
added code for co...
|
364
365
366
367
368
|
}
return ss.str();
}
|
025d4bf3
David Mayerich
added documentati...
|
369
370
371
|
///Retrieves the index for a supported argument, given that argument's name.
/// @param _name is the name of the requested argument
|
3b012a80
David Mayerich
added code for co...
|
372
373
|
int index(std::string _name)
{
|
81e0d221
David Mayerich
separated executa...
|
374
|
unsigned int i = find(opts.begin(), opts.end(), _name) - opts.begin();
|
3b012a80
David Mayerich
added code for co...
|
375
|
|
81e0d221
David Mayerich
separated executa...
|
376
|
if(i >= opts.size())
|
cac62fd3
David Mayerich
modified to work ...
|
377
|
return -1;
|
3b012a80
David Mayerich
added code for co...
|
378
|
|
cac62fd3
David Mayerich
modified to work ...
|
379
|
return (int)i;
|
3b012a80
David Mayerich
added code for co...
|
380
381
|
}
|
025d4bf3
David Mayerich
added documentati...
|
382
383
384
385
|
///Sets an argument to a specified value
/// @param _name is the name of the argument to be set
/// @param _value is the value that it is given
|
3b012a80
David Mayerich
added code for co...
|
386
387
388
389
390
391
|
void set(std::string _name, std::string _value)
{
int i = index(_name);
if(i != -1)
{
|
81e0d221
David Mayerich
separated executa...
|
392
|
opts[i].set(_value);
|
3b012a80
David Mayerich
added code for co...
|
393
|
//adjust the column width if necessary
|
81e0d221
David Mayerich
separated executa...
|
394
|
col_width = (std::max)(col_width, opts[i].col_width());
|
3b012a80
David Mayerich
added code for co...
|
395
396
|
}
else
|
81e0d221
David Mayerich
separated executa...
|
397
|
std::cout<<"ERROR - option not recognized: "<<_name<<std::endl;
|
3b012a80
David Mayerich
added code for co...
|
398
399
|
}
|
025d4bf3
David Mayerich
added documentati...
|
400
401
402
403
|
///Parses the command line
/// @param argc is the number of command line arguments (provided by the OS)
/// @param argv[] is the list of command line arguments (provided by the OS)
|
3b012a80
David Mayerich
added code for co...
|
404
405
|
void parse(int argc, char* argv[])
{
|
81e0d221
David Mayerich
separated executa...
|
406
|
//if the number of options is 1, we're done
|
3b012a80
David Mayerich
added code for co...
|
407
408
409
410
411
|
if(argc <= 1) return;
std::string name;
std::string params;
|
81e0d221
David Mayerich
separated executa...
|
412
413
|
bool args_done = false; //create a flag that turns true when the first option is encountered
|
3b012a80
David Mayerich
added code for co...
|
414
415
|
for(int i=1; i<argc; i++)
{
|
81e0d221
David Mayerich
separated executa...
|
416
|
//if the argument is an option
|
3b012a80
David Mayerich
added code for co...
|
417
418
|
if(argv[i][0] == '-' && argv[i][1] == '-')
{
|
81e0d221
David Mayerich
separated executa...
|
419
420
|
args_done = true; //arguments for the executable are done, all options now
//add any previous options
|
3b012a80
David Mayerich
added code for co...
|
421
422
|
if(name != "")
set(name, params);
|
81e0d221
David Mayerich
separated executa...
|
423
|
//set the current option to this name
|
3b012a80
David Mayerich
added code for co...
|
424
425
426
427
|
name = argv[i]+2;
//clear the parameters list
params = "";
}
|
81e0d221
David Mayerich
separated executa...
|
428
429
430
431
|
else if(!args_done){
args.push_back(argv[i]);
}
else{ //everything else is an arg for the most recent option
|
3b012a80
David Mayerich
added code for co...
|
432
433
434
435
436
437
|
if(params != "")
params += " ";
params += argv[i];
}
}
|
81e0d221
David Mayerich
separated executa...
|
438
|
//set the last option
|
3b012a80
David Mayerich
added code for co...
|
439
440
441
|
set(name, params);
}
|
025d4bf3
David Mayerich
added documentati...
|
442
443
444
|
///Determines of a parameter has been set and returns true if it has
/// @param _name is the name of the argument
|
3b012a80
David Mayerich
added code for co...
|
445
446
|
bool operator()(std::string _name)
{
|
81e0d221
David Mayerich
separated executa...
|
447
|
int i = find(opts.begin(), opts.end(), _name) - opts.begin();
|
3b012a80
David Mayerich
added code for co...
|
448
449
450
451
452
453
454
|
if(i < 0)
{
std::cout<<"ERROR - Unspecified parameter name: "<<_name<<std::endl;
exit(1);
}
|
81e0d221
David Mayerich
separated executa...
|
455
|
return opts[i].is_set();
|
3b012a80
David Mayerich
added code for co...
|
456
457
|
}
|
025d4bf3
David Mayerich
added documentati...
|
458
459
460
|
///Returns the number of parameters for a specified argument
/// @param _name is the name of the argument whose parameter number will be returned
|
81e0d221
David Mayerich
separated executa...
|
461
|
unsigned int nargs(std::string _name)
|
3b012a80
David Mayerich
added code for co...
|
462
|
{
|
81e0d221
David Mayerich
separated executa...
|
463
|
int i = find(opts.begin(), opts.end(), _name) - opts.begin();
|
3b012a80
David Mayerich
added code for co...
|
464
465
466
467
468
469
470
|
if(i < 0)
{
std::cout<<"ERROR - Unspecified parameter name: "<<_name<<std::endl;
exit(1);
}
|
81e0d221
David Mayerich
separated executa...
|
471
472
473
|
return opts[i].nargs();
}
|
025d4bf3
David Mayerich
added documentati...
|
474
|
///Returns the number of arguments that have been set
|
81e0d221
David Mayerich
separated executa...
|
475
476
477
478
|
unsigned int nargs(){
return args.size();
}
|
025d4bf3
David Mayerich
added documentati...
|
479
480
481
|
///Returns the name of an argument, given its index
/// @param a is the index of the requested argument
|
81e0d221
David Mayerich
separated executa...
|
482
483
|
std::string arg(unsigned int a){
return args[a];
|
3b012a80
David Mayerich
added code for co...
|
484
485
|
}
|
025d4bf3
David Mayerich
added documentati...
|
486
487
488
|
///Returns an object describing the argument
/// @param _name is the name of the requested argument
|
81e0d221
David Mayerich
separated executa...
|
489
|
cmd_option operator[](std::string _name)
|
3b012a80
David Mayerich
added code for co...
|
490
|
{
|
81e0d221
David Mayerich
separated executa...
|
491
|
int i = find(opts.begin(), opts.end(), _name) - opts.begin();
|
3b012a80
David Mayerich
added code for co...
|
492
|
|
695d32fa
unknown
David's changes t...
|
493
|
if(i < 0 || i >= opts.size())
|
3b012a80
David Mayerich
added code for co...
|
494
495
496
497
498
|
{
std::cout<<"ERROR - Unspecified parameter name: "<<_name<<std::endl;
exit(1);
}
|
81e0d221
David Mayerich
separated executa...
|
499
|
return opts[i];
|
3b012a80
David Mayerich
added code for co...
|
500
501
502
|
}
|
7a2d0012
David Mayerich
mirst1d updates
|
503
504
505
506
|
};
|
2e73e7bc
David Mayerich
basic changes for...
|
507
|
} //end namespace stim
|
3b012a80
David Mayerich
added code for co...
|
508
509
|
#endif
|