1
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
4
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=us-ascii">
5
<TITLE>Advanced argtable topics</TITLE>
6
<META NAME="GENERATOR" CONTENT="OpenOffice.org 1.1.3 (FreeBSD)">
7
<META NAME="CREATED" CONTENT="20030925;11311700">
8
<META NAME="CHANGED" CONTENT="20041218;1203400">
9
<META NAME="CLASSIFICATION" CONTENT="ANSI C command line parser">
10
<META NAME="KEYWORDS" CONTENT="command line parser">
13
@page { size: 8.27in 11.69in }
14
H1 { margin-top: 0.79in }
15
PRE { margin-left: 0.3in }
16
PRE.western { font-size: 9pt }
20
<BODY LANG="en-GB" DIR="LTR">
21
<H1 ALIGN=CENTER>Advanced argtable-2.x topics<BR><FONT SIZE=3>An ANSI
22
C library for parsing GNU style command line arguments</FONT></H1>
23
<P ALIGN=CENTER STYLE="margin-bottom: 0.39in">Stewart
24
Heitmann<BR><I>sheitmann@users.sourceforge.net</I></P>
25
<H1 ALIGN=CENTER>Topics</H1>
26
<P ALIGN=CENTER>Parsing multiple command line syntaxes</P>
27
<P ALIGN=CENTER>Writing custom callbacks</P>
28
<P ALIGN=CENTER>Creating custom argument types</P>
29
<H1 STYLE="margin-top: 1.11in; margin-bottom: 0.2in; border: none; padding: 0in">
30
1. Parsing multiple command line syntaxes</H1>
31
<P STYLE="margin-bottom: 0in"><I><B>example code:</B>
32
<FONT FACE="Bitstream Vera Serif"><installdir>/share/doc/argtable2/example/multisyntax.c</FONT></I></P>
33
<P STYLE="margin-top: 0.2in; margin-bottom: 0.2in">This topic shows
34
how to use argtable to implement a program having multiple
35
alternative command line syntaxes. In this case our example program
36
has four alternate syntaxes as follows:</P>
37
<PRE CLASS="western">Usage: multisyntax [-nvR] insert <file> [<file>]... [-o <output>]
38
multisyntax [-nv] remove <file>
39
multisyntax [-v] search <pattern> [-o <output>]
40
multisyntax [--help] [--version]
41
This program demonstrates the use of the argtable2 library for parsing multiple command line syntaxes.
43
-v, --verbose verbose messages
44
-R recurse through subdirectories
45
<file> input file(s)
46
-o <output> output file (default is "-")
47
<pattern> search string
48
--help print this help and exit
49
</PRE><P STYLE="margin-bottom: 0in">
50
A separate argument table is defined for each alternate syntax and
51
each is parsed against the command line in turn. That syntax which
52
returns no errors is taken to be the winner. Should no syntax match
53
the command line then the appropriate error messages are displayed
54
and the program exits. Obviously, you must design your alternate
55
syntaxes to be mutually exclusive, otherwise your program syntax will
56
be ambiguous. Mutual exclusion is achieved in this case by the use of
57
keywords (insert, remove, search) in the command line which uniquely
58
identify each syntax.</P>
59
<P STYLE="margin-top: 0.1in; margin-bottom: 0.2in">Looking at the
60
code, we see that each syntax is defined by its own argument table as
62
<PRE CLASS="western">/* SYNTAX 1: insert [-nvR] <file> [file]... -o <file> */
63
<B>struct</B> arg_rex *cmd1 = arg_rex1(NULL, NULL, "insert", NULL, REG_ICASE, NULL);
64
<B>struct</B> arg_lit *noact1 = arg_lit0("n", NULL, "take no action");
65
<B>struct</B> arg_lit *verbose1 = arg_lit0("v", "verbose", "verbose messages");
66
<B>struct</B> arg_lit *recurse1 = arg_lit0("R", NULL, "recurse through subdirectories");
67
<B>struct</B> arg_file *infiles1 = arg_filen(NULL,NULL, NULL, 1,argc+2, "input files)");
68
<B>struct</B> arg_file *outfile1 = arg_file0("o", NULL, "<output>", "output file (default is \"-\")");
69
<B>struct</B> arg_end *end1 = arg_end(20);
70
<B>void</B>* argtable1[] = {cmd1,noact1,verbose1,recurse1,infiles1,outfile1,end1};
73
/* SYNTAX 2: remove [-nv] <file> */
74
<B>struct</B> arg_rex *cmd2 = arg_rex1(NULL, NULL, "remove", NULL, REG_ICASE, NULL);
75
<B>struct</B> arg_lit *noact2 = arg_lit0("n", NULL, NULL);
76
<B>struct</B> arg_lit *verbose2 = arg_lit0("v", "verbose", NULL);
77
<B>struct</B> arg_file *infiles2 = arg_file1(NULL, NULL, NULL, NULL);
78
<B>struct</B> arg_end *end2 = arg_end(20);
79
<B>void</B>* argtable2[] = {cmd2,noact2,verbose2,infiles2,end2};
82
/* SYNTAX 3: search [-v] <pattern> [-o <file>] [--help] [--version] */
83
<B>struct</B> arg_rex *cmd3 = arg_rex1(NULL, NULL, "search", NULL, REG_ICASE, NULL);
84
<B>struct</B> arg_lit *verbose3 = arg_lit0("v", "verbose", NULL);
85
<B>struct</B> arg_str *pattern3 = arg_str1(NULL, NULL, "<pattern>", "search string");
86
<B>struct</B> arg_file *outfile3 = arg_file0("o", NULL, "<output>", NULL);
87
<B>struct</B> arg_end *end3 = arg_end(20);
88
<B>void</B>* argtable3[] = {cmd3,verbose3,pattern3,outfile3,end3};
91
/* SYNTAX 4: [-help] [-version] */
92
<B>struct</B> arg_lit *help4 = arg_lit0(NULL,"help", "print this help and exit");
93
<B>struct</B> arg_lit *version4 = arg_lit0(NULL,"version", "print version information and exit");
94
<B>struct</B> arg_end *end4 = arg_end(20);
95
<B>void</B>* argtable4[] = {help4,version4,end4};
96
<B>int</B> nerrors4;</PRE><P STYLE="margin-bottom: 0in">
97
Notice that the argument tables keep their contents separate from
98
each other. While it may be tempting to share an <I><FONT FACE="Bitstream Vera Serif">arg_xxx</FONT></I>
99
structure between multiple argument tables, that will not work in
100
this example code since the contents of any shared <I><FONT FACE="Bitstream Vera Serif">arg_xxx</FONT></I>
101
structure will be repeatedly overwritten when each successive
102
argument table is parsed.</P>
103
<P STYLE="margin-bottom: 0in">The insert/remove/search keywords are
104
implemented using <I><FONT FACE="Bitstream Vera Serif">arg_rex</FONT></I>
105
arguments. These are parsed as untagged string arguments that must
106
match a given regular expression: "insert", "remove",
107
and "search" respectively. The REG_ICASE regex flag is also
108
given to allow case insensitive regular expression matching as a
109
nicety. See the argtable programmer's manual for more information of
110
the <I><FONT FACE="Bitstream Vera Serif">arg_rex</FONT></I> argument
112
<P STYLE="margin-bottom: 0.2in">Since we have multiple argument
113
tables, you'll need to pre-set any default argument values in every
114
argument table in which the value appears. Here we set the default
115
value of the output filename argument which appears in both the first
116
and third argument tables as <I><FONT FACE="Bitstream Vera Serif">struct
117
arg_file *outfile1</FONT></I> and <I><FONT FACE="Bitstream Vera Serif">struct
118
arg_file *outfile2</FONT></I> respectively.</P>
119
<PRE CLASS="western">/* set any command line default values prior to parsing */
120
outfile1->filename[0]="-";
121
outfile3->filename[0]="-";</PRE><P STYLE="margin-bottom: 0.2in">
122
Having completed the argument tables, the command line is parsed
123
against each argument table in turn and we record the number of
124
errors reported by each.</P>
125
<PRE CLASS="western">nerrors1 = arg_parse(argc,argv,argtable1);
126
nerrors2 = arg_parse(argc,argv,argtable2);
127
nerrors3 = arg_parse(argc,argv,argtable3);
128
nerrors4 = arg_parse(argc,argv,argtable4);</PRE><P STYLE="margin-bottom: 0.2in">
129
If any of these return zero errors then we have detected a successful
130
matching command line and we can pass the argument data from the
131
matching argument table to our program's main processing routine.
133
<PRE CLASS="western"><B>if</B> (nerrors1==0)
134
exitcode = mymain1(noact1->count, verbose1->count, recurse1->count,
135
outfile1->filename[0], infiles1->filename, infiles1->count);
136
<B>else</B> <B>if</B> (nerrors2==0)
137
exitcode = mymain2(noact2->count, verbose2->count, infiles2->filename[0]);
138
<B>else</B> <B>if</B> (nerrors3==0)
139
exitcode = mymain3(verbose3->count, pattern3->sval[0], outfile3->filename[0]);
140
<B>else</B> <B>if</B> (nerrors4==0)
141
exitcode = mymain4(help4->count, version4->count, progname,<BR> argtable1, argtable2, argtable3, argtable4);</PRE><P STYLE="margin-bottom: 0in">
142
Should they all return errors then we must display the appropriate
143
syntax error messages. The trick is knowing which error messages to
144
display. Simply displaying the error messages for each and every
145
syntax will work, but is overkill as it generates a lot of irrelevant
146
messages. A better strategy is to display only those errors related
147
to the syntax that gave the fewest errors on the presumption that the
148
user got it mostly correct. The strategy used in this example however
149
is to utilise the presence of any keywords ("insert",
150
"remove", "search") as markers to indicate which
151
syntax the user intended and only display the errors for that syntax.
152
Remember that the keywords were implemented using <I><FONT FACE="Bitstream Vera Serif">arg_rex</FONT></I>
153
argument structures (<FONT FACE="Bitstream Vera Serif"><I>cmd1</I>,
154
<I>cmd2</I>, <I>cmd3</I></FONT>) and these will return a count of 0
155
if the keyword was missing from the command line and 1 otherwise.
156
Thus we can test the presence of each keyword by checking the count
157
value stored in the <I>cmd1</I>, <I>cmd2</I>, and <I>cmd3</I>
160
<P STYLE="margin-bottom: 0.2in">So if the "insert" keyword
161
was given on the command line then we display only those errors
162
associated with the first argument table, namely, the errors stored
163
in <I><FONT FACE="Bitstream Vera Serif">struct arg_end *end1</FONT></I>.</P>
164
<PRE CLASS="western"><B>if</B> (cmd1->count > 0)
166
<I>/* here the cmd1 argument was correct, so presume syntax 1 was intended target */</I>
167
arg_print_errors(stdout,end1,progname);
168
printf("usage: %s ", progname);
169
arg_print_syntax(stdout,argtable1,"\n");
170
}</PRE><P STYLE="margin-bottom: 0.2in">
171
Likewise for the "remove" and "search" keywords
172
of the second and third argument tables</P>
173
<PRE CLASS="western"><B>else</B> <B>if</B> (cmd2->count > 0)
175
<I>/* here the cmd2 argument was correct, so presume syntax 2 was intended target */</I>
176
arg_print_errors(stdout,end2,progname);
177
printf("usage: %s ", progname);
178
arg_print_syntax(stdout,argtable2,"\n");
180
<B>else</B> <B>if</B> (cmd3->count > 0)
182
<I>/* here the cmd3 argument was correct, so presume syntax 3 was intended target */</I>
183
arg_print_errors(stdout,end3,progname);
184
printf("usage: %s ", progname);
185
arg_print_syntax(stdout,argtable3,"\n");
186
}</PRE><P STYLE="margin-bottom: 0.2in">
187
If none of the keywords were detected we display a message to that
188
effect followed by the full usage description.</P>
189
<PRE CLASS="western">else
191
<I>/* no correct cmd literals were given, so we cant presume which syntax was intended */</I>
192
printf("%s: missing <insert|remove|search> command.\n",progname);
193
printf("usage 1: %s ", progname); arg_print_syntax(stdout,argtable1,"\n");
194
printf("usage 2: %s ", progname); arg_print_syntax(stdout,argtable2,"\n");
195
printf("usage 3: %s ", progname); arg_print_syntax(stdout,argtable3,"\n");
196
printf("usage 4: %s", progname); arg_print_syntax(stdout,argtable4,"\n");
197
}</PRE><P STYLE="margin-bottom: 0.2in">
198
Lastly, remember to clean up all the argument tables at program's
200
<PRE CLASS="western">arg_freetable(argtable1,sizeof(argtable1)/sizeof(argtable1[0]));
201
arg_freetable(argtable2,sizeof(argtable2)/sizeof(argtable2[0]));
202
arg_freetable(argtable3,sizeof(argtable3)/sizeof(argtable3[0]));
203
arg_freetable(argtable4,sizeof(argtable4)/sizeof(argtable4[0]));</PRE>
205
<H1>2. Writing custom callbacks</H1>
206
<P STYLE="margin-bottom: 0in"><I><B>example code:</B>
207
<FONT FACE="Bitstream Vera Serif"><installdir>/share/doc/argtable2/example/callbacks.c</FONT></I></P>
208
<P STYLE="margin-top: 0.2in; margin-bottom: 0.2in">This topic shows
209
how to write your own argtable callback functions for controlling the
210
parsing, validation, and error reporting aspects of the command line
211
parsing. Each <I>arg_xxx</I> struct has four callback routines that
212
get called by the argtable parser. These are buried within the
213
<I>arg_hdr</I> structure that each <I>arg_xxx</I> structure has.
214
Among other things, you can see the relevant function pointers below.
215
They are called <I>resetfn</I>, <I>scanfn</I>, <I>checkfn</I>, and
217
<PRE CLASS="western">typedef void (arg_resetfn)(void *parent);
218
typedef int (arg_scanfn)(void *parent, const char *argval);
219
typedef int (arg_checkfn)(void *parent);
220
typedef void (arg_errorfn)(void *parent, FILE *fp, int error, const char *argval, const char *progname);
224
<FONT COLOR="#000000">char flag;</FONT>
225
const char *shortopts;
226
const char *longopts;
227
const char *datatype;
228
const char *glossary;
232
<B>arg_resetfn *resetfn;</B>
233
<B>arg_scanfn *scanfn; </B>
234
<B>arg_checkfn *checkfn;</B>
235
<B>arg_errorfn *errorfn;</B>
236
<FONT COLOR="#000000">void *priv;</FONT><FONT COLOR="#666666"> </FONT>
237
};</PRE><P STYLE="margin-bottom: 0in">
238
These function pointers are always pre-set by the <I>arg_xxx</I>
239
constructor functions to the default routines for that argument type
240
and ordinarily there is no need to change them. However, you may
241
replace them with your own custom routines if you wish. Thus when
242
argtable parses the command line for these particular argument types,
243
it will call your custom callbacks rather than the default routines.
244
However responsibility comes with control, and all callbacks must
245
implement certain features that argtable expects. These are each
246
discussed in turn.</P>
247
<H4>void resetfn(void *parent)</H4>
248
<P STYLE="margin-bottom: 0.2in">The <I>resetfn</I> of each <I>arg_xxx</I>
249
within an argument table is called once by the parser prior to
250
parsing the command line. This provides the opportunity to initialise
251
the <I>arg_xxx</I> structure prior to parsing and nominally requires
252
resetting the argument count to zero. The <I>parent</I> parameter is
253
actually a pointer to the pertinent <I>arg_xxx</I> structure, and
254
should be cast appropriately. The casting may be done in the function
255
definition as shown in this example for an <I>arg_int</I> struct.
257
<PRE CLASS="western">void myresetfn(struct arg_int *parent)
260
}</PRE><P STYLE="margin-bottom: 0in">
261
The storage space for the parsed argument values should <U>not</U> be
262
initialised since the user may have deliberately set default values
263
that should be retained.</P>
264
<H4>int scanfn(void *parent, const char *argval)</H4>
265
<P STYLE="margin-bottom: 0.2in">The parser calls an <I>arg_xxx</I>'s
266
scanfn routine once for each matching command line argument that
267
needs to be parsed. Its purpose is to extract the argument's data
268
value from the argument string in <I>argval</I>, convert it to the
269
appropriate data type, and store the result in the <I>arg_xxx</I>'s
270
data array. The function must return zero to indicate success and a
271
non-zero error code otherwise. The error codes may be of your own
272
choosing as they will latter be handled by your own <I>errorfn</I>
274
<PRE CLASS="western">enum {EMINCOUNT=1, EMAXCOUNT, EBADINT};
276
int myscanfn(struct arg_int *parent, const char *argval)
280
<I>/* return EMAXCOUNT if we have exceeded the maximum argument count */</I>
281
if (parent->count == parent->hdr.maxcount )
284
/* extract base10 integer from argval string into val */
285
/* return EBADINT if conversion failed */
286
val = (int)strtol(argval,&end,10);
290
<I>/* <perform custom checks here> */</I>
292
/* store the value in parent's ival[] array and increment the argument count */
293
parent->ival[parent->count++] = val;
295
/* return zero to indicate success */
297
}</PRE><P STYLE="margin-bottom: 0in">
298
Do <U>not</U> print error messages from within <I>scanfn</I> as the
299
user may wish to delay the error messages until alternative argument
300
tables have been tried. In the meantime the parser will save each
301
returned error code in the argument table's <I>arg_end</I> structure.
302
Latter, the <I>arg_print_errors</I> function will be called to
303
retrieve those error codes from <I>arg_end</I> and pass them onto the
304
<I>errorfn</I> callbacks whose job is to print the appropriate
306
<H4>int checkfn(void *parent)</H4>
307
<P STYLE="margin-bottom: 0.2in">The <I>checkfn</I> of each <I>arg_xxx</I>
308
within an the argument table is called by the parser once upon
309
completion of command line parsing. It provides the opportunity to
310
perform any post-parse error checks and nominally requires checking
311
the minimum argument count for the <I>arg_xxx</I> structure has been
314
<PRE CLASS="western">int mycheckfn(struct arg_int *parent)
316
<I>/* return EMINCOUNT if the minimum number of arguments is not present. */</I>
317
if (parent->count < parent->hdr.mincount)
320
<I>/* <perform custom checks here> */</I>
322
<I>/* all checks passed */</I>
324
}</PRE><P STYLE="margin-bottom: 0in">
325
Like scanfn, it should return zero for success and a user-defined
326
non-zero error code otherwise. These error codes are likewise
327
destined to be passed onto errorfn.</P>
328
<H4>int errorfn(void *parent, FILE *fp, int errorcode, const char
329
*argval, const char *progname)</H4>
330
<P STYLE="margin-bottom: 0.2in">When the users wishes to print the
331
syntax error messages he or she calls the <I>arg_print_errors</I>
332
function which in turn calls the <I>errorfn</I> routine of each
333
<I>arg_xxx</I> for each error that was previously reported. This is
334
where the error messages for the corresponding error codes are
335
printed. The <I>parent</I> pointer refers to the pertinent <I>arg_xxx</I>
336
structure, and <I>FILE* fp</I> designates the output stream onto
337
which the error messages should be printed. The <I>errorcode</I>
338
parameter contains the same value returned by the <I>scanfn</I> or
339
<I>checkfn</I> routine that reported the error, and <I>argval</I>
340
points to the offending command line argument string. The <I>progname</I>
341
parameter is the same one passed to the <I>arg_print_errors</I>
342
function, and is expected to contain the name of the program which is
343
usually prefixed onto the error message by convention. Notice that
344
each <I>arg_xxx</I> need only handle the error codes generated by its
345
own <I>scanfn</I> and <I>checkfn</I> routines.</P>
346
<PRE CLASS="western">void myerrorfn(struct arg_int *parent, FILE *fp, int errorcode, const char *argval, const char *progname)
348
<I>/* for convenience */</I>
349
const char *shortopts = parent->hdr.shortopts;
350
const char *longopts = parent->hdr.longopts;
351
const char *datatype = parent->hdr.datatype;
353
<I>/* prefix all error messages with the program name */</I>
354
fprintf(fp,"%s: ",progname);
359
fputs("missing option ",fp);
360
arg_print_option(fp,shortopts,longopts,datatype,"\n");
364
fputs("excess option ",fp);
365
arg_print_option(fp,shortopts,longopts,argval,"\n");
369
arg_print_option(fp,shortopts,longopts,argval," is not a valid <int>\n");
372
<I>/* <add custom error messages here> */</I>
376
Hooking the callbacks into the arg_xxx structure</H4>
377
<P STYLE="margin-bottom: 0.2in">There are no functions for
378
registering callbacks with arg_xxx structures, you simply write the
379
function pointers directly into the arg_xxx structure after it has
380
been constructed.</P>
381
<PRE CLASS="western">struct arg_int *val = arg_intn(NULL,NULL,NULL,2,100,"blah blah");
383
/* replace the default arg_int parser routines with custom routines */
384
val->hdr.resetfn = (arg_resetfn*)myresetfn;
385
val->hdr.scanfn = (arg_scanfn*)myscanfn;
386
val->hdr.checkfn = (arg_checkfn*)mycheckfn;
387
val->hdr.errorfn = (arg_errorfn*)myerrorfn;</PRE><H4>
388
Words of restraint</H4>
389
<P STYLE="margin-bottom: 0in">Callbacks are part of the argtable
390
design to make it possible to add new argument data types in future
391
without changing the base argtable source code. Since they exist,
392
they may be exploited by the programmer for finer control of the
393
parsing and error validation but that was never their intended role.
394
It is the authors view that the majority of custom argument checking
395
tasks are better done as a second stage in your program after
396
argtable has done its job. It is usually much simpler to implement
397
additional post-parse checks in your own code than creating custom
398
argtable callbacks that do it all. Custom callbacks are really only
399
required if you are scanning data types that argtable does not
400
support natively. In such cases you may also need to create a custom
401
arg_xxx structure in which to store the results, as is described in
404
<H1>3. Creating custom argument types</H1>
405
<P STYLE="margin-bottom: 0in"><I><B>example code:</B>
406
<FONT FACE="Bitstream Vera Serif"><installdir>/share/doc/argtable2/example/argcustom.c,
407
argxxx.c, argxxx.h</FONT></I></P>
408
<P STYLE="margin-top: 0.2in; margin-bottom: 0in">This topic shows how
409
to write new argument types for use with the argtable parser. These
410
need not be compiled into the library base code, so you can create
411
custom argument types for specific programs at will. A custom
412
argument type is required if you need to handle a data type that is
413
not supported natively by the argtable library. It involves defining
414
a new <I>arg_xxx</I> structure and writing the callback and
415
constructor functions that go with it. If you merely wish to alter
416
the parsing and validation rules applied to an existing <I>arg_xxx</I>
417
data type then hooking your own custom callbacks into the existing
418
structure as described in the previous topic is more appropriate.</P>
419
<H4>Defining an arg_xxx structure</H4>
420
<P STYLE="margin-bottom: 0.2in">Every <I>arg_xxx</I> struct must have
421
an <I>arg_hdr</I> struct as its first data member. Internally,
422
argtable casts all <I>arg_xxx</I> structures to <I>arg_hdr</I>
423
structures, so it is imperative that <I>arg_hdr</I> be the first data
424
member. Argtable uses the information within it to cast the command
425
line option into the format required by GNU getopt which actually
426
does the parsing.</P>
427
<PRE CLASS="western">struct arg_xxx
429
struct arg_hdr hdr; /* The mandatory argtable header struct */
430
int count; /* Number of matching arguments parsed */
431
<xxx> *data; /* Array for storing the argument values */
432
... /* Other custom fields go here */
433
};</PRE><P STYLE="margin-bottom: 0.2in">
434
Custom data members follow the <I>arg_hdr</I> struct. Since argtable
435
supports multiple instances of any given command line argument, it is
436
usual that your structure provides an array for storing multiple
437
argument values (<I>arg_xxx.data)</I> and a count of them
438
(<I>arg_xxx.count)</I>. Add any other fields you need for your custom
439
parsing routines as required. Any internal data you would prefer to
440
hide from the end-user can be stored in a user-defined private data
441
structure that is encapsulated by the <I>arg_hdr</I> structure as you
443
<PRE CLASS="western">struct arg_xxx_priv
445
/* Private custom data goes here */
448
Defining the argx_xxx constructors</H4>
449
<P STYLE="margin-bottom: 0.2in">Each arg_xxx structure should have a
450
constructor function that is responsible for allocating memory for it
451
and populating the data within it. By convention, there are
452
ordinarily three forms of constructor function for each arg_xxx
454
<PRE CLASS="western">struct arg_xxx* arg_xxx0(const char* shortopts, const char* longopts,<BR> const char *datatype, const char *glossary);
456
struct arg_xxx* arg_xxx1(const char* shortopts, const char* longopts,<BR> const char *datatype, const char *glossary);
458
struct arg_xxx* arg_xxxn(const char* shortopts, const char* longopts,<BR> const char *datatype,
459
int mincount, int maxcount,<BR> const char *glossary);</PRE><P STYLE="margin-bottom: 0in">
460
The different forms provide a convenient means for specifying command
461
line arguments that accept either zero-or-one, exactly-one, or many
462
instances on the command line. The first two forms are typically
463
implemented as wrapper functions of the third. You may customise the
464
actual parameters to fit your purposes, the declarations above are
465
merely examples of common forms.</P>
466
<P STYLE="margin-bottom: 0in"><IMG SRC="argxxx.gif" NAME="Graphic1" ALIGN=LEFT WIDTH=671 HEIGHT=623 BORDER=0><BR CLEAR=LEFT><BR>
468
<P STYLE="margin-bottom: 0.2in">The diagram shows the general layout
469
of the data structure that should be returned by the <I>arg_xxx</I>
470
constructor function(s). It comprises of a single contiguous block of
471
heap allocated memory, with the <I>arg_xxx</I> struct at its head,
472
followed by the storage space for <I>maxcount</I> argument values as
473
well as an optional private data structure that may be used to hide
474
internal data from the end-user. If the allocation failed then the
475
constructor should return NULL.</P>
476
<PRE CLASS="western">size_t nbytes;
477
struct arg_xxx *result;
479
nbytes = sizeof(struct arg_xxx) + sizeof(struct arg_xxx_priv) + maxcount*sizeof(<xxx>) ;
480
result = (struct arg_xxx*)malloc(nbytes);</PRE><P STYLE="margin-bottom: 0.2in">
481
The entire <I>arg_hdr</I> structure must be populated by the
482
constructor, including the pointers to the appropriate callback
483
functions, the enclosing <I>arg_xxx</I> structure (<I>void *parent</I>),
484
and the private data structure (<I>void *priv</I>).
486
<PRE CLASS="western">result->hdr.flag = ARG_HASVALUE; /* argument accepts a value */
487
result->hdr.shortopts = shortopts; /* short options */
488
result->hdr.longopts = longopts; /* long options */
489
result->hdr.datatype = datatype ? datatype : "<xxx>"; /* datatype description */
490
result->hdr.glossary = glossary; /* glossary description */
491
result->hdr.mincount = mincount; /* minimum number of arguments */
492
result->hdr.maxcount = maxcount; /* maximum number of arguments */
493
result->hdr.parent = result; /* ptr to parent arg_xxx struct */
494
result->hdr.resetfn = (arg_resetfn*)resetfn; /* ptr to resetfn callback */
495
result->hdr.scanfn = (arg_scanfn*)scanfn; /* ptr to scanfn callback */
496
result->hdr.checkfn = (arg_checkfn*)checkfn; /* ptr to checkfn callback */
497
result->hdr.errorfn = (arg_errorfn*)errorfn; /* ptr to errorfn callback */
498
result->hdr.priv = result + 1; /* ptr to private data */ </PRE><P STYLE="margin-bottom: 0.2in">
499
The custom <I>arg_xxx</I> fields should also be populated,
500
particularly the pointer to the argument storage array. The values
501
within the array may or may not be initialised at your discretion.</P>
502
<PRE CLASS="western"><I>/* locate the data[maxcount] array immediately after the private data structure */</I>
503
result->data = (<xxx>*)((struct arg_xxx_priv*)(result->hdr.priv) + 1);
505
/* init the remaining of the arg_xxx struct variables */
506
result->count = 0;
507
...</PRE><P STYLE="margin-bottom: 0in">
508
Lastly, we return a pointer to the completed data structure</P>
509
<PRE CLASS="western" STYLE="margin-top: 0.2in; margin-bottom: 0.2in">return result;</PRE><P STYLE="margin-bottom: 0in">
b'\\ No newline at end of file'