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.7 2006/08/04 12:45:33 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.keywords with
40 | Some keywords -> "Keywords: " ^ keywords ^ "\n\n") ^
41 (match model.redirect with
43 | Some redirect -> "Redirect: " ^ redirect ^ "\n\n") ^
46 fun (sectionname, divname, jsgo, content) ->
47 (match sectionname with
49 | Some sectionname -> "HEADING: " ^ sectionname ^ "\n\n") ^
53 | Some divname -> "CSS Id: " ^ divname ^ "\n") ^
56 | Some jsgo -> "Javascript Onclick: " ^ jsgo ^ "\n") ^
62 | Some css -> "CSS:\n\n" ^ css ^ "\n")
64 let le_re = Pcre.regexp "\r?\n"
65 let le_subst = Pcre.subst "\n"
67 let diff_cmd old_page new_page =
68 (* Convert line-endings in the input files from \r\n to \n. Diff
69 * can get confused by the \r characters, particularly in side-by-side
70 * mode when asked to expand tabs (-y -t).
72 let f = Pcre.replace ~rex:le_re ~itempl:le_subst in
73 let new_page = f new_page in
74 let old_page = f old_page in
76 let new_filename = output_tempfile new_page in
77 let old_filename = output_tempfile old_page in
79 (* Side-by-side mode was good, but stupidly implemented. It's
82 let diff_sidebyside = false in
85 if not diff_sidebyside then
89 let options = options ^ " -t -b -B" in
91 let cmd = sprintf "diff %s %s %s ||:" options old_filename new_filename in
92 let diff = pget cmd in
94 (* Remove the temporary files. *)
95 unlink new_filename; unlink old_filename;
98 if not diff_sidebyside then
100 _ :: _ :: diff -> diff
104 String.concat "\n" diff
106 let get_version_for_diff dbh version =
107 if version = 0l then ""
109 let title, description, keywords, redirect, css = List.hd (
111 "select title, description, keywords, redirect, css from pages
115 let contents_ = PGSQL(dbh)
116 "select sectionname, divname, jsgo, content
117 from contents where pageid = $version
118 order by ordering" in
120 let model = { id = version;
122 description = description;
125 contents_ = contents_ } in
127 let page = page_for_diff model css in
132 let get_diff dbh hostid page ?old_version ~version ()=
134 match old_version with
135 | Some version -> version
140 "select id from pages
141 where hostid = $hostid
142 and url_deleted = $page
144 order by 1 desc limit 1"
147 Not_found | ExtList.List.Empty_list | Failure "hd" -> 0l in
149 (* Get the two versions. *)
150 let new_page = get_version_for_diff dbh version in
151 let old_page = get_version_for_diff dbh old_version in
153 (* Compute the diff of the two versions. *)
154 let diff = diff_cmd old_page new_page in