~ubuntu-branches/ubuntu/trusty/argtable2/trusty

« back to all changes in this revision

Viewing changes to doc/argtable2-advanced.html

  • Committer: Bazaar Package Importer
  • Author(s): Shachar Shemesh
  • Date: 2005-09-07 12:28:43 UTC
  • Revision ID: james.westby@ubuntu.com-20050907122843-tvghbt3xckztce8m
Tags: upstream-2.4
ImportĀ upstreamĀ versionĀ 2.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
 
2
<HTML>
 
3
<HEAD>
 
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">
 
11
        <STYLE>
 
12
        <!--
 
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 }
 
17
        -->
 
18
        </STYLE>
 
19
</HEAD>
 
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">&lt;installdir&gt;/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 &lt;file&gt; [&lt;file&gt;]... [-o &lt;output&gt;]
 
38
       multisyntax [-nv] remove &lt;file&gt;
 
39
       multisyntax [-v] search &lt;pattern&gt; [-o &lt;output&gt;]
 
40
       multisyntax [--help] [--version]
 
41
This program demonstrates the use of the argtable2 library for parsing multiple command line syntaxes.
 
42
  -n                take no action
 
43
  -v, --verbose     verbose messages
 
44
  -R                recurse through subdirectories
 
45
  &lt;file&gt;            input file(s)
 
46
  -o &lt;output&gt;       output file (default is &quot;-&quot;)
 
47
  &lt;pattern&gt;         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
 
61
follows:</P>
 
62
<PRE CLASS="western">/* SYNTAX 1: insert [-nvR] &lt;file&gt; [file]... -o &lt;file&gt; */
 
63
<B>struct</B> arg_rex  *cmd1     = arg_rex1(NULL, NULL, &quot;insert&quot;, NULL, REG_ICASE, NULL);
 
64
<B>struct</B> arg_lit  *noact1   = arg_lit0(&quot;n&quot;,  NULL, &quot;take no action&quot;);
 
65
<B>struct</B> arg_lit  *verbose1 = arg_lit0(&quot;v&quot;, &quot;verbose&quot;, &quot;verbose messages&quot;);
 
66
<B>struct</B> arg_lit  *recurse1 = arg_lit0(&quot;R&quot;,  NULL, &quot;recurse through subdirectories&quot;);
 
67
<B>struct</B> arg_file *infiles1 = arg_filen(NULL,NULL, NULL, 1,argc+2, &quot;input files)&quot;);
 
68
<B>struct</B> arg_file *outfile1 = arg_file0(&quot;o&quot;, NULL, &quot;&lt;output&gt;&quot;, &quot;output file (default is \&quot;-\&quot;)&quot;);
 
69
<B>struct</B> arg_end  *end1     = arg_end(20);
 
70
<B>void</B>* argtable1[] = {cmd1,noact1,verbose1,recurse1,infiles1,outfile1,end1};
 
71
<B>int</B> nerrors1;
 
72
 
 
73
/* SYNTAX 2: remove [-nv] &lt;file&gt; */
 
74
<B>struct</B> arg_rex  *cmd2     = arg_rex1(NULL, NULL, &quot;remove&quot;, NULL, REG_ICASE, NULL);
 
75
<B>struct</B> arg_lit  *noact2   = arg_lit0(&quot;n&quot;, NULL, NULL);
 
76
<B>struct</B> arg_lit  *verbose2 = arg_lit0(&quot;v&quot;, &quot;verbose&quot;, 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};
 
80
<B>int</B> nerrors2;
 
81
 
 
82
/* SYNTAX 3: search [-v] &lt;pattern&gt; [-o &lt;file&gt;] [--help] [--version] */
 
83
<B>struct</B> arg_rex  *cmd3     = arg_rex1(NULL, NULL, &quot;search&quot;, NULL, REG_ICASE, NULL);
 
84
<B>struct</B> arg_lit  *verbose3 = arg_lit0(&quot;v&quot;, &quot;verbose&quot;, NULL);
 
85
<B>struct</B> arg_str  *pattern3 = arg_str1(NULL, NULL, &quot;&lt;pattern&gt;&quot;, &quot;search string&quot;);
 
86
<B>struct</B> arg_file *outfile3 = arg_file0(&quot;o&quot;, NULL, &quot;&lt;output&gt;&quot;, NULL);
 
87
<B>struct</B> arg_end  *end3     = arg_end(20);
 
88
<B>void</B>* argtable3[] = {cmd3,verbose3,pattern3,outfile3,end3};
 
89
<B>int</B> nerrors3;
 
90
 
 
91
/* SYNTAX 4: [-help] [-version] */
 
92
<B>struct</B> arg_lit *help4    = arg_lit0(NULL,&quot;help&quot;,    &quot;print this help and exit&quot;);
 
93
<B>struct</B> arg_lit *version4 = arg_lit0(NULL,&quot;version&quot;, &quot;print version information and exit&quot;);
 
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: &quot;insert&quot;, &quot;remove&quot;,
 
107
and &quot;search&quot; 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
 
111
type.</P>
 
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-&gt;filename[0]=&quot;-&quot;;
 
121
outfile3-&gt;filename[0]=&quot;-&quot;;</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. 
 
132
</P>
 
133
<PRE CLASS="western"><B>if</B> (nerrors1==0)
 
134
    exitcode = mymain1(noact1-&gt;count, verbose1-&gt;count, recurse1-&gt;count,
 
135
                       outfile1-&gt;filename[0], infiles1-&gt;filename, infiles1-&gt;count);
 
136
<B>else</B> <B>if</B> (nerrors2==0)
 
137
    exitcode = mymain2(noact2-&gt;count, verbose2-&gt;count, infiles2-&gt;filename[0]);
 
138
<B>else</B> <B>if</B> (nerrors3==0)
 
139
    exitcode = mymain3(verbose3-&gt;count, pattern3-&gt;sval[0], outfile3-&gt;filename[0]);
 
140
<B>else</B> <B>if</B> (nerrors4==0)
 
141
    exitcode = mymain4(help4-&gt;count, version4-&gt;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 (&quot;insert&quot;,
 
150
&quot;remove&quot;, &quot;search&quot;) 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>
 
158
structures. 
 
159
</P>
 
160
<P STYLE="margin-bottom: 0.2in">So if the &quot;insert&quot; 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-&gt;count &gt; 0)
 
165
   {
 
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(&quot;usage: %s &quot;, progname);
 
169
   arg_print_syntax(stdout,argtable1,&quot;\n&quot;);
 
170
   }</PRE><P STYLE="margin-bottom: 0.2in">
 
171
Likewise for the &quot;remove&quot; and &quot;search&quot; keywords
 
172
of the second and third argument tables</P>
 
173
<PRE CLASS="western"><B>else</B> <B>if</B> (cmd2-&gt;count &gt; 0)
 
174
   {
 
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(&quot;usage: %s &quot;, progname);
 
178
   arg_print_syntax(stdout,argtable2,&quot;\n&quot;);
 
179
   }
 
180
<B>else</B> <B>if</B> (cmd3-&gt;count &gt; 0)
 
181
   {
 
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(&quot;usage: %s &quot;, progname);
 
185
   arg_print_syntax(stdout,argtable3,&quot;\n&quot;);
 
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
 
190
   {
 
191
   <I>/* no correct cmd literals were given, so we cant presume which syntax was intended */</I>
 
192
   printf(&quot;%s: missing &lt;insert|remove|search&gt; command.\n&quot;,progname);
 
193
   printf(&quot;usage 1: %s &quot;, progname); arg_print_syntax(stdout,argtable1,&quot;\n&quot;);
 
194
   printf(&quot;usage 2: %s &quot;, progname); arg_print_syntax(stdout,argtable2,&quot;\n&quot;);
 
195
   printf(&quot;usage 3: %s &quot;, progname); arg_print_syntax(stdout,argtable3,&quot;\n&quot;);
 
196
   printf(&quot;usage 4: %s&quot;,  progname); arg_print_syntax(stdout,argtable4,&quot;\n&quot;);
 
197
   }</PRE><P STYLE="margin-bottom: 0.2in">
 
198
Lastly, remember to clean up all the argument tables at program's
 
199
end.</P>
 
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>
 
204
<HR>
 
205
<H1>2. Writing custom callbacks</H1>
 
206
<P STYLE="margin-bottom: 0in"><I><B>example code:</B>
 
207
<FONT FACE="Bitstream Vera Serif">&lt;installdir&gt;/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
 
216
<I>errorfn</I>.</P>
 
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);
 
221
 
 
222
struct arg_hdr
 
223
   {
 
224
   <FONT COLOR="#000000">char flag;</FONT>
 
225
   const char *shortopts;
 
226
   const char *longopts; 
 
227
   const char *datatype;
 
228
   const char *glossary; 
 
229
   int mincount;
 
230
   int maxcount;
 
231
   void *parent;
 
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. 
 
256
</P>
 
257
<PRE CLASS="western">void myresetfn(struct arg_int *parent)
 
258
   {
 
259
   parent-&gt;count=0;
 
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>
 
273
callback.</P>
 
274
<PRE CLASS="western">enum {EMINCOUNT=1, EMAXCOUNT, EBADINT};
 
275
 
 
276
int myscanfn(struct arg_int *parent, const char *argval)
 
277
   {
 
278
   int val;
 
279
   char *end;
 
280
   <I>/* return EMAXCOUNT if we have exceeded the maximum argument count */</I>
 
281
   if (parent-&gt;count == parent-&gt;hdr.maxcount )
 
282
      return EMAXCOUNT;
 
283
 
 
284
   /* extract base10 integer from argval string into val */
 
285
   /* return EBADINT if conversion failed */
 
286
   val = (int)strtol(argval,&amp;end,10);
 
287
   if (*end!=0)
 
288
      return EBADINT;  
 
289
 
 
290
   <I>/* &lt;perform custom checks here&gt; */</I>
 
291
 
 
292
   /* store the value in parent's ival[] array and increment the argument count */
 
293
   parent-&gt;ival[parent-&gt;count++] = val;
 
294
 
 
295
   /* return zero to indicate success */
 
296
   return 0;
 
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
 
305
messages.</P>
 
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
 
312
satisfied. 
 
313
</P>
 
314
<PRE CLASS="western">int mycheckfn(struct arg_int *parent)
 
315
    {
 
316
    <I>/* return EMINCOUNT if the minimum number of arguments is not present. */</I>
 
317
    if (parent-&gt;count &lt; parent-&gt;hdr.mincount)
 
318
        return EMINCOUNT;
 
319
 
 
320
    <I>/* &lt;perform custom checks here&gt; */</I>
 
321
 
 
322
    <I>/* all checks passed */</I>
 
323
    return 0;
 
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)
 
347
    {
 
348
    <I>/* for convenience */</I>
 
349
    const char *shortopts = parent-&gt;hdr.shortopts;
 
350
    const char *longopts  = parent-&gt;hdr.longopts;
 
351
    const char *datatype  = parent-&gt;hdr.datatype;
 
352
 
 
353
    <I>/* prefix all error messages with the program name */</I>
 
354
    fprintf(fp,&quot;%s: &quot;,progname);
 
355
 
 
356
    switch(errorcode)
 
357
        {
 
358
        case EMINCOUNT:
 
359
            fputs(&quot;missing option &quot;,fp);
 
360
            arg_print_option(fp,shortopts,longopts,datatype,&quot;\n&quot;);
 
361
            break;
 
362
 
 
363
        case EMAXCOUNT:
 
364
            fputs(&quot;excess option &quot;,fp);
 
365
            arg_print_option(fp,shortopts,longopts,argval,&quot;\n&quot;);
 
366
            break;
 
367
 
 
368
        case EBADINT:
 
369
            arg_print_option(fp,shortopts,longopts,argval,&quot; is not a valid &lt;int&gt;\n&quot;);
 
370
            break;
 
371
 
 
372
        <I>/* &lt;add custom error messages here&gt; */</I>        
 
373
 
 
374
        }
 
375
    }</PRE><H4>
 
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,&quot;blah blah&quot;); 
 
382
 
 
383
/* replace the default arg_int parser routines with custom routines */
 
384
val-&gt;hdr.resetfn = (arg_resetfn*)myresetfn;
 
385
val-&gt;hdr.scanfn  = (arg_scanfn*)myscanfn;
 
386
val-&gt;hdr.checkfn = (arg_checkfn*)mycheckfn;
 
387
val-&gt;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
 
402
the next topic.</P>
 
403
<HR>
 
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">&lt;installdir&gt;/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
 
428
   {
 
429
   struct arg_hdr hdr;      /* The mandatory argtable header struct */
 
430
   int count;               /* Number of matching arguments parsed */
 
431
   &lt;xxx&gt; *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
 
442
will see next.</P>
 
443
<PRE CLASS="western">struct arg_xxx_priv
 
444
   {
 
445
   /* Private custom data goes here */
 
446
   ...
 
447
   };</PRE><H4>
 
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
 
453
struct</P>
 
454
<PRE CLASS="western">struct arg_xxx* arg_xxx0(const char* shortopts, const char* longopts,<BR>                         const char *datatype, const char *glossary);
 
455
 
 
456
struct arg_xxx* arg_xxx1(const char* shortopts, const char* longopts,<BR>                         const char *datatype, const char *glossary);
 
457
 
 
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>
 
467
</P>
 
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;
 
478
 
 
479
nbytes = sizeof(struct arg_xxx) + sizeof(struct arg_xxx_priv) + maxcount*sizeof(&lt;xxx&gt;) ;
 
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>). 
 
485
</P>
 
486
<PRE CLASS="western">result-&gt;hdr.flag      = ARG_HASVALUE;                  /* argument accepts a value */
 
487
result-&gt;hdr.shortopts = shortopts;                     /* short options */
 
488
result-&gt;hdr.longopts  = longopts;                      /* long options */
 
489
result-&gt;hdr.datatype  = datatype ? datatype : &quot;&lt;xxx&gt;&quot;; /* datatype description */
 
490
result-&gt;hdr.glossary  = glossary;                      /* glossary description */
 
491
result-&gt;hdr.mincount  = mincount;                      /* minimum number of arguments */
 
492
result-&gt;hdr.maxcount  = maxcount;                      /* maximum number of arguments */
 
493
result-&gt;hdr.parent    = result;                        /* ptr to parent arg_xxx struct */
 
494
result-&gt;hdr.resetfn   = (arg_resetfn*)resetfn;         /* ptr to resetfn callback */
 
495
result-&gt;hdr.scanfn    = (arg_scanfn*)scanfn;           /* ptr to scanfn callback */
 
496
result-&gt;hdr.checkfn   = (arg_checkfn*)checkfn;         /* ptr to checkfn callback */
 
497
result-&gt;hdr.errorfn   = (arg_errorfn*)errorfn;         /* ptr to errorfn callback */
 
498
result-&gt;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-&gt;data  = (&lt;xxx&gt;*)((struct arg_xxx_priv*)(result-&gt;hdr.priv) + 1);
 
504
 
 
505
/* init the remaining of the arg_xxx struct variables */
 
506
result-&gt;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">
 
510
<BR>
 
511
</P>
 
512
</BODY>
 
513
</HTML>
 
 
b'\\ No newline at end of file'