defmodule Includer do @moduledoc """ Documentation for `Includer`. """ @doc """ ## SYNOPSIS: Includes missing header files to the top of the C source file by searching linux MAN. ## USAGE: Includer.run(filename) """ def loadSourceFromFile(fileName) do {:ok, f} = File.read(fileName) f end def reserved, do: ["if", "for", "while", "main", "switch"] def getFunctionsFromSource(text) do Regex.scan(~r/([A-Za-z_0-9]+)\(/, text) |> Enum.map(fn([_, b]) -> b end) |> Enum.filter(fn(x) -> !Enum.member?(reserved(), x) end) end def getIncludeFromMan(function) do IO.puts(function <> "\n") case HTTPoison.get("https://manpages.debian.org/buster/manpages-dev/" <> function <> ".3.en.html") do {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> parsedBody = body |> Floki.parse_document! |> Floki.find("#SYNOPSIS ~ pre") case parsedBody do [] -> body |> Floki.parse_document! |> Floki.find("#SYNOPSIS ~ b") |> Enum.map(fn({"b", [], [a]}) -> a end) [{_, _, a}| _] -> a |> Enum.map(fn({_, _, [a]}) -> a end) end {:ok, %HTTPoison.Response{status_code: 302}} -> case HTTPoison.get("https://manpages.debian.org/buster/manpages-dev/" <> function <> ".2.en.html") do {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> parsedBody = body |> Floki.parse_document! |> Floki.find("#SYNOPSIS ~ pre") case parsedBody do [] -> body |> Floki.parse_document! |> Floki.find("#SYNOPSIS ~ b") |> Enum.map(fn({"b", [], [a]}) -> a end) [{_, _, a}| _] -> a |> Enum.map(fn({_, _, [a]}) -> a end) end {:ok, %HTTPoison.Response{status_code: 302}} -> nil end {:ok, %HTTPoison.Response{status_code: 404}} -> IO.puts "Not found :(" {:error, %HTTPoison.Error{reason: reason}} -> IO.inspect reason end end def findIncludes(functions) do functions |> Enum.map(fn(function) -> getIncludeFromMan(function) end) |> Enum.filter(fn(x) -> x != nil end) |> List.foldr([], &Enum.concat/2) end def saveToFile(includes, filename, oldsource) do File.write(filename, Enum.join(includes, "\n") <> "\n" <> oldsource) :ok end def run(filename) do source = filename |> loadSourceFromFile alreadyIncluded = Regex.scan(~r/#include[ ]*<[A-Za-z\/\.]+>/, source) |> Enum.map(fn([a]) -> a end) includes = source |> getFunctionsFromSource |> findIncludes includes = includes -- alreadyIncluded includes = includes |> Enum.uniq() if includes != [], do: saveToFile(includes, filename, source) :ok end end