libassa 3.5.1
Loading...
Searching...
No Matches
CmdLineOpts.cpp
Go to the documentation of this file.
1// -*- c++ -*-
2//------------------------------------------------------------------------------
3// $Id: CmdLineOpts.cpp,v 1.7 2007/05/14 19:19:50 vlg Exp $
4//------------------------------------------------------------------------------
5// CmdLineOpts.cpp
6//------------------------------------------------------------------------------
7// Copyright (C) 2000,2005,2007 Vladislav Grinchenko
8//
9// This library is free software; you can redistribute it and/or
10// modify it under the terms of the GNU Library General Public
11// License as published by the Free Software Foundation; either
12// version 2 of the License, or (at your option) any later version.
13//------------------------------------------------------------------------------
14#include <errno.h>
15#include <string.h>
16#include <stdlib.h>
17
18#include <sstream>
19#include <iomanip>
20
21#include "assa/Logger.h"
22#include "assa/CmdLineOpts.h"
23#include "assa/CommonUtils.h"
24#include "assa/IniFile.h"
25
26using namespace ASSA;
27
28void
30dump () const
31{
32 std::ostringstream msg;
33
34 if (m_short_name != 0) {
35 msg << "-" << m_short_name << ", ";
36 }
37 else {
38 msg << " ";
39 }
40
41 if (m_long_name.size ()) {
42 msg << "--" << std::setiosflags (std::ios::left)
43 << std::setw(14) << m_long_name.c_str () << ' ';
44 }
45 else {
46 msg << std::setiosflags (std::ios::left) << std::setw (14) << " ";
47 }
48 msg << '[';
49
50 switch (m_type)
51 {
52 case Option::string_t:
53 msg << std::setiosflags (std::ios::left) << std::setw(7) << "string";
54 msg << "] = '" << *(string*) m_val << "'";
55 break;
56
57 case Option::int_t:
58 msg << std::setiosflags(std::ios::left) << std::setw(7) << "int";
59 msg << "] = " << *(int*) m_val;
60 break;
61
62 case Option::uint_t:
63 msg << std::setiosflags(std::ios::left) << std::setw(7) << "u_int";
64 msg << "] = " << *(int*) m_val;
65 break;
66
67 case Option::long_t:
68 msg << std::setiosflags(std::ios::left) << std::setw(7) << "long";
69 msg << "] = " << *(long*) m_val;
70 break;
71
72 case Option::ulong_t:
73 msg << std::setiosflags(std::ios::left) << std::setw(7) << "u_long";
74 msg << "] = " << *(long*) m_val;
75 break;
76
77 case Option::double_t:
78 msg << std::setiosflags(std::ios::left) << std::setw(7) << "double";
79 msg << "] = " << *(double*) m_val;
80 break;
81
82 case Option::float_t:
83 msg << std::setiosflags(std::ios::left) << std::setw(7) << "float";
84 msg << "] = " << *(float*) m_val;
85 break;
86
87 case Option::flag_t:
88 msg << std::setiosflags(std::ios::left) << std::setw(7) << "bool";
89 msg << "] = " << *(bool*) m_val ? "true" : "false";
90 break;
91
92 case Option::func_t:
93 msg << std::setiosflags(std::ios::left)
94 << std::setw(7) << "function ()";
95 msg << ']';
96 break;
97
99 msg << std::setiosflags(std::ios::left)
100 << std::setw(7) << "function (opt)";
101 msg << ']';
102 break;
103
104 case Option::none_t:
105 msg << std::setiosflags(std::ios::left) << std::setw(7) << "none";
106 msg << ']';
107 break;
108
109 default:
110 msg << std::setiosflags(std::ios::left)
111 << std::setw(7) << "--undef--";
112 msg << ']';
113 }
114 msg << std::ends;
115 DL((CMDLINEOPTS,"%s\n", msg.str ().c_str ()));
116}
117
118const char*
120type_c_str ()
121{
122 const char* ret;
123
124 switch (m_type)
125 {
126 case Option::string_t: ret = "string"; break;
127 case Option::int_t: ret = "int"; break;
128 case Option::uint_t: ret = "u_int"; break;
129 case Option::long_t: ret = "long"; break;
130 case Option::ulong_t: ret = "u_long"; break;
131 case Option::double_t: ret = "double"; break;
132 case Option::float_t: ret = "float"; break;
133 case Option::flag_t: ret = "bool"; break;
134 case Option::func_t: ret = "func()"; break;
135 case Option::func_one_t: ret = "func(opt)"; break;
136 case Option::none_t: ret = "none"; break;
137 default: ret = "--undef--";
138 }
139 return (ret);
140}
141
142/*----------------------------------------------------------------------------*/
143bool
145is_valid (const char sopt_, const string& lopt_)
146{
147 trace_with_mask ("CmdLineOpts::is_valid", CMDLINEOPTS);
148
150 OptionSet::const_iterator i;
151
152 for (i = m_opts_set.begin (); i != m_opts_set.end (); i++) {
153 if (sopt_ == '\0' && lopt_.empty ()) {
154 m_error = "Ignore empty option";
155 return (false);
156 }
157 else if (sopt_ != '\0' && i->m_short_name == sopt_) {
158 m_error = "Ignored multiple option '-";
159 m_error += sopt_ + string ("'");
160 return (false);
161 }
162 else if (!lopt_.empty () && i->m_long_name == lopt_) {
163 m_error = "Ignore multiple option '--";
164 m_error += lopt_ + string ("'");
165 return (false);
166 }
167 }
168 return (true);
169}
170
171Option*
173find_option (const char* str_)
174{
175 trace_with_mask ("CmdLineOpts::find_option(char*)", CMDLINEOPTS);
176
177 OptionSet::iterator i;
178
179 for ( i = m_opts_set.begin (); i != m_opts_set.end (); i++)
180 {
181 if (i->m_long_name == str_) {
182 return &(*i);
183 }
184 }
185 return (NULL);
186}
187
188Option*
190find_option (const char letter_)
191{
192 trace_with_mask ("CmdLineOpts::find_option(char)", CMDLINEOPTS);
193
194 OptionSet::iterator i;
195
196 for (i = m_opts_set.begin (); i != m_opts_set.end (); i++)
197 {
198 if (i->m_short_name == letter_)
199 return &(*i);
200 }
201 return (NULL);
202}
203
204bool
206add_flag_opt (const char sopt_, const string& lopt_, bool* v_)
207{
208 trace_with_mask ("CmdLineOpts::add_flag_opt", CMDLINEOPTS);
209
210 if (!is_valid (sopt_, lopt_))
211 return (false);
212
213 Option o (sopt_, lopt_, Option::flag_t, (void*) v_);
214 m_opts_set.push_back (o);
215 return (true);
216}
217
218bool
220add_opt (const char sopt_, const string& lopt_, string* v_)
221{
222 trace_with_mask ("CmdLineOpts::add_opt(string*)", CMDLINEOPTS);
223
224 if (!is_valid (sopt_, lopt_))
225 return (false);
226
227 Option o (sopt_, lopt_, Option::string_t, (void*) v_);
228 m_opts_set.push_back (o);
229 return (true);
230}
231
232bool
234add_opt (const char sopt_, const string& lopt_, int* v_)
235{
236 trace_with_mask ("CmdLineOpts::add_opt(int*)", CMDLINEOPTS);
237
238 if (!is_valid (sopt_, lopt_)) {
239 return (false);
240 }
241 Option o (sopt_, lopt_, Option::int_t, (void*) v_);
242 m_opts_set.push_back (o);
243 return (true);
244}
245
246bool
248add_opt (const char sopt_, const string& lopt_, unsigned int* v_)
249{
250 trace_with_mask ("CmdLineOpts::add_opt(u_int*)", CMDLINEOPTS);
251
252 if (!is_valid (sopt_, lopt_)) {
253 return (false);
254 }
255 Option o (sopt_, lopt_, Option::uint_t, (void*) v_);
256 m_opts_set.push_back (o);
257 return (true);
258}
259
260bool
262add_opt (const char sopt_, const string& lopt_, long* v_)
263{
264 trace_with_mask ("CmdLineOpts::add_opt(long*)", CMDLINEOPTS);
265
266 if (!is_valid (sopt_, lopt_)) {
267 return (false);
268 }
269 Option o (sopt_, lopt_, Option::long_t, (void*) v_);
270 m_opts_set.push_back (o);
271 return (true);
272}
273
274bool
276add_opt (const char sopt_, const string& lopt_, unsigned long* v_)
277{
278 trace_with_mask ("CmdLineOpts::add_opt(u_long*)", CMDLINEOPTS);
279
280 if (!is_valid (sopt_, lopt_)) {
281 return (false);
282 }
283 Option o (sopt_, lopt_, Option::long_t, (void*) v_);
284 m_opts_set.push_back (o);
285 return (true);
286}
287
288bool
290add_opt (const char sopt_, const string& lopt_, double* v_)
291{
292 trace_with_mask ("CmdLineOpts::add_opt(double*)", CMDLINEOPTS);
293
294 if (!is_valid (sopt_, lopt_)) {
295 return (false);
296 }
297 Option o (sopt_, lopt_, Option::double_t, (void*) v_);
298 m_opts_set.push_back (o);
299 return (true);
300}
301
302bool
304add_opt (const char sopt_, const string& lopt_, float* v_)
305{
306 trace_with_mask ("CmdLineOpts::add_opt(float*)", CMDLINEOPTS);
307
308 if (!is_valid (sopt_, lopt_)) {
309 return (false);
310 }
311 Option o (sopt_, lopt_, Option::float_t, (void*) v_);
312 m_opts_set.push_back (o);
313 return (true);
314}
315
316bool
318add_opt (const char sopt_, const string& lopt_, OPTS_FUNC v_)
319{
320 trace_with_mask ("CmdLineOpts::add_opt(OPTS_FUNC)", CMDLINEOPTS);
321
322 if (!is_valid (sopt_, lopt_)) {
323 return (false);
324 }
325 Option o (sopt_, lopt_, Option::func_t, (void*) v_);
326 m_opts_set.push_back (o);
327 return (true);
328}
329
330bool
332add_opt (const char sopt_, const string& lopt_, OPTS_FUNC_ONE v_)
333{
334 trace_with_mask ("CmdLineOpts::add_opt(OPTS_FUNC_ONE)", CMDLINEOPTS);
335
336 if (!is_valid (sopt_, lopt_)) {
337 return (false);
338 }
340 m_opts_set.push_back (o);
341 return (true);
342}
343
344bool
346rm_opt (const char sopt_, const string& lopt_)
347{
348 trace_with_mask ("CmdLineOpts::rm_opt(string&)", CMDLINEOPTS);
349
350 OptionSet::iterator i;
351
352 for (i = m_opts_set.begin (); i != m_opts_set.end (); i++)
353 {
354 if (i->m_short_name == sopt_ || i->m_long_name == lopt_)
355 {
356 m_opts_set.erase (i);
357 return (true);
358 }
359 }
360 return (false);
361}
362
363bool
365parse_args (const char* argv_[])
366{
367 trace_with_mask ("CmdLineOpts::parse_args", CMDLINEOPTS);
368
369 register int skip = 1;
370 bool pos_args_started = false;
371 string param ("");
372 string token ("");
374 Option* node = (Option*) NULL;
375
376 for (argv_++; argv_[0]; argv_ += skip) {
377 if (skip != 0) {
378 token = argv_[0];
379 }
380
381 DL((CMDLINEOPTS, "token: \"%s\"\n", token.c_str()));
382
383 if (pos_args_started) {
384 DL((CMDLINEOPTS,"pos_args_started = true\n"));
385
386 if (token[0] == '-' && token.size () != 1) {
387 m_error = "Invalid order of arguments: '";
388 m_error += token + "'.";
389 goto done;
390 }
391 pos_arg (token.c_str ());
392 continue;
393 }
394 skip = 1;
395
396 if (token[0] == '-' && token.size () > 1 && token[1] != '-') {
397 if (token.size () == 1 && !pos_args_started) {
398 pos_arg (token.c_str ());
399 pos_args_started = true;
400 continue;
401 }
402
403 if ((node = find_option (token[1])) != NULL) {
404 if (token.size () > 2) {
405 if (node->m_type == Option::flag_t ||
406 node->m_type == Option::func_t)
407 {
408 token.erase (1, 1);
409 skip = 0;
410 }
411 else {
412 param = token.substr (2);
413 }
414 } // if (token.size()>2)
415 } // if ((node = find_option ())
416 }
417 else {
418 if (token.size () > 1 && token[1] == '-') {
419 string op = token.substr (2);
420 size_t pos;
421
422 if ((pos = op.find ("=")) != (size_t)-1) {
423 param = op.substr (pos+1, op.length ());
424 op.replace (pos, op.length() - pos, "");
425 }
426 node = find_option (op.c_str ());
427 }
428 else {
429 pos_arg (token.c_str ());
430 pos_args_started = true;
431 continue;
432 }
433 } // if (token[0] == '-' && token[1] != '-')
434
435 if (!node) {
436 m_error = "Invalid option '" + token + "'.";
437 goto done;
438 }
439
440 if (node->m_type != Option::flag_t &&
441 node->m_type != Option::func_t)
442 {
443 if (param.empty ()) {
444 if (!argv_[1]) {
445 m_error = "Expecting parameter after '"
446 + string (argv_[0]) + "'.";
447 goto done;
448 }
449 param = argv_[1];
450 skip = 2;
451 }
452 }
453 /*---
454 * if positional arguments only
455 ---*/
456 if (!node) {
457 goto done;
458 }
459
460 if (param.empty ()) {
461 if (!assign (node, argv_[1])) {
462 return (false);
463 }
464 }
465 else {
466 const char* str = param.c_str ();
467 if (!assign (node, str)) {
468 return (false);
469 }
470 param = "";
471 }
472 } // for (argv_++; argv_[0]; argv_ += skip)
473
474 done:
475 return !m_error.empty () ? false : true;
476}
477
490int
493{
494 trace_with_mask ("CmdLineOpts::parse_config_file", CMDLINEOPTS);
495
496 unsigned int count = 0;
497 string v;
498 string s;
499 string optsect_name ("options");
500 OptionSet::iterator pos = m_opts_set.begin ();
501
502 if (inifile_.find_section (optsect_name) == inifile_.sect_end ())
503 {
504 optsect_name = "Options";
505 if (inifile_.find_section (optsect_name) == inifile_.sect_end ())
506 {
507 optsect_name = "OPTIONS";
508 if (inifile_.find_section (optsect_name) == inifile_.sect_end ())
509 {
510 m_error = "Missing [options] section in INI file!";
511 return -1;
512 }
513 }
514 }
515
516 while (pos != m_opts_set.end ()) {
517 if (pos->m_long_name.size ()) {
518 s = pos->m_long_name;
520 DL ((CMDLINEOPTS, "trying option \"%s\"\n", s.c_str ()));
521 v = inifile_.get_value (optsect_name, s);
522 if (v.size ()) {
523 if (assign (&(*pos), v.c_str ())) {
524 count++;
525 }
526 }
527 }
528 pos++;
529 }
530
531 return (count);
532}
533
534bool
536assign (Option* node_, const char* op_)
537{
538 trace_with_mask ("CmdLineOpts::assign", CMDLINEOPTS);
539
540 long l;
541 double d;
542
543 if (node_ && op_) {
544 DL ((CMDLINEOPTS, "Assign '%s' to {-%c, --%s, t=%s}\n",
545 op_, node_->m_short_name, node_->m_long_name.c_str (),
546 node_->type_c_str ()));
547 }
548
549 /*---
550 From strtol(3C) man page:
551
552 "Because 0 is returned on error and is also a valid return on
553 success, an application wishing to check for error situations
554 should set 'errno' to 0, then call strtol(3C), then check 'errno'
555 and if it is non-zero, assume an error has occured."
556 ---*/
557
558 switch (node_->m_type) {
559 case Option::string_t:
560 *(string*) node_->m_val = op_;
561 break;
562
563 case Option::int_t:
564 case Option::long_t:
565 errno = 0;
566 l = strtol (op_, NULL, 0);
567
568 if (errno != 0) {
569 m_error = "Error: '" + string (strerror (errno)) + "',";
570 m_error += " in converting to integer from '";
571 m_error += string (op_) + "'.";
572 return (false);
573 }
574
575 if (node_->m_type == Option::int_t) {
576 *(int*) node_->m_val = int (l);
577 }
578 else {
579 *(long*) node_->m_val = l;
580 }
581 break;
582
583 case Option::uint_t:
584 case Option::ulong_t:
585 errno = 0;
586 l = strtol (op_, NULL, 0);
587
588 if (errno != 0) {
589 m_error = "Error: '" + string (strerror (errno)) + "',";
590 m_error += " in converting to unsigned integer from '";
591 m_error += string (op_) + "'.";
592 return (false);
593 }
594
595 if (node_->m_type == Option::uint_t) {
596 *(unsigned int*) node_->m_val = int (l);
597 }
598 else {
599 *(unsigned long*) node_->m_val = l;
600 }
601 break;
602
603 case Option::double_t:
604 case Option::float_t:
605 errno = 0;
606 d = strtod (op_, NULL);
607
608 if (errno != 0) {
609 m_error = "Error: '" + string (strerror (errno)) + "',";
610 m_error += " in converting to double/float from '";
611 m_error += string (op_) + "'.";
612 return (false);
613 }
614
615 if (node_->m_type == Option::double_t) {
616 *(double*) node_->m_val = d;
617 }
618 else {
619 *(float*) node_->m_val = float (d);
620 }
621 break;
622
623 case Option::flag_t:
624 *(bool*) node_->m_val = true; // no more flipping!
625 break;
626
627 case Option::func_t:
628 (*(OPTS_FUNC)(node_->m_val)) ();
629 break;
630
632 (*(OPTS_FUNC_ONE)(node_->m_val)) (op_);
633 break;
634
635 case Option::none_t:
636 default:
637 m_error = "Undefined type for option '"+string (op_)+"'.";
638 return (false);
639 } /*-- switch () --*/
640
641 return (true);
642}
643
644void
646dump () const
647{
648 OptionSet::const_iterator i;
649
650 for (i = m_opts_set.begin (); i != m_opts_set.end (); i++) {
651 i->dump ();
652 }
653
654 if (!m_error.empty ()) {
655 DL((CMDLINEOPTS, "Last error: '%s'\n", m_error.c_str ()));
656 }
657}
658
659void
661str_to_argv (const string& src_, int& argc_, char**& argv_)
662{
663 trace_with_mask ("CmdLineOpts::str_to_argv", CMDLINEOPTS);
664
665 std::vector<string> vs;
666 std::istringstream input (src_);
667 std::string token;
668
669 while (input >> token) {
670 vs.push_back (token);
671 token = "";
672 }
673 int i = 0;
674 char* p;
675
676 if (vs.size ()) {
677 argv_ = new char* [vs.size() + 1];
678 std::vector<string>::iterator it;
679
680 for (it = vs.begin (); it != vs.end (); it++, i++) {
681 p = new char [it->size() + 1];
682 strcpy (p, it->c_str ());
683 p[it->size()] = '\0';
684 argv_[i] = p;
685 }
686 argv_[i] = NULL;
687 }
688 argc_ = i;
689}
690
691void
693free_argv (char**& argv_)
694{
695 trace_with_mask ("CmdLineOpts::free_argv", CMDLINEOPTS);
696
697 /* If argument is empty (which should never be the case),
698 * then freeing the memory would core dump application.
699 */
700 if (argv_ == NULL) {
701 return;
702 }
703
704 for (int i = 0; argv_[i]; i++) {
705 delete [] argv_[i];
706 }
707 delete [] argv_;
708 argv_ = NULL;
709}
710
Class to handle processing command-line options.
A Windows-style INI configuration file management class.
An abstraction to message logging facility.
#define DL(X)
A macro for writing debug message to the Logger.
Definition Logger.h:273
#define trace_with_mask(s, m)
trace_with_mask() is used to trace function call chain in C++ program.
Definition Logger.h:437
A wrapper class to provide AutoPtr with reference semantics.
Definition AutoPtr.h:32
Option * find_option(const char *str_)
Locate option in the options set.
string m_error
Last reported error.
bool parse_args(const char *argv[])
Parse command line arguments based on installed options set.
void(* OPTS_FUNC)(void)
void(* OPTS_FUNC_ONE)(const string &)
void set_error_none()
Reset error message to an empty string.
bool add_opt(const char c, const string &s, string *str)
Add an option with STL string argument.
bool rm_opt(const char c_, const string &s_)
Remove option for the option list.
OptionSet m_opts_set
Options set.
bool add_flag_opt(const char c, const string &s, bool *f)
Add binary flag option.
bool assign(Option *node_, const char *op_)
Perform value assignment to the node.
int parse_config_file(IniFile &inifile_)
Parse configuration parameters found in [options] section of the INI file.
virtual void pos_arg(const char *arg_)
Process positional argument arg_.
static void str_to_argv(const string &src_, int &argc_, char **&argv_)
Static function.
void dump() const
Write options set to the log file.
static void free_argv(char **&argv_)
Free up memory allocated by str_to_argv() function
bool is_valid(const char sopt_, const string &lopt_)
Detect if supplied option is valid.
Option class.
Definition CmdLineOpts.h:39
@ func_one_t
Convert argument to function with one argument
Definition CmdLineOpts.h:57
@ func_t
Convert argument to function
Definition CmdLineOpts.h:56
@ string_t
Convert argument to STL string
Definition CmdLineOpts.h:48
@ ulong_t
Convert argument to unsigned long
Definition CmdLineOpts.h:52
@ float_t
Convert argument to float
Definition CmdLineOpts.h:54
@ long_t
Convert argument to long
Definition CmdLineOpts.h:51
@ double_t
Convert argument to double
Definition CmdLineOpts.h:53
@ flag_t
No argument; bool value is flipped.
Definition CmdLineOpts.h:55
@ int_t
Convert argument to int
Definition CmdLineOpts.h:49
@ uint_t
Convert argument to unsigned int
Definition CmdLineOpts.h:50
type_t m_type
Option type.
Definition CmdLineOpts.h:82
string m_long_name
Long option name.
Definition CmdLineOpts.h:79
void * m_val
Pointer to the option value.
Definition CmdLineOpts.h:85
void dump() const
Write object state to the log file.
const char * type_c_str()
Return the type of the Option object.
char m_short_name
One-letter option name.
Definition CmdLineOpts.h:76
void find_and_replace_char(std::string &text_, char src_, char dest_)
Find and relpace all instances of src_ character with dest_ character in a string text_.
@ CMDLINEOPTS
Class CmdLineOpts messages
Definition LogMask.h:36