1#!/usr/bin/perl -w 2# 3# CDDL HEADER START 4# 5# The contents of this file are subject to the terms of the 6# Common Development and Distribution License (the "License"). 7# You may not use this file except in compliance with the License. 8# 9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10# or http://www.opensolaris.org/os/licensing. 11# See the License for the specific language governing permissions 12# and limitations under the License. 13# 14# When distributing Covered Code, include this CDDL HEADER in each 15# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16# If applicable, add the following below this CDDL HEADER, with the 17# fields enclosed by brackets "[]" replaced with your own identifying 18# information: Portions Copyright [yyyy] [name of copyright owner] 19# 20# CDDL HEADER END 21# 22# 23# ident "%Z%%M% %I% %E% SMI" 24# 25# Copyright 2006 Sun Microsystems, Inc. All rights reserved. 26# Use is subject to license terms. 27# 28# Make a dynamic HTML page for the unified diffs between two (C) files. 29# 30 31use Getopt::Std; 32 33$diffword = "wdiff"; 34$context = 10; 35 36getopt('t:c:'); 37 38if ($#ARGV + 1 == 1) { 39 $diffword = $ARGV[0]; 40 open DIFF, "<&STDIN"; 41 $ARGV[0] = '-'; 42 $ARGV[1] = '-'; 43} elsif ($#ARGV + 1 == 2) { 44 open DIFF, "diff -D $diffword $ARGV[0] $ARGV[1] | expand |"; 45} else { 46 print "Usage: $0 [-t title] [-c comment] file1 file2\n"; 47 exit 2; 48} 49 50$title = $opt_t ? $opt_t : "Differences between $ARGV[0] and $ARGV[1]"; 51$comment = ""; 52if (defined $opt_c) { 53 $comment = "<pre>\n" . $opt_c . "\n</pre>\n<hr />"; 54} 55 56$indiff = 0; 57$line1 = 0; 58$line2 = 0; 59@pretext = (); # Speculative pretext buffer (code) 60$posttext = 0; # Lines of posttext to print 61$nelided = 0; # Number of elided chunks 62$endfunc = 0; # Seen end of function? 63$inelided = 0; # Elided section open? 64$elided_lines = 0; 65 66print <<END; 67<?xml version="1.0"?> 68<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 69 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 70<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 71 <head> 72 <title>$title</title> 73 74 <meta http-equiv="cache-control" content="no-cache" /> 75 76 <style type='text/css' media='screen'> 77 pre { margin: 2px; } 78 79 body { background-color: #eeeeee; } 80 81 hr { border: none 0; border-top: 1px solid #aaa; height: 1px; } 82 83 .subtracted { color: brown } 84 .added { color: blue } 85 86 .elided { border: 1px solid #444; cursor: pointer; margin: 1px } 87 88 table.hidebar { border: 1px solid #ff9900; background-color: #eee; 89 text-align: center; border-collapse: collapse; } 90 91 .hidebar td.active-down { border: 1px solid #ff9900; 92 border-right: 1px solid #ccc; cursor: s-resize } 93 94 .hidebar td.active-down:hover { background-color: #ffcc99; } 95 96 .hidebar td.active-up { border: 1px solid #ff9900; cursor: n-resize; 97 border-left: 1px solid #ccc; } 98 99 .hidebar td.active-up:hover { background-color: #ffcc99; } 100 101 .hidebar td.elided-label { font-style: italic; width: 12em; } 102 103 .cmdbox { position: fixed; top: 0; right: 0; 104 border-left: solid 1px #444; 105 border-bottom: solid 1px #444; 106 background-color: #ccc; text-align: center } 107 108 .cmdbox td { background-color: #eee; border: 1px #444 outset; 109 cursor: pointer; padding: 3px 4px; } 110 .cmdbox td:hover { background-color: #ffcc99; 111 outline: thin solid #ff9900; } 112 113 a:hover { background-color: #ffcc99; } 114 115 a.print { font-size: x-small; } 116 </style> 117 118 <style type='text/css' media='print'> 119 pre { font-family: courier, monospace; font-size: 0.8em; } 120 .cmdbox { display: none; } 121 a.print { display: none; } 122 .hidebar td.active-down { display: none; } 123 .hidebar td.active-up { display: none; } 124 .hidebar td.elided-label { font-style: italic; font-size: small; } 125 table.hidebar { border: none; border-bottom: 1px dotted #000000; } 126 span.added { font-weight: bold; 127 background-color: #eee; width: 100%; display: block; } 128 span.subtracted { font-style: italic; 129 background-color: #eee; width: 100%; display: block; } 130 .elided { display: none; } 131 hr { border: none 0; border-top: 1px solid #aaa; height: 1px; } 132 </style> 133 134 <script type="text/javascript"> 135 function show_n_hide_dir(id_to_show, id_to_hide, dir) { 136 var elt_to_show = document.getElementById(id_to_show); 137 var elt_to_hide = document.getElementById(id_to_hide); 138 // When we're opening up, we need to make the bottoms of the 139 // elements appear to be the same. So our invariant should be 140 // elt.offsetBottom - window.scrollY. 141 var preinvar = elt_to_hide.offsetHeight - window.scrollY; 142 elt_to_show.style.setProperty('display', '', ''); 143 elt_to_hide.style.setProperty('display', 'none', ''); 144 if (dir == 'up') { 145 var postinvar = elt_to_show.offsetHeight - window.scrollY; 146 window.scrollBy(0, postinvar - preinvar); 147 } 148 } 149 150 function handle_click(e) { 151 var eh = e.target; 152 var es = document.getElementById("hb-" + e.target.id); 153 eh.style.setProperty('display', 'none', ''); 154 es.style.setProperty('display', '', ''); 155 /* Scroll so new element is at cursor. */ 156 window.scroll(0, es.offsetTop + (es.offsetHeight / 2) 157 - e.clientY); 158 } 159 160 function stripsearch(str) { 161 q = str.indexOf("?"); 162 if (q != -1) 163 str = str.substr(0, q); 164 return (str); 165 } 166 167 function split() { 168 page = stripsearch(location.href); 169 halfway = window.scrollY + window.innerHeight / 2 - 5; 170 document.write('<frameset rows="50%,*">' + 171 '<frame src="' + page + "?" + window.scrollY + '" />' + 172 '<frame src="' + page + "?" + halfway + '" />' + 173 '</frameset>'); 174 document.close(); 175 } 176 177 function closeframe() { 178 page = stripsearch(location.href); 179 180 otherf = window.parent.frames[0]; 181 if (otherf == window) 182 otherf = window.parent.frames[1]; 183 184 parent.location.replace(page + "?" + otherf.scrollY); 185 } 186 </script> 187 </head> 188 <body id='SUNWwebrev'> 189 <a class="print" href="javascript:print()">Print this page</a> 190 $comment 191 <table class='cmdbox'> 192 <tr> 193 <td onclick='split()'>Split</td> 194 <td id='close' onclick='closeframe()'>Close</td> 195 </tr> 196 <tr><td colspan="2" onclick='open_or_close_all(1)'>Expand all</td></tr> 197 <tr><td colspan="2" onclick='open_or_close_all(0)'>Collapse all</td></tr> 198 </table> 199 200 <script type='text/javascript'> 201 if (window == top) 202 document.getElementById('close').style.setProperty('display', 'none', ''); 203 </script> 204END 205 206print "<pre><span class='subtracted'> --- $ARGV[0] 207</span><span class='added'> +++ $ARGV[1] 208</span>"; 209 210sub begin_elided { 211 ++$nelided; 212 # onclick handler assigned at bottom 213 print "<pre id='elided$nelided' class='elided' style='display: none'>"; 214 $inelided = 1; 215 $elided_lines = 0; 216} 217 218sub end_elided { 219 print "</pre>\n"; 220 221 print <<END; 222<table id='hb-elided$nelided' class='hidebar'> 223 <tr> 224 <td class='active-down' 225 onclick='show_n_hide_dir("elided$nelided", "hb-elided$nelided", "down")'> 226 ↓ open down ↓</td> 227 <td class="elided-label">$elided_lines lines elided</td> 228 <td class='active-up' 229 onclick='show_n_hide_dir("elided$nelided", "hb-elided$nelided", "up")'> 230 ↑ open up ↑</td> 231 </tr> 232</table> 233END 234 $inelided = 0; 235} 236 237while (<DIFF>) { 238 chomp; 239 240 # Change detection 241 $previndiff = $indiff; 242 243 if (!$indiff) { 244 if (/^#ifdef $diffword$/) { 245 $indiff = 1; 246 } elsif (/^#ifndef $diffword$/) { 247 $indiff = -1; 248 } 249 } else { 250 if (/^#else \/\* $diffword \*\/$/) { 251 $indiff = -$indiff; 252 print "</span>"; 253 printf "<span class='%s'>", 254 ($indiff > 0 ? "added" : "subtracted"); 255 next; 256 } elsif (/^#endif \/\* (! )?$diffword \*\/$/) { 257 $indiff = 0; 258 $posttext = $context; 259 print "</span>"; 260 next; 261 } 262 } 263 264 if (!$previndiff && $indiff) { 265 # Beginning of a change: If we have an elided section open, 266 # end it. Print the pretext and continue. 267 268 if ($inelided) { 269 end_elided; 270 print "<pre>"; 271 } 272 273 print @pretext; 274 @pretext = (); 275 $endfunc = 0; 276 277 printf "<span class='%s'>", 278 ($indiff > 0 ? "added" : "subtracted"); 279 next; 280 } 281 282 # Line of code 283 284 # Quote for HTML 285 s/&/&/g; 286 s/</</g; 287 s/>/>/g; 288 289 # Format the line according to $indiff, and print it or put it into 290 # a buffer. 291 if ($indiff == -1) { 292 ++$line1; 293 printf "%4d %4s -%s\n", $line1, "", $_; 294 } elsif ($indiff == 0) { 295 ++$line1; 296 ++$line2; 297 298 $str = sprintf "%4d %4d %s\n", $line1, $line2, $_; 299 300 if ($posttext > 0) { 301 print $str; 302 --$posttext; 303 } else { 304 push @pretext, $str; 305 if ($#pretext + 1 > $context) { 306 $str = shift @pretext; 307 308 if (!$inelided) { 309 print "</pre>\n"; 310 begin_elided; 311 } 312 313 ++$elided_lines; 314 315 print $str; 316 } 317 } 318 } elsif ($indiff == 1) { 319 ++$line2; 320 printf "%4s %4d +%s\n", "", $line2, $_; 321 } 322} 323 324print @pretext; 325 326if ($inelided) { 327 $elided_lines += @pretext; 328 end_elided; 329} else { 330 print " </pre>\n"; 331} 332 333print "<pre id='linerefpre'><span id='lineref'>", 'X' x (4 + 1 + 4 + 2 + 80), 334 "</span></pre>\n"; 335 336print <<END; 337 <br clear="all" /> 338 <br /> 339 340 <script type="text/javascript"> 341 /* Assign event handlers and widths. */ 342 var w = document.getElementById('lineref').offsetWidth; 343 for (var i = 1; i <= $nelided; ++i) { 344 var e = document.getElementById("elided" + i); 345 e.onclick = handle_click; 346 e.style.setProperty('width', w + "px", ''); 347 348 e = document.getElementById("hb-elided" + i); 349 e.style.setProperty('width', w + "px", ''); 350 } 351 352 /* Hide our line size reference. */ 353 document.getElementById('linerefpre').style.setProperty('display', 354 'none', ''); 355 356 /* Scroll as indicated. */ 357 str = location.search; 358 s = str.substring(1, str.length); 359 if (s > 0) 360 window.scroll(0, s); 361 362 function open_or_close_all(open) { 363 for (var i = 1; i <= $nelided; ++i) { 364 var e = document.getElementById("hb-elided" + i); 365 e.style.setProperty("display", open ? "none" : "", ""); 366 367 e = document.getElementById("elided" + i); 368 e.style.setProperty("display", open ? "" : "none", ""); 369 } 370 } 371 </script> 372 </body> 373</html> 374END 375