Emeric Vigier | 2f62582 | 2012-08-06 11:09:52 -0400 | [diff] [blame] | 1 | // Copyright (C) 2001 Gianni Mariani |
| 2 | // |
| 3 | // This program is free software; you can redistribute it and/or modify |
| 4 | // it under the terms of the GNU General Public License as published by |
| 5 | // the Free Software Foundation; either version 2 of the License, or |
| 6 | // (at your option) any later version. |
| 7 | // |
| 8 | // This program is distributed in the hope that it will be useful, |
| 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | // GNU General Public License for more details. |
| 12 | // |
| 13 | // You should have received a copy of the GNU General Public License |
| 14 | // along with this program; if not, write to the Free Software |
| 15 | // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| 16 | // |
| 17 | // As a special exception to the GNU General Public License, permission is |
| 18 | // granted for additional uses of the text contained in its release |
| 19 | // of Common C++. |
| 20 | // |
| 21 | // The exception is that, if you link the Common C++ library with other |
| 22 | // files to produce an executable, this does not by itself cause the |
| 23 | // resulting executable to be covered by the GNU General Public License. |
| 24 | // Your use of that executable is in no way restricted on account of |
| 25 | // linking the Common C++ library code into it. |
| 26 | // |
| 27 | // This exception does not however invalidate any other reasons why |
| 28 | // the executable file might be covered by the GNU General Public License. |
| 29 | // |
| 30 | // This exception applies only to the code released under the |
| 31 | // name Common C++. If you copy code from other releases into a copy of |
| 32 | // Common C++, as the General Public License permits, the exception does |
| 33 | // not apply to the code that you add in this way. To avoid misleading |
| 34 | // anyone as to the status of such modified files, you must delete |
| 35 | // this exception notice from them. |
| 36 | // |
| 37 | // If you write modifications of your own for Common C++, it is your choice |
| 38 | // whether to permit this exception to apply to your modifications. |
| 39 | // If you do not wish that, delete this exception notice. |
| 40 | // |
| 41 | |
| 42 | |
| 43 | // |
| 44 | // Example for Common C++ the command line parser interface. |
| 45 | // |
| 46 | // |
| 47 | // This exmaple code shows how to use the command line parser provided by |
| 48 | // CommonC++. The command line parser provides an interface which is |
| 49 | // "object oriented" such that command line parameters are true "objects". |
| 50 | // |
| 51 | // Each command line option needs to be created. By defining "CommandOption"s |
| 52 | // statically, the C++ constructor is called when the objects are loaded and |
| 53 | // before the "main" function is called. The constructor links itself to |
| 54 | // a list of other CommandOptionXXX in the list provided. If no |
| 55 | // list is specified in the constructor, a default one is used. Because of |
| 56 | // the undefined nature as to the order in which constructors are called, |
| 57 | // no assumption as to the order in which the CommandOptionXXX constructors |
| 58 | // are called should be made. |
| 59 | // |
| 60 | // CommandOptionXXX classes can be used to derive specialized parameter |
| 61 | // classes that are specific to applications. The second example shows |
| 62 | // just how this can be done. |
| 63 | // |
| 64 | |
| 65 | // |
| 66 | // Include the CommandOption definitions |
| 67 | // |
| 68 | #include <cc++/common.h> |
| 69 | |
| 70 | #include <iostream> |
| 71 | #ifndef WIN32 |
| 72 | #include <cstdlib> |
| 73 | #endif |
| 74 | |
| 75 | #ifdef CCXX_NAMESPACES |
| 76 | using namespace std; |
| 77 | using namespace ost; |
| 78 | #endif |
| 79 | |
| 80 | // |
| 81 | // The following definition of options all use the list header |
| 82 | // defaultCommandOptionList (which is specified as the value of the |
| 83 | // default parameter in the constructor. This convention would |
| 84 | // allow other object files to link into the same list and add parameters |
| 85 | // to the command line of this executable. |
| 86 | |
| 87 | CommandOptionArg test_option1( |
| 88 | "test_option1", "p", "This option takes an argument", true |
| 89 | ); |
| 90 | |
| 91 | CommandOptionNoArg test_noarg( |
| 92 | "test_noarg", "b", "This option does not take an argument" |
| 93 | ); |
| 94 | |
| 95 | CommandOptionNoArg helparg( |
| 96 | "help", "?", "Print help usage" |
| 97 | ); |
| 98 | |
| 99 | CommandOptionCollect restoargs( |
| 100 | 0, 0, "Collect all the parameters", true |
| 101 | ); |
| 102 | |
| 103 | |
| 104 | // |
| 105 | // Normally this would me the regular main(). In this example |
| 106 | // this processes the first command option list. |
| 107 | // |
| 108 | int Example_main( int argc, char ** argv ) |
| 109 | { |
| 110 | |
| 111 | // Create a CommandOptionParse object. This takes the |
| 112 | // defaultCommandOptionList and parses the command line arguments. |
| 113 | // |
| 114 | CommandOptionParse * args = makeCommandOptionParse( |
| 115 | argc, argv, |
| 116 | "CommonC++ command like option interface. This is example\n" |
| 117 | " code only." |
| 118 | ); |
| 119 | |
| 120 | // If the user requested help then suppress all the usage error |
| 121 | // messages. |
| 122 | if ( helparg.numSet ) { |
| 123 | cerr << args->printUsage(); |
| 124 | ::exit(0); |
| 125 | } |
| 126 | |
| 127 | // Print usage your way. |
| 128 | if ( args->argsHaveError() ) { |
| 129 | cerr << args->printErrors(); |
| 130 | cerr << args->printUsage(); |
| 131 | ::exit(1); |
| 132 | } |
| 133 | |
| 134 | // Go off and run any option specific task |
| 135 | args->performTask(); |
| 136 | |
| 137 | // print all the -p options |
| 138 | for ( int i = 0; i < test_option1.numValue; i ++ ) { |
| 139 | cerr << "test_option1 = " << test_option1.values[ i ] << endl; |
| 140 | } |
| 141 | |
| 142 | // print all the other options. |
| 143 | for ( int i = 0; i < restoargs.numValue; i ++ ) { |
| 144 | cerr << "restoargs " << i << " : " << restoargs.values[ i ] << endl; |
| 145 | } |
| 146 | |
| 147 | delete args; |
| 148 | |
| 149 | return 0; |
| 150 | } |
| 151 | |
| 152 | |
| 153 | // |
| 154 | // This shows how to build a second option list. The example is similar to |
| 155 | // the first as well as it shows how to derive a new command object. |
| 156 | // |
| 157 | |
| 158 | CommandOption * TestList = 0; |
| 159 | |
| 160 | extern CommandOptionRest test_restoargs; |
| 161 | |
| 162 | #include <unistd.h> |
| 163 | #include <sys/types.h> |
| 164 | #include <sys/stat.h> |
| 165 | #include <fcntl.h> |
| 166 | #include <errno.h> |
| 167 | #include <string.h> |
| 168 | #include <stdlib.h> |
| 169 | #include <sys/wait.h> |
| 170 | #include <strstream> |
| 171 | |
| 172 | // |
| 173 | // This is a parameter class derived from CommandOptionArg that takes |
| 174 | // a file name parameter and detects wether the file is accessible |
| 175 | // flagging an error if the file is inaccessible to read. |
| 176 | // |
| 177 | class file_option : public CommandOptionArg { |
| 178 | public: |
| 179 | |
| 180 | // the constructor calls the regular CommandOptionArg constructor |
| 181 | // and all should be well. |
| 182 | file_option( |
| 183 | const char * in_option_name, |
| 184 | const char * in_option_letter, |
| 185 | const char * in_description, |
| 186 | bool in_required = false, |
| 187 | CommandOption ** pp_next = & defaultCommandOptionList |
| 188 | ) |
| 189 | : CommandOptionArg( |
| 190 | in_option_name, |
| 191 | in_option_letter, |
| 192 | in_description, |
| 193 | in_required, |
| 194 | pp_next |
| 195 | ) |
| 196 | { |
| 197 | } |
| 198 | |
| 199 | // |
| 200 | // When parsing is done check if the file is accessible and register |
| 201 | // an error with the CommandOptionParse object to let it know so. |
| 202 | virtual void parseDone( CommandOptionParse * cop ) { |
| 203 | if ( numValue ) { |
| 204 | if ( ::access( values[ numValue - 1 ], R_OK ) ) { |
| 205 | int errno_s = errno; |
| 206 | strstream msg; |
| 207 | msg << "Error: " << optionName << " '" << values[ numValue - 1 ]; |
| 208 | msg << "' : " << ::strerror( errno_s ); |
| 209 | |
| 210 | cop->registerError( msg.str() ); |
| 211 | } |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | // |
| 216 | // Open said file. Do some operations on things - like open the file. |
| 217 | int OpenFile() { |
| 218 | // Should put in way more error handling here ... |
| 219 | return ::open( values[ numValue - 1 ], O_RDONLY ); |
| 220 | } |
| 221 | |
| 222 | // |
| 223 | // The most elaborate way to spit the contents of a file |
| 224 | // to standard output. |
| 225 | pid_t pid; |
| 226 | virtual void performTask( CommandOptionParse * cop ) { |
| 227 | pid = ::fork(); |
| 228 | |
| 229 | if ( pid ) { |
| 230 | return; |
| 231 | } |
| 232 | |
| 233 | int fd = OpenFile(); |
| 234 | if ( fd < 0 ) { |
| 235 | int errno_s = errno; |
| 236 | cerr |
| 237 | << "Error: '" |
| 238 | << values[ numValue - 1 ] |
| 239 | << "' : " |
| 240 | << ::strerror( errno_s ) |
| 241 | ; |
| 242 | |
| 243 | ::exit( 1 ); |
| 244 | } |
| 245 | dup2(fd, 0); |
| 246 | ::execvp( test_restoargs.values[0], (char**) test_restoargs.values ); |
| 247 | ::exit(1); |
| 248 | } |
| 249 | |
| 250 | ~file_option() { |
| 251 | if ( pid <= 0 ) return; |
| 252 | int status; |
| 253 | ::wait(&status); |
| 254 | } |
| 255 | }; |
| 256 | |
| 257 | |
| 258 | // |
| 259 | // This is the linked list head for the options in the second example. |
| 260 | // Note that the first example used the default value defined in the |
| 261 | // method. Here it is explicitly specified as TestList in all the following |
| 262 | // CommandOption constructors. |
| 263 | |
| 264 | file_option test_file( |
| 265 | "test_file", "f", "Filename to read from", true, &TestList |
| 266 | ); |
| 267 | |
| 268 | CommandOptionNoArg test_xnoarg( |
| 269 | "test_xnoarg", "b", "This option does not take an argument", false, &TestList |
| 270 | ); |
| 271 | |
| 272 | CommandOptionNoArg test_helparg( |
| 273 | "help", "?", "Print help usage", false, &TestList |
| 274 | ); |
| 275 | |
| 276 | CommandOptionRest test_restoargs( |
| 277 | 0, 0, "Command to be executed", true, &TestList |
| 278 | ); |
| 279 | |
| 280 | // |
| 281 | // in most apps this would be the regular "main" function. |
| 282 | int Test_main( int argc, char ** argv ) |
| 283 | { |
| 284 | CommandOptionParse * args = makeCommandOptionParse( |
| 285 | argc, argv, |
| 286 | "Command line parser X test.\n" |
| 287 | " This example is executed when the command ends in 'x'\n" |
| 288 | " It shows how the -f parameter can be specialized.\n", |
| 289 | TestList |
| 290 | ); |
| 291 | |
| 292 | // If the user requested help then suppress all the usage error |
| 293 | // messages. |
| 294 | if ( test_helparg.numSet ) { |
| 295 | cerr << args->printUsage(); |
| 296 | ::exit(0); |
| 297 | } |
| 298 | |
| 299 | // Print usage your way. |
| 300 | if ( args->argsHaveError() ) { |
| 301 | cerr << args->printErrors(); |
| 302 | cerr << "Get help by --help\n"; |
| 303 | ::exit(1); |
| 304 | } |
| 305 | |
| 306 | // Go off and run any option specific task |
| 307 | args->performTask(); |
| 308 | |
| 309 | for ( int i = 0; i < test_file.numValue; i ++ ) { |
| 310 | cerr << "test_file = " << test_file.values[ i ] << endl; |
| 311 | } |
| 312 | |
| 313 | for ( int i = 0; i < test_restoargs.numValue; i ++ ) { |
| 314 | cerr << "test_restoargs " << i << " : " << test_restoargs.values[ i ] << endl; |
| 315 | } |
| 316 | |
| 317 | delete args; |
| 318 | |
| 319 | return 0; |
| 320 | } |
| 321 | |
| 322 | |
| 323 | // |
| 324 | // This switches behaviour of this executable depending of wether it is |
| 325 | // invoked with a command ending in "x". This is mimicking for example |
| 326 | // the behaviour of bunzip2 and bzip2. These executables are THE SAME |
| 327 | // file i.e. |
| 328 | // 0 lrwxrwxrwx 1 root root 5 Oct 11 14:04 /usr/bin/bunzip2 -> bzip2* |
| 329 | // and the behaviour is determined by the executable name. |
| 330 | // |
| 331 | // This example is way more complex than the way most people will end up |
| 332 | // using feature. |
| 333 | |
| 334 | int main( int argc, char ** argv ) |
| 335 | { |
| 336 | |
| 337 | int i = ::strlen( argv[ 0 ] ); |
| 338 | |
| 339 | // determine which real "main" function do I call |
| 340 | if ( argv[ 0 ][ i - 1 ] == 'x' ) { |
| 341 | return Test_main( argc, argv ); |
| 342 | } else { |
| 343 | return Example_main( argc, argv ); |
| 344 | } |
| 345 | |
| 346 | } |