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 \future Warn in run_interactive() when extra parameters are given 00173 \future Include a "remove command" function 00174 \future A replace command function, there's already some code 00175 in cli.cpp for this. 00176 \future There's some code duplication between comm_option_run() 00177 and run_interactive() 00178 \future Allow the user to set the tilde string 00179 00180 <b>Concepts</b> 00181 00182 As a matter of definition, the command-line arguments are simply 00183 called arguments. These arguments may be options (in which case 00184 they begin with either one dash or two) or parameters to these 00185 options. When run in interactive mode, these options are also 00186 commands. 00187 00188 */ 00189 class cli { 00190 00191 #ifndef DOXYGEN_INTERNAL 00192 00193 protected: 00194 00195 /// Desc 00196 int expand_tilde(std::vector<std::string> &sv); 00197 00198 /// Replace all occurences of \c sold with \c snew in \c sv 00199 int apply_alias(std::vector<std::string> &sv, 00200 std::string sold, std::string snew); 00201 00202 /** \brief Separate a string into words, handling quotes 00203 00204 This function separates a string into words, and handles 00205 words that begin with a <tt>"</tt> by adding more words 00206 until finding one which ends with a <tt>"</tt>. 00207 00208 This is used to reformat command descriptions and help text 00209 for the screen width in comm_option_help(), to process 00210 lines read from a file in comm_option_run(), and to process 00211 input in run_interactive(). 00212 */ 00213 int separate(std::string str, std::vector<std::string> &sv); 00214 00215 /// Control screen output 00216 int verbose; 00217 00218 /// Pointer to collection for parameters 00219 collection *cop; 00220 00221 /// \name The hard-coded command functions 00222 //@{ 00223 int comm_option_alias(std::vector<std::string> &sv, bool itive_com); 00224 int comm_option_commands(std::vector<std::string> &sv, bool itive_com); 00225 int comm_option_get(std::vector<std::string> &sv, bool itive_com); 00226 int comm_option_help(std::vector<std::string> &sv, bool itive_com); 00227 int comm_option_license(std::vector<std::string> &sv, bool itive_com); 00228 int comm_option_no_intro(std::vector<std::string> &sv, bool itive_com); 00229 int comm_option_run(std::vector<std::string> &sv, bool itive_com); 00230 int comm_option_set(std::vector<std::string> &sv, bool itive_com); 00231 int comm_option_warranty(std::vector<std::string> &sv, bool itive_com); 00232 //@} 00233 00234 /// Storage for getline 00235 char buf[300]; 00236 00237 /// Storage for the function to call after setting a parameter 00238 comm_option_funct *user_set_func; 00239 00240 /// List of commands 00241 std::vector<comm_option_s> clist; 00242 00243 /// \name Help for parameters 00244 //@{ 00245 std::vector<std::string> ph_name, ph_desc; 00246 //@} 00247 00248 /// \name Aliases 00249 //@{ 00250 std::vector<std::string> al1, al2; 00251 //@} 00252 00253 /// Compare two strings, treating dashes and underscores as equivalent 00254 bool string_equal_dash(std::string s1, std::string s2); 00255 00256 #endif 00257 00258 public: 00259 00260 cli(); 00261 00262 virtual ~cli(); 00263 00264 /// Desc 00265 std::string tilde_string; 00266 00267 /** \brief If true, output the usual GNU intro when run_interactive() 00268 is called. 00269 00270 In order to conform to GNU standards, this ought not be set to 00271 false by default. 00272 */ 00273 bool gnu_intro; 00274 00275 /// Function to call when a \c set command is issued 00276 int set_function(comm_option_funct &usf) { 00277 user_set_func=&usf; 00278 return 0; 00279 } 00280 00281 /// \name Value to indicate whether commands are also command-line options 00282 //@{ 00283 static const int comm_option_command=0; 00284 static const int comm_option_cl_param=1; 00285 static const int comm_option_both=2; 00286 //@} 00287 00288 /// \name The hard-coded command objects 00289 //@{ 00290 comm_option_s c_commands; 00291 comm_option_s c_help; 00292 comm_option_s c_quit; 00293 comm_option_s c_exit; 00294 comm_option_s c_license; 00295 comm_option_s c_warranty; 00296 comm_option_s c_set; 00297 comm_option_s c_get; 00298 comm_option_s c_run; 00299 comm_option_s c_no_intro; 00300 comm_option_s c_alias; 00301 //@} 00302 00303 /// If true, then sync ::verbose, with a parameter of the same name 00304 bool sync_verbose; 00305 00306 /** \brief If true, allow the user to use ! to execute a shell command 00307 (default true) 00308 */ 00309 bool shell_cmd_allowed; 00310 00311 /// The prompt (default <tt>"> "</tt>) 00312 std::string prompt; 00313 00314 /// A one- or two-line description (default is empty string) 00315 std::string desc; 00316 00317 /// The name of the command 00318 std::string cmd_name; 00319 00320 /// Additional help text for interactive mode (default is empty string) 00321 std::string addl_help_cmd; 00322 00323 /// Additional help text for command-line (default is empty string) 00324 std::string addl_help_cli; 00325 00326 /// \name Basic operation 00327 //@{ 00328 /** 00329 \brief Add a new command 00330 00331 Each command/option must have either a short form in 00332 comm_option_s::shrt or a long from in comm_option_s::lng, 00333 which is unique from the other commands/options already 00334 present. You cannot add two commands/options with the same 00335 short form, even if they have different long forms, and vice 00336 versa. 00337 00338 */ 00339 int set_comm_option(comm_option_s &ic); 00340 00341 /// Add a vector containing new commands 00342 template<class vec_t> int set_comm_option_vec(size_t nic, vec_t &ic) { 00343 for(size_t k=0;k<nic;k++) { 00344 bool found=false; 00345 for(size_t i=0;found==false && i<clist.size();i++) { 00346 if ((ic[k].shrt!=0 && clist[i].shrt==ic[k].shrt) || 00347 (ic[k].lng.length()>0 && clist[i].lng==ic[k].lng)) { 00348 found=true; 00349 } 00350 } 00351 if (found==true) { 00352 if (ic[k].shrt!=0) { 00353 std::string err="Option "; 00354 err+=ic[k].shrt; 00355 err+=((std::string)" , ")+ic[k].lng+" already present."; 00356 O2SCL_ERR_RET(err.c_str(),gsl_einval); 00357 } else { 00358 std::string err="Option "; 00359 err+=ic[k].lng+" already present."; 00360 O2SCL_ERR_RET(err.c_str(),gsl_einval); 00361 } 00362 } 00363 clist.push_back(ic[k]); 00364 } 00365 return 0; 00366 } 00367 00368 /// Set the parameters with a collection 00369 int set_parameters(collection &co); 00370 00371 /// Set one-line help text for a parameter named \c param 00372 int set_param_help(std::string param, std::string help); 00373 00374 /** \brief Automatically parse arguments to main and 00375 call interactive mode if required 00376 */ 00377 int run_auto(int argv, const char *argc[]) { 00378 int ret; 00379 00380 std::vector<cmd_line_arg> ca; 00381 00382 // --------------------------------------- 00383 // Process command-line options 00384 00385 ret=process_args(argv,argc,ca); 00386 if (ret!=0) { 00387 O2SCL_ERR_RET("Failed to process command-line in cli::run_auto().", 00388 gsl_efailed); 00389 } 00390 00391 if (ca.size()<1) { 00392 00393 ret=run_interactive(); 00394 if (ret!=0) { 00395 O2SCL_ERR_RET 00396 ("Failed to run interactive mode in cli::run_auto().", 00397 gsl_efailed); 00398 } 00399 00400 } else { 00401 00402 ret=call_args(ca); 00403 if (ret!=0) { 00404 O2SCL_ERR_RET("Function call_args() failed in cli::run_auto().", 00405 gsl_efailed); 00406 } 00407 00408 } 00409 return gsl_success; 00410 } 00411 00412 //@} 00413 00414 /** \brief The function which obtains input from the user 00415 00416 \future Think about whether or not this should be protected? 00417 (Possibly not, as it's extensively used by acolm.cpp) 00418 */ 00419 virtual char *cli_gets(const char *c) { 00420 std::cout << c << std::flush; 00421 std::cin.getline(buf,300); 00422 return buf; 00423 } 00424 00425 /// Call functions corresponding to command-line args 00426 int call_args(std::vector<cmd_line_arg> &ca); 00427 00428 /** \brief Process command-line arguments from a const char array 00429 00430 This doesn't actually execute the functions for the 00431 corresponding options, but simply processes the parameters \c 00432 argv and \c argc and packs the information into \c ca. 00433 */ 00434 int process_args(int argv, const char *argc[], 00435 std::vector<cmd_line_arg> &ca, int debug=0); 00436 00437 /// Process command-line arguments from a string 00438 int process_args(std::string s, std::vector<cmd_line_arg> &ca, 00439 int debug=0) { 00440 std::vector<std::string> sv; 00441 separate(s,sv); 00442 int argv=sv.size(); 00443 const char **argc=new const char *[argv]; 00444 for(int i=0;i<argv;i++) argc[i]=sv[i].c_str(); 00445 int ret=process_args(argv,argc,ca,debug); 00446 delete[] argc; 00447 return ret; 00448 } 00449 00450 /** 00451 \brief Set verbosity 00452 00453 Most errors are output to the screen even if verbose is zero. 00454 */ 00455 int set_verbose(int v); 00456 00457 /// Run the interactive mode 00458 int run_interactive(); 00459 00460 // Create a new command 00461 // int replace_command(comm_option &ic); 00462 00463 /** 00464 \brief Set an alias \c alias for the string \c str 00465 00466 Aliases can also be set using the command \c 'alias', but 00467 that version allows only one-word aliases. 00468 */ 00469 int set_alias(std::string alias, std::string str) { 00470 al1.push_back(alias); 00471 al2.push_back(str); 00472 return 0; 00473 } 00474 00475 }; 00476 00477 #ifndef DOXYGENP 00478 } 00479 #endif 00480 00481 #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