00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <errno.h>
00015 #include <string.h>
00016 #include <stdlib.h>
00017
00018 #include <sstream>
00019 #include <iomanip>
00020
00021 #include "assa/Logger.h"
00022 #include "assa/CmdLineOpts.h"
00023 #include "assa/CommonUtils.h"
00024 #include "assa/IniFile.h"
00025
00026 using namespace ASSA;
00027
00028 void
00029 Option::
00030 dump () const
00031 {
00032 std::ostringstream msg;
00033
00034 if (m_short_name != 0) {
00035 msg << "-" << m_short_name << ", ";
00036 }
00037 else {
00038 msg << " ";
00039 }
00040
00041 if (m_long_name.size ()) {
00042 msg << "--" << std::setiosflags (std::ios::left)
00043 << std::setw(14) << m_long_name.c_str () << ' ';
00044 }
00045 else {
00046 msg << std::setiosflags (std::ios::left) << std::setw (14) << " ";
00047 }
00048 msg << '[';
00049
00050 switch (m_type)
00051 {
00052 case Option::string_t:
00053 msg << std::setiosflags (std::ios::left) << std::setw(7) << "string";
00054 msg << "] = '" << *(string*) m_val << "'";
00055 break;
00056
00057 case Option::int_t:
00058 msg << std::setiosflags(std::ios::left) << std::setw(7) << "int";
00059 msg << "] = " << *(int*) m_val;
00060 break;
00061
00062 case Option::uint_t:
00063 msg << std::setiosflags(std::ios::left) << std::setw(7) << "u_int";
00064 msg << "] = " << *(int*) m_val;
00065 break;
00066
00067 case Option::long_t:
00068 msg << std::setiosflags(std::ios::left) << std::setw(7) << "long";
00069 msg << "] = " << *(long*) m_val;
00070 break;
00071
00072 case Option::ulong_t:
00073 msg << std::setiosflags(std::ios::left) << std::setw(7) << "u_long";
00074 msg << "] = " << *(long*) m_val;
00075 break;
00076
00077 case Option::double_t:
00078 msg << std::setiosflags(std::ios::left) << std::setw(7) << "double";
00079 msg << "] = " << *(double*) m_val;
00080 break;
00081
00082 case Option::float_t:
00083 msg << std::setiosflags(std::ios::left) << std::setw(7) << "float";
00084 msg << "] = " << *(float*) m_val;
00085 break;
00086
00087 case Option::flag_t:
00088 msg << std::setiosflags(std::ios::left) << std::setw(7) << "bool";
00089 msg << "] = " << *(bool*) m_val ? "true" : "false";
00090 break;
00091
00092 case Option::func_t:
00093 msg << std::setiosflags(std::ios::left)
00094 << std::setw(7) << "function ()";
00095 msg << ']';
00096 break;
00097
00098 case Option::func_one_t:
00099 msg << std::setiosflags(std::ios::left)
00100 << std::setw(7) << "function (opt)";
00101 msg << ']';
00102 break;
00103
00104 case Option::none_t:
00105 msg << std::setiosflags(std::ios::left) << std::setw(7) << "none";
00106 msg << ']';
00107 break;
00108
00109 default:
00110 msg << std::setiosflags(std::ios::left)
00111 << std::setw(7) << "--undef--";
00112 msg << ']';
00113 }
00114 msg << std::ends;
00115 DL((CMDLINEOPTS,"%s\n", msg.str ().c_str ()));
00116 }
00117
00118 const char*
00119 Option::
00120 type_c_str ()
00121 {
00122 const char* ret;
00123
00124 switch (m_type)
00125 {
00126 case Option::string_t: ret = "string"; break;
00127 case Option::int_t: ret = "int"; break;
00128 case Option::uint_t: ret = "u_int"; break;
00129 case Option::long_t: ret = "long"; break;
00130 case Option::ulong_t: ret = "u_long"; break;
00131 case Option::double_t: ret = "double"; break;
00132 case Option::float_t: ret = "float"; break;
00133 case Option::flag_t: ret = "bool"; break;
00134 case Option::func_t: ret = "func()"; break;
00135 case Option::func_one_t: ret = "func(opt)"; break;
00136 case Option::none_t: ret = "none"; break;
00137 default: ret = "--undef--";
00138 }
00139 return (ret);
00140 }
00141
00142
00143 bool
00144 CmdLineOpts::
00145 is_valid (const char sopt_, const string& lopt_)
00146 {
00147 trace_with_mask ("CmdLineOpts::is_valid", CMDLINEOPTS);
00148
00149 set_error_none ();
00150 OptionSet::const_iterator i;
00151
00152 for (i = m_opts_set.begin (); i != m_opts_set.end (); i++) {
00153 if (sopt_ == '\0' && lopt_.empty ()) {
00154 m_error = "Ignore empty option";
00155 return (false);
00156 }
00157 else if (sopt_ != '\0' && i->m_short_name == sopt_) {
00158 m_error = "Ignored multiple option '-";
00159 m_error += sopt_ + string ("'");
00160 return (false);
00161 }
00162 else if (!lopt_.empty () && i->m_long_name == lopt_) {
00163 m_error = "Ignore multiple option '--";
00164 m_error += lopt_ + string ("'");
00165 return (false);
00166 }
00167 }
00168 return (true);
00169 }
00170
00171 Option*
00172 CmdLineOpts::
00173 find_option (const char* str_)
00174 {
00175 trace_with_mask ("CmdLineOpts::find_option(char*)", CMDLINEOPTS);
00176
00177 OptionSet::iterator i;
00178
00179 for ( i = m_opts_set.begin (); i != m_opts_set.end (); i++)
00180 {
00181 if (i->m_long_name == str_) {
00182 return &(*i);
00183 }
00184 }
00185 return (NULL);
00186 }
00187
00188 Option*
00189 CmdLineOpts::
00190 find_option (const char letter_)
00191 {
00192 trace_with_mask ("CmdLineOpts::find_option(char)", CMDLINEOPTS);
00193
00194 OptionSet::iterator i;
00195
00196 for (i = m_opts_set.begin (); i != m_opts_set.end (); i++)
00197 {
00198 if (i->m_short_name == letter_)
00199 return &(*i);
00200 }
00201 return (NULL);
00202 }
00203
00204 bool
00205 CmdLineOpts::
00206 add_flag_opt (const char sopt_, const string& lopt_, bool* v_)
00207 {
00208 trace_with_mask ("CmdLineOpts::add_flag_opt", CMDLINEOPTS);
00209
00210 if (!is_valid (sopt_, lopt_))
00211 return (false);
00212
00213 Option o (sopt_, lopt_, Option::flag_t, (void*) v_);
00214 m_opts_set.push_back (o);
00215 return (true);
00216 }
00217
00218 bool
00219 CmdLineOpts::
00220 add_opt (const char sopt_, const string& lopt_, string* v_)
00221 {
00222 trace_with_mask ("CmdLineOpts::add_opt(string*)", CMDLINEOPTS);
00223
00224 if (!is_valid (sopt_, lopt_))
00225 return (false);
00226
00227 Option o (sopt_, lopt_, Option::string_t, (void*) v_);
00228 m_opts_set.push_back (o);
00229 return (true);
00230 }
00231
00232 bool
00233 CmdLineOpts::
00234 add_opt (const char sopt_, const string& lopt_, int* v_)
00235 {
00236 trace_with_mask ("CmdLineOpts::add_opt(int*)", CMDLINEOPTS);
00237
00238 if (!is_valid (sopt_, lopt_)) {
00239 return (false);
00240 }
00241 Option o (sopt_, lopt_, Option::int_t, (void*) v_);
00242 m_opts_set.push_back (o);
00243 return (true);
00244 }
00245
00246 bool
00247 CmdLineOpts::
00248 add_opt (const char sopt_, const string& lopt_, unsigned int* v_)
00249 {
00250 trace_with_mask ("CmdLineOpts::add_opt(u_int*)", CMDLINEOPTS);
00251
00252 if (!is_valid (sopt_, lopt_)) {
00253 return (false);
00254 }
00255 Option o (sopt_, lopt_, Option::uint_t, (void*) v_);
00256 m_opts_set.push_back (o);
00257 return (true);
00258 }
00259
00260 bool
00261 CmdLineOpts::
00262 add_opt (const char sopt_, const string& lopt_, long* v_)
00263 {
00264 trace_with_mask ("CmdLineOpts::add_opt(long*)", CMDLINEOPTS);
00265
00266 if (!is_valid (sopt_, lopt_)) {
00267 return (false);
00268 }
00269 Option o (sopt_, lopt_, Option::long_t, (void*) v_);
00270 m_opts_set.push_back (o);
00271 return (true);
00272 }
00273
00274 bool
00275 CmdLineOpts::
00276 add_opt (const char sopt_, const string& lopt_, unsigned long* v_)
00277 {
00278 trace_with_mask ("CmdLineOpts::add_opt(u_long*)", CMDLINEOPTS);
00279
00280 if (!is_valid (sopt_, lopt_)) {
00281 return (false);
00282 }
00283 Option o (sopt_, lopt_, Option::long_t, (void*) v_);
00284 m_opts_set.push_back (o);
00285 return (true);
00286 }
00287
00288 bool
00289 CmdLineOpts::
00290 add_opt (const char sopt_, const string& lopt_, double* v_)
00291 {
00292 trace_with_mask ("CmdLineOpts::add_opt(double*)", CMDLINEOPTS);
00293
00294 if (!is_valid (sopt_, lopt_)) {
00295 return (false);
00296 }
00297 Option o (sopt_, lopt_, Option::double_t, (void*) v_);
00298 m_opts_set.push_back (o);
00299 return (true);
00300 }
00301
00302 bool
00303 CmdLineOpts::
00304 add_opt (const char sopt_, const string& lopt_, float* v_)
00305 {
00306 trace_with_mask ("CmdLineOpts::add_opt(float*)", CMDLINEOPTS);
00307
00308 if (!is_valid (sopt_, lopt_)) {
00309 return (false);
00310 }
00311 Option o (sopt_, lopt_, Option::float_t, (void*) v_);
00312 m_opts_set.push_back (o);
00313 return (true);
00314 }
00315
00316 bool
00317 CmdLineOpts::
00318 add_opt (const char sopt_, const string& lopt_, OPTS_FUNC v_)
00319 {
00320 trace_with_mask ("CmdLineOpts::add_opt(OPTS_FUNC)", CMDLINEOPTS);
00321
00322 if (!is_valid (sopt_, lopt_)) {
00323 return (false);
00324 }
00325 Option o (sopt_, lopt_, Option::func_t, (void*) v_);
00326 m_opts_set.push_back (o);
00327 return (true);
00328 }
00329
00330 bool
00331 CmdLineOpts::
00332 add_opt (const char sopt_, const string& lopt_, OPTS_FUNC_ONE v_)
00333 {
00334 trace_with_mask ("CmdLineOpts::add_opt(OPTS_FUNC_ONE)", CMDLINEOPTS);
00335
00336 if (!is_valid (sopt_, lopt_)) {
00337 return (false);
00338 }
00339 Option o (sopt_, lopt_, Option::func_one_t, (void*) v_);
00340 m_opts_set.push_back (o);
00341 return (true);
00342 }
00343
00344 bool
00345 CmdLineOpts::
00346 rm_opt (const char sopt_, const string& lopt_)
00347 {
00348 trace_with_mask ("CmdLineOpts::rm_opt(string&)", CMDLINEOPTS);
00349
00350 OptionSet::iterator i;
00351
00352 for (i = m_opts_set.begin (); i != m_opts_set.end (); i++)
00353 {
00354 if (i->m_short_name == sopt_ || i->m_long_name == lopt_)
00355 {
00356 m_opts_set.erase (i);
00357 return (true);
00358 }
00359 }
00360 return (false);
00361 }
00362
00363 bool
00364 CmdLineOpts::
00365 parse_args (const char* argv_[])
00366 {
00367 trace_with_mask ("CmdLineOpts::parse_args", CMDLINEOPTS);
00368
00369 register int skip = 1;
00370 bool pos_args_started = false;
00371 string param ("");
00372 string token ("");
00373 set_error_none ();
00374 Option* node = (Option*) NULL;
00375
00376 for (argv_++; argv_[0]; argv_ += skip) {
00377 if (skip != 0) {
00378 token = argv_[0];
00379 }
00380
00381 DL((CMDLINEOPTS, "token: \"%s\"\n", token.c_str()));
00382
00383 if (pos_args_started) {
00384 DL((CMDLINEOPTS,"pos_args_started = true\n"));
00385
00386 if (token[0] == '-' && token.size () != 1) {
00387 m_error = "Invalid order of arguments: '";
00388 m_error += token + "'.";
00389 goto done;
00390 }
00391 pos_arg (token.c_str ());
00392 continue;
00393 }
00394 skip = 1;
00395
00396 if (token[0] == '-' && token.size () > 1 && token[1] != '-') {
00397 if (token.size () == 1 && !pos_args_started) {
00398 pos_arg (token.c_str ());
00399 pos_args_started = true;
00400 continue;
00401 }
00402
00403 if ((node = find_option (token[1])) != NULL) {
00404 if (token.size () > 2) {
00405 if (node->m_type == Option::flag_t ||
00406 node->m_type == Option::func_t)
00407 {
00408 token.erase (1, 1);
00409 skip = 0;
00410 }
00411 else {
00412 param = token.substr (2);
00413 }
00414 }
00415 }
00416 }
00417 else {
00418 if (token.size () > 1 && token[1] == '-') {
00419 string op = token.substr (2);
00420 size_t pos;
00421
00422 if ((pos = op.find ("=")) != (size_t)-1) {
00423 param = op.substr (pos+1, op.length ());
00424 op.replace (pos, op.length() - pos, "");
00425 }
00426 node = find_option (op.c_str ());
00427 }
00428 else {
00429 pos_arg (token.c_str ());
00430 pos_args_started = true;
00431 continue;
00432 }
00433 }
00434
00435 if (!node) {
00436 m_error = "Invalid option '" + token + "'.";
00437 goto done;
00438 }
00439
00440 if (node->m_type != Option::flag_t &&
00441 node->m_type != Option::func_t)
00442 {
00443 if (param.empty ()) {
00444 if (!argv_[1]) {
00445 m_error = "Expecting parameter after '"
00446 + string (argv_[0]) + "'.";
00447 goto done;
00448 }
00449 param = argv_[1];
00450 skip = 2;
00451 }
00452 }
00453
00454
00455
00456 if (!node) {
00457 goto done;
00458 }
00459
00460 if (param.empty ()) {
00461 if (!assign (node, argv_[1])) {
00462 return (false);
00463 }
00464 }
00465 else {
00466 const char* str = param.c_str ();
00467 if (!assign (node, str)) {
00468 return (false);
00469 }
00470 param = "";
00471 }
00472 }
00473
00474 done:
00475 return !m_error.empty () ? false : true;
00476 }
00477
00486 int
00487 CmdLineOpts::
00488 parse_config_file (IniFile& inifile_)
00489 {
00490 trace_with_mask ("CmdLineOpts::parse_config_file", CMDLINEOPTS);
00491
00492 unsigned int count = 0;
00493 string v;
00494 string s;
00495 OptionSet::iterator pos = m_opts_set.begin ();
00496
00497 if (inifile_.find_section ("options") == inifile_.sect_end ()) {
00498 m_error = "Missing [options] section in INI file!";
00499 return -1;
00500 }
00501
00502 while (pos != m_opts_set.end ()) {
00503 if (pos->m_long_name.size ()) {
00504 s = pos->m_long_name;
00505 ASSA::Utils::find_and_replace_char (s, '-', '_');
00506 DL ((CMDLINEOPTS, "trying option \"%s\"\n", s.c_str ()));
00507 v = inifile_.get_value ("options", s);
00508 if (v.size ()) {
00509 if (assign (&(*pos), v.c_str ())) {
00510 count++;
00511 }
00512 }
00513 }
00514 pos++;
00515 }
00516
00517 return (count);
00518 }
00519
00520 bool
00521 CmdLineOpts::
00522 assign (Option* node_, const char* op_)
00523 {
00524 trace_with_mask ("CmdLineOpts::assign", CMDLINEOPTS);
00525
00526 long l;
00527 double d;
00528
00529 if (node_ && op_) {
00530 DL ((CMDLINEOPTS, "Assign '%s' to {-%c, --%s, t=%s}\n",
00531 op_, node_->m_short_name, node_->m_long_name.c_str (),
00532 node_->type_c_str ()));
00533 }
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544 switch (node_->m_type) {
00545 case Option::string_t:
00546 *(string*) node_->m_val = op_;
00547 break;
00548
00549 case Option::int_t:
00550 case Option::long_t:
00551 errno = 0;
00552 l = strtol (op_, NULL, 0);
00553
00554 if (errno != 0) {
00555 m_error = "Error: '" + string (strerror (errno)) + "',";
00556 m_error += " in converting to integer from '";
00557 m_error += string (op_) + "'.";
00558 return (false);
00559 }
00560
00561 if (node_->m_type == Option::int_t) {
00562 *(int*) node_->m_val = int (l);
00563 }
00564 else {
00565 *(long*) node_->m_val = l;
00566 }
00567 break;
00568
00569 case Option::uint_t:
00570 case Option::ulong_t:
00571 errno = 0;
00572 l = strtol (op_, NULL, 0);
00573
00574 if (errno != 0) {
00575 m_error = "Error: '" + string (strerror (errno)) + "',";
00576 m_error += " in converting to unsinged integer from '";
00577 m_error += string (op_) + "'.";
00578 return (false);
00579 }
00580
00581 if (node_->m_type == Option::uint_t) {
00582 *(unsigned int*) node_->m_val = int (l);
00583 }
00584 else {
00585 *(unsigned long*) node_->m_val = l;
00586 }
00587 break;
00588
00589 case Option::double_t:
00590 case Option::float_t:
00591 errno = 0;
00592 d = strtod (op_, NULL);
00593
00594 if (errno != 0) {
00595 m_error = "Error: '" + string (strerror (errno)) + "',";
00596 m_error += " in converting to double/float from '";
00597 m_error += string (op_) + "'.";
00598 return (false);
00599 }
00600
00601 if (node_->m_type == Option::double_t) {
00602 *(double*) node_->m_val = d;
00603 }
00604 else {
00605 *(float*) node_->m_val = float (d);
00606 }
00607 break;
00608
00609 case Option::flag_t:
00610 *(bool*) node_->m_val = true;
00611 break;
00612
00613 case Option::func_t:
00614 (*(OPTS_FUNC)(node_->m_val)) ();
00615 break;
00616
00617 case Option::func_one_t:
00618 (*(OPTS_FUNC_ONE)(node_->m_val)) (op_);
00619 break;
00620
00621 case Option::none_t:
00622 default:
00623 m_error = "Undefined type for option '"+string (op_)+"'.";
00624 return (false);
00625 }
00626
00627 return (true);
00628 }
00629
00630 void
00631 CmdLineOpts::
00632 dump () const
00633 {
00634 OptionSet::const_iterator i;
00635
00636 for (i = m_opts_set.begin (); i != m_opts_set.end (); i++) {
00637 i->dump ();
00638 }
00639
00640 if (!m_error.empty ()) {
00641 DL((CMDLINEOPTS, "Last error: '%s'\n", m_error.c_str ()));
00642 }
00643 }
00644
00645 void
00646 CmdLineOpts::
00647 str_to_argv (const string& src_, int& argc_, char**& argv_)
00648 {
00649 trace_with_mask ("CmdLineOpts::str_to_argv", CMDLINEOPTS);
00650
00651 std::vector<string> vs;
00652 std::istringstream input (src_);
00653 std::string token;
00654
00655 while (input >> token) {
00656 vs.push_back (token);
00657 token = "";
00658 }
00659 int i = 0;
00660 char* p;
00661
00662 if (vs.size ()) {
00663 argv_ = new char* [vs.size() + 1];
00664 std::vector<string>::iterator it;
00665
00666 for (it = vs.begin (); it != vs.end (); it++, i++) {
00667 p = new char [it->size() + 1];
00668 strcpy (p, it->c_str ());
00669 p[it->size()] = '\0';
00670 argv_[i] = p;
00671 }
00672 argv_[i] = NULL;
00673 }
00674 argc_ = i;
00675 }
00676
00677 void
00678 CmdLineOpts::
00679 free_argv (char**& argv_)
00680 {
00681 trace_with_mask ("CmdLineOpts::free_argv", CMDLINEOPTS);
00682
00683
00684
00685
00686 if (argv_ == NULL) {
00687 return;
00688 }
00689
00690 for (int i = 0; argv_[i]; i++) {
00691 delete [] argv_[i];
00692 }
00693 delete [] argv_;
00694 argv_ = NULL;
00695 }
00696