• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package jdiff;
2 
3 import java.io.*;
4 import java.util.*;
5 
6 /**
7  * Class to generate colored differences between two sections of HTML text.
8  *
9  * See the file LICENSE.txt for copyright details.
10  * @author Matthew Doar, mdoar@pobox.com
11  */
12 class Diff {
13 
14     /**
15      * Save the differences between the two strings in a DiffOutput object
16      * for later use.
17      *
18      * @param id A per-package unique identifier for each documentation
19      *           change.
20      */
saveDocDiffs(String pkgName, String className, String oldDoc, String newDoc, String id, String title)21     static String saveDocDiffs(String pkgName, String className,
22                                String oldDoc, String newDoc,
23                                String id, String title) {
24         // Generate the string which will link to this set of diffs
25         if (noDocDiffs)
26             return "Documentation changed from ";
27         if (oldDoc == null || newDoc == null) {
28             return "Documentation changed from ";
29         }
30 
31         // Generate the differences.
32         generateDiffs(pkgName, className, oldDoc, newDoc, id, title);
33 
34         return "Documentation <a href=\"" + diffFileName + pkgName +
35             HTMLReportGenerator.reportFileExt + "#" + id +
36             "\">changed</a> from ";
37     }
38 
39     /**
40      * Generate the differences.
41      */
generateDiffs(String pkgName, String className, String oldDoc, String newDoc, String id, String title)42     static void generateDiffs(String pkgName, String className,
43                               String oldDoc, String newDoc,
44                               String id, String title) {
45         String[] oldDocWords = parseDoc(oldDoc);
46         String[] newDocWords = parseDoc(newDoc);
47 
48         DiffMyers diff = new DiffMyers(oldDocWords, newDocWords);
49         DiffMyers.change script = diff.diff_2(false);
50         script = mergeDiffs(oldDocWords, newDocWords, script);
51         String text = "<A NAME=\"" + id + "\"></A>" + title + "<br><br>";
52         // Generate the differences in blockquotes to cope with unterminated
53         // HTML tags
54         text += "<blockquote>";
55         text = addDiffs(oldDocWords, newDocWords, script, text);
56         text += "</blockquote>";
57         docDiffs.add(new DiffOutput(pkgName, className, id, title, text));
58     }
59 
60     /**
61      * Convert the string to an array of strings, but don't break HTML tags up.
62      */
parseDoc(String doc)63     static String[] parseDoc(String doc) {
64         String delimiters = " .,;:?!(){}[]\"'~@#$%^&*+=_-|\\<>/";
65         StringTokenizer st = new StringTokenizer(doc, delimiters, true);
66         List docList = new ArrayList();
67         boolean inTag = false;
68         String tag = null;
69         while (st.hasMoreTokens()) {
70             String tok = st.nextToken();
71             if (!inTag) {
72                 if (tok.compareTo("<") == 0) {
73                     tag = tok;
74                     if (st.hasMoreTokens()) {
75                         // See if this really is a tag
76                         tok = st.nextToken();
77                         char ch = tok.charAt(0);
78                         if (Character.isLetter(ch) || ch == '/') {
79                             inTag = true;
80                             tag += tok;
81                         }
82                     }
83                     if (!inTag)
84                       docList.add(tag);
85                 } else {
86                     docList.add(tok);
87                 }
88             } else {
89                 // Add all tokens to the tag until the closing > is seen
90                 if (tok.compareTo(">") == 0) {
91                     inTag = false;
92                     tag += tok;
93                     docList.add(tag);
94                 } else {
95                     tag += tok;
96                 }
97             }
98         }
99         if (inTag) {
100             // An unterminated tag, or more likely, < used instead of &lt;
101             // There are no nested tags such as <a <b>> in HTML
102             docList.add(tag);
103         }
104         String[] docWords = new String[docList.size()];
105         docWords = (String[])docList.toArray(docWords);
106         return docWords;
107     }
108 
109     /**
110      * For improved readability, merge changes of the form
111      *  "delete 1, insert 1, space, delete 1, insert 1"
112      * to
113      *  "delete 3, insert 3" (including the space).
114      *
115      * @param oldDocWords The original documentation as a String array
116      * @param newDocWords The new documentation as a String array
117      */
mergeDiffs(String[] oldDocWords, String[] newDocWords, DiffMyers.change script)118     static DiffMyers.change mergeDiffs(String[] oldDocWords, String[] newDocWords,
119                                        DiffMyers.change script) {
120         if (script.link == null)
121             return script; // Only one change
122         DiffMyers.change hunk = script;
123         DiffMyers.change lasthunk = null; // Set to the last potential hunk
124         int startOld = 0;
125         for (; hunk != null; hunk = hunk.link) {
126             int deletes = hunk.deleted;
127             int inserts = hunk.inserted;
128             if (lasthunk == null) {
129                 if (deletes == 1 && inserts == 1) {
130                     // This is the start of a potential merge
131                     lasthunk = hunk;
132                 }
133                 continue;
134             } else {
135                 int first0 = hunk.line0; // Index of first deleted word
136                 int first1 = hunk.line1; // Index of first inserted word
137                 if (deletes == 1 && inserts == 1 &&
138                     oldDocWords[first0 - 1].compareTo(" ") == 0 &&
139                     newDocWords[first1 - 1].compareTo(" ") == 0 &&
140                     first0 == lasthunk.line0 + lasthunk.deleted + 1 &&
141                     first1 == lasthunk.line1 + lasthunk.inserted + 1) {
142                     // Merge this change into the last change
143                     lasthunk.deleted += 2;
144                     lasthunk.inserted += 2;
145                     lasthunk.link = hunk.link;
146                 } else {
147                     lasthunk = null;
148                 }
149             }
150         }
151         return script;
152     }
153 
154     /**
155      * Add the differences to the text passed in. The old documentation is
156      * edited using the edit script provided by the DiffMyers object.
157      * Do not display diffs in HTML tags.
158      *
159      * @param oldDocWords The original documentation as a String array
160      * @param newDocWords The new documentation as a String array
161      * @return The text for this documentation difference
162      */
addDiffs(String[] oldDocWords, String[] newDocWords, DiffMyers.change script, String text)163     static String addDiffs(String[] oldDocWords, String[] newDocWords,
164                            DiffMyers.change script, String text) {
165         String res = text;
166         DiffMyers.change hunk = script;
167         int startOld = 0;
168         if (trace) {
169             System.out.println("Old Text:");
170             for (int i = 0; i < oldDocWords.length; i++) {
171                 System.out.print(oldDocWords[i]);
172             }
173             System.out.println(":END");
174             System.out.println("New Text:");
175             for (int i = 0; i < newDocWords.length; i++) {
176                 System.out.print(newDocWords[i]);
177             }
178             System.out.println(":END");
179         }
180 
181         for (; hunk != null; hunk = hunk.link) {
182             int deletes = hunk.deleted;
183             int inserts = hunk.inserted;
184             if (deletes == 0 && inserts == 0) {
185                 continue; // Not clear how this would occur, but handle it
186             }
187 
188             // Determine the range of word and delimiter numbers involved
189             // in each file.
190             int first0 = hunk.line0; // Index of first deleted word
191             // Index of last deleted word, invalid if deletes == 0
192             int last0 = hunk.line0 + hunk.deleted - 1;
193             int first1 = hunk.line1; // Index of first inserted word
194             // Index of last inserted word, invalid if inserts == 0
195             int last1 = hunk.line1 + hunk.inserted - 1;
196 
197             if (trace) {
198                 System.out.println("HUNK: ");
199                 System.out.println("inserts: " + inserts);
200                 System.out.println("deletes: " + deletes);
201                 System.out.println("first0: " + first0);
202                 System.out.println("last0: " + last0);
203                 System.out.println("first1: " + first1);
204                 System.out.println("last1: " + last1);
205             }
206 
207             // Emit the original document up to this change
208             for (int i = startOld; i < first0; i++) {
209                 res += oldDocWords[i];
210             }
211             // Record where to start the next hunk from
212             startOld = last0 + 1;
213             // Emit the deleted words, but struck through
214             // but do not emit deleted HTML tags
215             if (deletes != 0) {
216                 boolean inStrike = false;
217                 for (int i = first0; i <= last0; i++) {
218                     if (!oldDocWords[i].startsWith("<") &&
219                         !oldDocWords[i].endsWith(">")) {
220                         if (!inStrike) {
221                             if (deleteEffect == 0)
222                                 res += "<strike>";
223                             else if (deleteEffect == 1)
224                                 res += "<span style=\"background: #FFCCCC\">";
225                             inStrike = true;
226                         }
227                         res += oldDocWords[i];
228                     }
229                 }
230                 if (inStrike) {
231                     if (deleteEffect == 0)
232                         res += "</strike>";
233                     else if (deleteEffect == 1)
234                         res += "</span>";
235                 }
236             }
237             // Emit the inserted words, but do not emphasise new HTML tags
238             if (inserts != 0) {
239                 boolean inEmph = false;
240                 for (int i = first1; i <= last1; i++) {
241                     if (!newDocWords[i].startsWith("<") &&
242                         !newDocWords[i].endsWith(">")) {
243                         if (!inEmph) {
244                             if (insertEffect == 0)
245                                 res += "<font color=\"red\">";
246                             else if (insertEffect == 1)
247                                 res += "<span style=\"background: #FFFF00\">";
248                             inEmph = true;
249                         }
250                     }
251                     res += newDocWords[i];
252                 }
253                 if (inEmph) {
254                     if (insertEffect == 0)
255                         res += "</font>";
256                     else if (insertEffect == 1)
257                         res += "</span>";
258                 }
259             }
260         } //for (; hunk != null; hunk = hunk.link)
261         // Print out the remaining part of the old text
262         for (int i = startOld; i < oldDocWords.length; i++) {
263             res += oldDocWords[i];
264         }
265         return res;
266     }
267 
268     /**
269      * Emit all the documentation differences into one file per package.
270      */
emitDocDiffs(String fullReportFileName)271     static void emitDocDiffs(String fullReportFileName) {
272         Collections.sort(docDiffs);
273 
274         DiffOutput[] docDiffsArr = new DiffOutput[docDiffs.size()];
275         docDiffsArr = (DiffOutput[])docDiffs.toArray(docDiffsArr);
276 
277         for (int i = 0; i < docDiffsArr.length; i++) {
278             DiffOutput diffOutput = docDiffsArr[i];
279             if (currPkgName == null ||
280                 currPkgName.compareTo(diffOutput.pkgName_) != 0) {
281                 // Open a different file for each package, add the HTML header,
282                 // the navigation bar and some preamble.
283                 if (currPkgName != null)
284                     closeDiffFile(); // Close the existing file
285                 // Create the HTML link to the previous package
286                 String prevPkgName = currPkgName;
287                 if (currPkgName != null) {
288                     prevPkgName = diffFileName + docDiffsArr[i-1].pkgName_ +
289                     HTMLReportGenerator.reportFileExt;
290                 }
291                 // Set the current package name
292                 currPkgName = diffOutput.pkgName_;
293                 // Create the HTML link to the next package
294                 String nextPkgName = null;
295                 for (int j = i; j < docDiffsArr.length; j++) {
296                     if (currPkgName.compareTo(docDiffsArr[j].pkgName_) != 0) {
297                         nextPkgName = diffFileName + docDiffsArr[j].pkgName_ +
298                             HTMLReportGenerator.reportFileExt;
299                         break;
300                     }
301                 }
302 
303                 String fullDiffFileName = fullReportFileName +
304                     JDiff.DIR_SEP + diffFileName + currPkgName +
305                     HTMLReportGenerator.reportFileExt;
306                 // Create the output file
307                 try {
308                     FileOutputStream fos = new FileOutputStream(fullDiffFileName);
309                     diffFile = new PrintWriter(fos);
310 
311                     // Write the HTML header
312                     diffFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Frameset//EN\"\"" + RootDocToXML.baseURI + "/TR/REC-html40/frameset.dtd\">");
313                     diffFile.println("<HTML>");
314                     diffFile.println("<HEAD>");
315                     diffFile.println("<meta name=\"generator\" content=\"JDiff v" + JDiff.version + "\">");
316                     diffFile.println("<!-- Generated by the JDiff Javadoc doclet -->");
317                     diffFile.println("<!-- (" + JDiff.jDiffLocation + ") -->");
318 //                    diffFile.println("<!-- on " + new Date() + " -->");
319                     diffFile.println("<meta name=\"description\" content=\"" + JDiff.jDiffDescription + "\">");
320                     diffFile.println("<meta name=\"keywords\" content=\"" + JDiff.jDiffKeywords + "\">");
321                     diffFile.println("<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"" + "../" + "stylesheet-jdiff.css\" TITLE=\"Style\">");
322                     diffFile.println("<TITLE>");
323                     diffFile.println(currPkgName + " Documentation Differences");
324                     diffFile.println("</TITLE>");
325                     diffFile.println("</HEAD>");
326                     diffFile.println("<BODY>");
327 
328                     // Write the navigation bar
329                     diffFile.println("<!-- Start of nav bar -->");
330                     diffFile.println("<TABLE summary=\"Navigation bar\" BORDER=\"0\" WIDTH=\"100%\" CELLPADDING=\"1\" CELLSPACING=\"0\">");
331                     diffFile.println("<TR>");
332                     diffFile.println("<TD COLSPAN=2 BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\">");
333                     diffFile.println("  <TABLE summary=\"Navigation bar\" BORDER=\"0\" CELLPADDING=\"0\" CELLSPACING=\"3\">");
334                     diffFile.println("    <TR ALIGN=\"center\" VALIGN=\"top\">");
335                     // Always have a link to the Javadoc files
336                     String pkgRef = currPkgName;
337                     pkgRef = pkgRef.replace('.', '/');
338                     pkgRef = HTMLReportGenerator.newDocPrefix + pkgRef + "/package-summary";
339                     diffFile.println("      <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + pkgRef + ".html\" target=\"_top\"><FONT CLASS=\"NavBarFont1\"><B><code>" + APIDiff.newAPIName_ + "</code></B></FONT></A>&nbsp;</TD>");
340                     diffFile.println("      <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + HTMLReportGenerator.reportFileName + "-summary" + HTMLReportGenerator.reportFileExt + "\"><FONT CLASS=\"NavBarFont1\"><B>Overview</B></FONT></A>&nbsp;</TD>");
341                     diffFile.println("      <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> &nbsp;<FONT CLASS=\"NavBarFont1\">Package</FONT>&nbsp;</TD>");
342                     diffFile.println("      <TD BGCOLOR=\"#FFFFFF\" CLASS=\"NavBarCell1\"> &nbsp;<FONT CLASS=\"NavBarFont1\">Class</FONT>&nbsp;</TD>");
343                     if (!Diff.noDocDiffs) {
344                         diffFile.println("      <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + Diff.diffFileName + "index" + HTMLReportGenerator.reportFileExt + "\"><FONT CLASS=\"NavBarFont1\"><B>Text Changes</B></FONT></A>&nbsp;</TD>");
345                     }
346                     if (HTMLReportGenerator.doStats) {
347                         diffFile.println("      <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"jdiff_statistics" + HTMLReportGenerator.reportFileExt + "\"><FONT CLASS=\"NavBarFont1\"><B>Statistics</B></FONT></A>&nbsp;</TD>");
348                     }
349                     diffFile.println("      <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"jdiff_help" + HTMLReportGenerator.reportFileExt + "\"><FONT CLASS=\"NavBarFont1\"><B>Help</B></FONT></A>&nbsp;</TD>");
350                     diffFile.println("    </TR>");
351                     diffFile.println("  </TABLE>");
352                     diffFile.println("</TD>");
353 
354                     // The right hand side title
355                     diffFile.println("<TD ALIGN=\"right\" VALIGN=\"top\" ROWSPAN=3><EM><b>Generated by<br><a href=\"" + JDiff.jDiffLocation + "\" class=\"staysblack\" target=\"_top\">JDiff</a></b></EM></TD>");
356                     diffFile.println("</TR>");
357 
358                     // Links for previous and next, and frames and no frames
359                     diffFile.println("<TR>");
360                     diffFile.println("  <TD BGCOLOR=\"" + HTMLReportGenerator.bgcolor + "\" CLASS=\"NavBarCell2\"><FONT SIZE=\"-2\">");
361                     if (prevPkgName != null)
362                         diffFile.println("  <A HREF=\"" + prevPkgName + "\"><B>PREV PACKAGE</B></A>  &nbsp;");
363                     else
364                         diffFile.println("  <B>PREV PACKAGE</B>  &nbsp;");
365                     if (nextPkgName != null)
366                         diffFile.println("  &nbsp;<A HREF=\"" + nextPkgName + "\"><B>NEXT PACKAGE</B></A>");
367                     else
368                         diffFile.println("  &nbsp;<B>NEXT PACKAGE</B>");
369                     diffFile.println("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
370                     diffFile.println("  <A HREF=\"" + "../" + HTMLReportGenerator.reportFileName + HTMLReportGenerator.reportFileExt + "\" TARGET=\"_top\"><B>FRAMES</B></A>  &nbsp;");
371                     diffFile.println("  &nbsp;<A HREF=\"" + diffFileName + currPkgName + HTMLReportGenerator.reportFileExt + "\" TARGET=\"_top\"><B>NO FRAMES</B></A></FONT></TD>");
372                     diffFile.println("  <TD BGCOLOR=\"" + HTMLReportGenerator.bgcolor + "\" CLASS=\"NavBarCell2\">&nbsp;</TD>");
373                     diffFile.println("</TR>");
374 
375                     diffFile.println("</TABLE>");
376                     diffFile.println("<HR>");
377                     diffFile.println("<!-- End of nav bar -->");
378 
379                     diffFile.println("<h2>");
380                     diffFile.println(currPkgName + " Documentation Differences");
381                     diffFile.println("</h2>");
382                     diffFile.println();
383                     diffFile.println("<blockquote>");
384                     diffFile.println("This file contains all the changes in documentation in the package <code>" + currPkgName + "</code> as colored differences.");
385                     if (deleteEffect == 0)
386                         diffFile.println("Deletions are shown <strike>like this</strike>, and");
387                     else if (deleteEffect == 1)
388                         diffFile.println("Deletions are shown <span style=\"background: #FFCCCC\">like this</span>, and");
389                     if (insertEffect == 0)
390                         diffFile.println("additions are shown in red <font color=\"red\">like this</font>.");
391                     else if (insertEffect == 1)
392                         diffFile.println("additions are shown <span style=\"background: #FFFF00\">like this</span>.");
393                     diffFile.println("</blockquote>");
394 
395                     diffFile.println("<blockquote>");
396                     diffFile.println("If no deletions or additions are shown in an entry, the HTML tags will be what has changed. The <i>new</i> HTML tags are shown in the differences. ");
397                     diffFile.println("If no documentation existed, and then some was added in a later version, this change is noted in the appropriate class pages of differences, but the change is not shown on this page. Only changes in existing text are shown here. ");
398                     diffFile.println("Similarly, documentation which was inherited from another class or interface is not shown here.");
399                     diffFile.println("</blockquote>");
400 
401                     diffFile.println("<blockquote>");
402                     diffFile.println(" Note that an HTML error in the new documentation may cause the display of other documentation changes to be presented incorrectly. For instance, failure to close a &lt;code&gt; tag will cause all subsequent paragraphs to be displayed differently.");
403                     diffFile.println("</blockquote>");
404                     diffFile.println("<hr>");
405                     diffFile.println();
406 
407                 } catch(IOException e) {
408                     System.out.println("IO Error while attempting to create " + fullDiffFileName);
409                     System.out.println("Error: " + e.getMessage());
410                     System.exit(1);
411                 }
412             } // if (currPkgName == null || currPkgName.compareTo(diffOutput.pkgName_) != 0)
413             // Now add the documentation difference text
414             diffFile.println(diffOutput.text_);
415             // Separate with a horizontal line
416             if (i != docDiffsArr.length - 1 &&
417                 diffOutput.className_ != null &&
418                 docDiffsArr[i+1].className_ != null &&
419                 diffOutput.className_.compareTo(docDiffsArr[i+1].className_) != 0)
420                 diffFile.println("<hr align=\"left\" width=\"100%\">");
421 //            else
422 //                diffFile.println("<hr align=\"left\" width=\"50%\">");
423         } // for (i = 0;
424         if (currPkgName != null)
425             closeDiffFile(); // Close the existing file
426 
427         // Emit the single file which is the index to all documentation changes
428         emitDocDiffIndex(fullReportFileName, docDiffsArr);
429     }
430 
431     /**
432      * Emit the single file which is the index to all documentation changes.
433      */
emitDocDiffIndex(String fullReportFileName, DiffOutput[] docDiffsArr)434     public static void emitDocDiffIndex(String fullReportFileName,
435                                         DiffOutput[] docDiffsArr) {
436 
437         String fullDiffFileName = fullReportFileName +
438             JDiff.DIR_SEP + diffFileName + "index" +
439             HTMLReportGenerator.reportFileExt;
440 
441         // Create the output file
442         try {
443             FileOutputStream fos = new FileOutputStream(fullDiffFileName);
444             diffFile = new PrintWriter(fos);
445 
446             // Write the HTML header
447             diffFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Frameset//EN\"\"" + RootDocToXML.baseURI + "/TR/REC-html40/frameset.dtd\">");
448             diffFile.println("<HTML>");
449             diffFile.println("<HEAD>");
450             diffFile.println("<meta name=\"generator\" content=\"JDiff v" + JDiff.version + "\">");
451             diffFile.println("<!-- Generated by the JDiff Javadoc doclet -->");
452             diffFile.println("<!-- (" + JDiff.jDiffLocation + ") -->");
453 //            diffFile.println("<!-- on " + new Date() + " -->");
454             diffFile.println("<meta name=\"description\" content=\"" + JDiff.jDiffDescription + "\">");
455             diffFile.println("<meta name=\"keywords\" content=\"" + JDiff.jDiffKeywords + "\">");
456             diffFile.println("<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"" + "../" + "stylesheet-jdiff.css\" TITLE=\"Style\">");
457             diffFile.println("<TITLE>");
458             diffFile.println("All Documentation Differences");
459             diffFile.println("</TITLE>");
460             diffFile.println("</HEAD>");
461             diffFile.println("<BODY>");
462 
463             // Write the navigation bar
464             diffFile.println("<!-- Start of nav bar -->");
465             diffFile.println("<TABLE summary=\"Navigation bar\" BORDER=\"0\" WIDTH=\"100%\" CELLPADDING=\"1\" CELLSPACING=\"0\">");
466             diffFile.println("<TR>");
467             diffFile.println("<TD COLSPAN=2 BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\">");
468             diffFile.println("  <TABLE summary=\"Navigation bar\" BORDER=\"0\" CELLPADDING=\"0\" CELLSPACING=\"3\">");
469             diffFile.println("    <TR ALIGN=\"center\" VALIGN=\"top\">");
470             // Always have a link to the Javadoc files
471             diffFile.println("      <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + HTMLReportGenerator.newDocPrefix + "index.html\" target=\"_top\"><FONT CLASS=\"NavBarFont1\"><B><code>" + APIDiff.newAPIName_ + "</code></B></FONT></A>&nbsp;</TD>");
472             diffFile.println("      <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + HTMLReportGenerator.reportFileName + "-summary" + HTMLReportGenerator.reportFileExt + "\"><FONT CLASS=\"NavBarFont1\"><B>Overview</B></FONT></A>&nbsp;</TD>");
473             diffFile.println("      <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> &nbsp;<FONT CLASS=\"NavBarFont1\">Package</FONT>&nbsp;</TD>");
474             diffFile.println("      <TD BGCOLOR=\"#FFFFFF\" CLASS=\"NavBarCell1\"> &nbsp;<FONT CLASS=\"NavBarFont1\">Class</FONT>&nbsp;</TD>");
475             if (!Diff.noDocDiffs) {
476                 diffFile.println("      <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1Rev\"> <FONT CLASS=\"NavBarFont1Rev\"><B>Text Changes</B></FONT>&nbsp;</TD>");
477             }
478             if (HTMLReportGenerator.doStats) {
479                 diffFile.println("      <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"jdiff_statistics" + HTMLReportGenerator.reportFileExt + "\"><FONT CLASS=\"NavBarFont1\"><B>Statistics</B></FONT></A>&nbsp;</TD>");
480             }
481             diffFile.println("      <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"jdiff_help" + HTMLReportGenerator.reportFileExt + "\"><FONT CLASS=\"NavBarFont1\"><B>Help</B></FONT></A>&nbsp;</TD>");
482             diffFile.println("    </TR>");
483             diffFile.println("  </TABLE>");
484             diffFile.println("</TD>");
485 
486             // The right hand side title
487             diffFile.println("<TD ALIGN=\"right\" VALIGN=\"top\" ROWSPAN=3><EM><b>Generated by<br><a href=\"" + JDiff.jDiffLocation + "\" class=\"staysblack\" target=\"_top\">JDiff</a></b></EM></TD>");
488             diffFile.println("</TR>");
489 
490             // Links for frames and no frames
491             diffFile.println("<TR>");
492             diffFile.println("  <TD BGCOLOR=\"" + HTMLReportGenerator.bgcolor + "\" CLASS=\"NavBarCell2\"><FONT SIZE=\"-2\">");
493             diffFile.println("  <A HREF=\"" + "../" + HTMLReportGenerator.reportFileName + HTMLReportGenerator.reportFileExt + "\" TARGET=\"_top\"><B>FRAMES</B></A>  &nbsp;");
494             diffFile.println("  &nbsp;<A HREF=\"" + diffFileName + "index" + HTMLReportGenerator.reportFileExt + "\" TARGET=\"_top\"><B>NO FRAMES</B></A></FONT></TD>");
495             diffFile.println("  <TD BGCOLOR=\"" + HTMLReportGenerator.bgcolor + "\" CLASS=\"NavBarCell2\">&nbsp;</TD>");
496             diffFile.println("</TR>");
497 
498             diffFile.println("</TABLE>");
499             diffFile.println("<HR>");
500             diffFile.println("<!-- End of nav bar -->");
501 
502             diffFile.println("<h2>");
503             diffFile.println("All Documentation Differences");
504             diffFile.println("</h2>");
505             diffFile.println();
506 
507             // For each package and class, add the first DiffOutput to
508             // the hash table. Used when generating navigation bars.
509             boolean firstPackage = true; // Set for the first package
510             boolean firstClass = true; // Set for first class in a package
511             boolean firstCtor = true; // Set for first ctor in a class
512             boolean firstMethod = true; // Set for first method in a class
513             boolean firstField = true; // Set for first field in a class
514             for (int i = 0; i < docDiffsArr.length; i++) {
515                 DiffOutput diffOutput = docDiffsArr[i];
516                 String link = "<a href=\"" + Diff.diffFileName + diffOutput.pkgName_ + HTMLReportGenerator.reportFileExt + "#" + diffOutput.id_ + "\">";
517 
518                 // See if the package name changed
519                 if (firstPackage || diffOutput.pkgName_.compareTo(docDiffsArr[i-1].pkgName_) != 0) {
520                     if (firstPackage) {
521                         firstPackage = false;
522                     } else {
523                         diffFile.println("<br>");
524                     }
525                     firstClass = true;
526                     firstCtor = true;
527                     firstMethod = true;
528                     firstField = true;
529                     String id = diffOutput.pkgName_ + "!package";
530                     firstDiffOutput.put(id, id);
531                     if (diffOutput.className_ == null) {
532                         diffFile.println("<A NAME=\"" + id + "\"></A>" + link + "Package <b>" + diffOutput.pkgName_ + "</b></a><br>");
533                     } else {
534                         diffFile.println("<A NAME=\"" + id + "\"></A>" + "Package <b>" + diffOutput.pkgName_ + "</b><br>");
535                     }
536                 }
537                 // See if the class name changed
538                 if (diffOutput.className_ != null &&
539                     (firstClass ||
540                      diffOutput.className_.compareTo(docDiffsArr[i-1].className_) != 0)) {
541                     if (firstClass) {
542                         firstClass = false;
543                     } else {
544                         diffFile.println("<br>");
545                     }
546                     firstCtor = true;
547                     firstMethod = true;
548                     firstField = true;
549                     String id = diffOutput.pkgName_ + "." + diffOutput.className_ + "!class";
550                     firstDiffOutput.put(id, id);
551                     if (diffOutput.id_.endsWith("!class")) {
552                         diffFile.println("<A NAME=\"" + id + "\"></A>&nbsp;&nbsp;Class " + link + diffOutput.className_ + "</a><br>");
553                     } else {
554                         diffFile.println("<A NAME=\"" + id + "\"></A>&nbsp;&nbsp;Class " + diffOutput.className_ + "<br>");
555                     }
556                 }
557                 // Work out what kind of member this is, and
558                 // display it appropriately
559                 if (diffOutput.className_ != null &&
560                     !diffOutput.id_.endsWith("!class")) {
561                     int ctorIdx = diffOutput.id_.indexOf(".ctor");
562                     if (ctorIdx != -1) {
563                         diffFile.println("&nbsp;&nbsp;&nbsp;&nbsp;" + link + diffOutput.className_ + diffOutput.id_.substring(ctorIdx + 5) + "</a><br>");
564                     } else {
565                         int methodIdx = diffOutput.id_.indexOf(".dmethod.");
566                         if (methodIdx != -1) {
567                             diffFile.println("&nbsp;&nbsp;&nbsp;&nbsp;"  + "Method " + link + diffOutput.id_.substring(methodIdx + 9) + "</a><br>");
568                         } else {
569                             int fieldIdx = diffOutput.id_.indexOf(".field.");
570                             if (fieldIdx != -1) {
571                                 diffFile.println("&nbsp;&nbsp;&nbsp;&nbsp;" + "Field " + link + diffOutput.id_.substring(fieldIdx + 7) + "</a><br>");
572                             }
573                         } //if (methodIdx != -1)
574                     } //if (ctorIdx != -1)
575                 } //diffOutput.className_ != null
576             }
577         } catch(IOException e) {
578             System.out.println("IO Error while attempting to create " + fullDiffFileName);
579             System.out.println("Error: " + e.getMessage());
580             System.exit(1);
581         }
582         closeDiffFile();
583     }
584 
585     /**
586      * Emit the HTML footer and close the diff file.
587      */
closeDiffFile()588     public static void closeDiffFile() {
589         if (diffFile != null) {
590             // Write the HTML footer
591             diffFile.println();
592             diffFile.println("</BODY>");
593             diffFile.println("</HTML>");
594             diffFile.close();
595         }
596     }
597 
598     /**
599      * Current file where documentation differences are written as colored
600      * differences.
601      */
602     public static PrintWriter diffFile = null;
603 
604     /**
605      * Base name of the current file where documentation differences are
606      * written as colored differences.
607      */
608     public static String diffFileName = "docdiffs_";
609 
610     /**
611      * The name of the current package, used to create diffFileName.
612      */
613     private static String currPkgName = null;
614 
615     /**
616      * If set, then do not generate colored diffs for documentation.
617      * Default is true.
618      */
619     public static boolean noDocDiffs = true;
620 
621     /**
622      * Define the type of emphasis for deleted words.
623      * 0 strikes the words through.
624      * 1 outlines the words in light grey.
625      */
626     public static int deleteEffect = 0;
627 
628     /**
629      * Define the type of emphasis for inserted words.
630      * 0 colors the words red.
631      * 1 outlines the words in yellow, like a highlighter.
632      */
633     public static int insertEffect = 1;
634 
635     /**
636      * For each package and class, the first DiffOutput is added to
637      * this hash table. Used when generating navigation bars.
638      */
639     public static Hashtable firstDiffOutput = new Hashtable();
640 
641     /**
642      * If set, then show changes in implementation-related modifiers such as
643      * native and synchronized. For more information, see
644      * https://java.sun.com/j2se/1.4.1/docs/tooldocs/solaris/javadoc.html#generatedapideclarations
645      */
646     public static boolean showAllChanges = false;
647 
648     /** The list of documentation differences. */
649     private static List docDiffs = new ArrayList(); // DiffOutput[]
650 
651     /** Set to enable increased logging verbosity for debugging. */
652     private static boolean trace = false;
653 
654 }
655