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;
}
|