#include <emsg: see ... '~$ sh aaa.sh.c -h'   (other opt:no/-m/-w/)>	/*
C='^[/][/*]SH_'     ;O=${0##*[/]};R=`dirname $0`;R=${R%/}/;R0=$R$O;R=$R${O%%.*}
O=${0##*.};Rs=$R.$O;Rm=$R.tmp.$O;Rh=$R.h;R=$Rs$Rh$Rm;Rp='printf %s\n ';Rc=:;O="
";[ "${R##*$R0*}" = '' ]&&$Rp"$0:NGsuffix"&&exit 1;R='sed -ne ';Cm=$R'"/[E]ND/!d
:l;n;p;bl"<$R0>$Rm;$Rp"$Rm"';RB=$($R"s/${C}OP//p"<$R0|(F=mw;while read -r a b;do
B=${a%:};F=`$Rp"$F"|$R"s#$B:*##1;p"`${a%_};$Rp"C$B=\$(cat<<'E'$O$b${O}E$O)";done
$Rp"R1=$F"));Rw=$R'"/$C$R/!d;:l;n;/${C}ED/q;p;bl"<$R0';Cw="(R=LS;$Rw;$Rw>&3;R=HD
$Rw;R=SC;$Rw>&3)"'>$Rh 3>$Rs;$Rp"$Rh $Rs"';Re=eval\ ;$Re"$RB";while getopts $R1\
 R;do case $R in \?)exit 1;;*)$Re"O$R=\$OPTARG";Rc=$Rc$O`$Re'$Rp"$C'$R\"`;;esac
done;[ "$Rc" = : ]&&Rc=$Cm;shift $((OPTIND-1));$Re"$C_$O$Rc";exit   #END GPL3+*/

//SH_LS
/*	GPL3+	*/
/* Copyright (C) 2019 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/>.
 */

/*-*
@name	dq
@auther momi-g
@brief	auto growing array
@synopsys
	// dflfuncs idq/ddq/pdq corresponds to int/double/void* payload   
	#include "dq.h"

	dq_t* idq_new(void)
	void idq_free(dq_t* dq)
	void idq_frees(dq_t* dq)
	
	void idq_push(dq_t* dq, int i)		// void pdq_push(dq_t* dq, void* p)
	int idq_pop(dq_t* dq)				// double ddq_pop(dq_t* dq)
	void idq_lift(dq_t* dq, int i)
	int idq_drop(dq_t* dq)

	int idq_popn(dq_t* dq, int cnt)
	int idq_dropn(dq_t* dq, int cnt)
	void idq_reset(dq_t* dq)
	
	int idq_rep(dq_t* dq, int idx, int i)
	int idq_see(dq_t* dq, int idx)
	int* idq_2arr(dq_t* dq)
	
	// custom macros
	#define DQ_CMN		deq		// >> ideq_new()
	DQ_IMPL([scope], [type], [pfix])	// DQ_IMPL(static, int32_t, i32)
	DQ_VOIDCALL()	// stop compile nouse warning

@eg
 // lift >>                              << push
 //         | head[0] | ... | tail[-1] |
 // drop <<                              >> pop
 
 #include "dq.h"
 int main(int argc, char** argv) {
 	int v;
 	dq_t* q=idq_new();	//		|NULL|
 
 	idq_push(q,11);		//		| 11 |
 	idq_push(q,22);		//		| 11 | 22 |
 	idq_push(q,33);		//		| 11 | 22 | 33 |
 	v = idq_pop(q);		//		| 11 | 22 |		>> v=33
 
 	idq_lift(q,10);		//		| 10 | 11 | 22 |
 	idq_lift(q,20);		//		| 20 | 10 | 11 | 22 |
 	v = idq_drop(q);	//		| 10 | 11 | 22 |	>> v=20
 
 	v = idq_see(q,0);	//		| 10 | 11 | 22 |	>> v=10
 	v = idq_see(q,-1);	//		| 10 | 11 | 22 |	>> v=22 (-1: tail)
 	v = idq_len(q);		//		| 10 | 11 | 22 |	>> v=3

 	idq_dropn(q,2);		//		| 22 |		>> drop x2
//	idq_popn(q,2);		//		| 10 |		>> pop x2
//	idq_reset(q);		//		|NULL|		>> clear all
//	idq_dropn(q,-1);	//		|NULL|		>> same as above
 	v = idq_len(q);		//		| 22 |		>> v=1
 	
// conv to arr
	int* arr = idq_2arr(q);	//	dup payload. 
 	dq_free(q);		// arr[0] == 22, duped.
	free(arr);		// needs free() same as c99 strdup()
 
// works only pdq func, 'pdq_frees()'
 	dq_t* dq = pdq_new();
 	void* p = malloc(32);
 	pdq_push(dq, p);
 	pdq_frees(dq);	//... free() payload and destroy dq.
 	// free(p);		...no need.
 	
// use voidcall if you detect unused warning at compile
	// DQ_VOIDCALL();
	return 0;
 }
 // ~$ gcc src.c dq.c

@param dq	arr/deque obj. holds memsz, idxdata, arrlen etc.
@param idx	tgt index. start with 0 and tail is -1. allows, -2, -3 etc.
@param cnt	popn/dropn takes cnt. cnt== -1 works as dq_reset().
@return	?	val/len etc. rtntype depends on new() type. popn/dropn rtns lastone.
@details
 - other type payload
	dflapi is only idq/ddq/pdq. you can use DQ_IMPL() macro for your own types.
		#include "dq.h"

		typedef struct my_tag{int a, int b} my_t;
		DQ_IMPL(static, my_t, zz)
		//	...>> expand macro
		//	static dq_t* zzdq_new(void){ ..code.. }
		//	static void zzdq_push(dq_t* dq, my_t v){..code..}
		//	static my_t* zzdq_2arr(dq_t* dq){ ..code.. }
		//.. new/push/pop(n)/lift/drop(n)/len/see/rep/reset/2arr/free
		dq_t* q = zzdq_new();
		my_t v = {1,2};
		zzdq_push(q, v);
		...

 - use no prefix api 'dq_XXX()'
	dflname 'dq_XXX' is undefined. you can set dfl apiname as follows. 
		#include "dq.h"
		DQ_IMPL(static, void*, )		// 3rd arg is blank

	 	dq_t* q=pdq_new();
		dq_t* Q= dq_new();	// use dq_new() as pdq_new()

 - rename 'dq' word	
	dq() uses cmnname 'dq' in func and type, idq_new()/dq_t.
	you can change word if set macro 'DQ_CMN' before includes dq.h 
	
		#define DQ_CMN	stack
		#include "dq.h"
		...
		stack_t* stk = istack_new();		// dq_t* stk = idq_new();	...dfl
		istack_push(stk, 10);
		...
	--
		#define DQ_CMN	stk
		#include "dq.h"
		typedef struct my_tag{int a; int b;} my_t;
		DQ_IMPL(static, int, )
		DQ_IMPL(static, my_t, m)
		
		int main(int argc, char** argv){
			stk_t* stk = stk_new();
			stk_push(stk, 10);
			stk_free(stk);
		
			mstk_t* obj = mstk_new();
			mstk_push(obj, (my_t){11,22} );		// (my_t)..compound lit, c99+
			mstk_free(obj);
			return 0;
		}

 - stop compile warning
	compile warning 'unused' will raise if you doesnt use idq()/ddq()/pdq().
	you can stop warning by calling DQ_VOIDCALL(). 

		#include "dq.h"
		int main(int argc, char** argv){
			DQ_VOIDCALL();
			return 0;
		}

	..DQ_VOIDCALL() do nothing. funcs are described in the unreachable block.

@_note
	-- sloppy speedtest( -O0)
	 - read/write
	arr[2]	:	36-41 ms
	dq_rep():	560-600 ms	(15-20 times slow, -O2:250ms, -O2+inline: 190ms)
	dq_2arr():	38-41 ms
	 - write
	arr[2]	:	48-50 ms
	dq_push():	300-350 ms	(6-8 times slow)
	
	 ..overhead src: idx funccall / idx calc+errck
	 ..'inline' will not be needed in generally
	
	-- test code
	int sz= 10 * 1000*1000;
	 - read/write
	for(int i=0; i<sz;i++){ arr[0]=arr[1]+1;}	//36-41ms
	for(int i=0; i<sz;i++){ idq_rep(dq, -1, idq_see(dq,0)+1);}	//370-390ms
	for(int i=0; i<sz;i++){ d2arr[1]=d2arr[0]+1; }	//38-41ms
	
	 - write
	for(i=0; i<sz-1;i++){ arr[0]=i%10;}	//48-50ms
	for(i=0; i<sz-1;i++){ idq_push(dq, i%10); }	//300-350ms

	- inline
	DQ_IMPL(static inline, int, ii)
	for(int i=0; i<sz;i++){ iidq_rep(dq, -1, iidq_see(dq,0)+1);}	//190ms
	
@conforming c89+
@version 2021-07-10 v1.1.2
-*/
/*SH_ED*/

/*SH_HD*/
#ifndef dq_3a298c227c3b
#define dq_3a298c227c3b	dq_3a298c227c3b
/*
- support auto realloc() deque
- support any size() payload, int/double/my_t etc
- support rename apifunc,	dfl: dq_new()	>>	custom: dqmy_new() 
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
/* #include "msgp.h" //*/

/* config */
#define DQ_BNAME	dq_3a298c227c3b
#define DQ_DFLLEN	32

#ifndef DQ_CMN
	#define DQ_CMN	dq
#endif

/* tools */
#define DQ_SCAT2(a,b)	DQ_SCAT2sub(a,b)
#define DQ_SCAT2sub(a,b)	a ## b

#define DQ_SCAT3	DQ_SCAT
#define DQ_SCAT(a,b,c)	DQ_SCATsub(a,b,c)
#define DQ_SCATsub(a,b,c)	a ## b ## c
#define DQ_BTYPE	DQ_SCAT2(DQ_BNAME,_t)
#define DQ_MTYPE	DQ_SCAT2(DQ_CMN,_t)
#define DQ_MTYPEDEF(mytype)	typedef DQ_BTYPE mytype;
#define DQ_CMT(a)

#if  (199901L <= __STDC_VERSION__ +0)  /* nealy 200112L, _POSIX_C_SOURCE	c99*/
#define DQ_PANIC(xpr, msg, act)	do{if(xpr){ fprintf(stderr, \
				"ERR: %s %d: %s():%s msg:%s sys:%s\n",__FILE__,__LINE__, __func__, \
				"hit(" #xpr ")", msg, strerror(errno) );act;} }while(0)
#else
#define DQ_PANIC(xpr, msg, act)	do{if(xpr){ fprintf(stderr, \
				"ERR: %s %d: %s():%s msg:%s sys:%s\n",__FILE__,__LINE__, "func:c99+", \
				"hit(" #xpr ")", msg, strerror(errno) );act;} }while(0)
#endif

/* main macro */
/* static dq_t* idq_new(void){...} etc */
#define DQ_IMPL(sc,tp,tpc)	DQ_IMPLsub(sc,tp,tpc,DQ_DFLLEN,DQ_CMN,DQ_MTYPE,DQ_BNAME,DQ_BTYPE)
#define DQ_IMPLsub(SCOPE, TP, TPC, DFLLEN, PFIX, MTYPE, BNAME, BTYPE)		\
static void DQ_SCAT(TPC,PFIX,BNAME)(void);									\
SCOPE MTYPE* DQ_SCAT(TPC,PFIX,_new)(void) {            			  			\
	MTYPE* rtn;																\
	int tpsz;  																\
	int memsz; 																\
	void* buf; 																\
	rtn=(MTYPE*)calloc(sizeof(MTYPE), 1);                        			\
	DQ_PANIC(rtn==NULL, "calloc() failed.", return NULL);    				\
	tpsz=sizeof(TP);                                                		\
	memsz=	DFLLEN *tpsz;              	    	                    		\
	buf= (void*)malloc( memsz );                                   			\
	DQ_PANIC(buf==NULL, "malloc() failed.", return NULL);	  				\
	memset(buf, '\0', memsz);                                           	\
																			\
	rtn->arr= buf;                                                       	\
	rtn->tp=	#TPC;                                                      	\
	rtn->tpsz= tpsz;                                                     	\
	rtn->sidx= DFLLEN-1;                                                   	\
	rtn->eidx= 0;                                                       	\
	rtn->len= 0;                                                         	\
	rtn->mlen= DFLLEN;	                                                	\
	return rtn;                                                         	\
	DQ_SCAT(TPC,PFIX,BNAME)();												\
}                                                                       	\
SCOPE void DQ_SCAT(TPC,PFIX,_push)(MTYPE* dq, TP v) {                   	\
	TP* arr;				                                             	\
	DQ_PANIC(!dq, "dq obj is NULL", exit(1); );	    						\
	if(dq->len >= dq->mlen) { DQ_SCAT2(BNAME,_extend)(dq); }            	\
	arr = (TP*)dq->arr; 	                                            	\
	arr[dq->eidx] = v;							                           	\
	dq->eidx++;                                                             \
	dq->len++;                                                              \
	if(dq->eidx==dq->mlen){dq->eidx=0;}                                     \
}                                                                       	\
SCOPE void DQ_SCAT(TPC,PFIX,_lift)(MTYPE* dq, TP v) {                   	\
	TP* arr;				                                             	\
	DQ_PANIC(!dq, "dq obj is NULL", exit(1); );	    						\
	if(dq->len >= dq->mlen) { DQ_SCAT2(BNAME,_extend)(dq); }   		    	\
	arr = (TP*)dq->arr;                                                 	\
	arr[dq->sidx] = v;							                           	\
    dq->sidx--;                                   						 	\
	dq->len++;                                                          	\
	if(dq->sidx<0){dq->sidx = dq->mlen-1;}                      			\
}                                                                       	\
SCOPE TP DQ_SCAT(TPC,PFIX,_popn)(MTYPE* dq, int cnt) {                   	\
	TP* arr;				                                             	\
	DQ_PANIC(!dq, "dq obj is NULL", exit(1); );	    						\
	arr = (TP*)dq->arr;                                             		\
	if(cnt== 1){                                                            \
		DQ_PANIC(dq->len==0, "dq_len()==0, tgt stack is empty", exit(1) );	\
		dq->eidx--;                                                         \
		dq->len--;															\
		if(dq->eidx<0){dq->eidx=dq->mlen-1;}                                \
	}                                                                       \
	else if(cnt<0){		                                                    \
		dq->eidx = dq->sidx+1;                                           	\
		dq->len=0;															\
		if(dq->eidx>=dq->mlen){dq->eidx=0;}                               	\
	}                                                                       \
	else {                                                                  \
		DQ_PANIC(dq->len<cnt, "popcnt is too large", exit(1) );				\
		dq->eidx -= cnt;                                                    \
		dq->len -= cnt;                                                     \
		if(dq->eidx<0){dq->eidx+=dq->mlen;}                               	\
	}                                                                       \
	return arr[dq->eidx];                                                  	\
}                                                                       	\
SCOPE TP DQ_SCAT(TPC,PFIX,_pop)(MTYPE* dq) {                                \
	return DQ_SCAT(TPC,PFIX,_popn)(dq, 1); 		                            \
}                    	                                                    \
SCOPE TP DQ_SCAT(TPC,PFIX,_reset)(MTYPE* dq) {                              \
	return DQ_SCAT(TPC,PFIX,_popn)(dq, -1);                                 \
}                    	                                                    \
SCOPE TP DQ_SCAT(TPC,PFIX,_dropn)(MTYPE* dq, int cnt) {	                   	\
	TP* arr;				                                             	\
	DQ_PANIC(!dq, "dq obj is NULL", exit(1); );	    						\
	arr = (TP*)dq->arr;                                             		\
	if(cnt== 1){                                                            \
		DQ_PANIC(dq->len==0, "dq_len()==0, tgt stack is empty", exit(1) );	\
		dq->sidx++;                                                         \
		dq->len--;															\
		if(dq->sidx>=dq->mlen){dq->sidx=0;}                                 \
	}                                                                       \
	else if(cnt<0){		                                                    \
		dq->sidx = dq->eidx-1;                                           	\
		dq->len=0;															\
		if(dq->sidx<0){dq->sidx+=dq->mlen;}                               	\
	}                                                                       \
	else {                                                                  \
		DQ_PANIC(dq->len<cnt, "dropcnt is too large", exit(1) );			\
		dq->sidx += cnt;                                                    \
		dq->len -= cnt;                                                     \
		if(dq->sidx>=dq->mlen){dq->sidx-=dq->mlen;}                        	\
	}                                                                       \
	return arr[dq->sidx];                                                  	\
}        	                                                             	\
SCOPE TP DQ_SCAT(TPC,PFIX,_drop)(MTYPE* dq) {                               \
	return DQ_SCAT(TPC,PFIX,_dropn)(dq, 1);                                 \
}                    	                                                    \
SCOPE void DQ_SCAT(TPC,PFIX,_rep)(MTYPE* dq, int idx, TP v) {	           	\
	TP* arr;				                                             	\
	DQ_PANIC(!dq, "dq obj is NULL", exit(1); );	    						\
	arr = (TP*)dq->arr;                                             		\
	arr[DQ_SCAT2(BNAME,_getidx)(dq, idx)] = v;                              \
}                                                                       	\
SCOPE TP DQ_SCAT(TPC,PFIX,_see)(MTYPE* dq, int idx) {                    	\
	TP* arr;				                                             	\
	DQ_PANIC(!dq, "dq obj is NULL", exit(1); );	    						\
	arr = (TP*)dq->arr;		                                           		\
	return arr[DQ_SCAT2(BNAME,_getidx)(dq, idx)];                  			\
}                                                                       	\
SCOPE TP* DQ_SCAT(TPC,PFIX,_2arr)(MTYPE* dq) {		                     	\
	TP* arr;				                                             	\
	TP* p;					                                             	\
	int sidx, eidx;                                                         \
	DQ_PANIC(!dq, "dq obj is NULL", exit(1); );	    						\
	if(dq->len==0){return NULL;}                                            \
	arr = (TP*)dq->arr;		                                           		\
	p = (TP*)calloc(dq->len, dq->tpsz);                              		\
	sidx = dq->sidx+1;      	                                            \
	eidx = dq->eidx-1;		                                                \
	if(sidx>=dq->mlen){sidx= 0;}                                            \
	if(eidx<0){eidx= dq->mlen-1;}                                           \
	if(sidx<eidx||dq->len==1){ memcpy(p,&(arr[sidx]), dq->len*dq->tpsz); }	\
	else{                                                                   \
		memcpy( p, &(arr[sidx]), (dq->mlen-sidx)*dq->tpsz);					\
		memcpy( &(p[dq->mlen-sidx]), arr, (eidx+1)*dq->tpsz);               \
	}			  								                            \
	return p;                                                               \
}		                                                                    \
SCOPE size_t DQ_SCAT(TPC,PFIX,_len)(MTYPE* dq){return DQ_SCAT2(BNAME,_len)(dq);}	\
SCOPE void DQ_SCAT(TPC,PFIX,_free)(MTYPE* dq){DQ_SCAT2(BNAME,_free)(dq);}			\
SCOPE void DQ_SCAT(TPC,PFIX,_frees)(MTYPE* dq){DQ_SCAT2(BNAME,_frees)(dq);}			\
static void DQ_SCAT(TPC,PFIX,BNAME)(void){				\
MTYPE* dmy; TP obj;		return;                        	\
DQ_SCAT(TPC,PFIX,_new)();	                            \
DQ_SCAT(TPC,PFIX,_push)		(dmy, obj);	                \
DQ_SCAT(TPC,PFIX,_lift)		(dmy, obj);                 \
DQ_SCAT(TPC,PFIX,_pop)		(dmy);                      \
DQ_SCAT(TPC,PFIX,_popn)		(dmy, 0);                   \
DQ_SCAT(TPC,PFIX,_drop)		(dmy);                      \
DQ_SCAT(TPC,PFIX,_dropn)	(dmy, 0);                   \
DQ_SCAT(TPC,PFIX,_reset)	(dmy); 	                    \
DQ_SCAT(TPC,PFIX,_rep)		(dmy, 0, obj);              \
DQ_SCAT(TPC,PFIX,_see)		(dmy, 0);                   \
DQ_SCAT(TPC,PFIX,_2arr)		(dmy);                      \
DQ_SCAT(TPC,PFIX,_len)		(dmy);                      \
DQ_SCAT(TPC,PFIX,_free)		(dmy);                      \
DQ_SCAT(TPC,PFIX,_frees)	(dmy);                      \
}	\
/*tail_IMPL*/

/* dfl global funcs, TPC+BNAME+_push(BTYPE*, TP) == idqbasic_push(dq_t*, int) */
/* len/free uses raw basicname */
#define DQ_PROTOBASE(TP, TPC)		\
DQ_BTYPE* DQ_SCAT(TPC,DQ_BNAME,_new)(void);	                	\
void	DQ_SCAT(TPC,DQ_BNAME,	_push	)	(DQ_BTYPE*,		TP	);	  	\
void	DQ_SCAT(TPC,DQ_BNAME,	_lift	)	(DQ_BTYPE*,		TP	);	  	\
TP		DQ_SCAT(TPC,DQ_BNAME,	_pop	)	(DQ_BTYPE*			);		\
TP		DQ_SCAT(TPC,DQ_BNAME,	_popn	)	(DQ_BTYPE*,	int		);		\
TP		DQ_SCAT(TPC,DQ_BNAME,	_drop	)	(DQ_BTYPE*			);		\
TP		DQ_SCAT(TPC,DQ_BNAME,	_dropn	)	(DQ_BTYPE*, int		);		\
TP		DQ_SCAT(TPC,DQ_BNAME,	_reset	)	(DQ_BTYPE*			);		\
void	DQ_SCAT(TPC,DQ_BNAME,	_rep	)	(DQ_BTYPE*,	int,TP	);   	\
TP		DQ_SCAT(TPC,DQ_BNAME,	_see	)	(DQ_BTYPE*,	int		);   	\
TP*		DQ_SCAT(TPC,DQ_BNAME,	_2arr	)	(DQ_BTYPE*			);   	\
/*tail_PROTOBASE*/


/* LINK,sub,VOID: make VOIDCALL(). call i/d/p funcs from yoursrc to stop warn */
/* DQ_LINKBASE() >>
	static idq_new(){return idqbase_new(); }
	static idq_push(){return idqbase_push(); }
	// static izz_push(){return ddqbase_push();  }	//if DQ_CMN==zz
	...
	void voidcall(){ return;
		idq_new();
		//izz_new();
		...
	}
*/
#define DQ_VOIDCALL	DQ_CMT(*** write DQ_VOIDCALL(); to yoursrc.c to del warning ***) DQ_SCAT(_voidcall, _unused_warn_stopper_, DQ_BNAME)
#define DQ_LINKBASE(dmy)					\
	DQ_LINKBASEsub(int, i, DQ_CMN)			\
	DQ_LINKBASEsub(double, d, DQ_CMN)		\
	DQ_LINKBASEsub(void*, p, DQ_CMN)		\
static void DQ_VOIDCALL(void){ return;		\
	DQ_SCAT(i,dmycall,DQ_BNAME)();			\
	DQ_SCAT(d,dmycall,DQ_BNAME)();			\
	DQ_SCAT(p,dmycall,DQ_BNAME)();			\
}	\
/*tail_LINKBASE*/

#define DQ_LINKBASEsub(TP, TPC, PFIX)		\
static void DQ_SCAT(TPC,dmycall,DQ_BNAME)(void);	\
static DQ_MTYPE* DQ_SCAT(TPC,PFIX,_new)		(void)						{return DQ_SCAT(TPC,DQ_BNAME,_new		)	();DQ_SCAT(TPC,dmycall,DQ_BNAME)();} \
static void		DQ_SCAT(TPC,PFIX,_push)		(DQ_MTYPE* a,	TP b)		{/**/		DQ_SCAT(TPC,DQ_BNAME,_push		)	(a,b)	;} \
static void		DQ_SCAT(TPC,PFIX,_lift)		(DQ_MTYPE* a,	TP b)		{/**/	DQ_SCAT(TPC,DQ_BNAME,_lift		)	(a,b)	;} \
static TP		DQ_SCAT(TPC,PFIX,_pop)		(DQ_MTYPE* a		)		{return DQ_SCAT(TPC,DQ_BNAME,_popn		)	(a,1)	;} \
static TP		DQ_SCAT(TPC,PFIX,_popn)		(DQ_MTYPE* a, int b )		{return DQ_SCAT(TPC,DQ_BNAME,_popn		)	(a,b)	;} \
static TP		DQ_SCAT(TPC,PFIX,_drop)		(DQ_MTYPE* a		)		{return DQ_SCAT(TPC,DQ_BNAME,_dropn		)	(a,1)	;} \
static TP		DQ_SCAT(TPC,PFIX,_dropn)	(DQ_MTYPE* a, int b )		{return DQ_SCAT(TPC,DQ_BNAME,_dropn		)	(a,b)	;} \
static TP		DQ_SCAT(TPC,PFIX,_reset)	(DQ_MTYPE* a		)		{return DQ_SCAT(TPC,DQ_BNAME,_popn		)	(a,-1)	;} \
static void		DQ_SCAT(TPC,PFIX,_rep)		(DQ_MTYPE* a,int b,TP c)	{/**/	DQ_SCAT(TPC,DQ_BNAME,_rep		)	(a,b,c)	;} \
static TP		DQ_SCAT(TPC,PFIX,_see)		(DQ_MTYPE* a, int b	)		{return DQ_SCAT(TPC,DQ_BNAME,_see		)	(a,b)	;} \
static TP*		DQ_SCAT(TPC,PFIX,_2arr)		(DQ_MTYPE* a		)		{return DQ_SCAT(TPC,DQ_BNAME,_2arr		)	(a)		;} \
static size_t	DQ_SCAT(TPC,PFIX,_len)		(DQ_MTYPE* a)        	{return DQ_SCAT2(DQ_BNAME,_len		)	(a)		;} \
static void		DQ_SCAT(TPC,PFIX,_free)		(DQ_MTYPE* a)         	{/**/	DQ_SCAT2(DQ_BNAME,_free		)	(a)		;} \
static void		DQ_SCAT(TPC,PFIX,_frees)	(DQ_MTYPE* a)         	{/**/	DQ_SCAT2(DQ_BNAME,_frees	)	(a)		;} \
static void DQ_SCAT(TPC,dmycall,DQ_BNAME)(void){		\
DQ_MTYPE* dmy; TP obj; return;                          \
DQ_SCAT(TPC,PFIX,_new)();	                            \
DQ_SCAT(TPC,PFIX,_push)		(dmy, obj);	                \
DQ_SCAT(TPC,PFIX,_lift)		(dmy, obj);                 \
DQ_SCAT(TPC,PFIX,_pop)		(dmy);	                    \
DQ_SCAT(TPC,PFIX,_popn)		(dmy, 0);                   \
DQ_SCAT(TPC,PFIX,_drop)		(dmy);		                \
DQ_SCAT(TPC,PFIX,_dropn)	(dmy, 0);                   \
DQ_SCAT(TPC,PFIX,_reset)	(dmy);	                    \
DQ_SCAT(TPC,PFIX,_rep)		(dmy, 0, obj);              \
DQ_SCAT(TPC,PFIX,_see)		(dmy, 0);                   \
DQ_SCAT(TPC,PFIX,_2arr)		(dmy);                      \
DQ_SCAT(TPC,PFIX,_len)		(dmy);                      \
DQ_SCAT(TPC,PFIX,_free)		(dmy);                      \
DQ_SCAT(TPC,PFIX,_frees)	(dmy);                      \
}	\
/*tail_DQ_LINKBASEsub*/

/* header_main */
typedef struct DQ_SCAT2(DQ_BNAME,_tag){  		  
	void* arr;                           		  
	const char* tp;                      		  
	int tpsz;                            		  
	int sidx;
	int eidx;                            		  
	int len;                             		  
	int mlen;                            		  
} DQ_BTYPE;
typedef DQ_BTYPE	DQ_SCAT2(DQ_CMN,_t);		

/* dfl funcs */                          		  
/*	dq123z* dq123z_new(void) etc. basicfunc. impl is wrote in dq.c.	*/
DQ_PROTOBASE(int, i)
DQ_PROTOBASE(double, d)
DQ_PROTOBASE(void*, p)

/* cmn_basicfuncs, prototype */
size_t	DQ_SCAT2(DQ_BNAME,	_len	)	(DQ_BTYPE*);              	
void	DQ_SCAT2(DQ_BNAME,	_free	)	(DQ_BTYPE*);              	
void	DQ_SCAT2(DQ_BNAME,	_frees	)	(DQ_BTYPE*);              	
void	DQ_SCAT2(DQ_BNAME,	_extend	)	(DQ_BTYPE*);              	
int		DQ_SCAT2(DQ_BNAME,	_getidx	)	(DQ_BTYPE*, int		);

/* link renamed dflfc to global fc. static my_t* imy_new(void){return ibase_new();} */
DQ_LINKBASE(dmy)
#endif
/*SH_ED*/


/*SH_SC*/
#include "*SH_bn*.h"	/*SH_co* -std=c89	*/
#include <stdio.h>

/* common_funcs */
size_t DQ_SCAT2(DQ_BNAME,_len)(DQ_BTYPE* dq) { return dq->len; DQ_VOIDCALL();}
void DQ_SCAT2(DQ_BNAME,_free)(DQ_BTYPE* dq) {
	if(dq==NULL) {return;}
	memset(dq->arr, '\0', dq->tpsz * dq->mlen);
	free(dq->arr);
	memset(dq, '\0', sizeof(DQ_BTYPE) );
	free(dq);
}
void DQ_SCAT2(DQ_BNAME,_frees)(DQ_BTYPE* dq) {
	int pos, i;
	void** arr;
	if(dq==NULL) {return;}
	DQ_PANIC(dq->tp[0] != 'p', "dq_frees() only works for ptr payload", exit(1) );
	pos = dq->sidx+1;
	arr = (void**)dq->arr;
	i=0;
	for(i=0; i<dq->len; i++) {
		if(dq->mlen <= pos){pos=0;}
		free(arr[pos]);
		pos++;
	}
	DQ_SCAT2(DQ_BNAME,_free)(dq); 
}
void DQ_SCAT2(DQ_BNAME,_extend)(DQ_BTYPE* dq) {
	char* newbuf;
	int cnt;
	newbuf = (char*)realloc(dq->arr, dq->mlen*2 * dq->tpsz );
	DQ_PANIC(newbuf==NULL, "realloc() failed.", exit(1) );
	cnt = dq->mlen - dq->eidx;
/*
//int* i=(int*)newbuf;
//printf("%d\n", *i );
// for(int i=0;i<32;i++){ printf("%d ", ((int*)dq->arr)[i] ); }
// printf("\n%d %d %d\n", dq->sidx, dq->eidx, cnt );

//倍だから絶対に重ならない. 足せばぴったりsidxは移動する
//sスライドかeスライドかの違い。eスライドの方がわずかに早いか。
//一度でもdropしたらsの方が早い。sの方がわかりやすいしs採用
*/
	memcpy( newbuf + (dq->eidx+dq->mlen)*dq->tpsz
		, newbuf + (dq->eidx)*dq->tpsz
		, cnt * dq->tpsz);
/*printf("%d\n", *i );//*/
	dq->arr = newbuf;
	dq->sidx = dq->eidx+dq->mlen -1;
	dq->mlen *= 2;
/*printf("\n%d %d %d\n", dq->sidx, dq->eidx, cnt ); //*/
/*printf("%d\n", dq->sidx); //*/
}
int  DQ_SCAT2(DQ_BNAME,_getidx)(DQ_BTYPE* dq, int idx){
	int bk=idx;
	if(idx<0){idx+=dq->len;}
	DQ_PANIC(idx<0||dq->len<=idx, "bad idx req"
		, printf("dq_len:%d, req:%d\n", dq->len, bk); exit(1) );
	idx += dq->sidx+1;
	if(idx >= dq->mlen){ idx -= dq->mlen; }
	return idx;
}
/* 1st is scope, extern/static */
DQ_IMPLsub(extern ,int		, i, DQ_DFLLEN, DQ_BNAME, DQ_BTYPE, DQ_BNAME, DQ_BTYPE)
DQ_IMPLsub(extern ,double	, d, DQ_DFLLEN, DQ_BNAME, DQ_BTYPE, DQ_BNAME, DQ_BTYPE)
DQ_IMPLsub(extern ,void*	, p, DQ_DFLLEN, DQ_BNAME, DQ_BTYPE, DQ_BNAME, DQ_BTYPE)

#ifdef TEST
#include "*SH_bn*.h"	/*SH_co*	-std=c99 -D_POSIX_C_SOURCE=200112 */
#include "msgp.h"
#include "hcut.h"
#include "laptime.h"
#endif

#ifdef TEST
HCUT_ADD(t_min) {
	dq_t* dq;
	dq = idq_new();	eq(dq != NULL);	idq_free(dq);
	dq = ddq_new();	eq(dq != NULL);	ddq_free(dq);
	dq = pdq_new();	eq(dq != NULL);	pdq_free(dq);
}
#endif

#ifdef TEST
HCUT_ADD(t_dq_new) {
	dq_t* dq;
	char* p;
	dq = idq_new();	eq(dq != NULL);	idq_free(dq);
	dq = ddq_new();	eq(dq != NULL);	ddq_free(dq);
	dq = pdq_new();	eq(dq != NULL);	pdq_free(dq);
	
	dq = pdq_new();
	p = (char*)malloc(32);
	pdq_push(dq, p);
	eq_i(pdq_len(dq), 1);
	pdq_pop(dq);
	eq_i(pdq_len(dq), 0);
	pdq_frees(dq);

	dq = pdq_new();
	eq(dq!=NULL);
	pdq_frees(dq);

	dq = idq_new();
	idq_push(dq, 10);
	idq_push(dq, 11);
	idq_push(dq, 12);
	eq_i(idq_len(dq), 3);
	eq_i(idq_see(dq,1), 11);
	
	idq_dropn(dq, 2);
	eq_i(idq_len(dq), 1);
	eq_i(idq_see(dq,0), 12);
	idq_lift(dq, 30);
	idq_lift(dq, 31);
	eq_i(idq_len(dq), 3);
	eq_i(idq_see(dq,0), 31);
	idq_reset(dq);
	eq_i(idq_len(dq), 0);
	idq_free(dq);
/*	dq = dq_new();	eq(dq != NULL);	dq_frees(dq);	// stoptest */
}
#endif

#ifdef TEST
HCUT_ADD(t_dq_pop) {
	dq_t* dq;
//	int i;
//	double d;
//	char* p;

/* int */
	dq = idq_new();
	idq_push(dq, 10);
	idq_push(dq, 20);
	idq_push(dq, 30);
	idq_push(dq, 40);
	eq_i(idq_len(dq), 4, "len ck");
	eq_i(idq_pop(dq), 40, "pop ck");
	eq_i(idq_len(dq), 3, "len ck");
	
/* extend test */
	int j;
	for(j=0;j<40;j++){ idq_push(dq, j+50); }
/*/for(int i=0;i<64;i++){ printf("%d ", ((int*)dq->arr)[i] ); }*/
	eq_i(idq_see(dq, 0), 10, "len ck");
	eq_i(idq_len(dq), 43 );	/*/pre == 2 + 40;*/
	eq_i(dq->mlen, 64);
	for(j=0;j<100;j++){ idq_push(dq, j+60); }
	eq_i(idq_len(dq), 143 );	/*/pre == 2 + 40; */
	eq_i(dq->mlen, 256);
	
	//20,30, ...
	eq_i(idq_drop(dq), 10);		/*/pre == 2 + 40;	*/
	eq_i(idq_len(dq), 142 );	/*/pre == 2 + 40;	*/
	eq_i( idq_see(dq,0), 20 );	/*/pre == 2 + 40;	*/
	idq_dropn(dq, 1);                            	
	eq_i(idq_len(dq), 141 );	/*/pre == 2 + 40;	*/
	eq_i(idq_see(dq, 0), 30 );	/*/pre == 2 + 40;	*/

	idq_popn(dq, 139);
	eq_i(idq_len(dq), 2 );
	eq_i(idq_see(dq, 0), 30 );
	eq_i(idq_see(dq, 1), 50 );

	idq_rep(dq, 1, 11);
	eq_i(idq_see(dq, 1), 11 );
	eq_i(idq_see(dq, 0), 30 );
	int* arr = idq_2arr(dq);
//dbg(dq->sidx, dq->eidx);
//for(int i=0;i<256;i++){ printf("%d ", ((int*)dq->arr)[i]); }
	eq_i(arr[0],30);
	eq_i(arr[1],11);
	free(arr);
	
	idq_popn(dq, -1);
	eq_i(idq_len(dq), 0);
	
	idq_free(dq);

/*/double*/
	dq = ddq_new();
	ddq_push(dq, 10);
	ddq_push(dq, 20);
	ddq_push(dq, 30);
	ddq_push(dq, 40);
	eq_d(ddq_len(dq), 4, "len ck");
	eq_d(ddq_pop(dq), 40, "pop ck");
	eq_d(ddq_len(dq), 3, "len ck");
	
/*/extend test*/
	for(j=0;j<40;j++){ ddq_push(dq, j+50); }
	eq_d(ddq_len(dq), 43 );		/*/pre == 2 + 40;*/
	eq_d(dq->mlen, 64);
	for(j=0;j<100;j++){ ddq_push(dq, j+60); }
	eq_d(ddq_len(dq), 143 );	/*/pre == 2 + 40;*/
	eq_d(dq->mlen, 256);
	
	//20,30, ...
	eq_d(ddq_drop(dq), 10);		/*/pre == 2 + 40;*/
	eq_d(ddq_len(dq), 142 );	/*/pre == 2 + 40;*/
	eq_d( ddq_see(dq,0), 20 );	/*/pre == 2 + 40;*/
	ddq_drop(dq);             
	eq_d(ddq_len(dq), 141 );	/*/pre == 2 + 40;*/
	eq_d(ddq_see(dq, 0), 30 );	/*/pre == 2 + 40;*/

	ddq_popn(dq, 139);
	eq_d(ddq_len(dq), 2 );
	eq_d(ddq_see(dq, 0), 30 );
	eq_d(ddq_see(dq, 1), 50 );

	ddq_rep(dq, 1, 11);
	eq_d(ddq_see(dq, 1), 11 );
	double* darr = ddq_2arr(dq);
	eq_d(darr[0],30);
	eq_d(darr[1],11);
	free(darr);

	ddq_reset(dq);
	eq_i(ddq_len(dq), 0);
	
	ddq_free(dq);
/*ptr	*/
	dq = pdq_new();
	pdq_push(dq, (void*)10);
	pdq_push(dq, (void*)20);
	pdq_push(dq, (void*)30);
	pdq_push(dq, (void*)40);
	eq_p(pdq_len(dq), 4, "len ck");
	eq_p(pdq_pop(dq), 40, "pop ck");
	eq_p(pdq_len(dq), 3, "len ck");
	
/*/extend test*/
	for(j=0;j<40;j++){ pdq_push(dq, (void*)(j+50) ); }
	eq_p(pdq_len(dq), 43 );	/*/pre == 2 + 40;*/
	eq_p(dq->mlen, 64);
	for(j=0;j<100;j++){ pdq_push(dq, (void*)(j+60) ); }
	eq_p(pdq_len(dq), 143 );	/*/pre == 2 + 40;*/
	eq_p(dq->mlen, 256);
	
	/*/20,30, ...*/
	eq_p(pdq_drop(dq), 10);		/*/pre == 2 + 40;*/
	eq_p(pdq_len(dq), 142 );	/*/pre == 2 + 40;*/
	eq_p( pdq_see(dq,0), 20 );	/*/pre == 2 + 40;*/
	pdq_drop(dq);
	eq_p(pdq_len(dq), 141 );	/*/pre == 2 + 40;*/
	eq_p(pdq_see(dq, 0), 30 );	/*/pre == 2 + 40;*/

	pdq_popn(dq, 139);
	eq_p(pdq_len(dq), 2 );
	eq_p(pdq_see(dq, 0), 30 );
	eq_p(pdq_see(dq, 1), 50 );

	pdq_rep(dq, 1, (void*)11);
	eq_p(pdq_see(dq, 1), 11 );
	void** parr = pdq_2arr(dq);
	eq_p(parr[0],30);
	eq_p(parr[1],11);
	free(parr);

	pdq_reset(dq);
	eq_i(pdq_len(dq), 0);
	
	pdq_free(dq);
	
}
#endif

#ifdef TEST
HCUT_ADD(t_bm1) {
	//bench mark
	int sz=10 * 1000*1000;
	int arr[2] = {1,1};
	int i;
laptime(0);
	for(i=0; i<sz-1;i++){ arr[0]=arr[1]+1;}
laptime("r/w arr[]");
//real	0m0.036s
//user	0m0.035s
//sys	0m0.001s

//real	41.959 ms
}
#endif

#ifdef TEST
DQ_IMPL(static inline, int, ii)

HCUT_ADD(t_bm2) {
	int sz=10 * 1000*1000;
	dq_t* dq = idq_new();
	idq_push(dq, 1);idq_push(dq, 1);
	int i;
laptime(0);
	for(i=0; i<sz-1;i++){ idq_rep(dq, -1, idq_see(dq,0)+1); }
laptime("r/w dq()");
	idq_free(dq);
//real	0m0.376s
//user	0m0.365s
//sys	0m0.010s
//real	335.487 ms
// real	640.128 ms	: ./dq.ts.c 204: t_bm2_sub(): msg:r/w dq()

	dq = iidq_new();
	iidq_push(dq, 1);iidq_push(dq, 1);
laptime(0);
	for(i=0; i<sz-1;i++){ iidq_rep(dq, -1, iidq_see(dq,0)+1); }
laptime("r/w iidq(), DQ_IMPL(static inline, int, ii)");
	idq_free(dq);
//real	466.954 ms	: ./dq.ts.c 214: t_bm2_sub(): msg:r/w iidq(), inline
}
#endif

#ifdef TEST
HCUT_ADD(t_bm3) {
	int sz=10 * 1000*1000;
	dq_t* dq = idq_new();
	idq_push(dq, 1);idq_push(dq, 1);
	int* arr = idq_2arr(dq);
	int i;
laptime(0);
	for(i=0; i<sz-1;i++){ arr[1]=arr[0]+1; }
laptime("r/w dqarr[]");
	idq_free(dq);
	free(arr);
//real	0m0.038s
//user	0m0.033s
//sys	0m0.004s
}
#endif

#ifdef TEST
HCUT_ADD(t_bm4) {
	int sz=10 * 1000*1000;
	int arr[1] = {1};
	int i;
laptime(0);
	for(i=0; i<sz-1;i++){ arr[0]=i%10;}
laptime("w arr[]");
//real	0m0.050s
//user	0m0.034s
//sys	0m0.017s

//real	54.630 ms
}
#endif

#ifdef TEST
HCUT_ADD(t_bm5) {
	int sz=10 * 1000*1000;
	dq_t* dq = idq_new();
	int i;
laptime(0);
	for(i=0; i<sz-1;i++){ idq_push(dq, i%10); }
laptime("w dq()");
	idq_free(dq);
//real	0m0.292s
//user	0m0.258s
//sys	0m0.034s

//real	204.161 ms	
}
#endif


#ifdef TEST
HCUT_RUN("stderr", 1,
t_dq_new, t_dq_pop, t_bm1, t_bm2, t_bm3, t_bm4, t_bm5 );
#endif

/*SH_SMP
#include <stdio.h>
#include "*SH_bn*.h"

typedef struct my_tag{ int a; int b;} my_t;
DQ_IMPL(static, my_t, my);

int main(int argc, char** argv) {
	DQ_VOIDCALL();
	puts("hw");
	dq_t* dq = mydq_new();
	my_t obj = {1,2};
	mydq_push(dq, obj);
printf("%d\n", mydq_len(dq) );
	obj = mydq_pop(dq);
printf("%d\n", obj.b );
	mydq_free(dq);
	return 0;
}
// ~$ gcc src.c libdq.a
//SH_SMPE*/

/*
 change log
 --
2021-07-10  Momi-g	<dmy@dmy.dmy>

	* *SH_bn*(dq_2arr): fix len==1 b/o write err. add len==1

2021-05-20  Momi-g	<dmy@dmy.dmy>

	* *SH_bn*(all): fix -Wpedantic warning, improve sh.c macros

	* *SH_bn*(test): add -O0, -O2 test, fixdoc

2021-03-27  Momi-g	<dmy@dmy.dmy>

	* *SH_bn*(all): add NULL obj PANIC()

2021-02-23  Momi-g	<dmy@dmy.dmy>

	* *SH_bn*(_2arr): fix invalid memcpy() range.

2021-02-22  Momi-g	<dmy@dmy.dmy>

	* *SH_bn*(all): change api. v1.1.0
	* (settail/sethead): omit. replace to popn(), dropn()
	* (pop/drop): change api. pop/drop() takes only 1 args
	* (popn/dropn): new api. popn/dropn() takes 2 args for multi remove

2021-02-19  Momi-g	<dmy@dmy.dmy>

	* *SH_bn*.c(dq_reset): add newfunc. fix macros
	
	* *SH_bn*.c(all): change dq_obj struct for use lowcost i++. 50ms -> 40ms

2021-01-30  Momi-g	<dmy@dmy.dmy>

	* *SH_bn*.c(DQ_VOIDCALL): add new macro for kill compile warning, dmycall.
	(DQ_CMN): add
	(DQ_LINKBASE): fix
	(DQ_IMPLsub): fix new(), add voidfunccall()

2021-01-21  Momi-g	<dmy@dmy.dmy>

	* *SH_bn*.c: v1.0.0

*/

/*SH_ED*/

/*SH_OP _ set -e;a=`sed -ne "/${C}DF/!d;:l;n;/${C}DE/q;p;bl"<$R0`;eval "$a"	#*/
/*SH_OP	h $p"-tsbS:test/eg/.o/.so -LMP:leak,mem,prof -f:funcs -o:bldout		GPLv3+"	 #*/
/*SH_OP	f sed -ne "/${C}DF/q;/;/d;/^[a-z].*)/p"<$R0 #*/
/*SH_OP t $e"$CW";ftt "$@";$p'cc -O0 -Wall -pedantic -g -pg -ggdb3 $tf $Rs `fOI $Rs $tf` `fg $Rs $tf` `fL`'|fv	#*/
/*SH_OP T $e"$CW";ftt "$@";$p'cc -O2 $tf $Rs `fOI $Rs $tf ` `fg $Rs $tf ` `fL`'|fv	#*/
/*SH_OP s $e"$CB";fgr0 "${C}SMP" "${C}SMPE"<$Rs|fbn>eg.c;$p'cc eg.c `fg eg.c` `fOI eg.c`'|fv #*/

/*SH_OP L $p"valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose ./a.out 2>&1|sed -e '/SUMMA/!d;n;n;n;n'"|fv #*/
/*SH_OP M $p"fM ./a.out"|fv	 #*/
/*SH_OP P $p'valgrind --tool=callgrind --callgrind-out-file=log.out ./a.out;kcachegrind log.out'|fv	 #*/

/*SH_OP b $e"$CW";$p'cc -c $Rs -pedantic -O2 -Wall -g `fg $Rs` `fI $Rs`'|fv;$p"$bn.o"	#*/
/*SH_OP B $e"$Cb";$p"ar -r lib$bn.a $bn.o `fO $Rs`"|fv;$p"lib$bn.a"	#*/
/*SH_OP A $e"$CB";$p'fA lib$bn.a `fg $Rh $Rs|fu|grep '[.]a$'|fU`'|fv;$p"lib$bn.a" #*/
/*SH_OP S $e"$Cb";$p"cc -shared -fPIC -o lib$bn.so $bn.o `fOI $Rs` `fg $Rs`"|fv;$p"lib$bn.so" #*/
/*SH_OP W $e"$Cm$O$Cw">/dev/null;$i0;$i1;$p"$Rs $Rh $tf"	#*/
/*SH_OP o $e"$CW";$p"rm $tf"|fv;fman $R0 3	#*/

/*SH_DF
#-- noob
fman()(fgr0 "${C}doc" "${C}docE"<$1>$Rm
cat $Rm|sed -e's/^@\([_a-zA-Z][_[:alnum:]]*\)/\n\n# \1\n\n/g
/^\\/{s/^\\/<br>/g}'>$bn.md
cat $bn.md|pandoc -f markdown -thtml> $Rm
cat $Rm|pandoc -s -f html -t man -M title="$bn" -M section="$2" \
-M date=`date '+%Y-%m-%d'` > $bn.$2
sed -e 's/^.nf/.RE\n.nf/'<$bn.$2>$Rm
mv $Rm $bn.$2
fhtml
)
fhtml()( md2h $bn.md $bn )

#-- local

#-- vars
bn=`basename ${Rs%.*}`; tf=${Rs%/*}/${bn}.ts.${Rs##*.}; e="eval "; p="$Rp"
#-- mod
fv()(while read -r a;do $e"cat<<E$O# $a${O}E"|sed -e 's@-L.*-L[^ ]*@-L(omit)@g'>/dev/stderr;$e"$a";done)

fbn()(sed -e "s@\*${C##*]}bn\*@$bn@g"|frf)
fsn()(tr -s ' \t' '\n')
fsl()(tr -s '\n' ' ')
fu()(fsn|sort -u)
fU()(fu|fsl;$p)

fgr()(sed -e "/$1/!d;:l;/$2/{p;d};n;bl")	#切出
fgr0()(sed -ne "/$1/!d;:l;n;/$2/d;p;bl")	#抜き切出
fgR()(sed -ne "/$1/bl;p;d;:l;n;/$2/d;bl")	#切すて
fg()(sed -ne "s/.*${C##*]}co\*\([^*]*\).*$/\1/p" "$@"|fsn|awk '!a[$0]{a[$0]=1;print}'|fsl)

# fO src.o from inc"src.abc" etc. kick self
fO()(set -- `fdp "$@"|awk '$0~/[.](h|hpp)$/{print}'|sed -e 's/[.][^.]*$/.o/'|fU`
	buf="";for i;do test -f $i&&buf="$buf $i";done;$p"$buf"
)
fI()(fdp "$@"|sed -e 's/[^/]*$//g'|fu|sed -e '/./s/^/ -I/g'|fu|grep -v '^\-I$'|fU)
fL()(find -L `dirname $R0` -type d|sed -e 's/^/-L/g'|fU)
# inc""系.h,hpp,oをパス付きで羅列 OIはfdpが重複するので高速化でまとめる 複数file_ok
fOI()(
set -- `fdp "$@"`
s="-I./ "`$p"$@"|sed -e 's/[^/]*$//g'|fu|sed -e 's/^/ -I/g'|fu|grep -v '^\-I$'|fU`
set -- `$p"$@"|awk '$0~/[.](h|hpp)$/{print}'|sed -e 's/[.][^.]*$/.o/'|fU`
buf="";for i;do test -f $i&&buf="$buf $i";done;
$p"$buf $s"
)

# 依存inc""を再帰的に取得./以下全て self系はkick
fdp()( l="$*"; paths="$@"; all=""; used=""
 while :;do
	all=`$p$all $paths|fU`	#差分を追加 repの始末 差分たちからaaa.hを取得 partial path
	buf=`(cat $paths|sed -ne 's@^[ \t]*#inc[^"]*.\([a-zA-Z0-9._]*\)".*@\1@p')|sort -u`
	ch=`$p$used $buf|tr -s ' ' '\n'|sort|uniq -u`	#使用済は外す
	used="$used $ch"	#リスト更新
	paths=`fsvy $ch|sort -u`	#ls検索 name系のみのはず
	buf=`$p"$all" "$paths"|fU`	#増えたらloop
	[ ${#all} = ${#buf} ]&&break
 done
# initを除く
 set -- $all
 for i;do a=${i##*[/]}; a=${a%%.*};[ "${l##*$a*}" = "$l" ]&&set -- "$@" $i;shift;done
 $p"$@"
)

# corecode:search + depthck + uniq
fsvy()(c="find -L ./ -false"
	for i; do c="$c -o -path '*'$i";done; l=`$e"$c"`
	for i; do $p"$l"|grep -F "$i"|awk '{sv=$0;print gsub("[/]","") " " sv}'|
	sort -k 1.1,1n -k 2.2,2|awk '{print $2;exit}'; done
)

# libをまとめる
fA()(n=0;dir=`dirname $0`/tmpdir;mkdir $dir;cd $dir;
 for i;do
 	n=$((n+1))
 	cp ../$i $i
 	ar -x $i
 	for ii in *.o;do mv "$ii" "p${n}_$ii";done
 	ar -r lib$bn.aa *.o
 	rm *.o
 done
 $p'mv lib$bn.aa ../lib$bn.a'|fv
 cd ..;rm -r $dir
)

#-- yacc
# /*SH_OP y $e"$CW";fy
# /*SH_OP Y $e"$Cy";fU $( ($p"lib$bn.a";fg $Rs $Rh)|$n|grep '[.]a$'|$U)
fy()(
cat<<'EEE'|fv
f0 "${C}YACC" "${C}YACCE"<$Rs>myyacc.y
f0 "${C}LEX" "${C}LEXE"<$Rs>mylex.l
lex mylex.l; yacc -p zz -dv myyacc.y
cat y.tab.c lex.yy.c > $Rs
gcc -c y.tab.c lex.yy.c -lfl `fA $Rs $Rh`
rm mylex.l myyacc.y lib$bn.a
ar r lib$bn.a `fo $Rs` y.tab.o lex.yy.o
$p"lib$bn.a"
EEE
)

#-- longcmd
frf()(
 awk -v r="${C##*]}rf" 'match($0,r){
 s=substr($0, RSTART+RLENGTH+1)
 gsub(/.[^*]*$/, "", s);split(s, a)
 m="[ -f %s ]&&echo \"/*--copyfrom %s*\"/&&cat %s&&echo \"/*--copyend %s*\"/"
 for(i=1;v=a[i];i++){ system( sprintf(m, v,v,v,v))}
 next
 }
 {print}'
)

ftt()(a="`sed -ne 's@^HCUT_ADD(\([^)]*\).*@\1, @p' $tf|tr -d '\n'`NULL"
	if [ $# != 0 ];then	a=""; for i;do a="$a $i,";done; a="$a NULL"; fi
	sed -ne "p;/_RUN/bl;d;:l;/[)]/{c\\$O $a)$O p;d};n;bl"<$tf>$Rm;mv $Rm $tf)
i0=$e'fgr0 "^#ifdef TEST" "^#endif"<$R0|fbn>$tf'
i1=$e'fgR "^#ifdef TEST" "^#endif"<$Rs|fbn>$Rm;mv $Rm $Rs;fbn<$Rh>$Rm;mv $Rm $Rh'
fM()(
 valgrind -q --tool=massif --massif-out-file=./vmem.buf --stacks=yes --trace-children=yes $1>/dev/null
 ms_print ./vmem.buf|sed -ne '/[KMG]B/bl;d;:l;/snap/q;p;n;bl';rm ./vmem.buf)

/*SH_DE*/
