Source

haikuml_generator / haikuml_getclass.erl

Full commit
-module(haikuml_getclass).
-export([get_class/1]).
-define(URLBASE, "http://haiku-os.org/legacy-docs/bebook/").
-define(BANNED_STRINGS,
	[
		"GetRunningAppInfo(be_app-&gt", "Team(), theInfo)",
		"status_t SetStreamHook(void (*hook)(void * cookie, void* inBuffer, size_t byteCount, BStreamingGameSound* object), void* cookie)",
		"void Draw(BRectupdateRect)",
		"void DoForEach(bool (*func)(BListItem*))",
		"void DoForEach(bool (*func)(BListItem*), void* arg2)",
		"void* SortItems(int (*compareFunc)( void* , void* ))",
		"BListItem* EachItemUnder(BListItem* underItem, bool oneLevelOnly, BListItem* (*eachFunc) (BListItem*, void* ), void* data)",
		"void FullListDoForEach(bool (*func)(BListItem*))",
		"void FullListDoForEach(bool (*func)(BListItem*), void* ))",
		"void FullListDoForEach(bool (*func)(BListItem*), void* ), void* )",
		"void FullListSortItems(int (*compareFunc)( BListItem *, BListItem *))",
		"void SortItemsUnder(BListItem* underItem, bool oneLevelOnly, int (*compareFunc)( BListItem *, BListItem *))",
		"BTimeSource( char* name = NULL, void (*PlayBuffer) (void* , void* buffer, size_t size, media_raw_audio_format& format) = NULL, void (*Notifier) (void* , sound_player_notification what) = NULL, void* cookie = NULL)",
		"BTimeSource( media_raw_audio_format* format, char* name = NULL, void (*PlayBuffer) (void* , void* buffer, size_t size, media_raw_audio_format& format) = NULL, void (*Notifier) (void* , sound_player_notification what) = NULL, void* cookie = NULL)",
		"void SetNotifier(void (*Notifier)(void* , sound_player_notification what, ...)))",
		"void DoForEach(bool (*func)(void * ))",
		"void DoForEach(bool (*func)(void * ), void* arg2)",
		"void* SortItems(int (*compareFunc)( void * , void * ))"
		]).

get_class(ClassName) ->
	URL = ?URLBASE ++ ClassName ++ ".html",
	{ok, HTML} = get_url_contents(URL),
	Constructors = get_constructors(HTML),
	Hooks = get_hooks(HTML),
	Functions = get_functions(HTML),
	Module = {{module, ClassName},
		{methods, Constructors ++ Hooks ++ Functions}},
	Module.

get_constructors(HTML) ->
	L = re:split(HTML, "(<code class=\"constru.*/code>)",
			[{return, list}]) --
		re:split(HTML, "<code class=\"constru.*/code>",
			[{return, list}]),
	R= [
		re:replace(
			re:replace(
				re:replace(
					re:replace(
						re:replace(
							re:replace(X, "</?code.*>", "",
								[{return, list}, ungreedy, global]),
							"</?span.*>", "",
							[{return, list}, ungreedy, global]),
						"</?a.*>", "",
						[{return, list}, ungreedy, global]),
					"virtual", "",
					[{return, list}, ungreedy, global]),
				"const", "",
				[{return, list}, ungreedy, global]),
			"\302\240", " ",
			[{return, list}, ungreedy, global])
		|| X <- L ],
	E = [
		re:replace(
			re:replace(
				re:replace(
					re:replace(X, "<br.*>", "",
						[{return, list}, ungreedy, global]),
					"\\n", " ",
					[{return, list}, ungreedy, global]),
				"\\s+", " ",
				[{return, list}, global]),
			"<p>", "",
			[{return, list}, global])
		|| X <- R ],
	M = lists:foldl(
		fun(X, Acc) ->
			Acc ++ [ string:strip(Y)
			|| Y <- re:split(
					re:replace(X, "\\&amp;", "\\&", [{return, list}]),
					";", [{return, list}]),
				Y =/= [] ]
		end, [], E),
	io:fwrite("~p~n", [E]),
	[
		begin	
			io:fwrite("~p~n", [X]),
			[_, ArgString] = string:tokens(X, "("),
			Args = string:tokens(
				string:strip(ArgString, both, $)),
				","),
			ArgTuples = [
				begin
					[YType, YName|_] = string:tokens(Y, " "),
					{string_to_type(YType), YName}
				end
				|| Y <- Args ],
			{constructor, ArgTuples}
		end
	|| X <- M,
		not lists:member(X, ?BANNED_STRINGS),
		[lists:nth(1, lists:reverse(X))] == ")",
		[lists:nth(1, X)] /= "<",
		length(string:tokens(
			lists:nth(1, string:tokens(X, "(")),
			" ")) == 1 ].

get_hooks(HTML) ->
	case re:split(HTML, "</a>Hook Functions</h3>",
			[ungreedy, {return, list}]) of
		[_, P] ->
			HookL = hd(re:split(P, "/h3", [ungreedy, {return, list}])),
			L = re:split(HookL, "(<code class=\"methodsyn.*/code>)",
					[{return, list}]) --
				re:split(HookL, "<code class=\"methodsyn.*/code>",
					[{return, list}]),
			R= [
				re:replace(
					re:replace(
						re:replace(
							re:replace(
								re:replace(
									re:replace(X, "</?code.*>", "",
										[{return, list}, ungreedy, global]),
									"</?span.*>", "",
									[{return, list}, ungreedy, global]),
								"</?a.*>", "",
								[{return, list}, ungreedy, global]),
							"virtual", "",
							[{return, list}, ungreedy, global]),
						"const", "",
						[{return, list}, ungreedy, global]),
					"\302\240", " ",
					[{return, list}, ungreedy, global])
				|| X <- L ],
			E = [
				re:replace(
					re:replace(
						re:replace(
							re:replace(X, "<br.*>", "",
								[{return, list}, ungreedy, global]),
							"\\n", " ",
							[{return, list}, ungreedy, global]),
						"\\s+", " ",
						[{return, list}, global]),
					"<p>", "",
					[{return, list}, global])
				|| X <- R ],
			M = lists:foldl(
				fun(X, Acc) ->
					Acc ++ [ string:strip(Y)
					|| Y <- re:split(X, ";", [{return, list}]),
						Y =/= [] ]
				end, [], E),
			[
				begin	
					io:fwrite("~p~n", [X]),
					[TypeAndName, ArgString] = string:tokens(X, "("),
					[TypeString, NameString] =
						string:tokens(TypeAndName, " "),
					Args = string:tokens(
						string:strip(ArgString, both, $)),
						","),
					ArgTuples = [
						begin
							[YType, YName|_] = string:tokens(Y, " "),
							{string_to_type(YType), YName}
						end
						|| Y <- Args ],
					{{hook, string_to_type(TypeString)}, NameString, ArgTuples}
				end
			|| X <- M, not lists:member(X, ?BANNED_STRINGS),
				[lists:nth(1, lists:reverse(X))] == ")",
				[lists:nth(1, X)] /= "<",
				length(string:tokens(
					lists:nth(1, string:tokens(X, "(")),
					" ")) == 2 ];
		_ -> []
	end.

get_functions(HTML) ->
	case re:split(HTML, "</a>Member Functions</h3>",
			[ungreedy, {return, list}]) of
		[_, P] ->
			FunL = hd(re:split(P, "/h3", [ungreedy, {return, list}])),
			L = re:split(FunL, "(<code class=\"methodsyn.*/code>)",
					[{return, list}]) --
				re:split(FunL, "<code class=\"methodsyn.*/code>",
					[{return, list}]),
			R= [
				re:replace(
					re:replace(
						re:replace(
							re:replace(
								re:replace(
									re:replace(X, "</?code.*>", "",
										[{return, list}, ungreedy, global]),
									"</?span.*>", "",
									[{return, list}, ungreedy, global]),
								"</?a.*>", "",
								[{return, list}, ungreedy, global]),
							"virtual", "",
							[{return, list}, ungreedy, global]),
						"const", "",
						[{return, list}, ungreedy, global]),
					"\302\240", " ",
					[{return, list}, ungreedy, global])
				|| X <- L ],
			E = [
				re:replace(
					re:replace(
						re:replace(
							re:replace(X, "<br.*>", "",
								[{return, list}, ungreedy, global]),
							"\\n", " ",
							[{return, list}, ungreedy, global]),
						"\\s+", " ",
						[{return, list}, global]),
					"<p>", "",
					[{return, list}, global])
				|| X <- R ],
			M = lists:foldl(
				fun(X, Acc) ->
					Acc ++ [ string:strip(Y)
					|| Y <- re:split(X, ";", [{return, list}]),
						Y =/= [] ]
				end, [], E),
			[
				begin
					io:fwrite("~p~n", [X]),
					[TypeAndName, ArgString] = string:tokens(X, "("),
					[TypeString, NameString] =
						string:tokens(TypeAndName, " "),
					Args = string:tokens(
						string:strip(ArgString, both, $)),
						","),
					ArgTuples = [
						begin
							[YType, YName|_] = string:tokens(Y, " "),
							{string_to_type(YType), YName}
						end
						|| Y <- Args ],
					{{function, string_to_type(TypeString)},
						NameString, ArgTuples}
				end
			|| X <- M, not lists:member(X, ?BANNED_STRINGS),
				[lists:nth(1, lists:reverse(X))] == ")",
				[lists:nth(1, X)] /= "<",
				length(string:tokens(
					lists:nth(1, string:tokens(X, "(")),
					" ")) == 2 ];
		_ -> []
	end.


string_to_type("void") -> void;
string_to_type("float") -> float;
string_to_type("uint32") -> int;
string_to_type("int32") -> int;
string_to_type("int") -> int;
string_to_type("char*") -> string;
string_to_type("bool") -> bool;
string_to_type(Type) -> Type.


get_url_contents(Url) ->
	inets:start(),
	get_url_contents(Url, 5).

get_url_contents(_Url, 0) -> failed;
get_url_contents(Url, MaxFailures) ->
  case http:request(Url) of
      {ok, {{_, RetCode, _}, _, Result}} -> if
	  	RetCode == 200;RetCode == 201 ->
			{ok, Result};
		RetCode >= 500 ->
			% server error, retry 
			%io:format("HTTP code ~p~n", [RetCode]),
			timer:sleep(1000),
			get_url_contents(Url, MaxFailures-1);
		true ->
			% all other errors
			failed
		end;
	{error, _Why} ->
		%io:format("failed request: ~s : ~w~n", [Url, Why]), 
		timer:sleep(1000),
		get_url_contents(Url, MaxFailures-1)
	end.