/* Copyright (C) 2020 Momi-g

 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 3 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.

 You should have received a copy of the GNU General Public License
 along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

/*SH_doc
@NAME	optbox - cmdline option parser consisting of a header file

@SYNOPSYS
<pre>
#include "optbox.h"

//macro
OPTBOX_SET(ptrname, mode
 , ( col1, col2, col3, col4, col5)	//setting(col1-4)+test(col5)
 , ( col1, col2, col3, col4)
 , .....
)	
//func
static int optbox_init(void* buff, int *argc_p, char** *argv_p);
static void* optbox_get(void* obj, const char* name);
static void* optbox_set(void* obj, const char* name, ...);	//va_arg
</pre>

@EXSAMPLE
<pre>
#include "optbox.h"

OPTBOX_SET( opts, "q"
 , ( help,  "-h", "0"     ,bool)	//basic
 , ( count, "-n", "1"     ,int	,return (0<=i && i<=3))	//with test
 , ( file,  "-f", "a.ini" ,str	, { if(strlen(s)>10){return 0;} } )
 , ( wait,  "-d", "0.3"   ,dbl	,if(0>d)	\
 	{ return 0;}; opts->wait += 123; return 1; )
)

int main(int argc, char** argv){
 int rc= optbox_init(opts, &argc, &argv);	//consume optargs
 if(rc){ printf("badopt: %c\n", rc);return rc;}
//
 printf("%d\n", opts->help);		// 0 or 1. bool >>> int.
 printf("%d\n", opts->count);		// 0<=num<=3 
 puts(opts->file);			// "a.ini" "cmdin_string"	etc
 puts(argv[1]);			//~$ ./a.out -h xy >>> ac=2, av[1]="xy"
 double d= *(double*)optbox_get(opts,"wait");	//type punning. d=123.03
 optbox_set(opts, "file", "hw");
 puts(opts->file);		// before:"a.ini" >>> after:"hw"
 return 0;
}
// ~$ gcc src.c 	#>> header file holds implements
// ~$ ./a.out -f abc.txt xyz
// ~$ ./a.out -n abc; echo $?	# emsg
</pre>

@DESCRIPTION
optbox saves cmdline options to static vars and doesnt use malloc().
options are parsed under the posix, getopts() rule. longopt is unsupported.

<pre>
- OPTBOX_SET(pname, mode, (cols), (cols),...): basic setting macro

	pname: ptrname to static buff created automatically like XX_pname 
	mode : flgchars for parse mode. dfl is "". allows "xq" chars
	 x: expand. dflmode works under the posix Utility Syntax Guidelines.
		'x' allows symbol opt, '-@' '-_' '-+' etc. '--' works as optend.
		'x' parses until '--' or args end.	eg) a.out abc -h >> hit -h
	
	 q: quiet. dflmode outputs emsg to stderr and exit if detect err in 
	    optbox_init(). 'q' mode rtns err charcode and skip emsg/exit.
		
	cols: option setting core. (col1, col2, col3, col4 [,col5])
	 col1: option name. no quote.
	 col2: cmdline short option char. needs prefix hyphen '-' and quote.
	 col3: dfl val. needs quote (or 'NULL' if datatype is str).
	 col4: datatype, 'bool(on-off)/int/dbl/str'. no quote. cmdin filter.
	 col5: optional. write raw testcode. no quote. expands as below.
 
		static int testfc_[col1](const char* s){
			if(!s){s="1";}
			int i=atoi(s); double d=atof(s);
			//--- expand [col5] --- 
			;return 1;
		}
		// ~$ ./a.out -p 32.1  >>>  s="32.1", i=32, d=32.1 

 ...you can use i/d/s vars. s is cmdin optarg. raise err if rtn 0.
 dfldata skips this test.

- int optbox_init(void* pname, int *ac_p, char** *av_p): execute parse

	pname: ptrname to buff. use the same of OPTBOX_SET() ag1
	ac_p : ptr to args count, &argc etc. optbox eats optargs and shift
	av_p : ptr to args array, &argv etc
	return: suc/fail == 0/not 0(mode q). rtn bad optchar, rc='h' etc

 you can get/set optvalues using pname. value type is defined in
 OPTBOX_SET(), bool/int/dbl/str. bool is treaded as int. optvalue
 holds 3 data, XXX, XXX_dfl, XXX_cmdin.

	pname->help	     : dfl/cmdin value. int/double/const char*
	pname->help_dfl	 : dfl setting *string* ptr
	pname->help_cmdin: cmdin *string* ptr. set NULL if no cmdin


- void* optbox_get(void* pname, const char* name): getter
 you can get optvalues from other srcfiles, out of filescope.

	pname: ptr address to buffer
	name : option name string
	return: ptr to optvalue. use type punning. exit(1) if err.

		val = *(int*)optbox_get(opts, "help")	//same as opts->help
		p = *(char**)optbox_get(opts, "help_dfl")	//opts->help_dfl
		p = *(char**)optbox_get(opts, "help_cmdin") //opts->help_cmdin


- void* optbox_set(void* pname, const char* name, ...): setter
 set optvalues from other srcfiles. 

	pname: see getter
	name : see getter
	va_arg:	new value. set the same typedata you used in OPTBOX_SET().
	return: see getter

		(width, "-w", "2", int) 
			>>>  obj->width=10 == optbox_set(obj,"width", 10)
		
		(sec, "-s", "0.1", dbl)
			>>> obj->sec=20 == optbox_set(obj,"sec",(double)20)
	
		(id, "-i", "alice",str)
			>>> obj->id="bob" == optbox_set(obj, "id", "bob" )
</pre>

@OPTIONS	-
@EXIT_STATUS	-
@RETURN_VALUE	-
@ERRORS almost of all err causes exit. optbox_init() + quiet mode
can avoid exit at invalid cmdline input, user input.
@NOTES
<pre>
- sloppy benchmark: gcc -O0
	real	65.208 ms	: msg:direct get: 10*1000*1000
	real	635.469 ms	: msg:getter()  : 10*1000*1000
	real	48.198 ms	: msg:direct set: 10*1000*1000
	real	814.323 ms	: msg:setter()  : 10*1000*1000

 FAST: direct get/set(1) >>> optbox_get(10) > optbox_set(15) :SLOW
	...getter/setter need cost to search optvalue ptr.

- call from other files
	//a.c
	#include "optbox.h"
	OPTBOX_SET(opt, "", (id, "-i", "alice", str)	)
	int main(int argc, char** argv){
		optbox_init(opt, &argc, &argv);
		myf(opt);
		return 0;
	}
	
	//b.c
	#include "optbox.h"
	void myf(void* obj){
		char* p = *(char**)optbox_get(obj, "id");
		puts(p);
		optbox_set(obj,"id", "bob");
		p = *(char**)optbox_get(obj, "id");
		puts(p);
	}
	// ~$ gcc a.c b.c
	// ~$ ./a.out -i chris


- optbox is created with the following concept
	- easy to set standard items such as '-h' and '-n 10'
	- support boring test such as int/str and range check
	- easy to access parse result
	- collect the setting information to reduce working line of srcedit
	- avoid to force the complex apis, complex orignal macros
</pre>
@CONFORMING_TO POSIX.1-2001+
@BUGS \-
@COPYRIGHT
<pre>
Copyright 2020 momi-g, GPLv3+

uses cc-by-sa 2.5/3.0 code:
https://stackoverflow.com/questions/2632300
https://stackoverflow.com/questions/44479282
</pre>
@VERSION 2021-06-21 v2.0.0
@SEE_ALSO	-
<pre>
</pre>
//SH_docE*/
#ifndef a18d0ac31a24b
#define a18d0ac31a24b

#include <features.h>
#if ( _POSIX_C_SOURCE +0 < 200112L )
	#include "needs compiler posix-2001 or upper"
#endif

#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#define OPTBOX_ERR(xpr, msg, act)	if(xpr){ fprintf(stderr, \
	"ERR: %s %d %s() pid:%d %s msg:%s sys:%s\n",__FILE__,__LINE__, __func__	\
	, getpid(), "hit(" #xpr ")", msg, strerror(errno) ); act; }

#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdarg.h>

//uses for ptraccess arr/list 
typedef int (*optbox_test_ft)(const char*);
typedef struct optbox_ifmt_tag {
	const char* name;
	const char* optstr;	//"-h"とか
	const char* dflstr;
	const char* tp;
	void*		p;	//& static XXobj.?	...obj.help, myopt.count etc
	const char* *dfl;	//& obj.?_dfl	oldstr
	const char*	*cmdin;	//& obj.?_cmdin	newstr
	optbox_test_ft func;
}optbox_ifmt_t;

#define OPTBOX_SET(nm,mode,...)	\
	OPTBOX_BASIC(nm,mode,__VA_ARGS__)	\
	OPTBOX_DEFTF(nm,__VA_ARGS__) \
	OPTBOX_INIARR(nm,__VA_ARGS__)

//	OPTBOX_SET( obj, "mode",
//	   ( help,  "-h", "0"     ,bool )...)
#define OPTBOX_BASIC(nm, str,...)	typedef struct optbox_##nm##_tag { \
	void* parr;		                                                   \
	OPTBOX_ARGCNT(__VA_ARGS__)(OPTBOX_EXPTP, 0, __VA_ARGS__)           \
	} optbox_##nm##_t;                                                 \
	static optbox_##nm##_t OPTBOX_OBJ(nm);	                           \
	static optbox_##nm##_t* nm = &OPTBOX_OBJ(nm);	                   \
	static const char* optbox_##nm##_mode = str;
//
#define OPTBOX_OBJ(a)	optbox_##a##_obj	//root buffer
//a== ( help,  "-h", "0"     ,bool )
#define	OPTBOX_EXP(...)		__VA_ARGS__
#define	OPTBOX_EXPTP(dmy, a) OPTBOX_EXPTP1( OPTBOX_EXP a	)
#define	OPTBOX_EXPTP1(...) OPTBOX_EXPTP2(__VA_ARGS__, 0)
#define	OPTBOX_EXPTP2(a,b,c,d,...) \
	OPTBOX_##d a;	\
	const char* a##_dfl;	\
	const char* a##_cmdin;
#define OPTBOX_int	int
#define OPTBOX_dbl	double
#define OPTBOX_str	const char*
#define OPTBOX_bool	int

#define OPTBOX_DEFTF(nm,...)	OPTBOX_ARGCNT(__VA_ARGS__)(OPTBOX_DEFTF1,nm, __VA_ARGS__)
#define	OPTBOX_DEFTF1(nm, a) OPTBOX_DEFTF2(nm, OPTBOX_EXP a)
#define	OPTBOX_DEFTF2(...) OPTBOX_DEFTF3(__VA_ARGS__)
#define	OPTBOX_DEFTF3(nm, aa,bb,cc,dd,...) \
	static int optbox_tf_##nm##_##aa(const char* s){ \
	if(!s){s="1";}int i=atoi(s);double d=atof(s);__VA_ARGS__ ;return 1;i=i;d=d;}
	// i=i..stop no use warning

//inputの基本データをarrにして準備に使いやすくする a,b,c,dは()された基本データ 
#define OPTBOX_INIARR(nm,...)	static optbox_ifmt_t optbox_##nm##_iniarr[] = \
	{ OPTBOX_ARGCNT(__VA_ARGS__)(OPTBOX_INI, nm, __VA_ARGS__) {0} };	\
	static void* optbox_##nm##_parr[] = \
	{ OPTBOX_ARGCNT(__VA_ARGS__)(OPTBOX_PARR, nm, __VA_ARGS__) 0 };

#define	OPTBOX_INI(nm, a)		OPTBOX_INI1(nm, OPTBOX_EXP a) 
#define	OPTBOX_INI1(...)		OPTBOX_INI2(__VA_ARGS__) 
#define	OPTBOX_INI2(nm, a,b,c,d,...)	{#a, b, c, #d    \
	, &(OPTBOX_OBJ(nm).a) ,&(OPTBOX_OBJ(nm).a##_dfl)     \
	, &(OPTBOX_OBJ(nm).a##_cmdin), optbox_tf_##nm##_##a },
// { "help", "-h", "0", "bool", optbox_tf_obj_help, &(obj->help), &->help_dfl ...
// nm->a##_cmdin is invalid. nm.a##_cmdin is valid. right-val must be constant-value
#define	OPTBOX_PARR(nm, a)		OPTBOX_PARR1(nm, OPTBOX_EXP a) 
#define	OPTBOX_PARR1(...)		OPTBOX_PARR2(__VA_ARGS__) 
#define	OPTBOX_PARR2(nm, a,b,c,d,...)	\
	#a, &(OPTBOX_OBJ(nm).a), #d,	\
	#a "_dfl", &(OPTBOX_OBJ(nm).a##_dfl), #d,	\
	#a "_cmdin", &(OPTBOX_OBJ(nm).a##_cmdin), #d,	

static void* optbox_set(void* obj, const char* name, ...);
static void* optbox_get(void* obj, const char* name);

//cmdline parser. 設定ミスはexit, parse失敗はqならcharを返す フツーはexit 成功で0
#define optbox_init(nm, ac_p, av_p)	\
	optbox_initsub(nm, optbox_##nm##_iniarr, optbox_##nm##_parr, optbox_##nm##_mode, ac_p, av_p)
static int optbox_initsub(void* obj, optbox_ifmt_t* iniarr, void* parr, const char* mode, int *argc, char** *argv){
	*(void**)obj=parr;	//init時に初期化すれば使用に間に合う offset0で直接代入
	//型情報が可変なのでoffsetを使ってアクセスする準備
	int ac= *argc;
	char** av= *argv;
	char* emsg=NULL;
	//inputのcharとsetのcharを結びつける hから逆引き	apos[(int)iniarr[i].optstr[1]]=i;
	//iniarrがメイン情報源でidxがhとかvとか分かるのでaidx['h'] == idx, iniarr[idx]
	//と逆引きできる
	int aidx[130];	/*95:sym33 aZ52 num10, (sp)32- 09/48-57 Az65-90/97-122 -(~)126 */
	for(int i=0;i<130;i++){aidx[i]= -1;}
	/*init setdfl*/
	for(int i=0;;i++) {
		if(iniarr[i].optstr==NULL){break;}
		OPTBOX_ERR(iniarr[i].optstr[1]=='-', "'-' cant set as optchar",exit(1) );
		OPTBOX_ERR(strstr("bool/int/dbl/str",iniarr[i].tp)==NULL
			,"type must be bool/int/dbl/str: ", fprintf(stderr, "%s\n",iniarr[i].tp);exit(1));
		if(strpbrk(mode, "x")==NULL){
			char c = iniarr[i].optstr[1];
			int rc = ( (48<=c&&c<=57) || (65<=c&&c<=90) || (97<=c&&c<=122) );
			OPTBOX_ERR(rc==0, "out of posix [0-9a-zA-Z]: ",fprintf(stderr,"%c\n",c);exit(1));
		}
		*(iniarr[i].dfl) = iniarr[i].dflstr;
		if(iniarr[i].tp[0]=='i'||iniarr[i].tp[0]=='b'){
			char* p;
			int v = (int)strtol(iniarr[i].dflstr, &p, 0);
			OPTBOX_ERR(*p!='\0', "detect badchar in dfl:"
				, fprintf(stderr,"%s\n", iniarr[i].dflstr);exit(1) );
			int* ip = iniarr[i].p;
			*ip = v;
			//memcpy(*ip, &v, sizeof(int) );
			/*可変型なのでtype警告が邪魔。memで踏み潰す*/
		}
		if(iniarr[i].tp[0]=='d'){
			char* p;
			double v = strtod(iniarr[i].dflstr, &p);
			OPTBOX_ERR(*p!='\0', "err, bad dblchar exist in dfl lit:"
				, fprintf(stderr,"%s\n", iniarr[i].dflstr);exit(1) );
			double* dp = (double*)iniarr[i].p;
			*dp = v;
			//memcpy(*dp, &v, sizeof(double) );
		}
		if(iniarr[i].tp[0]=='s'){
			const char** sp = (const char**)iniarr[i].p;
			*sp= iniarr[i].dflstr;
		}
		aidx[(int)iniarr[i].optstr[1]]=i;
	}
	/* parse cmd */
	int argind=1;	/*argv[0]: filename */
	int charpos=1;	 /*  -h .. skip '-' */
	//-vw1とか複数があるからcharposで進める
	// acは引数0で1 cmdstrがav[0], avは尻尾にNULLが固定で入ってるがacでも分かる
	while(argind<ac){
		if(av[argind][0]!='-'&&strpbrk(mode, "x")==NULL )	{break;}
		if(av[argind][0]!='-'||av[argind][1]==0)	{argind++;charpos=1;continue;}
		if(av[argind][charpos]=='\0')	{av[argind]=NULL;argind++;charpos=1;continue;}
		if(strcmp(av[argind],"--")==0)	{av[argind]=NULL;break;}

		/*optparse ... -h123 はh/1/2/3の順番で単発optか-h 123のどっちか*/
		//optargは-abcならabcが全部optの関係者でargにはならない
		int optchar=(int)av[argind][charpos];
		if(aidx[optchar]<0)	{emsg="no such opt";goto lb_OPTERR;}
		optbox_ifmt_t ini = iniarr[aidx[optchar]];

		/*tpck ... bool*/
		if(ini.tp[0]=='b'){
			//int v=1;
			int* ip = (int*)(ini.p);
			*ip = 1;
			*(ini.cmdin)="1";
			charpos++;
			goto lb_TESTFUNC;
		}
		/* i,d,s has optarg */
		charpos++;
		if(av[argind][charpos]==0){
			av[argind]=NULL;
			argind++;charpos=0;
			if(ac-1<argind){emsg="optarg not found";goto lb_OPTERR;}
		}
		if(ini.tp[0]=='i'){
			char* p;
			int v = (int)strtol(charpos+av[argind], &p, 0);
			if(*p!='\0'){emsg="detect invalid intchar";goto lb_OPTERR;}
			int* ip = (int*)(ini.p);
			*ip = v;
		}
		if(ini.tp[0]=='d'){
			char* p;
			double v = strtod(charpos+av[argind], &p);
			if(*p!='\0'){emsg="detect invalid numchar";goto lb_OPTERR;}
			double* dp = (double*)(ini.p);
			*dp = v;
		}
		if(ini.tp[0]=='s'){
			char* p = charpos+av[argind];
			const char** sp = (const char**)ini.p;
			*sp = p;
		}
		*(ini.cmdin) = charpos+av[argind];	//保存
		av[argind]=NULL;
		argind++;
		charpos=1;	//引数系は全消費
		goto lb_TESTFUNC;
//		OPTBOX_ERR(1,"fatal err. unreachable code, optbox() bug", exit(1) );
lb_TESTFUNC:;
		int rc = ini.func(*ini.cmdin);
		if(rc==0){ emsg="value test failed"; goto lb_OPTERR; }
		continue;
lb_OPTERR:;
		if(strpbrk(mode, "q") ){return optchar;}
		fprintf(stderr,"%s: %s: -%c\n", av[0], emsg, optchar);
		exit(optchar);	//戻すか終わるか微妙だけどエラーは終了が妥当だろう
	}
	// shift args
	int agpos=1;
	for(int i=1; i<ac;i++){
		if(av[i]==NULL){continue;}
		av[agpos] =av[i];
		agpos++;
	}
	av[agpos]=NULL;
	*argc=agpos;
	return 0;
	//unreachable, but needs to save nouse warning at compile
	optbox_get(NULL, NULL);
	optbox_set(NULL, NULL);
}

static void* optbox_get(void* obj, const char* name){
	char** arr = *(char***)obj;	//topmemberはchar*の配列char** >>位置取得
	for(int i=0;arr[i]!=NULL;i=i+3){
		if( name[0]!=arr[i][0]){continue;}
		if(strcmp(name, arr[i])!=0){continue;}
		return arr[i+1];
	}
	//err
	OPTBOX_ERR(1, "optname not found", fprintf(stderr, "badname: %s\n",name);exit(1) );
	//unreachable code
	return NULL;
}

static void* optbox_set(void* obj, const char* name, ...){
	char** arr = *(char***)obj;
	int c=0;
	void* p=NULL;
	for(int i=0;arr[i]!=NULL;i=i+3){
		if( name[0]!=arr[i][0]){continue;}
		if(strcmp(name, arr[i])!=0){continue;}
		c = arr[i+2][0];
		p = arr[i+1];
		break;
	}
	OPTBOX_ERR(p==NULL, "optname not found", fprintf(stderr, "badname: %s\n",name);exit(1) );
//
	va_list vl;
	va_start(vl, name);
	if(c=='i'||c=='b'){
		int i = va_arg(vl, int);
		*(int*)p = i;
	}
	else if(c=='d'){
		double d = va_arg(vl, double);
		*(double*)p = d;
	}
	else if(c=='s'){
		char* s = va_arg(vl, char*);
		*(char**)p = s;
	}
	else{
		OPTBOX_ERR(1, "unreachable code", exit(1) );
	}
	return p;
}

//95:sym33 aZ52 num10, (sp)32- 09/48-57 Az65-90/97-122 -(~)126
// from license: cc-by-sa 2.5/3.0 (code is changed from the orig)
// https://stackoverflow.com/questions/2632300	Q: Ed Marty  ->  A: Matthew Slattery
#define OPTBOX_ARGCNT(...)	OPTBOX_ARGCNT2(__VA_ARGS__,99,98,97,96,95,94,93,92,\
	91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,\
	66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,\
	41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,\
	16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1 )
#define OPTBOX_ARGCNT2(a99,a98,a97,a96,a95,a94,a93,a92,a91,a90,a89,a88,a87,a86,\
	a85,a84,a83,a82,a81,a80,a79,a78,a77,a76,a75,a74,a73,a72,a71,a70,a69,a68,a67,\
	a66,a65,a64,a63,a62,a61,a60,a59,a58,a57,a56,a55,a54,a53,a52,a51,a50,a49,a48,\
	a47,a46,a45,a44,a43,a42,a41,a40,a39,a38,a37,a36,a35,a34,a33,a32,a31,a30,a29,\
	a28,a27,a26,a25,a24,a23,a22,a21,a20,a19,a18,a17,a16,a15,a14,a13,a12,a11,a10,\
	a9,a8,a7,a6,a5,a4,a3,a2,a1,a,...)	OPTBOX_ITER_ ## a

// https://stackoverflow.com/questions/44479282 Q: user1150609 -> A: H Walters
#define OPTBOX_ITER_1(a,b,c,  ...) a(b,c)
#define OPTBOX_ITER_2(a,b,c,  ...) a(b,c) OPTBOX_ITER_1(a,b,__VA_ARGS__)
#define OPTBOX_ITER_3(a,b,c,  ...) a(b,c) OPTBOX_ITER_2(a,b,__VA_ARGS__)
#define OPTBOX_ITER_4(a,b,c,  ...) a(b,c) OPTBOX_ITER_3(a,b,__VA_ARGS__)
#define OPTBOX_ITER_5(a,b,c,  ...) a(b,c) OPTBOX_ITER_4(a,b,__VA_ARGS__)
#define OPTBOX_ITER_6(a,b,c,  ...) a(b,c) OPTBOX_ITER_5(a,b,__VA_ARGS__)
#define OPTBOX_ITER_7(a,b,c,  ...) a(b,c) OPTBOX_ITER_6(a,b,__VA_ARGS__)
#define OPTBOX_ITER_8(a,b,c,  ...) a(b,c) OPTBOX_ITER_7(a,b,__VA_ARGS__)
#define OPTBOX_ITER_9(a,b,c,  ...) a(b,c) OPTBOX_ITER_8(a,b,__VA_ARGS__)
#define OPTBOX_ITER_10(a,b,c, ...) a(b,c) OPTBOX_ITER_9(a,b,__VA_ARGS__)
#define OPTBOX_ITER_11(a,b,c, ...) a(b,c) OPTBOX_ITER_10(a,b,__VA_ARGS__)
#define OPTBOX_ITER_12(a,b,c, ...) a(b,c) OPTBOX_ITER_11(a,b,__VA_ARGS__)
#define OPTBOX_ITER_13(a,b,c, ...) a(b,c) OPTBOX_ITER_12(a,b,__VA_ARGS__)
#define OPTBOX_ITER_14(a,b,c, ...) a(b,c) OPTBOX_ITER_13(a,b,__VA_ARGS__)
#define OPTBOX_ITER_15(a,b,c, ...) a(b,c) OPTBOX_ITER_14(a,b,__VA_ARGS__)
#define OPTBOX_ITER_16(a,b,c, ...) a(b,c) OPTBOX_ITER_15(a,b,__VA_ARGS__)
#define OPTBOX_ITER_17(a,b,c, ...) a(b,c) OPTBOX_ITER_16(a,b,__VA_ARGS__)
#define OPTBOX_ITER_18(a,b,c, ...) a(b,c) OPTBOX_ITER_17(a,b,__VA_ARGS__)
#define OPTBOX_ITER_19(a,b,c, ...) a(b,c) OPTBOX_ITER_18(a,b,__VA_ARGS__)
#define OPTBOX_ITER_20(a,b,c, ...) a(b,c) OPTBOX_ITER_19(a,b,__VA_ARGS__)
#define OPTBOX_ITER_21(a,b,c, ...) a(b,c) OPTBOX_ITER_20(a,b,__VA_ARGS__)
#define OPTBOX_ITER_22(a,b,c, ...) a(b,c) OPTBOX_ITER_21(a,b,__VA_ARGS__)
#define OPTBOX_ITER_23(a,b,c, ...) a(b,c) OPTBOX_ITER_22(a,b,__VA_ARGS__)
#define OPTBOX_ITER_24(a,b,c, ...) a(b,c) OPTBOX_ITER_23(a,b,__VA_ARGS__)
#define OPTBOX_ITER_25(a,b,c, ...) a(b,c) OPTBOX_ITER_24(a,b,__VA_ARGS__)
#define OPTBOX_ITER_26(a,b,c, ...) a(b,c) OPTBOX_ITER_25(a,b,__VA_ARGS__)
#define OPTBOX_ITER_27(a,b,c, ...) a(b,c) OPTBOX_ITER_26(a,b,__VA_ARGS__)
#define OPTBOX_ITER_28(a,b,c, ...) a(b,c) OPTBOX_ITER_27(a,b,__VA_ARGS__)
#define OPTBOX_ITER_29(a,b,c, ...) a(b,c) OPTBOX_ITER_28(a,b,__VA_ARGS__)
#define OPTBOX_ITER_30(a,b,c, ...) a(b,c) OPTBOX_ITER_29(a,b,__VA_ARGS__)
#define OPTBOX_ITER_31(a,b,c, ...) a(b,c) OPTBOX_ITER_30(a,b,__VA_ARGS__)
#define OPTBOX_ITER_32(a,b,c, ...) a(b,c) OPTBOX_ITER_31(a,b,__VA_ARGS__)
#define OPTBOX_ITER_33(a,b,c, ...) a(b,c) OPTBOX_ITER_32(a,b,__VA_ARGS__)
#define OPTBOX_ITER_34(a,b,c, ...) a(b,c) OPTBOX_ITER_33(a,b,__VA_ARGS__)
#define OPTBOX_ITER_35(a,b,c, ...) a(b,c) OPTBOX_ITER_34(a,b,__VA_ARGS__)
#define OPTBOX_ITER_36(a,b,c, ...) a(b,c) OPTBOX_ITER_35(a,b,__VA_ARGS__)
#define OPTBOX_ITER_37(a,b,c, ...) a(b,c) OPTBOX_ITER_36(a,b,__VA_ARGS__)
#define OPTBOX_ITER_38(a,b,c, ...) a(b,c) OPTBOX_ITER_37(a,b,__VA_ARGS__)
#define OPTBOX_ITER_39(a,b,c, ...) a(b,c) OPTBOX_ITER_38(a,b,__VA_ARGS__)
#define OPTBOX_ITER_40(a,b,c, ...) a(b,c) OPTBOX_ITER_39(a,b,__VA_ARGS__)
#define OPTBOX_ITER_41(a,b,c, ...) a(b,c) OPTBOX_ITER_40(a,b,__VA_ARGS__)
#define OPTBOX_ITER_42(a,b,c, ...) a(b,c) OPTBOX_ITER_41(a,b,__VA_ARGS__)
#define OPTBOX_ITER_43(a,b,c, ...) a(b,c) OPTBOX_ITER_42(a,b,__VA_ARGS__)
#define OPTBOX_ITER_44(a,b,c, ...) a(b,c) OPTBOX_ITER_43(a,b,__VA_ARGS__)
#define OPTBOX_ITER_45(a,b,c, ...) a(b,c) OPTBOX_ITER_44(a,b,__VA_ARGS__)
#define OPTBOX_ITER_46(a,b,c, ...) a(b,c) OPTBOX_ITER_45(a,b,__VA_ARGS__)
#define OPTBOX_ITER_47(a,b,c, ...) a(b,c) OPTBOX_ITER_46(a,b,__VA_ARGS__)
#define OPTBOX_ITER_48(a,b,c, ...) a(b,c) OPTBOX_ITER_47(a,b,__VA_ARGS__)
#define OPTBOX_ITER_49(a,b,c, ...) a(b,c) OPTBOX_ITER_48(a,b,__VA_ARGS__)
#define OPTBOX_ITER_50(a,b,c, ...) a(b,c) OPTBOX_ITER_49(a,b,__VA_ARGS__)
#define OPTBOX_ITER_51(a,b,c, ...) a(b,c) OPTBOX_ITER_50(a,b,__VA_ARGS__)
#define OPTBOX_ITER_52(a,b,c, ...) a(b,c) OPTBOX_ITER_51(a,b,__VA_ARGS__)
#define OPTBOX_ITER_53(a,b,c, ...) a(b,c) OPTBOX_ITER_52(a,b,__VA_ARGS__)
#define OPTBOX_ITER_54(a,b,c, ...) a(b,c) OPTBOX_ITER_53(a,b,__VA_ARGS__)
#define OPTBOX_ITER_55(a,b,c, ...) a(b,c) OPTBOX_ITER_54(a,b,__VA_ARGS__)
#define OPTBOX_ITER_56(a,b,c, ...) a(b,c) OPTBOX_ITER_55(a,b,__VA_ARGS__)
#define OPTBOX_ITER_57(a,b,c, ...) a(b,c) OPTBOX_ITER_56(a,b,__VA_ARGS__)
#define OPTBOX_ITER_58(a,b,c, ...) a(b,c) OPTBOX_ITER_57(a,b,__VA_ARGS__)
#define OPTBOX_ITER_59(a,b,c, ...) a(b,c) OPTBOX_ITER_58(a,b,__VA_ARGS__)
#define OPTBOX_ITER_60(a,b,c, ...) a(b,c) OPTBOX_ITER_59(a,b,__VA_ARGS__)
#define OPTBOX_ITER_61(a,b,c, ...) a(b,c) OPTBOX_ITER_60(a,b,__VA_ARGS__)
#define OPTBOX_ITER_62(a,b,c, ...) a(b,c) OPTBOX_ITER_61(a,b,__VA_ARGS__)
#define OPTBOX_ITER_63(a,b,c, ...) a(b,c) OPTBOX_ITER_62(a,b,__VA_ARGS__)
#define OPTBOX_ITER_64(a,b,c, ...) a(b,c) OPTBOX_ITER_63(a,b,__VA_ARGS__)
#define OPTBOX_ITER_65(a,b,c, ...) a(b,c) OPTBOX_ITER_64(a,b,__VA_ARGS__)
#define OPTBOX_ITER_66(a,b,c, ...) a(b,c) OPTBOX_ITER_65(a,b,__VA_ARGS__)
#define OPTBOX_ITER_67(a,b,c, ...) a(b,c) OPTBOX_ITER_66(a,b,__VA_ARGS__)
#define OPTBOX_ITER_68(a,b,c, ...) a(b,c) OPTBOX_ITER_67(a,b,__VA_ARGS__)
#define OPTBOX_ITER_69(a,b,c, ...) a(b,c) OPTBOX_ITER_68(a,b,__VA_ARGS__)
#define OPTBOX_ITER_70(a,b,c, ...) a(b,c) OPTBOX_ITER_69(a,b,__VA_ARGS__)
#define OPTBOX_ITER_71(a,b,c, ...) a(b,c) OPTBOX_ITER_70(a,b,__VA_ARGS__)
#define OPTBOX_ITER_72(a,b,c, ...) a(b,c) OPTBOX_ITER_71(a,b,__VA_ARGS__)
#define OPTBOX_ITER_73(a,b,c, ...) a(b,c) OPTBOX_ITER_72(a,b,__VA_ARGS__)
#define OPTBOX_ITER_74(a,b,c, ...) a(b,c) OPTBOX_ITER_73(a,b,__VA_ARGS__)
#define OPTBOX_ITER_75(a,b,c, ...) a(b,c) OPTBOX_ITER_74(a,b,__VA_ARGS__)
#define OPTBOX_ITER_76(a,b,c, ...) a(b,c) OPTBOX_ITER_75(a,b,__VA_ARGS__)
#define OPTBOX_ITER_77(a,b,c, ...) a(b,c) OPTBOX_ITER_76(a,b,__VA_ARGS__)
#define OPTBOX_ITER_78(a,b,c, ...) a(b,c) OPTBOX_ITER_77(a,b,__VA_ARGS__)
#define OPTBOX_ITER_79(a,b,c, ...) a(b,c) OPTBOX_ITER_78(a,b,__VA_ARGS__)
#define OPTBOX_ITER_80(a,b,c, ...) a(b,c) OPTBOX_ITER_79(a,b,__VA_ARGS__)
#define OPTBOX_ITER_81(a,b,c, ...) a(b,c) OPTBOX_ITER_80(a,b,__VA_ARGS__)
#define OPTBOX_ITER_82(a,b,c, ...) a(b,c) OPTBOX_ITER_81(a,b,__VA_ARGS__)
#define OPTBOX_ITER_83(a,b,c, ...) a(b,c) OPTBOX_ITER_82(a,b,__VA_ARGS__)
#define OPTBOX_ITER_84(a,b,c, ...) a(b,c) OPTBOX_ITER_83(a,b,__VA_ARGS__)
#define OPTBOX_ITER_85(a,b,c, ...) a(b,c) OPTBOX_ITER_84(a,b,__VA_ARGS__)
#define OPTBOX_ITER_86(a,b,c, ...) a(b,c) OPTBOX_ITER_85(a,b,__VA_ARGS__)
#define OPTBOX_ITER_87(a,b,c, ...) a(b,c) OPTBOX_ITER_86(a,b,__VA_ARGS__)
#define OPTBOX_ITER_88(a,b,c, ...) a(b,c) OPTBOX_ITER_87(a,b,__VA_ARGS__)
#define OPTBOX_ITER_89(a,b,c, ...) a(b,c) OPTBOX_ITER_88(a,b,__VA_ARGS__)
#define OPTBOX_ITER_90(a,b,c, ...) a(b,c) OPTBOX_ITER_89(a,b,__VA_ARGS__)
#define OPTBOX_ITER_91(a,b,c, ...) a(b,c) OPTBOX_ITER_90(a,b,__VA_ARGS__)
#define OPTBOX_ITER_92(a,b,c, ...) a(b,c) OPTBOX_ITER_91(a,b,__VA_ARGS__)
#define OPTBOX_ITER_93(a,b,c, ...) a(b,c) OPTBOX_ITER_92(a,b,__VA_ARGS__)
#define OPTBOX_ITER_94(a,b,c, ...) a(b,c) OPTBOX_ITER_93(a,b,__VA_ARGS__)
#define OPTBOX_ITER_95(a,b,c, ...) a(b,c) OPTBOX_ITER_94(a,b,__VA_ARGS__)
#define OPTBOX_ITER_96(a,b,c, ...) a(b,c) OPTBOX_ITER_95(a,b,__VA_ARGS__)
#define OPTBOX_ITER_97(a,b,c, ...) a(b,c) OPTBOX_ITER_96(a,b,__VA_ARGS__)
#define OPTBOX_ITER_98(a,b,c, ...) a(b,c) OPTBOX_ITER_97(a,b,__VA_ARGS__)
#define OPTBOX_ITER_99(a,b,c, ...) a(b,c) OPTBOX_ITER_98(a,b,__VA_ARGS__)
// end license:	cc-by-sa 2.5/3.0

#endif //a18d0ac31a24b
