cli.h

00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 2006, 2007, 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)
00115     char shrt;
00116     /// Long option (must be specified)
00117     std::string lng;
00118     /// Description for help (default is empty string)
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 (default is empty string)
00125     std::string parm_desc;
00126     /// The help description (default is empty string)
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 (default command)
00131     int type;
00132 
00133   } comm_option_s;
00134   
00135   /** 
00136       \brief Command for interactive mode in \ref cli
00137 
00138       See the \ref cli class for more details.
00139   */
00140   class comm_option : public comm_option_s {
00141     
00142   public:
00143 
00144     comm_option() {
00145       shrt=0;
00146       lng="";
00147       desc="";
00148       min_parms=0;
00149       max_parms=0;
00150       parm_desc="";
00151       help="";
00152       func=0;
00153       type=command;
00154     }
00155 
00156     comm_option(comm_option_s c) {
00157       shrt=c.shrt;
00158       lng=c.lng;
00159       desc=c.desc;
00160       min_parms=c.min_parms;
00161       max_parms=c.max_parms;
00162       parm_desc=c.parm_desc;
00163       help=c.help;
00164       func=c.func;
00165       type=c.type;
00166     }
00167     
00168     /// \name Possible values of ::type
00169     //@{
00170     static const int command=0;
00171     static const int cl_param=1;
00172     static const int both=2;
00173     //@}
00174 
00175   }; 
00176 
00177   /** \brief A command-line argument
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 (0, unless it's an option)
00189     comm_option *cop;
00190   } cmd_line_arg;
00191 
00192   /** 
00193       \brief Configurable command-line interface
00194 
00195       Somewhat experimental.
00196 
00197       Default commands: help, get/set, quit, exit, '!', verbose, license,
00198       warranty, alias.
00199 
00200       Note that if the shell command is allowed (as it is by default)
00201       there are some potential security issues which are not 
00202       solved here.
00203       
00204       Commands which begin with a '#' character are ignored.
00205   */
00206   class cli {
00207 
00208 #ifndef DOXYGEN_INTERNAL
00209 
00210   protected:
00211   
00212     /// Replace all occurences of \c sold with \c snew in \c s
00213     int apply_alias(std::string &s, std::string sold, std::string snew);
00214 
00215     /// Separate a string into words
00216     int separate(std::string str, std::vector<std::string> &sv);
00217   
00218     /// Control screen output
00219     int verbose;
00220 
00221     /// Pointer to collection for parameters
00222     collection *cop;
00223     
00224     /// \name The hard-coded command functions
00225     //@{
00226     int comm_option_get(std::vector<std::string> &sv, bool itive_com);
00227     int comm_option_set(std::vector<std::string> &sv, bool itive_com);
00228     int comm_option_help(std::vector<std::string> &sv, bool itive_com);
00229     int comm_option_license(std::vector<std::string> &sv, bool itive_com);
00230     int comm_option_warranty(std::vector<std::string> &sv, bool itive_com);
00231     int comm_option_no_intro(std::vector<std::string> &sv, bool itive_com);
00232     int comm_option_alias(std::vector<std::string> &sv, bool itive_com);
00233     //@}
00234 
00235     /// Storage for getline
00236     char buf[300];
00237 
00238     /// Storage for the function to call after setting a parameter
00239     comm_option_funct *user_set_func;
00240     
00241     /// List of commands
00242     std::vector<comm_option *> clist;
00243   
00244     /// \name Help for parameters
00245     //@{
00246     std::vector<std::string> ph_name, ph_desc;
00247     //@}
00248 
00249     /// \name Aliases
00250     //@{
00251     std::vector<std::string> al1, al2;
00252     //@}
00253     
00254     /// Compare two strings, treating dashes as underscores
00255     bool string_equal(std::string s1, std::string s2);
00256 
00257 #endif
00258   
00259   public:
00260 
00261     cli();
00262 
00263     virtual ~cli();
00264 
00265     /** \brief If true, output the usual GNU intro when run_interactive() 
00266         is called.
00267 
00268         In order to conform to GNU standards, this ought not be set to
00269         false by default.
00270     */
00271     bool gnu_intro;
00272 
00273     /// Function to call when a \c set command is issued
00274     int set_function(comm_option_funct &usf) {
00275       user_set_func=&usf;
00276       return 0;
00277     }
00278 
00279     /// \name The hard-coded command objects
00280     //@{
00281     comm_option c_help;
00282     comm_option c_quit;
00283     comm_option c_exit;
00284     comm_option c_license;
00285     comm_option c_warranty;
00286     comm_option c_set;
00287     comm_option c_get;
00288     comm_option c_no_intro;
00289     comm_option c_alias;
00290     //@}
00291     
00292     /// If true, then sync ::verbose, with a parameter of the same name
00293     bool sync_verbose;
00294 
00295     /** \brief If true, allow the user to use ! to execute a shell command 
00296         (default true)
00297     */
00298     bool shell_cmd_allowed;
00299 
00300     /// The prompt (default \c "> ")
00301     std::string prompt;
00302     
00303     /// A one- or two-line description (default is empty string)
00304     std::string desc;
00305 
00306     /// The name of the command
00307     std::string cmd_name;
00308 
00309     /// Additional help text for interactive mode (default is empty string)
00310     std::string addl_help_cmd;
00311 
00312     /// Additional help text for command-line (default is empty string)
00313     std::string addl_help_cli;
00314 
00315     /* A static variable for holding the line for \ref sn_cli */
00316     char *line_read;
00317 
00318     virtual char *cli_gets(const char *c) {
00319       std::cout << c << std::flush;
00320       std::cin.getline(buf,300);
00321       return buf;
00322     }
00323     
00324     /// Call functions corresponding to command-line args
00325     int call_args(std::vector<cmd_line_arg> &ca);
00326 
00327     /// Process command-line arguments
00328     int process_args(int argv, const char *argc[], 
00329                      std::vector<cmd_line_arg> &ca, int debug=0);
00330     
00331     /// Process command-line arguments
00332     int process_args(std::string s, std::vector<cmd_line_arg> &ca, 
00333                      int debug=0) {
00334       std::vector<std::string> sv;
00335       separate(s,sv);
00336       int argv=sv.size();
00337       const char **argc=new const char *[argv];
00338       for(int i=0;i<argv;i++) argc[i]=sv[i].c_str();
00339       int ret=process_args(argv,argc,ca,debug);
00340       delete[] argc;
00341       return ret;
00342     }
00343 
00344     /** 
00345         \brief Set verbosity
00346         
00347         Most errors are output to the screen even if verbose is zero.
00348     */
00349     int set_verbose(int v);
00350 
00351     /// Run the interactive mode
00352     int run_interactive();
00353     
00354     /** 
00355         \brief Add a new command
00356         
00357         Each command/option must have either a short form in
00358         comm_option::shrt or a long from in comm_option::lng,
00359         which is unique from the other commands/options already
00360         present. You cannot add two commands/options with the same
00361         short form, even if they have different long forms, and vice
00362         versa.
00363 
00364      */
00365     int set_comm_option(comm_option &ic);
00366 
00367     /// Create a new command
00368     //    int replace_command(comm_option &ic);
00369 
00370     /// Set the parameters with a collection
00371     int set_parameters(collection &co);
00372 
00373     /// Set one-line help text for a parameter named \c param
00374     int set_param_help(std::string param, std::string help);
00375 
00376     /** 
00377         \brief Set an alias \c alias for the string \c str
00378 
00379         Aliases can also be set using the command \c 'alias', but 
00380         that version allows only one-word aliases. 
00381      */
00382     int set_alias(std::string alias, std::string str) {
00383       al1.push_back(alias);
00384       al2.push_back(str);
00385       return 0;
00386     }
00387   
00388   };
00389 
00390 #ifndef DOXYGENP
00391 }
00392 #endif
00393 
00394 #endif

Documentation generated with Doxygen and provided under the GNU Free Documentation License. See License Information for details.

Project hosting provided by SourceForge.net Logo, O2scl Sourceforge Project Page