diff options
| author | root <root@dc13.lemmi> | 2020-07-21 10:00:46 +0200 |
|---|---|---|
| committer | root <root@dc13.lemmi> | 2020-07-21 10:00:46 +0200 |
| commit | 1192c4575ea7afdf38e3fa0df4587a08620af11e (patch) | |
| tree | 6910a62487c282d0840d2e668aa7eb40b7c8a3fd /project/dclib/dclib-option.c | |
| parent | 76de8a89f7c1d1b4522eb66e8f89d248e8c1781f (diff) | |
SZS v2.18a
Diffstat (limited to 'project/dclib/dclib-option.c')
| -rw-r--r-- | project/dclib/dclib-option.c | 1012 |
1 files changed, 1012 insertions, 0 deletions
diff --git a/project/dclib/dclib-option.c b/project/dclib/dclib-option.c new file mode 100644 index 0000000..5a2044b --- /dev/null +++ b/project/dclib/dclib-option.c @@ -0,0 +1,1012 @@ + +/*************************************************************************** + * * + * _____ ____ * + * | __ \ / __ \ _ _ _____ * + * | | \ \ / / \_\ | | | | _ \ * + * | | \ \| | | | | | |_| | * + * | | | || | | | | | ___/ * + * | | / /| | __ | | | | _ \ * + * | |__/ / \ \__/ / | |___| | |_| | * + * |_____/ \____/ |_____|_|_____/ * + * * + * Wiimms source code library * + * * + *************************************************************************** + * * + * Copyright (c) 2012-2020 by Dirk Clemens <wiimm@wiimm.de> * + * * + *************************************************************************** + * * + * 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. * + * * + * See file gpl-2.0.txt or http://www.gnu.org/licenses/gpl-2.0.txt * + * * + ***************************************************************************/ + +#define _GNU_SOURCE 1 + +#include "dclib-option.h" +#include <getopt.h> + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// GenericOpt_t /////////////// +/////////////////////////////////////////////////////////////////////////////// + +void InitializeGenericOpt ( GenericOpt_t *go, char first_char ) +{ + DASSERT(go); + memset(go,0,sizeof(*go)); + InitializeMemPool(&go->str_pool,2000); + + char *dest = go->sopt; + if (first_char) + *dest++ = first_char; + *dest++ = ':'; + *dest = 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +void ResetGenericOpt ( GenericOpt_t *go ) +{ + DASSERT(go); + ResetMemPool(&go->str_pool); + FREE(go->lopt); + InitializeGenericOpt(go,0); +} + +/////////////////////////////////////////////////////////////////////////////// + +void AddGenericOpt +( + GenericOpt_t *go, // data structure + const GenericOptParm_t *gp, // list to add, list end on name==NULL + bool rm_minus // remove '-' on options for alternatives +) +{ + DASSERT(go); + DASSERT(gp); + + char * sopt_ptr = go->sopt + strlen(go->sopt); + char * sopt_end = go->sopt + sizeof(go->sopt) - 3; + + for ( ; gp->name; gp++ ) + { + ccp ptr = gp->name; + for(;;) + { + while ( *ptr == '|' ) + ptr++; + + uint have_minus = 0; + char name_buf[50], *name_ptr = name_buf; + while ( *ptr && *ptr != '|' ) + { + char ch = *ptr++; + if ( ch == '-' ) + have_minus++; + if ( name_ptr < name_buf + sizeof(name_buf) - 1 ) + *name_ptr++ = ch; + } + *name_ptr = 0; + uint len = name_ptr - name_buf; + if (!len) + break; + + //--- short option + + if ( len == 1 ) + { + uchar ch = *name_buf; + if ( ch > ' ' && ch < 0x80 && ch != ':' + && !go->sopt_id[ch] && sopt_ptr < sopt_end ) + { + go->sopt_id[ch] = gp->id; + *sopt_ptr++ = ch; + if ( gp->arg ) + { + *sopt_ptr++ = ':'; + if ( gp->arg > 1 ) + *sopt_ptr++ = ':'; + } + } + } + + + //--- long option + + for(;;) + { + #if 0 // avoid duplicates, needed? + uint i; + for ( i = 0; i < go->lopt_used; i++ ) + if (!strcmp(name_buf,go->lopt[i].name)) + goto skip; + #endif + + if ( go->lopt_used == go->lopt_size ) + { + go->lopt_size += 100; + go->lopt = REALLOC( go->lopt, go->lopt_size * sizeof(*go->lopt) ); + } + + struct option *opt = go->lopt + go->lopt_used++; + opt->name = StrDupMemPool(&go->str_pool,name_buf); + opt->has_arg = gp->arg; + opt->flag = 0; + opt->val = gp->id; + + //skip:; + if ( !have_minus || !rm_minus ) + break; + have_minus = 0; + + char *src = name_buf, *dest = name_buf; + while ( *src ) + { + if ( *src != '-' ) + *dest++ = *src; + src++; + } + *dest = 0; + } + } + } + + *sopt_ptr = 0; + + if ( go->lopt_used == go->lopt_size ) + { + go->lopt_size += 100; + go->lopt = REALLOC( go->lopt, go->lopt_size * sizeof(*go->lopt) ); + } + struct option *opt = go->lopt + go->lopt_used; + memset(opt,0,sizeof(*opt)); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// global options: parameters /////////////// +/////////////////////////////////////////////////////////////////////////////// + +GParamValueType_t GetGParamValueType ( GOPT_t gt ) +{ + if ( gt & GOPT_RESERVED_BEG ) + gt = GetGOPType(gt); + + switch (gt) + { + case GOPT_IDX_INC0: + case GOPT_IDX_INC: + case GOPT_IDX_DEC0: + case GOPT_IDX_DEC: + case GOPT_IDX_SETP: + case GOPT_IDX_SETM: + case GOPT_IDX_SINT: + return GPT_SN; + + case GOPT_IDX_UINT: + case GOPT_IDX_OFF_ON: + case GOPT_IDX_OR: + case GOPT_IDX_SETBIT: + return GPT_UN; + + case GOPT_IDX_SETP64: + case GOPT_IDX_SETM64: + case GOPT_IDX_S64: + return GPT_SN64; + + case GOPT_IDX_U64: + case GOPT_IDX_OR64: + case GOPT_IDX_SETBIT64: + case GOPT_IDX_HEX: + case GOPT_IDX_SIZE: + return GPT_UN64; + + case GOPT_IDX_DOUBLE: + case GOPT_IDX_DURATION: + return GPT_D; + + case GOPT_IDX_STRING: + return GPT_STR; + + case GOPT_IDX_BIT: + return GPT_BIT; + + default: + return GPT_NONE; + } +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +GetGParam_t GetGParamINT ( const GParam_t *par, int *return_val ) +{ + if (par) + { + DASSERT( par->vtype == GetGParamValueType(par->ptype) ); + switch (par->vtype) + { + case GPT_NONE: + case GPT_STR: + case GPT_BIT: + return GGP_NONE; + + case GPT_SN: + if (return_val) + *return_val = par->sn; + return GGP_OK; + + case GPT_UN: + if (return_val) + *return_val = par->un; + return GGP_SIGN; + + case GPT_SN64: + if (return_val) + *return_val = par->sn64; + return GGP_CONVERT; + + case GPT_UN64: + if (return_val) + *return_val = par->un64; + return GGP_CONVERT; + + case GPT_D: + if (return_val) + *return_val = par->d; + return GGP_CONVERT; + } + } + return GGP_NONE; +} + +/////////////////////////////////////////////////////////////////////////////// + +GetGParam_t GetGParamUINT ( const GParam_t *par, uint *return_val ) +{ + if (par) + { + DASSERT( par->vtype == GetGParamValueType(par->ptype) ); + switch (par->vtype) + { + case GPT_NONE: + case GPT_STR: + case GPT_BIT: + return GGP_NONE; + + case GPT_SN: + if (return_val) + *return_val = par->sn; + return GGP_SIGN; + + case GPT_UN: + if (return_val) + *return_val = par->un; + return GGP_OK; + + case GPT_SN64: + if (return_val) + *return_val = par->sn64; + return GGP_CONVERT; + + case GPT_UN64: + if (return_val) + *return_val = par->un64; + return GGP_CONVERT; + + case GPT_D: + if (return_val) + *return_val = par->d; + return GGP_CONVERT; + } + } + return GGP_NONE; +} + +/////////////////////////////////////////////////////////////////////////////// + +GetGParam_t GetGParamS64 ( const GParam_t *par, s64 *return_val ) +{ + if (par) + { + DASSERT( par->vtype == GetGParamValueType(par->ptype) ); + switch (par->vtype) + { + case GPT_NONE: + case GPT_STR: + case GPT_BIT: + return GGP_NONE; + + case GPT_SN: + if (return_val) + *return_val = par->sn; + return GGP_OK; + + case GPT_UN: + if (return_val) + *return_val = par->un; + return GGP_SIGN; + + case GPT_SN64: + if (return_val) + *return_val = par->sn64; + return GGP_OK; + + case GPT_UN64: + if (return_val) + *return_val = par->un64; + return GGP_SIGN; + + case GPT_D: + if (return_val) + *return_val = par->d; + return GGP_CONVERT; + } + } + return GGP_NONE; +} + +/////////////////////////////////////////////////////////////////////////////// + +GetGParam_t GetGParamU64 ( const GParam_t *par, u64 *return_val ) +{ + if (par) + { + DASSERT( par->vtype == GetGParamValueType(par->ptype) ); + switch (par->vtype) + { + case GPT_NONE: + case GPT_STR: + case GPT_BIT: + return GGP_NONE; + + case GPT_SN: + if (return_val) + *return_val = par->sn; + return GGP_SIGN; + + case GPT_UN: + if (return_val) + *return_val = par->un; + return GGP_OK; + + case GPT_SN64: + if (return_val) + *return_val = par->sn64; + return GGP_SIGN; + + case GPT_UN64: + if (return_val) + *return_val = par->un64; + return GGP_OK; + + case GPT_D: + if (return_val) + *return_val = par->d; + return GGP_CONVERT; + } + } + return GGP_NONE; +} + +/////////////////////////////////////////////////////////////////////////////// + +GetGParam_t GetGParamDBL ( const GParam_t *par, double *return_val ) +{ + if (par) + { + DASSERT( par->vtype == GetGParamValueType(par->ptype) ); + switch (par->vtype) + { + case GPT_NONE: + case GPT_STR: + case GPT_BIT: + return GGP_NONE; + + case GPT_SN: + if (return_val) + *return_val = par->sn; + return GGP_CONVERT; + + case GPT_UN: + if (return_val) + *return_val = par->un; + return GGP_CONVERT; + + case GPT_SN64: + if (return_val) + *return_val = par->sn64; + return GGP_CONVERT; + + case GPT_UN64: + if (return_val) + *return_val = par->un64; + return GGP_CONVERT; + + case GPT_D: + if (return_val) + *return_val = par->d; + return GGP_OK; + } + } + return GGP_NONE; +} + +/////////////////////////////////////////////////////////////////////////////// + +GetGParam_t GetGParamSTR ( const GParam_t *par, ccp *return_val ) +{ + DASSERT( !par || par->vtype == GetGParamValueType(par->ptype) ); + if ( par && par->vtype == GPT_STR ) + { + if (return_val) + *return_val = par->str; + return GGP_OK; + } + return GGP_NONE; +} + +/////////////////////////////////////////////////////////////////////////////// + +GetGParam_t GetGParamBIT ( const GParam_t *par, u32 *return_val, u32 *return_mask ) +{ + DASSERT( !par || par->vtype == GetGParamValueType(par->ptype) ); + if ( par && par->vtype == GPT_BIT ) + { + if (return_val) + *return_val = par->bit.val; + if (return_mask) + *return_mask = par->bit.mask; + return GGP_OK; + } + return GGP_NONE; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +ccp PrintGParam ( const GParam_t *par ) +{ + DASSERT(par); + DASSERT( par->vtype == GetGParamValueType(par->ptype) ); + char buf[100]; + ccp extra = ""; + + switch (par->ptype) + { + case GOPT_IDX_NULL: + snprintf(buf,sizeof(buf),"[-]"); + break; + + case GOPT_IDX_INC0: + case GOPT_IDX_DEC0: + case GOPT_IDX_DEC: + extra = "?"; + case GOPT_IDX_INC: + snprintf(buf,sizeof(buf),"[%sINC] %d",extra,par->sn); + break; + + case GOPT_IDX_SETP: + case GOPT_IDX_SETM: + extra = "?"; + case GOPT_IDX_SINT: + snprintf(buf,sizeof(buf),"[%sSINT] %d",extra,par->sn); + break; + + case GOPT_IDX_OR: + case GOPT_IDX_SETBIT: + case GOPT_IDX_OFF_ON: + extra = "?"; + case GOPT_IDX_UINT: + snprintf(buf,sizeof(buf),"[%sUINT] %u",extra,par->un); + break; + + case GOPT_IDX_BIT: + snprintf(buf,sizeof(buf),"[BIT] set=%x, clr=%x", + par->bit.val, par->bit.mask & ~par->bit.val ); + break; + + case GOPT_IDX_SETP64: + case GOPT_IDX_SETM64: + extra = "?"; + case GOPT_IDX_S64: + snprintf(buf,sizeof(buf),"[%sS64] %lld",extra,par->sn64); + break; + + case GOPT_IDX_OR64: + case GOPT_IDX_SETBIT64: + extra = "?"; + case GOPT_IDX_U64: + snprintf(buf,sizeof(buf),"[%sU64] %llu",extra,par->un64); + break; + + case GOPT_IDX_HEX: + snprintf(buf,sizeof(buf),"[HEX] 0x%llx",par->un64); + break; + + case GOPT_IDX_SIZE: + snprintf(buf,sizeof(buf),"[SIZE] %llu = %s", + par->un64, PrintSize1024(0,0,par->un64,false) ); + break; + + case GOPT_IDX_DOUBLE: + snprintf(buf,sizeof(buf),"[DBL] %12g",par->d); + break; + + case GOPT_IDX_DURATION: + snprintf(buf,sizeof(buf),"[DUR] %12g = %s", + par->d, PrintTimerUSec6(0,0,double2usec(par->d),false) ); + break; + + case GOPT_IDX_STRING: + snprintf(buf,sizeof(buf),"[STR] \"%s\"",par->str); + break; + + + default: + snprintf(buf,sizeof(buf),"[?%u]",par->ptype); + break; + } + + const uint size = strlen(buf) + 1; + char *res = GetCircBuf(size); + memcpy(res,buf,size); + return res; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// ScanGOptionsHelper() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +const GenericOptParm_t StandardGOptions[] = +{ + { GOPT_O_TEST_OPT, 0, "_opt" }, + { GOPT_O_HELP, 0, "h|help" }, + { GOPT_O_CLEAR, 0, "c|clear" }, + { GOPT_O_PAGER, 0, "p|pager" }, + { GOPT_O_QUIT, 0, "Q|quit" }, + { GOPT_O_QUIET, 0, "q|quiet" }, + { GOPT_O_VERBOSE, 0, "v|verbose" }, + {0,0,0} +}; + +/////////////////////////////////////////////////////////////////////////////// + +static int ScanGOffOn ( GenericOpt_t *go, int opt_stat, bool use_max, ccp optarg ) +{ + ccp object = "'off/on' value"; + + char buf[100]; + if (go) + { + uint i; + for ( i = 0; i < go->lopt_used; i++ ) + { + struct option *lp = go->lopt + i; + if ( lp->val == opt_stat && lp->has_arg && lp->name ) + { + snprintf(buf,sizeof(buf),"'off/on' value of --%s",lp->name); + object = buf; + break; + } + } + } + + const uint max_num = use_max ? ( opt_stat & GOPT_M_VALUE ) >> GOPT_S_VALUE : 0; + return ScanKeywordOffOn(optarg,max_num,object); +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanGOptionsHelper +( + GOptions_t *gopt, // valid pointer + GenericOpt_t *go, // NULL or list with options + // => ResetGenericOpt() is called at finish + int argc, // argument counter + char **argv, // list of arguments + int max_param, // >=0: max allowed parameters + ScanGOpt_t scan_opt, // scan options + + //--- call back functions + ScanOptionFunc OnAddOptions, // not NULL: called once to add options + ScanOptionFunc OnOption, // not NULL: called for each option + ScanOptionFunc OnArgument, // not NULL: called for each argument + void *any_ptr // NULL or user specific pointer for call back +) +{ + DASSERT(gopt); + DASSERT(argc>1); + DASSERT(argv); + + //--- setup options + + GenericOpt_t go0; + if (!go) + { + go = &go0; + InitializeGenericOpt( go, scan_opt & SGO_KNOWN ? '+' : 0 ); + } + + if (OnAddOptions) + OnAddOptions(go,gopt,any_ptr,scan_opt,0); + AddGenericOpt(go,StandardGOptions,true); + + if ( argc > 1 ) + { + // skip command + argc--; + argv++; + } + + optind = 0; // '0' is correct for GNU to reset scanning + #if !defined(TEST) && !defined(DEBUG) + opterr = 0; // suppress error messages to stderr + #endif + + + //--- check options + + InitializeGOptions(gopt); + + int err = 0, test_opt = 0; + enumError stat = ERR_OK; + while ( stat == ERR_OK ) + { + int opt_stat = getopt_long(argc,argv,go->sopt,go->lopt,0); + if ( opt_stat == -1 ) + break; + + // translate short option names + if ( (uint)opt_stat < sizeof(go->sopt_id)/sizeof(*go->sopt_id) && go->sopt_id[opt_stat] ) + opt_stat = go->sopt_id[opt_stat]; + + if ( opt_stat >= GOPT_RESERVED_BEG && opt_stat < GOPT_RESERVED_END ) + { + const uint pidx = opt_stat & GOPT_M_INDEX; + if ( pidx >= GOPT_N_PARAM ) + { + printf("%s!!! %s: Parameter index %u must be <%u: %s%s\n", + colout->warn, *argv, + pidx, GOPT_N_PARAM, argv[optind-1], + colout->reset ); + stat = ERR_SYNTAX; + break; + } + GParam_t *par = gopt->param + pidx; + + const uint ptype = GetGOPType(opt_stat); + switch(ptype) + { + //--- increment & decrement: indicator 'ptype' is always GOPT_IDX_INC + + case GOPT_IDX_INC0: + if ( par->ptype != GOPT_IDX_INC ) + { + par->ptype = GOPT_IDX_INC; + par->sn = 1; + } + else + par->sn = par->sn >= 0 ? par->sn+1 : 0; + break; + + case GOPT_IDX_INC: + if ( par->ptype != GOPT_IDX_INC ) + { + par->ptype = GOPT_IDX_INC; + par->sn = 1; + } + else + par->sn = par->sn > 0 ? par->sn+1 : 1; + break; + + case GOPT_IDX_DEC0: + if ( par->ptype != GOPT_IDX_INC ) + { + par->ptype = GOPT_IDX_INC; + par->sn = -1; + } + else + par->sn = par->sn <= 0 ? par->sn-1 : 0; + break; + + case GOPT_IDX_DEC: + if ( par->ptype != GOPT_IDX_INC ) + { + par->ptype = GOPT_IDX_INC; + par->sn = -1; + } + else + par->sn = par->sn < 0 ? par->sn-1 : -1; + break; + + + //--- set values: indicator 'ptype' is GOPT_IDX_SINT or GOPT_IDX_S64 + + case GOPT_IDX_SETP: + par->ptype = GOPT_IDX_SINT; + par->un = ( opt_stat & GOPT_M_VALUE ) >> GOPT_S_VALUE; + break; + + case GOPT_IDX_SETM: + par->ptype = GOPT_IDX_SINT; + par->sn = - ( ( opt_stat & GOPT_M_VALUE ) >> GOPT_S_VALUE ); + break; + + case GOPT_IDX_SETP64: + par->ptype = GOPT_IDX_S64; + par->un64 = ( opt_stat & GOPT_M_VALUE ) >> GOPT_S_VALUE; + break; + + case GOPT_IDX_SETM64: + par->ptype = GOPT_IDX_S64; + par->sn64 = - ( ( opt_stat & GOPT_M_VALUE ) >> GOPT_S_VALUE ); + break; + + + //--- set bits: indicator 'ptype' is GOPT_IDX_UINT or GOPT_IDX_U64 + + case GOPT_IDX_OR: + if ( par->ptype != GOPT_IDX_UINT ) + { + par->ptype = GOPT_IDX_UINT; + par->un = 0; + } + par->un |= ( opt_stat & GOPT_M_VALUE ) >> GOPT_S_VALUE; + break; + + case GOPT_IDX_SETBIT: + { + if ( par->ptype != GOPT_IDX_UINT ) + { + par->ptype = GOPT_IDX_UINT; + par->un = 0; + } + const uint bitnum = ( opt_stat & GOPT_M_VALUE ) >> GOPT_S_VALUE; + if ( bitnum < 8*sizeof(par->un) ) + par->un |= 1u << bitnum; + } + break; + + case GOPT_IDX_OR64: + if ( par->ptype != GOPT_IDX_U64 ) + { + par->ptype = GOPT_IDX_U64; + par->un64 = 0; + } + par->un64 |= ( opt_stat & GOPT_M_VALUE ) >> GOPT_S_VALUE; + break; + + case GOPT_IDX_SETBIT64: + if ( par->ptype != GOPT_IDX_U64 ) + { + par->ptype = GOPT_IDX_U64; + par->un64 = 0; + } + { + const uint bitnum = ( opt_stat & GOPT_M_VALUE ) >> GOPT_S_VALUE; + if ( bitnum < 64 ) + par->un64 |= 1llu << bitnum; + } + break; + + case GOPT_IDX_BIT: + { + if ( par->ptype != GOPT_IDX_BIT ) + { + par->ptype = GOPT_IDX_BIT; + par->bit.val = par->bit.mask = 0; + } + + const int stat = ScanGOffOn(go,opt_stat,false,optarg); + if ( stat >= 0 ) + { + const uint bitnum = ( opt_stat & GOPT_M_VALUE ) >> GOPT_S_VALUE; + if ( bitnum < 32 ) + { + const u32 m = 1u << bitnum; + par->bit.mask |= m; + if ( stat > 0 ) + par->un |= m; + else + par->un &= ~m; + } + } + } + break; + + + //--- scan parameters + + case GOPT_IDX_SINT: + par->ptype = GOPT_IDX_SINT; + par->sn = str2l(optarg,0,10); + break; + + case GOPT_IDX_UINT: + par->ptype = GOPT_IDX_UINT; + par->un = str2ul(optarg,0,10); + break; + + case GOPT_IDX_OFF_ON: + { + const int stat = ScanGOffOn(go,opt_stat,true,optarg); + par->un = stat >= 0 ? stat : 0; + par->ptype = GOPT_IDX_UINT; + } + break; + + case GOPT_IDX_S64: + par->ptype = GOPT_IDX_S64; + par->sn64 = str2ll(optarg,0,10); + break; + + case GOPT_IDX_U64: + par->ptype = GOPT_IDX_U64; + par->un64 = str2ull(optarg,0,10); + break; + + case GOPT_IDX_HEX: + par->ptype = GOPT_IDX_HEX; + par->un64 = str2ull(optarg,0,16); + break; + + case GOPT_IDX_SIZE: + par->ptype = GOPT_IDX_SIZE; + ScanSizeU64(&par->un64,optarg,1,1,0); break; + break; + + case GOPT_IDX_DOUBLE: + par->ptype = GOPT_IDX_DOUBLE; + par->d = strtod(optarg,0); + break; + + case GOPT_IDX_DURATION: + par->ptype = GOPT_IDX_DURATION; + ScanDuration(&par->d,optarg,1,SDUMD_M_ALL); break; + break; + + case GOPT_IDX_STRING: + par->ptype = GOPT_IDX_STRING; + par->str = optarg; + break; + + default: + printf("!!! %s: Undefinef GOPT_* type 0x%02x [0x%02x]: %s\n", + *argv, GetGOPType(opt_stat), opt_stat, argv[optind-1] ); + stat = ERR_ERROR; + } + par->vtype = GetGParamValueType(par->ptype); + continue; + } + + switch (opt_stat) + { + case '?': + if ( optopt && (uint)optopt < 0x7f ) + printf("%s!!! %s: Invalid option: %s-%c [0x%02x]%s\n", + colout->warn, *argv, + colout->value, optopt, optopt, + colout->reset ); + else + printf("%s!!! %s: Invalid option: %s%s%s\n", + colout->warn, *argv, + colout->value, argv[optind-1], + colout->reset ); + stat = ERR_SYNTAX; + break; + + case ':': + printf("%s!!! %s: Missing parameter for %s%s%s\n", + colout->warn, *argv, + colout->value, argv[optind-1], + colout->reset ); + stat = ERR_SYNTAX; + break; + + + //--- standard options + + case GOPT_O_QUIET: + gopt->verbose = gopt->verbose > -1 ? -1 : gopt->verbose - 1; + break; + case GOPT_O_VERBOSE: + gopt->verbose = gopt->verbose < 0 ? 0 : gopt->verbose + 1; + break; + + case GOPT_O_HELP: gopt->help++; scan_opt |= SGO_PAGER; break; + case GOPT_O_CLEAR: gopt->clear++; break; + case GOPT_O_PAGER: gopt->pager++; break; + case GOPT_O_QUIT: gopt->quit++; break; + case GOPT_O_TEST_OPT: test_opt++; break; + + + //--- misc + + default: + if (OnOption) + { + const int ostat = OnOption(go,gopt,any_ptr,opt_stat,optarg); + if ( ostat <= 0 ) + { + if (!ostat) + printf("!!! %s: Internal error while scanning options [0x%02x]!\n", + *argv, opt_stat ); + stat = ERR_ERROR; + } + } + break; + } + } + + if (test_opt) + { + printf("\nOPTIONS [N=%u/%u]: %s\n",go->lopt_used,go->lopt_size,go->sopt); + const struct option *opt; + for ( opt = go->lopt; opt->name; opt++ ) + printf(" %04x %u %s\n", opt->val, opt->has_arg, opt->name ); + } + + char **dest = argv + optind; + gopt->argv = dest; + + uint i; + for ( i = optind; i < argc; i++ ) + { + char *arg = argv[i]; + if ( !OnArgument || !OnArgument(go,gopt,any_ptr,dest-gopt->argv,arg) ) + *dest++ = arg; + } + gopt->argc = dest - gopt->argv; + + if (err) + { + printf("%s!!! %s: Syntax error!%s\n",colout->warn,*argv,colout->reset); + stat = ERR_SYNTAX; + goto abort; + } + + if ( max_param >= 0 && gopt->argc > max_param ) + { + if (!max_param) + printf( + "%s!!! %s: No parameters allowed, but %u found!%s\n", + colout->warn, *argv, gopt->argc, colout->reset ); + else + printf( + "%s!!! %s: Maximal %u parameter%s allowed, but %u found!%s\n", + colout->warn, *argv, + max_param, max_param == 1 ? "" : "s", + gopt->argc, colout->reset ); + stat = ERR_SYNTAX; + goto abort; + } + + if ( scan_opt & SGO_PAGER && !gopt->pager ) + gopt->pager++; + + abort: + ResetGenericOpt(go); + if (stat) + InitializeGOptions(gopt); + return stat; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// END /////////////// +/////////////////////////////////////////////////////////////////////////////// + |
