00001 /* 00002 ------------------------------------------------------------------- 00003 00004 Copyright (C) 2006, 2007, 2008, 2009, Andrew W. Steiner 00005 00006 This file is part of O2scl. 00007 00008 O2scl is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 3 of the License, or 00011 (at your option) any later version. 00012 00013 O2scl is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with O2scl. If not, see <http://www.gnu.org/licenses/>. 00020 00021 ------------------------------------------------------------------- 00022 */ 00023 #ifndef O2SCL_CLI_H 00024 #define O2SCL_CLI_H 00025 00026 #include <iostream> 00027 #include <vector> 00028 #include <algorithm> 00029 #include <sstream> 00030 00031 #include <o2scl/collection.h> 00032 #include <o2scl/columnify.h> 00033 00034 #ifndef DOXYGENP 00035 namespace o2scl { 00036 #endif 00037 00038 /** 00039 \brief Base for \ref cli command function 00040 00041 See the \ref cli class for more details. 00042 */ 00043 class comm_option_funct { 00044 00045 public: 00046 00047 comm_option_funct() {} 00048 00049 virtual ~comm_option_funct() {} 00050 00051 /// The basic function called by \ref cli 00052 virtual int operator()(std::vector<std::string> &cstr, bool itive_com) { 00053 return 0; 00054 } 00055 00056 #ifndef DOXYGENP 00057 00058 private: 00059 comm_option_funct(const comm_option_funct &); 00060 comm_option_funct& operator=(const comm_option_funct&); 00061 00062 #endif 00063 00064 }; 00065 00066 /// Member function pointer for \ref cli command function 00067 template<class tclass> class comm_option_mfptr : public comm_option_funct { 00068 00069 public: 00070 00071 /// Create from a member function pointer from the specified class 00072 comm_option_mfptr(tclass *tp, int (tclass::*fp)(std::vector<std::string> &, 00073 bool)) { 00074 tptr=tp; 00075 fptr=fp; 00076 } 00077 00078 virtual ~comm_option_mfptr() {} 00079 00080 /// The basic function called by \ref cli 00081 virtual int operator()(std::vector<std::string> &cstr, bool itive_com) { 00082 return (*tptr.*fptr)(cstr,itive_com); 00083 } 00084 00085 #ifndef DOXYGEN_INTERNAL 00086 00087 protected: 00088 00089 /// The pointer to the member function 00090 int (tclass::*fptr)(std::vector<std::string> &cstr, bool itive_com); 00091 00092 /// The pointer to the class 00093 tclass *tptr; 00094 00095 #endif 00096 00097 #ifndef DOXYGENP 00098 00099 private: 00100 comm_option_mfptr(const comm_option_mfptr &); 00101 comm_option_mfptr& operator=(const comm_option_mfptr&); 00102 00103 #endif 00104 00105 }; 00106 00107 /** 00108 \brief Command for interactive mode in \ref cli 00109 00110 See the \ref cli class for more details. 00111 */ 00112 typedef struct { 00113 00114 /// Short option (\c '\\0' for none, must be unique if present) 00115 char shrt; 00116 /// Long option (must be specified and must be unique) 00117 std::string lng; 00118 /// Description for help 00119 std::string desc; 00120 /// Minimum number of parameters (0 for none, -1 for variable) 00121 int min_parms; 00122 /// Maximum number of parameters (0 for none, -1 for variable) 00123 int max_parms; 00124 /// Description of parameters 00125 std::string parm_desc; 00126 /// The help description 00127 std::string help; 00128 /// The pointer to the function to be called (or 0 for no function) 00129 comm_option_funct *func; 00130 /// Type: command-line parameter, command, or both 00131 int type; 00132 00133 } comm_option_s; 00134 00135 #ifdef O2SCL_NEVER_DEFINED 00136 00137 // This was taken out because it wasn't really used, and 00138 // the comm_option_s struct was easier to use. 00139 00140 /** 00141 \brief Command for interactive mode in \ref cli 00142 00143 See the \ref cli class for more details. 00144 */ 00145 class comm_option : public comm_option_s { 00146 00147 public: 00148 00149 comm_option() { 00150 shrt=0; 00151 lng=""; 00152 desc=""; 00153 min_parms=0; 00154 max_parms=0; 00155 parm_desc=""; 00156 help=""; 00157 func=0; 00158 type=command; 00159 } 00160 00161 /// Create an option from a structure 00162 comm_option(comm_option_s c) { 00163 shrt=c.shrt; 00164 lng=c.lng; 00165 desc=c.desc; 00166 min_parms=c.min_parms; 00167 max_parms=c.max_parms; 00168 parm_desc=c.parm_desc; 00169 help=c.help; 00170 func=c.func; 00171 type=c.type; 00172 } 00173 00174 /// \name Possible values of ::type 00175 //@{ 00176 static const int command=0; 00177 static const int cl_param=1; 00178 static const int both=2; 00179 //@} 00180 00181 }; 00182 #endif 00183 00184 /** \brief A command-line argument for \ref cli 00185 */ 00186 typedef struct { 00187 /// The argument 00188 std::string arg; 00189 /// Is an option? 00190 bool is_option; 00191 /// Is a properly formatted option 00192 bool is_valid; 00193 /// List of parameters (empty, unless it's an option) 00194 std::vector<std::string> parms; 00195 /// A pointer to the appropriate (0, unless it's an option) 00196 comm_option_s *cop; 00197 } cmd_line_arg; 00198 00199 /** 00200 \brief Configurable command-line interface 00201 00202 This class is experimental. 00203 00204 Default commands: help, get/set, quit, exit, '!', verbose, license, 00205 warranty, alias, run. 00206 00207 Note that if the shell command is allowed (as it is by default) 00208 there are some potential security issues which are not 00209 solved here. 00210 00211 Commands which begin with a '#' character are ignored. 00212 00213 \todo There are some fixme entries in cli.cpp associated 00214 with when cop is zero 00215 \todo Only add get() and set() commands if some parameters 00216 are set 00217 \future Include a "remove command" function 00218 */ 00219 class cli { 00220 00221 #ifndef DOXYGEN_INTERNAL 00222 00223 protected: 00224 00225 static const int comm_option_command=0; 00226 static const int comm_option_cl_param=1; 00227 static const int comm_option_both=2; 00228 00229 /// Replace all occurences of \c sold with \c snew in \c s 00230 int apply_alias(std::string &s, std::string sold, std::string snew); 00231 00232 /// Separate a string into words 00233 int separate(std::string str, std::vector<std::string> &sv); 00234 00235 /// Control screen output 00236 int verbose; 00237 00238 /// Pointer to collection for parameters 00239 collection *cop; 00240 00241 /// \name The hard-coded command functions 00242 //@{ 00243 int comm_option_run(std::vector<std::string> &sv, bool itive_com); 00244 int comm_option_get(std::vector<std::string> &sv, bool itive_com); 00245 int comm_option_set(std::vector<std::string> &sv, bool itive_com); 00246 int comm_option_help(std::vector<std::string> &sv, bool itive_com); 00247 int comm_option_license(std::vector<std::string> &sv, bool itive_com); 00248 int comm_option_warranty(std::vector<std::string> &sv, bool itive_com); 00249 int comm_option_no_intro(std::vector<std::string> &sv, bool itive_com); 00250 int comm_option_commands(std::vector<std::string> &sv, bool itive_com); 00251 int comm_option_alias(std::vector<std::string> &sv, bool itive_com); 00252 //@} 00253 00254 /// Storage for getline 00255 char buf[300]; 00256 00257 /// Storage for the function to call after setting a parameter 00258 comm_option_funct *user_set_func; 00259 00260 /// List of commands 00261 std::vector<comm_option_s *> clist; 00262 00263 /// \name Help for parameters 00264 //@{ 00265 std::vector<std::string> ph_name, ph_desc; 00266 //@} 00267 00268 /// \name Aliases 00269 //@{ 00270 std::vector<std::string> al1, al2; 00271 //@} 00272 00273 /// Compare two strings, treating dashes as underscores 00274 bool string_equal(std::string s1, std::string s2); 00275 00276 #endif 00277 00278 public: 00279 00280 cli(); 00281 00282 virtual ~cli(); 00283 00284 /** \brief If true, output the usual GNU intro when run_interactive() 00285 is called. 00286 00287 In order to conform to GNU standards, this ought not be set to 00288 false by default. 00289 */ 00290 bool gnu_intro; 00291 00292 /// Function to call when a \c set command is issued 00293 int set_function(comm_option_funct &usf) { 00294 user_set_func=&usf; 00295 return 0; 00296 } 00297 00298 /// \name The hard-coded command objects 00299 //@{ 00300 comm_option_s c_commands; 00301 comm_option_s c_help; 00302 comm_option_s c_quit; 00303 comm_option_s c_exit; 00304 comm_option_s c_license; 00305 comm_option_s c_warranty; 00306 comm_option_s c_set; 00307 comm_option_s c_get; 00308 comm_option_s c_run; 00309 comm_option_s c_no_intro; 00310 comm_option_s c_alias; 00311 //@} 00312 00313 /// If true, then sync ::verbose, with a parameter of the same name 00314 bool sync_verbose; 00315 00316 /** \brief If true, allow the user to use ! to execute a shell command 00317 (default true) 00318 */ 00319 bool shell_cmd_allowed; 00320 00321 /// The prompt (default \c "> ") 00322 std::string prompt; 00323 00324 /// A one- or two-line description (default is empty string) 00325 std::string desc; 00326 00327 /// The name of the command 00328 std::string cmd_name; 00329 00330 /// Additional help text for interactive mode (default is empty string) 00331 std::string addl_help_cmd; 00332 00333 /// Additional help text for command-line (default is empty string) 00334 std::string addl_help_cli; 00335 00336 /// \name Basic operation 00337 //@{ 00338 /** 00339 \brief Add a new command 00340 00341 Each command/option must have either a short form in 00342 comm_option_s::shrt or a long from in comm_option_s::lng, 00343 which is unique from the other commands/options already 00344 present. You cannot add two commands/options with the same 00345 short form, even if they have different long forms, and vice 00346 versa. 00347 00348 */ 00349 int set_comm_option(comm_option_s &ic); 00350 00351 /// Add a vector containing new commands 00352 template<class vec_t> int set_comm_option_vec(size_t nic, vec_t &ic) { 00353 for(size_t k=0;k<nic;k++) { 00354 bool found=false; 00355 for(size_t i=0;found==false && i<clist.size();i++) { 00356 if ((ic[k].shrt!=0 && clist[i]->shrt==ic[k].shrt) || 00357 (ic[k].lng.length()>0 && clist[i]->lng==ic[k].lng)) { 00358 found=true; 00359 } 00360 } 00361 if (found==true) { 00362 if (ic[k].shrt!=0) { 00363 std::string err="Option "; 00364 err+=ic[k].shrt; 00365 err+=((std::string)" , ")+ic[k].lng+" already present."; 00366 O2SCL_ERR_RET(err.c_str(),gsl_einval); 00367 } else { 00368 std::string err="Option "; 00369 err+=ic[k].lng+" already present."; 00370 O2SCL_ERR_RET(err.c_str(),gsl_einval); 00371 } 00372 } 00373 comm_option_s *p=&(ic[k]); 00374 clist.push_back(p); 00375 } 00376 return 0; 00377 } 00378 00379 /// Set the parameters with a collection 00380 int set_parameters(collection &co); 00381 00382 /// Set one-line help text for a parameter named \c param 00383 int set_param_help(std::string param, std::string help); 00384 00385 /** \brief Automatically parse arguments to main and 00386 call interactive mode if required 00387 */ 00388 int run_auto(int argv, const char *argc[]) { 00389 int ret; 00390 00391 std::vector<cmd_line_arg> ca; 00392 00393 // --------------------------------------- 00394 // Process command-line options 00395 00396 ret=process_args(argv,argc,ca); 00397 if (ret!=0) { 00398 O2SCL_ERR_RET("Failed to process command-line in cli::run_auto().", 00399 gsl_efailed); 00400 } 00401 00402 if (ca.size()<1) { 00403 00404 ret=run_interactive(); 00405 if (ret!=0) { 00406 O2SCL_ERR_RET 00407 ("Failed to run interactive mode in cli::run_auto().", 00408 gsl_efailed); 00409 } 00410 } else { 00411 ret=call_args(ca); 00412 if (ret!=0) { 00413 O2SCL_ERR_RET("Function call_args() failed in cli::run_auto().", 00414 gsl_efailed); 00415 } 00416 } 00417 return gsl_success; 00418 } 00419 00420 //@} 00421 00422 /** \brief The function which obtains input from the user 00423 00424 \todo Should this be protected? 00425 00426 */ 00427 virtual char *cli_gets(const char *c) { 00428 std::cout << c << std::flush; 00429 std::cin.getline(buf,300); 00430 return buf; 00431 } 00432 00433 /// Call functions corresponding to command-line args 00434 int call_args(std::vector<cmd_line_arg> &ca); 00435 00436 /// Process command-line arguments from a const char array 00437 int process_args(int argv, const char *argc[], 00438 std::vector<cmd_line_arg> &ca, int debug=0); 00439 00440 /// Process command-line arguments from a string 00441 int process_args(std::string s, std::vector<cmd_line_arg> &ca, 00442 int debug=0) { 00443 std::vector<std::string> sv; 00444 separate(s,sv); 00445 int argv=sv.size(); 00446 const char **argc=new const char *[argv]; 00447 for(int i=0;i<argv;i++) argc[i]=sv[i].c_str(); 00448 int ret=process_args(argv,argc,ca,debug); 00449 delete[] argc; 00450 return ret; 00451 } 00452 00453 /** 00454 \brief Set verbosity 00455 00456 Most errors are output to the screen even if verbose is zero. 00457 */ 00458 int set_verbose(int v); 00459 00460 /// Run the interactive mode 00461 int run_interactive(); 00462 00463 /// Create a new command 00464 // int replace_command(comm_option &ic); 00465 00466 /** 00467 \brief Set an alias \c alias for the string \c str 00468 00469 Aliases can also be set using the command \c 'alias', but 00470 that version allows only one-word aliases. 00471 */ 00472 int set_alias(std::string alias, std::string str) { 00473 al1.push_back(alias); 00474 al2.push_back(str); 00475 return 0; 00476 } 00477 00478 }; 00479 00480 #ifndef DOXYGENP 00481 } 00482 #endif 00483 00484 #endif
Documentation generated with Doxygen and provided under the GNU Free Documentation License. See License Information for details.
Project hosting provided by
,
O2scl Sourceforge Project Page