blob: 9ae8d48898954b9787023fb1351380a61b965689 [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001// 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
76using namespace std;
77using 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
87CommandOptionArg test_option1(
88 "test_option1", "p", "This option takes an argument", true
89);
90
91CommandOptionNoArg test_noarg(
92 "test_noarg", "b", "This option does not take an argument"
93);
94
95CommandOptionNoArg helparg(
96 "help", "?", "Print help usage"
97);
98
99CommandOptionCollect 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//
108int 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
158CommandOption * TestList = 0;
159
160extern 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//
177class file_option : public CommandOptionArg {
178public:
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
264file_option test_file(
265 "test_file", "f", "Filename to read from", true, &TestList
266);
267
268CommandOptionNoArg test_xnoarg(
269 "test_xnoarg", "b", "This option does not take an argument", false, &TestList
270);
271
272CommandOptionNoArg test_helparg(
273 "help", "?", "Print help usage", false, &TestList
274);
275
276CommandOptionRest 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.
282int 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
334int 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}