#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/>.
*/

/*SH_doc
title=ped section=1
@name	ped
@_brief	sed-style editer using peg
@synopsis
	ped [-e str|-f rulefile] [-n|N] [-r|R] [-t|T] [-hHgVodEL] file/stdin
@tl;dr
	@(code)@
	~$ echo "12a"|ped -re 'ID<-[a-z]+ {_1="Z"}'
		>>> 12Z
	@()
@_desc
	see ~$ ped -h or -H
@copyright
	Copyright (C) 2021 Momi-g --
	License GPLv3+ <https://gnu.org/licenses/gpl.html>.
//SH_docE*/
/*SH_ED*/

/*SH_HD*/
#ifndef ped_main_5906e77bc764
#define ped_main_5906e77bc764
//no header. runner src only

#endif /* inc grd */
/*SH_ED*/

/*SH_SC*/
//set_clists()でgnuregのfastmapが必要
#ifndef _GNU_SOURCE
	#define _GNU_SOURCE
#endif
#include <stdio.h>
#ifndef _DEFAULT_SOURCE
	# inclide "this src needs -D_GNU_SOURCE / glibc"
#endif

#ifndef ERRact
#include <stdio.h>
 #if (199901L <= __STDC_VERSION__ +0)
	#include <sys/types.h>
	#include <unistd.h>
	#define ERRactag	__func__, getpid()
 #else
	#define ERRactag	"func:c99+", 0
 #endif
 #include <string.h>
 #include <errno.h>
 #define ERRact(xpr, msg, act)	if(xpr){ fprintf(stderr, \
	"ERR: %s %d %s() pid:%d %s msg:%s sys:%s\n",__FILE__,__LINE__, ERRactag \
	, "hit(" #xpr ")", msg, strerror(errno) ); act; }
 #define STOP(xpr, msg)	ERRact(xpr, msg, fputs("STOP\n",stderr);exit(1) )
#endif
#define loop(a)		for(int lpcnt=0;lpcnt<a;lpcnt++)

#include "ped.h"	//*SH_co*	libped.a -ldl -lm	*
#include "stringrow.h"
#include "msgp.h"
#include "laptime.h"
#include "optbox.h"

static char optmemo[32]={0};
OPTBOX_SET(opt, "x"
	, (help, "-h", "0", bool )
	, (Help, "-H", "0", bool )
	, (ruleinfo, "-d", "0", bool, strcat(optmemo, "d") )
	, (ignore, "-g", "0", bool)
	, (version, "-V", "0", bool)
	
	, (epeg, "-e", NULL, str)	//rule系はped_new()の邪魔になる
	, (fpeg, "-f", NULL, str)
	
	, (noout, "-n", "0", bool,	strcat(optmemo, "n") )
	, (Noout, "-N", "0",bool,	strcat(optmemo, "N") )
	
	, (regex, "-r", "0", bool,	strcat(optmemo, "r") )
	, (Regex, "-R", "0", bool,	strcat(optmemo, "R") )
	
	, (tree, "-t", "0", bool,	strcat(optmemo, "t") )
	, (Tree, "-T", "0", bool,	strcat(optmemo, "T") )
	
	, (esrc, "-E", NULL, str )
	, (fileout, "-o", NULL,str )
	, (nlstr, "-L", "\\n", str )
)

#define INBUF_SZ	1024
int main(int argc, char** argv){
	int rc=0;
	char* emsg=NULL;
	ped_t* pedvm = NULL;
	FILE* outfp=stdout;
	FILE* infp=stdin;
	char inbuf[INBUF_SZ]={0};
	int inbufsz = INBUF_SZ;
	
	optbox_init(opt, &argc, &argv);
//usage
	if(opt->help || opt->Help || opt->version){
		if(opt->help){optmemo[0]='h';}
		else if(opt->Help){optmemo[0]='H';}
		else if(opt->version){optmemo[0]='V';}
		optmemo[1] = '\0';
		pedvm = ped_new(optmemo, "");	//dmy
		printf("%s\n", pedvm->info);
		goto lb_END;
	}

// selective opt
	if(!opt->epeg && !opt->fpeg){ emsg="opt -e/f is not found"; }
	if(opt->epeg && opt->fpeg){ emsg="-e/f is selective opt"; }
	
	if(opt->noout && opt->Noout){ emsg="-n/N is selective opt";} 
	if(opt->regex && opt->Regex){ emsg="-r/R is selective opt";}
	if(opt->tree && opt->Tree){ emsg="-t/T is selective opt";}
	if(opt->esrc && argc>1){ emsg="-E/file_ag1 is selective opt";}
	; ERRact(emsg, emsg, exit(1););
//env set
	if(opt->fileout){
		outfp = fopen(opt->fileout, "w");
		; ERRact(!outfp, "file open failed",fprintf(stderr,"file: %s\n",opt->fileout); exit(1) );
	}
	//stdin or not
	if(opt->esrc){ infp=NULL; }
	else if(argv[1]){
		infp = fopen(argv[1], "rb");	//bは無視されるが互換性が上がる 常につけるべき
		; ERRact(!infp, "file open failed",fprintf(stderr,"file: %s\n",argv[0]); exit(1) );
	}

//start vm
	//read pegrule
	char* rstr = (char*)opt->epeg;
	int rstrsz = opt->epeg_cmdin ? strlen(opt->epeg): -1;
	if(opt->fpeg){
		errno=0;
		rstr = ped_fileread(opt->fpeg, &rstrsz);
		if(errno){ fprintf(stderr, "%s\n", rstr);free(rstr);goto lb_ERR; }
	}
	//init
	pedvm = ped_new(optmemo, rstr, rstrsz, opt->nlstr);
	if(opt->fpeg_cmdin){ free(rstr);}
	if(pedvm->emsg){ fprintf(stderr, "%s\n", pedvm->emsg);goto lb_ERR; }
	
	//info only
	if(opt->ruleinfo){ printf("%s\n", pedvm->info); goto lb_END; }

//mainloop
	int eflg=0;
	ped_rt res={0};
	res.rc=128;	//first req for stdin
	if(infp==NULL){
		res = ped_parse(pedvm, opt->esrc);
		eflg=1;
	}
	while(1){
		if( (res.rc== -1 || res.rc>0) && eflg==1){
			res=ped_parse(pedvm, NULL);
			continue;
		}
		else if(res.rc== -1){
			sg_t* sg = sg_new();
			while(1){
				size_t sz = fread(inbuf, 1, inbufsz-1, infp);
				if(sz==0 && feof(infp) ){
					eflg=1;
					res = ped_parse(pedvm, sg_ptr(sg), sg_sz(sg) );
					break;
				}
				if(ferror(infp) ){ eflg= -1; fprintf(stderr, "read fp failed\n"); break; }
				sg_add(sg, inbuf, sz);
			}
			sg_free(sg);
			if(eflg<0){ goto lb_ERR; }
			continue;
		}
		else if(res.rc>0){
			size_t sz = fread(inbuf, 1, inbufsz, infp);
//dbg(sz, inbuf);
			if(ferror(infp) ){ fprintf(stderr, "read fp failed\n"); goto lb_ERR; }
			else if(sz==0 && feof(infp) ) {eflg=1;sz= -1;}
			res = ped_parse(pedvm, inbuf, sz);
			continue;
		}
		else if(res.rc == -2){
			fprintf(outfp, "%.*s", res.binsz, res.bin);
			res=ped_parse(pedvm, "");
			continue;
		} //報告 空文字送信
		else if(res.rc == -10){ fprintf(stderr, "%s\n", res.emsg); goto lb_ERR; } //err
		else if(res.rc == 0){ break; } // complete
		else { STOP(1, "fatal err"); }
	}
lb_END:;	
	ped_free(pedvm);
	if(opt->fileout){fclose(outfp);}
	if(argv[1]){fclose(infp);}
	return rc;
lb_ERR:;
	rc=1;
	goto lb_END;
}

#ifdef TEST
	#include <assert.h>
	#include "*SH_bn*.h"	//*SH_co*	libped.a -lm -ldl	*
	#include "hcut.h"
	#include "msgp.h"
	#include "laptime.h"
	#define loop(a)		for(int lpcnt=0;lpcnt<a;lpcnt++)
	#define qu(...)		Qsub(__VA_ARGS__)
	#define Qsub(...)	#__VA_ARGS__
#endif

#ifdef TEST
extern int* clcnt;
HCUT_ADD(t_ped_parse) {
	int rc=0;
	errno=0;
}
#endif

/*SH_SMP
#include "ped.h"	//*SH_co*	libped.a
int main(int argc, char** argv){
	puts("hw");
	return 0;
}

// maincode only
//SH_SMPE*/

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

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

	* *SH_bn*.c (optbox): add -V opt

2021-06-24  Momi-g	<dmy@dmy.dmy>

	* *SH_bn*.c (all): deploy v1.0.0

2021-06-16  Momi-g	<dmy@dmy.dmy>

	* *SH_bn*.c (all): rewrite, make support libso, lbc etc, ver 3

*/
/*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 -static -pedantic -g -pg $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`'|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 ./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 $p'fman $R0 1'|fv		#*/

/*SH_DF
#-- noob
fman()(
bn=ped
fgr0 "${C}doc" "${C}docE"<$1|amn >$bn.$2
mandoc -Thtml <$bn.$2 >${bn}_$2.html
)

#-- local
# f_inc<$Rh>$tf;mv $tf $Rh
f_inc()( awk '
$1=="#include" && $2 =="\"lua.h\"" {next}
$1=="#include" && $2 =="\"luaconf.h\"" {next}
{print}'
)

#-- 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)
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`
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*/
