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
parent
205b20f0f4
commit
0835191372
|
@ -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 =
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
211
src/mdtest.c
211
src/mdtest.c
|
@ -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, ¶m) != 0) {
|
||||
if (backend->mkdir(testdirpath, DIRMODE, ¶m) != 0) {
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue