/* LIBDGL -- a Directed Graph Library implementation * Copyright (C) 2002 Roberto Micarelli * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* best view tabstop=4 */ #include #include #include #include "opt.h" static int _ParseLongOption( GnoOption_s * pOpt, char * pszArg ) { char * pszLong; char * pszPar; char * pszMatch = NULL; int nret; if ( pOpt->pszLong == NULL ) { return 0; } pszLong = strdup( pOpt->pszLong ); if ( (pszPar = strchr( pszArg, '=' )) != NULL ) { *pszPar = 0; } pszMatch = strdup( pszArg ); if ( pszPar ) *pszPar++ = '='; if ( strcmp( pszLong , pszMatch+2 ) == 0 ) { /* * mandatory parameter not found * */ if ( pszPar == NULL ) { nret = -1; goto free_and_exit; } if ( pOpt->ppszValue ) { if ( pOpt->ppszValue[ 0 ] ) free( pOpt->ppszValue[ 0 ] ); pOpt->ppszValue[ 0 ] = strdup( pszPar ); } nret = 1; goto free_and_exit; } nret = 0; free_and_exit: free( pszLong ); free( pszMatch ); return nret; } static int _ParseLongSwitch( GnoOption_s * pOpt, char * pszArg ) { if ( pOpt->pszLong == NULL ) { return 0; } if ( strcmp( pOpt->pszLong , pszArg+2 ) == 0 ) { if ( pOpt->pfValue ) *pOpt->pfValue = True; return 1; } return 0; } static int _ParseShortOption( GnoOption_s * pOpt, char * pszArg, char * pszPar ) { char * pszShort; int ich; if ( pOpt->pszShort == NULL ) return 0; pszShort = strdup( pOpt->pszShort ); for ( ich = 1; pszArg[ ich ]; ich ++ ) { if ( pszShort[ 0 ] == pszArg[ ich ] ) { if ( pszPar == NULL || pszPar[ 0 ] == 0 ) { free( pszShort ); return -1; } if ( pszPar[ 0 ] == '-' && pszPar[ 1 ] != 0 ) { free( pszShort ); return -1; } if ( pOpt->ppszValue ) { if ( pOpt->ppszValue[ 0 ] ) free( pOpt->ppszValue[ 0 ] ); pOpt->ppszValue[ 0 ] = strdup( pszPar ); } free( pszShort ); return 2; } } free( pszShort ); return 0; } static int _ParseShortSwitch( GnoOption_s * pOpt, char * pszArg ) { int ich; if ( pOpt->pszShort == NULL ) return 0; for ( ich = 1; pszArg[ ich ]; ich ++ ) { if ( pOpt->pszShort[ 0 ] == pszArg[ ich ] ) { if ( pOpt->pfValue ) *pOpt->pfValue = True; return 1; } } return 0; } /*********************************************************************** * CALLBACKS **********************************************************************/ /*********************************************************************** * PUBLIC FUNCTIONS **********************************************************************/ /*@*-------------------------------------------------------------------- * @func: GnoParse() * @descr: Parse argc, argv against the option array and setup option * values in the array. * * @args: I: argc = count of argv entries * I: argv -> array of pointer to string * I: pOpt -> option array pointer * * @ret: The number of 'orphan' entries found in the argv. * @see: GnoOption_s * * @notes: The argv array will be modified: each argv entry that contains a * recognized option ( '-.' or '--...' ) or each entry recognized as * a parametric option parameter, will be set to NULL. * Thus, at the function return the argv entries not set to NULL are * those of orphan entries (those not related to any option). * The user can then scan argv to find out orphans. * However the number of argv entries will not be altered. * *--------------------------------------------------------------------*/ int GnoParse( int argc , char ** argv , GnoOption_s * pOpt ) { char * pszArgv; char * pszArgvNxt; int iArg, iOpt, cOrphan = 0; int nret, cret; Boolean fParseError = False; /* * this first loop setup default values * * strdup is used for non-switch options * * to make life easier when freeing the field * */ for ( iOpt = 0 ; pOpt[ iOpt ].pszShort || pOpt[ iOpt ].pszLong ; iOpt ++ ) { if ( pOpt[ iOpt ].nFlg & GNO_FLG_SWITCH ) { if ( pOpt[ iOpt ].pfValue ) { pOpt[ iOpt ].pfValue[ 0 ] = pOpt[ iOpt ].fDef; } } else { if ( pOpt[ iOpt ].pszDef ) { if ( pOpt[ iOpt ].ppszValue ) { pOpt[ iOpt ].ppszValue[ 0 ] = strdup( pOpt[ iOpt ].pszDef ); } } else { if ( pOpt[ iOpt ].ppszValue ) { pOpt[ iOpt ].ppszValue[ 0 ] = NULL; } } } } /* * for each arg in argv lookup the matching options * */ for ( iArg = 0, pszArgv = NULL ; iArg < argc && (pszArgv = strdup( argv[ iArg ] )) != NULL ; iArg ++, free( pszArgv ), pszArgv = NULL ) { if ( pszArgv[ 0 ] == '-' && pszArgv[ 1 ] == '-' && pszArgv[ 2 ] ) /* long style */ { for ( iOpt = 0 ; (pOpt[ iOpt ].pszShort || pOpt[ iOpt ].pszLong) && argv[ iArg ] ; iOpt ++ ) { if ( pOpt[ iOpt ].pszLong ) { if ( pOpt[ iOpt ].nFlg & GNO_FLG_SWITCH ) { nret = _ParseLongSwitch( & pOpt[ iOpt ], pszArgv ); } else { nret = _ParseLongOption( & pOpt[ iOpt ], pszArgv ); } if ( nret < 0 ) { fprintf( stderr, "parse option: syntax error at <%s>\n", pszArgv ); fParseError = True; } if ( nret == 1 ) { argv[ iArg ] = NULL; } } } if ( argv[ iArg ] ) { fprintf( stderr, "parse option: <%s> is out of scope\n", pszArgv ); fParseError = True; } } else if ( argv[iArg][ 0 ] == '-' && argv[iArg][ 1 ] ) /* short style */ { if ( iArg + 1 < argc ) { pszArgvNxt = strdup( argv[ iArg + 1 ] ); } else { pszArgvNxt = NULL; } for ( cret = iOpt = 0 ; pOpt[ iOpt ].pszShort || pOpt[ iOpt ].pszLong ; iOpt ++ ) { if ( pOpt[ iOpt ].pszShort ) { if ( pOpt[ iOpt ].nFlg & GNO_FLG_SWITCH ) { nret = _ParseShortSwitch( & pOpt[ iOpt ], pszArgv ); } else { nret = _ParseShortOption( & pOpt[ iOpt ], pszArgv , pszArgvNxt ); } if ( nret < 0 ) { fprintf( stderr, "parse option: syntax error at <%s>\n", pszArgv ); fParseError = True; } else { cret = (nret>cret) ? nret : cret; } } } if ( pszArgvNxt ) { free( pszArgvNxt ); } if ( cret == 1 ) { argv[ iArg ] = NULL; } else if ( cret == 2 ) { argv[ iArg++ ] = NULL; argv[ iArg ] = NULL; } } else { cOrphan ++; } } if ( pszArgv ) free( pszArgv ); return ( fParseError == True ) ? -1 : cOrphan; } /*@*-------------------------------------------------------------------- * @func: GnoFree() * @descr: Free resource previously created with a call to GnoParse() * * @args: I: pOpt -> option array pointer * * @see: GnoOption_s, GnoParse() * *--------------------------------------------------------------------*/ void GnoFree( GnoOption_s * pOpt ) { int iOpt; for ( iOpt = 0 ; pOpt[ iOpt ].pszShort || pOpt[ iOpt ].pszLong ; iOpt ++ ) { if ( pOpt[ iOpt ].ppszValue ) { if ( pOpt[ iOpt ].ppszValue[ 0 ] ) { free( pOpt[ iOpt ].ppszValue[ 0 ] ); pOpt[ iOpt ].ppszValue[ 0 ] = NULL; } } } } /*@*-------------------------------------------------------------------- * @func: GnoHelp() * @descr: Print a brief option's help on the standard error * * @args: I: pszHead -> help header string * * @args: I: pOpt -> option array pointer * * @see: GnoOption_s * *--------------------------------------------------------------------*/ void GnoHelp( char *pszHead, GnoOption_s * pOpt ) { int iOpt; fprintf( stderr, "%s\n", (pszHead) ? pszHead : "options" ); for ( iOpt = 0 ; pOpt[ iOpt ].pszShort || pOpt[ iOpt ].pszLong ; iOpt ++ ) { if ( pOpt[ iOpt ].nFlg & GNO_FLG_SWITCH ) { if ( pOpt[ iOpt ].pszShort ) { fprintf( stderr, "-%s ", pOpt[ iOpt ].pszShort ); } if ( pOpt[ iOpt ].pszLong ) { fprintf( stderr, "--%s", pOpt[ iOpt ].pszLong ); } fprintf( stderr, "\n\t%s\n", ( pOpt[ iOpt ].pszDescr ) ? pOpt[ iOpt ].pszDescr : "No description available." ); } else { if ( pOpt[ iOpt ].pszShort ) { fprintf( stderr, "-%s ", pOpt[ iOpt ].pszShort ); fprintf( stderr, " " ); } if ( pOpt[ iOpt ].pszLong ) { fprintf( stderr, "--%s", pOpt[ iOpt ].pszLong ); fprintf( stderr, "=" ); } fprintf( stderr, "\n\t%s\n", ( pOpt[ iOpt ].pszDescr ) ? pOpt[ iOpt ].pszDescr : "No description available." ); } } } /******************************* END OF FILE **************************/