1#!/bin/env escript
2
3-mode(compile).
4
5-record(f, {c,f,t,a,os,w,p}).
6
7
8main([]) ->
9    {ok, A280} = file:consult("wx_28_api.dump"),
10    {ok, A300} = file:consult("wx_30_api.dump"),
11    A28 = [#f{c=C,f=F,t=T,a=A,os=Os,w=W,p=P} || {C,F,T,A,Os,W,P} <- A280],
12    A30 = [#f{c=C,f=F,t=T,a=A,os=Os,w=W,p=P} || {C,F,T,A,Os,W,P} <- A300],
13    Diff = A28 -- A30,
14    Problems = diff(Diff, A30, []),
15    {Remain,Incomp} = write(Problems, 0, 0),
16    io:format("~n Remaining Problems: ~p~n",[Remain]),
17    io:format(" Known incompatibles: ~p~n",[Incomp]),
18    ok.
19
20diff([A|R], A30, Acc) ->
21    Potential = find(A, A30),
22    case is_ok(A, Potential, A30) of
23        true -> diff(R, A30, Acc);
24        {opt_differ, _} = Diff ->
25            diff(R, A30, [{A, Diff}|Acc]);
26        false ->
27            diff(R, A30, [{A,Potential}|Acc])
28    end;
29diff([], _, Acc) ->
30    Acc.
31
32find(#f{c=C,f=Search}, New) ->
33    Parents = parents(C,New),
34    lists:append(find([C|Parents], Search, New)).
35
36find([C|R], M, New) ->
37    [[F || #f{c=C2,f=M2} = F <- New, C =:= C2, M =:= M2] | find(R, M, New)];
38find([], _, _) ->
39    [].
40
41parents(C, All) ->
42    case lists:keyfind(C, #f.c, All) of
43        #f{p=P} when P =/= root; P =/= object ->
44            [P|parents(P,All)];
45        _ ->
46            []
47    end.
48
49is_ok(A,Bs,All) ->
50    is_ok(A,Bs,All,false).
51
52is_ok(#f{f=destroy}, _, _, _) ->
53    %% Ignore destroy
54    true;
55is_ok(#f{f='\'Destroy\''}, _, _, _) ->
56    %% Ignore destroy
57    true;
58is_ok(#f{f=M,t=T,a=As,os=O}, [#f{f=M,t=T,a=As,os=O}|_], _, _) ->
59    true;
60is_ok(#f{f=M,t=T,a=As,os=O,w=Info}=A, [#f{f=M,t=T,a=As,os=O2}|R], All, Acc) ->
61    %% Only opts
62    case O -- O2 of
63        [] when Info == erl_no_opt -> is_ok(A, R, All, Acc);
64        [] -> true;
65        _ when Info == taylormade -> true;
66        _Changed -> is_ok(A, R, All, {opt_differ, O2 -- O})
67    end;
68is_ok(#f{f=M,t=T,a=As,os=O}=A, [#f{f=M,t=T,a=Bs,os=O}|R], All, Acc) ->
69    %% Only args check if merged
70    check_args(As,Bs,All) orelse is_ok(A,R,All,Acc);
71is_ok(#f{f=M,t=T,a=As,os=O}=A, [#f{f=M,t=_T2, a=As,os=O}|R], All, Acc) ->
72    case T of %% Was cast now returns something
73        ok ->
74            %% io:format("Return type diff: ~p => ~p~n",[A, _T2]),
75            true;
76        _ ->
77            is_ok(A,R,All,Acc)
78    end;
79is_ok(A, [_|R], All, Acc) ->
80    is_ok(A, R, All, Acc);
81is_ok(_, [], _All, Acc) ->
82    Acc.
83
84check_args([A|As], [A|Bs], All) ->
85    check_args(As,Bs, All);
86check_args([A|As], [B|Bs], All) when is_list(A), is_list(B) ->
87    lists:all(fun(M) -> lists:member(M, B) end, B) andalso check_args(As,Bs,All);
88check_args([A|As], [B|Bs], All) when is_list(B) ->
89    lists:member(A, B) andalso check_args(As,Bs,All);
90check_args([], [], _) ->
91    true;
92check_args([A|As], [B|Bs], All) when is_atom(A) ->
93    Parents = parents(A,All),
94    %% io:format("A ~p is ~p? ~p ~p~n", [A, B, Parents, lists:member(B, Parents)]),
95    lists:member(B, Parents) andalso check_args(As,Bs, All);
96check_args(_, _, _) ->
97    false.
98
99%% Known API changes
100write([{#f{c=wxGLCanvas},_}|Rest0], P, K) ->
101    io:format("wxGLCanvas API is incompatible~n",[]),
102    Rest = [F || {#f{c=Mod},_} = F <- Rest0, Mod =/= wxGLCanvas],
103    write(Rest, P, K+1);
104write([{#f{f=clientDC, a=[], os=[]},_}|Rest], P, K) ->
105    io:format("wxClientDC default creators have been removed~n",[]),
106    write(Rest, P, K+1);
107write([{#f{f=paintDC, a=[], os=[]},_}|Rest], P, K) ->
108    io:format("wxPaintDC default creators have been removed~n",[]),
109    write(Rest, P, K+1);
110write([{#f{f=windowDC, a=[], os=[]},_}|Rest], P, K) ->
111    io:format("wxWindowDC default creators have been removed~n",[]),
112    write(Rest, P, K+1);
113write([{#f{c=wxBitmapButton,f=setBitmapSelected},_}|Rest0], P, K) ->
114    io:format("wxBitmapButton:[g|s]etBitmapSelected have been removed~n",[]),
115    [{#f{f=getBitmapSelected},_}|Rest] = Rest0,
116    write(Rest, P, K+1);
117write([{#f{c=wxCalendarDateAttr,f=calendarDateAttr},_}|Rest0], P, K) ->
118    io:format("wxCalendarDateAttr:new(ColText [,OptList]) have been removed~n",[]),
119    [{#f{f=calendarDateAttr},_}|Rest] = Rest0,
120    write(Rest, P, K+1);
121write([{#f{c=wxColourData,f=colourData},_}|Rest], P, K) ->
122    write(Rest, P, K+1);
123write([{#f{c=wxColourPickerCtrl,f=setColour, t=bool},_}|Rest], P, K) ->
124    %% Changed type from bool to void
125    write(Rest, P, K+1);
126write([{#f{c=wxCursor, f=cursor, a=[binary|_]},_}|Rest], P, K) ->
127    %% Removed in 2.9
128    write(Rest, P, K);
129write([{#f{c=wxDC,f=computeScaleAndOrigin},_}|Rest], P, K) ->
130    %% Implementation detail?
131    write(Rest, P, K+1);
132write([{#f{c=wxDC,f=setClippingRegion, a=[_,wxRegion]},_}|Rest], P, K) ->
133    %% Implementation detail?
134    write(Rest, P, K+1);
135write([{#f{c=wxFindReplaceData,f=findReplaceData, a=[_]},_}|Rest], P, K) ->
136    %% Changed with default value
137    write(Rest, P, K+1);
138write([{#f{c=wxGraphicsRenderer,f=GradBrush},_}|Rest], P, K)
139  when GradBrush =:= createRadialGradientBrush; GradBrush =:= createLinearGradientBrush ->
140    io:format("wxGraphicsRenderer:create*GradientBrush(..) uses GradientStops now~n",[]),
141    write(Rest, P, K+1);
142write([{#f{c=wxGraphicsRenderer,f=createPen},_}|Rest], P, K) ->
143    io:format("wxGraphicsRenderer:createPen(..) have been removed~n",[]),
144    write(Rest, P, K+1);
145
146%% wxGrid API have been reworked
147write([{#f{c=wxGrid,f=canDragRowSize},_}|Rest], P, K) ->
148    io:format("wxGrid API have many changes~n",[]),
149    write(Rest, P, K+1);
150write([{#f{c=wxGrid,f=canDragColSize},_}|Rest], P, K) -> write(Rest, P, K);
151write([{#f{c=wxGrid,f=getViewWidth},_}|Rest], P, K) -> write(Rest, P, K);
152write([{#f{c=wxGrid,f=grid, a=[wxWindow,int,int]},_}|Rest], P, K) -> write(Rest, P, K);
153write([{#f{c=wxGrid,f=setCellAlignment},_}|Rest], P, K) -> write(Rest, P, K);
154write([{#f{c=wxGrid,f=setCellBackgroundColour, a=[_,{int,int,int,int}|_]},_}|Rest], P, K) -> write(Rest, P, K);
155write([{#f{c=wxGrid,f=setCellTextColour, a=[_,{int,int,int,int}|_]},_}|Rest], P, K) -> write(Rest, P, K);
156write([{#f{c=wxGrid,f=setCellValue, a=[_,list|_]},_}|Rest], P, K) -> write(Rest, P, K);
157write([{#f{c=wxGridCellEditor,f=paintBackground},_}|Rest], P, K) -> write(Rest, P, K);
158write([{#f{c=wxGridCellEditor,f=beginEdit},_}|Rest], P, K) -> write(Rest, P, K);
159write([{#f{c=wxGridCellEditor,f=endEdit},_}|Rest], P, K) -> write(Rest, P, K);
160
161write([{#f{c=wxIcon,f=icon, a=[wx]},_}|Rest], P, K) ->
162    write(Rest, P, K+1);
163write([{#f{c=wxIconBundle,f=icon, a=[wx]},_}|Rest], P, K) ->
164    %% Removed strange
165    write(Rest, P, K+1);
166write([{#f{c=wxIconizeEvent,f=iconized},_}|Rest], P, K) ->
167    %% Changed to isIconized
168    write(Rest, P, K+1);
169write([{#f{c=wxIdleEvent,f=canSend},_}|Rest], P, K) ->
170    %% removed
171    write(Rest, P, K+1);
172write([{#f{c=wxListCtrl,f=setItem, t=int},_}|Rest], P, K) ->
173    io:format("wxListCtrl:setItem/4 changed return value~n",[]),
174    write(Rest, P, K+1);
175write([{#f{c=wxListCtrl,f=sortItems},_}|Rest], P, K) ->
176    write(Rest, P, K);
177write([{#f{c=wxMDIClientWindow,f=mDIClientWindow},_}|Rest], P, K) ->
178    write(Rest, P, K);
179write([{#f{c=wxMenu,f=prepend,a=[_,_,_,_,bool]},_}|Rest], P, K) ->
180    write(Rest, P, K);
181write([{#f{c=wxMenu,f=insert,a=[_,_,_,_,_,bool]},_}|Rest], P, K) ->
182    write(Rest, P, K);
183write([{#f{c=wxMenu,f=append,a=[_,_,_,_,bool]},_}|Rest], P, K) ->
184    io:format("wxMenu append/insert/prepend have changed return value and lost IsCheckable argument~n",[]),
185    write(Rest, P, K+1);
186write([{#f{c=wxMultiChoiceDialog,f=multiChoiceDialog,a=[]},_}|Rest], P, K) ->
187    write(Rest, P, K+1);
188write([{#f{c=wxNotebookEvent},_}|Rest0], P, K) ->
189    io:format("wxNotebookEvent have been replaced by the wxBookctrlEvent~n",[]),
190    Rest = [F || {#f{c=Mod},_} = F <- Rest0, Mod =/= wxNotebookEvent],
191    write(Rest, P, K+1);
192write([{#f{c=wxPageSetupDialogData,f=setPaperSize},_}|Rest], P, K) ->
193    write(Rest, P, K+1);
194write([{#f{c=wxPanel,f=panel},_}|Rest], P, K) ->
195    write(Rest, P, K+1);
196write([{#f{c=wxPostScriptDC,f=Resolution},_}|Rest], P, K)
197  when Resolution =:= setResolution; Resolution =:= getResolution ->
198    %% Deprecated in 2.9
199    write(Rest, P, K+1);
200write([{#f{c=wxPrinter,f=createAbortWindow},_}|Rest], P, K) ->
201    write(Rest, P, K+1);
202write([{#f{c=wxRegion,f=subtract},_}|Rest], P, K) ->
203    write(Rest, P, K+1);
204write([{#f{c=wxShowEvent,f=getShow},_}|Rest], P, K) ->
205    %% Deprecated in 2.9
206    write(Rest, P, K+1);
207write([{#f{c=wxSingleChoiceDialog,f=singleChoiceDialog, a=[]},_}|Rest], P, K) ->
208    write(Rest, P, K+1);
209write([{#f{c=wxSizer,f=recalcSizes},_}|Rest], P, K) ->
210    io:format("Removed wxSizer:recalcSizer() was an wxWidgets internal function now deprected~n", []),
211    write(Rest, P, K+1);
212write([{#f{c=wxSizerItem,f=setWindow},_}|Rest], P, K) ->
213    io:format("Removed depr wxSizerItem:setWindow() use assignWindow~n", []),
214    write(Rest, P, K+1);
215write([{#f{c=wxSizerItem,f=setSpacer},_}|Rest], P, K) ->
216    io:format("Removed depr wxSizerItem:setSpacer() use assignSpacer~n", []),
217    write(Rest, P, K+1);
218write([{#f{c=wxSizerItem,f=setSizer},_}|Rest], P, K) ->
219    io:format("Removed depr wxSizerItem:setSizer() use assignSizer~n", []),
220    write(Rest, P, K+1);
221write([{#f{c=wxSizerItem, f=sizerItem},_}|Rest0], P, K) ->
222    io:format("wxSizerItem:new() Some args have become options ~n",[]),
223    Rest = [F || {#f{c=Mod, f=M},_} = F <- Rest0, Mod =/= wxSizerItem orelse M =/= sizerItem],
224    write(Rest, P, K+1);
225write([{#f{c=wxSplashScreen,f=splashScreen, a=[]},_}|Rest], P, K) ->
226    write(Rest, P, K+1);
227write([{#f{c=wxSplitterWindow,f=setSashSize},_}|Rest], P, K) ->
228    %% Deprecated No-op
229    write(Rest, P, K+1);
230write([{#f{c=wxStyledTextCtrl,f=addStyledText},_}|Rest], P, K) ->
231    %% Unusable API couldn't have been used
232    write(Rest, P, K);
233write([{#f{c=wxStyledTextCtrl,f=getStyledText},_}|Rest], P, K) ->
234    %% Unusable API couldn't have been used
235    write(Rest, P, K);
236write([{#f{c=wxStyledTextCtrl,f=getCaretSticky},_}|Rest], P, K) ->
237    write(Rest, P, K);     %% Changed from bool => int
238write([{#f{c=wxStyledTextCtrl,f=setCaretSticky},_}|Rest], P, K) ->
239    write(Rest, P, K);     %% Changed from bool => int
240write([{#f{c=wxStyledTextCtrl,f=getIndentationGuides},_}|Rest], P, K) ->
241    write(Rest, P, K);    %% Changed from bool => int
242write([{#f{c=wxStyledTextCtrl,f=setIndentationGuides},_}|Rest], P, K) ->
243    write(Rest, P, K);    %% Changed from bool => int
244write([{#f{c=wxStyledTextCtrl,f=startStyling},_}|Rest], P, K) ->
245    write(Rest, P, K);    %% Remove mask arg?
246write([{#f{c=wxStyledTextCtrl,f=usePopUp},_}|Rest], P, K) ->
247    io:format("wxStyledTextCtrl some functions have changed args from boolean to int~n"),
248    write(Rest, P, K+1);
249write([{#f{c=wxToolBar,f=insertTool},_}|Rest], P, K) ->
250    write(Rest, P, K);
251write([{#f{c=wxToolBar,f=addTool},_}|Rest0], P, K) ->
252    io:format("wxToolBar add/insertTool without label have been deprecated~n",[]),
253    Rest = [F || {#f{c=Mod, f=M},_} = F <- Rest0, Mod =/= wxToolBar orelse M =/= addTool],
254    write(Rest, P, K+1);
255write([{#f{c=wxWindow,f=makeModal},_}|Rest], P, K) ->
256    io:format("wxWindow:makeModal(..) have been deprecated~n",[]),
257    write(Rest, P, K+1);
258write([{#f{c=wxWindow,f=setVirtualSizeHints},_}|Rest0], P, K) ->
259    io:format("wxWindow:setVirtualSizeHints(..) have been deprecated~n",[]),
260    Rest = [F || {#f{c=Mod, f=M},_} = F <- Rest0, Mod =/= wxWindow orelse M =/= setVirtualSizeHints],
261    write(Rest, P, K+1);
262write([{#f{c=wx_misc,f=genericFindWindowAtPoint},_}|Rest], P, K) ->
263    write(Rest, P, K+1);
264write([{#f{c=wx_misc,f=shutdown},_}|Rest], P, K) ->
265    write(Rest, P, K+1);
266
267
268%% Options
269write([{#f{c=wxDisplay, f=display},{opt_differ,_}}|Rest], P, K) ->
270    io:format("wxDisplay::wxDisplay opts incompatible~n",[]),
271    write(Rest, P, K+1);
272write([{#f{c=wxFlexGridSizer, f=flexGridSizer},{opt_differ,_}}|Rest], P, K) ->
273    io:format("wxFlexGridSizer::wxFlexGridSizer opts incompatible~n",[]),
274    write(Rest, P, K+1);
275write([{#f{c=wxGridSizer, f=gridSizer},{opt_differ,_}}|Rest], P, K) ->
276    io:format("wxGridSizer::wxGridSizer opts incompatible~n",[]),
277    write(Rest, P, K+1);
278write([{#f{c=wxHtmlWindow, f=setFonts},{opt_differ,_}}|Rest], P, K) ->
279    %% Bug in old api??
280    write(Rest, P, K);
281write([{#f{c=wxImage, f=convertToGreyscale},{opt_differ,_}}|Rest], P, K) ->
282    io:format("wxImage::convertToGreyscale opts incompatible~n",[]),
283    write(Rest, P, K+1);
284
285%% Unknown
286
287write([{A, {opt_differ, Opts}}|Rest], P, K) ->
288    io:format("28: ~0p ",[A]),
289    io:format(" Changed Opts: ~p~n",[Opts]),
290    write(Rest, P+1, K);
291write([{A,Ps}|Rest], P, K) ->
292    io:format("28: ~0p~n",[A]),
293    [io:format("  30: ~0p~n",[B]) || B <- Ps],
294    io:nl(),
295    write(Rest, P+1, K);
296%% write([_|Rest], P, K) ->
297%%     write(Rest, P+1, K);
298write([], P, K) ->
299    {P,K}.
300
301