1 (* COCANWIKI - a wiki written in Objective CAML.
2 * Written by Richard W.M. Jones <rich@merjis.com>.
3 * Copyright (C) 2004 Merjis Ltd.
4 * $Id: cocanwiki_diff.ml,v 1.6 2006/08/04 12:20:07 rich Exp $
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; see the file COPYING. If not, write to
18 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
31 (* Convenience code for generating diffs between versions. See diff.ml
32 * and edit.ml which both use this code.
34 let page_for_diff model css =
35 let title_or_url = match model.pt with Page t -> t | Title t -> t in
36 "Title or URL: " ^ title_or_url ^ "\n" ^
37 "Description: " ^ model.description ^ "\n\n" ^
38 (match model.redirect with
40 | Some redirect -> "Redirect: " ^ redirect ^ "\n\n") ^
43 fun (sectionname, divname, jsgo, content) ->
44 (match sectionname with
46 | Some sectionname -> "HEADING: " ^ sectionname ^ "\n\n") ^
50 | Some divname -> "CSS Id: " ^ divname ^ "\n") ^
53 | Some jsgo -> "Javascript Onclick: " ^ jsgo ^ "\n") ^
59 | Some css -> "CSS:\n\n" ^ css ^ "\n")
61 let le_re = Pcre.regexp "\r?\n"
62 let le_subst = Pcre.subst "\n"
64 let diff_cmd old_page new_page =
65 (* Convert line-endings in the input files from \r\n to \n. Diff
66 * can get confused by the \r characters, particularly in side-by-side
67 * mode when asked to expand tabs (-y -t).
69 let f = Pcre.replace ~rex:le_re ~itempl:le_subst in
70 let new_page = f new_page in
71 let old_page = f old_page in
73 let new_filename = output_tempfile new_page in
74 let old_filename = output_tempfile old_page in
76 (* Side-by-side mode was good, but stupidly implemented. It's
79 let diff_sidebyside = false in
82 if not diff_sidebyside then
86 let options = options ^ " -t -b -B" in
88 let cmd = sprintf "diff %s %s %s ||:" options old_filename new_filename in
89 let diff = pget cmd in
91 (* Remove the temporary files. *)
92 unlink new_filename; unlink old_filename;
95 if not diff_sidebyside then
97 _ :: _ :: diff -> diff
101 String.concat "\n" diff
103 let get_version_for_diff dbh version =
104 if version = 0l then ""
106 let title, description, redirect, css = List.hd (
108 "select title, description, redirect, css from pages
112 let contents_ = PGSQL(dbh)
113 "select sectionname, divname, jsgo, content
114 from contents where pageid = $version
115 order by ordering" in
117 let model = { id = version;
119 description = description;
121 contents_ = contents_ } in
123 let page = page_for_diff model css in
128 let get_diff dbh hostid page ?old_version ~version ()=
130 match old_version with
131 | Some version -> version
136 "select id from pages
137 where hostid = $hostid
138 and url_deleted = $page
140 order by 1 desc limit 1"
143 Not_found | ExtList.List.Empty_list | Failure "hd" -> 0l in
145 (* Get the two versions. *)
146 let new_page = get_version_for_diff dbh version in
147 let old_page = get_version_for_diff dbh old_version in
149 (* Compute the diff of the two versions. *)
150 let diff = diff_cmd old_page new_page in