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 }; 00057 00058 /// Member function pointer for \ref cli command function 00059 template<class tclass> class comm_option_mfptr : public comm_option_funct { 00060 00061 public: 00062 00063 /// Create from a member function pointer from the specified class 00064 comm_option_mfptr(tclass *tp, int (tclass::*fp)(std::vector<std::string> &, 00065 bool)) { 00066 tptr=tp; 00067 fptr=fp; 00068 } 00069 00070 virtual ~comm_option_mfptr() {} 00071 00072 /// The basic function called by \ref cli 00073 virtual int operator()(std::vector<std::string> &cstr, bool itive_com) { 00074 return (*tptr.*fptr)(cstr,itive_com); 00075 } 00076 00077 #ifndef DOXYGEN_INTERNAL 00078 00079 protected: 00080 00081 /// The pointer to the member function 00082 int (tclass::*fptr)(std::vector<std::string> &cstr, bool itive_com); 00083 00084 /// The pointer to the class 00085 tclass *tptr; 00086 00087 /// Copy constructor 00088 comm_option_mfptr(const comm_option_mfptr &f) { 00089 fptr=f.fptr; 00090 tptr=f.tptr; 00091 } 00092 00093 /// Copy constructor 00094 comm_option_mfptr& operator=(const comm_option_mfptr &f) { 00095 fptr=f.fptr; 00096 tptr=f.tptr; 00097 return *this; 00098 } 00099 00100 #endif 00101 00102 }; 00103 00104 /** 00105 \brief Command for interactive mode in \ref cli 00106 00107 See the \ref cli class for more details. 00108 00109 \comment 00110 This was at one point converted into a call, but it wasn't that 00111 easy to use, in comparison to structs which are easy to 00112 initialize in aggregate. 00113 \endcomment 00114 */ 00115 typedef struct { 00116 00117 /// Short option (\c '\\0' for none, must be unique if present) 00118 char shrt; 00119 /// Long option (must be specified and must be unique) 00120 std::string lng; 00121 /// Description for help 00122 std::string desc; 00123 /// Minimum number of parameters (0 for none, -1 for variable) 00124 int min_parms; 00125 /// Maximum number of parameters (0 for none, -1 for variable) 00126 int max_parms; 00127 /// Description of parameters 00128 std::string parm_desc; 00129 /// The help description 00130 std::string help; 00131 /// The pointer to the function to be called (or 0 for no function) 00132 comm_option_funct *func; 00133 /// Type: command-line parameter, command, or both 00134 int type; 00135 00136 } comm_option_s; 00137 00138 /** \brief A command-line argument for \ref cli 00139 00140 This is the internal structure that \ref cli uses to package 00141 command-line arguments. 00142 */ 00143 typedef struct { 00144 /// The argument 00145 std::string arg; 00146 /// Is an option? 00147 bool is_option; 00148 /// Is a properly formatted option 00149 bool is_valid; 00150 /// List of parameters (empty, unless it's an option) 00151 std::vector<std::string> parms; 00152 /// A pointer to the appropriate option (0, unless it's an option) 00153 comm_option_s *cop; 00154 } cmd_line_arg; 00155 00156 /** 00157 \brief Configurable command-line interface 00158 00159 This class is experimental. 00160 00161 Default commands: help, get/set, quit, exit, '!', verbose, license, 00162 warranty, alias, run. 00163 00164 Note that if the shell command is allowed (as it is by default) 00165 there are some potential security issues which are not solved 00166 here. 00167 00168 Commands which begin with a '#' character are ignored. 00169 00170 \note In interactive mode, commands are limited to 300 characters. 00171 00172 \todo There are some fixme entries in cli.cpp associated 00173 with when cop is zero 00174 \todo Only add get() and set() commands if some parameters 00175 are set 00176 \todo Warn in run_interactive() when extra parameters are given 00177 \future Include a "remove command" function 00178 \future A replace command function, there's already some code 00179 in cli.cpp for this. 00180 \future There's some code duplication between comm_option_run() 00181 and run_interactive() 00182 \future Allow the user to set the tilde string 00183 00184 <b>Concepts</b> 00185 00186 As a matter of definition, the command-line arguments are simply 00187 called arguments. These arguments may be options (in which case 00188 they begin with either one dash or two) or parameters to these 00189 options. When run in interactive mode, these options are also 00190 commands. 00191 00192 */ 00193 class cli { 00194 00195 #ifndef DOXYGEN_INTERNAL 00196 00197 protected: 00198 00199 /// Desc 00200 int expand_tilde(std::vector<std::string> &sv); 00201 00202 /// Replace all occurences of \c sold with \c snew in \c sv 00203 int apply_alias(std::vector<std::string> &sv, 00204 std::string sold, std::string snew); 00205 00206 /** \brief Separate a string into words, handling quotes 00207 00208 This function separates a string into words, and handles 00209 words that begin with a <tt>"</tt> by adding more words 00210 until finding one which ends with a <tt>"</tt>. 00211 00212 This is used to reformat command descriptions and help text 00213 for the screen width in comm_option_help(), to process 00214 lines read from a file in comm_option_run(), and to process 00215 input in run_interactive(). 00216 */ 00217 int separate(std::string str, std::vector<std::string> &sv); 00218 00219 /// Control screen output 00220 int verbose; 00221 00222 /// Pointer to collection for parameters 00223 collection *cop; 00224 00225 /// \name The hard-coded command functions 00226 //@{ 00227 int comm_option_alias(std::vector<std::string> &sv, bool itive_com); 00228 int comm_option_commands(std::vector<std::string> &sv, bool itive_com); 00229 int comm_option_get(std::vector<std::string> &sv, bool itive_com); 00230 int comm_option_help(std::vector<std::string> &sv, bool itive_com); 00231 int comm_option_license(std::vector<std::string> &sv, bool itive_com); 00232 int comm_option_no_intro(std::vector<std::string> &sv, bool itive_com); 00233 int comm_option_run(std::vector<std::string> &sv, bool itive_com); 00234 int comm_option_set(std::vector<std::string> &sv, bool itive_com); 00235 int comm_option_warranty(std::vector<std::string> &sv, bool itive_com); 00236 //@} 00237 00238 /// Storage for getline 00239 char buf[300]; 00240 00241 /// Storage for the function to call after setting a parameter 00242 comm_option_funct *user_set_func; 00243 00244 /// List of commands 00245 std::vector<comm_option_s> clist; 00246 00247 /// \name Help for parameters 00248 //@{ 00249 std::vector<std::string> ph_name, ph_desc; 00250 //@} 00251 00252 /// \name Aliases 00253 //@{ 00254 std::vector<std::string> al1, al2; 00255 //@} 00256 00257 /// Compare two strings, treating dashes and underscores as equivalent 00258 bool string_equal_dash(std::string s1, std::string s2); 00259 00260 #endif 00261 00262 public: 00263 00264 cli(); 00265 00266 virtual ~cli(); 00267 00268 /// Desc 00269 std::string tilde_string; 00270 00271 /** \brief If true, output the usual GNU intro when run_interactive() 00272 is called. 00273 00274 In order to conform to GNU standards, this ought not be set to 00275 false by default. 00276 */ 00277 bool gnu_intro; 00278 00279 /// Function to call when a \c set command is issued 00280 int set_function(comm_option_funct &usf) { 00281 user_set_func=&usf; 00282 return 0; 00283 } 00284 00285 /// \name Value to indicate whether commands are also command-line options 00286 //@{ 00287 static const int comm_option_command=0; 00288 static const int comm_option_cl_param=1; 00289 static const int comm_option_both=2; 00290 //@} 00291 00292 /// \name The hard-coded command objects 00293 //@{ 00294 comm_option_s c_commands; 00295 comm_option_s c_help; 00296 comm_option_s c_quit; 00297 comm_option_s c_exit; 00298 comm_option_s c_license; 00299 comm_option_s c_warranty; 00300 comm_option_s c_set; 00301 comm_option_s c_get; 00302 comm_option_s c_run; 00303 comm_option_s c_no_intro; 00304 comm_option_s c_alias; 00305 //@} 00306 00307 /// If true, then sync ::verbose, with a parameter of the same name 00308 bool sync_verbose; 00309 00310 /** \brief If true, allow the user to use ! to execute a shell command 00311 (default true) 00312 */ 00313 bool shell_cmd_allowed; 00314 00315 /// The prompt (default <tt>"> "</tt>) 00316 std::string prompt; 00317 00318 /// A one- or two-line description (default is empty string) 00319 std::string desc; 00320 00321 /// The name of the command 00322 std::string cmd_name; 00323 00324 /// Additional help text for interactive mode (default is empty string) 00325 std::string addl_help_cmd; 00326 00327 /// Additional help text for command-line (default is empty string) 00328 std::string addl_help_cli; 00329 00330 /// \name Basic operation 00331 //@{ 00332 /** 00333 \brief Add a new command 00334 00335 Each command/option must have either a short form in 00336 comm_option_s::shrt or a long from in comm_option_s::lng, 00337 which is unique from the other commands/options already 00338 present. You cannot add two commands/options with the same 00339 short form, even if they have different long forms, and vice 00340 versa. 00341 00342 */ 00343 int set_comm_option(comm_option_s &ic); 00344 00345 /// Add a vector containing new commands 00346 template<class vec_t> int set_comm_option_vec(size_t nic, vec_t &ic) { 00347 for(size_t k=0;k<nic;k++) { 00348 bool found=false; 00349 for(size_t i=0;found==false && i<clist.size();i++) { 00350 if ((ic[k].shrt!=0 && clist[i].shrt==ic[k].shrt) || 00351 (ic[k].lng.length()>0 && clist[i].lng==ic[k].lng)) { 00352 found=true; 00353 } 00354 } 00355 if (found==true) { 00356 if (ic[k].shrt!=0) { 00357 std::string err="Option "; 00358 err+=ic[k].shrt; 00359 err+=((std::string)" , ")+ic[k].lng+" already present."; 00360 O2SCL_ERR_RET(err.c_str(),gsl_einval); 00361 } else { 00362 std::string err="Option "; 00363 err+=ic[k].lng+" already present."; 00364 O2SCL_ERR_RET(err.c_str(),gsl_einval); 00365 } 00366 } 00367 clist.push_back(ic[k]); 00368 } 00369 return 0; 00370 } 00371 00372 /// Set the parameters with a collection 00373 int set_parameters(collection &co); 00374 00375 /// Set one-line help text for a parameter named \c param 00376 int set_param_help(std::string param, std::string help); 00377 00378 /** \brief Automatically parse arguments to main and 00379 call interactive mode if required 00380 */ 00381 int run_auto(int argv, const char *argc[]) { 00382 int ret; 00383 00384 std::vector<cmd_line_arg> ca; 00385 00386 // --------------------------------------- 00387 // Process command-line options 00388 00389 ret=process_args(argv,argc,ca); 00390 if (ret!=0) { 00391 O2SCL_ERR_RET("Failed to process command-line in cli::run_auto().", 00392 gsl_efailed); 00393 } 00394 00395 if (ca.size()<1) { 00396 00397 ret=run_interactive(); 00398 if (ret!=0) { 00399 O2SCL_ERR_RET 00400 ("Failed to run interactive mode in cli::run_auto().", 00401 gsl_efailed); 00402 } 00403 00404 } else { 00405 00406 ret=call_args(ca); 00407 if (ret!=0) { 00408 O2SCL_ERR_RET("Function call_args() failed in cli::run_auto().", 00409 gsl_efailed); 00410 } 00411 00412 } 00413 return gsl_success; 00414 } 00415 00416 //@} 00417 00418 /** \brief The function which obtains input from the user 00419 00420 \todo Should this be protected? 00421 00422 */ 00423 virtual char *cli_gets(const char *c) { 00424 std::cout << c << std::flush; 00425 std::cin.getline(buf,300); 00426 return buf; 00427 } 00428 00429 /// Call functions corresponding to command-line args 00430 int call_args(std::vector<cmd_line_arg> &ca); 00431 00432 /** \brief Process command-line arguments from a const char array 00433 00434 This doesn't actually execute the functions for the 00435 corresponding options, but simply processes the parameters \c 00436 argv and \c argc and packs the information into \c ca. 00437 */ 00438 int process_args(int argv, const char *argc[], 00439 std::vector<cmd_line_arg> &ca, int debug=0); 00440 00441 /// Process command-line arguments from a string 00442 int process_args(std::string s, std::vector<cmd_line_arg> &ca, 00443 int debug=0) { 00444 std::vector<std::string> sv; 00445 separate(s,sv); 00446 int argv=sv.size(); 00447 const char **argc=new const char *[argv]; 00448 for(int i=0;i<argv;i++) argc[i]=sv[i].c_str(); 00449 int ret=process_args(argv,argc,ca,debug); 00450 delete[] argc; 00451 return ret; 00452 } 00453 00454 /** 00455 \brief Set verbosity 00456 00457 Most errors are output to the screen even if verbose is zero. 00458 */ 00459 int set_verbose(int v); 00460 00461 /// Run the interactive mode 00462 int run_interactive(); 00463 00464 // Create a new command 00465 // int replace_command(comm_option &ic); 00466 00467 /** 00468 \brief Set an alias \c alias for the string \c str 00469 00470 Aliases can also be set using the command \c 'alias', but 00471 that version allows only one-word aliases. 00472 */ 00473 int set_alias(std::string alias, std::string str) { 00474 al1.push_back(alias); 00475 al2.push_back(str); 00476 return 0; 00477 } 00478 00479 }; 00480 00481 #ifndef DOXYGENP 00482 } 00483 #endif 00484 00485 #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