Plasma GitLab Archive
Projects Blog Knowledge

#! /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
       ()
    )

This web site is published by Informatikbüro Gerd Stolpmann
Powered by Caml