1 /* HTML-format output routines for GNU DIFF.
2 Copyright (C) 1988, 89, 91, 92, 93 Free Software Foundation, Inc.
4 This file is part of GNU DIFF.
6 GNU DIFF 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, or (at your option)
11 GNU DIFF 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 GNU DIFF; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21 #include "PatchHTML.h"
25 static struct change *find_hunk(struct change *);
26 static void mark_ignorable(struct change *);
27 static void pr_unidiff_hunk(struct change *);
28 static void print_1_escapedhtml(const char **line);
29 static void output_1_escapedhtml(const char *text, const char *limit);
31 /* Print a header for a context diff, with the file names and dates. */
34 print_html_header (void)
37 "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n"
40 "<title>WinMerge File Compare Report</title>\n"
42 "<style type=\"text/css\">\n"
46 " background-color: #ffffff;\n"
54 " A:link { color: #0000ff; }\n"
55 " A:visited { color: #880088; }\n"
56 " A:active { color: #0000ff; }\n"
59 " /** Navigation Headers ***/\n"
61 " background-color: #8888ff;\n"
65 " /*** Table Headers ***/\n"
67 " text-align: left;\n"
68 " background-color: #cccccc;\n"
70 " .vc_header_sort {\n"
71 " text-align: left;\n"
72 " background-color: #88ff88;\n"
76 " /*** Table Rows ***/\n"
78 " background-color: #ffffff;\n"
81 " background-color: #ccccee;\n"
85 " /*** Markup Summary Header ***/\n"
87 " background-color: #eeeeee;\n"
91 " /*** Colour Diff Styles ***/\n"
92 " .vc_diff_header {\n"
93 " background-color: #ffffff;\n"
95 " .vc_diff_chunk_header {\n"
96 " background-color: #99cccc;\n"
98 " .vc_diff_chunk_extra {\n"
99 " font-size: smaller;\n"
101 " .vc_diff_empty {\n"
102 " background-color: #cccccc;\n"
103 " font-family: monospace;\n"
104 " font-size: smaller;\n"
107 " background-color: #aaffaa;\n"
108 " font-family: monospace;\n"
109 " font-size: smaller;\n"
111 " .vc_diff_remove {\n"
112 " background-color: #ffaaaa;\n"
113 " font-family: monospace;\n"
114 " font-size: smaller;\n"
116 " .vc_diff_change {\n"
117 " background-color: #ffff77;\n"
118 " font-family: monospace;\n"
119 " font-size: smaller;\n"
121 " .vc_diff_change_empty {\n"
122 " background-color: #eeee77;\n"
123 " font-family: monospace;\n"
124 " font-size: smaller;\n"
126 " .vc_diff_nochange {\n"
127 " font-family: monospace;\n"
128 " font-size: smaller;\n"
132 " /*** Query Form ***/\n"
133 " .vc_query_form {\n"
134 " background-color: #e6e6e6;\n"
145 print_html_terminator (void)
153 print_html_diff_header (struct file_data inf[])
155 fprintf (outfile, "Left: %s<br />Right: %s<br /><br />", inf[0].name, inf[1].name);
157 "<table cellspacing=\"0\" cellpadding=\"0\">\n"
158 " <tr class=\"vc_diff_header\">\n");
160 char ctimeBuffer[26];
161 ctime_s(ctimeBuffer, sizeof(ctimeBuffer), &inf[0].stat.st_mtime);
163 " <th style=\"width:50%%; vertical-align:top;\">Left: %s</th>\n", ctimeBuffer);
164 ctime_s(ctimeBuffer, sizeof(ctimeBuffer), &inf[1].stat.st_mtime);
166 " <th style=\"width:50%%; vertical-align:top;\">Right: %s</th>\n", ctimeBuffer);
172 print_html_diff_terminator (void)
174 fprintf (outfile, "</table>\n");
177 /* Print an edit script in context format. */
180 print_html_script (struct change *script/*, int src_codepage*/)
182 if (ignore_blank_lines_flag)
183 mark_ignorable (script);
187 for (e = script; e; e = e->link)
191 print_script (script, find_hunk, pr_unidiff_hunk);
194 /* Print a portion of an edit script in unidiff format.
195 HUNK is the beginning of the portion to be printed.
196 The end is marked by a `link' that has been nulled out.
198 Prints out lines from both files, and precedes each
199 line with the appropriate flag-character. */
202 pr_unidiff_hunk (struct change *hunk)
204 int first0, last0, first1, last1, show_from, show_to, i, j, k0, k1;
205 int trans_a, trans_b;
209 /* Determine range of line numbers involved in each file. */
211 analyze_hunk (hunk, &first0, &last0, &first1, &last1, &show_from, &show_to, files);
213 if (!show_from && !show_to)
216 /* Include a context's width before and after. */
218 i = - files[0].prefix_lines;
219 first0 = (std::max) (first0 - context, i);
220 first1 = (std::max) (first1 - context, i);
221 last0 = (std::min) (last0 + context, files[0].valid_lines - 1);
222 last1 = (std::min) (last1 + context, files[1].valid_lines - 1);
226 fprintf (out, " <tr class=\"vc_diff_chunk_header\">\n");
227 fprintf (out, " <td style=\"width:50%%;\">\n");
228 translate_range (&files[0], first0, last0, &trans_a, &trans_b);
229 fprintf (out, " <strong>Line %d</strong> \n", trans_a);
230 fprintf (out, " <span class=\"vc_diff_chunk_extra\"></span>\n");
231 fprintf (out, " </td>\n");
232 fprintf (out, " <td style=\"width:50%%;\">\n");
233 translate_range (&files[1], first1, last1, &trans_a, &trans_b);
234 fprintf (out, " <strong>Line %d</strong> \n", trans_a);
235 fprintf (out, " <span class=\"vc_diff_chunk_extra\"></span>\n");
236 fprintf (out, " </td>\n");
237 fprintf (out, " </tr>\n");
243 while (i <= last0 || j <= last1)
246 /* If the line isn't a difference, output the context from file 0. */
248 if (next == nullptr || i < next->line0)
250 fprintf (out, " <tr>\n");
251 fprintf (out, " <td class=\"vc_diff_nochange\"> ");
252 print_1_escapedhtml(&files[0].linbuf[i++]);
253 fprintf (out, "</td>\n");
254 fprintf (out, " <td class=\"vc_diff_nochange\"> ");
255 print_1_escapedhtml(&files[1].linbuf[j++]);
256 fprintf (out, "</td>\n");
257 fprintf (out, " </tr>\n");
263 if (next->inserted > 0 && next->deleted > 0)
265 while (k0 > 0 || k1 > 0)
267 fprintf (out, " <tr>\n");
270 fprintf (out, " <td class=\"vc_diff_change\"> ");
271 print_1_escapedhtml(&files[0].linbuf[i++]);
272 fprintf (out, "</td>\n");
276 fprintf (out, " <td class=\"vc_diff_empty\"> </td>");
280 fprintf (out, " <td class=\"vc_diff_change\"> ");
281 print_1_escapedhtml(&files[1].linbuf[j++]);
282 fprintf (out, "</td>\n");
286 fprintf (out, " <td class=\"vc_diff_empty\"> </td>");
288 fprintf (out, " </tr>\n");
293 else if (next->deleted > 0 )
297 fprintf (out, " <tr>\n");
298 fprintf (out, " <td class=\"vc_diff_remove\"> ");
299 print_1_escapedhtml(&files[0].linbuf[i++]);
300 fprintf (out, "</td>\n");
301 fprintf (out, " <td class=\"vc_diff_empty\"> </td>");
302 fprintf (out, " </tr>\n");
309 fprintf (out, " <tr>\n");
310 fprintf (out, " <td class=\"vc_diff_empty\"> </td>");
311 fprintf (out, " <td class=\"vc_diff_add\"> ");
312 print_1_escapedhtml(&files[1].linbuf[j++]);
313 fprintf (out, "</td>\n");
314 fprintf (out, " </tr>\n");
317 /* We're done with this hunk, so on to the next! */
324 /* Scan a (forward-ordered) edit script for the first place that more than
325 2*CONTEXT unchanged lines appear, and return a pointer
326 to the `struct change' for the last change before those lines. */
328 static struct change *
329 find_hunk (struct change *start)
337 /* Compute number of first line in each file beyond this changed. */
338 top0 = start->line0 + start->deleted;
339 int top1 = start->line1 + start->inserted;
342 /* Threshold distance is 2*CONTEXT between two non-ignorable changes,
343 but only CONTEXT if one is ignorable. */
344 thresh = ((prev->ignore || (start && start->ignore))
347 /* It is not supposed to matter which file we check in the end-test.
348 If it would matter, crash. */
349 if (start && start->line0 - top0 != start->line1 - top1)
352 /* Keep going if less than THRESH lines
353 elapse before the affected line. */
354 && start->line0 < top0 + thresh);
359 /* Set the `ignore' flag properly in each change in SCRIPT.
360 It should be 1 if all the lines inserted or deleted in that change
361 are ignorable lines. */
364 mark_ignorable (struct change *script)
366 while (script != nullptr)
368 struct change *next = script->link;
369 int first0, last0, first1, last1, deletes, inserts;
371 /* Turn this change into a hunk: detach it from the others. */
372 script->link = nullptr;
374 /* Determine whether this change is ignorable. */
375 analyze_hunk (script, &first0, &last0, &first1, &last1, &deletes, &inserts, files);
376 /* Reconnect the chain as before. */
379 /* If the change is ignorable, mark it. */
380 script->ignore = (char)(!deletes && !inserts);
382 /* Advance to the following change. */
388 print_1_escapedhtml(const char **line)
390 output_1_escapedhtml(line[0], line[1]);
394 output_1_escapedhtml(const char *text, const char *limit)
397 const char *t = text;
402 switch (unsigned char c = *t++)
405 fprintf (out, "&");
410 fprintf (out, ">");
415 fprintf (out, "<");
420 if (spcolumn + 1 < column)
423 fprintf (out, " ");
429 fprintf (out, """);
434 unsigned spaces = TAB_WIDTH - column % TAB_WIDTH;
441 fprintf (out, " ");