Option parser replaced.

Benefits: shows currently set options when used with -h
Supports options for child modules, example for aiori-dummy works, RADOS untested.
master
Julian M. Kunkel 2018-07-12 18:09:13 +01:00
parent 205b20f0f4
commit 0835191372
7 changed files with 510 additions and 127 deletions

View File

@ -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 =

View File

@ -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
};

View File

@ -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(&param->rados_cluster, "admin");
ret = rados_create(&param->rados_cluster, o.username);
if (ret)
RADOS_ERR("unable to create RADOS cluster handle", ret);

View File

@ -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;

View File

@ -38,7 +38,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#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, &param) != 0) {
if (backend->mkdir(testdirpath, DIRMODE, &param) != 0) {

326
src/option.c Normal file
View File

@ -0,0 +1,326 @@
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <option.h>
/*
* 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(" -- <Plugin options, see below>\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;
}

32
src/option.h Normal file
View File

@ -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