%% options copyright owner = Dirk Krause copyright year = 2011-2014 license = bsd %% header #include "dk3conf.h" #include "dk3types.h" #ifdef __cplusplus extern "C" { #endif /** Create new options set. @param options Array of option descriptions. @param szoptions Number of entries in options. @param foc Character introducing a further option. @param focl String introducing a further option. @param argc Number of command line arguments to process. @param argv Command line arguments array pointer. @param app Application structure for diagnostics, may be NULL. @return Pointer to option set on success, NULL on error. */ dk3_option_set_t * dk3opt_open_app( dk3_option_t const *options, size_t szoptions, dkChar foc, dkChar const *focl, int argc, dkChar const * const *argv, dk3_app_t *app ); /** Create new options set. @param options Array of option descriptions. @param szoptions Number of entries in options. @param foc Character to indicate a further option. @param focl Long option for further options. @param app Application structure. @return Pointer to option set on success, NULL on error. */ dk3_option_set_t * dk3opt_open_from_app( dk3_option_t const *options, size_t szoptions, dkChar foc, dkChar const *focl, dk3_app_t *app ); /** Check whether or not an option is set. @param optset Options set. @param shortopt Option character. @return 1 for option was set, 0 for option was not set. */ int dk3opt_is_set( dk3_option_set_t const *optset, dkChar shortopt ); /** Check whether or not a long option is set. @param optset Options set. @param longopt Long option name string. @return 1 for option was set, 0 for option was not set. */ int dk3opt_is_set_long( dk3_option_set_t const *optset, dkChar const *longopt ); /** Get option argument. @param optset Options set. @param shortopt Option character. @return Option argument (if any) or NULL. */ dkChar const * dk3opt_get_short_arg( dk3_option_set_t const *optset, dkChar shortopt ); /** Get long option argument. @param optset Options set. @param longopt Option name. @return Option argument (if any) or NULL. */ dkChar const * dk3opt_get_long_arg( dk3_option_set_t const *optset, dkChar const *longopt ); /** Get number of command line arguments without options. @param optset Options set. @return Number of command line arguments. */ int dk3opt_get_num_args( dk3_option_set_t const *optset ); /** Get one command line argument. @param optset Options set. @param num Index of argument. @return The argument on success, NULL on error. */ dkChar const * dk3opt_get_arg( dk3_option_set_t const *optset, int num ); /** Get number of further options. @param os Options set. @return Number of further options. */ int dk3opt_get_num_fo( dk3_option_set_t const *os ); /** Get one further option. @param os Options set. @param num Index of option. @return The further option on success, NULL on error. */ dkChar const * dk3opt_get_fo( dk3_option_set_t const *os, int num ); /** Destroy option set. @param os Option set to destroy. */ void dk3opt_close( dk3_option_set_t *os ); /** Get error code. @param os Option set to check for errors. @return Error code value. */ int dk3opt_get_error_code(dk3_option_set_t const *os); /** Reset error code. @param os Option set to clean up. */ void dk3opt_reset_error_code(dk3_option_set_t *os); #ifdef __cplusplus } #endif %% module #include "dk3all.h" $!trace-include /** Find index of character in options set. @param os Options set. @param c Character to search for. @param pind Pointer to destination variable. @return 1 on success, 0 on error. */ static int dk3opt_find_index_short( dk3_option_set_t const *os, dkChar c, size_t *pind ) { int back = 0; size_t i; $? "+ dk3opt_find_index_short %c", c if((os) && (pind)) { if((os->options) && (os->szoptions)) { for(i = 0; ((i < os->szoptions) && (back == 0)); i++) { if(((os->options)[i]).so == c) { *pind = i; back = 1; $? ". index=%u", (unsigned)i } } } } $? "- dk3opt_find_index_short %d", back return back; } /** Find index of long option in options set. @param os Options set. @param t Long option name to search for. @param pind Pointer to destination variable. @return 1 on success, 0 on error. */ static int dk3opt_find_index_long( dk3_option_set_t const *os, dkChar const *t, size_t *pind ) { int back = 0; size_t i; $? "+ dk3opt_find_index_long \"%s\"", TR_STR(t) if((os) && (t) && (pind)) { if((os->options) && (os->szoptions)) { for(i = 0; ((i < os->szoptions) && (back == 0)); i++) { if(((os->options)[i]).lo) { if(dk3str_cmp(((os->options)[i]).lo, t) == 0) { *pind = i; back = 1; $? ". index=%u", (unsigned)i } } } } } $? "- dk3opt_find_index_long %d", back return back; } /** Apply the command line options to the options set. @param os Options set. @param argc Number of command line arguments. @param argv Command line arguments array. */ static void dk3opt_apply_options( dk3_option_set_t *os, int argc, dkChar const * const *argv ) { dkChar const * const *lfdptr; dkChar const *ptr; dkChar const *optr; dkChar const *cptr; int i; size_t j; int done; dkChar bu[2 * DK3_MAX_PATH]; dkChar *p1; $? "+ dk3opt_apply_options" lfdptr = argv; i = 0; while(i < argc) { optr = ptr = *lfdptr; if(*ptr == dkT('-')) { $? ". option" ptr++; if(*ptr == dkT('-')) { $? ". long option" ptr++; if(dk3str_len(ptr) < DK3_SIZEOF(bu,dkChar)) { dk3str_cpy_not_overlapped(bu, ptr); p1 = dk3str_chr(bu, dkT('=')); if(p1) { *p1 = dkT('\0'); } done = 0; if(os->focl) { if(dk3str_cmp(os->focl, bu) == 0) { done = 1; cptr = dk3str_chr(ptr, dkT('=')); if(cptr) { cptr++; if(!(*cptr)) { cptr = NULL; } } if(!(cptr)) { lfdptr++; i++; if(i < argc) { cptr = *lfdptr; } } if(cptr) { (os->fo)[os->fou] = cptr; os->fou += 1; } else { /* ERROR: Option needs argument! */ os->ec = 1; if(os->app) { dk3app_log_i3(os->app, DK3_LL_ERROR, 133, 134, optr); } } } } if(!done) { if(dk3opt_find_index_long(os, bu, &j)) { (os->found)[j] += 1; if((os->found)[j] == 0) { /* Overflow */ (os->found)[j] = 0x7FFF; } if(((os->options)[j]).na) { cptr = dk3str_chr(ptr, dkT('=')); if(cptr) { cptr++; if(!(*cptr)) { cptr = NULL; } } if(!(cptr)) { lfdptr++; i++; if(i < argc) { cptr = *lfdptr; } } if(cptr) { if((os->optargs)[j]) { /* Warning: Redefinition */ /* os->ec = 1; */ if(os->app) { dk3app_log_i5( os->app, DK3_LL_WARNING, 206, 207, 208, (os->optargs)[j], cptr ); } } (os->optargs)[j] = cptr; } else { /* ERROR: Option needs argument! */ os->ec = 1; if(os->app) { dk3app_log_i3(os->app, DK3_LL_ERROR, 133, 134, optr); } } } } else { /* ERROR: Illegal option! */ os->ec = 1; if(os->app) { dk3app_log_i3(os->app, DK3_LL_ERROR, 139, 140, optr); } } } } else { /* ERROR: Option too long! */ os->ec = 1; if(os->app) { dk3app_log_i3(os->app, DK3_LL_ERROR, 135, 136, optr); } } } else { $? ". short option" if(*ptr == os->foc) { $? ". a further option" ptr++; if(!(*ptr)) { ptr = NULL; lfdptr++; i++; if(i < argc) { ptr = *lfdptr; } } if(ptr) { (os->fo)[os->fou] = ptr; os->fou += 1; } else { /* ERROR: Option needs an argument! */ os->ec = 1; if(os->app) { dk3app_log_i3(os->app, DK3_LL_ERROR, 133, 134, optr); } } } else { $? ". normal option" if(dk3opt_find_index_short(os, *ptr, &j)) { (os->found)[j] += 1; if((os->found)[j] == 0) { /* Overflow */ (os->found)[j] = 0x7FFF; } if(((os->options)[j]).na) { ptr++; if(!(*ptr)) { ptr = NULL; lfdptr++; i++; if(i < argc) { ptr = *lfdptr; } } if(ptr) { if((os->optargs)[j]) { /* Warning: Redefinition of option. */ /* os->ec = 1; */ if(os->app) { dk3app_log_i5( os->app, DK3_LL_WARNING, 206, 207, 208, (os->optargs)[j], ptr ); } } (os->optargs)[j] = ptr; } else { /* ERROR: Option needs an argument! */ os->ec = 1; if(os->app) { dk3app_log_i3(os->app, DK3_LL_ERROR, 133, 134, optr); } } } else { ptr++; if(*ptr) { if((os->optargs)[j]) { if(os->app) { dk3app_log_i5( os->app, DK3_LL_WARNING, 206, 207, 208, (os->optargs)[j], ptr ); } } (os->optargs)[j] = ptr; } } } else { /* ERROR: Illegal option! */ os->ec = 1; if(os->app) { dk3app_log_i3(os->app, DK3_LL_ERROR, 139, 140, optr); } } } } } else { $? ". file name" (os->args)[os->argsused] = ptr; os->argsused += 1; } lfdptr++; i++; } $? "- dk3opt_apply_options" } dk3_option_set_t * dk3opt_open_app( dk3_option_t const *options, size_t szoptions, dkChar foc, dkChar const *focl, int argc, dkChar const * const *argv, dk3_app_t *app ) { dk3_option_set_t *back = NULL; int ok = 0; int i = 0; size_t j = 0; $? "+ dk3opt_open_app" if((options) && (szoptions)) { $? ". args ok" back = dk3_new_app(dk3_option_set_t,1,app); if(back) { $? ". back ok" back->app = app; back->options = options; back->szoptions = szoptions; back->found = NULL; back->optargs = NULL; back->args = NULL; back->fo = NULL; back->foc = foc; back->focl = focl; back->argsav = 0; back->argsused = 0; back->foav = 0; back->fou = 0; back->ec = 0; back->found = dk3_new_app(int,szoptions,app); if(back->found) { $? ". back->found ok cleaning" for(j = 0; j < szoptions; j++) { (back->found)[j] = 0; } $? ". cleaning finished, going to allocate optargs" back->optargs = dk3_new_app(DK3_PCDKCHAR,szoptions,app); if(back->optargs) { $? ". back->optargs ok" for(j = 0; j < szoptions; j++) { (back->optargs)[j] = NULL; } if(argc) { back->args = dk3_new_app(DK3_PCDKCHAR,argc,app); if(back->args) { back->argsav = argc; for(i = 0; i < argc; i++) { (back->args)[i] = NULL; } back->fo = dk3_new_app(DK3_PCDKCHAR,argc,app); if(back->fo) { back->foav = argc; for(i = 0; i < argc; i++) { (back->fo)[i] = NULL; } ok = 1; $? ". all memory ok" dk3opt_apply_options(back, argc, argv); } } } else { ok = 1; } } else { $? "! back->optargs" } } else { $? "! back->found" } if(!ok) { dk3opt_close(back); back = NULL; } if(back) { if(back->ec) { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 252); } } } } } $? "- dk3opt_open_app %s", TR_PTR(back) return back; } dk3_option_set_t * dk3opt_open_from_app( dk3_option_t const *options, size_t szoptions, dkChar foc, dkChar const *focl, dk3_app_t *app ) { dk3_option_set_t *back = NULL; dkChar const * const *argv; int argc; $? "+ dk3opt_open_from_app" if((options) && (szoptions) && (app)) { argc = dk3app_get_argc(app); argv = dk3app_get_argv(app); argv++; argc--; back = dk3opt_open_app(options, szoptions, foc, focl, argc, argv, app); } $? "- dk3opt_open_from_app %s", TR_PTR(back) return back; } int dk3opt_is_set( dk3_option_set_t const *optset, dkChar shortopt ) { int back = 0; size_t i; $? "+ dk3opt_is_set %c", shortopt if(optset) { if(dk3opt_find_index_short(optset, shortopt, &i)) { if(optset->found) { back = (optset->found)[i]; } } } $? "- dk3opt_is_set %d", back return back; } int dk3opt_is_set_long( dk3_option_set_t const *optset, dkChar const *longopt ) { int back = 0; size_t i; $? "+ dk3opt_is_set_long \"%s\"", TR_STR(longopt) if((optset) && (longopt)) { if(dk3opt_find_index_long(optset, longopt, &i)) { if(optset->found) { back = (optset->found)[i]; $? ". index=%u", (unsigned)i } } } $? "- dk3opt_is_set_long %d", back return back; } dkChar const * dk3opt_get_short_arg( dk3_option_set_t const *optset, dkChar shortopt ) { dkChar const *back = NULL; size_t i; $? "+ dk3opt_get_short_arg %c", shortopt if(optset) { if(dk3opt_find_index_short(optset, shortopt, &i)) { if(optset->options) { if(((optset->options)[i]).na) { if(optset->optargs) { back = (optset->optargs)[i]; } } } } } $? "- dk3opt_get_short_arg \"%s\"", TR_STR(back) return back; } dkChar const * dk3opt_get_long_arg( dk3_option_set_t const *optset, dkChar const *longopt ) { dkChar const *back = NULL; size_t i; $? "+ dk3opt_get_long_arg \"%s\"", TR_STR(longopt) if((optset) && (longopt)) { if(dk3opt_find_index_long(optset, longopt, &i)) { if(optset->options) { if(((optset->options)[i]).na) { if(optset->optargs) { back = (optset->optargs)[i]; } } } } } $? "- dk3opt_get_long_arg \"%s\"", TR_STR(back) return back; } int dk3opt_get_num_args( dk3_option_set_t const *optset ) { int back = 0; $? "+ dk3opt_get_num_args" if(optset) { back = optset->argsused; } $? "- dk3opt_get_num_args %d", back return back; } dkChar const * dk3opt_get_arg( dk3_option_set_t const *optset, int num ) { dkChar const *back = NULL; $? "+ dk3opt_get_arg %d", num if((optset) && (num >= 0)) { if(num < optset->argsused) { if(optset->args) { back = (optset->args)[num]; } } } $? "- dk3opt_get_arg \"%s\"", TR_STR(back) return back; } int dk3opt_get_num_fo( dk3_option_set_t const *os ) { int back = 0; $? "+ dk3opt_get_num_fo" if(os) { back = os->fou; } $? "- dk3opt_get_num_fo %d", back return back; } dkChar const * dk3opt_get_fo( dk3_option_set_t const *os, int num ) { dkChar const *back = NULL; $? "+ dk3opt_get_fo %d", num if((os) && (num >= 0)) { if(num < os->fou) { if(os->fo) { back = (os->fo)[num]; } } } $? "- dk3opt_get_fo \"%s\"", TR_STR(back) return back; } void dk3opt_close( dk3_option_set_t *os ) { int i; size_t j; $? "+ dk3opt_close" if(os) { if(os->optargs) { for(j = 0; j < os->szoptions; j++) { (os->optargs)[j] = NULL; } $? ". del optargs +" dk3_delete(os->optargs); $? ". del optargs -" } os->optargs = NULL; if(os->found) { for(j = 0; j < os->szoptions; j++) { (os->found)[j] = 0;} $? ". del found +" dk3_delete(os->found); $? ". del found -" } os->found = NULL; if(os->args) { for(i = 0; i < os->argsav; i++) { (os->args)[i] = NULL; } $? ". del args +" dk3_delete(os->args); $? ". del args -" } os->args = NULL; if(os->fo) { for(i = 0; i < os->foav; i++) { (os->fo)[i] = NULL; } $? ". del fo +" dk3_delete(os->fo); $? ". del fo -" } os->fo = NULL; os->options = NULL; os->szoptions = 0; os->argsav = os->argsused = 0; os->foav = os->fou = 0; os->ec = 0; os->focl = NULL; os->foc = dkT('\0'); $? ". del os +" dk3_delete(os); $? ". del os -" } $? "- dk3opt_close" } int dk3opt_get_error_code(dk3_option_set_t const *os) { int back = 0; if(os) { back = os->ec; } return back; } void dk3opt_reset_error_code(dk3_option_set_t *os) { if(os) { os->ec = 0; } } /* vim: set ai sw=2 : */