cmdlineopt.cpp

00001 // Copyright (C) 2001 Gianni Mariani
00002 //
00003 // This program is free software; you can redistribute it and/or modify
00004 // it under the terms of the GNU General Public License as published by
00005 // the Free Software Foundation; either version 2 of the License, or
00006 // (at your option) any later version.
00007 //
00008 // This program is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 // GNU General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU General Public License
00014 // along with this program; if not, write to the Free Software
00015 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00016 //
00017 // As a special exception to the GNU General Public License, permission is
00018 // granted for additional uses of the text contained in its release
00019 // of Common C++.
00020 //
00021 // The exception is that, if you link the Common C++ library with other
00022 // files to produce an executable, this does not by itself cause the
00023 // resulting executable to be covered by the GNU General Public License.
00024 // Your use of that executable is in no way restricted on account of
00025 // linking the Common C++ library code into it.
00026 //
00027 // This exception does not however invalidate any other reasons why
00028 // the executable file might be covered by the GNU General Public License.
00029 //
00030 // This exception applies only to the code released under the
00031 // name Common C++.  If you copy code from other releases into a copy of
00032 // Common C++, as the General Public License permits, the exception does
00033 // not apply to the code that you add in this way.  To avoid misleading
00034 // anyone as to the status of such modified files, you must delete
00035 // this exception notice from them.
00036 //
00037 // If you write modifications of your own for Common C++, it is your choice
00038 // whether to permit this exception to apply to your modifications.
00039 // If you do not wish that, delete this exception notice.
00040 //
00041 
00042 
00043 //
00044 // Example for Common C++ the command line parser interface.
00045 //
00046 //
00047 // This exmaple code shows how to use the command line parser provided by
00048 // CommonC++.  The command line parser provides an interface which is
00049 // "object oriented" such that command line parameters are true "objects".
00050 //
00051 // Each command line option needs to be created.  By defining "CommandOption"s
00052 // statically, the C++ constructor is called when the objects are loaded and
00053 // before the "main" function is called.  The constructor links itself to
00054 // a list of other CommandOptionXXX in the list provided.  If no
00055 // list is specified in the constructor, a default one is used. Because of
00056 // the undefined nature as to the order in which constructors are called,
00057 // no assumption as to the order in which the CommandOptionXXX constructors
00058 // are called should be made.
00059 //
00060 // CommandOptionXXX classes can be used to derive specialized parameter
00061 // classes that are specific to applications.  The second example shows
00062 // just how this can be done.
00063 //
00064 
00065 //
00066 // Include the CommandOption definitions
00067 //
00068 #include <cc++/common.h>
00069 
00070 #include <iostream>
00071 #ifndef WIN32
00072 #include <cstdlib>
00073 #endif
00074 
00075 #ifdef  CCXX_NAMESPACES
00076 using namespace std;
00077 using namespace ost;
00078 #endif
00079 
00080 //
00081 // The following definition of options all use the list header
00082 // defaultCommandOptionList (which is specified as the value of the
00083 // default parameter in the constructor.  This convention would
00084 // allow other object files to link into the same list and add parameters
00085 // to the command line of this executable.
00086 
00087 CommandOptionArg        test_option1(
00088         "test_option1", "p", "This option takes an argument", true
00089 );
00090 
00091 CommandOptionNoArg      test_noarg(
00092         "test_noarg", "b", "This option does not take an argument"
00093 );
00094 
00095 CommandOptionNoArg      helparg(
00096         "help", "?", "Print help usage"
00097 );
00098 
00099 CommandOptionCollect    restoargs(
00100         0, 0, "Collect all the parameters", true
00101 );
00102 
00103 
00104 //
00105 // Normally this would me the regular main().  In this example
00106 // this processes the first command option list.
00107 //
00108 int Example_main( int argc, char ** argv )
00109 {
00110 
00111         // Create a CommandOptionParse object.  This takes the
00112         // defaultCommandOptionList and parses the command line arguments.
00113         //
00114         CommandOptionParse * args = makeCommandOptionParse(
00115                 argc, argv,
00116                 "CommonC++ command like option interface.  This is example\n"
00117                 "       code only."
00118         );
00119 
00120         // If the user requested help then suppress all the usage error
00121         // messages.
00122         if ( helparg.numSet ) {
00123                 cerr << args->printUsage();
00124                 ::exit(0);
00125         }
00126 
00127         // Print usage your way.
00128         if ( args->argsHaveError() ) {
00129                 cerr << args->printErrors();
00130                 cerr << args->printUsage();
00131                 ::exit(1);
00132         }
00133 
00134         // Go off and run any option specific task
00135         args->performTask();
00136 
00137         // print all the -p options
00138         for ( int i = 0; i < test_option1.numValue; i ++ ) {
00139                 cerr << "test_option1 = " << test_option1.values[ i ] << endl;
00140         }
00141 
00142         // print all the other options.
00143         for ( int i = 0; i < restoargs.numValue; i ++ ) {
00144                 cerr << "restoargs " << i << " : " << restoargs.values[ i ] << endl;
00145         }
00146 
00147         delete args;
00148 
00149         return 0;
00150 }
00151 
00152 
00153 //
00154 // This shows how to build a second option list.  The example is similar to
00155 // the first as well as it shows how to derive a new command object.
00156 //
00157 
00158 CommandOption * TestList = 0;
00159 
00160 extern CommandOptionRest        test_restoargs;
00161 
00162 
00163 #include <unistd.h>
00164 #include <sys/types.h>
00165 #include <sys/stat.h>
00166 #include <fcntl.h>
00167 #include <strstream>
00168 #include <errno.h>
00169 #include <string.h>
00170 #include <stdlib.h>
00171 #include <sys/wait.h>
00172 
00173 
00174 //
00175 // This is a parameter class derived from CommandOptionArg that takes
00176 // a file name parameter and detects wether the file is accessible
00177 // flagging an error if the file is inaccessible to read.
00178 //
00179 class file_option : public CommandOptionArg {
00180 public:
00181 
00182         // the constructor calls the regular CommandOptionArg constructor
00183         // and all should be well.
00184         file_option(
00185                 const char      * in_option_name,
00186                 const char      * in_option_letter,
00187                 const char      * in_description,
00188                 bool              in_required = false,
00189                 CommandOption  ** pp_next = & defaultCommandOptionList
00190         )
00191                 : CommandOptionArg(
00192                         in_option_name,
00193                         in_option_letter,
00194                         in_description,
00195                         in_required,
00196                         pp_next
00197                 )
00198         {
00199         }
00200 
00201         //
00202         // When parsing is done check if the file is accessible and register
00203         // an error with the CommandOptionParse object to let it know so.
00204         virtual void parseDone( CommandOptionParse * cop ) {
00205                 if ( numValue ) {
00206                         if ( ::access( values[ numValue - 1 ], R_OK ) ) {
00207                                 int     errno_s = errno;
00208                                 strstream msg;
00209                                 msg << "Error: " << optionName << " '" << values[ numValue - 1 ];
00210                                 msg << "' : " << ::strerror( errno_s );
00211 
00212                                 cop->registerError( msg.str() );
00213                         }
00214                 }
00215         }
00216 
00217         //
00218         // Open said file.  Do some operations on things - like open the file.
00219         int OpenFile() {
00220                 // Should put in way more error handling here ...
00221                 return ::open( values[ numValue - 1 ], O_RDONLY );
00222         }
00223 
00224         //
00225         // The most elaborate way to spit the contents of a file
00226         // to standard output.
00227         pid_t   pid;
00228         virtual void performTask( CommandOptionParse * cop ) {
00229                 pid = ::fork();
00230 
00231                 if ( pid ) {
00232                         return;
00233                 }
00234 
00235                 int fd = OpenFile();
00236                 if ( fd < 0 ) {
00237                         int errno_s = errno;
00238                         cerr
00239                                 << "Error:  '"
00240                                 << values[ numValue - 1 ]
00241                                 << "' : "
00242                                 << ::strerror( errno_s )
00243                         ;
00244 
00245                         ::exit( 1 );
00246                 }
00247                 dup2(fd, 0);
00248                 ::execvp( test_restoargs.values[0], (char**) test_restoargs.values );
00249                 ::exit(1);
00250         }
00251 
00252         ~file_option() {
00253                 if ( pid <= 0 ) return;
00254                 int status;
00255 		::wait(&status);
00256         }
00257 };
00258 
00259 
00260 //
00261 // This is the linked list head for the options in the second example.
00262 // Note that the first example used the default value defined in the
00263 // method.  Here it is explicitly specified as TestList in all the following
00264 // CommandOption constructors.
00265 
00266 file_option     test_file(
00267         "test_file", "f", "Filename to read from", true, &TestList
00268 );
00269 
00270 CommandOptionNoArg      test_xnoarg(
00271         "test_xnoarg", "b", "This option does not take an argument", false, &TestList
00272 );
00273 
00274 CommandOptionNoArg      test_helparg(
00275         "help", "?", "Print help usage", false, &TestList
00276 );
00277 
00278 CommandOptionRest       test_restoargs(
00279         0, 0, "Command to be executed", true, &TestList
00280 );
00281 
00282 //
00283 // in most apps this would be the regular "main" function.
00284 int Test_main( int argc, char ** argv )
00285 {
00286         CommandOptionParse * args = makeCommandOptionParse(
00287                 argc, argv,
00288                 "Command line parser X test.\n"
00289                 "       This example is executed when the command ends in 'x'\n"
00290                 "       It shows how the -f parameter can be specialized.\n",
00291                 TestList
00292         );
00293 
00294         // If the user requested help then suppress all the usage error
00295         // messages.
00296         if ( test_helparg.numSet ) {
00297                 cerr << args->printUsage();
00298                 ::exit(0);
00299         }
00300 
00301         // Print usage your way.
00302         if ( args->argsHaveError() ) {
00303                 cerr << args->printErrors();
00304                 cerr << "Get help by --help\n";
00305                 ::exit(1);
00306         }
00307 
00308         // Go off and run any option specific task
00309         args->performTask();
00310 
00311         for ( int i = 0; i < test_file.numValue; i ++ ) {
00312                 cerr << "test_file = " << test_file.values[ i ] << endl;
00313         }
00314 
00315         for ( int i = 0; i < test_restoargs.numValue; i ++ ) {
00316                 cerr << "test_restoargs " << i << " : " << test_restoargs.values[ i ] << endl;
00317         }
00318 
00319         delete args;
00320 
00321         return 0;
00322 }
00323 
00324 
00325 //
00326 // This switches behaviour of this executable depending of wether it is
00327 // invoked with a command ending in "x".  This is mimicking for example
00328 // the behaviour of bunzip2 and bzip2.  These executables are THE SAME
00329 // file i.e.
00330 //   0 lrwxrwxrwx    1 root     root    5 Oct 11 14:04 /usr/bin/bunzip2 -> bzip2*
00331 // and the behaviour is determined by the executable name.
00332 //
00333 // This example is way more complex than the way most people will end up
00334 // using feature.
00335 
00336 int main( int argc, char ** argv )
00337 {
00338 
00339         int i = ::strlen( argv[ 0 ] );
00340 
00341         // determine which real "main" function do I call
00342         if ( argv[ 0 ][ i - 1 ] == 'x' ) {
00343                 return Test_main( argc, argv );
00344         } else {
00345                 return Example_main( argc, argv );
00346         }
00347 
00348 }

Generated on Tue Apr 7 05:52:06 2009 for GNU CommonC++ by  doxygen 1.4.7