diff --git a/src/Makefile.am b/src/Makefile.am index 2bb9e96..447b9b9 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,19 +3,19 @@ if USE_CAPS bin_PROGRAMS += IOR MDTEST endif -noinst_HEADERS = ior.h utilities.h parse_options.h aiori.h iordef.h getopt/optlist.h ior-internal.h +noinst_HEADERS = ior.h utilities.h parse_options.h aiori.h iordef.h getopt/optlist.h ior-internal.h option.h extraSOURCES = aiori.c aiori-DUMMY.c extraLDADD = extraLDFLAGS = extraCPPFLAGS = -ior_SOURCES = ior-main.c ior.c utilities.c parse_options.c getopt/optlist.c ior-output.c +ior_SOURCES = ior-main.c ior.c utilities.c parse_options.c getopt/optlist.c ior-output.c option.c ior_LDFLAGS = ior_LDADD = ior_CPPFLAGS = -mdtest_SOURCES = mdtest-main.c mdtest.c utilities.c getopt/optlist.c +mdtest_SOURCES = mdtest-main.c mdtest.c utilities.c getopt/optlist.c option.c mdtest_LDFLAGS = mdtest_LDADD = mdtest_CPPFLAGS = diff --git a/src/aiori-DUMMY.c b/src/aiori-DUMMY.c index eb54940..511a97c 100755 --- a/src/aiori-DUMMY.c +++ b/src/aiori-DUMMY.c @@ -14,16 +14,40 @@ #include "aiori.h" #include "utilities.h" + +/************************** O P T I O N S *****************************/ +struct dummy_options{ + uint64_t delay_creates; + int delay_rank_0_only; +}; + +static struct dummy_options o = { + .delay_creates = 0, + .delay_rank_0_only = 0, +}; + +static option_help options [] = { + {'c', "delay-create", "Delay per create in usec", OPTION_OPTIONAL_ARGUMENT, 'l', & o.delay_creates}, + {'z', "delay-only-rank0", "Delay only Rank0", OPTION_FLAG, 'd', & o.delay_rank_0_only}, + LAST_OPTION +}; + static char * current = (char*) 1; +static option_help * DUMMY_options(){ + return options; +} + static void *DUMMY_Create(char *testFileName, IOR_param_t * param) { if(verbose > 4){ fprintf(out_logfile, "DUMMY create: %s = %p\n", testFileName, current); } - if (rank == 0){ - usleep(100000); - } + if (o.delay_creates){ + if (! o.delay_rank_0_only || (o.delay_rank_0_only && rank == 0)){ + usleep(o.delay_creates); + } + } return current++; } @@ -58,7 +82,7 @@ static void DUMMY_Delete(char *testFileName, IOR_param_t * param) static void DUMMY_SetVersion(IOR_param_t * test) { - sprintf(test->apiVersion, "DUMMY"); + sprintf(test->apiVersion, "DUMMY-0.5"); } static IOR_offset_t DUMMY_GetFileSize(IOR_param_t * test, MPI_Comm testComm, char *testFileName) @@ -119,5 +143,6 @@ ior_aiori_t dummy_aiori = { DUMMY_mkdir, DUMMY_rmdir, DUMMY_access, - DUMMY_stat + DUMMY_stat, + DUMMY_options }; diff --git a/src/aiori-RADOS.c b/src/aiori-RADOS.c index 6d88a7c..a1f51c1 100755 --- a/src/aiori-RADOS.c +++ b/src/aiori-RADOS.c @@ -27,6 +27,21 @@ #include "aiori.h" #include "utilities.h" +/************************** O P T I O N S *****************************/ +struct rados_options{ + char * username; +}; + +static struct rados_options o = { + .username = "admin", +}; + +static option_help options [] = { + {'u', "username", "Username for the RADOS cluster", OPTION_REQUIRED_ARGUMENT, 's', & o.username}, + LAST_OPTION +}; + + /**************************** P R O T O T Y P E S *****************************/ static void *RADOS_Create(char *, IOR_param_t *); static void *RADOS_Open(char *, IOR_param_t *); @@ -42,9 +57,9 @@ static int RADOS_MkDir(const char *, mode_t, IOR_param_t *); static int RADOS_RmDir(const char *, IOR_param_t *); static int RADOS_Access(const char *, int, IOR_param_t *); static int RADOS_Stat(const char *, struct stat *, IOR_param_t *); +static option_help * RADIOS_options(); /************************** D E C L A R A T I O N S ***************************/ - ior_aiori_t rados_aiori = { .name = "RADOS", .create = RADOS_Create, @@ -60,6 +75,7 @@ ior_aiori_t rados_aiori = { .rmdir = RADOS_RmDir, .access = RADOS_Access, .stat = RADOS_Stat, + .get_options = RADIOS_options, }; #define RADOS_ERR(__err_str, __ret) do { \ @@ -68,14 +84,16 @@ ior_aiori_t rados_aiori = { } while(0) /***************************** F U N C T I O N S ******************************/ +static option_help * RADIOS_options(){ + return options; +} static void RADOS_Cluster_Init(IOR_param_t * param) { int ret; /* create RADOS cluster handle */ - /* XXX: HARDCODED RADOS USER NAME */ - ret = rados_create(¶m->rados_cluster, "admin"); + ret = rados_create(¶m->rados_cluster, o.username); if (ret) RADOS_ERR("unable to create RADOS cluster handle", ret); diff --git a/src/aiori.h b/src/aiori.h index ca28c3c..c815a9b 100755 --- a/src/aiori.h +++ b/src/aiori.h @@ -25,6 +25,7 @@ #include "ior.h" #include "iordef.h" /* IOR Definitions */ +#include "option.h" /*************************** D E F I N I T I O N S ****************************/ @@ -61,6 +62,7 @@ typedef struct ior_aiori_statfs { uint64_t f_ffree; } ior_aiori_statfs_t; + typedef struct ior_aiori { char *name; void *(*create)(char *, IOR_param_t *); @@ -77,6 +79,7 @@ typedef struct ior_aiori { int (*rmdir) (const char *path, IOR_param_t * param); int (*access) (const char *path, int mode, IOR_param_t * param); int (*stat) (const char *path, struct stat *buf, IOR_param_t * param); + option_help * (*get_options)(); } ior_aiori_t; extern ior_aiori_t dummy_aiori; diff --git a/src/mdtest.c b/src/mdtest.c index c88e0f9..2da9edc 100644 --- a/src/mdtest.c +++ b/src/mdtest.c @@ -38,7 +38,7 @@ #include #include -#include "getopt/optlist.h" +#include "option.h" #include "utilities.h" #if HAVE_SYS_PARAM_H @@ -1520,6 +1520,18 @@ void summarize_results(int iterations) { /* Checks to see if the test setup is valid. If it isn't, fail. */ void valid_tests() { + if(stone_wall_timer_seconds > 0 && branch_factor > 1 || ! barriers){ + fprintf(out_logfile, "Error, stone wall timer does only work with a branch factor <= 1 and with barriers\n"); + MPI_Abort(testComm, 1); + } + + if (!create_only && !stat_only && !read_only && !remove_only) { + create_only = stat_only = read_only = remove_only = 1; + if (( rank == 0 ) && ( verbose >= 1 )) { + fprintf( out_logfile, "V-1: main: Setting create/stat/read/remove_only to True\n" ); + fflush( out_logfile ); + } + } if (( rank == 0 ) && ( verbose >= 1 )) { fprintf( out_logfile, "V-1: Entering valid_tests...\n" ); @@ -2076,6 +2088,7 @@ void mdtest_init_args(){ nstride = 0; } + mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE * world_out) { testComm = world_com; out_logfile = world_out; @@ -2097,14 +2110,76 @@ mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE * int stride = 1; int iterations = 1; - /* Check for -h parameter before MPI_Init so the mdtest binary can be - called directly, without, for instance, mpirun. */ - for (i = 1; i < argc; i++) { - if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { - print_help(); - } + verbose = 0; + int no_barriers = 0; + char * path = "./out"; + int randomize = 0; + option_help options [] = { + {'a', NULL, "API for I/O [POSIX|MPIIO|HDF5|HDFS|S3|S3_EMC|NCMPI]", OPTION_OPTIONAL_ARGUMENT, 's', & backend_name}, + {'b', NULL, "branching factor of hierarchical directory structure", OPTION_OPTIONAL_ARGUMENT, 'd', & branch_factor}, + {'d', NULL, "the directory in which the tests will run", OPTION_OPTIONAL_ARGUMENT, 's', & path}, + {'B', NULL, "no barriers between phases", OPTION_OPTIONAL_ARGUMENT, 'd', & no_barriers}, + {'C', NULL, "only create files/dirs", OPTION_FLAG, 'd', & create_only}, + {'T', NULL, "only stat files/dirs", OPTION_FLAG, 'd', & stat_only}, + {'E', NULL, "only read files/dir", OPTION_FLAG, 'd', & read_only}, + {'r', NULL, "only remove files or directories left behind by previous runs", OPTION_FLAG, 'd', & remove_only}, + {'D', NULL, "perform test on directories only (no files)", OPTION_FLAG, 'd', & dirs_only}, + {'e', NULL, "bytes to read from each file", OPTION_OPTIONAL_ARGUMENT, 'l', & read_bytes}, + {'f', NULL, "first number of tasks on which the test will run", OPTION_OPTIONAL_ARGUMENT, 'd', & first}, + {'F', NULL, "perform test on files only (no directories)", OPTION_FLAG, 'd', & files_only}, + {'i', NULL, "number of iterations the test will run", OPTION_OPTIONAL_ARGUMENT, 'i', & iterations}, + {'I', NULL, "number of items per directory in tree", OPTION_OPTIONAL_ARGUMENT, 'l', & items_per_dir}, + {'l', NULL, "last number of tasks on which the test will run", OPTION_OPTIONAL_ARGUMENT, 'd', & last}, + {'L', NULL, "files only at leaf level of tree", OPTION_FLAG, 'd', & leaf_only}, + {'n', NULL, "every process will creat/stat/read/remove # directories and files", OPTION_OPTIONAL_ARGUMENT, 'l', & items}, + {'N', NULL, "stride # between neighbor tasks for file/dir operation (local=0)", OPTION_OPTIONAL_ARGUMENT, 'd', & nstride}, + {'p', NULL, "pre-iteration delay (in seconds)", OPTION_OPTIONAL_ARGUMENT, 'd', & pre_delay}, + {'R', NULL, "randomly stat files", OPTION_FLAG, 'd', & randomize}, + {0, "random-seed", "random seed for -R", OPTION_OPTIONAL_ARGUMENT, 'd', & random_seed}, + {'s', NULL, "stride between the number of tasks for each test", OPTION_OPTIONAL_ARGUMENT, 'd', & stride}, + {'S', NULL, "shared file access (file only, no directories)", OPTION_FLAG, 'd', & shared_file}, + {'c', NULL, "collective creates: task 0 does all creates", OPTION_FLAG, 'd', & collective_creates}, + {'t', NULL, "time unique working directory overhead", OPTION_FLAG, 'd', & time_unique_dir_overhead}, + {'u', NULL, "unique working directory for each task", OPTION_FLAG, 'd', & unique_dir_per_task}, + {'v', NULL, "verbosity (each instance of option increments by one)", OPTION_FLAG, 'd', & verbose}, + {'V', NULL, "verbosity value", OPTION_OPTIONAL_ARGUMENT, 'd', & verbose}, + {'w', NULL, "bytes to write to each file after it is created", OPTION_OPTIONAL_ARGUMENT, 'l', & write_bytes}, + {'W', NULL, "number in seconds; stonewall timer, write as many seconds and ensure all processes did the same number of operations (currently only stops during create phase)", OPTION_OPTIONAL_ARGUMENT, 'd', & stone_wall_timer_seconds}, + {'x', NULL, "StoneWallingStatusFile; contains the number of iterations of the creation phase, can be used to split phases across runs", OPTION_OPTIONAL_ARGUMENT, 's', & stoneWallingStatusFile}, + {'y', NULL, "sync file after writing", OPTION_FLAG, 'd', & sync_file}, + {'z', NULL, "depth of hierarchical directory structure", OPTION_OPTIONAL_ARGUMENT, 'd', & depth}, + {'Z', NULL, "print time instead of rate", OPTION_FLAG, 'd', & print_time}, + LAST_OPTION + }; + int printhelp = 0; + int parsed_options = option_parse(argc, argv, options, & printhelp); + + backend = aiori_select (backend_name); + if (NULL == backend) { + FAIL("Could not find suitable backend to use"); } + if(backend->get_options != NULL){ + option_parse(argc - parsed_options, argv + parsed_options, backend->get_options(), & printhelp); + } + + if(printhelp != 0){ + printf("\nSynopsis: %s ", argv[0]); + + option_print_help(options, 0); + + if(backend->get_options != NULL){ + printf("\nPlugin options for backend %s\n", backend_name); + option_print_help(backend->get_options(), 1); + } + if(printhelp == 1){ + exit(0); + }else{ + exit(1); + } + } + + MPI_Comm_rank(testComm, &rank); MPI_Comm_size(testComm, &size); @@ -2129,116 +2204,25 @@ mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE * fflush(out_logfile); } - /* Parse command line options */ - - verbose = 0; - option_t *optList, *thisOpt; - optList = GetOptList(argc, argv, "a:b:BcCd:De:Ef:Fhi:I:l:Ln:N:p:rR::s:StTuvV:w:W:x:yz:Z"); - - - while (optList != NULL) { - thisOpt = optList; - optarg = thisOpt->argument; - optList = optList->next; - switch (thisOpt->option) { - case 'a': - backend_name = optarg; break; - case 'b': - branch_factor = atoi(optarg); break; - case 'B': - barriers = 0; break; - case 'c': - collective_creates = 1; break; - case 'C': - create_only = 1; break; - case 'd': - parse_dirpath(optarg); break; - case 'D': - dirs_only = 1; break; - case 'e': - read_bytes = ( size_t )strtoul( optarg, ( char ** )NULL, 10 ); break; - //read_bytes = atoi(optarg); break; - case 'E': - read_only = 1; break; - case 'f': - first = atoi(optarg); break; - case 'F': - files_only = 1; break; - case 'h': - print_help(); break; - case 'i': - iterations = atoi(optarg); break; - case 'I': - items_per_dir = (uint64_t) strtoul( optarg, ( char ** )NULL, 10 ); break; - //items_per_dir = atoi(optarg); break; - case 'l': - last = atoi(optarg); break; - case 'L': - leaf_only = 1; break; - case 'n': - items = (uint64_t) strtoul( optarg, ( char ** )NULL, 10 ); break; - //items = atoi(optarg); break; - case 'N': - nstride = atoi(optarg); break; - case 'p': - pre_delay = atoi(optarg); break; - case 'r': - remove_only = 1; break; - case 'R': - if (optarg == NULL) { - random_seed = time(NULL); - MPI_Barrier(testComm); - MPI_Bcast(&random_seed, 1, MPI_INT, 0, testComm); - random_seed += rank; - } else { - random_seed = atoi(optarg)+rank; - } - break; - case 's': - stride = atoi(optarg); break; - case 'S': - shared_file = 1; break; - case 't': - time_unique_dir_overhead = 1; break; - case 'T': - stat_only = 1; break; - case 'u': - unique_dir_per_task = 1; break; - case 'v': - verbose += 1; break; - case 'V': - verbose = atoi(optarg); break; - case 'w': - write_bytes = ( size_t )strtoul( optarg, ( char ** )NULL, 10 ); break; - case 'W': - stone_wall_timer_seconds = atoi( optarg ); break; - case 'x': - stoneWallingStatusFile = strdup(optarg); break; - case 'y': - sync_file = 1; break; - case 'z': - depth = atoi(optarg); break; - case 'Z': - print_time = TRUE; break; - } + /* adjust special variables */ + barriers = ! no_barriers; + if (path != NULL){ + parse_dirpath(path); } - - if(stone_wall_timer_seconds > 0 && branch_factor > 1 || ! barriers){ - fprintf(out_logfile, "Error, stone wall timer does only work with a branch factor <= 1 and with barriers\n"); - MPI_Abort(testComm, 1); - } - - if (!create_only && !stat_only && !read_only && !remove_only) { - create_only = stat_only = read_only = remove_only = 1; - if (( rank == 0 ) && ( verbose >= 1 )) { - fprintf( out_logfile, "V-1: main: Setting create/stat/read/remove_only to True\n" ); - fflush( out_logfile ); - } + if( randomize > 0 ){ + if (random_seed == 0) { + /* Ensure all procs have the same random number */ + random_seed = time(NULL); + MPI_Barrier(testComm); + MPI_Bcast(&random_seed, 1, MPI_INT, 0, testComm); + } + random_seed += rank; } valid_tests(); if (( rank == 0 ) && ( verbose >= 1 )) { + // option_print_current(options); fprintf (out_logfile, "api : %s\n", backend_name); fprintf( out_logfile, "barriers : %s\n", ( barriers ? "True" : "False" )); fprintf( out_logfile, "collective_creates : %s\n", ( collective_creates ? "True" : "False" )); @@ -2363,11 +2347,6 @@ mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE * strcpy(testdirpath, filenames[rank%path_count]); } - backend = aiori_select (backend_name); - if (NULL == backend) { - FAIL("Could not find suitable backend to use"); - } - /* if directory does not exist, create it */ if ((rank < path_count) && backend->access(testdirpath, F_OK, ¶m) != 0) { if (backend->mkdir(testdirpath, DIRMODE, ¶m) != 0) { diff --git a/src/option.c b/src/option.c new file mode 100644 index 0000000..f9f6183 --- /dev/null +++ b/src/option.c @@ -0,0 +1,326 @@ +#include +#include +#include +#include +#include + +#include + +/* + * Initial revision by JK + */ + +static int print_value(option_help * o){ + int pos = 0; + if (o->arg == OPTION_OPTIONAL_ARGUMENT || o->arg == OPTION_REQUIRED_ARGUMENT){ + assert(o->variable != NULL); + + switch(o->type){ + case('F'):{ + pos += printf("=%.14f ", *(double*) o->variable); + break; + } + case('f'):{ + pos += printf("=%.6f ", (double) *(float*) o->variable); + break; + } + case('d'):{ + pos += printf("=%d ", *(int*) o->variable); + break; + } + case('H'): + case('s'):{ + if ( *(char**) o->variable != NULL && ((char**) o->variable)[0][0] != 0 ){ + pos += printf("=%s", *(char**) o->variable); + }else{ + pos += printf("=STRING"); + } + break; + } + case('c'):{ + pos += printf("=%c", *(char*) o->variable); + break; + } + case('l'):{ + pos += printf("=%lld", *(long long*) o->variable); + break; + } + } + } + if (o->arg == OPTION_FLAG && (*(int*)o->variable) != 0){ + pos += printf(" (%d)", (*(int*)o->variable)); + } + + return pos; +} + +static void print_help_section(option_help * args, option_value_type type, char * name){ + int first; + first = 1; + option_help * o; + for(o = args; o->shortVar != 0 || o->longVar != 0 || o->help != NULL ; o++){ + if( o->shortVar == 0 && o->longVar == 0 && o->help != NULL){ + printf("%-15s %s\n", "", o->help); + continue; + } + + if (o->arg == type){ + if (first){ + printf("\n%s\n", name); + first = 0; + } + printf(" "); + int pos = 0; + if(o->shortVar != 0 && o->longVar != 0){ + pos += printf("-%c, --%s", o->shortVar, o->longVar); + }else if(o->shortVar != 0){ + pos += printf("-%c", o->shortVar); + }else if(o->longVar != 0){ + pos += printf("--%s", o->longVar); + } + + pos += print_value(o); + if(o->help != NULL){ + for(int i = 0 ; i < (30 - pos); i++){ + printf(" "); + } + printf("%s", o->help); + } + printf("\n"); + } + } +} + +void option_print_help(option_help * args, int is_plugin){ + option_help * o; + int optionalArgs = 0; + for(o = args; o->shortVar != 0 || o->longVar != 0 ; o++){ + if(o->arg != OPTION_REQUIRED_ARGUMENT){ + optionalArgs = 1; + } + + switch(o->arg){ + case (OPTION_OPTIONAL_ARGUMENT): + case (OPTION_FLAG):{ + if(o->shortVar != 0){ + printf("[-%c] ", o->shortVar); + }else if(o->longVar != 0){ + printf("[--%s] ", o->longVar); + } + break; + }case (OPTION_REQUIRED_ARGUMENT):{ + if(o->shortVar != 0){ + printf("-%c ", o->shortVar); + }else if(o->longVar != 0){ + printf("--%s ", o->longVar); + } + break; + } + } + } + if (optionalArgs){ + //printf(" [Optional Args]"); + } + if (! is_plugin){ + printf(" -- \n"); + } + + print_help_section(args, OPTION_REQUIRED_ARGUMENT, "Required arguments"); + print_help_section(args, OPTION_FLAG, "Flags"); + print_help_section(args, OPTION_OPTIONAL_ARGUMENT, "Optional arguments"); +} + + +static int print_option_value(option_help * o){ + int pos = 0; + if (o->arg == OPTION_OPTIONAL_ARGUMENT || o->arg == OPTION_REQUIRED_ARGUMENT){ + assert(o->variable != NULL); + + switch(o->type){ + case('F'):{ + pos += printf("=%.14f ", *(double*) o->variable); + break; + } + case('f'):{ + pos += printf("=%.6f ", (double) *(float*) o->variable); + break; + } + case('d'):{ + pos += printf("=%d ", *(int*) o->variable); + break; + } + case('H'):{ + pos += printf("=HIDDEN"); + break; + } + case('s'):{ + if ( *(char**) o->variable != NULL && ((char**) o->variable)[0][0] != 0 ){ + pos += printf("=%s", *(char**) o->variable); + }else{ + pos += printf("="); + } + break; + } + case('c'):{ + pos += printf("=%c", *(char*) o->variable); + break; + } + case('l'):{ + pos += printf("=%lld", *(long long*) o->variable); + break; + } + } + }else{ + //printf(" "); + } + + return pos; +} + + +static void print_current_option_section(option_help * args, option_value_type type){ + option_help * o; + for(o = args; o->shortVar != 0 || o->longVar != 0 ; o++){ + if (o->arg == type){ + int pos = 0; + if (o->arg == OPTION_FLAG && (*(int*)o->variable) == 0){ + continue; + } + printf("\t"); + + if(o->shortVar != 0 && o->longVar != 0){ + pos += printf("%s", o->longVar); + }else if(o->shortVar != 0){ + pos += printf("%c", o->shortVar); + }else if(o->longVar != 0){ + pos += printf("%s", o->longVar); + } + + pos += print_option_value(o); + printf("\n"); + } + } +} + + +void option_print_current(option_help * args){ + print_current_option_section(args, OPTION_REQUIRED_ARGUMENT); + print_current_option_section(args, OPTION_OPTIONAL_ARGUMENT); + print_current_option_section(args, OPTION_FLAG); +} + +int option_parse(int argc, char ** argv, option_help * args, int * printhelp){ + int error = 0; + int requiredArgsSeen = 0; + int requiredArgsNeeded = 0; + int i; + + for(option_help * o = args; o->shortVar != 0 || o->longVar != 0 ; o++ ){ + if(o->arg == OPTION_REQUIRED_ARGUMENT){ + requiredArgsNeeded++; + } + } + for(i=1; i < argc; i++){ + char * txt = argv[i]; + int foundOption = 0; + char * arg = strstr(txt, "="); + if(arg != NULL){ + arg[0] = 0; + arg++; + } + if(strcmp(txt, "--") == 0){ + // we found plugin options + break; + } + + // try to find matching option help + for(option_help * o = args; o->shortVar != 0 || o->longVar != 0 || o->help != NULL ; o++ ){ + if ( (strlen(txt) == 2 && txt[0] == '-' && o->shortVar == txt[1]) || (strlen(txt) > 2 && txt[0] == '-' && txt[1] == '-' && o->longVar != NULL && strcmp(txt + 2, o->longVar) == 0)){ + foundOption = 1; + + if( o->shortVar == 0 && o->longVar == 0 && o->help != NULL){ + // section + continue; + } + + // now process the option. + switch(o->arg){ + case (OPTION_FLAG):{ + assert(o->type == 'd'); + (*(int*) o->variable)++; + break; + } + case (OPTION_OPTIONAL_ARGUMENT): + case (OPTION_REQUIRED_ARGUMENT):{ + // check if next is an argument + if(arg == NULL){ + // simply take the next value as argument + i++; + arg = argv[i]; + } + + switch(o->type){ + case('F'):{ + *(double*) o->variable = atof(arg); + break; + } + case('f'):{ + *(float*) o->variable = atof(arg); + break; + } + case('d'):{ + *(int*) o->variable = atoi(arg); + break; + } + case('H'): + case('s'):{ + (*(char **) o->variable) = strdup(arg); + break; + } + case('c'):{ + (*(char *)o->variable) = arg[0]; + if(strlen(arg) > 1){ + printf("Error, ignoring remainder of string for option %c (%s).\n", o->shortVar, o->longVar); + } + break; + } + case('l'):{ + *(long long*) o->variable = atoll(arg); + break; + } + } + } + } + if(arg != NULL){ + arg[-1] = '='; + } + + if(o->arg == OPTION_REQUIRED_ARGUMENT){ + requiredArgsSeen++; + } + + break; + } + } + if (! foundOption){ + if(strcmp(txt, "-h") == 0 || strcmp(txt, "--help") == 0){ + *printhelp=1; + }else{ + printf("Error invalid argument: %s\n", txt); + error = 1; + } + } + } + + if( requiredArgsSeen != requiredArgsNeeded ){ + printf("Error: Missing some required arguments\n\n"); + *printhelp = -1; + } + + if(error != 0){ + printf("Invalid options\n"); + *printhelp = -1; + } + + return i; +} diff --git a/src/option.h b/src/option.h new file mode 100644 index 0000000..e2f5249 --- /dev/null +++ b/src/option.h @@ -0,0 +1,32 @@ +#ifndef IOR_OPTION_H +#define IOR_OPTION_H + +/* + * Initial revision by JK + */ + +typedef enum{ + OPTION_FLAG, + OPTION_OPTIONAL_ARGUMENT, + OPTION_REQUIRED_ARGUMENT +} option_value_type; + +typedef struct{ + char shortVar; + char * longVar; + char * help; + + option_value_type arg; + char type; // data type, H = hidden string + void * variable; +} option_help; + +#define LAST_OPTION {0, 0, 0, (option_value_type) 0, 0, NULL} + +void option_print_help(option_help * args, int is_plugin); +void option_print_current(option_help * args); + +//@return the number of parsed arguments +int option_parse(int argc, char ** argv, option_help * args, int * print_help); + +#endif