Object-oriented Scientific Computing Library: Version 0.910
cli.h
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
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).

Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads.