File: callbacks.c

package info (click to toggle)
argtable2 13-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 6,312 kB
  • sloc: sh: 9,928; ansic: 4,565; makefile: 101
file content (211 lines) | stat: -rw-r--r-- 7,773 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
/*********************************************************************
Example source code for using the argtable2 library to implement:

    myprog [-lRv] [-k <int>] [-D MACRO]... [-o <output>] [--help]
       [--version] <file> [<file>]...

This file is part of the argtable2 library.
Copyright (C) 1998-2001,2003-2011 Stewart Heitmann
sheitmann@users.sourceforge.net

The argtable2 library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.

This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA.
**********************************************************************/
#include <argtable2.h>
#include <stdlib.h>


/* error codes returned by myscanfn and mycheckfn, and received by myerrorfn. */
/* The exact values are unimportant provided they are non-zero and consistent */
/* between those three functions.                                             */                            
enum {EMINCOUNT=1, EMAXCOUNT, EBADINT, EZEROVAL, EODDCOUNT, EBADSUM};

/* 
 * Argtable calls an arg_xxx structure's hdr.scanfn routine once for each matching
 * command line argument.
 * The scanfn routine must extract the argument data value from the argv[]
 * string passed in argval and write the result back into the arg_xxx data
 * array.
 * Error codes returned by this function are saved by argtable and later
 * passed to the errorfn callback.
 *
 * This particular myscanfn is for arg_int structs. For demonstration purposes
 * it performs additional error checking to verify that the integer value
 * extracted is non-zero. Other custom rules could also be implemented at
 * that point in the code.
 */ 
int myscanfn(struct arg_int *parent,  /* ptr to relevant arg_int structure in argument table */
             const char *argval)      /* ptr to current command line argv[] string */ 
    {
    int val;
    char *end;

    /* return EMAXCOUNT error if we have reached the upper limit of allowed arguments for parent arg_int struct. */
    /* This is a mandatory check that scanfn must alwasy perform */
    if (parent->count == parent->hdr.maxcount )
        return EMAXCOUNT;

    /* extract base10 integer from argval string into val, return EBADINT if conversion failed */
    val = (int)strtol(argval,&end,10);
    if (*end!=0)
        return EBADINT;

    /* check the value is non-zero (for example purposes) and return EZEROVAL if it is not the case*/
    if (val==0)
        return EZEROVAL;

    /* all checks are passed, store the value in parent's ival[] array and increment the count */
    parent->ival[parent->count++] = val;

    /* return zero to indicate success */
    return 0;
    }


/* 
 * Argtable calls an arg_xxx structure's hdr.checkfn routine upon completion
 * of parsing the entire command line. It allows post-parse checks to be performed,
 * such as verifying the minimum number of exepected arguments have been received.
 * Like scanfn, error codes returned by this function are saved by argtable and later
 * passed to the errorfn callback.
 * 
 * This particular mycheckfn is for arg_int structs. For demonstration purposes
 * it performs additional checking to ensure that the number of arguments is even,
 * and that all values given sum to exactly 100.
 */
int mycheckfn(struct arg_int *parent)
    {
    int i;
    long sum = 0;

    /* return EMINCOUNT if the minimum number of arguments is not present. */
    /* This is a mandatory check that checkfn must alwasy perform. */
    if (parent->count < parent->hdr.mincount)
        return EMINCOUNT;

    /* return EODDCOUNT if the number of argument occurences is not even (for example purposes) */
    if (parent->count % 2 != 0)
        return EODDCOUNT;

    /* return EBADSUM if the sum of the arguments is not 100 (for example purposes) */
    for (i=0; i<parent->count; i++)
        sum += parent->ival[i];
    if (sum!=100)
        return EBADSUM;

    /* all checks passed */
    return 0;
    }


/* 
 * Argtable calls an arg_xxx structure's hdr.errorfn routine when arg_print_errors is executed.
 * The errorfn routine must print a meaningful error messages for the given error code.
 * The error codes are the same values returned by scanfn and checkfn.
 */
void myerrorfn(struct arg_int *parent, FILE *fp, int errorcode, const char *argval, const char *progname)
    {
    const char *shortopts = parent->hdr.shortopts;
    const char *longopts  = parent->hdr.longopts;
    const char *datatype  = parent->hdr.datatype;

    fprintf(fp,"%s: ",progname);
    switch(errorcode)
        {
        case EMINCOUNT:
            fputs("missing option ",fp);
            arg_print_option(fp,shortopts,longopts,datatype,"\n");
            break;

        case EMAXCOUNT:
            fputs("excess option ",fp);
            arg_print_option(fp,shortopts,longopts,argval,"\n");
            break;

        case EBADINT:
            arg_print_option(fp,shortopts,longopts,argval," is not a valid <int>\n");
            break;

        case EZEROVAL:
            arg_print_option(fp,shortopts,longopts,datatype," values cannot be zero\n");
            break;

        case EODDCOUNT:
            arg_print_option(fp,shortopts,longopts,datatype," values must occur in even numbers\n");
            break;

        case EBADSUM:
            arg_print_option(fp,shortopts,longopts,datatype," values must sum to 100\n");
            break;
        }
    }


int main(int argc, char **argv)
    {
    struct arg_int  *val = arg_intn(NULL,NULL,NULL,2,100,"must be an even number of non-zero integer values that sum to 100");
    struct arg_end  *end = arg_end(20);
    void* argtable[] = {val,end};
    const char* progname = "callbacks";
    int nerrors;
    int exitcode=0;
    int i;

    /* verify the argtable[] entries were allocated sucessfully */
    if (arg_nullcheck(argtable) != 0)
        {
        /* NULL entries were detected, some allocations must have failed */
        printf("%s: insufficient memory\n",progname);
        exitcode=1;
        goto exit;
        }

    /* replace the default arg_int parsing and error validation routines with our own custom routines */
    val->hdr.scanfn  = (arg_scanfn*)myscanfn;
    val->hdr.checkfn = (arg_checkfn*)mycheckfn;
    val->hdr.errorfn = (arg_errorfn*)myerrorfn;

    /* special case: no command line options induces brief help */
    if (argc==1)
        {
        printf("Usage: %s ", progname);
        arg_print_syntax(stdout,argtable,"\n");
        arg_print_glossary(stdout,argtable,"where: %s %s\n");
        exitcode=0;
        goto exit;
        }

    /* Parse the command line as defined by argtable[] */
    nerrors = arg_parse(argc,argv,argtable);

    /* If the parser returned any errors then display them and exit */
    if (nerrors > 0)
        {
        /* Display the error details contained in the arg_end struct.*/
        arg_print_errors(stdout,end,progname);
        exitcode=1;
        goto exit;
        }

    /* parsing was succesful, print the values obtained */
    for (i=0; i<val->count; i++)
        printf("val->ival[%d] = %d\n",i, val->ival[i]);

    exit:
    /* deallocate each non-null entry in argtable[] */
    arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0]));

    return exitcode;
    }