![]() |
Object-oriented Scientific Computing Library: Version 0.910
|
00001 /* 00002 ------------------------------------------------------------------- 00003 00004 Copyright (C) 2006-2012, 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/columnify.h> 00032 #include <o2scl/vector.h> 00033 #include <o2scl/string_conv.h> 00034 00035 #ifndef DOXYGENP 00036 namespace o2scl { 00037 #endif 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)=0; 00053 00054 }; 00055 00056 /// Function pointer for \ref cli command function 00057 class comm_option_fptr : public comm_option_funct { 00058 00059 public: 00060 00061 /// Create from a member function pointer from the specified class 00062 comm_option_fptr(int (*fp)(std::vector<std::string> &, bool)) { 00063 fptr=fp; 00064 } 00065 00066 virtual ~comm_option_fptr() {} 00067 00068 /// The basic function called by \ref cli 00069 virtual int operator()(std::vector<std::string> &cstr, bool itive_com) { 00070 return (*fptr)(cstr,itive_com); 00071 } 00072 00073 #ifndef DOXYGEN_INTERNAL 00074 00075 protected: 00076 00077 /// The pointer to the member function 00078 int (*fptr)(std::vector<std::string> &cstr, bool itive_com); 00079 00080 // Copy constructor 00081 //comm_option_fptr(const comm_option_fptr &f) { 00082 //fptr=f.fptr; 00083 //} 00084 00085 /// Copy constructor 00086 comm_option_fptr& operator=(const comm_option_fptr &f) { 00087 fptr=f.fptr; 00088 return *this; 00089 } 00090 00091 #endif 00092 00093 }; 00094 00095 /// Member function pointer for \ref cli command function 00096 template<class tclass> class comm_option_mfptr : public comm_option_funct { 00097 00098 public: 00099 00100 /// Create from a member function pointer from the specified class 00101 comm_option_mfptr(tclass *tp, int (tclass::*fp)(std::vector<std::string> &, 00102 bool)) { 00103 tptr=tp; 00104 fptr=fp; 00105 } 00106 00107 virtual ~comm_option_mfptr() {} 00108 00109 /// The basic function called by \ref cli 00110 virtual int operator()(std::vector<std::string> &cstr, bool itive_com) { 00111 return (*tptr.*fptr)(cstr,itive_com); 00112 } 00113 00114 #ifndef DOXYGEN_INTERNAL 00115 00116 protected: 00117 00118 /// The pointer to the member function 00119 int (tclass::*fptr)(std::vector<std::string> &cstr, bool itive_com); 00120 00121 /// The pointer to the class 00122 tclass *tptr; 00123 00124 /// Copy constructor 00125 comm_option_mfptr(const comm_option_mfptr &f) { 00126 fptr=f.fptr; 00127 tptr=f.tptr; 00128 } 00129 00130 /// Copy constructor 00131 comm_option_mfptr& operator=(const comm_option_mfptr &f) { 00132 fptr=f.fptr; 00133 tptr=f.tptr; 00134 return *this; 00135 } 00136 00137 #endif 00138 00139 }; 00140 00141 /** \brief Command for interactive mode in \ref cli 00142 00143 See the \ref cli class for more details. 00144 00145 \comment 00146 This was at one point converted into a class, but it wasn't that 00147 easy to use, in comparison to structs which are easy to 00148 initialize in aggregate. 00149 \endcomment 00150 */ 00151 typedef struct { 00152 00153 /// Short option (\c '\\0' for none, must be unique if present) 00154 char shrt; 00155 /// Long option (must be specified and must be unique) 00156 std::string lng; 00157 /// Description for help 00158 std::string desc; 00159 /// Minimum number of parameters (0 for none, -1 for variable) 00160 int min_parms; 00161 /// Maximum number of parameters (0 for none, -1 for variable) 00162 int max_parms; 00163 /// Description of parameters 00164 std::string parm_desc; 00165 /// The help description 00166 std::string help; 00167 /// The pointer to the function to be called (or 0 for no function) 00168 comm_option_funct *func; 00169 /// Type: command-line parameter, command, or both 00170 int type; 00171 00172 } comm_option_s; 00173 00174 /** \brief A command-line argument for \ref cli 00175 00176 This is the internal structure that \ref cli uses to package 00177 command-line arguments. 00178 */ 00179 typedef struct { 00180 /// The argument 00181 std::string arg; 00182 /// Is an option? 00183 bool is_option; 00184 /// Is a properly formatted option 00185 bool is_valid; 00186 /// List of parameters (empty, unless it's an option) 00187 std::vector<std::string> parms; 00188 /// A pointer to the appropriate option (0, unless it's an option) 00189 comm_option_s *cop; 00190 } cmd_line_arg; 00191 00192 /** \brief Configurable command-line interface 00193 00194 This class is experimental. 00195 00196 Default commands: help, get/set, quit, exit, '!', verbose, license, 00197 warranty, alias, run. 00198 00199 Note that if the shell command is allowed (as it is by default) 00200 there are some potential security issues which are not solved 00201 here. 00202 00203 Commands which begin with a '#' character are ignored. 00204 00205 \note In interactive mode, commands are limited to 300 characters. 00206 00207 \todo Long options cannot be one letter long, or else 00208 process_args() will fail, thus the class should throw 00209 if a long option with only one letter is given. 00210 00211 \future Warn in run_interactive() when extra parameters are given 00212 \future Include a "remove command" function 00213 \future A replace command function, there's already some code 00214 in cli.cpp for this. 00215 \future There's some code duplication between comm_option_run() 00216 and run_interactive() 00217 \future Allow the user to set the tilde string 00218 \future Disallow direct access to \ref cli::par_list in order to 00219 ensure parameter names do not contain whitespace 00220 00221 <b>Concepts</b> 00222 00223 As a matter of definition, the command-line arguments are simply 00224 called arguments. These arguments may be options (in which case 00225 they begin with either one dash or two) or parameters to these 00226 options. When run in interactive mode, these options are also 00227 commands. 00228 00229 */ 00230 class cli { 00231 00232 public: 00233 00234 /// Parameter for \ref cli 00235 class parameter { 00236 00237 public: 00238 00239 virtual ~parameter() {} 00240 00241 /// Help description 00242 std::string help; 00243 00244 /// Set from string 00245 virtual int set(std::string s)=0; 00246 00247 /// Convert to string 00248 virtual std::string get()=0; 00249 00250 }; 00251 00252 /// String parameter for \ref cli 00253 class parameter_string : public parameter { 00254 00255 public: 00256 00257 virtual ~parameter_string() {} 00258 00259 /// Parameter 00260 std::string *str; 00261 00262 /// Set from string 00263 virtual int set(std::string s) { 00264 *str=s; 00265 return 0; 00266 } 00267 00268 /// Convert to string 00269 virtual std::string get() { 00270 return *str; 00271 } 00272 00273 }; 00274 00275 /// String parameter for \ref cli 00276 class parameter_bool : public parameter { 00277 00278 public: 00279 00280 virtual ~parameter_bool() {} 00281 00282 /// Parameter 00283 bool *b; 00284 00285 /// Set from string 00286 virtual int set(std::string s) { 00287 *b=stob(s); 00288 return 0; 00289 } 00290 00291 /// Convert to string 00292 virtual std::string get() { 00293 return btos(*b); 00294 } 00295 00296 }; 00297 00298 /// Double parameter for \ref cli 00299 class parameter_double : public parameter { 00300 00301 public: 00302 00303 virtual ~parameter_double() {} 00304 00305 /// Parameter 00306 double *d; 00307 00308 /// Set from string 00309 virtual int set(std::string s) { 00310 *d=stod(s); 00311 return 0; 00312 } 00313 00314 /// Convert to string 00315 virtual std::string get() { 00316 return dtos(*d); 00317 } 00318 00319 }; 00320 00321 /// Integer parameter for \ref cli 00322 class parameter_int : public parameter { 00323 00324 public: 00325 00326 virtual ~parameter_int() {} 00327 00328 /// Parameter 00329 int *i; 00330 00331 /// Set from string 00332 virtual int set(std::string s) { 00333 *i=stoi(s); 00334 return 0; 00335 } 00336 00337 /// Convert to string 00338 virtual std::string get() { 00339 return itos(*i); 00340 } 00341 00342 }; 00343 00344 /// \name Parameter storage and associated iterator type 00345 //@{ 00346 /// Parameter list 00347 std::map<std::string,parameter *,string_comp> par_list; 00348 /// List iterator 00349 typedef std::map<std::string,parameter *,string_comp>::iterator par_t; 00350 //@} 00351 00352 #ifndef DOXYGENP_INTERNAL 00353 00354 protected: 00355 00356 /// Output the parameter list 00357 int output_param_list(); 00358 00359 /** \brief Attempt to expand a tilde to a user's home directory 00360 00361 Experimental and currently unused. 00362 */ 00363 int expand_tilde(std::vector<std::string> &sv); 00364 00365 /// Replace all occurences of \c sold with \c snew in \c sv 00366 int apply_alias(std::vector<std::string> &sv, 00367 std::string sold, std::string snew); 00368 00369 /** \brief Separate a string into words, handling quotes 00370 00371 This function separates a string into words, and handles words 00372 that begin with a <tt>"</tt> by adding more words until 00373 finding one which ends with another <tt>"</tt>. 00374 00375 This is used to reformat command descriptions and help text 00376 for the screen width in comm_option_help(), to process lines 00377 read from a file in comm_option_run(), and to process input in 00378 run_interactive(). 00379 00380 \note This function does not understand nested quotes. 00381 */ 00382 int separate(std::string str, std::vector<std::string> &sv); 00383 00384 /// Control screen output 00385 int verbose; 00386 00387 /// \name The hard-coded command functions 00388 //@{ 00389 int comm_option_alias(std::vector<std::string> &sv, bool itive_com); 00390 int comm_option_commands(std::vector<std::string> &sv, bool itive_com); 00391 int comm_option_get(std::vector<std::string> &sv, bool itive_com); 00392 int comm_option_help(std::vector<std::string> &sv, bool itive_com); 00393 int comm_option_license(std::vector<std::string> &sv, bool itive_com); 00394 int comm_option_no_intro(std::vector<std::string> &sv, bool itive_com); 00395 int comm_option_run(std::vector<std::string> &sv, bool itive_com); 00396 int comm_option_set(std::vector<std::string> &sv, bool itive_com); 00397 int comm_option_warranty(std::vector<std::string> &sv, bool itive_com); 00398 //@} 00399 00400 /// Storage for getline 00401 char buf[300]; 00402 00403 /// Storage for the function to call after setting a parameter 00404 comm_option_funct *user_set_func; 00405 00406 /// List of commands 00407 std::vector<comm_option_s> clist; 00408 00409 /// \name Help for parameters 00410 //@{ 00411 std::vector<std::string> ph_name, ph_desc; 00412 //@} 00413 00414 /// \name Aliases 00415 //@{ 00416 std::map<std::string,std::string,string_comp> als; 00417 typedef std::map<std::string,std::string,string_comp>::iterator al_it; 00418 //@} 00419 00420 /// Compare two strings, treating dashes and underscores as equivalent 00421 bool string_equal_dash(std::string s1, std::string s2); 00422 00423 #endif 00424 00425 public: 00426 00427 cli(); 00428 00429 virtual ~cli(); 00430 00431 /// String to replace tildes with 00432 std::string tilde_string; 00433 00434 /** \brief If true, output the usual GNU intro when run_interactive() 00435 is called (default true). 00436 00437 In order to conform to GNU standards, this ought not be set to 00438 false by default. 00439 */ 00440 bool gnu_intro; 00441 00442 /// Function to call when a \c set command is issued 00443 int set_function(comm_option_funct &usf) { 00444 user_set_func=&usf; 00445 return 0; 00446 } 00447 00448 /// \name Value to indicate whether commands are also command-line options 00449 //@{ 00450 static const int comm_option_command=0; 00451 static const int comm_option_cl_param=1; 00452 static const int comm_option_both=2; 00453 //@} 00454 00455 /// \name The default command objects 00456 //@{ 00457 comm_option_s c_commands; 00458 comm_option_s c_help; 00459 comm_option_s c_quit; 00460 comm_option_s c_exit; 00461 comm_option_s c_license; 00462 comm_option_s c_warranty; 00463 comm_option_s c_set; 00464 comm_option_s c_get; 00465 comm_option_s c_run; 00466 comm_option_s c_no_intro; 00467 comm_option_s c_alias; 00468 //@} 00469 00470 /// If true, then sync cli::verbose, with a parameter of the same name 00471 bool sync_verbose; 00472 00473 /** \brief If true, allow the user to use ! to execute a shell command 00474 (default true) 00475 */ 00476 bool shell_cmd_allowed; 00477 00478 /// The prompt (default <tt>"> "</tt>) 00479 std::string prompt; 00480 00481 /// A one- or two-line description (default is empty string) 00482 std::string desc; 00483 00484 /// The name of the command 00485 std::string cmd_name; 00486 00487 /// Additional help text for interactive mode (default is empty string) 00488 std::string addl_help_cmd; 00489 00490 /// Additional help text for command-line (default is empty string) 00491 std::string addl_help_cli; 00492 00493 /// \name Basic operation 00494 //@{ 00495 /** \brief Add a new command 00496 00497 Each command/option must have either a short form in 00498 comm_option_s::shrt or a long from in comm_option_s::lng, 00499 which is unique from the other commands/options already 00500 present. You cannot add two commands/options with the same 00501 short form, even if they have different long forms, and vice 00502 versa. 00503 00504 */ 00505 int set_comm_option(comm_option_s &ic); 00506 00507 /// Add a vector containing new commands/options 00508 template<class vec_t> int set_comm_option_vec 00509 (size_t list_size, vec_t &option_list) { 00510 00511 for(size_t k=0;k<list_size;k++) { 00512 bool found=false; 00513 for(size_t i=0;found==false && i<clist.size();i++) { 00514 // If short or long options match 00515 if ((option_list[k].shrt!=0 && 00516 clist[i].shrt==option_list[k].shrt) || 00517 (option_list[k].lng.length()>0 && 00518 clist[i].lng==option_list[k].lng)) { 00519 found=true; 00520 } 00521 } 00522 if (found==true) { 00523 // Call the error handler 00524 if (option_list[k].shrt!=0) { 00525 std::string err="Option "; 00526 err+=option_list[k].shrt; 00527 err+=((std::string)" , ")+option_list[k].lng+" already present."; 00528 O2SCL_ERR_RET(err.c_str(),gsl_einval); 00529 } else { 00530 std::string err="Option "; 00531 err+=option_list[k].lng+" already present."; 00532 O2SCL_ERR_RET(err.c_str(),gsl_einval); 00533 } 00534 } 00535 // Add the option to the option list 00536 clist.push_back(option_list[k]); 00537 } 00538 00539 return 0; 00540 } 00541 00542 /// Set one-line help text for a parameter named \c param 00543 int set_param_help(std::string param, std::string help); 00544 00545 /** \brief Automatically parse arguments to main and 00546 call interactive mode if required 00547 */ 00548 int run_auto(int argv, char *argc[]); 00549 //@} 00550 00551 /** \brief The function which obtains input from the user 00552 00553 \future Think about whether or not this should be protected? 00554 (Possibly not, as it's extensively used by acolm.cpp) 00555 */ 00556 virtual char *cli_gets(const char *c); 00557 00558 /// Call functions corresponding to command-line args 00559 int call_args(std::vector<cmd_line_arg> &ca); 00560 00561 /** \brief Process command-line arguments from a const char array 00562 00563 This doesn't actually execute the functions for the 00564 corresponding options, but simply processes the parameters \c 00565 argv and \c argc and packs the information into \c ca. 00566 00567 This function assumes that <tt>argc[0]</tt> just contains 00568 the name of the command, and should thus be ignored. 00569 */ 00570 int process_args(int argv, char *argc[], 00571 std::vector<cmd_line_arg> &ca, int debug=0); 00572 00573 /** \brief Process command-line arguments from a string 00574 00575 \todo There's a typecast in this function to (char *) 00576 from (const char *) which needs reworking. 00577 */ 00578 int process_args(std::string s, std::vector<cmd_line_arg> &ca, 00579 int debug=0); 00580 00581 /** \brief Set verbosity 00582 00583 Most errors are output to the screen even if verbose is zero. 00584 */ 00585 int set_verbose(int v); 00586 00587 /// Run the interactive mode 00588 int run_interactive(); 00589 00590 // Create a new command 00591 // int replace_command(comm_option &ic); 00592 00593 /** \brief Set an alias \c alias for the string \c str 00594 00595 Aliases can also be set using the command \c 'alias', but 00596 that version allows only one-word aliases. 00597 */ 00598 int set_alias(std::string alias, std::string str); 00599 00600 /** \brief Set an alias \c alias for the string \c str 00601 00602 Aliases can also be set using the command \c 'alias', but 00603 that version allows only one-word aliases. 00604 */ 00605 std::string get_alias(std::string alias); 00606 00607 }; 00608 00609 #ifndef DOXYGENP 00610 } 00611 #endif 00612 00613 #endif
Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).