/********************************************************************* Example source code for using the argtable2 library to implement: myprog [-lRv] [-k ] [-D MACRO]... [-o ] [--help] [--version] []... This file is part of the argtable2 library. Copyright (C) 1998,1999,2000,2001,2003,2004,2005 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 #include /* 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; icount; 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 \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; icount; 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; }