%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Sample Of Child Prolog Process Management %%
%%           2009.07.01 T.Inaba SOFNEC.CO.JP %%
%
% How To Compile
% Parent Prolog
%  >azpc -p setof.pl utility.pl grammar.pl mlt_parent.pl azedit.pl /i /e prolog
%
% Child Prolog(With Parent)
%  >azpc -p setof.pl utility.pl grammar.pl mlt_child.pl mlt_parent.pl /i /dcurses /e prolog_c
%
% Stand Alone 
%  >azpc -p setof.pl utility.pl grammar.pl mlt_child.pl mlt_parent.pl YourProgram.pl /dcurses /e YourExeName

% Using Next Special Builtin Predicate
% s_child/5       % 子プロセスを立ち上げる.   s_child(+実行形式プログラム,+[パラメータ並びリスト],-InputStream,-OutputStream,-ProcessID)
% s_kill/2        % プロセスを削除する.       s_kill(+ProcessID,0).  % 第二引数めはＵｎｉｘとの引数互換のためであり、意味はない
% s_flush/0       % 標準出力バッファをフラッシュする.  対向（親）プロセス側で読み込めるようにする。  
% s_can_read/1    % OutputStreamから読み込み可能な場合（子プロセス側で標準出力にwriteq+"."+s_flushされている場合）にのみ成功する。

:- extern c:'Parent_top_level'/0.    % 本来のインタプリタトップレベル。起動時引数-childでfailする
:- bltin read/1.
:- bltin b_load/1.
:- bltin consult/1.
:- bltin compile/1.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% -p 以前に-child があると子プロセス用のループにはいる
%% 子プロセスのとき　-p 以降にconsult(ファイル名)があると起動時にPrologソースファイルをコンサルトする
%% 子プロセスのとき　-p 以降にb_load(ファイル名)があると起動時にバイトコンパイル済みファイルをロードする
%% 子プロセスのとき　-p 以降にcompile(ファイル名)があると起動時にバイトコンパイルしたファイルをロードする
%% 子プロセスのとき　標準入力からread/1した項をCallし、結果を標準出力にwriteq/1し、入力待ちに戻る。
%% 　　　readした項が2要素のリストのとき、前者をＣａｌｌし、後者を結果として出力する 例：　[put([1,2,3,4],[],L),L]
%% 　　　ゴールのみの時とエラー、Ｆａｉｌのときは status({init;read;exec},{succ;fail;Error番号})を返す

  %% TopLevel For Child Process
top_level:-
	ctr_c_control,
	'Parent_top_level',!.
top_level:-
	set_write_list_length(_,0),prompt(_,''),errormode(_,0),
	get_parameter(Param),mlt_param(Param),
	repeat,
		mlt_errorset_cut(read(X),read),
		mlt_exec_cmd(X),
	fail.

ctr_c_control:- s_version(_,'LINUX',_,_),!.
ctr_c_control:-
   winLoadLibrary('KERNEL32',KERN),
   winGetProcAddress(KERN,'SetConsoleCtrlHandler',Addr),
   ( winCallApi(Addr,[0,0],0,1,_,_,_) ; winCallApi(Addr,[0,1],0,1,_,_,_) ,fail). 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Child Process Processing

mlt_errorset_cut(X,Phase):- errorset(X,Y),!,mlt_errorset_cut_check(Y,Phase).

mlt_errorset_cut_check(succ,Phase):-!.
mlt_errorset_cut_check(Y,Phase):- mlt_output(status(Phase,Y)),fail.

mlt_exec_cmd([X,Out]):-   !,mlt_errorset_cut(X,exec),mlt_output(Out).
mlt_exec_cmd({X,Out}):-   !,errorset(X,Y),(Y==succ -> mlt_output(Out),fail ; mlt_output(status(exec,Y))),!.
mlt_exec_cmd({{X,Out}}):- !,errorset(X,Y),(Y==succ -> mlt_output0(Out),fail ; mlt_output(status(exec,Y))),!.
mlt_exec_cmd(X):-         mlt_exec_cmd([X,status(exec,succ)]).

mlt_output(X):- writeq(X),write('.'),nl,s_flush.
mlt_output0(X):- writeq(X),write('.'),nl.

%%% 起動時引数チェック
mlt_param([]):-!.
mlt_param([B|L]):- term_atom(A,B),mlt_cmd(A),mlt_param(L).

mlt_cmd(consult(X)):-mlt_errorset_cut(consult(X),init),!.
mlt_cmd(b_load(X)) :-mlt_errorset_cut(b_load(X),init),!.
mlt_cmd(compile(X)):-mlt_errorset_cut(compile(X),init),!.
mlt_cmd(assert(X)) :-mlt_errorset_cut(assert(X),init),!.
mlt_cmd(exec(X))   :-mlt_errorset_cut(X,init),!.
mlt_cmd(_).
