Blame view

parser/arguments.h 9.92 KB
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
240
241
242
243
244
  	};
  
  	struct argsection
  	{
  		std::string name;
  		unsigned int index;
  	};
  
  	class arglist
  	{
      private:
  		bool ansi;
  
81e0d221   David Mayerich   separated executa...
245
246
247
  		//vector of options
          std::vector<cmd_option> opts;
          std::vector<std::string> args;
3b012a80   David Mayerich   added code for co...
248
  
81e0d221   David Mayerich   separated executa...
249
  		//column width of the longest option
3b012a80   David Mayerich   added code for co...
250
251
252
253
254
255
256
          int col_width;
  
  		//list of sections
  		std::vector<argsection> sections;
  
      public:
  
0ef519a4   David Mayerich   optimized materia...
257
258
259
260
          arglist(){
          	col_width = 0;
          	ansi = true;
          }
3b012a80   David Mayerich   added code for co...
261
262
263
264
  
  		void set_ansi(bool b)
  		{
  			ansi = b;
81e0d221   David Mayerich   separated executa...
265
266
  			for(unsigned int i=0; i<opts.size(); i++)
  				opts[i].set_ansi(ansi);
3b012a80   David Mayerich   added code for co...
267
268
269
270
  		}
  
          void add(std::string _name, std::string _desc, std::string _default = "", std::string _range = "")
          {
81e0d221   David Mayerich   separated executa...
271
272
273
              cmd_option opt(_name, _desc, _default, _range);
  			opt.set_ansi(ansi);
              opts.push_back(opt);
3b012a80   David Mayerich   added code for co...
274
  
81e0d221   David Mayerich   separated executa...
275
              col_width = std::max<int>(col_width, opt.col_width());
3b012a80   David Mayerich   added code for co...
276
277
278
279
280
281
          }
  
  		void section(std::string _name)
  		{
  			argsection s;
  			s.name = _name;
81e0d221   David Mayerich   separated executa...
282
  			s.index = opts.size();
3b012a80   David Mayerich   added code for co...
283
284
285
  			sections.push_back(s);
  		}
  
81e0d221   David Mayerich   separated executa...
286
          //output the options (generally in response to --help)
7a2d0012   David Mayerich   mirst1d updates
287
          std::string str()
3b012a80   David Mayerich   added code for co...
288
289
290
291
292
293
294
295
          {
              std::stringstream ss;
  
              int si = -1;
  
              if(sections.size() > 0)
                  si = 0;
  
81e0d221   David Mayerich   separated executa...
296
297
              //for each option
              for(unsigned int a=0; a<opts.size(); a++)
3b012a80   David Mayerich   added code for co...
298
299
300
301
              {
                  if(si != -1 && a == sections[si].index)
                  {
  					if(ansi)
0ef519a4   David Mayerich   optimized materia...
302
  						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...
303
  					else
0ef519a4   David Mayerich   optimized materia...
304
  						ss<<std::endl<<std::left<<std::setfill('=')<<std::setw(col_width)<<sections[si].name<<std::endl;
3b012a80   David Mayerich   added code for co...
305
                      si++;
2e73e7bc   David Mayerich   basic changes for...
306
                      if(si == (int)sections.size()) si = -1;
3b012a80   David Mayerich   added code for co...
307
308
                  }
  
81e0d221   David Mayerich   separated executa...
309
                  ss<<opts[a].toStr(col_width)<<std::endl;
3b012a80   David Mayerich   added code for co...
310
311
312
313
314
315
316
              }
  
              return ss.str();
          }
  
          int index(std::string _name)
          {
81e0d221   David Mayerich   separated executa...
317
          	unsigned int i = find(opts.begin(), opts.end(), _name) - opts.begin();
3b012a80   David Mayerich   added code for co...
318
  
81e0d221   David Mayerich   separated executa...
319
              if(i >= opts.size())
cac62fd3   David Mayerich   modified to work ...
320
                  return -1;
3b012a80   David Mayerich   added code for co...
321
  
cac62fd3   David Mayerich   modified to work ...
322
              return (int)i;
3b012a80   David Mayerich   added code for co...
323
324
325
326
327
328
329
330
          }
  
          void set(std::string _name, std::string _value)
          {
              int i = index(_name);
  
              if(i != -1)
              {
81e0d221   David Mayerich   separated executa...
331
              	opts[i].set(_value);
3b012a80   David Mayerich   added code for co...
332
                  //adjust the column width if necessary
81e0d221   David Mayerich   separated executa...
333
                  col_width = (std::max)(col_width, opts[i].col_width());
3b012a80   David Mayerich   added code for co...
334
335
              }
              else
81e0d221   David Mayerich   separated executa...
336
                  std::cout<<"ERROR - option not recognized: "<<_name<<std::endl;
3b012a80   David Mayerich   added code for co...
337
338
339
340
341
          }
  
          //parse a parameter string
          void parse(int argc, char* argv[])
          {
81e0d221   David Mayerich   separated executa...
342
              //if the number of options is 1, we're done
3b012a80   David Mayerich   added code for co...
343
344
345
346
347
              if(argc <= 1) return;
  
              std::string name;
              std::string params;
  
81e0d221   David Mayerich   separated executa...
348
349
              bool args_done = false;		//create a flag that turns true when the first option is encountered
  
3b012a80   David Mayerich   added code for co...
350
351
              for(int i=1; i<argc; i++)
              {
81e0d221   David Mayerich   separated executa...
352
                  //if the argument is an option
3b012a80   David Mayerich   added code for co...
353
354
                  if(argv[i][0] == '-' && argv[i][1] == '-')
                  {
81e0d221   David Mayerich   separated executa...
355
356
                  	args_done = true;				//arguments for the executable are done, all options now
                      //add any previous options
3b012a80   David Mayerich   added code for co...
357
358
                      if(name != "")
                          set(name, params);
81e0d221   David Mayerich   separated executa...
359
                      //set the current option to this name
3b012a80   David Mayerich   added code for co...
360
361
362
363
                      name = argv[i]+2;
                      //clear the parameters list
                      params = "";
                  }
81e0d221   David Mayerich   separated executa...
364
365
366
367
                  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...
368
369
370
371
372
373
  					if(params != "")
  						params += " ";
                      params += argv[i];
                  }
              }
  
81e0d221   David Mayerich   separated executa...
374
              //set the last option
3b012a80   David Mayerich   added code for co...
375
376
377
378
379
380
              set(name, params);
          }
  
          //determine if a parameter has been set (either specified by the user or with a default value)
          bool operator()(std::string _name)
          {
81e0d221   David Mayerich   separated executa...
381
              int i = find(opts.begin(), opts.end(), _name) - opts.begin();
3b012a80   David Mayerich   added code for co...
382
383
384
385
386
387
388
  
              if(i < 0)
              {
                  std::cout<<"ERROR - Unspecified parameter name: "<<_name<<std::endl;
                  exit(1);
              }
  
81e0d221   David Mayerich   separated executa...
389
              return opts[i].is_set();
3b012a80   David Mayerich   added code for co...
390
391
          }
  
81e0d221   David Mayerich   separated executa...
392
393
          //number of arguments in a specified option
          unsigned int nargs(std::string _name)
3b012a80   David Mayerich   added code for co...
394
          {
81e0d221   David Mayerich   separated executa...
395
              int i = find(opts.begin(), opts.end(), _name) - opts.begin();
3b012a80   David Mayerich   added code for co...
396
397
398
399
400
401
402
  
              if(i < 0)
              {
                  std::cout<<"ERROR - Unspecified parameter name: "<<_name<<std::endl;
                  exit(1);
              }
  
81e0d221   David Mayerich   separated executa...
403
404
405
406
407
408
409
410
411
412
413
              return opts[i].nargs();
          }
  
          //number of arguments for the executable
          unsigned int nargs(){
          	return args.size();
          }
  
          //return the a'th executable argument
          std::string arg(unsigned int a){
          	return args[a];
3b012a80   David Mayerich   added code for co...
414
415
          }
  
81e0d221   David Mayerich   separated executa...
416
          cmd_option operator[](std::string _name)
3b012a80   David Mayerich   added code for co...
417
          {
81e0d221   David Mayerich   separated executa...
418
              int i = find(opts.begin(), opts.end(), _name) - opts.begin();
3b012a80   David Mayerich   added code for co...
419
  
695d32fa   unknown   David's changes t...
420
              if(i < 0 || i >= opts.size())
3b012a80   David Mayerich   added code for co...
421
422
423
424
425
              {
                  std::cout<<"ERROR - Unspecified parameter name: "<<_name<<std::endl;
                  exit(1);
              }
  
81e0d221   David Mayerich   separated executa...
426
              return opts[i];
3b012a80   David Mayerich   added code for co...
427
428
429
          }
  
  
7a2d0012   David Mayerich   mirst1d updates
430
431
432
433
  	};
  
  
  
2e73e7bc   David Mayerich   basic changes for...
434
  }	//end namespace stim
3b012a80   David Mayerich   added code for co...
435
436
  
  #endif