(* COCANWIKI - a wiki written in Objective CAML.
* Written by Richard W.M. Jones <rich@merjis.com>.
* Copyright (C) 2004 Merjis Ltd.
- * $Id: wikilib.ml,v 1.5 2006/03/27 16:43:44 rich Exp $
+ * $Id: wikilib.ml,v 1.6 2006/07/26 14:59:04 rich Exp $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
(* close tags ignored *)
escape_html first :: "</" :: escape_html elem :: ">" ::
loop (rest, [])
- | FoundOpen (first, elem, rest) when elem = "nowiki" ->
+ | FoundOpen (first, "nowiki", rest) ->
(* handle <nowiki> specially ... *)
- escape_html first :: loop (rest, elem :: [])
- | FoundOpen (first, elem, rest) when elem = "br" ->
+ escape_html first :: loop (rest, "nowiki" :: [])
+ | FoundOpen (first, "br", rest) ->
(* handle <br> specially ... *)
escape_html first :: "<br/>" :: loop (rest, [])
| FoundOpen (first, elem, rest) ->
| FoundClose (first, elem, rest, elem_rest) ->
(* non-matching close tag *)
escape_html first :: "</" :: x :: ">" :: loop (elem_rest, xs)
- | FoundOpen (first, elem, rest) when elem = "nowiki" ->
+ | FoundOpen (first, "nowiki", rest) ->
(* handle <nowiki> specially ... *)
- escape_html first :: loop (rest, elem :: stack)
- | FoundOpen (first, elem, rest) when elem = "br" ->
+ escape_html first :: loop (rest, "nowiki" :: stack)
+ | FoundOpen (first, "br", rest) ->
(* handle <br> specially ... *)
escape_html first :: "<br/>" :: loop (rest, stack)
| FoundOpen (first, elem, rest) ->
let preformatted_re = Pcre.regexp "^ (.*)"
let html_open_re = Pcre.regexp "^<html>\\s*$"
let html_close_re = Pcre.regexp "^</html>\\s*$"
+let macro_re = Pcre.regexp "^{{(\\w+)}}$"
let xhtml_of_content dbh hostid text =
(* Split the text into lines. *)
let lines = Pcre.split ~rex:split_lines_re text in
+ (* Do macro expansion before anything else, because macros could
+ * contain <html> sections, etc.
+ *)
+ let is_macro line =
+ try
+ let subs = Pcre.exec ~rex:macro_re line in
+ let name = Pcre.get_substring subs 1 in
+ let rows = PGSQL(dbh) "select 1 from macros
+ where hostid = $hostid and name = $name" in
+ (match rows with
+ | [] -> false (* Not an actual macro name from the database. *)
+ | [_] -> true (* Is an actual macro name. *)
+ | _ -> assert false (* Uniqueness should stop this from happening. *)
+ )
+ with
+ Not_found -> false
+ in
+ let expand_macro line =
+ try
+ let subs = Pcre.exec ~rex:macro_re line in
+ let name = Pcre.get_substring subs 1 in
+ let content =
+ List.hd (
+ PGSQL(dbh) "select content from macros
+ where hostid = $hostid and name = $name"
+ ) in
+ (* Split the content into lines of text. *)
+ let lines = Pcre.split ~rex:split_lines_re content in
+ lines
+ with
+ (Not_found | Failure "hd" | ExtList.List.Empty_list) as exn ->
+ failwith ("Wikilib: expand_macro: you should never see this: " ^
+ Printexc.to_string exn)
+ in
+ let rec loop = function
+ | [] -> []
+ | line :: xs when is_macro line -> expand_macro line @ loop xs
+ | x :: xs -> x :: loop xs
+ in
+ let lines = loop lines in
+
(* HTML blocks span multiple lines, so isolate these out first. *)
let rec loop = function
| [] -> []
(* Iterate over the lines to isolate headers and paragraphs. *)
let lines =
- List.map
- (function
- | STpLine line ->
- if Pcre.pmatch ~rex:preformatted_re line then (
- let subs = Pcre.exec ~rex:preformatted_re line in
- let line = Pcre.get_substring subs 1 in
- STPreformatted [line]
- )
- else if Pcre.pmatch ~rex:blank_re line then
- STBlank
- else if Pcre.pmatch ~rex:heading_re line then (
- let subs = Pcre.exec ~rex:heading_re line in
- let count = String.length (Pcre.get_substring subs 1) + 2 in
- let line = Pcre.get_substring subs 2 in
- STHeading (count, line)
- )
- else if Pcre.pmatch ~rex:unnumbered_re line then (
- let subs = Pcre.exec ~rex:unnumbered_re line in
- let line = Pcre.get_substring subs 2 in
- STUnnumbered [line]
- )
- else if Pcre.pmatch ~rex:numbered_re line then (
- let subs = Pcre.exec ~rex:numbered_re line in
- let line = Pcre.get_substring subs 2 in
- STNumbered [line]
- ) else
- STParagraph line
- | STpHTML html ->
- STHTML html
- ) lines in
+ List.map (
+ function
+ | STpLine line ->
+ if Pcre.pmatch ~rex:preformatted_re line then (
+ let subs = Pcre.exec ~rex:preformatted_re line in
+ let line = Pcre.get_substring subs 1 in
+ STPreformatted [line]
+ )
+ else if Pcre.pmatch ~rex:blank_re line then
+ STBlank
+ else if Pcre.pmatch ~rex:heading_re line then (
+ let subs = Pcre.exec ~rex:heading_re line in
+ let count = String.length (Pcre.get_substring subs 1) + 2 in
+ let line = Pcre.get_substring subs 2 in
+ STHeading (count, line)
+ )
+ else if Pcre.pmatch ~rex:unnumbered_re line then (
+ let subs = Pcre.exec ~rex:unnumbered_re line in
+ let line = Pcre.get_substring subs 2 in
+ STUnnumbered [line]
+ )
+ else if Pcre.pmatch ~rex:numbered_re line then (
+ let subs = Pcre.exec ~rex:numbered_re line in
+ let line = Pcre.get_substring subs 2 in
+ STNumbered [line]
+ )
+ else
+ STParagraph line
+ | STpHTML html ->
+ STHTML html
+ ) lines in
(* Aggregate paragraphs and lists. *)
let rec loop = function