(* This CDuce script produces CDuce web site. *) (** Command line **) let (input, php) = match argv with | [ "-php" s ] -> (s, `true) | [ s ] -> (s, `false) | _ -> raise "Please specify an input file on the command line" (** Output types **) include "xhtml-strict.cd" (* XHTML 1 Strict DTD *) include "xhtml-categ.cd" (* Categories (Inline, ...) from this DTD *) (** Input types **) type Page = [ String <banner>[InlineText*]? Item* ] type External = <external {|href=String; title=String; name=String |}>[] type Item = <box title=String; subtitle=?String; link=String>Content | <meta>Content | <left>Content | Page | External type Author = <author>String type Paper = <paper file=?String>[ <title>String Author+ <comment>[InlineText*] <abstract>Content ] type Slides = <slides file=String>[ <title>String Author+ <comment>[InlineText*] ] type Link = <link url=String; title=String>[ InlineText* ] type Content = [ ( <p {||}>[InlineText*] | <ul {||}>[<li {||}>Content +] | <section title=String>Content | <sample highlight=?"true"|"false">String | Xtable | Paper | Slides | Link | <boxes-toc>[] | <pages-toc>[] | <site-toc>[] | <local-links href=String>[] | <two-columns>[ <left>Content <right>Content ] | InlineText )* ] type InlineText = Char | <(`b|`i|`tt|`em) {||}>[InlineText*] | <code>String | <local href=String>String | Xa | Ximg | Xbr (** Generic purpose functions **) (* Recursive inclusion of XML files and verbatim text files *) let load_include (String -> [Any*]) name -> (* let _ = print [ 'Loading ' !name '... \n' ] in *) xtransform [ (load_xml name) ] with | <include file=(s & String)>[] -> load_include s | <include-verbatim file=(s & String)>[] -> load_file s (* Highlighting text between {{...}} *) let highlight (String -> [ (Char | Xvar | Xi)* ] ) | [ '{{' h ::(Char *?) '}}' ; rest ] -> [ <var class="highlight">h; highlight rest ] | [ '%%' h ::(Char *?) '%%' ; rest ] -> [ <i>h; highlight rest ] | [ c; rest ] -> [ c; highlight rest ] | [] -> [] (* Split a comma-separated string *) let split_comma (String -> [String*]) | [ x::(Char*?) ',' ; rest ] -> (x, split_comma rest) | s -> [ s ] (** Ugly hack to introduce PHP code ... The idea is to produce first an XML document with a distinguished element. The function patch_css search for the textual representation of this element and replace it with the PHP code. **) let css : Latin1 = ['<link rel="stylesheet" href="cduce.css" type="text/css">'] let protect_quote (s : Latin1) : Latin1 = transform s with '"' -> [ '\\"' ] | c -> [c] let php_css : Latin1 = if php then [' <?php $browser = getenv("HTTP_USER_AGENT"); if (preg_match("/MSIE/i", "$browser")) { $css = "<link rel=\\"stylesheet\\" href=\\"cduce.css\\" type=\\"text/css\\">"; } elseif (preg_match("/Mozilla/i", "$browser")) { $css = "<blink>For better presentation use a more recent version of your browser, like Netscape 6</blink>"; } if (preg_match("/Mozilla\\/5.0/i", "$browser")) { $css = "<link rel=\\"stylesheet\\" href=\\"cduce.css\\" type=\\"text/css\\">"; } elseif (preg_match("/opera/i", "$browser")) { $css = "<link rel=\\"stylesheet\\" href=\\"cduce.css\\" type=\\"text/css\\">"; } echo "$css"; ?> '] else css (** It does not work with IE if php then [' <?php $browser = getenv("HTTP_USER_AGENT"); if (preg_match("/Mozilla/i", "$browser") && !preg_match("/Mozilla\\/5.0/i", "$browser")) { echo "<blink>For better presentation use a more recent version of your browser, like Netscape 6</blink>"; } else { echo "' !(protect_quote css) '"; } ?> '] else css **) let patch_css (Latin1 -> Latin1) | [ a::_*? '<meta content="css"/>'; rem ] -> a @ php_css @ rem | s -> s (** Internal types **) type Path = [ { url = String; title = String }* ] type Tree = { name = String; url = String; title = String; children = [Tree*] } let url_of_name (String -> String) "index" -> "/" | s -> s @ ".html" let authors ([Author+] -> String) | [ <author>a ] -> a | [ <author>a1 <author>a2 ] -> a1 @ ", and " @ a2 | [ <author>a; rem ] -> a @ ", " @ authors rem let find_local_link (sitemap : [Tree*], l : String) : Tree = match sitemap with | (h,t) -> if (h . name = l) then h else (try find_local_link (t,l) with `Not_found -> find_local_link (h . children,l)) | [] -> raise `Not_found let local_link (sitemap : Tree, l : String, txt : String) : Inline = try let h = find_local_link ([sitemap],l) in let txt = if txt = "" then h . title else txt in <a href=(h . url)>txt with `Not_found -> raise [ 'Local link not found: ' !l ] let compute_sitemap ((Page|External) -> Tree) <page name=name>[ <title>title (c::(Page|External) | _)* ] -> let children = map c with p -> compute_sitemap p in { name = name; url = url_of_name name; title = title; children =children } |<external name=name; href=h; title=t>[] -> { name = name; url = h; title = t; children = [] } let display_sitemap (h : Tree) : Xli = let ch = map h . children with x -> display_sitemap x in let ch = match ch with [] -> [] | l -> [ <ul>l ] in <li>[ <a href=(h . url)>(h . title); ch ] let link_to (Page -> Xa) <page name=n>[<title>t ; _ ] -> <a href=(url_of_name n)>t (* Main transformation function *) (* returns the last page of the descendance *) let gen_page (prev : Page|[], page : Page, next : Page|[], path : Path, sitemap : Tree) : (Page|[]) = match page with <page name=name>[ <title>title <banner>banner | <title>(title & banner); items ] -> let text (t : [InlineText*]) : Inlines = map t with | <code>x -> <b>[ <tt>(highlight x) ] | <local href=l>txt -> local_link (sitemap,l,txt) | <(tag & (`b|`i|`tt|`em))>x -> <(tag)>(text x) (* | <a href=url>_ & z -> let [] = print [ 'Link: ' !url '\n'] in z *) | z -> z in let content (t : Content) : Flow = transform t with | <section title=title>c -> [ <h4>title !(content c) ] | <paper (r)>[ <title>tit aut::Author* <comment>com <abstract>ab ] -> [ (match r with { file = f } -> <a href=f>tit | _ -> <b>tit) '. ' !(authors aut) '. ' !(text com) <div class="abstract">[ 'Abstract:' !(content ab) ] ] | <slides file=f>[ <title>tit aut::Author* <comment>com ] -> [ <a href=f>tit '. ' !(authors aut) '. ' !(text com) ] | <sample highlight="false">s -> [ <div class="code">[ <pre>s ] ] | <sample>s -> [ <div class="code">[ <pre>(highlight s) ] ] | <link url=url; title=title>com -> [ <a href=url>title '. ' !(text com) ] | <ul>lis -> [ <ul>(map lis with <li>x -> <li>(content x)) ] | Xtable & x -> [ x ] | <p>x -> [ <p>(text x) ] | <pages-toc>[] -> let toc = transform items with | Page & p -> [ <li>[ (link_to p) ] ] | <external href=l; title=t>[] -> [ <li>[ <a href=l>t ] ] in (match toc with [] -> [] | lis -> [ <ul>lis ]) | <boxes-toc>[] -> let toc = transform items with <box title=t; link=l>_ -> [ <li>[ <a href=('#',l)>t ] ] in (match toc with [] -> [] | lis -> [ <ul>lis ]) | <site-toc>[] -> [ <ul>[ (display_sitemap sitemap) ] ] | <local-links href=s>[] -> (match (split_comma s) with | [] -> [] | l -> let l = map l with x -> <li>[ (local_link(sitemap,x,"")) ] in [ <ul>l ]) | <two-columns>[ <left>x <right>y ] -> [ <table width="100%">[ <tr>[ <td valign="top">(content x) <td valign="top">(content y) ] ] ] | t -> text [ t ] in let main : Flow = transform items with | <box (r)>c -> [ <div class="box">[ <h2>(r . title) !(match r with { subtitle = t } -> [<b>t] | _ -> []) <a name=r . link>[] !(content c) ] ] | <meta>c -> [ <div class="meta">(content c) ] in let navig : Flow = transform items with | <left>c -> [<div class="box">(content c)] in let left = match navig with | [] -> [<div class="box">(content [<boxes-toc>[]])] | n -> n in let dpath : Inlines = transform path with | { url = f; title = t } -> [ <a href=f>t ': '] in let npath = path @ [ { url = url_of_name name; title = title } ] in let subpages = transform items with p & Page -> [ p ] in let (next,last) = gen_page_seq (page, subpages, next, npath, sitemap) in let next = match next with [] -> [] | <page name=n>[ <title>t; _ ] -> [ <a href=(url_of_name n)>[ <img width="16"; height="16"; class="icon"; alt="Next page"; src="img/right.gif">[] ' ' !t ] ] in let prev = match prev with [] -> [] | <page name=n>[ <title>t; _ ] -> [ <a href=(url_of_name n)>[ <img width="16"; height="16"; class="icon"; alt="Previous page"; src="img/left.gif">[] ' ' !t ] ] in let navig : [ Xdiv* ] = if prev = [] then [] else [ <div class="box">[ <p>[ !dpath !title ] <p>[ !prev ' ' !next ] ] ] in let html : Xhtml = <html>[ <head>[ <title>[ 'CDuce: ' !title ] <meta content="text/html; charset=iso-8859-1"; http-equiv="Content-Type">[] <meta content="css">[] (* Placeholder for PHP code *) ] <body>[ <div class="title">[ <h1>(text banner) ] <div id="Sidelog">left <div id="Content">( navig @ main @ navig ) ] ] in let txt : Latin1 = [ '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"' ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' !(patch_css (print_xml html)) ] in let fn = "www/" @ name @ (if php then ".html.php" else ".html") in let [] = dump_to_file fn txt in last let gen_page_seq (prev : Page|[], pages : [Page*], next : Page|[], path : Path, sitemap : Tree) : (Page|[], Page|[]) = match pages with | [ p1 p2 ; _ ] & [ _; rest ] -> let last = gen_page (prev,p1,p2, path, sitemap) in let (_,last) = gen_page_seq (last, rest, next, path, sitemap) in (p1,last) | [ p ] -> let last = gen_page (prev,p,next, path, sitemap) in (p,last) | [] -> (next,prev) ;; match load_include input with | [ Page & p ] -> let _ = gen_page ([],p,[], [], compute_sitemap p) in [] | _ -> raise ("Invalid input document " @ input)