Home | History | Annotate | Download | only in scripts
      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 
     31 use Getopt::Std;
     32 
     33 $diffword = "wdiff";
     34 $context = 10;
     35 
     36 getopt('t:c:');
     37 
     38 if ($#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 = "";
     52 if (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 
     66 print <<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>
    204 END
    205 
    206 print "<pre><span class='subtracted'>          --- $ARGV[0]
    207 </span><span class='added'>          +++ $ARGV[1]
    208 </span>";
    209 
    210 sub 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 
    218 sub 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       &darr;&nbsp;open down&nbsp;&darr;</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       &uarr;&nbsp;open up&nbsp;&uarr;</td>
    231   </tr>
    232 </table>
    233 END
    234 	$inelided = 0;
    235 }
    236 
    237 while (<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/&/&amp;/g;
    286 	s/</&lt;/g;
    287 	s/>/&gt;/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 
    324 print @pretext;
    325 
    326 if ($inelided) {
    327 	$elided_lines += @pretext;
    328 	end_elided;
    329 } else {
    330 	print "    </pre>\n";
    331 }
    332 
    333 print "<pre id='linerefpre'><span id='lineref'>", 'X' x (4 + 1 + 4 + 2 + 80),
    334     "</span></pre>\n";
    335 
    336 print <<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>
    374 END
    375