libassa
3.5.0
|
00001 // -*- c++ -*- 00002 //------------------------------------------------------------------------------ 00003 // $Id: CmdLineOpts.cpp,v 1.7 2007/05/14 19:19:50 vlg Exp $ 00004 //------------------------------------------------------------------------------ 00005 // CmdLineOpts.cpp 00006 //------------------------------------------------------------------------------ 00007 // Copyright (C) 2000,2005,2007 Vladislav Grinchenko 00008 // 00009 // This library is free software; you can redistribute it and/or 00010 // modify it under the terms of the GNU Library General Public 00011 // License as published by the Free Software Foundation; either 00012 // version 2 of the License, or (at your option) any later version. 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 } // if (token.size()>2) 00415 } // if ((node = find_option ()) 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 } // if (token[0] == '-' && token[1] != '-') 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 * if positional arguments only 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 } // for (argv_++; argv_[0]; argv_ += skip) 00473 00474 done: 00475 return !m_error.empty () ? false : true; 00476 } 00477 00490 int 00491 CmdLineOpts:: 00492 parse_config_file (IniFile& inifile_) 00493 { 00494 trace_with_mask ("CmdLineOpts::parse_config_file", CMDLINEOPTS); 00495 00496 unsigned int count = 0; 00497 string v; 00498 string s; 00499 string optsect_name ("options"); 00500 OptionSet::iterator pos = m_opts_set.begin (); 00501 00502 if (inifile_.find_section (optsect_name) == inifile_.sect_end ()) 00503 { 00504 optsect_name = "Options"; 00505 if (inifile_.find_section (optsect_name) == inifile_.sect_end ()) 00506 { 00507 optsect_name = "OPTIONS"; 00508 if (inifile_.find_section (optsect_name) == inifile_.sect_end ()) 00509 { 00510 m_error = "Missing [options] section in INI file!"; 00511 return -1; 00512 } 00513 } 00514 } 00515 00516 while (pos != m_opts_set.end ()) { 00517 if (pos->m_long_name.size ()) { 00518 s = pos->m_long_name; 00519 ASSA::Utils::find_and_replace_char (s, '-', '_'); 00520 DL ((CMDLINEOPTS, "trying option \"%s\"\n", s.c_str ())); 00521 v = inifile_.get_value (optsect_name, s); 00522 if (v.size ()) { 00523 if (assign (&(*pos), v.c_str ())) { 00524 count++; 00525 } 00526 } 00527 } 00528 pos++; 00529 } 00530 00531 return (count); 00532 } 00533 00534 bool 00535 CmdLineOpts:: 00536 assign (Option* node_, const char* op_) 00537 { 00538 trace_with_mask ("CmdLineOpts::assign", CMDLINEOPTS); 00539 00540 long l; 00541 double d; 00542 00543 if (node_ && op_) { 00544 DL ((CMDLINEOPTS, "Assign '%s' to {-%c, --%s, t=%s}\n", 00545 op_, node_->m_short_name, node_->m_long_name.c_str (), 00546 node_->type_c_str ())); 00547 } 00548 00549 /*--- 00550 From strtol(3C) man page: 00551 00552 "Because 0 is returned on error and is also a valid return on 00553 success, an application wishing to check for error situations 00554 should set 'errno' to 0, then call strtol(3C), then check 'errno' 00555 and if it is non-zero, assume an error has occured." 00556 ---*/ 00557 00558 switch (node_->m_type) { 00559 case Option::string_t: 00560 *(string*) node_->m_val = op_; 00561 break; 00562 00563 case Option::int_t: 00564 case Option::long_t: 00565 errno = 0; 00566 l = strtol (op_, NULL, 0); 00567 00568 if (errno != 0) { 00569 m_error = "Error: '" + string (strerror (errno)) + "',"; 00570 m_error += " in converting to integer from '"; 00571 m_error += string (op_) + "'."; 00572 return (false); 00573 } 00574 00575 if (node_->m_type == Option::int_t) { 00576 *(int*) node_->m_val = int (l); 00577 } 00578 else { 00579 *(long*) node_->m_val = l; 00580 } 00581 break; 00582 00583 case Option::uint_t: 00584 case Option::ulong_t: 00585 errno = 0; 00586 l = strtol (op_, NULL, 0); 00587 00588 if (errno != 0) { 00589 m_error = "Error: '" + string (strerror (errno)) + "',"; 00590 m_error += " in converting to unsinged integer from '"; 00591 m_error += string (op_) + "'."; 00592 return (false); 00593 } 00594 00595 if (node_->m_type == Option::uint_t) { 00596 *(unsigned int*) node_->m_val = int (l); 00597 } 00598 else { 00599 *(unsigned long*) node_->m_val = l; 00600 } 00601 break; 00602 00603 case Option::double_t: 00604 case Option::float_t: 00605 errno = 0; 00606 d = strtod (op_, NULL); 00607 00608 if (errno != 0) { 00609 m_error = "Error: '" + string (strerror (errno)) + "',"; 00610 m_error += " in converting to double/float from '"; 00611 m_error += string (op_) + "'."; 00612 return (false); 00613 } 00614 00615 if (node_->m_type == Option::double_t) { 00616 *(double*) node_->m_val = d; 00617 } 00618 else { 00619 *(float*) node_->m_val = float (d); 00620 } 00621 break; 00622 00623 case Option::flag_t: 00624 *(bool*) node_->m_val = true; // no more flipping! 00625 break; 00626 00627 case Option::func_t: 00628 (*(OPTS_FUNC)(node_->m_val)) (); 00629 break; 00630 00631 case Option::func_one_t: 00632 (*(OPTS_FUNC_ONE)(node_->m_val)) (op_); 00633 break; 00634 00635 case Option::none_t: 00636 default: 00637 m_error = "Undefined type for option '"+string (op_)+"'."; 00638 return (false); 00639 } /*-- switch () --*/ 00640 00641 return (true); 00642 } 00643 00644 void 00645 CmdLineOpts:: 00646 dump () const 00647 { 00648 OptionSet::const_iterator i; 00649 00650 for (i = m_opts_set.begin (); i != m_opts_set.end (); i++) { 00651 i->dump (); 00652 } 00653 00654 if (!m_error.empty ()) { 00655 DL((CMDLINEOPTS, "Last error: '%s'\n", m_error.c_str ())); 00656 } 00657 } 00658 00659 void 00660 CmdLineOpts:: 00661 str_to_argv (const string& src_, int& argc_, char**& argv_) 00662 { 00663 trace_with_mask ("CmdLineOpts::str_to_argv", CMDLINEOPTS); 00664 00665 std::vector<string> vs; 00666 std::istringstream input (src_); 00667 std::string token; 00668 00669 while (input >> token) { 00670 vs.push_back (token); 00671 token = ""; 00672 } 00673 int i = 0; 00674 char* p; 00675 00676 if (vs.size ()) { 00677 argv_ = new char* [vs.size() + 1]; 00678 std::vector<string>::iterator it; 00679 00680 for (it = vs.begin (); it != vs.end (); it++, i++) { 00681 p = new char [it->size() + 1]; 00682 strcpy (p, it->c_str ()); 00683 p[it->size()] = '\0'; 00684 argv_[i] = p; 00685 } 00686 argv_[i] = NULL; 00687 } 00688 argc_ = i; 00689 } 00690 00691 void 00692 CmdLineOpts:: 00693 free_argv (char**& argv_) 00694 { 00695 trace_with_mask ("CmdLineOpts::free_argv", CMDLINEOPTS); 00696 00697 /* If argument is empty (which should never be the case), 00698 * then freeing the memory would core dump application. 00699 */ 00700 if (argv_ == NULL) { 00701 return; 00702 } 00703 00704 for (int i = 0; argv_[i]; i++) { 00705 delete [] argv_[i]; 00706 } 00707 delete [] argv_; 00708 argv_ = NULL; 00709 } 00710