:- use_module(library(apply)). :- use_module(library(dcg/basics)). not_covered(Regex, Macros) :- words(Regex, Used), defined(Regex, Defined), exclude(done(Defined), Used, Macros). not_covered(Regex) :- not_covered(Regex, Macros), forall(member(W-F, Macros), format('~w ~t~w~30|~n', [W,F])). not_covered_config(Regex) :- not_covered(Regex, Pairs), pairs_keys(Pairs, Macros), partition(is_header_macro, Macros, HMacros0, FMacros0), sort(HMacros0, HMacros), maplist(config_header, HMacros), nl, sort(FMacros0, FMacros), maplist(config_function, FMacros). is_header_macro(M) :- sub_atom(M, _, _, 0, '_H'). config_header(M) :- atom_concat('HAVE_', HeaderR, M), atom_concat(HeaderU, '_H', HeaderR), downcase_atom(HeaderU, Header0), ( atom_concat(sys_, SubDir, Header0) -> atom_concat('sys/', SubDir, Header) ; Header = Header0 ), format('check_include_file(~w.h ~w)~n', [Header, M]). config_function(M) :- atom_concat('HAVE_', FunctionU, M), downcase_atom(FunctionU, Function), format('check_function_exists(~w ~w)~n', [Function, M]). done(Defined, Used-_Count) :- memberchk(Used, Defined). words(Regex, Pairs) :- src_words(AllWords), length(AllWords, Count), debug(stats, 'Got ~D words~n', [Count]), include(re_match(Regex), AllWords, Words), words_freq(Words, Pairs). src_words(AllWords) :- directory_files('.', '*.[ch]', Files), maplist(file_words, Files, NestedWords), append(NestedWords, AllWords). defined(Regex, Macros) :- directory_files(cmake, '*.cmake', CMakeFiles), maplist(file_words, ['CMakeLists.txt'|CMakeFiles], AllWordsNested), append(AllWordsNested, AllWords), sort(AllWords, Sorted), include(re_match(Regex), Sorted, Macros). %! words_freq(+Words, -FreqPairs) % % Create from a word list an ordered set of Word-Count words_freq(List, Pairs) :- msort(List, Sorted), count_words(Sorted, Pairs0), sort(2, >=, Pairs0, Pairs). count_words([], []). count_words([H|T0], [H-C|T]) :- count_same(T0, H, 1, C, T1), count_words(T1, T). count_same([H|T0], H, C0, C, T) :- !, C1 is C0+1, count_same(T0, H, C1, C, T). count_same(T, _, C, C, T). %! directory_files(+Dir, +Pattern, -Files) % % Get all files in Dir and its subdirs that match Pattern. directory_files(Dir, Pattern, Files) :- phrase(directory_files(Pattern, Dir), Files). directory_files(Pattern, Dir) --> { directory_file_path(Dir, Pattern, DirPattern), expand_file_name(DirPattern, Files0), include(exists_file, Files0, Files), directory_files(Dir, All), convlist(subdir(Dir), All, SubDirs) }, string(Files), foldl(directory_files(Pattern), SubDirs). subdir(Dir, Entry, SubDir) :- \+ sub_atom(Entry, 0, _, _, '.'), directory_file_path(Dir, Entry, SubDir), exists_directory(SubDir). %! file_words(+File, -Words) % % Get all identifiers from File. file_words(File, Words) :- read_file_to_string(File, String, []), re_split('[a-zA-Z_]+', String, Tokens), include(word, Tokens, WordStrings), maplist(atom_string, Words, WordStrings). word(Atom) :- sub_atom(Atom, 0, 1, _, First), char_type(First, alnum).