#! /bin/sh
# (*
exec /opt/godi-3.11-ocamlnet3/bin/ocaml "$0" "$@"
*) directory ".";;
(* $Id: browser.cgi 10 2010-08-02 01:01:07Z gerd $
* ----------------------------------------------------------------------
*
*)
#use "topfind";;
#require "findlib";;
#require "unix";;
#require "str";;
#require "netcgi2";;
(* -CUT- *)
(* ---------------------------------------------------------------------- *)
let buffered_transactional_optype =
`Transactional (fun config ch -> new Netchannels.buffered_trans_channel ch)
module type CGI = sig val cgi : Netcgi.cgi end
module Body(Cgi : CGI) = struct
let cgi = Cgi.cgi
let param n = (cgi # argument n) # value;;
let print s = cgi # output # output_string s;;
let cancel() = cgi # output # rollback_work();;
let commit() = cgi # output # commit_work();;
(* ---------------------------------------------------------------------- *)
let list_directory d =
try
let dd = Unix.opendir d in
let rec read () =
try
let name = Unix.readdir dd in
if name <> "." & name <> ".." then
name :: read()
else
read()
with
End_of_file ->
Unix.closedir dd;
[]
in
read()
with
Unix.Unix_error (code,_,_) ->
prerr_endline ("Warning: cannot read directory " ^ d ^ ": " ^
Unix.error_message code);
[]
;;
let all_packages() =
let l = Fl_package_base.list_packages() in
Sort.list ( <= ) l
;;
let modules_of_pkg pkg =
try
List.map
String.capitalize
(Str.split
(Str.regexp "[ \t]*\\([ \t]\\|,\\)[ \t]*")
(Findlib.package_property [] pkg "browse_interfaces"))
with
Not_found ->
let d = Findlib.package_directory pkg in
let l = list_directory d in
let re = Str.regexp "^\\(.*\\)\\.cmi$" in
List.flatten
(List.map
(fun f ->
if Str.string_match re f 0 then
[String.capitalize (Str.matched_group 1 f)]
else
[])
l)
;;
(* ---------------------------------------------------------------------- *)
let escape_html =
Netencoding.Html.encode ~in_enc:`Enc_iso88591 ()
;;
type text =
Highlighted of string
| Normal of string
;;
let read_file path =
let fd = open_in path in
let rec read () =
try
let line = input_line fd in
Normal line :: Normal "\n" :: read()
with
End_of_file -> []
in
let t = read() in
close_in fd;
t
;;
let rec highlight re t =
let rec highlight_string s k =
if k < String.length s then begin
try
let k' = Str.search_forward re s k in
let x1 = Normal (String.sub s k (k'-k)) in
let x2 = Highlighted (Str.matched_string s) in
let x3 = highlight_string s (Str.match_end()) in
x1 :: x2 :: x3
with
Not_found ->
[ Normal (String.sub s k (String.length s - k)) ]
end
else []
in
match t with
Highlighted s :: t' -> Highlighted s :: highlight re t'
| Normal s :: t' ->
highlight_string s 0 @ highlight re t'
| [] ->
[]
;;
let rec somewhere_highlighted t =
match t with
Normal s :: t' -> somewhere_highlighted t'
| Highlighted s :: t' -> true
| [] -> false
;;
let highlighted_lines t =
let rec extract this_line t =
match t with
Normal "\n" :: t' ->
extract t' t'
| Normal s :: t' ->
extract this_line t'
| Highlighted s :: t' ->
extract_line this_line
| [] ->
[]
and extract_line this_line =
match this_line with
Normal "\n" :: l' -> Normal "\n" :: extract l' l'
| [] -> []
| x :: l' -> x :: extract_line l'
in
extract t t
;;
let rec print_text t =
match t with
Normal s :: t' ->
print (escape_html s);
print_text t'
| Highlighted s :: t' ->
print "<font color=\"blue\"><b>";
print (escape_html s);
print "</b></font>";
print_text t'
| [] ->
()
;;
(* ---------------------------------------------------------------------- *)
let action() =
let pkg =
try
Str.split (Str.regexp ",") (param "pkg")
with
Not_found -> [] in
let modules =
try
Str.split (Str.regexp ",") (param "mod")
with
Not_found -> [] in
let searchmod = try param "searchmod" with Not_found -> "" in
let searchtext = try param "searchtext" with Not_found -> "" in
let hlight = try param "hlight" with Not_found -> "" in
let pkg_url p =
"<a href=\"browser.cgi?" ^
"pkg=" ^ Netencoding.Url.encode p ^
"\">" ^
escape_html p ^
"</a>"
in
let mod_url p m =
"<a href=\"browser.cgi?" ^
"pkg=" ^ Netencoding.Url.encode p ^
"&mod=" ^ Netencoding.Url.encode m ^
"\">" ^
escape_html m ^
"</a>"
in
let mod_url_hl p m hl =
"<a href=\"browser.cgi?" ^
"pkg=" ^ Netencoding.Url.encode p ^
"&mod=" ^ Netencoding.Url.encode m ^
"&hlight=" ^ Netencoding.Url.encode hl ^
"\">" ^
escape_html m ^
"</a>"
in
(*** headline ***)
cgi # set_header();
print "<html><head><title>Objective Caml Packages</title></head>\n";
print "<body bgcolor=white>\n";
print "<h1>Objective Caml Packages</h1>\n";
(*** package list ***)
let n_cols = 6 in
let l_packages = all_packages() in
let packages = Array.of_list l_packages in
let n = Array.length packages in
let n_rows = (n-1)/n_cols + 1 in
print "<table>\n";
for row = 0 to n_rows - 1 do
print "<tr>\n";
for col = 0 to n_cols - 1 do
let k = col * n_rows + row in
if k < n then begin
print "<td>";
print (pkg_url packages.(k));
print "</td>\n";
end
done;
print "</tr>\n";
done;
print "</table>\n";
(*** searched modules ***)
if searchmod <> "" then begin
print "<h1>Results of module search</h1>\n";
let l1 = Str.split_delim (Str.regexp "\\*") searchmod in
let s1 = "^" ^ String.concat ".*" (List.map Str.quote l1) ^ "$" in
let r1 = Str.regexp_case_fold s1 in
let rec search_pkg pl =
match pl with
[] -> []
| p :: pl' ->
let modules = Sort.list ( <= ) (modules_of_pkg p) in
let found_modules =
List.flatten
(List.map
(fun m ->
if Str.string_match r1 m 0 then [m] else [])
modules) in
List.map (fun m -> p,m) found_modules
@ search_pkg pl'
in
let result = search_pkg l_packages in
if result = [] then
print "Sorry, nothing found.\n"
else begin
print "<table>\n";
List.iter
(fun (p,m) ->
print "<tr valign=top>\n";
print ("<td>Package " ^ pkg_url p ^ "</td>\n");
print ("<td>Module " ^ mod_url p m ^ "</td>\n");
print "</tr>\n")
result;
print "</table>\n"
end
end;
(*** full-text search ***)
if searchtext <> "" then begin
print "<h1>Results of full-text search</h1>\n";
let l1 = Str.split_delim (Str.regexp "\\*") searchtext in
let s1 = String.concat ".*" (List.map Str.quote l1) in
let r1 = Str.regexp_case_fold s1 in
let rec search_pkg pl =
match pl with
[] -> []
| p :: pl' ->
let p_dir = Findlib.package_directory p in
let modules = Sort.list ( <= ) (modules_of_pkg p) in
let found =
List.flatten
(List.map
(fun m ->
let m_file = String.uncapitalize m ^ ".mli" in
let m_path = Filename.concat p_dir m_file in
if Sys.file_exists m_path then begin
let t = read_file m_path in
let t' = highlight r1 t in
if somewhere_highlighted t' then
let lines = highlighted_lines t' in
[p,m,lines]
else
[]
end
else [])
modules) in
found @ search_pkg pl'
in
let result = search_pkg l_packages in
if result = [] then
print "Sorry, nothing found.\n"
else begin
print "<table>\n";
List.iter
(fun (p,m,lines) ->
print "<tr valign=top>\n";
print ("<td>Package " ^ pkg_url p ^ "</td>\n");
print ("<td>Module " ^ mod_url_hl p m s1 ^ "</td>\n");
print "</tr>\n";
print "<tr valign=top>\n";
print "<td></td><td><pre>\n";
print_text lines;
print "</pre></td></tr>\n")
result;
print "</table>\n"
end
end;
(*** selected packages ***)
List.iter
(fun p ->
if List.mem p l_packages then begin
let p_html = escape_html p in
print ("<h1>Package <code>" ^ p_html ^ "</code></h1>\n");
let version =
try Findlib.package_property [] p "version"
with Not_found -> "unknown"
in
let description =
try Findlib.package_property [] p "description"
with Not_found -> "none"
in
let uses_pkg = Findlib.package_ancestors [] p in
let pkg_mods = Sort.list ( <= ) (modules_of_pkg p) in
print "<table>\n";
print "<tr valign=top>\n";
print "<td>Version:</td>\n";
print ("<td>" ^ escape_html version ^ "</td>\n");
print "</tr>\n";
print "<tr valign=top>\n";
print "<td>Description:</td>\n";
print ("<td>" ^ escape_html description ^ "</td>\n");
print "</tr>\n";
print "<tr valign=top>\n";
print "<td>Ancestors:</td>\n";
print "<td>";
if uses_pkg = [] then
print "none"
else
print (String.concat ", " (List.map pkg_url uses_pkg));
print "</td>\n";
print "</tr>\n";
print "<tr valign=top>\n";
print "<td>Modules:</td>\n";
print "<td>";
if pkg_mods = [] then
print "none"
else
print (String.concat ", " (List.map (mod_url p) pkg_mods));
print "</td>\n";
print "</tr>\n";
print "</table>\n";
end)
pkg;
(*** selected modules ***)
if List.length pkg = 1 then begin
let p = List.hd pkg in
let p_dir = Findlib.package_directory p in
List.iter
(fun m ->
let m_html = escape_html m in
print ("<h1>Module <code>" ^ m_html ^ "</code></h1>\n");
let m_file = String.uncapitalize m ^ ".mli" in
let m_path = Filename.concat p_dir m_file in
if Sys.file_exists m_path then begin
print "<pre>\n";
let t = read_file m_path in
let t' =
if hlight <> "" then
highlight (Str.regexp_case_fold hlight) t
else
t
in
print_text t';
print "</pre>\n"
end
else
print "Sorry, no printable interface definition found.")
modules
end;
(*** search ***)
print "<h1>Search</h1>\n";
print "You may use <code>*</code> as wildcard character.<br>\n";
print "<form method=post action=\"browser.cgi\">\n";
print "<table>\n";
print "<tr>\n";
print "<td>Search toplevel module:</td>";
print "<td><input type=text name=\"searchmod\"></td>";
print "<td><input type=submit name=\"do_searchmod\" value=\"Go!\"><br></td>\n";
print "</tr>\n";
print "<tr>\n";
print "<td>Full-text search:</td>";
print "<td><input type=text name=\"searchtext\"></td>";
print "<td><input type=submit name=\"do_searchtext\" value=\"Go!\"><br></td>\n";
print "</tr>\n";
print "</table>\n";
print "</form>\n";
print "</body></html>\n"
;;
begin try
action()
with
e ->
cgi # set_header();
print "<html><body><h1>Software error</h1>\n";
print (Printexc.to_string e);
print "</body></html>\n";
end;
commit()
end
let () =
Netcgi_cgi.run
~output_type:buffered_transactional_optype
(fun cgi ->
let module Cgi = struct let cgi = cgi end in
let module B = Body(Cgi) in
()
)