#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
/*	GPLv3+	*/
/* 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	laptime
@auther momi-g
@brief	research interval times
@_synopsys
	void laptime(int num / void / const char* msg);
@_eg
	#include <unistd.h>		//sleep()
	#include "*SH_bn*.h"

	int main(int argc, char** argv) {
		laptime(0);	//reset
		sleep(1);	
		laptime();		//>> real 1009ms	: src.c 4:func(): msg:-
		laptime("hw");	//>> real 1010ms	: src.c 5:func(): msg:hw

		laptime(0);	// reset
		laptime();	//>> real 5ms	: src.c 4:func(): msg:-	
		return 0;
	}
	// ~$ cc src.c

@param num	only 0. init timer.
@param void/msg	disp spend times from init. 
@details
	save times to static val when set laptime(0). thread-unsafe.
	time precision is 'ms'.
@_note
@conforming posix-2001+
@version 1.0.2, 2021-06-22
-*/
/*SH_ED*/

/*SH_HD*/
#ifndef e56c45531f01
#define e56c45531f01

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

#define laptime(...)		laptime_sub(#__VA_ARGS__, __FILE__,__LINE__, __func__, __VA_ARGS__+0)
void laptime_sub(const char* s, const char* fname, int lnum, const char* fcname, const char* msg);

#endif
/*SH_ED*/

/*SH_SC*/
#include <stdio.h>
#include <unistd.h>
#include <time.h>

#ifdef TEST
#include "*SH_bn*.h"
 #if  (199901L <= __STDC_VERSION__ +0)
	#include "msgp.h"
	#include "hcut.h"
 #endif
#endif

static struct timespec lapbase;
void laptime_sub(const char* str, const char* fname, int lnum, const char* fcname, const char* msg){
	if(str[0]!='\0'&&msg==NULL){ clock_gettime(CLOCK_MONOTONIC, &lapbase);return;}
	struct timespec tbuf;
	clock_gettime(CLOCK_MONOTONIC, &tbuf);
	time_t s = tbuf.tv_sec-lapbase.tv_sec;
	long ns = tbuf.tv_nsec-lapbase.tv_nsec;
	if(ns<0){s--; ns+=1000*1000*1000;}
	double bet = (double)s*1000 + (double)ns/1000/1000;
	fprintf(stderr, "real\t%.3f ms", bet);
	if(msg==NULL){msg="-";}
	fprintf(stderr, "\t: %s %d: %s(): msg:%s\n" ,fname , lnum, fcname, msg);
}

#ifdef TEST
#include <unistd.h>
HCUT_ADD(t_laptime) {
	return;
	laptime(0);
	sleep(1);
	laptime();
	laptime();
	laptime(0);
	laptime("unkokko");
}
#endif

#ifdef TEST
HCUT_RUN("stderr", 1,
t_laptime );
#endif

/*SH_SMP
#include <unistd.h>		//sleep()
#include "*SH_bn*.h"

int main(int argc, char** argv) {
	laptime(0);	//reset
	sleep(1);	
	laptime();		//>> real 9ms	: src.c 4:func(): msg:-
	laptime("hw");	//>> real 10ms	: src.c 5:func(): msg:hw

	laptime(0);	// reset
	laptime();	//>> real 5ms	: src.c 4:func(): msg:-	
	return 0;
}
// ~$ cc src.c *SH_bn*.c
//SH_SMPE*/


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

	* *SH_bn*.c(header): fix #error, edit cmt etc. v1.0.2

2021-02-17  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*/
