--- /dev/null
+module StringSet = Set.Make (String)
+
+type file = {
+ ddeps: string list;
+ rdeps: StringSet.t option
+}
+
+let graph = Hashtbl.create 503
+
+let add fname =
+ if Hashtbl.mem graph fname then () else
+ Hashtbl.add graph fname {ddeps = []; rdeps = None}
+
+let add_ddep fname dname =
+ let file = Hashtbl.find graph fname in
+ Hashtbl.replace graph fname {file with ddeps = dname :: file.ddeps}
+
+let init fname dname =
+ add fname; add dname; add_ddep fname dname
+
+let rec compute fname file = match file.rdeps with
+ | Some rdeps -> rdeps
+ | None ->
+ let rdeps = List.fold_left (iter fname) StringSet.empty file.ddeps in
+ Hashtbl.replace graph fname {file with rdeps = Some rdeps};
+ rdeps
+
+and iter fname rdeps dname =
+ if StringSet.mem dname rdeps then
+ begin Printf.printf "%s: redundant %s\n" fname dname; rdeps end
+ else
+ let file = Hashtbl.find graph dname in
+ StringSet.add dname (StringSet.union (compute dname file) rdeps)
+
+let check () =
+ let iter fname file =
+ if StringSet.mem fname (compute fname file) then
+ Printf.printf "%s: circular\n" fname
+ in
+ Hashtbl.iter iter graph
+
+let rec read ich =
+ let _ = Scanf.fscanf ich "./%s@:include \"%s@\". " init in
+ read ich
+
+let _ =
+ try read stdin with End_of_file -> check ()