#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*/
/* Copyright (C) 2021 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	charbits
@auther momi-g
@brief	macros, bitcalc with char/int/any arr[]
@_synopsys
	#define CBIT_NOT(p, sz)		
	#define CBIT_RR(p, sz, sft) 
	#define CBIT_LL(p, sz, sft) 
								
	#define CBIT_OR(p1, p2, sz)
	#define CBIT_AND(p1, p2, sz)
	#define CBIT_XOR(p1, p2, sz)
	#define CBIT_SET(p1, p2, sz)	//not bitop. assing arr, p1=p2
	// all macros can set a caststr to ag1, XXX( (float),p1,p2,sz) etc.  

@_eg
	#include "charbits.hpp"
	#include <stdio.h>

	int main(int argc, char** argv){
		char p1[] = {1,0,0,0, 0,0,0,0};		// {1000 0000}
		char p2[] = {1,0,1,0, 0,0,0,0,1};	// {1010 0000 1}
		
		CBIT_NOT(p1, 8);	// {0111 1111}
		CBIT_LL(p1, 8, 2);	// {1111 1100}	// arr shift. drop p1[0], p1[1]
		CBIT_RR(p1, 6, 3);	// {0001 1100}	// handle p1[0]-p1[5], sz==6
		
		CBIT_OR( (char), p1, p2, 8);	// {1011 1101},  p1[n]=(char)p2[n]
		CBIT_AND(p1, p2, 8);// {1010 0000}
		
		CBIT_NOT(p1, 2);	// {0110 0000}	ignore p1[2]-
		// CBIT_NOT(p1, 100);	// sizeover. cause SIGSEGV
		
		for(int i=0;i<8;i++){printf("%d ",p1[i]);}
		puts("");
		return 0;
	}
	// ~$ ~$ gcc -E -P eg.c
	// ~$ ~$ gcc eg.c

@param	p	arrhead ptr. int arr[10]={0}; char* arr = malloc(12); etc.
@param	sz	idx limit for calc.	 0000 >>> CBIT_NOT(p,2) >>> 1100 
@param	sft	RR/LL needs shift size. size is unlimited until size_t max.
@details
 - macros treats val as bool but try to hold rawdata.
   priority is ag1>ag2.  macros changes rawdata to 0/1 if invert bit/byte.
		int p1[] = {10,0,12,0};	// 1010
		int p2[] = {20,0,0,23};	// 1001
		CBIT_OR(p1, p2, 4);	//  {10,0,12,23}
		CBIT_NOT(p1);	// {0,1,0,0}
	
 - idxlimit setting must be smaller than p1 and p2 size.
		float p1[] = {1,1,1,0};
		float p2[] = {1,0,0,0};
		CBIT_AND(p1, p2, 16);	// NG. out of idx range
		CBIT_AND(p1, p2, 2);	// ok. get {1,0,1,0}. check only first 2 idx.

 - shift direction 
   someone feels the shift operation is reversed. set your macro if necessary. 
		#include "charbits.hpp"
		#define CBIT_myRR	CBIT_LL
		#define CBIT_myLL	CBIT_RR
		int main(int argc, char** argv){ ...

 - cast option
   macros can handle different types of arrays.
		#include "charbits.hpp"
		int main(int argc, char** argv){
			char p1[] = {1,0,1,0};
			void* p2[] ={0,1,0,0};
			CBIT_OR(p1, p2, 4); //{1110}	val is cast to void* >> char
			return 0;
		}

	but some oparation causes type compatibility warning, int a=(float)3 etc.
	you can stop warning by setting caststr to macro arg1.
			char p1[4];
			void* p2[8];

			CBIT_XOR(        p1, p2, 4);	// p1[n]= p2[n]
			CBIT_XOR((char), p1, p2, 4);	// p1[n]= (char)p2[n]
			CBIT_OR((void*), p2, p1, 4);	// p2[n]= (void*)p1[n]
			CBIT_NOT((void*)(int),p2,6);	// p2[n]= (void*)(int)1  etc
	
	see ~$ gcc -E -P eg.c
	
@_note
https://programming-place.net/ppp/contents/c/rev_res/array011.html#way1
https://stackoverflow.com/questions/2632300	Q: Ed Marty  ->  A: Matthew Slattery
@conforming posix-2001+
@version 1.0.0, 2021-02-12
-*/
/*SH_ED*/

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

/* api */
#define CBIT_NOT	CHARBITS_NOT
#define CBIT_RR     CHARBITS_RR
#define CBIT_LL     CHARBITS_LL
#define CBIT_OR     CHARBITS_OR
#define CBIT_AND    CHARBITS_AND
#define CBIT_XOR    CHARBITS_XOR
#define CBIT_SET    CHARBITS_SET

/* impl */
#include <string.h>

// from license: cc-by-sa 2.5 (code is changed from the orig)
// https://stackoverflow.com/questions/2632300	Q: Ed Marty  ->  A: Matthew Slattery
#define CHARBITS_CAST(...) CHARBITS_CASTsub(__VA_ARGS__, CHARBITS_CASTset, CHARBITS_CASTdfl)
#define CHARBITS_CASTsub(a1,a2,a3,a4,mc,...)	mc(a1)
#define CHARBITS_CASTset(a1)	a1
#define CHARBITS_CASTdfl(a1)	

#define CHARBITS_CNT(...) CHARBITS_CNTsub(__VA_ARGS__, CHARBITS_C4, CHARBITS_C3)
#define CHARBITS_CNTsub(a1,a2,a3,a4,mc,...)	mc(a1,a2,a3,a4)
#define CHARBITS_C4(a1,a2,a3,a4)	a2,a3,a4
#define CHARBITS_C3(a1,a2,a3,a4)	a1,a2,a3	
// end licence:	cc-by-sa 2.5

#define CHARBITS_NOT(...) CHARBITS_impl(NOT, CHARBITS_CAST(__VA_ARGS__, dmy), CHARBITS_CNT(__VA_ARGS__,dmy) )
#define  CHARBITS_RR(...) CHARBITS_impl( RR, CHARBITS_CAST(__VA_ARGS__     ), CHARBITS_CNT(__VA_ARGS__    ) )
#define  CHARBITS_LL(...) CHARBITS_impl( LL, CHARBITS_CAST(__VA_ARGS__     ), CHARBITS_CNT(__VA_ARGS__    ) )
#define  CHARBITS_OR(...) CHARBITS_impl( OR, CHARBITS_CAST(__VA_ARGS__     ), CHARBITS_CNT(__VA_ARGS__    ) )
#define CHARBITS_AND(...) CHARBITS_impl(AND, CHARBITS_CAST(__VA_ARGS__     ), CHARBITS_CNT(__VA_ARGS__    ) )
#define CHARBITS_XOR(...) CHARBITS_impl(XOR, CHARBITS_CAST(__VA_ARGS__     ), CHARBITS_CNT(__VA_ARGS__    ) )
#define CHARBITS_SET(...) CHARBITS_impl(SET, CHARBITS_CAST(__VA_ARGS__     ), CHARBITS_CNT(__VA_ARGS__    ) )

#define CHARBITS_impl(suf, ...) CHARBITS_##suf##impl(__VA_ARGS__)
#define CHARBITS_NOTimpl(pre, p, sz, dmy) do{size_t i=0;for(;i<sz;i++){p[i]= pre!p[i];} }while(0)
#define  CHARBITS_RRimpl(pre, p, sz, sft) do{memmove(p+sft,p,sizeof(p[0])*(sz-sft));memset(p,0,sizeof(p[0])*sft);} while(0)
#define  CHARBITS_LLimpl(pre, p, sz, sft) do{memmove(p,p+sft,sizeof(p[0])*(sz-sft));memset(p+sz-sft,0,sizeof(p[0])*sft); }while(0)
#define  CHARBITS_ORimpl(pre, p1, p2, sz) do{size_t i=0;for(;i<sz;i++){p1[i]= (p1[i]||p2[i]) ? (p1[i]?p1[i]:pre p2[i]) : 0;} } while(0)
#define CHARBITS_ANDimpl(pre, p1, p2, sz) do{size_t i=0;for(;i<sz;i++){p1[i]= (p1[i]&&p2[i]) ? p1[i] : 0; } } while(0)
#define CHARBITS_XORimpl(pre, p1, p2, sz) do{size_t i=0;for(;i<sz;i++){p1[i]= (p1[i]&&!p2[i]) ? p1[i]: (!p1[i]&&p2[i])?pre p2[i] : 0; } }while(0)
#define CHARBITS_SETimpl(pre, p1, p2, sz) do{size_t i=0;for(;i<sz;i++){p1[i]= pre p2[i];} } while(0)
/*SH_ED*/

/*SH_SC*/
/* hpp, header only */

#ifdef TEST
#include "*SH_bn*.h"
#include "hcut.h"
#include "msgp.h"
#endif

#ifdef TEST
HCUT_ADD(t_charbits) {
	char p1[] = {1,0,0,0, 0,0,0,0};	//1000 0000
	char p2[] = {1,0,1,0, 0,0,0,0,1};	//1010 0000 1
	
	CBIT_NOT(p1, 8);
	for(char i=0,*s="01111111";s[i];i++){eq_i(p1[i],s[i]=='1');fprintf(stderr, "%c ",s[i]);}puts("");
	
	CBIT_RR(p1, 8, 2);
	for(char i=0,*s="00011111";s[i];i++){eq_i(p1[i],s[i]=='1');fprintf(stderr, "%c ",s[i]);}puts("");

	CBIT_LL(p1, 8, 1);
	for(char i=0,*s="00111110";s[i];i++){eq_i(p1[i],s[i]=='1');fprintf(stderr, "%c ",s[i]);}puts("");
	
	CBIT_OR(p1, p2, 8);
	for(char i=0,*s="10111110";s[i];i++){eq_i(p1[i],s[i]=='1');fprintf(stderr, "%c ",s[i]);}puts("");
	
	CBIT_AND(p1, p2, 8);
	for(char i=0,*s="10100000";s[i];i++){eq_i(p1[i],s[i]=='1');fprintf(stderr, "%c ",s[i]);}puts("");
	
	CBIT_NOT(p1, 2);		// 0000 0110	ignore upper 6bit
	for(char i=0,*s="01100000";s[i];i++){eq_i(p1[i],s[i]=='1');fprintf(stderr, "%c ",s[i]);}puts("");
	// CBIT_NOT(p1, 100);	// sizeover. cause SIGSEGV
	
	CBIT_XOR(p1, p2, 8);	// 0000 0011 
	for(char i=0,*s="11000000";s[i];i++){eq_i(p1[i],s[i]=='1');fprintf(stderr, "%c ",s[i]);}puts("");
	CBIT_XOR(p1, p2, 8);	// 0000 0110 
	for(char i=0,*s="01100000";s[i];i++){eq_i(p1[i],s[i]=='1');fprintf(stderr, "%c ",s[i]);}puts("");
//
	
	
	void* p3[] = {(void*)1,0,0,0, 0,0,0,0};	//1000 0000
	float p4[] = {1,0,1,0, 0,0,0,0,1};	//1010 0000 1
	
	CBIT_NOT((void*)(int), p3, 8);
	for(char i=0,*s="01111111";s[i];i++){eq_i(p3[i],s[i]=='1');fprintf(stderr, "%p:%c ",p3[i],s[i]);}puts("");
	
	CBIT_RR(p3, 8, 2);
	for(char i=0,*s="00011111";s[i];i++){eq_i(p3[i],s[i]=='1');fprintf(stderr, "%p:%c ",p3[i],s[i]);}puts("");

	CBIT_LL(p3, 8, 1);
	for(char i=0,*s="00111110";s[i];i++){eq_i(p3[i],s[i]=='1');fprintf(stderr, "%p:%c ",p3[i],s[i]);}puts("");
	
	CBIT_OR((void*)(int), p3, p4, 8);
	for(char i=0,*s="10111110";s[i];i++){eq_i(p3[i],s[i]=='1');fprintf(stderr, "%p:%c ",p3[i],s[i]);}puts("");
	
	CBIT_AND((void*)(int), p3, p4, 8);
	for(char i=0,*s="10100000";s[i];i++){eq_i(p3[i],s[i]=='1');fprintf(stderr, "%p:%c ",p3[i],s[i]);}puts("");
	
	CBIT_NOT((void*)(int), p3, 2);		// 0000 0110	ignore upper 6bit
	for(char i=0,*s="01100000";s[i];i++){eq_i(p3[i],s[i]=='1');fprintf(stderr, "%p:%c ",p3[i],s[i]);}puts("");
	// CBIT_NOT(p3, 100);	// sizeover. cause SIGSEGV
	
	CBIT_XOR((void*)(int), p3, p4, 8);	// 0000 0011 
	for(char i=0,*s="11000000";s[i];i++){eq_i(p3[i],s[i]=='1');fprintf(stderr, "%p:%c ",p3[i],s[i]);}puts("");
	CBIT_XOR((void*)(int), p3, p4, 8);	// 0000 0110 
	for(char i=0,*s="01100000";s[i];i++){eq_i(p3[i],s[i]=='1');fprintf(stderr, "%p:%c ",p3[i],s[i]);}puts("");

// add
	double p5[] = {1,1,1,0, 0,0,0,1};	//1000 0000
	
	CBIT_RR(p5, 2, 1);
	for(char i=0,*s="01100001";s[i];i++){eq_i(p5[i],s[i]=='1');fprintf(stderr, "%p:%c ",(int)p5[i],s[i]);}puts("");
	CBIT_LL(p5, 8, 2);
	for(char i=0,*s="10000100";s[i];i++){eq_i(p5[i],s[i]=='1');fprintf(stderr, "%p:%c ",(int)p5[i],s[i]);}puts("");

	double p6[] = {1,1,1,0, 0,0,0,1};
	double p7[] = {1,0,0,0, 0,0,0,0};
	CBIT_SET((double)(int), p6, p7, 2);
	for(char i=0,*s="10100001";s[i];i++){eq_i(p6[i],s[i]=='1');fprintf(stderr, "%p:%c ",(int)p6[i],s[i]);}puts("");
}
#endif

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

int main(int argc, char** argv){
	char p1[] = {1,0,0,0, 0,0,0,0};		// {1000 0000}
	char p2[] = {1,0,1,0, 0,0,0,0,1};	// {1010 0000 1}
	
	CBIT_NOT(p1, 8);	// {0111 1111}
	CBIT_LL(p1, 8, 2);	// {1111 1100}	// CBIT_LLa() <-> CBIT_LLb() see detail
	CBIT_RR(p1, 8, 3);	// {0001 1111}
	
	CBIT_OR(p1, p2, 8);	// {1011 1111}
	CBIT_AND(p1, p2, 8);// {1010 0000}
	
	CBIT_NOT(p1, 2);	// {0110 0000}	ignore p1[2]-
	// CBIT_NOT(p1, 100);	// sizeover. cause SIGSEGV

	for(int i=0;i<8;i++){printf("%d ",p1[i]);}puts("");
	return 0;
}
// ~$ gcc eg.c

//SH_SMPE*/

#ifdef TEST
HCUT_RUN("stderr", 1,	/* keep newline. use for SH sed edit, -t test.*/
t_charbits );
#endif

/*
 change log
 --
2021-06-03  Momi-g	<dmy@dmy.dmy>

	* *SH_bn*.c (all): add test CBIT_RR(p, 6, 2)

	* *SH_bn*.c (all): add add CBIT_SET(), array assign macro

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

	* *SH_bn*.c (all): 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"-t/s/b:test/smpl/bld /T:t+mem /f:functop	GPLv3+"	 #*/
/*SH_OP	f sed -ne "/${C}DF/q;/;/d;/^[a-z].*)/p"<$R0 #*/

/*SH_OP t $e"$CB";ft "$@";$p'cc -g -pg $tf `foi $tf $Rs` `fg $tf $Rs`'|fv	#*/
/*SH_OP s $e"$CB";fgr "${C}SMP" "${C}SMPE"<$Rs|fbn>eg.c;$p'cc eg.c `fg eg.c`'|fv #*/
/*SH_OP L $p"valgrind --leak-check=full ./a.out 2>&1|sed -e '/SUMMA/!d;n;n;n;n'"|fv #*/
/*SH_OP M $p"fM"|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 -O2 -Wall -g `fg $Rs` `fI $Rs`'|fv;$p"$bn.o"	#*/
/*SH_OP B $e"$Cb";$p"ar -r lib$bn.a $bn.o"|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";$i0;$i1;fbn<$Rh>$Rm;mv $Rm $Rh;$p"$Rs $tf"	#*/

/*SH_OP y $e"$CW";fy	#*/
/*SH_OP Y $e"$Cy";fU $( ($p"lib$bn.a";fg $Rs $Rh)|$n|grep '[.]a$'|$U)	#*/

/*SH_DF

#--name
bn=`basename ${Rs%.*}`
tf=${Rs%/*}/${bn}.ts.${Rs##*.}

#--cmd
e="eval "
p="$Rp"

fbn()(sed -e "s@\*${C##*]}bn\*@$bn@g")
fu()(tr -s ' \t' '\n'|sort -u)
fU()(fu|tr -s '\n' ' ';$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/.*\*SH_co\*\([^*]*\).*$/\1/p' "$@"|fU)

# fO src.c src.abc etc
fO()(
set -- `fdp "$@"|sed -ne 's/[.]h$/.o/p'|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)
fL()(find -L `dirname $0` -type d|sed -e 's/^/-L/g'|fU)
foi()(
a="cat"
for i;do
a="$a| grep -v ${i%.*}.o"
done
set -- `fO $@`
for i;do
set -- $@ -I`dirname $i`
done
$p"$@"|$e"$a"|sort -ur|tr '\n' ' ')

fsvy()(
c="find -L ./ -false"
for i
do
c="$c -o -name ${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
)

# こいつが重い。500msもかかる >>findを全部保持 >> むしろ遅くなった
fdp()(
while :;do
a=$#
set -- `(cat "$@"|sed -ne 's/^#inc[^"]*.//p'|sed -e 's@".*@@g';$p"$@")|sort -u`
set -- `fsvy "$@"|sort -u`
[ $a = $# ]&&break
done;$p"$*"|tr -s ' ' '\n'
)

	#in(\0)をo123(\n)系へ
fbin()(od -vAn -to1|tr -sc '0-7' '\n'|sed -e 's/^/o/g'|tr -d '\n'|sed -e 's/o000/\n/g')
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
)

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)

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
}

ft(){
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"<$Rm|fbn>$tf'
i1=$e'fgR "^#ifdef TEST" "^#endif"<$Rs|fbn>$Rm;mv $Rm $Rs'
 fM(){
 valgrind -q --tool=massif --massif-out-file=./vmem.buf --stacks=yes --trace-children=yes ./a.out>/dev/null
 ms_print ./vmem.buf|sed -ne '/[KMG]B/bl;d;:l;/snap/q;p;n;bl'
 rm ./vmem.buf
}

/*SH_DE*/
