/*
 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*/
//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;
}



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

// maincode only
//SH_SMPE*/


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

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

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

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

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

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

*/
