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