%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2008-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. %% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. %% %% %CopyrightEnd% %% %%%------------------------------------------------------------------- %%% File : gl_gen.erl %%% Author : Dan Gudmundsson <dgud@erix.ericsson.se> %%% Description : %%% %%% Created : 16 Apr 2007 by Dan Gudmundsson <dgud@erix.ericsson.se> %%%------------------------------------------------------------------- -module(gl_gen). -export([code/0]). -include_lib("xmerl/include/xmerl.hrl"). -include("gl_gen.hrl"). -import(lists, [foldl/3,foldr/3,reverse/1,reverse/2,keysearch/3,map/2,filter/2]). -import(proplists, [get_value/2,get_value/3]). -import(gen_util,[uppercase_all/1]). -compile(export_all). code() -> safe(fun gen_code/0,true). devcode() -> spawn(fun() -> safe(fun gen_code/0,false) end). safe(What, QuitOnErr) -> try What(), io:format("Completed successfully~n~n", []), QuitOnErr andalso gen_util:halt(0) catch Err:Reason -> io:format("Error ~p: ~p:~p~n ~p~n", [get(current_func),Err,Reason,erlang:get_stacktrace()]), (catch gen_util:close()), timer:sleep(1999), QuitOnErr andalso gen_util:halt(1) end. gen_code() -> {ok, Opts0} = file:consult("glapi.conf"), erase(func_id), Opts = init_defs(Opts0), GLUDefs = parse_glu_defs(Opts), GLDefs = parse_gl_defs(Opts), {GLUDefines,GLUFuncs} = setup(GLUDefs, Opts), {GLDefines,GLFuncs} = setup(GLDefs, Opts), gl_gen_erl:glu_defines(GLUDefines), gl_gen_erl:glu_api(GLUFuncs), gl_gen_erl:gl_defines(GLDefines), gl_gen_erl:gl_api(GLFuncs), %%gl_gen_erl:gen_debug(GLFuncs,GLUFuncs), gl_gen_c:gen(GLFuncs,GLUFuncs), ok. init_defs(Opts0) -> Opts0. parse_glu_defs(Opts0) -> All = foldl(fun(File, Acc) -> load_file(File,Opts0,Acc) end, [], ["glu"]), reverse(All). parse_gl_defs(Opts0) -> All = foldl(fun(File, Acc) -> load_file(File,Opts0,Acc) end, [], ["gl","glext"]), reverse(All). load_file(FileName, Opts, Acc) -> File = filename:join(["gl_xml",FileName ++ "_8h.xml"]), put({loaded, FileName}, true), case xmerl_scan:file(File, [{space, normalize}]) of {error, enoent} -> io:format("Skipped File not found ~p ~n", [File]), Acc; {Doc, _} -> io:format("Scanning ~p ~n", [File]), %% It's duplicated in xml get sectiondef only once. Content = find_data(Doc#xmlElement.content), lists:foreach(fun(D) -> extract_argnames(D) end, Content), foldl(fun(Data,Acc0) -> parse_file(Data, Opts, Acc0) end, Acc, Content) end. extract_argnames(#xmlElement{name=memberdef,attributes=Attr,content=C}) -> case keysearch(kind, #xmlAttribute.name, Attr) of {value, #xmlAttribute{value = "typedef"}} -> parse_typedef(C,undefined); _ -> ok end; extract_argnames(_) -> ok. parse_typedef([#xmlElement{name=argsstring,content=[#xmlText{value=AS}]}|R],_) -> parse_typedef(R,AS); parse_typedef([#xmlElement{name=name}|_],undefined) -> skip; parse_typedef([#xmlElement{name=name,content=[#xmlText{value=N}]}|_],AS) -> Args0 = string:tokens(AS," ,()*[]"), try Args = get_arg_names(Args0), put({typedef,string:strip(N)},Args) catch _:Where -> io:format("Error ~p: ~p ~p~n", [N,Args0,Where]), ?error(arg_names) end; parse_typedef([_|R],AS) -> parse_typedef(R,AS); parse_typedef([],_) -> skip. get_arg_names(As0) -> Args = lists:filter(fun("const") -> false; (_) -> true end, As0), get_arg_names(Args, []). get_arg_names([_Type,Name|R],Acc) -> get_arg_names(R, [Name|Acc]); get_arg_names([],Acc) -> reverse(Acc); get_arg_names(["void"],[]) -> []; get_arg_names(Error,_Acc) -> exit(Error). %% Avoid bugs in (old) doxygen..the new one doesn't have 'em find_data([#xmlElement{name=compounddef, content=C}|_]) -> find_data(C); find_data([#xmlElement{name=sectiondef, attributes=Attr, content=C}|R]) -> case keysearch(kind, #xmlAttribute.name, Attr) of {value, _} -> %% The new one have func define typedef find_data(R) ++ C; false -> C end; find_data([_Hmm|R]) -> %% case _Hmm of %% #xmlElement{} -> %% io:format("0 ~p ~n",[_Hmm#xmlElement.name]); %% _ -> %% ok %% end, find_data(R); find_data([]) -> []. parse_file(#xmlElement{name=memberdef,attributes=Attr, content=C}, Opts, Acc) -> case keysearch(kind, #xmlAttribute.name, Attr) of {value, #xmlAttribute{value = "function"}} -> try Def = parse_func(C, Opts), [Def|Acc] catch throw:skip -> Acc after erase(current_func) end; {value, #xmlAttribute{value = "define"}} -> try Def = parse_define(C, #def{}, Opts), [Def|Acc] catch throw:skip -> Acc end; {value, #xmlAttribute{value = "typedef"}} -> Acc; _W -> io:format("Hmm ~p~n",[_W]), Acc end; parse_file(_Hmm,_,Acc) -> Acc. parse_define([#xmlElement{name=name,content=[#xmlText{value="API" ++ _}]}|_],_Def,_Os) -> throw(skip); parse_define([#xmlElement{name=name,content=[#xmlText{value="GLAPI"++_}]}|_],_Def,_Os) -> throw(skip); parse_define([#xmlElement{name=name,content=[#xmlText{value="WINGDIAPI"++_}]}|_],_Def,_Os) -> throw(skip); parse_define([#xmlElement{name=name,content=[#xmlText{value=Name}]}|R], Def, Os) -> parse_define(R, Def#def{name=Name}, Os); parse_define([#xmlElement{name=initializer,content=[#xmlText{value=V}]}|_],Def,_Os) -> Val0 = string:strip(V), try case Val0 of "0x" ++ Val1 -> Val = http_util:hexlist_to_integer(Val1), Def#def{val=Val, type=hex}; _ -> Val = list_to_integer(Val0), Def#def{val=Val, type=int} end catch _:_ -> Def#def{val=Val0, type=string} end; parse_define([_|R], D, Opts) -> parse_define(R, D, Opts); parse_define([], D, _Opts) -> D. parse_func(Xml, Opts) -> {Func,_} = foldl(fun(X,Acc) -> parse_func(X,Acc,Opts) end, {#func{},1}, Xml), put(current_func, Func#func.name), #func{params=Args0,type=Type0} = Func, Args = filter(fun(#arg{type=void}) -> false; (_) -> true end, Args0), #arg{type=Type} = patch_param(Func#func.name,#arg{name="result",type=Type0},Opts), Func#func{params=reverse(Args), type=Type}. parse_func(#xmlElement{name=type, content=C}, {F,AC}, Os) -> Type = parse_type(drop_empty(C), Os), {F#func{type=Type},AC}; parse_func(#xmlElement{name=name, content=[#xmlText{value=C}]},{F,AC},Os) -> Func = string:strip(C), put(current_func, Func), {F#func{name=name(Func,Os)},AC}; parse_func(#xmlElement{name=param, content=C},{F,AC},Os) -> put(current_func, F#func.name), Parse = fun(Con, Ac) -> parse_param(Con, Ac, Os) end, Param0 = foldl(Parse, #arg{}, drop_empty(C)), Param = fix_param_name(Param0, F, AC), {add_param(Param, Os, F),AC+1}; parse_func(_, F,_) -> F. fix_param_name(A=#arg{name=undefined,type=T},#func{name=Func},Count) -> TDName = "PFN" ++ uppercase_all(Func) ++ "PROC", case get({typedef,TDName}) of undefined when T == void -> A; undefined -> io:format("Didn't find typedef for: ~s~n", [TDName]), exit(aargh); AS -> try A#arg{name = lists:nth(Count, AS)} catch _:_ -> A end end; fix_param_name(A,_,_) -> A. parse_param(#xmlElement{name=type,content=C}, Arg, Os) -> Arg#arg{type=parse_type(drop_empty(C),Os)}; parse_param(#xmlElement{name=declname,content=[C]},Arg,_Os) -> #xmlText{value=Name} = C, Arg#arg{name=Name}; parse_param(#xmlElement{name=array,content=[#xmlText{value=C}]}, Arg=#arg{type=Type0},_Os) -> try [Int] = string:tokens(C, "[] "), Val = list_to_integer(Int), Arg#arg{type=Type0#type{single={tuple,Val}, by_val=true}} catch _:_ -> ?warning("Undefined Array size ~p in ~p ~p~n", [Arg, get(current_func), C]), Arg#arg{type=Type0#type{single={tuple,undefined}, by_val=true}} end; %% Skip these parse_param(#xmlElement{name=definition}, Arg, _) -> Arg; parse_param(#xmlElement{name=argsstring}, Arg,_) -> Arg; parse_param(#xmlElement{name=briefdescription}, Arg,_) -> Arg; parse_param(#xmlElement{name=detaileddescription}, Arg,_) -> Arg; parse_param(#xmlElement{name=inbodydescription}, Arg,_) -> Arg; parse_param(#xmlElement{name=location}, Arg,_) -> Arg; parse_param(Other, Arg,_) -> io:format("Unhandled Param ~p ~n in ~p~n", [Other,Arg]), ?error(unhandled_param). add_param(Arg0=#arg{type=T0}, Opts, F=#func{name=Name,params=Args}) -> Arg = case T0 of %% #type{mod=[const],ref={pointer,1},name="GLubyte"} -> %% Arg0#arg{type=T0#type{base=binary}}; #type{mod=[const]} -> Arg0; %% In is true default #type{ref={pointer,_}} -> Arg0#arg{in=false, type=T0#type{single=undefined}}; _ -> Arg0 end, Patched = patch_param(Name,Arg,Opts), F#func{params=[Patched|Args]}. patch_param(Method,P = #arg{name=ArgName},AllOpts) -> %%io:format("~p ~n", [Method]), case lookup(Method,AllOpts,undefined) of undefined -> P; What -> %% io:format("~p ~p => ~p~n", [Method, ArgName, What]), case What of {ArgName,Fopt} when is_list(Fopt) -> foldl(fun handle_arg_opt/2,P,Fopt); {ArgName,Fopt} -> handle_arg_opt(Fopt,P); {_,_} -> P; Opts when is_list(Opts) -> case get_value(ArgName, Opts, undefined) of undefined -> P; List when is_list(List) -> foldl(fun handle_arg_opt/2,P,List); Val -> handle_arg_opt(Val,P) end end end. handle_arg_opt(skip, P) -> P#arg{where=c}; %%handle_arg_opt(nowhere, P) -> P#arg{where=nowhere}; %%handle_arg_opt(skip_member, _P) -> throw(skip_member); handle_arg_opt(in, P) -> P#arg{in=true}; handle_arg_opt(out, P) -> P#arg{in=false}; handle_arg_opt(both, P) -> P#arg{in=both}; handle_arg_opt(binary, P=#arg{type=T}) -> P#arg{type=T#type{size=undefined,base=binary}}; handle_arg_opt({binary,Sz}, P=#arg{type=T}) -> P#arg{type=T#type{size={Sz, Sz},base=binary}}; handle_arg_opt({binary,Max, Sz}, P=#arg{type=T}) -> P#arg{type=T#type{size={Max, Sz},base=binary}}; handle_arg_opt({type,Type}, P=#arg{type=T}) -> P#arg{type=T#type{name=Type}}; handle_arg_opt({single,Opt},P=#arg{type=T}) -> P#arg{type=T#type{single=Opt}}; handle_arg_opt({base,{Opt, Sz}}, P=#arg{type=T}) -> P#arg{type=T#type{base=Opt, size=Sz}}; handle_arg_opt({base,Opt}, P=#arg{type=T}) -> P#arg{type=T#type{base=Opt}}; handle_arg_opt({c_only,Opt},P) -> P#arg{where=c, alt=Opt}; handle_arg_opt(string, P=#arg{type=T}) -> P#arg{type=T#type{base=string}}; handle_arg_opt({string,Max,Sz}, P=#arg{type=T}) -> P#arg{type=T#type{base=string, size={Max,Sz}}}. parse_type([], _Os) -> void; parse_type(C, Os) -> {Type,_Info} = foldl(fun extract_type_info/2,{[],undefined},C), Empty = #type{}, case parse_type2(reverse(Type),Empty,Os) of Empty -> ?error({strange_type, Type}); Assert -> Assert end. extract_type_info(#xmlText{value=Value}, {Acc, Info}) -> {reverse(foldl(fun extract_type_info2/2, [], string:tokens(Value, " "))) ++ Acc, Info}; extract_type_info(#xmlElement{name=ref,attributes=As, content=[#xmlText{value=V}]}, {Acc,undefined}) -> {value, #xmlAttribute{value = Refid}} = keysearch(refid,#xmlAttribute.name,As), {value, #xmlAttribute{value = Kind}} = keysearch(kindref,#xmlAttribute.name,As), {reverse(foldl(fun extract_type_info2/2, [], string:tokens(V, " "))) ++ Acc, {Kind,Refid}}; extract_type_info(What,Acc) -> ?error({parse_error,What,Acc}). extract_type_info2("const",Acc) -> [const|Acc]; extract_type_info2("*", [{by_ref,{pointer,N}}|Acc]) -> [{by_ref,{pointer,N+1}}|Acc]; extract_type_info2("*", Acc) -> [{by_ref,{pointer,1}}|Acc]; extract_type_info2("**", Acc) -> [{by_ref,{pointer,2}}|Acc]; extract_type_info2(Type, Acc) -> [Type|Acc]. parse_type2(["void"], _T, _Opts) -> void; parse_type2([N="void"|R], T, Opts) -> parse_type2(R,T#type{name=N},Opts); parse_type2([const|R],T=#type{mod=Mod},Opts) -> parse_type2(R,T#type{mod=[const|Mod]},Opts); parse_type2(["unsigned"|R],T=#type{mod=Mod},Opts) -> parse_type2(R,T#type{mod=[unsigned|Mod]},Opts); parse_type2([N="GLenum"|R],T,Opts) -> parse_type2(R,T#type{name=N, size=4, base=int},Opts); parse_type2([N="GLboolean"|R],T,Opts) -> parse_type2(R,T#type{name=N, size=1, base=bool},Opts); parse_type2([N="GLbitfield"|R],T,Opts) -> parse_type2(R,T#type{name=N, size=4, base=int},Opts); parse_type2([N="GLvoid"|R],T,Opts) -> parse_type2(R,T#type{name=N, base=idx_binary},Opts); parse_type2([N="GLsync"|R],T,Opts) -> parse_type2(R,T#type{name=N, base=int, size=8},Opts); parse_type2([N="GLbyte"|R],T,Opts) -> parse_type2(R,T#type{name=N, size=1, base=int},Opts); parse_type2([N="GLubyte"|R],T,Opts) -> parse_type2(R,T#type{name=N, size=1, base=int},Opts); parse_type2([N="GLshort"|R],T,Opts) -> parse_type2(R,T#type{name=N, size=2, base=int},Opts); parse_type2([N="GLushort"|R],T,Opts) -> parse_type2(R,T#type{name=N, size=2, base=int},Opts); parse_type2([N="GLint"|R],T,Opts) -> parse_type2(R,T#type{name=N, size=4, base=int},Opts); parse_type2([N="GLint64"|R],T,Opts) -> parse_type2(R,T#type{name=N, size=8, base=int},Opts); parse_type2([N="GLuint64"|R],T,Opts) -> parse_type2(R,T#type{name=N, size=8, base=int},Opts); parse_type2([N="GLuint"|R],T,Opts) -> parse_type2(R,T#type{name=N, size=4, base=int},Opts); parse_type2([N="GLsizei"|R],T,Opts) -> parse_type2(R,T#type{name=N, size=4, base=int},Opts); parse_type2([N="GLfloat"|R],T,Opts) -> parse_type2(R,T#type{name=N, size=4,base=float},Opts); parse_type2([N="GLdouble"|R],T,Opts) -> parse_type2(R,T#type{name=N, size=8,base=float},Opts); parse_type2([N="GLclampf"|R],T,Opts) -> parse_type2(R,T#type{name=N, size=4,base=float},Opts); parse_type2([N="GLclampd"|R],T,Opts) -> parse_type2(R,T#type{name=N, size=8,base=float},Opts); parse_type2([N="GLhandleARB"|R],T,Opts) -> parse_type2(R,T#type{name=N, size=8,base=int},Opts); parse_type2(["GLchar" ++ _ARB|R],T,Opts) -> parse_type2(R,T#type{name="GLchar",size=1,base=string},Opts); parse_type2(["GLUquadric"|R],T,Opts) -> parse_type2(R,T#type{name="GLUquadric",size=8,base=int},Opts); parse_type2(["GLintptr" ++ _ARB|R],T,Opts) -> parse_type2(R,T#type{name="GLintptr",size=8,base=int},Opts); parse_type2(["GLsizeiptr" ++ _ARB|R],T,Opts) -> parse_type2(R,T#type{name="GLsizeiptr",size=8,base=int},Opts); parse_type2([{by_ref,Ref}|R],T,Opts) -> parse_type2(R,T#type{ref=Ref,by_val=false},Opts); %% Let type errors be seen later because we don't know if these unhandled types %% will be used. parse_type2(_A = [Name|R],T,Opts) -> %% io:format("unhandled ~p ~p ~n",[_A,T]), New = T#type{name={unhandled,Name,get(current_func)}}, parse_type2(R,New,Opts); parse_type2([], T, _) -> T. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Function mangling %% setup(Defs,Opts) -> {Fs0,Ds0} = foldr(fun(F=#func{name=N},{Fs,Ds}) -> case put(N,F) of undefined -> {[N|Fs],Ds}; _ -> %% Duplicate {Fs,Ds} end; (D=#def{}, {Fs,Ds}) -> {Fs,[D|Ds]} end, {[],[]}, Defs), Fs = setup_functions(Fs0,Opts,[]), erase(current_func), %% Remove duplicates but keep order {Ds,_} = foldl(fun(D=#def{name=Name},{Keep,Defined}) -> case gb_sets:is_member(Name,Defined) of true -> {Keep,Defined}; false -> {[D|Keep],gb_sets:add(Name,Defined)} end end, {[],gb_sets:empty()}, Ds0), {reverse(Ds),Fs}. setup_functions([F0|Defs],Opts,Acc) -> put(current_func, F0), {Name, Ext} = get_extension(F0,Opts), %%io:format("~p = ~p + ~p~n", [F0, Name, Ext]), Skip = (not keep(F0,Opts)) andalso (skip(F0,Opts) orelse skip(Ext,Opts)), case Skip of true -> setup_functions(Defs,Opts,Acc); false -> case setup_extension(Name,Ext,Opts) of skip -> setup_functions(Defs,Opts,Acc); New -> setup_functions(Defs,Opts,[New|Acc]) end end; setup_functions([],_, Acc) -> reverse(Acc). setup_extension(Name,"",Opts) -> setup_vector_variant(Name,"",Opts); setup_extension(Name,Ext,Opts) -> case get(Name) of undefined -> setup_vector_variant(Name,Ext,Opts); OrigF = #func{} -> F = get(Name++Ext), case is_equal(F,OrigF) of true -> put(Name, OrigF#func{ext={ext,Ext}}), skip; _ -> setup_vector_variant(Name,Ext,Opts) end end. setup_vector_variant(Name,Ext,Opts) -> case reverse(Name) of [$v|NoVec] -> %% Hmm might be a vector version RealName = reverse(NoVec,Ext), case get(RealName) of undefined -> setup_idx_binary(Name,Ext,Opts); Real = #func{} -> verify_args(Name,Ext,Real,RealName,Opts) end; _ -> setup_idx_binary(Name,Ext,Opts) end. verify_args(Name,Ext,Real = #func{params=RAs},RealName,Opts) -> FuncName = Name ++ Ext, Vector = #func{params=Args} = get(FuncName), case is_vector(Name,Opts) of false -> Check = fun(#arg{type=#type{name=Type}},Acc) -> if Type =:= Acc -> Acc; Acc =:= undefined -> Type; true -> different end end, case foldl(Check,undefined,RAs) of different -> setup_idx_binary(Name,Ext,Opts); undefined -> setup_idx_binary(Name,Ext,Opts); _ when length(Args) =/= 1 -> setup_idx_binary(Name,Ext,Opts); _Type -> put(FuncName,Vector#func{where=erl,alt={vector,0,RealName}}), put(RealName,Real#func{alt={has_vector,0,FuncName}}), Name++Ext end; VecPos -> put(FuncName,Vector#func{where=erl,alt={vector,VecPos,RealName}}), put(RealName,Real#func{alt={has_vector,VecPos,FuncName}}), Name++Ext end. is_vector(Name, Opts) -> Vecs = get_value(vector, Opts, []), lookup(Name, Vecs, false). lookup(Name,[{Vector, VecPos}|R],Def) when is_list(Vector) -> case lists:prefix(Vector,Name) of true -> %% VecPos; %%io:format("~s ~s => ~p ~n", [Vector,Name,VecPos]), case Vector == Name of true -> VecPos; false -> %% Look for exactly the correct Name case lookup(Name,R,Def) of Def -> VecPos; Other -> Other end end; false -> lookup(Name,R, Def) end; lookup(Name,[_|R],Def) -> lookup(Name,R,Def); lookup(_,[], Def) -> Def. setup_idx_binary(Name,Ext,_Opts) -> FuncName = Name ++ Ext, Func = #func{params=Args} = get(FuncName), Id = next_id(function), %% Ok warn if single is undefined lists:foreach(fun(#arg{type=#type{base=memory}}) -> ok; (#arg{type=#type{base=string}}) -> ok; (#arg{type=#type{base=idx_binary}}) -> ok; (#arg{type=#type{name="GLUquadric"}}) -> ok; (#arg{type=#type{base=binary, size=Sz}}) when Sz =/= undefined -> ok; (A=#arg{type=#type{single=undefined}}) -> ?warning("~p Unknown size of~n ~p~n", [get(current_func),A]), io:format("{~p, {~p, }}.~n", [get(current_func),A#arg.name]), ok; (_) -> ok end, Args), case setup_idx_binary(Args, []) of ignore -> put(FuncName, Func#func{id=Id}), Name++Ext; {bin, A1,A2} -> put(FuncName, Func#func{id=Id,params=A1}), Extra = FuncName++"Bin", put(Extra, Func#func{params=A2, id=next_id(function)}), [FuncName,Extra]; {matrix, A1,A2} -> put(FuncName, Func#func{id=Id,params=A2}), Extra = FuncName++"Matrix", put(Extra, Func#func{where=erl, params=A1, id=Id}), [FuncName,Extra] end. setup_idx_binary([A=#arg{in=true,type=T=#type{base=idx_binary}}|R], Acc) -> A1 = A#arg{type=T#type{base=guard_int,size=4}}, A2 = A#arg{type=T#type{base=binary}}, Head = reverse(Acc), case setup_idx_binary(R, []) of ignore -> {bin, Head ++ [A1|R], Head ++ [A2|R]}; {bin, R1,R2} -> {bin, Head ++ [A1|R1], Head ++ [A2|R2]} end; setup_idx_binary([A=#arg{in=true,type=T=#type{single={tuple,matrix}}}|R], Acc) -> A1 = A#arg{type=T#type{single={tuple, matrix12}}}, A2 = A#arg{type=T#type{single={tuple, 16}}}, Head = reverse(Acc), case setup_idx_binary(R, []) of ignore -> {matrix, Head ++ [A1|R], Head ++ [A2|R]}; {matrix, R1,R2} -> {matrix, Head ++ [A1|R1], Head ++ [A2|R2]} end; setup_idx_binary([H|R],Acc) -> setup_idx_binary(R,[H|Acc]); setup_idx_binary([],_) -> ignore. is_equal(F1=#func{type=T1,params=A1},F2=#func{type=T2,params=A2}) -> Equal = is_equal_type(T1,T2) andalso is_equal_args(A1,A2), case Equal of true -> ok; false -> %% io:format("A1: ~p~nA2: ~p~n",[A1,A2]), ?warning("Keeping Ext Not Equal ~p ~p~n", [F1#func.name,F2#func.name]) end, Equal. is_equal_args([],[]) -> true; is_equal_args([_A1=#arg{type=T1}|A1s],[_A2=#arg{type=T2}|A2s]) -> case is_equal_type(T1,T2) of true -> is_equal_args(A1s,A2s); false -> %%io:format("Diff~n ~p~n ~p ~n~n", [_A1,_A2]), false end. is_equal_type(T,T) -> true; is_equal_type(#type{name="GLcharARB"},#type{name="GLchar"}) -> true; %%is_equal_type(#type{name="GLhandleARB"},#type{name="GLuint"}) -> true; is_equal_type(#type{name="GLenum"},#type{name="GLuint"}) -> true; is_equal_type(#type{name="GLenum"},#type{name="GLint"}) -> true; is_equal_type(#type{base=idx_binary},#type{base=guard_int}) -> true; is_equal_type(#type{base=idx_binary},#type{base=memory}) -> true; is_equal_type(#type{single={tuple,matrix}},#type{single={tuple,matrix12}}) -> true; is_equal_type(#type{base=B,single=S,name=N,size=Sz}, #type{base=B,single=S,name=N,size=Sz}) -> true; is_equal_type(_,_) -> false. skip(Name,Opts) -> Skip = get_value(skip, Opts, []), lists:any(fun(Prefix) -> lists:prefix(Prefix,Name) end, Skip). keep(Name,Opts) -> Skip = get_value(keep, Opts, []), lists:any(fun(Prefix) -> lists:prefix(Prefix,Name) end, Skip). get_extension(ExtName,_Opts) -> case reverse(ExtName) of "BRA" ++ Name -> {reverse(Name),"ARB"}; "TXE" ++ Name -> {reverse(Name),"EXT"}; "ASEM" ++ Name -> {reverse(Name),"MESA"}; "ITA" ++ Name -> {reverse(Name),"ATI"}; "DMA" ++ Name -> {reverse(Name),"AMD"}; "VN" ++ Name -> {reverse(Name),"NV"}; %Nvidia "ELPPA"++ Name -> {reverse(Name),"APPLE"}; "LETNI"++ Name -> {reverse(Name),"INTEL"}; "NUS" ++ Name -> {reverse(Name),"SUN"}; "XNUS" ++ Name -> {reverse(Name),"SUNX"}; "IGS" ++ Name -> {reverse(Name),"SGI"}; "SIGS" ++ Name -> {reverse(Name),"SGIS"}; "XIGS" ++ Name -> {reverse(Name),"SGIX"}; "XFD3" ++ Name -> {reverse(Name),"3DFX"}; "MBI" ++ Name -> {reverse(Name),"IBM"}; "RGNI" ++ Name -> {reverse(Name),"INGR"}; "IGP" ++ Name -> {reverse(Name),"PGI"}; "PH" ++ Name -> {reverse(Name),"HP"}; "YDEMERG" ++ Name -> {reverse(Name),"GREMEDY"}; %%["" ++ Name] -> {Name; %% _ -> {ExtName, ""} end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% drop_empty(List) -> filter(fun(#xmlText { value = Text}) -> string:strip(Text) =/= ""; (_)-> true end, List). name(Name, _Opts) -> Name. next_id(What) -> Next = case get(What) of undefined -> 5010; %% Opengl N -> N+1 end, put(What, Next), Next.