%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%   ユーティリティ述語    T.Inaba %%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

:- public read_line/4.
% :- public atom_appends/3.
:- public atom_appends/2.

:- public local_time/1.
:- public p_puts/2.
:- public get_chars_list/4.
:- public write_list/1.
:- public write_listnl/1.
:- public my_system_name/1.

%% 正規表現文字列探索関係
:- public rexpl/3.
:- public rexpl/4.
:- public rexpl/5.
:- public rexpl/6.			% 
:- public pattern_compile/2.
:- public rexpl_search/6.		% 

%% Output with Format
:- public printf/1.
:- public printf/2.
:- public sprintfl/3.
:- public sprintf/3.
:- public spf_format/3.

%% 
:- public call_count_check/1.
:- public call_count_set/1.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% :- extern setof/4.

call_count_check(PG):-
        reset_call_count,
        errorset(PG,Status),
        setof(S,call_count_set(S),P,dec),!,
        nl,write('===CALL COUNT==='),nl,
        write(exec_status=Status),nl,
        write('==== user ===='),nl,
        write_call_count(user,P,Q),
        write('=== system ==='),nl,
        write_call_count(system,Q,R),
        write('=== builtin ==='),nl,
        write_call_count(builtin,R,[]).

write_call_count(Type,[Type/Z/Pred/_|L],R):-
	member(Pred,[s_found,call_count_set,setof]),
        !,write_call_count(Type,L,R).
write_call_count(Type,[Type/Z/X/Y|L],R):-
        !,write(X/Y),write('  =>  '),write(Z),nl,write_call_count(Type,L,R).
write_call_count(_,L,L).

call_count_set(Type/Z/X/Y):-
    current_pred(X,Y),functor(F,X,Y),s_sort(F,Type),get_call_count(X,Y,Z),Z>0.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%manual:- if_win,!,getenv('AZ-Prolog',L),atom_append(L,'\doc\index.html',X),system(X).
%manual:- getenv('AZProlog',L),atom_append(L,'/doc/index.html',X),system(X).

%if_win:- s_version(_,'Win64',_,_),!.
%if_win:- s_version(_,'Win32',_,_),!.

my_system_name(X):-s_atom('init_atom_end',N),M is N+1,s_atom(X,M).

get_chars_list(P,Dm,Cont,L):-get00(P,X),get_chars_list(P,Dm,Cont,X,L).

get00(con,X):-!,get0(X).
get00(P,X):- get0(P,X).

get_chars_list(P,Dm,end,4,[]):- s_version(_,'LINUX',_,_),!.
get_chars_list(P,Dm,end,26,[]):-!.
get_chars_list(P,Dm,cont,Dm,[]):-!.
get_chars_list(P,Dm,Cont,X,[X|L]):- get_chars_list(P,Dm,Cont,L).


p_puts(P,[]):- pp_put(P,31),!.
p_puts(P,[A|L]):- pp_put(P,A),p_puts(P,L).

pp_put(con,A):- !,put(A).
pp_put(X,A):- put(X,A).

write_listnl(X):- write_list(X),nl.
write_list([]):-!.
write_list([A|L]):- write(A),write_list(L).


%%%%%%%%%%%%%%%%%%%%
/*
local_time([Year,Month,DayOfWeek,Day,Hour,Minute,Second,Millisecond]) :-
	clause('$$_time_api_$$',2,1),
	'$$_time_api_$$'(Addr,Buffer),!,
	winCallApi(Addr,[Buffer],0,_,_,_,_),
	winLoadApiArgWORD(Buffer,0,Year),
	winLoadApiArgWORD(Buffer,1,Month),
	winLoadApiArgWORD(Buffer,2,DayOfWeek),
	winLoadApiArgWORD(Buffer,3,Day),
	winLoadApiArgWORD(Buffer,4,Hour),
	winLoadApiArgWORD(Buffer,5,Minute),
	winLoadApiArgWORD(Buffer,6,Second),
	winLoadApiArgWORD(Buffer,7,Millisecond).
local_time(L) :-
	winLoadLibrary('KERNEL32',KERN),
	winGetProcAddress(KERN,'GetLocalTime',Addr),
	winAllocApiArg(16,Buffer),
	s_mode(_,on),
	assert('$$_time_api_$$'(Addr,Buffer)),!,
	s_mode(_,off),
	local_time(L).
*/


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% ＣＳＶ形式ファイルからの行読み込み述語
%%
%%  read_line(-CharList,-PredicateList,+PredList,-Status)
%%
%%  PredList=[dislam=2,ip=4],		% Noは昇順に並べること
%% 
%% ?- read_line(X,Y,[dislam=4,ip=5],Z).
%%
%%   X= "aho,'yaro',tomma,3,baka,4" % 1 Line Asci Char List
%%   Y= [dislam(yaro),ip(3)] 		% 指定カラムを項形式で抜き出す
%%   Z= cont Or end                 % cont=後続行あり end=ファイルエンド
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

read_line(L,Out,Gets,Line):-get0(X),read_line(1,Gets,X,R-R,L,Out,Line).

read_line(N,Gets,31,L-[],[],Datas,cont):-!,names(N,Gets,_,L,Datas-[]).
read_line(N,Gets,26,L-[],[],Datas,end ):-!,names(N,Gets,_,L,Datas-[]).
read_line(N,Gets,44,List-[],[44|Rest],Datas,Line):-
    !,names(N,Gets,OGets,List,Datas-Else),
    get0(X),NN is N+1,read_line(NN,OGets,X,Y-Y,Rest,Else,Line).
read_line(N,Gets,X,List-[X|L],[X|Rest],R,Line):- 
    get0(Y),read_line(N,Gets,Y,List-L,Rest,R,Line).

names(N,[N|L],L,[W|List],[(D,List2)|R]-R):- 
    !,check_dq0(W,List,List2),name(D,List2).
names(N,[Pred=N|L],L,[W|List],[X|R]-R):- 
    !,check_dq0(W,List,List2),name(D,List2),X=..[Pred,D].
names(N,L,L,_,D-D).

check_dq0(39,A,B):-check_dq(39,A,B),!.  % "
check_dq0(34,A,B):-check_dq(34,A,B),!.  % '
check_dq0(W,A,[W|A]).

check_dq(W,[W],[]):-!.
check_dq(W,[],[]):-!.
check_dq(W,[Q|A],[Q|B]):- check_dq(W,A,B).

%%%%%%%%

% atom_appends(A,B,C):- term_atom(A,AA),atom_appends0(AA,B,C).
atom_appends(B,C):- atom_appends0('',B,C).

atom_appends0(L,[],L):-!.
atom_appends0(M,[A|L],O):-  
	term_atom(A,AA),atom_append(M,AA,M2),atom_appends0(M2,L,O).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%           UTILITY 正規表現(2003.5.16版)                         %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   非決定性述語。バックトラックしながら、次検索解をかえします。
%
% Usage:
% ?-rexpl(String,    検索対象文字列リスト(または、atomic,Float,Term)
%         Pattern,   検索パターン　（文字列List,Atom,Atomic-List)
%         Get,       検索された文字列リスト
%         Else,      検索残り文字列リスト
%         Before,    検索された文字列リストまでの文字列
%         Parts).    部分検索文字列リストのリスト
%
% 例：
% | ?-rexpl("test Port 3: 324Kbps,NM 606 aho baka ",
%           "Port[ ]*3:[ ]*([0-9]+)Kbps,NM[ ]*([0-9]+)",
%            A,B,C,[X,Y]).
%
% A       = "Port 3: 324Kbps,NM 606"
% B       = " aho baka "
% C       = "test "
% X       = "324"
% Y       = "606"
%
% 【第一引数：対象文字列リスト】
% 
%  1)文字列リスト  例："abcdefg hijke" 
%  2)アトム／数値  例：'abceef adsf'   124563     123.2233
%  3)評価式
%      3-1)  call(X,述語(X))のとき、述語(X)を評価した結果のＸを対象文字列とします。
%
%            ?-rexpl(call(Z,atom_append(abc,def,Z)),"b[a-z]{2}",Y).
%            Y = "bcd"
%
%      3-2)  is(X,計算式)のとき、計算式を評価した結果のＸを対象文字列とします。
%
%            ?-rexpl(Z is 3*sin(0.5),"\.[0-9]{5}",Y).
%            Y = ".43827"
%  4)その他の項    例： a(bcd,e)   "a(bcd,e)" と等価（変数が含まれるときは要注意）

% 【第２引数：正規表現検索パターン】
%
%  1)後述のパターン記述子と任意の文字列からなるパターンの文字列のリスト
%  2)後述のパターン記述子と任意の文字列からなるパターンの文字列のアトム
%  3)アトムと数値からなるリストでこれらを結合したものがパターンとなる
%    変数は、述語評価時までに値が決定されている必要がある
%    １）と区別するために、関数子 pattern/1の引数として与える
%    例：pattern( [ 'Port[ ]*:',3,'[ ]*' ] )
/*
<<<<<<<< 検索正規表現に記述可能なパターン記述子 >>>>>>>>>>

.		任意の１文字とマッチ（ダブルバイト文字も１文字。ただし、kanji_mode(_,on)のとき）

[] 		角かっこに囲まれた文字のうちの任意の 1 文字、または、
		ハイフン (-) で区切られた文字範囲のうちの任意の１文字にマッチ。
		たとえば、b[aeiou]d は bad、bed、bid、bod、および bud にマッチ
		また、r[eo]+d は red、rod、reed、および rood にはマッチするが、
		reod や roed にはマッチしない。x[0-9] は x0、x1、x2 などにマッチ。

		角かっこ内にカレット (^) を指定すると意味が反対になる、
		カレットに続く文字以外のすべての文字にマッチ
		たとえば、x[^0-9] は xa、xb、xc などにはマッチしますが、
		x0、x1、x2 などにはマッチしません。
		＾とそれ以外は混在可能。順序は問わない。

		例：[a-z^e-h^40-9]  
		   a〜ｚ、0〜9のうちe〜hと4を除いた文字とマッチする
		   すなわち、"abcdijklmnopqrstuvwxyz012356789" のどれかとマッチ

		＾指定のみで、メンバー指定が含まれないときは、含まれてはいけない
		文字だけを指定されたとみなす。


(s1|s2|...)  
        文字列 s1 または s2 または ... とマッチします。
        文字列には正規表現が使用できます。  

(s1)    文字列 s1 とマッチします。部分文字列として、順番にリスト化されます
		文字列には正規表現が使用できます。
		s1のなかにさらに(s0)があるときは結果は入れ子リストとなります
		s1のなかに｜があるとＯＲとみなされるので、必要があるときは、
		エスケープします。(s1\|s2)
		部分パターンの指定は再帰的です。たとえば、
		 " abc(def(ghiq) (aaa)) "はトップレベルで一要素の部分パターン、
		 部分パターンのなかにさらに２要素の部分パターンを含みます。
		 

^ 		行の先頭にマッチします。正規表現の最初にあるときのみ有効です。  
$ 		行の末尾にマッチします。正規表現の最後にあるときのみ有効です。  

%% 繰り返し
* 		直前にある文字または正規表現の０回以上の繰り返しにマッチします。
		たとえば、ba*c は bc、bac、baac、baaac などにマッチします。  

+		直前にある文字または正規表現の１回以上の繰り返しにマッチします。
		たとえば、ba+c は bac、baac、および baaac にはマッチしますが、
		bc にはマッチしません。  

? 		直前にある文字または正規表現の０回または１回の繰り返しにマッチ。
		たとえば、ba?c は bac、bc にはマッチしますが、baac にはマッチしない

{数値}  直前にある文字または正規表現の数値の回数繰り返しにマッチ。

%% エスケープ文字 ( ¥ )

\n    改行コード(Asci 31)とマッチ
\t    タブ(Asci 9)とマッチ
\b    バックスペース(Asci 8)とマッチ
\(7)  7 アスキーコード7とマッチする
     "(7)"とマッチさせたいときは、"\(\7\)"
\N N:一桁数字 (\1...\9) 部分パターンのN番目とマッチします。
     　例：　"abc(def) (p) zzz \2\1"　は、"abcdef p zzz pdef"とマッチします。

\Any  Any  たとえば、\[ は　[ 、  \- は -、\\ は　\ とマッチする

\< 		%英字で始まる英数字列単位での検索を行います。
		（^ を除く）正規表現の最初にあるときのみ有効です。  
\>		%英字で始まる英数字列単位での検索を行います。
		（$ を除く）正規表現の最後にあるときのみ有効です。  
\w		英数文字と"_"のみからなる文字とマッチします。
\W		
*/

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% 基本形
rexpl(Data,Pattern,Get,Else,Before,Parts):-
	data_compile(Data,String),
	pattern_compile(Pattern,P2),
	rexpl_members0(String,P2,Get,Else,Before,Parts).

%% 後方引数がいらないときの述語
rexpl(String,Pattern,Get):-             rexpl(String,Pattern,Get,_,_).
rexpl(String,Pattern,Get,Else):-        rexpl(String,Pattern,Get,Else,_).
rexpl(String,Pattern,Get,Else,Before):- rexpl(String,Pattern,Get,Else,Before,_).

%% 検索文字列の変換
data_compile([],_):-!,fail.
data_compile(Data,Data):-list(Data),!.
data_compile(is(X,Y),String):- !,X is Y,name(X,String).
data_compile(call(X,Y),String):-!,call(Y),!,data_compile(X,String).
data_compile(Data,String):-term_atom(Data,String1),name(String1,String).

%%%%% 検索を非決定性に次々にサーチするための細工
rexpl_search(A,B,C,D,E,F):- rexpl_members0(A,B,C,D,E,F).

rexpl_members0(S,[head|P],G,E,Bf,SS):-!,rexpl_membersxh(S,P,G,E,Bf,SS).
rexpl_members0(S,P,G,E,B,SS):-!,rexpl_membersx(S,P,G,E,B,SS).			 

%% ^指定の場合
%% 解を得た後,バックトラックで残りの検索対象リストの再検索
%% １文字単位で再検索をするのであれば、rexpl_members/6　のみでＯＫだが。。
rexpl_membersxh(A,B,C,D,Bf,S):-  
	rexpl_member(0,A-DD,B,CC-[],Se-[],Se),!,
	(C=CC,D=DD,Se=S,Bf=B;					%ここで第一解を返す
		rexpl_search_head(DD,DDH,Bf-R),
		rexpl_membersxh(DDH,B,C,D,R,S) ).   %バックトラックしたら先の残りから検索
rexpl_membersxh(A,B,C,D,Bf,S):-  
	rexpl_search_head(A,AH,Bf-R),
	rexpl_membersxh(AH,B,C,D,R,S).

rexpl_search_head([31|DDH],DDH,L-L):-!.
rexpl_search_head([13,10|DDH],DDH,L-L):-!.
rexpl_search_head([13|DDH],DDH,L-L):-!.
rexpl_search_head([X|DDH],DDA,[X|L]-R):- rexpl_search_head(DDH,DDA,L-R).

%% 解を得た後,バックトラックで残りの検索対象リストの再検索
%% １文字単位で再検索をするのであれば、rexpl_members/6　のみでＯＫだが。。
rexpl_membersx(A,B,C,D,Bfe,Se):- 
	rexpl_members(A,B,CC,DD,Bf,S),
	(C=CC,D=DD,Bfe=Bf,Se=S;					%ここで第一解を返す
		rexpl_membersx(DD,B,C,D,Bfe,Se)).   %バックトラックしたら先の残りから検索

%% 先頭からパターンを調べＦａｉｌしたら先頭を省いてパターンを調べる
rexpl_members(L,Pa,Get,E,[],Part):- 
	list(L),
	rexpl_member(0,L-E,Pa,Get-[],Part-[],Part),
	Get \== [],!.								% Do You Need Cut? 	Yes !.
rexpl_members([A|L],Pa,Get,E,[A|LL],Part):- 
	rexpl_members(L,Pa,Get,E,LL,Part).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%% パターンマッチ本体 %%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% rexpl_member(Flag,SearchString-Rest,SearchPattern,GetP,PartGetList,PartPointer)

	%% 終了条件
rexpl_member(_,L-L,              [],      G-G,  P-P,_):-!.    % パターン終わり
	%% パターン一つづつのループ
rexpl_member(F,L-L3,[Pat|Patterns],G-G3,Part,Q):-   % 先頭パターンが
	rexpl_m(Pat,F,L-L2,G-G2,Part,Part2,Q),			% 文字列からマッチしたら
	rexpl_member(F,L2-L3,Patterns,G2-G3,Part2,Q).	% 残分のパターンマッチを調べる

%%%%% パターン別処理

%% １対１の文字コードマッチ
rexpl_m(X, F,[X|L]-L,[X|G]-G,Part,Part2,_):-!,part_in(F,X,Part,Part2).

rexpl_m(head,_,R-L,G-G,Part,Part,_):-!,rexpl_m_head(R,L).		% 行頭と＾のマッチ

	rexpl_m_head([31|L],L):-!.		% 行頭と＾のマッチ
	rexpl_m_head([13,10|L],L):-!.	% 行頭と＾のマッチ
	rexpl_m_head([13|L],L):-!.		% 行頭と＾のマッチ

rexpl_m(end,_,R-L,G-G,Part,Part,_):-!,rexpl_m_end(R,L).		% 行頭と＾のマッチ

	rexpl_m_end([],       []):-!.       % 文末と$のマッチ
	rexpl_m_end([26|L],   L):-!.    % 文末と$のマッチ
	rexpl_m_end([31|L],   [31|L]):-!.    % 行末と$のマッチ
	rexpl_m_end([13,10|L],[31|L]):-!.    % 行末と$のマッチ
	rexpl_m_end([13|L],   [31|L]):-!.    % 行末と$のマッチ

% 全ての文字コードとマッチ
rexpl_m('?',F,[X|L]-L,[X|G]-G,Part,Part2,_):-!, part_in(F,X,Part,Part2).

%% 部分パターン結果の再指定  \1
%% ?-rexpl("私達は私達の信念に基ずいて活動しています","((私|私達))は\1の",A).

rexpl_m(part(N),F,L,G,P-T,T2-T,Q):-
	!,get_part_fromQ(N,Q,X0),					    % 再指定パターン取得
	rexpl_member(F,L,X0,G,P-T2,Q).					% 部分要素の検索

%% メンバー指定　　　[a-z],[^]
rexpl_m(member(M,N),F,[X|L]-L,[X|G]-G,Part,Part2,Q):-
	!,(list(M) -> sk_member(X,M);true),				% [文字候補]
	\+ sk_member(X,N),		                        % [^文字候補]
	part_in(F,X,Part,Part2).

%% ?- rexpl("私達はAI班です","(私|私達)はAI班です",A). 
%% OR指定　(s1|s2|s3...)
rexpl_m((X;_),F,L,G,Part-T,T2-T,Q):-				% (s1|s2|s3....) 非決定
	 rexpl_member(F,L,X,G,Part-T2,Q).

rexpl_m((_;X),F,L,G,Part-T,T2-T,Q):-				% (s1|s2|s3....)
	 !,rexpl_member(F,L,X,G,Part-T2,Q).

%% 部分要素指定  "pattern(pattern2)"
rexpl_m([],_,L-L,G-G,[[]|P]-T,P-T,_):-!.

rexpl_m(X0,_,L,G,[Part0|P]-T,P-T,Q):-
	list(X0),!,							            
	rexpl_member(1,L,X0,G,Part0-[],Q).				% 部分要素の検索

%%%%%%%%%%%%%%%%%%%%
%% パターンの繰り返し


%%  0または１回以上
rexpl_m(reps(*,Z),F,L,G,P-T,T3-T,Q):- 						% Over 0
	rexpl_m(reps(+,Z),F,L,G,P-T2,T2-T3,Q).
rexpl_m(reps(*,Z),_,L-L,G-G,P,P,_):-!.						% 0 回  非決定

rexpl_m(reps(*/,Z),F,L,G,P-T,T3-T,Q):- 						% Over 0
	rexpl_m(reps(+/,Z),F,L,G,P-T2,T2-T3,Q),!.
rexpl_m(reps(*/,Z),_,L-L,G-G,P,P,_):-!.						% 0 回  非決定

rexpl_m(reps(*?,Z),_,L-L,G-G,P,P,_).						% 0 回  非決定
rexpl_m(reps(*?,Z),F,L,G,P-T,T3-T,Q):-!, 					% Over 0
	rexpl_m(reps(+?,Z),F,L,G,P-T2,T2-T3,Q).

%% １回以上限定の繰り返し	
rexpl_m(reps(+,part(N)),F,L-L,G-G,P,P,Q):-				% 再指定パターンが空の繰り返なら
	get_part_fromQ(N,Q,[]),!.							% 無限ループ回避のために強制成功

rexpl_m(reps(+,Z),F,L-L2,G-G2,P-T,T3-T,Q):-!,			% Over 1
	Z \== [],
	rexpl_member(F,L-L1,[Z],G-G1,P-T1,Q),				% １回は現れる
	rexpl_m(reps(*,Z),F,L1-L2,G1-G2,T1-T2,T2-T3,Q).		%  !!!!!

rexpl_m(reps(+/,Z),F,L-L2,G-G2,P-T,T3-T,Q):-!,			% Over 1
	Z \== [],
	rexpl_member(F,L-L1,[Z],G-G1,P-T1,Q),				% １回は現れる
	rexpl_m(reps(*/,Z),F,L1-L2,G1-G2,T1-T2,T2-T3,Q),!.		%  !!!!!

rexpl_m(reps(+?,Z),F,L-L2,G-G2,P-T,T3-T,Q):-!,			% Over 1
	Z \== [],
	rexpl_member(F,L-L1,[Z],G-G1,P-T1,Q),				% １回は現れる
	rexpl_m(reps(*?,Z),F,L1-L2,G1-G2,T1-T2,T2-T3,Q).	%  !!!!!

%%１回ないし０回現れるパターン
rexpl_m(reps(?,Z),F,L,G,P-T,T2-T,Q):- 					% 1 回
	rexpl_member(F,L,[Z],G,P-T2,Q).
rexpl_m(reps(?,Z),_,L-L,G-G,P,P,_):-!.					% 0 回  非決定

rexpl_m(reps(?/,Z),F,L,G,P-T,T2-T,Q):- 					% 1 回
	rexpl_member(F,L,[Z],G,P-T2,Q),!.
rexpl_m(reps(?/,Z),_,L-L,G-G,P,P,_):-!.					% 0 回  非決定

rexpl_m(reps(??,Z),_,L-L,G-G,P,P,_).					% 0 回  非決定
rexpl_m(reps(??,Z),F,L,G,P-T,T2-T,Q):-!,				% 1 回
	rexpl_member(F,L,[Z],G,P-T2,Q).

%% Ｎ件のパターン指定がある場合
rexpl_m(reps(0,Z),_,L-L,G-G,P,P,_):-!.
rexpl_m(reps(N,Z),F,L-L3,G-G2,P-T,T3-T,Q):-
	integer(N),N>0,!,NN is N-1,
	rexpl_member(F,L-L2,[Z],G-G1,P-T1,Q),
	rexpl_m(reps(NN,Z),F,L2-L3,G1-G2,T1-T2,T2-T3,Q).

%%%%%%部品%%%%%%
%% 要素検索
:- mode sk_member(integer,list).

sk_member(X,[X|_]):-!.					%% そのものである
sk_member(X,[?|_]):-!.					%% 何でもよい
sk_member(X,[A-B|_]):-A=<X,X=<B,!.		%% 範囲に含まれている
sk_member(X,[_|L]):- sk_member(X,L).

%% 部分要素リストの生成
part_in(0,_,L,L):-!.			%不要なとき
part_in(1,X,[X|L]-P,L-P):-!.	%必要なとき

get_part_fromQ(1,Q,X0):- nonvar(Q),!,Q=[X0|_].
get_part_fromQ(N,Q,X0):- 
	nonvar(Q),N>1,!,NN is N-1,Q=[_|L],get_part_fromQ(NN,L,X0).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 正規表現を予め処理しやすいように変換する %%
%%   pattern_compile/2                      %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
pattern_compile(A,B):- list(A),!,pattern_comp1(A,B),!.					% 文字列ならそのまま解析
pattern_compile(A,B):- atom(A),!,name(A,AL),pattern_compile(AL,B).			% アトムなら文字列へ変換して再帰
pattern_compile(pattern(A),B):- atom_appends(A,AL),pattern_compile(AL,B).	% アトムリストなら結合して再帰

%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% 解析メインルーチン %%%
%%%%%%%%%%%%%%%%%%%%%%%%%%
pattern_comp1([94|L],[head|B]):-!,pattern_comp(L-[],B).    % 行頭の＾
pattern_comp1(L,B):-pattern_comp(L-[],B).

pattern_comp("$"-[],[end]):-!.					% 行末の＄
pattern_comp([Cd|L1]-Rest,[P2|Patterns]):-		% 先頭文字コード Cdを
	one_comp(Cd,L1-L2,P1),!,					% 解析しパターンP1を得て
	reps(L2-L3,P1,P2),							% 繰り返しをチェックしたパターンP2を得
	pattern_comp(L3-Rest,Patterns).				% 次の解析へ
pattern_comp(L-L,[]).							% 終了パターン

%%% 一文字（およびそれ以降の任意のパターン）解析ルーチン

:- mode one_comp(integer,+,-).

one_comp(92, DList,C):-!,				% "\〜" ESC 文字  2012.3.5 T.Inaba kanji_mode(_,off)対応
	esc(DList,C).
one_comp(40, L-L2,Part2):-!,			% "("が現れたら部分解析開く
	pattern_comp(L-L1,Part),			%    再帰的に部分解析を行い、
	part_pattern(L1-L2,Part,_,Part2).	%    部分終了タイプ別に処理
one_comp(41, _,_):-!,fail. 				% ")" は部分解析END
one_comp(46, L-L, '?'):-!. 				% "." は何でもＯＫ
one_comp(91, L-L1,member(M,N)):-!,		% "["ではじまり"]"で終わるまで
	pat(L-[93|L1],M-[],N-[]).			%  は要素と非要素の指定
one_comp(124,_,_):-!,fail.				% "|" は部分解析区切り
one_comp(X,  L-L,X).					% その他の文字コードは1対1照合

%%% 部分パターン、ORの場合のタイプ別処理
%% Part=PatternList OR=(PatternList;PatternList) または　(PatternList;[OR])

part_pattern([41 |L]-L,  Part,Part,Part):-!.				% ")"で終わり
part_pattern([124|L1]-L3,Part,[(Part;OR)],(Part;OR) ):-		% "|"はOR区切り
	pattern_comp(L1-L2,Part1),								% 再度部分パターンコンパイル
	part_pattern(L2-L3,Part1,OR,_).							% 再部分の終了タイプ別処理

%%% パターンの繰り返しポストフィックス
%%%  [0-9]*  a+  a?  a{10} 

reps([X,X1|L]-L,C,reps(Y,C)):-assoc([X,X1],Y,["*?",*?,"+?",+?,"??",??,"*/",*/,"+/",+/,"?/",?/]),!.	% ０回以上 1回以上の ０回または１回の繰り返し
reps([X|L]-L,   C,reps(Y,C)):-assoc([X],Y,["*",*,"+",+,"?",?]),!.	% ０回以上 1回以上の ０回または１回の繰り返し
reps([123|L]-R, C,reps(N,C)):-pick_num(L-[125|R],Q-Q,N),!.			% "{"で始まって数値コード並び "}" で閉じる
reps(L-L,C,C).                                    					% 繰り返しなし

%%% "["と"]" で囲まれたパターン表現
%%% 文字並び   メンバー  非メンバー
pat(L-L,       M-M,    N-N):-!.
pat([94|L]-L2, Mem,    Not-Te):-!,pat0(L-L1,Not-T),!,pat(L1-L2,Mem, T-Te).
pat(L-L2,      Mem-Te, Not   ):-  pat0(L-L1,Mem-T),!,pat(L1-L2,T-Te,Not).

pat0([A,45,B|L]-L,[A-B|M]-M).					% A-B
pat0([92|L]-E,    [C|M]-M):- esc(L-E,C),!.		% \A
pat0([46|L]-L,    [?|M]-M).						% .
pat0([A|L]-L,     [A|M]-M).						% A

%%% ESC文字
esc([X|L]-L,  Y):-assoc([X],Y,["n",31, "t",9, "b",8]),!.	% "\n"=>31 "\t"=>9  "\b"=>8
esc([40 |L]-R,N):- pick_num(L-[41|R],Q-Q,N),!.				% "\(10)"  => 10 
esc([C|L]-L,part(N) ):- is_between(C,49,57),!,name(N,[C]).	% "\1"  => part(1)
esc([X|L]-L,  X).

%%% 連想文字変換、数値ピックアップなどの雑ユーティリティ
assoc(X,Y,[X,Y|_]):-!.
assoc(X,Y,[_,_|L]):- assoc(X,Y,L).

pick_num(L-L,Q-[],N):-!,name(N,Q).					% 空になったら、数値コード並びを数値化
pick_num([C|L]-R,Q-[C|T],N):-is_between(C,48,57),!,pick_num(L-R,Q-T,N).	% 数値コードならキュー保存

is_between(C,X,Y):- X=<C,C=<Y.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% printf 
/* 

%% Special Char Format 
\n	復帰改行	0A
\a	警報音		07
\t	タブコード	09
\b	バックスペース	08
\\	文字としての \	5C
\'	文字としての '	2C
\"	文字としての "	22
\0	文字列終了コード 0

%s %c %f %d %x %o

%%%%
test:-
	C  = 66,
	S  = aho, 
	S2 = baka(tomma),
	D  = 321, 
	F  = 12345.6789,
	printf("c[66]=%c aho=%s baka(tomma)=%.15s\n",[C,S,S2]),
	printf("decimal:%d\t=octal:%o\t=hex:%x\n",   [D,D,D]),
	printf("%f=%3.2f=%0.6f\n",                   [F,F,F]).

% ?- sprintf(-Atom,+Format(list or atom),+TermList).
*/


printf(Format):- printf(Format,[]).

printf(Format,List):- sprintf(Out,Format,List),write(Out).

sprintfl(OutL,Form,List):-
	( list(Form) -> FormO=Form;name(Form,FormO)),
	errorset(spf_format(FormO,List,OutL),succ),!.

sprintf(Out,Form,List):-
	sprintfl(OutL,Form,List),
	name(Out,OutL).

%%%
spf_format([],_,[]):-!.
spf_format([0'5c,X|L],Map,A):-    	% \n etc 
	!,spf_esc([X],A,R),spf_format(L,Map,R). 
spf_format([0'25|L],Map,S):- 		%  %15s etc
	!,spf_format2(L,L2,Map,Map2,S,S2),spf_format(L2,Map2,S2).
spf_format([A|L],Map,[A|S]):- spf_format(L,Map,S).

  %% \n \a etc
%spf_esc("n", [0'a|R],R):- s_version(_,'LINUX',_,_),!.
%spf_esc("n", [0'd,0'a|R],R):- !.
spf_esc("n", [31|R],R):- !.
spf_esc("a", [0'7|R],R):-!.
spf_esc("t", [0'9|R],R):-!.
spf_esc("b", [0'8|R],R):-!.
spf_esc("""",[0'22|R],R):-!.
spf_esc("%", [0'25|R],R):-!.
spf_esc("'", [0'2c|R],R):-!.
spf_esc("\", [0'5c|R],R):-!.
spf_esc("0", [0|R],R).

  %% %s %d etc
spf_format2(L,L2,[Term|Map],Map,S,S2):-
	spf_type_get(L,L2,Type,0,ALL,Under),
	spf_check_num(ALL,ALLC),spf_check_num(Under,UnderC),
	spf_make_data(Type,Term,ALLC,UnderC,S,S2).

spf_check_num([],0):-!.
spf_check_num(X,Vol):- name(Vol,X).

spf_type_get([ 99|L],L,c,_,[],[]):-!.	 %c  CharCode
spf_type_get([100|L],L,d,_,[],[]):-!.	 %d  Decimal=>10 
spf_type_get([102|L],L,f,_,[],[]):-!.	 %f  float  
spf_type_get([111|L],L,o,_,[],[]):-!.	 %o  decimal=>8
spf_type_get([115|L],L,s,_,[],[]):-!.	 %s  String
spf_type_get([120|L],L,x,_,[],[]):-!.	 %x  decimal=>16
spf_type_get([46|L],R,Type,_,[],Under):-  % .
	!,spf_type_get(L,R,Type,1,_,Under).
spf_type_get([A|L],R,Type,0,[A|ALL],Under):-  % 
	!,spf_type_get(L,R,Type,0,ALL,Under). 
spf_type_get([A|L],R,Type,1,ALL,[A|Under]):-
	!,spf_type_get(L,R,Type,1,ALL,Under). 

%%%%%%%%%%%%%%%%%%%%%%%%%%
%%  %s %s.12s %s5s %s5.12s
spf_make_data(s,Term,ALL,Under,S,S2):-
	!,term_atom(Term,Atom),atom(Atom,AtomLen),
	spf_get_atom_len(AtomLen,ALL,Under,Len),
	name(Atom,List),
	(AtomLen > Len 
		-> spf_reduce_atom(Len,List,S,S2);
		SP is Len-AtomLen,spf_add_sp(SP,List,S,S2) ).

   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
spf_get_atom_len(Len,0,0,Len):-!.
spf_get_atom_len(_,0,Len,Len):-!.
spf_get_atom_len(_,Len,0,Len):-!.

spf_reduce_atom(0,_,S,S):-!.
spf_reduce_atom(N,[A|L],[A|R],S):- NN is N-1,spf_reduce_atom(NN,L,R,S).

spf_add_sp(0,L,LS,S):-!,append(L,S,LS).
spf_add_sp(N,L,[32|LS],S):- NN is N-1,spf_add_sp(NN,L,LS,S).

%%%%%%%%%%%%%%%%%%%%%%%%%%
%%  %c 
spf_make_data(c,Int,ALL,Under,[Char|S],S):-
	!,Char is Int and 0'ff.
%%%%%%%%%%%%%%%%%%%%%%%%%%
%%  %d  
spf_make_data(d,Int,ALL,Under,Out,S):-
	!,integer(Int),
	(Int<0 -> Int2 is -1*Int,Out=[45|Out2] ;Int2=Int ,Out=Out2),
	name(Int2,Chars),append(Chars,S,Out2).
%%%%%%%%%%%%%%%%%%%%%%%%%%
%%  %o  Integer --> Octal
spf_make_data(o,Int,ALL,Under,Out,S):-
	!,integer(Int),
	(Int<0 -> Int2 is -1*Int,Out=[45|Out2] ;Int2=Int ,Out=Out2),
	(Int2==0 -> Out2=[48|S];spf_ch8(Int2,Out2,S)).

spf_ch8(0,S,S):-!.
spf_ch8(Int,Out,S):-
	AA is "0"+ (Int mod 8),B is Int // 8,
	spf_ch8(B,Out,[AA|S]).

%%%%%%%%%%%%%%%%%%%%%%%%%%
%%  %x  Integer --> Hex 
spf_make_data(x,Int,ALL,Under,Out,S):-
	!,integer(Int),
	(Int<0 -> Int2 is -1*Int,Out=[45|Out2] ;Int2=Int ,Out=Out2),
	(Int2==0 -> Out2=[48|S];spf_ch16(Int2,Out2,S)).

spf_ch16(0,S,S):-!.
spf_ch16(Int,Out,S):-
	A is Int mod 16,B is Int // 16,
	(A <10 -> AA is "0"+A;AA is "A"+A-10),
	spf_ch16(B,Out,[AA|S]).

%%%%%%%%%%%%%%%%%%%%%%%%%%
%%  %f %5.2f   Float
spf_make_data(f,F,_,Under,Out,S):-
	!,float(F),name(F,Fchars),
	spf_ch_f(Fchars,Under,Out,S).

  % %f
spf_ch_f(Fchars,0,Out,S):- !,append(Fchars,S,Out).
  % %4.3f
spf_ch_f(Fchars,N,Out,S):- !,spf_make_f(Fchars,0,N,Out,S).

spf_make_f(_,1,0,S,S):-!.
spf_make_f([],1,N,[48|Out],S):-!,NN is N-1,spf_make_f([],1,NN,Out,S).
spf_make_f([A|FC],1,N,[A|Out],S):-!,NN is N-1,spf_make_f(FC,1,NN,Out,S).
spf_make_f([46|Fchars],_,N,[46|Out],S):-!, spf_make_f(Fchars,1,N,Out,S).
spf_make_f([A|Fchars],0,N,[A|Out],S):- spf_make_f(Fchars,0,N,Out,S).

